Пример #1
0
 def list(self):
     """ Get the list of files from the workspace. """
     p = Path(self.console.config['WORKSPACE']).expanduser()
     for f in p.walk(filter_func=lambda p: p.is_file(), relative=True):
         if all(not re.match(x, f.filename)
                for x in ["(data|key|store)\.db.*", "history"]):
             yield f
Пример #2
0
 def start(self, filename, overwrite=False):
     """ Start the recorder, creating the record file. """
     self.__file = f = Path(filename)
     if f.suffix != ".rc":
         self.__file = f = Path(self.root_dir).joinpath(filename + ".rc")
     if not overwrite and f.exists():
         raise OSError("File already exists")
     f.reset()
Пример #3
0
 def edit(self, filename):
     """ Edit a file using the configured text editor. """
     #FIXME: edit by calling the locator and manage its local file (e.g. for a URL, point to a temp folder)
     ted = self.console.config['TEXT_EDITOR']
     if which(ted) is None:
         raise ValueError("'%s' does not exist or is not installed" % ted)
     p = Path(self.console.config['WORKSPACE']).joinpath(filename)
     if not p.exists():
         p.touch()
     call([ted, str(p)], stderr=PIPE)
Пример #4
0
 def run(self, project):
     self.logger.debug("Loading archive '{}'...".format(project + ".zip"))
     projpath = Path(self.workspace).joinpath(project)
     archive = ProjectPath(projpath.with_suffix(".zip"))
     ask = self.console.config.option("ENCRYPT_PROJECT").value
     try:
         archive.load(ask=ask)
         self.logger.success("'{}' loaded".format(project))
     except Exception as e:
         logger.error("Bad password" if "error -3" in str(e) else str(e))
         self.logger.failure("'{}' not loaded".format(project))
Пример #5
0
 def __init__(self, n, cmd, **kwargs):
     self.id = n
     self.parent = kwargs.pop('parent')
     if isinstance(cmd, str):
         cmd = shlex.split(cmd)
     self._path = Path(self.parent.console._files.tempdir,
                       "session",
                       str(n),
                       create=True)
     for i, s in enumerate(["stdin", "stdout", "stderr"]):
         fifo = str(self._path.joinpath(str(i)))
         self._named_pipes.append(fifo)
         os.mkfifo(fifo, 0o777)
         setattr(self, "_" + s, os.open(fifo, os.O_WRONLY))
Пример #6
0
 def __new__(meta, name, bases, clsdict):
     subcls = type.__new__(meta, name, bases, clsdict)
     # compute module's path from its root folder if no path attribute defined on its class
     if not hasattr(subcls, "path") or subcls.path is None:
         p = Path(getfile(subcls)).parent
         # collect the source temporary attribute
         s = getattr(subcls, "_source", ".")
         try:
             subcls.path = str(p.relative_to(Path(s)))
         except ValueError:
             subcls.path = None
     # then pass the subclass with its freshly computed path attribute to the original __new__ method, for
     #  registration in subclasses and in the list of modules
     super(MetaModule, meta).__new__(meta, name, bases, clsdict, subcls)
     return subcls
Пример #7
0
class Session(object):
    """ Class representing a session object based on a shell command """
    def __init__(self, n, cmd, **kwargs):
        self.id = n
        self.parent = kwargs.pop('parent')
        if isinstance(cmd, str):
            cmd = shlex.split(cmd)
        self._path = Path(self.parent.console._files.tempdir,
                          "session",
                          str(n),
                          create=True)
        for i, s in enumerate(["stdin", "stdout", "stderr"]):
            fifo = str(self._path.joinpath(str(i)))
            self._named_pipes.append(fifo)
            os.mkfifo(fifo, 0o777)
            setattr(self, "_" + s, os.open(fifo, os.O_WRONLY))

    def close(self):
        for s in ["stdin", "stdout", "stderr"]:
            getattr(self, "_" + s).close()
        shutil.rmtree(str(self._path))
        self._process.wait()
        del self.parent[self.id]

    def start(self, **kwargs):
        kwargs['close_fds'] = True
        kwargs[
            'preexec_fn'] = os.setsid  # NB: see subprocess' doc ; preexec_fn is not thread-safe
        self._process = Popen(cmd,
                              stdout=self._stdout,
                              stderr=self._stderr,
                              stdin=self._stdin,
                              **kwargs)
Пример #8
0
 def value(self):
     """ Normalized value attribute. """
     value = self.input
     if self.required and value is None:
         raise ValueError("{} must be defined".format(self.name))
     try:  # try to expand format variables using console's attributes
         kw = {}
         for n in re.findall(r'\{([a-z]+)\}', str(value)):
             kw[n] = self.config.console.__dict__.get(n, "")
         try:
             value = value.format(**kw)
         except:
             pass
     except AttributeError as e:  # occurs when console is not linked to config (i.e. at startup)
         pass
     # expand and resolve paths
     if self.name.endswith("FOLDER") or self.name.endswith("WORKSPACE"):
         # this will ensure that every path is expanded
         value = str(Path(value, expand=True))
     # convert common formats to their basic types
     try:
         if value.isdigit():
             value = int(value)
         if value.lower() in ["false", "true"]:
             value = value.lower() == "true"
     except AttributeError:  # occurs e.g. if value is already a bool
         pass
     # then try to transform using the user-defined function
     if isinstance(self.transform,
                   type(lambda: 0)) and self.transform.__name__ == (
                       lambda: 0).__name__:
         value = self.transform(value)
     return value
Пример #9
0
 def __init__(self, appname=None, *args, **kwargs):
     Console.appname = appname or getattr(self, "appname", Console.appname)
     o, v = self.config.option('APP_FOLDER'), str(self.config['APP_FOLDER'])
     self.config[o] = Path(v.format(appname=self.appname.lower()))
     o.old_value = None
     self._set_app_folder()
     self._set_workspace()
     super(FrameworkConsole, self).__init__(*args, **kwargs)
Пример #10
0
 def run(self, key, rcfile=None):
     if key == "start":
         self.recorder.start(str(Path(self.workspace).joinpath(rcfile)))
     elif key == "stop":
         self.recorder.stop()
     elif key == "status":
         self.logger.info("Recording is {}".format(
             ["disabled", "enabled"][self.recorder.enabled]))
Пример #11
0
 def validate(self, key, rcfile=None):
     if key == "start":
         if rcfile is None:
             raise ValueError("please enter a filename")
         if Path(self.workspace).joinpath(rcfile).exists():
             raise ValueError("a file with the same name already exists")
     elif key in ["stop", "status"]:
         if rcfile is not None:
             raise ValueError("this key takes no value")
Пример #12
0
 def _sources(self, items):
     """ Return the list of sources for the related items [banners|entities|libraries], first trying subclass' one
          then Console class' one. Also, resolve paths relative to the path where the parent Console is found. """
     src = self.sources.get(items, Console.sources[items])
     if isinstance(src, (str, Path)):
         src = [src]
     return [
         Path(self._root.dirname.joinpath(s).expanduser().resolve())
         for s in (src or [])
     ]
Пример #13
0
 def __init__(self, appname=None, *args, **kwargs):
     Console._dev_mode = kwargs.pop("dev", False)
     Console.appname = appname or getattr(self, "appname", Console.appname)
     o, v = self.config.option('APP_FOLDER'), str(self.config['APP_FOLDER'])
     self.config[o] = Path(v.format(appname=self.appname.lower()))
     o.old_value = None
     self.config['DEBUG'] = kwargs.get('debug', False)
     self._set_app_folder(silent=True, **kwargs)
     self._set_workspace()
     super(FrameworkConsole, self).__init__(*args, **kwargs)
Пример #14
0
 def page(self, *filenames):
     """ Page a list of files using Less. """
     tvw = self.console.config['TEXT_VIEWER']
     if which(tvw) is None:
         raise ValueError("'%s' does not exist or is not installed" % tvw)
     filenames = list(map(str, filenames))
     for f in filenames:
         if not Path(str(f)).is_file():
             raise OSError("File does not exist")
     call([tvw] + filenames, stderr=PIPE)
Пример #15
0
 def run(self, key, value=None):
     if key == "files":
         if value is None:
             data = [["Path", "Size"]]
             p = Path(self.config.option("WORKSPACE").value)
             for f in self.console._files.list:
                 data.append([f, human_readable_size(p.joinpath(f).size)])
             print_formatted_text(
                 BorderlessTable(data, "Files from the workspace"))
         elif self.config.option("TEXT_VIEWER").value:
             self.console._files.view(value)
     elif key == "issues":
         t = Entity.get_issues()
         if len(t) > 0:
             print_formatted_text(t)
     elif key == "modules":
         h = Module.get_help(value)
         if h.strip() != "":
             print_formatted_text(h)
         else:
             self.logger.warning("No module loaded")
     elif key == "options":
         if value is None:
             print_formatted_text(ANSI(str(self.config)))
         else:
             c = Config()
             c[self.config.option(value)] = self.config[value]
             print_formatted_text(ANSI(str(c)))
     elif key == "projects":
         if value is None:
             data = [["Name"]]
             for p in projects(self):
                 data.append([p])
             print_formatted_text(BorderlessTable(data,
                                                  "Existing projects"))
         else:
             print_formatted_text(value)
     elif key == "sessions":
         data = [["ID", "Description"]]
         for i, s in self.console._sessions:
             data.append([str(i), getattr(s, "description", "<undefined>")])
             print_formatted_text(BorderlessTable(data, "Open sessions"))
Пример #16
0
 def run(self, project):
     projpath = Path(self.workspace).joinpath(project)
     folder = ProjectPath(projpath)
     self.logger.debug("Archiving project '{}'...".format(project))
     ask = self.console.config.option("ENCRYPT_PROJECT").value
     try:
         folder.archive(ask=ask)
         self.logger.success("'{}' archived".format(project))
     except OSError as e:
         logger.error(str(e))
         self.logger.failure("'{}' not archived".format(project))
Пример #17
0
 def identifier(self):
     """ Compute a unique identifier for this entity subclass. """
     f = Path(getattr(self, "__file__", getfile(self)))
     d, fn = f.dirname, f.filename
     if len(d.parts) > 0 and d.parts[-1] == "__pycache__":
         parts = fn.split(".")
         if re.match(r".?python\-?[23]\d", parts[-2]):
             parts.pop(-2)
         parts[-1] = "py"
         f = d.parent.joinpath(".".join(parts))
     return str(f), self.__name__
Пример #18
0
 def __init__(self, parent=None, **kwargs):
     fail = kwargs.pop("fail", True)
     super(Console, self).__init__()
     # determine the relevant parent
     self.parent = parent
     if self.parent is not None and self.parent.level == self.level:
         while parent is not None and parent.level == self.level:
             parent = parent.parent  # go up of one console level
         # raise an exception in the context of command's .run() execution, to be propagated to console's .run()
         #  execution, setting the directly higher level console in argument
         raise ConsoleDuplicate(self, parent)
     # back-reference the console
     self.config.console = self
     # configure the console regarding its parenthood
     if self.parent is None:
         if Console.parent is not None:
             raise Exception("Only one parent console can be used")
         Console.parent = self
         Console.parent._start_time = datetime.now()
         Console.appdispname = Console.appname
         Console.appname = Console.appname.lower()
         self._root = Path(getfile(self.__class__)).resolve()
         self.__init(**kwargs)
     else:
         self.parent.child = self
     # reset commands and other bound stuffs
     self.reset()
     # setup the session with the custom completer and validator
     completer, validator = CommandCompleter(), CommandValidator(fail)
     completer.console = validator.console = self
     message, style = self.prompt
     self._session = PromptSession(
         message,
         completer=completer,
         history=FileHistory(
             Path(self.config.option("WORKSPACE").value).joinpath(
                 "history")),
         validator=validator,
         style=Style.from_dict(style),
     )
     CustomLayout(self)
Пример #19
0
 def view(self, key):
     """ View a file using the configured text viewer. """
     try:
         self.page_text(self[key])
     except KeyError:
         pass
     p = Path(self.console.config['WORKSPACE'], expand=True).joinpath(key)
     if p.suffix == ".md":
         self.page_text(txt_terminal_render(p.text, format="md").strip())
     else:
         # if the given key is not in the dictionary of files (APP_FOLDER/files/), it can still be in the workspace
         self.page(p)
Пример #20
0
 def run(self, project):
     p = self.workspace.joinpath(project)
     loader = Load()
     if project in loader.complete_values() and confirm(
             "An archive with this name already exists ; "
             "do you want to load the archive instead ?"):
         loader.run(project)
     if not p.exists():
         self.logger.debug("Creating project '{}'...".format(project))
         p.mkdir()
         self.logger.success("'{}' created".format(project))
     ProjectConsole(self.console, project).start()
     self.config['WORKSPACE'] = str(Path(self.config['WORKSPACE']).parent)
Пример #21
0
 def __set_folder(self, option, subpath=""):
     """ Set a new folder, moving an old to the new one if necessary. """
     o = self.config.option(option)
     old, new = o.old_value, o.value
     if old == new:
         return
     try:
         if old is not None:
             os.rename(old, new)
     except Exception as e:
         pass
     Path(new).joinpath(subpath).mkdir(parents=True, exist_ok=True)
     return new
Пример #22
0
 def reset(self):
     """ Setup commands for the current level, reset bindings between commands and the current console then update
          store's object. """
     self.detach("command")
     # setup level's commands, starting from general-purpose commands
     self.commands = {}
     # add commands
     for n, c in chain(
             Command.commands.get("general", {}).items(),
             Command.commands.get(self.level, {}).items()):
         self.attach(c)
         if self.level not in getattr(c, "except_levels", []) and c.check():
             self.commands[n] = c
         else:
             self.detach(c)
     root = self.config.option('WORKSPACE').value
     # get the relevant store and bind it to loaded models
     Console.store = Console._storage.get(Path(root).joinpath("store.db"))
     # update command recorder's root directory
     self._recorder.root_dir = root
Пример #23
0
 def unregister_commands(cls, *identifiers):
     """ Unregister items from Command based on their 'identifiers' (functionality or level/name). """
     for i in identifiers:
         _ = i.split("/", 1)
         try:
             l, n = _           # level, name
         except ValueError:
             f, n = _[0], None  # functionality
         # apply deletions
         if n is None:
             if f not in cls._functionalities:
                 raise ValueError("Unknown functionality {}".format(f))
             p = Path(__file__).parent.joinpath("../base/commands/" + f + ".py").resolve()
             for c in PythonPath(str(p)).get_classes(Command):
                 Command.unregister_command(c)
         else:
             try:
                 c = Command.commands[l][n]
                 Command.unregister_command(c)
             except KeyError:
                 pass
Пример #24
0
 def subpath(self):
     """ First child path of the module. """
     return str(Path(self.path).child)
Пример #25
0
 def fullpath(self):
     """ Full path of the module, that is, its path joined with its name. """
     return str(Path(self.path).joinpath(self.name))
Пример #26
0
 def category(self):
     """ Module's category. """
     try:
         return str(Path(self.path).parts[0])
     except IndexError:
         return ""
Пример #27
0
 def base(self):
     """ Module's category. """
     return str(Path(
         self.fullpath).child) if self.category != "" else self.name
Пример #28
0
 def complete_values(self, key):
     if key.upper() == "WORKSPACE":
         return [str(x) for x in Path(".").home().iterpubdir()]
     return self.config.option(key).choices or []
Пример #29
0
 def run(self):
     h = Path(self.config.option("WORKSPACE").value).joinpath("history")
     self.console._files.page(str(h))
Пример #30
0
 def run(self, filename):
     f = Path(self.config.option("WORKSPACE").value).joinpath(filename)
     self.console._files.edit(str(f))