def clone(source=None, dest=None, noupdate=False, updaterev=None, rev=None, branch=None, pull=False, uncompressed=False, ssh=None, remotecmd=None, insecure=False, encoding=None, configs=None): args = util.cmdbuilder('clone', source, dest, noupdate=noupdate, updaterev=updaterev, rev=rev, branch=branch, pull=pull, uncompresses=uncompressed, e=ssh, remotecmd=remotecmd, insecure=insecure) args.insert(0, HGPATH) proc = util.popen(args) out, err = proc.communicate() if proc.returncode: raise error.CommandError(args, proc.returncode, out, err) return client.hgclient(dest, encoding, configs, connect=False)
def unbundle(self, file, update=False, ssh=None, remotecmd=None, insecure=False): """ Apply one or more compressed changegroup files generated by the bundle command. Returns True on success, False if an update has unresolved files. file - source file name update - update to new branch head if changesets were unbundled ssh - specify ssh command to use remotecmd - specify hg command to run on the remote side insecure - do not verify server certificate (ignoring web.cacerts config) """ args = util.cmdbuilder('unbundle', file, u=update, e=ssh, remotecmd=remotecmd, insecure=insecure) eh = util.reterrorhandler(args) self.rawcommand(args, eh=eh) return bool(eh)
def purge(self, dirs=None, all=False, include=None, exclude=None, p=False, abortonerr=False): """ aliases: clean removes files not tracked by Mercurial Delete files not known to Mercurial. This is useful to test local and uncommitted changes in an otherwise-clean source tree. This means that purge will delete: - Unknown files: files marked with "?" by "hg status" - Empty directories: in fact Mercurial ignores directories unless they contain files under source control management But it will leave untouched: - Modified and unmodified tracked files - Ignored files (unless --all is specified) - New files added to the repository (with "hg add") If directories are given on the command line, only files in these directories are considered. Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of files that this program would delete, use the --print option. Return True on success all - purge ignored files too include - include names matching the given patterns exclude - exclude names matching the given patterns abortonerror - abort if an error occurs p - print filenames instead of deleting them """ if not isinstance(dirs, list): dirs = [dirs] args = util.cmdbuilder('purge', all=all, I=include, X=exclude, p=p, a=abortonerr, *dirs) args.extend(['--config', 'extensions.hgext.purge=']) eh = util.reterrorhandler(args) self.rawcommand(args, eh=eh) return bool(eh)
def main(self): args = cmdbuilder( b('annotate'), self.client.root(), d=True, u=True, T='json') blame_json = ''.join(self.client.rawcommand(args)) file_blames = json.loads(blame_json) for file_blame in file_blames: self.handleFile(file_blame) return {'authors': self.users, 'blame': self.blame}
def _get_touched_files(hg_repo, commit_node): # Build list of files touched by this commit. def strip_servo(filename): assert filename.startswith('servo/') return filename[len('servo/'):] # Grab a list of files under the servo/ directory touched by this # change. args = cmdbuilder('log', template='{join(files,"\n")}', r=commit_node, I='path:servo/') return map(strip_servo, hg_repo.rawcommand(args).split('\n'))
def init(dest=None, ssh=None, remotecmd=None, insecure=False, encoding=None, configs=None): args = util.cmdbuilder('init', dest, e=ssh, remotecmd=remotecmd, insecure=insecure) args.insert(0, HGPATH) proc = util.popen(args) out, err = proc.communicate() if proc.returncode: raise error.CommandError(args, proc.returncode, out, err) return client.hgclient(dest, encoding, configs, connect=False)
def churn(self, revrange=None, date=None, template=None, dateformat=None, files=[], changesets=False, sort=None, include=None, exclude=None): """ histogram of changes to the repository This command will display a histogram representing the number of changed lines or revisions, grouped according to the given template. The default template will group changes by author. The --dateformat option may be used to group the results by date instead. Statistics are based on the number of changed lines, or alternatively the number of matching revisions if the --changesets option is specified. Examples: # display count of changed lines for every committer hg churn -t '{author|email}' # display daily activity graph hg churn -f '%H' -s -c # display activity of developers by month hg churn -f '%Y-%m' -s -c # display count of lines changed in every year hg churn -f '%Y' -s It is possible to map alternate email addresses to a main address by providing a file using the following format: <alias email> = <actual email> Such a file may be specified with the --aliases option, otherwise a .hgchurn file will be looked for in the working directory root. revrange count rate for the specified revision or range date count rate for revisions matching date spec template TEMPLATE to group changesets (default: {author|email}) dateformat FORMAT strftime-compatible format for grouping by date changesets count rate by number of changesets sort sort by key (default: sort by count) include include names matching the given patterns exclude exclude names matching the given patterns """ args = util.cmdbuilder('churn', r=revrange, c=changesets, t=template, f=dateformat, s=sort, d=date, I=include, X=exclude, *files) args.extend(['--config', 'extensions.hgext.churn=']) return self.rawcommand(args)
def main(self): args = cmdbuilder(b('annotate'), self.client.root(), d=True, u=True, T='json') blame_json = ''.join(self.client.rawcommand(args)) file_blames = json.loads(blame_json) for file_blame in file_blames: self.handleFile(file_blame) return {'authors': self.users, 'blame': self.blame}
def attribution(self, file_paths): args = cmdbuilder(b('annotate'), *[b(p) for p in file_paths], template='json', date=True, user=True, cwd=self.client.root()) blame_json = self.client.rawcommand(args) file_blames = json.loads(blame_json) for file_blame in file_blames: self.handleFile(file_blame) return {'authors': self.users, 'blame': self.blame}
def clone(source=None, dest=None, noupdate=False, updaterev=None, rev=None, branch=None, pull=False, uncompressed=False, ssh=None, remotecmd=None, insecure=False, encoding=None, configs=None): args = util.cmdbuilder('clone', source, dest, noupdate=noupdate, updaterev=updaterev, rev=rev, branch=branch, pull=pull, uncompressed=uncompressed, e=ssh, remotecmd=remotecmd, insecure=insecure) args.insert(0, HGPATH) proc = util.popen(args) out, err = proc.communicate() if proc.returncode: raise error.CommandError(args, proc.returncode, out, err) return client.hgclient(dest, encoding, configs, connect=False)
def purge(self, dirs=None, all=False, include=None, exclude=None, p=False, abortonerr=False): """ aliases: clean removes files not tracked by Mercurial Delete files not known to Mercurial. This is useful to test local and uncommitted changes in an otherwise-clean source tree. This means that purge will delete: - Unknown files: files marked with "?" by "hg status" - Empty directories: in fact Mercurial ignores directories unless they contain files under source control management But it will leave untouched: - Modified and unmodified tracked files - Ignored files (unless --all is specified) - New files added to the repository (with "hg add") If directories are given on the command line, only files in these directories are considered. Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of files that this program would delete, use the --print option. Return True on success all - purge ignored files too include - include names matching the given patterns exclude - exclude names matching the given patterns abortonerror - abort if an error occurs p - print filenames instead of deleting them """ if not isinstance(dirs, list): dirs = [dirs] args = util.cmdbuilder( 'purge', all=all, I=include, X=exclude, p=p, a=abortonerr, *dirs) args.extend(['--config', 'extensions.hgext.purge=']) eh = util.reterrorhandler(args) self.rawcommand(args, eh=eh) return bool(eh)
def compare(sourceBranch="default", targetBranch="stable"): excludeFile = None excludes = [] if os.path.isfile('graft_exclude.conf'): excludeFile = 'graft_exclude.conf' elif os.path.isfile('buildscripts/graft_exclude.conf'): excludeFile = 'buildscripts/graft_exclude.conf' if excludeFile: for L in open(excludeFile, 'r'): L = L.strip() if L: if L.startswith('#'): continue Ls = L.split() if len(Ls[0]) > 12: Ls[0] = Ls[0][:12] excludes.append(Ls[0]) print('Loaded %s exclusions from %s\n' % (len(excludes), excludeFile)) try: # Try if cwd is buildscripts/ folder c = hglib.open('../') except: # Try whether we are in hg root folder c = hglib.open('.') # Difference in changesets between branches cDiff = c.log("ancestors(%s) and not ancestors(%s)" % (sourceBranch, targetBranch)) # Filter out already grafted commits stdOut = c.rawcommand(cmdbuilder('log', debug=True, b=targetBranch)) grafted = [] r = re.compile('.*source=([a-zA-Z0-9]*)') for outL in stdOut.split('\n'): if outL.strip().startswith('extra') and ' source=' in outL: sourceRev = r.match(outL).groups()[0] grafted.append(sourceRev) # Filtered result # Also filter out merge commits (which are skipped by graft anyway) return [cs for cs in cDiff if (cs.node not in grafted and \ cs.node[:12] not in excludes and \ not isMergeCommit(c, cs) )]
def compare(sourceBranch="default", targetBranch="stable"): excludeFile = None excludes = [] if os.path.isfile('graft_exclude.conf'): excludeFile = 'graft_exclude.conf' elif os.path.isfile('buildscripts/graft_exclude.conf'): excludeFile = 'buildscripts/graft_exclude.conf' if excludeFile: for L in open(excludeFile, 'r'): L = L.strip() if L: if L.startswith('#'): continue Ls = L.split() if len(Ls[0]) > 12: Ls[0] = Ls[0][:12] excludes.append(Ls[0]) print 'Loaded %s exclusions from %s\n' % (len(excludes), excludeFile) try: # Try if cwd is buildscripts/ folder c = hglib.open('../') except: # Try whether we are in hg root folder c = hglib.open('.') # Difference in changesets between branches cDiff = c.log("ancestors(%s) and not ancestors(%s)" % (sourceBranch, targetBranch)) # Filter out already grafted commits stdOut = c.rawcommand(cmdbuilder('log', debug=True, b=targetBranch)) grafted = [] r = re.compile('.*source=([a-zA-Z0-9]*)') for outL in stdOut.split('\n'): if outL.strip().startswith('extra') and ' source=' in outL: sourceRev = r.match(outL).groups()[0] grafted.append(sourceRev) # Filtered result # Also filter out merge commits (which are skipped by graft anyway) return [cs for cs in cDiff if (cs.node not in grafted and \ cs.node[:12] not in excludes and \ not isMergeCommit(c, cs) )]
def commit(self, paths, op_meta): if 'message' not in op_meta or not op_meta['message']: raise ValueError("No commit message specified.") kwargs = {} if 'author' in op_meta: kwargs['u'] = _b(op_meta['author']) try: # We need to write our own command because somehow the `commit` # method in `hglib` doesn't support specifying the file(s) # directly -- only with `--include`. Weird. args = cmdbuilder( b'commit', *_b(paths), debug=True, m=_b(op_meta['message']), A=True, **kwargs) self.client.rawcommand(args) except CommandError as e: raise SourceControlError('commit', str(e), _s(e.args), _s(e.out))
def get_file_contents(self, path, revision=None): # Note: Should ideally use the library's "cat" function, but it # has a bug in that it doesn't provide a "cwd" argument. This implementation # is based on the library's with the fix implemented. from hglib.util import b, cmdbuilder if path is not None: path = b(str(path)) if revision is not None: revision = b(str(revision)) files = [path] args = cmdbuilder(b('cat'), r=revision, o=None, cwd=self.path, hidden=self.client.hidden, *files) print("hg " + ' '.join([x.decode() for x in args])) return BytesIO(self.client.rawcommand(args))
def unbundle(self, file, update=False, ssh=None, remotecmd=None, insecure=False): """ Apply one or more compressed changegroup files generated by the bundle command. Returns True on success, False if an update has unresolved files. file - source file name update - update to new branch head if changesets were unbundled ssh - specify ssh command to use remotecmd - specify hg command to run on the remote side insecure - do not verify server certificate (ignoring web.cacerts config) """ args = util.cmdbuilder( 'unbundle', file, u=update, e=ssh, remotecmd=remotecmd, insecure=insecure) eh = util.reterrorhandler(args) self.rawcommand(args, eh=eh) return bool(eh)
def handleFile(self, leaf): try: parser = getParser(leaf) except UserWarning: return args = cmdbuilder(b('annotate'), d=True, u=True, T='json', *['path:' + leaf]) blame_json = ''.join(self.client.rawcommand(args)) blames = json.loads(blame_json) fname = os.path.join(self.client.root(), leaf) parser.readFile(fname) entities, emap = parser.parse() self.blame[leaf] = {} for e in entities: blines = blames[(e.value_position()[0] - 1):e.value_position(-1)[0]] blines.sort(key=lambda blame: -blame['date'][0]) # ignore timezone blame = blines[0] user = blame['user'] timestamp = blame['date'][0] # ignore timezone if user not in self.users: self.users.append(user) userid = self.users.index(user) self.blame[leaf][e.key] = [userid, timestamp]
if args.get('graft', False): import subprocess try: # Try if cwd is buildscripts/ folder c = hglib.open('../') except: # Try whether we are in hg root folder c = hglib.open('.') # Difference in changesets between branches cDiff = c.log("ancestors(%s) and not ancestors(%s)" % (sourceBranch, targetBranch)) # Filter out already grafted commits stdOut = c.rawcommand(cmdbuilder('log', debug=True, b=targetBranch)) grafted = [] r = re.compile('.*source=([a-zA-Z0-9]*)') for outL in stdOut.split('\n'): if outL.strip().startswith('extra') and ' source=' in outL: sourceRev = r.match(outL).groups()[0] grafted.append(sourceRev) # Filtered result # Also filter out merge commits (which are skipped by graft anyway) return [cs for cs in cDiff if (cs.node not in grafted and \ cs.node[:12] not in excludes and \ not isMergeCommit(c, cs) )] def formatChangeset(cs):
def _get_touched_files(hg_repo, commit_node): # Grab a list of files under the servo/ directory touched by this # change, stripping the leading servo/ prefix. args = cmdbuilder('log', template='{join(files,"\n")}', r=commit_node) files = hg_repo.rawcommand(args).split('\n') return [fn[len('servo/'):] for fn in files if fn.startswith('servo/')]