-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Delete core and lib directories during uninstallation, Add imachug's …
…ZeroNet Cmd Lib under Tools directory
- Loading branch information
Christian Seibold
committed
May 20, 2018
1 parent
22884a9
commit 778f295
Showing
17 changed files
with
1,227 additions
and
1 deletion.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.pyc | ||
/config.json |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import sys | ||
argv = sys.argv[1:] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import sys, inspect | ||
|
||
def classAsFunction(cls): | ||
if not isinstance(cls, type): | ||
return cls | ||
|
||
class Class(cls): | ||
def __new__(cls, args): | ||
instance = super(Callable, cls).__new__(cls) | ||
return instance.__init__(args) | ||
|
||
return Class | ||
|
||
@classAsFunction | ||
class Callable(object): | ||
class SubCommand(Exception): | ||
pass | ||
class Redirect(Exception): | ||
pass | ||
class Error(Exception): | ||
pass | ||
|
||
def __init__(self, args): | ||
return self.call("", args) | ||
|
||
def call(self, cmd, args): | ||
cmd = cmd.strip() | ||
|
||
try: | ||
handler = getattr(self, "action" + "".join(map(lambda part: part[0].upper() + part[1:] if part != "" else "", cmd.split(" ")))) | ||
except AttributeError: | ||
all_commands = [name[6].lower() + name[7:] for name in dir(self) if name.startswith("action") and len(name) > 6] | ||
raise Callable.Error("Unknown command '%s'. Allowed commands are: %s" % (cmd, ", ".join(all_commands))) | ||
|
||
self.checkCall(cmd, handler, args) | ||
|
||
try: | ||
return self.callArgs(handler, args) | ||
except Callable.SubCommand as e: | ||
if len(args) == 0: | ||
raise Callable.Error("'%s' command is not a command but has subcommands." % cmd) | ||
|
||
if len(tuple(e)) == 0: | ||
# Remove first argument and call it | ||
return self.call("%s %s" % (cmd, args[0]), args[1:]) | ||
else: | ||
# Remove first argument and call given command | ||
return self.call(tuple(e)[0], args[1:]) | ||
except Callable.Redirect as e: | ||
if len(tuple(e)) == 0: | ||
# Remove first argument and call it (as SubCommand) | ||
if len(args) == 0: | ||
raise Callable.Error("'%s' command is not a command but has subcommands." % cmd) | ||
return self.call("%s %s" % (cmd, args[0]), args[1:]) | ||
elif len(tuple(e)) == 1: | ||
# Call given value | ||
return self.call(tuple(e)[0], args) | ||
else: | ||
# Call given value and arguments | ||
return self.call(tuple(e)[0], tuple(e)[1]) | ||
|
||
def checkCall(self, cmd, func, argv): | ||
import inspect | ||
|
||
expected_args = inspect.getargspec(func).args[1:] # Split "self" | ||
defaults = inspect.getargspec(func).defaults or tuple() | ||
|
||
if self.checkArgs(cmd, func, argv): | ||
return True | ||
|
||
if len(defaults) > 0: | ||
default_args = reversed(zip(reversed(expected_args), reversed(defaults))) | ||
default_args = map(lambda arg: "%s=%s" % arg, default_args) | ||
expected_args = expected_args[:-len(default_args)] + default_args | ||
|
||
raise Callable.Error("Allowed arguments: %s" % ", ".join(expected_args)) | ||
|
||
def checkArgs(self, cmd, func, argv): | ||
args, kwargs = self.parseArgs(argv) | ||
|
||
import inspect | ||
|
||
expected_args = inspect.getargspec(func).args[1:] # Split "self" | ||
varargs = inspect.getargspec(func).varargs | ||
keywords = inspect.getargspec(func).keywords | ||
defaults = inspect.getargspec(func).defaults or tuple() | ||
|
||
resulting_args = dict() | ||
if varargs is not None: | ||
resulting_args[varargs] = [] | ||
if keywords is not None: | ||
resulting_args[keywords] = {} | ||
|
||
# Positional arguments | ||
for cnt, value in enumerate(args): | ||
if cnt < len(expected_args): | ||
# Passed just as argument | ||
resulting_args[expected_args[cnt]] = value | ||
else: | ||
# Passed to *args | ||
if varargs is None: | ||
raise Callable.Error("Too many positional arguments passed to '%s': expected at most %s, got %s." % (cmd, len(expected_args), len(args))) | ||
else: | ||
resulting_args[varargs].append(value) | ||
|
||
# Named arguments | ||
handled_kwargs = [] | ||
for name, value in kwargs.iteritems(): | ||
if name in handled_kwargs: | ||
raise Callable.Error("'%s' was passed to '%s' as named argument several times." % (name, cmd)) | ||
|
||
handled_kwargs.append(name) | ||
|
||
if name in expected_args: | ||
# Passed just as argument | ||
if name in resulting_args: | ||
raise Callable.Error("'%s' was passed to '%s' as both positional argument and named." % (name, cmd)) | ||
|
||
resulting_args[name] = value | ||
else: | ||
# Passed to **kwargs | ||
if keywords is None: | ||
raise Callable.Error("Unknown named argument '%s' passed to '%s'." % (name, cmd)) | ||
else: | ||
resulting_args[keywords][name] = value | ||
|
||
# Defaults | ||
if len(defaults) > 0: | ||
for cnt, name in enumerate(expected_args[-len(defaults):]): | ||
if name not in resulting_args: | ||
resulting_args[name] = defaults[cnt] | ||
|
||
# Check that all the arguments were passed | ||
for name in expected_args: | ||
if name not in resulting_args: | ||
raise Callable.Error("Argument '%s' was not passed to '%s'." % (name, cmd)) | ||
|
||
return True | ||
|
||
def parseArgs(self, argv): | ||
args = [] | ||
kwargs = {} | ||
|
||
kwname = None | ||
|
||
for arg in argv: | ||
if arg.startswith("--"): | ||
if kwname is not None: | ||
kwargs[kwname] = True | ||
|
||
kwname = arg[2:] | ||
else: | ||
if kwname is None: | ||
args.append(arg) | ||
else: | ||
kwargs[kwname] = arg | ||
kwname = None | ||
|
||
if kwname is not None: | ||
kwargs[kwname] = True | ||
|
||
return args, kwargs | ||
|
||
def callArgs(self, handler, argv): | ||
args, kwargs = self.parseArgs(argv) | ||
return handler(*args, **kwargs) | ||
|
||
def action(self, *args, **kwargs): | ||
raise Callable.SubCommand | ||
|
||
class WithHelp(Callable): | ||
def actionHelp(self, *cmd): | ||
if cmd in [[], [""], tuple(), ("",)]: | ||
# Print info about the class | ||
print inspect.cleandoc(self.__doc__) | ||
return | ||
|
||
try: | ||
handler = getattr(self, "action" + "".join(map(lambda part: part[0].upper() + part[1:], cmd))) | ||
if handler.__doc__ is not None: | ||
print inspect.cleandoc(handler.__doc__) | ||
return | ||
except AttributeError: | ||
pass | ||
|
||
if cmd == ["help"] or cmd == ("help",): | ||
# Unable to find info on topic 'help' - no __doc__ in 'help' method or no 'help' method, use default help | ||
print inspect.cleandoc(self.__doc__) | ||
return | ||
|
||
print "Unknown topic '%s'" % " ".join(cmd) | ||
|
||
Callable.WithHelp = WithHelp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import os, json | ||
|
||
def recursiveDir(obj, prefix=""): | ||
result = [] | ||
for name in obj: | ||
absolute = "%s.%s" % (prefix, name) if prefix != "" else name | ||
if isinstance(obj[name], dict): | ||
result += recursiveDir(obj[name], absolute) | ||
else: | ||
result.append(absolute) | ||
return result | ||
|
||
class Config(object): | ||
class AttributeError(AttributeError): | ||
pass | ||
|
||
def __init__(self, path): | ||
self.__dict__["path"] = path | ||
|
||
# Read single value | ||
def __getattr__(self, name): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
return config[name] | ||
except (KeyError, AttributeError): | ||
raise Config.AttributeError("No '%s' config variable" % name) | ||
except IOError: | ||
raise Config.AttributeError("No config file and therefore no '%s' attribute" % name) | ||
def __getitem__(self, name): | ||
return self.__getattr__(name) | ||
|
||
# Read value recursively | ||
def get(self, name, default=None): | ||
name = name.split(".") | ||
|
||
try: | ||
val = self[name[0]] | ||
for part in name[1:]: | ||
val = val[part] | ||
|
||
return val | ||
except (KeyError, AttributeError, Config.AttributeError): | ||
return default | ||
|
||
# Write single value | ||
def __setattr__(self, name, value): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
except IOError: | ||
config = dict() | ||
|
||
config[name] = value | ||
|
||
with open(self.path, "w") as f: | ||
f.write(json.dumps(config)) | ||
def __setitem__(self, name, value): | ||
self.__setattr__(name, value) | ||
|
||
# Write value recursively | ||
def set(self, name, value): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
except IOError: | ||
config = dict() | ||
|
||
current = config | ||
for part in name.split(".")[:-1]: | ||
try: | ||
current = current[part] | ||
except KeyError: | ||
current[part] = dict() | ||
current = current[part] | ||
|
||
current[name.split(".")[-1]] = value | ||
|
||
with open(self.path, "w") as f: | ||
f.write(json.dumps(config)) | ||
|
||
# Delete variable | ||
def __delattr__(self, name): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
except IOError: | ||
config = dict() | ||
|
||
del config[name] | ||
|
||
with open(self.path, "w") as f: | ||
f.write(json.dumps(config)) | ||
def __delitem__(self, name, value): | ||
self.__delattr__(name, value) | ||
|
||
# Delete variable recursively | ||
def remove(self, name): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
except IOError: | ||
config = dict() | ||
|
||
current = config | ||
for part in name.split(".")[:-1]: | ||
try: | ||
current = current[part] | ||
except KeyError: | ||
current[part] = dict() | ||
current = current[part] | ||
|
||
del current[name.split(".")[-1]] | ||
|
||
with open(self.path, "w") as f: | ||
f.write(json.dumps(config)) | ||
|
||
# Get data list | ||
def __dir__(self): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
return dir(config) | ||
except IOError: | ||
return [] | ||
|
||
# Get data list recursively | ||
def list(self): | ||
try: | ||
with open(self.path, "r") as f: | ||
config = json.loads(f.read()) | ||
except IOError: | ||
return [] | ||
|
||
return recursiveDir(config) | ||
|
||
current_dir = os.path.dirname(os.path.abspath(__file__)) | ||
config_json = os.path.abspath(os.path.join(current_dir, "../config.json")) | ||
config = Config(config_json) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
psutil | ||
websocket |
Oops, something went wrong.