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)
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)
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
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)
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()
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))