def git_rev_parse(object_name, abbrev_ref=None, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Add a new remote to the Git sandbox" cmd_args = ["git", "rev-parse"] if abbrev_ref is not None: if abbrev_ref is True: cmd_args.append("--abbrev-ref") elif abbrev_ref in ("strict", "loose"): cmd_args.append("--abbrev-ref=%s" % abbrev_ref) else: raise GitException("Bad mode \"%s\" for --abbrev-ref" % (abbrev_ref, )) cmd_args.append(object_name) rev_hash = None for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:3]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): if rev_hash is not None: if sandbox_dir is None: sandbox_dir = "." raise Exception("Found multiple hash values for \"%s\" in %s" % (object_name, sandbox_dir)) rev_hash = line.rstrip() return rev_hash
def git_submodule_status(sandbox_dir=None, debug=False, dry_run=False, verbose=False): """ Return tuples describing the status of this Git project's submodules. Each tuple contains (name, status, sha1, branchname) """ cmd_args = ["git", "submodule", "status"] stat_pat = re.compile(r"^(.)(\S+)\s+([^(]+)(?:\s+\((.*)\))?\s*$") for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): mtch = stat_pat.match(line) if mtch is None: print("WARNING: Ignoring unknown SUBMODULE STATUS line %s" % (line, ), file=sys.stderr) continue # unpack the groups into named variables and return them in a # slightly shuffled order (status, sha1, name, branchname) = mtch.groups() if status not in SUB_ALL: raise GitException("Unknown submodule status \"%s\" in \"%s\"" % (status, line.rstrip())) yield (name, status, sha1, branchname)
def git_ls_files(filelist=None, list_option=None, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Remove the specified files/directories from the GIT commit index" if list_option is not None: if list_option not in LIST_OPTIONS: raise GitException("Bad list option \"--%s\"" % (list_option, )) flag = "--%s" % (list_option, ) elif filelist is None or len(filelist) == 0: raise GitException("No files specified") else: flag = "-r" if filelist is None: cmd_args = ["git", "ls-files", flag] elif isinstance(filelist, (tuple, list)): cmd_args = ["git", "ls-files", flag] + filelist else: cmd_args = ("git", "ls-files", flag, unicode(filelist)) for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, stderr_handler=__handle_generic_stderr, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def git_list_branches(sandbox_dir=None, debug=False, dry_run=False, verbose=False): """ Return a list of all branches, where the first element is the default branch """ cmd_args = ("git", "branch", "--list") branches = [] default_branch = None for line in run_generator(cmd_args, cmdname="GIT CURRENT_BRANCH", working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): branch_name = line.rstrip() if branch_name.startswith("*"): default_branch = branch_name[1:].strip() else: branches.append(branch_name.strip()) if default_branch is None: print("WARNING: No default branch found in %s" % (sandbox_dir, ), file=sys.stderr) else: branches.insert(0, default_branch) return branches
def git_show_ref(sandbox_dir=None, debug=False, dry_run=False, verbose=False): cmd_args = ["git", "show-ref"] heads = {} tags = {} remotes = {} for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): line = line.rstrip() flds = line.split() if len(flds) != 2 or not flds[1].startswith("refs/"): print("Bad 'show-ref' line: %s" % (line, ), file=sys.stderr) continue # remember the hash for this reference git_hash = flds[0] # break reference into pieces ref_flds = flds[1].split("/") if ref_flds[1] == "heads": heads[ref_flds[2]] = git_hash elif ref_flds[1] == "tags": tags[ref_flds[2]] = git_hash elif ref_flds[1] == "remotes": remotes["/".join(ref_flds[2:])] = git_hash else: print("ERROR: Unknown reference \"%s\"" % (flds[1], ), file=sys.stderr) return heads, tags, remotes
def git_log(sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Return the log entries for the sandbox" cmd_args = ("git", "log") for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def git_remote_add(remote_name, url, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Add a new remote to the Git sandbox" cmd_args = ("git", "remote", "add", remote_name, url) for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:3]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def git_show_hash(sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Return the full hash of the current Git sandbox" handler = ShowHashHandler() for no_patch in True, False: cmd_args = ["git", "show", "--format=%H"] if no_patch and ShowHashHandler.NO_PATCH_SUPPORTED: cmd_args.append("--no-patch") handler.clear_no_patch_error() full_hash = None for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, returncode_handler=handler.handle_rtncode, stderr_handler=handler.handle_stderr, stderr_finalizer=handler.finalize_stderr, debug=debug, dry_run=dry_run, verbose=verbose): line = line.rstrip() if line == "": continue if line.startswith("fatal: ") and line.find("--no-patch") > 0: break if full_hash is None: full_hash = line.rstrip() continue if line.startswith("diff "): break raise GitException("Found multiple lines:\n%s\n%s" % (full_hash, line.rstrip())) if full_hash is not None: break if full_hash is None: raise GitException("Cannot find full hash from 'git show %s'" %\ (sandbox_dir, )) return full_hash
def git_status(sandbox_dir=None, porcelain=False, debug=False, dry_run=False, verbose=False): "Return the lines describing the status of the Git sandbox" cmd_args = ["git", "status"] if porcelain: cmd_args.append("--porcelain") for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def git_diff(unified=False, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Return a list of changes to all files" cmd_args = ["git", "diff"] if unified: cmd_args.append("-U") for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, stderr_handler=__handle_generic_stderr, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def git_config(name, value=None, get_value=False, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Set a repository or global option" if not get_value and value is None: raise GitException("No value supplied for config option \"%s\"" % (name, )) elif get_value and value is not None: raise GitException("Cannot supply value while get_value is True for" " config option \"%s\"" % (name, )) cmd_args = ["git", "config"] cmd_args.append(unicode(name)) if not get_value: cmd_args.append(unicode(value)) returned_value = None for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, returncode_handler=__config_returncode_handler, debug=debug, dry_run=dry_run, verbose=verbose): if get_value: if returned_value is not None: raise GitException("Found multiple values for %s:" " \"%s\" and \"%s\"" % (name, returned_value, line)) returned_value = line elif line != "": raise GitException("%s returned \"%s\"" % (" ".join(cmd_args[:2]), line)) return returned_value
def git_current_branch(sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Return the current branch" cmd_args = ("git", "branch", "--show-current") branch_name = None for line in run_generator(cmd_args, cmdname="GIT CURRENT_BRANCH", working_directory=sandbox_dir, debug=debug, dry_run=dry_run, verbose=verbose): if branch_name is None: branch_name = line.rstrip() else: print("WARNING: Ignoring extra line from" " 'git branch --show-current': %s" % line.rstrip()) return branch_name
def __diff_dirs(orig_dir, new_dir, debug=False, dry_run=False, verbose=False): "Print the differences between two directories" cmd_args = ["diff", "-ru", orig_dir, new_dir] found_diffs = False for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), returncode_handler=__handle_diff_returncode, debug=debug, dry_run=dry_run, verbose=verbose): # ignore complaints about missing 'moat' and 'domapp' directories, # we're intentionally trying to omit those directories if line.startswith("Only in "): idx = line.find(": ") if idx >= 0: filename = line[idx + 2:] if filename == "moat" or filename == "domapp": continue found_diffs = True if found_diffs: read_input("%%%%%% Found diffs for %s: " % new_dir) # XXX
def git_push(remote_name=None, upstream=None, sandbox_dir=None, debug=False, dry_run=False, verbose=False): "Push all changes to the remote Git repository" cmd_args = ["git", "push"] if upstream is not None: cmd_args += ("-u", upstream) if remote_name is not None: cmd_args.append(remote_name) for line in run_generator(cmd_args, cmdname=" ".join(cmd_args[:2]).upper(), working_directory=sandbox_dir, stderr_handler=__handle_generic_stderr, debug=debug, dry_run=dry_run, verbose=verbose): yield line
def run_handler(self): logfile = tempfile.NamedTemporaryFile(mode="w", delete=False) try: # write log message to a temporary file if self.__commit_message is None: commit_file = os.devnull else: print("%s" % self.__commit_message, file=logfile, end="") logfile.close() commit_file = logfile.name cmd_args = ["git", "commit", "-F", commit_file] + self.__extra_args cmdname = " ".join(cmd_args[:2]).upper() while True: for line in run_generator(cmd_args, cmdname=cmdname, returncode_handler=self.__hndl_rtncd, stderr_handler=self.handle_stderr, working_directory=self.__sandbox_dir, debug=self.__debug, dry_run=self.__dry_run, verbose=self.__verbose): self.__process_line(line) # no errors seen, we're done if not self.__saw_error: break # reset flags and try again self.__saw_error = False self.__auto_pack_err = False finally: os.unlink(logfile.name) return self.tuple