def sync_repo_to_ref(repo_path: Path, ref: str) -> None: ui.info_2("Resetting to", ref) status = tsrc.git.get_status(repo_path) if status.dirty: raise tsrc.Error(f"{repo_path} is dirty, skipping") try: tsrc.git.run(repo_path, "reset", "--hard", ref) except tsrc.Error: raise tsrc.Error("updating ref failed")
def sync_repo_to_ref(repo_path, ref): ui.info_2("Resetting to", ref) status = tsrc.git.get_status(repo_path) if status != "clean": raise tsrc.Error("%s, skipping" % status) try: tsrc.git.run_git(repo_path, "reset", "--hard", ref) except tsrc.Error: raise tsrc.Error("updating ref failed")
def get_gitlab_url(self): manifest = self.load_manifest() gitlab_config = manifest.gitlab if not gitlab_config: raise tsrc.Error("No gitlab configuration found in manifest") res = gitlab_config.get("url") if not res: raise tsrc.Error("Missing 'url' in gitlab configuration") return res
def main(args: argparse.Namespace) -> None: path_as_str = args.workspace_path or os.getcwd() workspace_path = Path(path_as_str) cfg_path = workspace_path / ".tsrc" / "config.yml" if cfg_path.exists(): raise tsrc.Error("Workspace already configured with file " + cfg_path) ui.info_1("Configuring workspace in", ui.bold, workspace_path) workspace_config = WorkspaceConfig( manifest_url=args.url, manifest_branch=args.branch, clone_all_repos=args.clone_all_repos, repo_groups=args.groups, shallow_clones=args.shallow, ) workspace_config.save_to_file(cfg_path) workspace = Workspace(workspace_path) workspace.update_manifest() workspace.clone_missing() workspace.set_remotes() workspace.copy_files() ui.info_2("Workspace initialized") ui.info_2("Configuration written in", ui.bold, workspace.cfg_path)
def run(args: argparse.Namespace) -> None: workspace_path = args.workspace_path or Path.cwd() cfg_path = workspace_path / ".tsrc" / "config.yml" if cfg_path.exists(): raise tsrc.Error( f"Workspace already configured. `{cfg_path}` already exists") ui.info_1("Configuring workspace in", ui.bold, workspace_path) workspace_config = WorkspaceConfig( manifest_url=args.manifest_url, manifest_branch=args.manifest_branch, clone_all_repos=args.clone_all_repos, repo_groups=args.groups or [], shallow_clones=args.shallow_clones, singular_remote=args.singular_remote, ) workspace_config.save_to_file(cfg_path) workspace = Workspace(workspace_path) workspace.update_manifest() manifest = workspace.get_manifest() workspace.repos = repos_from_config(manifest, workspace_config) workspace.clone_missing() workspace.set_remotes() workspace.perform_filesystem_operations() ui.info_2("Workspace initialized") ui.info_2("Configuration written in", ui.bold, workspace.cfg_path)
def run(args: argparse.Namespace) -> None: workspace = get_workspace_with_repos(args) all_ok = True for repo in workspace.repos: full_path = workspace.root_path / repo.dest if not full_path.exists(): ui.info(ui.bold, repo.dest, ": ", ui.red, "error: missing repo", sep="") all_ok = False continue colors = ["green", "reset", "yellow", "reset", "bold blue", "reset"] log_format = "%m {}%h{} - {}%d{} %s {}<%an>{}" log_format = log_format.format(*("%C({})".format(x) for x in colors)) cmd = [ "log", "--color=always", f"--pretty=format:{log_format}", f"{args.from_ref}...{args.to_ref}", ] rc, out = tsrc.git.run_captured(full_path, *cmd, check=False) if rc != 0: all_ok = False if out: ui.info(ui.bold, repo.dest) ui.info(ui.bold, "-" * len(repo.dest)) ui.info(out) if not all_ok: raise tsrc.Error()
def process(self, index: int, count: int, item: tsrc.FileSystemOperation) -> None: ui.info_count(index, count, item) try: item.perform(self.workspace_path) except OSError as e: raise tsrc.Error(str(e))
def clone_repo(self, repo: tsrc.Repo) -> None: """ Clone a missing repo. Note: must use the correct remote(s) and branch when cloning, *and* must reset the repo to the correct state if `tag` or `sha1` were set in the manifest configuration. """ repo_path = self.workspace_path / repo.dest parent, name = repo_path.splitpath() parent.makedirs_p() remote = self._choose_remote(repo) remote_name = remote.name remote_url = remote.url clone_args = ["clone", "--origin", remote_name, remote_url] ref = None if repo.tag: ref = repo.tag elif repo.branch: ref = repo.branch if ref: clone_args.extend(["--branch", ref]) if self.shallow: clone_args.extend(["--depth", "1"]) clone_args.append(name) try: tsrc.git.run(parent, *clone_args) except tsrc.Error: raise tsrc.Error("Cloning failed")
def load_manifest(self): manifest_yml_path = self.manifest_clone_path.joinpath("manifest.yml") if not manifest_yml_path.exists(): message = "No manifest found in {}. Did you run `tsrc init` ?" raise tsrc.Error(message.format(manifest_yml_path)) manifest = tsrc.manifest.Manifest() manifest.load(manifest_yml_path.text()) return manifest
def configure(self, url=None, branch="master", tag=None, groups=None): if not self.cfg_path.exists() and not url: raise tsrc.Error( "manifest URL is required when creating a new workspace") if self.cfg_path.exists() and not url: url = self.load_config()["url"] self._ensure_git_state(url, branch=branch, tag=tag) self.save_config(url=url, branch=branch, tag=tag, groups=groups)
def process(self, repo): ui.info(repo.src) repo_path = self.workspace.joinpath(repo.src) parent, name = repo_path.splitpath() parent.makedirs_p() try: tsrc.git.run_git(parent, "clone", repo.url, "--branch", repo.branch, name) except tsrc.Error: raise tsrc.Error("Cloning failed") ref = repo.fixed_ref if ref: ui.info_2("Resetting", repo.src, "to", ref) try: tsrc.git.run_git(repo_path, "reset", "--hard", ref) except tsrc.Error: raise tsrc.Error("Resetting to", ref, "failed")
def check_shallow_with_sha1(self, repo: tsrc.Repo) -> None: if not repo.sha1: return if self.shallow: message = textwrap.dedent( f"Cannot use --shallow with a fixed sha1 ({repo.sha1})\n" "Consider using a tag instead") raise tsrc.Error(message)
def check_branch(self, repo, repo_path): current_branch = None try: current_branch = tsrc.git.get_current_branch(repo_path) except tsrc.Error: raise tsrc.Error("Not on any branch") if current_branch and current_branch != repo.branch: self.bad_branches.append((repo.src, current_branch, repo.branch))
def _pick_remotes(self, repo: tsrc.Repo) -> List[tsrc.Remote]: if self.remote_name: for remote in repo.remotes: if remote.name == self.remote_name: return [remote] message = f"Remote {self.remote_name} not found for repository {repo.dest}" raise tsrc.Error(message) return repo.remotes
def reset_repo(self, repo: tsrc.Repo) -> None: repo_path = self.workspace_path / repo.src ref = repo.sha1 if ref: ui.info_2("Resetting", repo.src, "to", ref) try: tsrc.git.run(repo_path, "reset", "--hard", ref) except tsrc.Error: raise tsrc.Error("Resetting to", ref, "failed")
def fetch(self, repo: tsrc.Repo) -> None: repo_path = self.workspace_path / repo.src for remote in repo.remotes: try: ui.info_2("Fetching", remote.name) tsrc.git.run(repo_path, "fetch", "--tags", "--prune", remote.name) except tsrc.Error: raise tsrc.Error("fetch from %s failed" % remote.name)
def load(self) -> None: config = self.load_config() if not config.file_path: yml_path = self.clone_path / "manifest.yml" else: yml_path = config.file_path if not yml_path.exists(): message = "No manifest found in {}. Did you run `tsrc init` ?" raise tsrc.Error(message.format(yml_path)) self.manifest = tsrc.manifest.load(yml_path)
def update(self) -> None: ui.info_2("Updating manifest") if not self.clone_path.exists(): message = "Could not find manifest in {}. " message += "Did you run `tsrc init` ?" raise tsrc.Error(message.format(self.clone_path)) cmd = ("fetch", "--prune", "origin") tsrc.git.run(self.clone_path, *cmd) cmd = ("reset", "--hard", "@{upstream}") tsrc.git.run(self.clone_path, *cmd)
def _choose_remote(self, repo: tsrc.Repo) -> tsrc.Remote: if self.remote_name: for remote in repo.remotes: if remote.name == self.remote_name: return remote message = ( f"Remote '{self.remote_name}' not found for repository '{repo.dest}'" ) raise tsrc.Error(message) return repo.remotes[0]
def fetch(self, repo: tsrc.Repo) -> None: repo_path = self.workspace_path / repo.dest for remote in self._pick_remotes(repo): try: ui.info_2("Fetching", remote.name) cmd = ["fetch", "--tags", "--prune", remote.name] if self.force: cmd.append("--force") tsrc.git.run(repo_path, *cmd) except tsrc.Error: raise tsrc.Error(f"fetch from '{remote.name}' failed")
def update_manifest(self): ui.info_2("Updating manifest") if not self.manifest_clone_path.exists(): message = "Could not find manifest in {}. " message += "Did you run `tsrc init` ?" raise tsrc.Error(message.format(self.manifest_clone_path)) cmd = ("fetch", "--prune", "origin") tsrc.git.run_git(self.manifest_clone_path, *cmd) cmd = ("reset", "--hard", "@{u}") tsrc.git.run_git(self.manifest_clone_path, *cmd) return self.load_manifest()
def check_branch(self, repo: tsrc.Repo, repo_path: Path) -> None: current_branch = None try: current_branch = tsrc.git.get_current_branch(repo_path) except tsrc.Error: raise tsrc.Error("Not on any branch") # FIXME: is repo.branch allowed to be None ? if current_branch and current_branch != repo.branch: self.bad_branches.append( # type: ignore (repo.src, current_branch, repo.branch))
def check_branch(self, repo: tsrc.Repo, repo_path: Path) -> None: current_branch = None try: current_branch = tsrc.git.get_current_branch(repo_path) except tsrc.Error: raise tsrc.Error("Not on any branch") if current_branch and current_branch != repo.branch: self.bad_branches.append( RepoAtIncorrectBranchDescription( dest=repo.dest, actual=current_branch, expected=repo.branch ) )
def find_merge_request(self) -> Optional[ProjectMergeRequest]: assert self.remote_branch assert self.project res = self.project.mergerequests.list( state="opened", source_branch=self.remote_branch, all=True ) if len(res) >= 2: raise tsrc.Error("Found more than one opened merge request with the same branch") if not res: return None return res[0]
def process(self, item): src, dest = item ui.info(src, "->", dest) try: src_path = self.workspace.joinpath(src) dest_path = self.workspace.joinpath(dest) if dest_path.exists(): # Re-set the write permissions on the file: dest_path.chmod(stat.S_IWRITE) src_path.copy(dest_path) # Make sure perms are read only for everyone dest_path.chmod(0o10444) except Exception as e: raise tsrc.Error(str(e))
def find_workspace_path() -> Path: """ Look for a workspace root somewhere in the upper directories hierarchy """ head = os.getcwd() tail = "a truthy string" while tail: tsrc_path = os.path.join(head, ".tsrc") if os.path.isdir(tsrc_path): return Path(head) else: head, tail = os.path.split(head) raise tsrc.Error("Could not find current workspace")
def process(self, repo): full_path = self.workspace.joinpath(repo.src) try: _, old_url = tsrc.git.run_git(full_path, "remote", "get-url", "origin", raises=False) if old_url != repo.url: ui.info_2(repo.src, old_url, "->", repo.url) tsrc.git.run_git(full_path, "remote", "set-url", "origin", repo.url) except Exception: raise tsrc.Error(repo.src, ":", "Failed to set remote url to %s" % repo.url)
def find_workspace_path() -> Path: """ Find the workspace path when not specified on the command line. """ # Walk up the file system hierarchy until a `.tsrc` directory is found head = os.getcwd() tail = "a truthy string" while tail: tsrc_path = os.path.join(head, ".tsrc") if os.path.isdir(tsrc_path): return Path(head) else: head, tail = os.path.split(head) raise tsrc.Error("Could not find current workspace")
def process(self, index: int, count: int, item: tsrc.Copy) -> None: known_sources = {x.src for x in self.repos} if item.repo not in known_sources: return ui.info_count(index, count, item.src, "->", item.dest) try: src_path = self.workspace_path / item.repo / item.src dest_path = self.workspace_path / item.dest if dest_path.exists(): # Re-set the write permissions on the file: dest_path.chmod(stat.S_IWRITE) src_path.copy(dest_path) # Make sure perms are read only for everyone dest_path.chmod(0o10444) except Exception as e: raise tsrc.Error(str(e))
def find_workspace_path(): """ Look for a workspace root somewhere in the upper directories hierarchy """ head = os.getcwd() tail = True while tail: tsrc_path = os.path.join(head, ".tsrc") if os.path.isdir(tsrc_path): return path.Path(head) tbuild_yml_path = os.path.join(head, "tbuild.yml") if os.path.exists(tbuild_yml_path): return path.Path(head) else: head, tail = os.path.split(head) raise tsrc.Error("Could not find current workspace")