Ejemplo n.º 1
0
    def _generate_file(self):
        """Decrypts the first file in :attr:`self.sources<dyanmicfile.sources>`
        using gpg.

        Returns:
            bytearray: The content of the decrypted file
        """
        # Get sources and temp file
        encryped_file = self.sources[0]
        tmp = os.path.join(self.getdir(), self.name)
        # Set arguments for OpenPGP
        args = ["gpg", "-q", "-d", "--yes"]
        strargs = " ".join(args)
        if constants.DECRYPT_PWD:
            args += ["--batch", "--passphrase", constants.DECRYPT_PWD]
            strargs += " " + " ".join(args[-3:-1]) + " "
            strargs += "*" * len(constants.DECRYPT_PWD)
        else:
            log("Tipp: You can set a password in uberdots " +
                "config that will be used for all encrypted files.")
        args += ["-o", tmp, encryped_file]
        strargs += " " + " ".join(args[-3:])
        log_debug("Invoking OpenPGP with '" + strargs + "'")
        # Use OpenPGP to decrypt the file
        process = Popen(args, stdin=PIPE)
        process.communicate()
        # Remove the decrypted file. It will be written by the update function
        # of the super class to its correct location.
        result = open(tmp, "rb").read()
        os.remove(tmp)
        return result
Ejemplo n.º 2
0
 def handle_custom_error(err):
     # An error occured that we (more or less) expected.
     # Print error, a stacktrace and exit
     if isinstance(err, FatalError):
         logger.critical(traceback.format_exc())
         logger.critical(err.message + "\n")
     else:
         log_debug(traceback.format_exc())
         log_error(err.message)
     sys.exit(err.EXITCODE)
Ejemplo n.º 3
0
    def getdir(self):
        """Gets the path of the directory that is used to store the generated
        file.

        Returns:
            str: The path to the directory
        """
        path = normpath(os.path.join(constants.DATA_DIR, self.SUBDIR))
        # Create dir if it doesn't exist
        if not os.path.isdir(path):
            log_debug("Creating directory '" + path + "'")
            os.mkdir(path)
        return path
Ejemplo n.º 4
0
 def update(self):
     """Generates the newest version of the file and writes it
     if it is not in its subdir yet."""
     # Generate file and calc checksum
     file_bytes = self._generate_file()
     self.md5sum = md5(file_bytes)
     # If this version of the file (with same checksum) doesn't exist,
     # write it to the correct location
     if not os.path.isfile(self.getpath()):
         log_debug("Writing dynamic file '" + self.getpath() + "'.")
         file = open(self.getpath(), "wb")
         file.write(file_bytes)
         file.flush()
         # Also create a backup that can be used to restore the original
         copyfile(self.getpath(),
                  self.getpath() + "." + constants.BACKUP_EXTENSION)
Ejemplo n.º 5
0
    def load_installed(self):
        """Reads the installed-file and parses it's content into
        :attr:`self.installed<UberDot.installed>`.

        Raises:
            :class:`~errors.PreconditionError`: uberdot and installed-file
                aren't version compatible.
        """
        try:
            self.installed = json.load(open(constants.INSTALLED_FILE))
        except FileNotFoundError:
            log_debug("No installed profiles found.")
        # Check installed-file version
        if (int(self.installed["@version"].split("_")[1]) != int(
                constants.VERSION.split("_")[1])):
            msg = "There was a change of the installed-file schema "
            msg += "with the last update. Please revert to version "
            msg += self.installed["@version"] + " and uninstall "
            msg += "all of your profiles before using this version."
            raise PreconditionError(msg)
Ejemplo n.º 6
0
    def generator(self):
        """This is the wrapper for :func:`generate()`. It overwrites the
        builtins and maps it own commands to them. :func:`generate()` must not
        be called without this wrapper.

        .. warning:: Do NOT call this from within the same profile, only
            from outside!!

        Returns:
            dict: The result dictionary :attr:`self.result<Profile.result>`
        """
        if self.executed:
            self._gen_err("A profile can be only generated " +
                          "one time to prevent side-effects!")
        self.executed = True
        self.__set_builtins()
        try:
            log_debug("Generating event scripts for profile '" + self.name +
                      "'.")
            self.__generate_scripts()
            log_debug("Generating profile '" + self.name + "'.")
            self.generate()
            log_debug("Successfully generated profile '" + self.name + "'.")
        except Exception as err:
            if isinstance(err, CustomError):
                raise
            msg = "An unkown error occured in your generate() function: "
            self._gen_err(msg + type(err).__name__ + ": " + str(err))
        finally:
            self.__reset_builtins()
        return self.result
Ejemplo n.º 7
0
    def dryrun(self, difflog):
        """Like `run()` but instead of resolving it it will be just printed out

        Args:
            difflog (DiffLog): The DiffLog that will be checked

        Raises:
            :class:`~errors.CustomError`: Executed interpreters can and will
                raise all kinds of :class:`~errors.CustomError`.
        """
        log_warning("This is just a dry-run! Nothing of the following " +
                    "is actually happening.")
        # Run tests
        log_debug("Checking operations for errors and conflicts.")
        difflog.run_interpreter(
            CheckProfilesInterpreter(self.installed, self.args.parent))
        tests = [
            CheckLinksInterpreter(self.installed),
            CheckLinkBlacklistInterpreter(self.args.superforce),
            CheckLinkDirsInterpreter(self.args.makedirs),
            CheckLinkExistsInterpreter(self.args.force),
            CheckDynamicFilesInterpreter(True)
        ]
        difflog.run_interpreter(*tests)
        log_debug("Checking if root would be needed")
        difflog.run_interpreter(RootNeededInterpreter())
        # Simulate events before
        if not self.args.skipevents and not self.args.skipbefore:
            difflog.run_interpreter(
                EventPrintInterpreter(self.profiles, self.installed, "before"))
        # Simulate execution
        difflog.run_interpreter(PrintInterpreter())
        # Simulate events after
        if not self.args.skipevents and not self.args.skipafter:
            difflog.run_interpreter(
                EventPrintInterpreter(self.profiles, self.installed, "after"))
Ejemplo n.º 8
0
 def execute_arguments(self):
     """Executes whatever was specified via commandline arguments."""
     # Check which mode, then run it
     if self.args.show:
         self.print_installed_profiles()
     elif self.args.version:
         print(constants.BOLD + "Version: " + constants.ENDC +
               constants.VERSION)
     elif self.args.debuginfo:
         self.print_debuginfo()
     else:
         # The above are modes that just print stuff, but here we
         # have to actually do something:
         # 1. Decide how to solve the differences
         if self.args.uninstall:
             dfs = UninstallDiffSolver(self.installed, self.args.profiles)
         elif self.args.install:
             self.execute_profiles()
             profile_results = [p.result for p in self.profiles]
             dfs = UpdateDiffSolver(self.installed, profile_results,
                                    self.args.parent)
         # elif TODO history resolve...
         else:
             raise FatalError("None of the expected modes were set")
         # 2. Solve differences
         log_debug("Calculate operations for linking process.")
         dfl = dfs.solve()
         # 3. Eventually manipulate the result
         if self.args.dui:
             log_debug("Reordering operations according to --dui.")
             dfl.run_interpreter(DUIStrategyInterpreter())
         if self.args.skiproot:
             log_debug("Removing operations that require root.")
             dfl.run_interpreter(SkipRootInterpreter())
         # 4. Simmulate a run, print the result or actually resolve the
         # differences
         if self.args.dryrun:
             self.dryrun(dfl)
         elif self.args.plain:
             dfl.run_interpreter(PlainPrintInterpreter())
         elif self.args.print:
             dfl.run_interpreter(PrintInterpreter())
         else:
             self.run(dfl)
Ejemplo n.º 9
0
        def gen_script(event_name, script):
            def get_prepare_scripts(profile=self, profilename=self.name):
                result = ""
                # First check if prepare_script is available and is a string
                if profile.prepare_script is not None:
                    if isinstance(profile.prepare_script, str):
                        # Save prepare_script as result
                        result = profile.prepare_script
                    else:
                        self._gen_err("prepare_script of " + profilename +
                                      " needs to be a string.")
                # Prepend prepare_scripts of parents to result
                if profile.parent is not None:
                    result = get_prepare_scripts(profile.parent,
                                                 profilename) + result
                return result

            # Change dir automatically if enabled and the main script doesn't
            # start with a cd command
            if constants.SMART_CD:
                if not script.strip().startswith("cd "):
                    script = "\ncd " + self.directory + "\n" + script
            # Prepend prepare_scripts
            script = get_prepare_scripts() + "\n" + script
            # Prettify script a little bit
            pretty_script = ""
            start = 0
            end = 0
            i = 0
            for line in script.splitlines():
                line = line.strip()
                if line:
                    if start == 0:
                        start = i
                    end = i
                pretty_script += line + "\n"
                i += 1
            # Remove empty lines at beginning and end of script
            pretty_script = "\n".join(pretty_script.splitlines()[start:end +
                                                                 1])
            # Build path where the script will be stored
            script_dir = os.path.join(constants.DATA_DIR, "scripts")
            if not os.path.exists(script_dir):
                os.mkdir(script_dir)
            script_name = self.name + "_" + event_name
            script_path = script_dir + "/" + script_name
            script_path += "_" + md5(pretty_script) + ".sh"
            # Write new script to file
            if not os.path.exists(script_path):
                try:
                    script_file = open(script_path, "w")
                    script_file.write(pretty_script)
                    script_file.close()
                except IOError:
                    self._gen_err("Could not write file '" + script_path + "'")
                log_debug("Generated script '" + script_path + "'")
            # Create symlink for easy access of latest generated script for event
            link_path = script_dir + "/" + script_name
            if os.path.exists(link_path):
                os.remove(link_path)
            os.symlink(script_path, link_path)
Ejemplo n.º 10
0
    def run(self, difflog):
        """Performs checks on DiffLog and resolves it.

        Furthermore this function handles backups, converts exceptions into
        UnkownErrors and might replace the entire process when uberdot was
        started with insufficient permissions.

        Args:
            difflog (DiffLog): The DiffLog that will be resolved.

        Raises:
            :class:`~errors.UnkownError`: All exceptions that are no
                :class:`~errors.CustomError` and occured in the critical
                section will be converted to this error.
            :class:`~errors.CustomError`: Executed interpreters can and will
                raise all kinds of :class:`~errors.CustomError`.
        """
        # Run integration tests on difflog
        log_debug("Checking operations for errors and conflicts.")
        difflog.run_interpreter(
            CheckProfilesInterpreter(self.installed, self.args.parent))
        tests = [
            CheckLinksInterpreter(self.installed),
            CheckLinkDirsInterpreter(self.args.makedirs),
            CheckLinkExistsInterpreter(self.args.force),
            CheckDynamicFilesInterpreter(False)
        ]
        difflog.run_interpreter(*tests)
        # Gain root if needed
        if not has_root_priveleges():
            log_debug("Checking if root is needed")
            difflog.run_interpreter(GainRootInterpreter())
        else:
            log_debug("uberdot was started with root priveleges")
        # Check blacklist not until now, because the user would need confirm it
        # twice if the programm is restarted with sudo
        difflog.run_interpreter(
            CheckLinkBlacklistInterpreter(self.args.superforce))
        # Now the critical part begins, devided into three main tasks:
        # 1. running events before, 2. linking, 3. running events after
        # Each part is surrounded with a try-catch block that wraps every
        # exception which isn't a CustomError into UnkownError and reraises them
        # to handle them in the outer pokemon handler
        old_installed = dict(self.installed)
        # Execute all events before linking and print them
        try:
            if not self.args.skipevents and not self.args.skipbefore:
                difflog.run_interpreter(
                    EventExecInterpreter(self.profiles, old_installed,
                                         "before"))
                try:
                    # We need to run those tests again because the executed event
                    # might have f****d with some links or dynamic files
                    difflog.run_interpreter(
                        CheckLinkExistsInterpreter(self.args.force),
                        CheckDynamicFilesInterpreter(False))
                except CustomError as err:
                    # We add some additional information to the raised errors
                    err._message += "This error occured because at least one of "
                    err._message += "the previously executed events interfered "
                    err._message += "with files that are defined by a profile."
                    raise err
        except CustomError:
            raise
        except Exception as err:
            msg = "An unkown error occured during before_event execution."
            raise UnkownError(err, msg)
        # Execute operations from difflog
        try:
            # Create Backup in case something wents wrong,
            # so the user can fix the mess we caused
            if os.path.isfile(constants.INSTALLED_FILE):
                shutil.copyfile(constants.INSTALLED_FILE,
                                constants.INSTALLED_FILE_BACKUP)
            # Apply difflog operations and print them simultaneously
            difflog.run_interpreter(
                ExecuteInterpreter(self.installed, self.args.force),
                PrintInterpreter())
            # Remove Backup
            if os.path.isfile(constants.INSTALLED_FILE_BACKUP):
                os.remove(constants.INSTALLED_FILE_BACKUP)
            log_success("Updated links successfully.")
        except CustomError:
            raise
        except Exception as err:
            msg = "An unkown error occured during linking/unlinking. Some "
            msg += "links or your installed-file may be corrupted! Check the "
            msg += "backup of your installed-file to resolve all possible "
            msg += "issues before you proceed to use this tool!"
            raise UnkownError(err, msg)
        # Execute all events after linking and print them
        try:
            if not self.args.skipevents and not self.args.skipafter:
                difflog.run_interpreter(
                    EventExecInterpreter(self.profiles, old_installed,
                                         "after"))
        except CustomError:
            raise
        except Exception as err:
            msg = "An unkown error occured during after_event execution."
            raise UnkownError(err, msg)