Arguments are working :fingers_crossed:

This commit is contained in:
Gnarwhal 2024-08-31 17:29:46 +00:00
parent 7b8fbf672b
commit 987eddbf00
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
5 changed files with 172 additions and 69 deletions

View file

@ -26,9 +26,7 @@ import sys
from pathlib import Path from pathlib import Path
from version import version from version import version
from plugins.config import Default
from plugins.config import NoDefault from plugins.config import NoDefault
from plugins.config import Flags
class Congloggerate: class Congloggerate:
def __init__(self, loggers): def __init__(self, loggers):
@ -81,12 +79,9 @@ def main():
Plugin("append_type", importlib.import_module("plugins.default.append_type")), Plugin("append_type", importlib.import_module("plugins.default.append_type")),
Plugin("ssh", importlib.import_module("plugins.default.ssh")), Plugin("ssh", importlib.import_module("plugins.default.ssh")),
] ]
plugins = { plugins = {}
"logger": [], for type in [ "logger", "source", "name", "upload" ]:
"source": [], plugins[type] = { "active": [], "inactive": [] }
"name": [],
"upload": [],
}
# Load external plugins # Load external plugins
sys.dont_write_bytecode = True sys.dont_write_bytecode = True
@ -102,6 +97,20 @@ def main():
sys.dont_write_bytecode = False sys.dont_write_bytecode = False
# Set plugin configurations from config file # Set plugin configurations from config file
# Load plugin arguments and detect conflicts
error = False
argument_map = {}
used_arguments = {}
parser = argparse.ArgumentParser(
prog = "SSHare",
description = "Upload files to a server via ssh",
)
parser.add_argument(
"-v",
"--version",
action="version",
version=f"%(prog)s version {version}",
)
if config.get("plugins") == None: if config.get("plugins") == None:
config["plugins"] = {} config["plugins"] = {}
for plugin in plugins_flat: for plugin in plugins_flat:
@ -109,33 +118,34 @@ def main():
plugin_config = config["plugins"].get(plugin.name) plugin_config = config["plugins"].get(plugin.name)
if plugin_config != None: if plugin_config != None:
for config_entry in plugin_config.items(): for config_entry in plugin_config.items():
plugin.module.config[config_entry[0]] = Default(config_entry[1]) plugin.module.config[config_entry[0]] = config_entry[1]
# Flatten plugin configs
class PluginConfig: pass
error = False
for plugin in plugins_flat:
if hasattr(plugin.module, "config"):
config = plugin.module.config
plugin.module.config = PluginConfig()
for config_entry in config.items():
if isinstance(config_entry[1], NoDefault):
logger.error(f"{plugin.name} > Error: Value '{config_entry[0]}' has no default value and must be specified explicitly")
error = True
elif isinstance(config_entry[1], Default):
setattr(plugin.module.config, config_entry[0], config_entry[1].value)
else: else:
setattr(plugin.module.config, config_entry[0], config_entry[1]) setattr(plugin.module, "config", {})
if hasattr(plugin.module, "args"):
for arg_name, arg in plugin.module.args.items():
if arg.is_valid():
arg.set_for_plugin(plugin)
def check_flag(flag):
if flag in used_arguments:
logger.error(f"Error: Argument '{arg_name}' for plugin '{plugin.name}' has conflict. Flag '{flag}' is also used by plugin '{used_arguments[arg.short]}'")
error = True
check_flag(arg.short)
check_flag(arg.long)
arg.add(parser, used_arguments)
argument_map[arg.dest] = plugin, arg_name
else:
logger.error(f"Error: Argument '{arg_name}' must set either one or both of short and long flag parameters")
error = True
if error: if error:
sys.exit(1) sys.exit(1)
# Initialise plugins arguments = parser.parse_args()
for plugin in plugins_flat: for arg, (plugin, config) in list(argument_map.items()):
setattr(plugin.module, "logger", logger) if getattr(arguments, arg):
if hasattr(plugin.module, "init"): plugin.module.config[config] = getattr(arguments, arg)
plugin.module.init() del argument_map[arg]
# Sort plugins by type # Sort plugins by type and check activation criteria
error = False error = False
for plugin in plugins_flat: for plugin in plugins_flat:
if isinstance(plugin.module.plugin_type, str): if isinstance(plugin.module.plugin_type, str):
@ -146,24 +156,73 @@ def main():
logger.error(f"Error: Plugin '{plugin.name}' has an invalid plugin type '{plugin_type}'") logger.error(f"Error: Plugin '{plugin.name}' has an invalid plugin type '{plugin_type}'")
error = True error = True
else: else:
plugins_of_type.append(plugin) active = True
if hasattr(plugin.module, "activate"):
criteria = plugin.module.activate
if isinstance(plugin.module.activate, dict):
criteria = plugin.module.activate.get(plugin_type)
if criteria != None:
for criterion in criteria:
active = not plugin.module.args[criterion].dest in argument_map
if not active:
break
plugins_of_type["active" if active else "inactive"].append(plugin)
for plugin_type, plugins_of_type in plugins.items():
if len(plugins_of_type["active"]) == 0 and plugin_type != "logger":
if len(plugins_of_type["inactive"]) == 0:
logger.error(f"No '{plugin_type}' plugins available. Atleast one must be provided")
else:
logger.error(f"No '{plugin_type}' plugins activated. Activate at least one of:")
for plugin in plugins_of_type["inactive"]:
logger.error(f"{plugin.name}:")
criteria = plugin.module.activate
if isinstance(plugin.module.activate, dict):
criteria = plugin.module.activate[plugin_type]
for criterion in criteria:
logger.error(f" {plugin.module.args[criterion].pretty()}")
error = True
if error: if error:
sys.exit(1) sys.exit(1)
logger = Congloggerate([ logger.module for logger in plugins["logger"] ]) # Flatten plugin configs
error = False
class PluginConfig: pass
for plugin in plugins_flat:
if hasattr(plugin.module, "config"):
config = plugin.module.config
plugin.module.config = PluginConfig()
for config_entry in config.items():
if config_entry[1] == NoDefault:
logger.error(f"Error: Value 'plugins.{plugin.name}.{config_entry[0]}' has no default value and must be specified explicitly")
error = True
else:
setattr(plugin.module.config, config_entry[0], config_entry[1])
if error:
sys.exit(1)
# Initialise plugins
for plugin in plugins_flat:
setattr(plugin.module, "logger", logger)
if hasattr(plugin.module, "init"):
error = error or plugin.module.init()
logger = Congloggerate([ logger.module for logger in plugins["logger"]["active"] ])
sources = [] sources = []
for plugin in plugins["source"]: for plugin in plugins["source"]["active"]:
sources.append(plugin.module.get()) sources.append(plugin.module.get())
if len(sources) == 0:
logger.error("Error: No sources provided. Must activate at least one source plugin")
log_activations(logger, plugins["source"])
for index, source in enumerate(sources): for index, source in enumerate(sources):
name = "" name = ""
for plugin in plugins["name"]: for plugin in plugins["name"]["active"]:
name = plugin.module.name(name, source) name = plugin.module.name(name, source)
sources[index] = name, source sources[index] = name, source
for (name, source) in sources: for (name, source) in sources:
for plugin in plugins["upload"]: for plugin in plugins["upload"]["active"]:
plugin.module.upload(name, source) plugin.module.upload(name, source)
sys.exit(0) sys.exit(0)
@ -174,12 +233,6 @@ def parse_arguments():
description = "Upload files to a server via ssh", description = "Upload files to a server via ssh",
) )
parser.add_argument(
"-v",
"--version",
action="version",
version=f"%(prog)s version {version}",
)
parser.add_argument( parser.add_argument(
"-l", "-l",
"--latest", "--latest",
@ -206,7 +259,6 @@ def parse_arguments():
const=True, const=True,
help="Copy the resultant URL to the clipboard", help="Copy the resultant URL to the clipboard",
) )
arguments = parser.parse_args()
return arguments return arguments

View file

@ -12,16 +12,63 @@
# You should have received a copy of the GNU General Public License along with # You should have received a copy of the GNU General Public License along with
# SSHare. If not, see <https://www.gnu.org/licenses/>. # SSHare. If not, see <https://www.gnu.org/licenses/>.
class NoDefault: class NoDefault: pass
def __init__(self, flags=None):
self.flags = flags
class Default: class Argument:
def __init__(self, value, flags=None): def __init__(self,
self.value = value short=None,
self.flags = flags long=None,
action='store',
class Flags: nargs=None,
def __init__(self, short=None, long=None): const=None,
default=None,
type=str,
choices=None,
required=False,
help=None,
metavar=None):
self.short = short self.short = short
self.long = long self.long = long
self.action = action
self.nargs = nargs
self.const = const
self.default = default
self.type = type
self.choices = choices
self.help = help
self.metavar = metavar or self.long or self.short
def is_valid(self):
return (self.short != None and self.short != "") or (self.long != None and self.long != "")
def pretty(self):
if self.short and self.long:
pretty = f"-{self.short}, --{self.long}"
elif self.long:
pretty = f"--{self.long}"
else:
pretty = f"-{self.short}"
return pretty + f" {self.help}"
def set_for_plugin(self, plugin):
self.plugin = plugin
self.dest = f"{plugin.name}_{self.metavar}"
def add(self, parser, used_arguments):
parser.add_argument(
f"-{self.short}",
f"--{self.long}",
action=self.action,
nargs=self.nargs,
const=self.const,
default=self.default,
type=self.type,
choices=self.choices,
help=self.help,
metavar=self.metavar,
dest=self.dest,
)
if self.short:
used_arguments["short"] = self.plugin
if self.long:
used_arguments["long"] = self.plugin

View file

@ -14,8 +14,7 @@
import time import time
from ..config import Default from ..config import Argument
from ..config import Flags
from ..source import File from ..source import File
plugin_type = "name" plugin_type = "name"
@ -23,6 +22,13 @@ plugin_type = "name"
config = { config = {
"base": 62, "base": 62,
} }
args = {
"base": Argument(
short="b",
long="base",
help="Set the numeric base to use for the current time"
)
}
def init(): def init():
if not isinstance(config.base, int): if not isinstance(config.base, int):

View file

@ -12,19 +12,19 @@
# You should have received a copy of the GNU General Public License along with # You should have received a copy of the GNU General Public License along with
# SSHare. If not, see <https://www.gnu.org/licenses/>. # SSHare. If not, see <https://www.gnu.org/licenses/>.
from ..config import Argument
from ..config import NoDefault from ..config import NoDefault
from ..config import Flags
from ..source import File from ..source import File
plugin_type = "source" plugin_type = "source"
config = { activate = [ "file" ]
"file": NoDefault( args = {
flags=Flags( "file": Argument(
short="f", short="f",
long="file" long="file",
help="Upload a file"
) )
),
} }
def get(): def get():

View file

@ -15,23 +15,21 @@
import getpass import getpass
import subprocess import subprocess
from ..config import Default
from ..config import NoDefault from ..config import NoDefault
from ..config import Flags
from ..source import File from ..source import File
from ..source import Raw from ..source import Raw
plugin_type = "upload" plugin_type = "upload"
config = { config = {
"host": NoDefault(), "host": NoDefault,
"path": NoDefault(), "path": NoDefault,
"port": 22, "port": 22,
"user": getpass.getuser(), "user": getpass.getuser(),
} }
def upload(name, source): def upload(name, source):
logger.info(f"Uploading to {config.user}@{config.host}/{config.port}:{config.path}/{name}") logger.info(f"Uploading to {config.user}@{config.host}:{config.path}/{name} on port {config.port}")
if isinstance(source, File): if isinstance(source, File):
command = [ command = [
"scp", "scp",