Example #1
0
def run_devserver(projectPath=PATH.PROJECT, port=SITE.APP_PORT):
    app.config.update(DEBUG=True)
    if socket.gethostname() == '1bo':
        os.environ['WERKZEUG_DEBUG_PIN'] = 'off'
    with local.cwd(projectPath):
        log.info("serving on http://localhost:%s", port)
        app.run(host='0.0.0.0', port=port)
Example #2
0
    def _execute_tasks(self, tasks: Sequence[Mapping]) -> None:
        """Run the given tasks.

        Arguments:
            tasks: The list of tasks to run.
        """
        for i, task in enumerate(tasks):
            task_cmd = task["task"]
            use_shell = isinstance(task_cmd, str)
            if use_shell:
                task_cmd = self._render_string(task_cmd)
            else:
                task_cmd = [
                    self._render_string(str(part)) for part in task_cmd
                ]
            if not self.quiet:
                print(
                    colors.info
                    | f" > Running task {i + 1} of {len(tasks)}: {task_cmd}",
                    file=sys.stderr,
                )
            with local.cwd(self.subproject.local_abspath), local.env(
                    **task.get("extra_env", {})):
                subprocess.run(task_cmd,
                               shell=use_shell,
                               check=True,
                               env=local.env)
Example #3
0
    def is_dirty(self) -> bool:
        """Indicates if the local template root is dirty.

        Only applicable for VCS-tracked templates.
        """
        if self.vcs == "git":
            with local.cwd(self.local_abspath):
                return bool(git("status", "--porcelain").strip())
        return False
Example #4
0
 def version(self) -> Optional[Version]:
     """PEP440-compliant version object."""
     if self.vcs != "git" or not self.commit:
         return None
     try:
         with local.cwd(self.local_abspath):
             # Leverage dunamai by default; usually it gets best results
             return Version(
                 dunamai.Version.from_git().serialize(style=dunamai.Style.Pep440)
             )
     except ValueError:
         # A fully descripted commit can be easily detected converted into a
         # PEP440 version, because it has the format "<tag>-<count>-g<hash>"
         if re.match(r"^.+-\d+-g\w+$", self.commit):
             base, count, git_hash = self.commit.rsplit("-", 2)
             return Version(f"{base}.dev{count}+{git_hash}")
     # If we get here, the commit string is a tag, so we can safely expect
     # it's a valid PEP440 version
     return Version(self.commit)
Example #5
0
 def commit(self) -> OptStr:
     """If the template is VCS-tracked, get its commit description."""
     if self.vcs == "git":
         with local.cwd(self.local_abspath):
             return git("describe", "--tags", "--always").strip()
Example #6
0
    def run_update(self) -> None:
        """Update a subproject that was already generated.

        See [updating a project][updating-a-project].
        """
        # Check all you need is there
        if self.subproject.vcs != "git":
            raise UserMessageError(
                "Updating is only supported in git-tracked subprojects.")
        if self.subproject.is_dirty():
            raise UserMessageError(
                "Destination repository is dirty; cannot continue. "
                "Please commit or stash your local changes and retry.")
        if self.subproject.template is None or self.subproject.template.ref is None:
            raise UserMessageError(
                "Cannot update because cannot obtain old template references "
                f"from `{self.subproject.answers_relpath}`.")
        if self.template.commit is None:
            raise UserMessageError(
                "Updating is only supported in git-tracked templates.")
        if self.subproject.template.version > self.template.version:
            raise UserMessageError(
                f"Your are downgrading from {self.subproject.template.version} to {self.template.version}. "
                "Downgrades are not supported.")
        # Copy old template into a temporary destination
        with TemporaryDirectory(prefix=f"{__name__}.update_diff.") as dst_temp:
            old_worker = replace(
                self,
                dst_path=dst_temp,
                data=self.subproject.last_answers,
                defaults=True,
                quiet=True,
                src_path=self.subproject.template.url,
                vcs_ref=self.subproject.template.commit,
            )
            old_worker.run_copy()
            # Extract diff between temporary destination and real destination
            with local.cwd(dst_temp):
                subproject_top = git(
                    "-C",
                    self.subproject.local_abspath.absolute(),
                    "rev-parse",
                    "--show-toplevel",
                ).strip()
                git("init", retcode=None)
                git("add", ".")
                git("config", "user.name", "Copier")
                git("config", "user.email", "copier@copier")
                # 1st commit could fail if any pre-commit hook reformats code
                git("commit",
                    "--allow-empty",
                    "-am",
                    "dumb commit 1",
                    retcode=None)
                git("commit", "--allow-empty", "-am", "dumb commit 2")
                git("config", "--unset", "user.name")
                git("config", "--unset", "user.email")
                git("remote", "add", "real_dst", "file://" + subproject_top)
                git("fetch", "--depth=1", "real_dst", "HEAD")
                diff_cmd = git["diff-tree", "--unified=1", "HEAD...FETCH_HEAD"]
                try:
                    diff = diff_cmd("--inter-hunk-context=-1")
                except ProcessExecutionError:
                    print(
                        colors.warn
                        |
                        "Make sure Git >= 2.24 is installed to improve updates.",
                        file=sys.stderr,
                    )
                    diff = diff_cmd("--inter-hunk-context=0")
        # Run pre-migration tasks
        self._execute_tasks(
            self.template.migration_tasks("before", self.subproject.template))
        # Clear last answers cache to load possible answers migration
        with suppress(AttributeError):
            del self.answers
        with suppress(AttributeError):
            del self.subproject.last_answers
        # Do a normal update in final destination
        self.run_copy()
        # Try to apply cached diff into final destination
        with local.cwd(self.subproject.local_abspath):
            apply_cmd = git["apply", "--reject", "--exclude",
                            self.answers_relpath]
            for skip_pattern in chain(self.skip_if_exists,
                                      self.template.skip_if_exists):
                apply_cmd = apply_cmd["--exclude", skip_pattern]
            (apply_cmd << diff)(retcode=None)
        # Run post-migration tasks
        self._execute_tasks(
            self.template.migration_tasks("after", self.subproject.template))