def _getbundle(repo, dest, **opts): """return a bundle containing changesets missing in "dest" The `opts` keyword-arguments are the same as the one accepted by the `bundle` command. The bundle is a returned as a single in-memory binary blob. """ ui = repo.ui tmpdir = pycompat.mkdtemp(prefix=b'hg-email-bundle-') tmpfn = os.path.join(tmpdir, b'bundle') btype = ui.config(b'patchbomb', b'bundletype') if btype: opts['type'] = btype try: dests = [] if dest: dests = [dest] commands.bundle(ui, repo, tmpfn, *dests, **opts) return util.readfile(tmpfn) finally: try: os.unlink(tmpfn) except OSError: pass os.rmdir(tmpdir)
def before(self): self.tmppath = pycompat.mkdtemp(prefix=b'convert-' + os.path.basename(self.path) + b'-') output, status = self.run(b'init', repodir=self.tmppath) self.checkexit(status) tree = self.xml(b'changes', xml_output=True, summary=True, repodir=self.path) tagname = None child = None for elt in tree.findall(b'patch'): node = elt.get(b'hash') name = elt.findtext(b'name', b'') if name.startswith(b'TAG '): tagname = name[4:].strip() elif tagname is not None: self.tags[tagname] = node tagname = None self.changes[node] = elt self.parents[child] = [node] child = node self.parents[child] = []
def dodiff(ui, repo, cmdline, pats, opts): """Do the actual diff.""" revs = opts.get('rev') old, new = scmutil.revpair(repo, revs) subrepos = opts.get('subrepos') matcher = scmutil.match(new, pats, opts) status = old.status(new, matcher, listsubrepos=subrepos) copy = copies.pathcopies(old, new, matcher) mod, add, rem = map(set, status[:3]) paths_new = mod | add paths_old = mod | set(copy.values()) paths_all = paths_old | paths_new if not paths_all: return 0 tmproot = pycompat.mkdtemp(prefix='extdiff2.') try: # Always make a copy of old dir_old = snapshot(ui, repo, paths_old, old.node(), tmproot, subrepos) dir_old = os.path.join(tmproot, dir_old) label_old = '@%d' % old.rev() # If new in not the wc, copy it if new.node(): dir_new = snapshot(ui, repo, paths_new, new.node(), tmproot, subrepos) label_new = '@%d' % new.rev() else: # This lets the diff tool open the changed file(s) directly dir_new = '' label_new = '' # Diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist for path in paths_new: path = util.localpath(path) path_old = os.path.join(dir_old, copy.get(path, path)) label_old = path + label_old #if not os.path.isfile(path_old): #path_old = os.devnull path_new = os.path.join(repo.root, path) if not dir_new: path_new = os.path.relpath(path_new) label_new = path + label_new # Function to quote file/dir names in the argument string. replace = { 'old': path_old, 'olabel': label_old, 'nlabel': label_new, 'new': path_new, 'root': repo.root } def quote(match): pre = match.group(2) key = match.group(3) return pre + procutil.shellquote(replace[key]) regex = (br"""(['"]?)([^\s'"$]*)""" br'\$(old|new|olabel|nlabel|root)\1') if not re.search(regex, cmdline): cmdline2 = cmdline + ' $old $new' else: cmdline2 = cmdline cmdline3 = re.sub(regex, quote, cmdline2) ui.write(pycompat.bytestr(cmdline3) + b'\n') ui.system(cmdline3, blockedtag='extdiff2') return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)
def dodiff(ui, repo, cmdline, pats, opts, guitool=False): '''Do the actual diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' revs = opts.get(b'rev') change = opts.get(b'change') do3way = b'$parent2' in cmdline if revs and change: msg = _(b'cannot specify --rev and --change at the same time') raise error.Abort(msg) elif change: ctx2 = scmutil.revsingle(repo, change, None) ctx1a, ctx1b = ctx2.p1(), ctx2.p2() else: ctx1a, ctx2 = scmutil.revpair(repo, revs) if not revs: ctx1b = repo[None].p2() else: ctx1b = repo[nullid] perfile = opts.get(b'per_file') confirm = opts.get(b'confirm') node1a = ctx1a.node() node1b = ctx1b.node() node2 = ctx2.node() # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False subrepos = opts.get(b'subrepos') matcher = scmutil.match(repo[node2], pats, opts) if opts.get(b'patch'): if subrepos: raise error.Abort(_(b'--patch cannot be used with --subrepos')) if perfile: raise error.Abort(_(b'--patch cannot be used with --per-file')) if node2 is None: raise error.Abort(_(b'--patch requires two revisions')) else: mod_a, add_a, rem_a = map( set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3]) if do3way: mod_b, add_b, rem_b = map( set, repo.status(node1b, node2, matcher, listsubrepos=subrepos)[:3], ) else: mod_b, add_b, rem_b = set(), set(), set() modadd = mod_a | add_a | mod_b | add_b common = modadd | rem_a | rem_b if not common: return 0 tmproot = pycompat.mkdtemp(prefix=b'extdiff.') try: if not opts.get(b'patch'): # Always make a copy of node1a (and node1b, if applicable) dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0] rev1a = b'@%d' % repo[node1a].rev() if do3way: dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, subrepos)[0] rev1b = b'@%d' % repo[node1b].rev() else: dir1b = None rev1b = b'' fnsandstat = [] # If node2 in not the wc or there is >1 change, copy it dir2root = b'' rev2 = b'' if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] rev2 = b'@%d' % repo[node2].rev() elif len(common) > 1: # we only actually need to get the files to copy back to # the working dir in this case (because the other cases # are: diffing 2 revisions or single file -- in which case # the file is already directly passed to the diff tool). dir2, fnsandstat = snapshot(ui, repo, modadd, None, tmproot, subrepos) else: # This lets the diff tool open the changed file directly dir2 = b'' dir2root = repo.root label1a = rev1a label1b = rev1b label2 = rev2 # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(common) == 1: common_file = util.localpath(common.pop()) dir1a = os.path.join(tmproot, dir1a, common_file) label1a = common_file + rev1a if not os.path.isfile(dir1a): dir1a = os.devnull if do3way: dir1b = os.path.join(tmproot, dir1b, common_file) label1b = common_file + rev1b if not os.path.isfile(dir1b): dir1b = os.devnull dir2 = os.path.join(dir2root, dir2, common_file) label2 = common_file + rev2 else: template = b'hg-%h.patch' with formatter.nullformatter(ui, b'extdiff', {}) as fm: cmdutil.export( repo, [repo[node1a].rev(), repo[node2].rev()], fm, fntemplate=repo.vfs.reljoin(tmproot, template), match=matcher, ) label1a = cmdutil.makefilename(repo[node1a], template) label2 = cmdutil.makefilename(repo[node2], template) dir1a = repo.vfs.reljoin(tmproot, label1a) dir2 = repo.vfs.reljoin(tmproot, label2) dir1b = None label1b = None fnsandstat = [] if not perfile: # Run the external tool on the 2 temp directories or the patches cmdline = formatcmdline( cmdline, repo.root, do3way=do3way, parent1=dir1a, plabel1=label1a, parent2=dir1b, plabel2=label1b, child=dir2, clabel=label2, ) ui.debug(b'running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot)) ui.system(cmdline, cwd=tmproot, blockedtag=b'extdiff') else: # Run the external tool once for each pair of files _runperfilediff( cmdline, repo.root, ui, guitool=guitool, do3way=do3way, confirm=confirm, commonfiles=common, tmproot=tmproot, dir1a=dir1a, dir1b=dir1b, dir2root=dir2root, dir2=dir2, rev1a=rev1a, rev1b=rev1b, rev2=rev2, ) for copy_fn, working_fn, st in fnsandstat: cpstat = os.lstat(copy_fn) # Some tools copy the file and attributes, so mtime may not detect # all changes. A size check will detect more cases, but not all. # The only certain way to detect every case is to diff all files, # which could be expensive. # copyfile() carries over the permission, so the mode check could # be in an 'elif' branch, but for the case where the file has # changed without affecting mtime or size. if (cpstat[stat.ST_MTIME] != st[stat.ST_MTIME] or cpstat.st_size != st.st_size or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100)): ui.debug(b'file changed while diffing. ' b'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_(b'cleaning up temp directory\n')) shutil.rmtree(tmproot)
def demo(ui, repo, *args, **opts): '''print [keywordmaps] configuration and an expansion example Show current, custom, or default keyword template maps and their expansions. Extend the current configuration by specifying maps as arguments and using -f/--rcfile to source an external hgrc file. Use -d/--default to disable current configuration. See :hg:`help templates` for information on templates and filters. ''' def demoitems(section, items): ui.write(b'[%s]\n' % section) for k, v in sorted(items): if isinstance(v, bool): v = stringutil.pprint(v) ui.write(b'%s = %s\n' % (k, v)) fn = b'demo.txt' tmpdir = pycompat.mkdtemp(b'', b'kwdemo.') ui.note(_(b'creating temporary repository at %s\n') % tmpdir) if repo is None: baseui = ui else: baseui = repo.baseui repo = localrepo.instance(baseui, tmpdir, create=True) ui.setconfig(b'keyword', fn, b'', b'keyword') svn = ui.configbool(b'keywordset', b'svn') # explicitly set keywordset for demo output ui.setconfig(b'keywordset', b'svn', svn, b'keyword') uikwmaps = ui.configitems(b'keywordmaps') if args or opts.get(r'rcfile'): ui.status(_(b'\n\tconfiguration using custom keyword template maps\n')) if uikwmaps: ui.status(_(b'\textending current template maps\n')) if opts.get(r'default') or not uikwmaps: if svn: ui.status(_(b'\toverriding default svn keywordset\n')) else: ui.status(_(b'\toverriding default cvs keywordset\n')) if opts.get(r'rcfile'): ui.readconfig(opts.get(b'rcfile')) if args: # simulate hgrc parsing rcmaps = b'[keywordmaps]\n%s\n' % b'\n'.join(args) repo.vfs.write(b'hgrc', rcmaps) ui.readconfig(repo.vfs.join(b'hgrc')) kwmaps = dict(ui.configitems(b'keywordmaps')) elif opts.get(r'default'): if svn: ui.status(_(b'\n\tconfiguration using default svn keywordset\n')) else: ui.status(_(b'\n\tconfiguration using default cvs keywordset\n')) kwmaps = _defaultkwmaps(ui) if uikwmaps: ui.status(_(b'\tdisabling current template maps\n')) for k, v in pycompat.iteritems(kwmaps): ui.setconfig(b'keywordmaps', k, v, b'keyword') else: ui.status(_(b'\n\tconfiguration using current keyword template maps\n')) if uikwmaps: kwmaps = dict(uikwmaps) else: kwmaps = _defaultkwmaps(ui) uisetup(ui) reposetup(ui, repo) ui.writenoi18n(b'[extensions]\nkeyword =\n') demoitems(b'keyword', ui.configitems(b'keyword')) demoitems(b'keywordset', ui.configitems(b'keywordset')) demoitems(b'keywordmaps', pycompat.iteritems(kwmaps)) keywords = b'$' + b'$\n$'.join(sorted(kwmaps.keys())) + b'$\n' repo.wvfs.write(fn, keywords) repo[None].add([fn]) ui.note(_(b'\nkeywords written to %s:\n') % fn) ui.note(keywords) with repo.wlock(): repo.dirstate.setbranch(b'demobranch') for name, cmd in ui.configitems(b'hooks'): if name.split(b'.', 1)[0].find(b'commit') > -1: repo.ui.setconfig(b'hooks', name, b'', b'keyword') msg = _(b'hg keyword configuration and expansion example') ui.note((b"hg ci -m '%s'\n" % msg)) repo.commit(text=msg) ui.status(_(b'\n\tkeywords expanded\n')) ui.write(repo.wread(fn)) repo.wvfs.rmtree(repo.root)
def dodiff(ui, repo, cmdline, pats, opts, guitool=False): """Do the actual diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir """ cmdutil.check_at_most_one_arg(opts, b'rev', b'change') revs = opts.get(b'rev') from_rev = opts.get(b'from') to_rev = opts.get(b'to') change = opts.get(b'change') do3way = b'$parent2' in cmdline if change: ctx2 = scmutil.revsingle(repo, change, None) ctx1a, ctx1b = ctx2.p1(), ctx2.p2() elif from_rev or to_rev: repo = scmutil.unhidehashlikerevs( repo, [from_rev] + [to_rev], b'nowarn' ) ctx1a = scmutil.revsingle(repo, from_rev, None) ctx1b = repo[nullrev] ctx2 = scmutil.revsingle(repo, to_rev, None) else: ctx1a, ctx2 = scmutil.revpair(repo, revs) if not revs: ctx1b = repo[None].p2() else: ctx1b = repo[nullrev] # Disable 3-way merge if there is only one parent if do3way: if ctx1b.rev() == nullrev: do3way = False matcher = scmutil.match(ctx2, pats, opts) if opts.get(b'patch'): if opts.get(b'subrepos'): raise error.Abort(_(b'--patch cannot be used with --subrepos')) if opts.get(b'per_file'): raise error.Abort(_(b'--patch cannot be used with --per-file')) if ctx2.node() is None: raise error.Abort(_(b'--patch requires two revisions')) tmproot = pycompat.mkdtemp(prefix=b'extdiff.') try: if opts.get(b'patch'): return diffpatch( ui, repo, ctx1a.node(), ctx2.node(), tmproot, matcher, cmdline ) return diffrevs( ui, repo, ctx1a, ctx1b, ctx2, matcher, tmproot, cmdline, do3way, guitool, opts, ) finally: ui.note(_(b'cleaning up temp directory\n')) shutil.rmtree(tmproot)
def dodiff(ui, repo, cmdline, pats, opts): '''Do the actual diff: - copy to a temp structure if diffing 2 internal revisions - copy to a temp structure if diffing working revision with another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' revs = opts.get('rev') change = opts.get('change') do3way = '$parent2' in cmdline if revs and change: msg = _('cannot specify --rev and --change at the same time') raise error.Abort(msg) elif change: ctx2 = scmutil.revsingle(repo, change, None) ctx1a, ctx1b = ctx2.p1(), ctx2.p2() else: ctx1a, ctx2 = scmutil.revpair(repo, revs) if not revs: ctx1b = repo[None].p2() else: ctx1b = repo[nullid] node1a = ctx1a.node() node1b = ctx1b.node() node2 = ctx2.node() # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False subrepos = opts.get('subrepos') matcher = scmutil.match(repo[node2], pats, opts) if opts.get('patch'): if subrepos: raise error.Abort(_('--patch cannot be used with --subrepos')) if node2 is None: raise error.Abort(_('--patch requires two revisions')) else: mod_a, add_a, rem_a = map( set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3]) if do3way: mod_b, add_b, rem_b = map( set, repo.status(node1b, node2, matcher, listsubrepos=subrepos)[:3]) else: mod_b, add_b, rem_b = set(), set(), set() modadd = mod_a | add_a | mod_b | add_b common = modadd | rem_a | rem_b if not common: return 0 tmproot = pycompat.mkdtemp(prefix='extdiff.') try: if not opts.get('patch'): # Always make a copy of node1a (and node1b, if applicable) dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0] rev1a = '@%d' % repo[node1a].rev() if do3way: dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, subrepos)[0] rev1b = '@%d' % repo[node1b].rev() else: dir1b = None rev1b = '' fnsandstat = [] # If node2 in not the wc or there is >1 change, copy it dir2root = '' rev2 = '' if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] rev2 = '@%d' % repo[node2].rev() elif len(common) > 1: #we only actually need to get the files to copy back to #the working dir in this case (because the other cases #are: diffing 2 revisions or single file -- in which case #the file is already directly passed to the diff tool). dir2, fnsandstat = snapshot(ui, repo, modadd, None, tmproot, subrepos) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root label1a = rev1a label1b = rev1b label2 = rev2 # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(common) == 1: common_file = util.localpath(common.pop()) dir1a = os.path.join(tmproot, dir1a, common_file) label1a = common_file + rev1a if not os.path.isfile(dir1a): dir1a = os.devnull if do3way: dir1b = os.path.join(tmproot, dir1b, common_file) label1b = common_file + rev1b if not os.path.isfile(dir1b): dir1b = os.devnull dir2 = os.path.join(dir2root, dir2, common_file) label2 = common_file + rev2 else: template = 'hg-%h.patch' with formatter.nullformatter(ui, 'extdiff', {}) as fm: cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()], fm, fntemplate=repo.vfs.reljoin(tmproot, template), match=matcher) label1a = cmdutil.makefilename(repo[node1a], template) label2 = cmdutil.makefilename(repo[node2], template) dir1a = repo.vfs.reljoin(tmproot, label1a) dir2 = repo.vfs.reljoin(tmproot, label2) dir1b = None label1b = None fnsandstat = [] # Function to quote file/dir names in the argument string. # When not operating in 3-way mode, an empty string is # returned for parent2 replace = { 'parent': dir1a, 'parent1': dir1a, 'parent2': dir1b, 'plabel1': label1a, 'plabel2': label1b, 'clabel': label2, 'child': dir2, 'root': repo.root } def quote(match): pre = match.group(2) key = match.group(3) if not do3way and key == 'parent2': return pre return pre + procutil.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = (br'''(['"]?)([^\s'"$]*)''' br'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1') if not do3way and not re.search(regex, cmdline): cmdline += ' $parent1 $child' cmdline = re.sub(regex, quote, cmdline) ui.debug('running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot)) ui.system(cmdline, cwd=tmproot, blockedtag='extdiff') for copy_fn, working_fn, st in fnsandstat: cpstat = os.lstat(copy_fn) # Some tools copy the file and attributes, so mtime may not detect # all changes. A size check will detect more cases, but not all. # The only certain way to detect every case is to diff all files, # which could be expensive. # copyfile() carries over the permission, so the mode check could # be in an 'elif' branch, but for the case where the file has # changed without affecting mtime or size. if (cpstat[stat.ST_MTIME] != st[stat.ST_MTIME] or cpstat.st_size != st.st_size or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100)): ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) return 1 finally: ui.note(_('cleaning up temp directory\n')) shutil.rmtree(tmproot)