def dodiff(tmproot): assert not (hascopies and len(MAR) > 1), \ 'dodiff cannot handle copies when diffing dirs' sa = [mod_a, add_a, rem_a] sb = [mod_b, add_b, rem_b] ctxs = [ctx1a, ctx1b, ctx2] # If more than one file, diff on working dir copy. copyworkingdir = len(MAR) > 1 dirs, labels, fns_and_mtimes = snapshotset(repo, ctxs, sa, sb, cpy, tmproot, copyworkingdir) dir1a, dir1b, dir2 = dirs label1a, label1b, label2 = labels fns_and_mtime = fns_and_mtimes[2] if len(MAR) > 1 and label2 == '': label2 = 'working files' def getfile(fname, dir, label): file = os.path.join(tmproot, dir, fname) if os.path.isfile(file): return fname+label, file nullfile = os.path.join(tmproot, 'empty') fp = open(nullfile, 'w') fp.close() return _nonexistant+label, nullfile # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(MAR) == 1: file2 = util.localpath(MAR.pop()) if file2 in cto: file1 = util.localpath(cpy[file2]) else: file1 = file2 label1a, dir1a = getfile(file1, dir1a, label1a) if do3way: label1b, dir1b = getfile(file1, dir1b, label1b) label2, dir2 = getfile(file2, dir2, label2) if do3way: label1a += '[local]' label1b += '[other]' label2 += '[merged]' replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, plabel1=label1a, plabel2=label1b, phash1=str(ctx1a), phash2=str(ctx1b), repo=hglib.get_reponame(repo), clabel=label2, child=dir2, chash=str(ctx2)) launchtool(diffcmd, args, replace, True) # detect if changes were made to mirrored working files for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn)
def getfile(ctx, dir, fname, source): m = ctx.manifest() if fname in m: path = os.path.join(dir, util.localpath(fname)) return fname, path elif source and source in m: path = os.path.join(dir, util.localpath(source)) return source, path else: nullfile = os.path.join(qtlib.gettempdir(), 'empty') fp = open(nullfile, 'w') fp.close() return hglib.fromunicode(_nonexistant, 'replace'), nullfile
def getfile(ctx, dir, fname, source): m = ctx.manifest() if fname in m: path = os.path.join(dir, util.localpath(fname)) return fname, path elif source and source in m: path = os.path.join(dir, util.localpath(source)) return source, path else: nullfile = os.path.join(self.tmproot, 'empty') fp = open(nullfile, 'w') fp.close() return _nonexistant, nullfile
def savefiles(repo, files, rev, parent=None): for curfile in files: wfile = util.localpath(curfile) wfile, ext = os.path.splitext(os.path.basename(wfile)) if wfile: filename = "%s@%d%s" % (wfile, rev, ext) else: filename = "%s@%d" % (ext, rev) result = QFileDialog.getSaveFileName( parent=parent, caption=_("Save file to"), directory=hglib.tounicode(filename)) if not result: continue cwd = os.getcwd() try: os.chdir(repo.root) try: commands.cat(repo.ui, repo, curfile, rev=rev, output=hglib.fromunicode(result)) except (util.Abort, IOError), e: QMessageBox.critical(self, _('Unable to save file'), hglib.tounicode(str(e))) finally: os.chdir(cwd)
def testVisitdir(self): m = matchmod.match(util.localpath(b'root/d'), b'e/f', [b'../a.txt', b'b.txt']) pm = matchmod.prefixdirmatcher(b'root', b'd/e/f', b'd', m) # `m` elides 'd' because it's part of the root, and the rest of the # patterns are relative. self.assertEqual(bool(m(b'a.txt')), False) self.assertEqual(bool(m(b'b.txt')), False) self.assertEqual(bool(m(b'e/a.txt')), True) self.assertEqual(bool(m(b'e/b.txt')), False) self.assertEqual(bool(m(b'e/f/b.txt')), True) # The prefix matcher re-adds 'd' to the paths, so they need to be # specified when using the prefixdirmatcher. self.assertEqual(bool(pm(b'a.txt')), False) self.assertEqual(bool(pm(b'b.txt')), False) self.assertEqual(bool(pm(b'd/e/a.txt')), True) self.assertEqual(bool(pm(b'd/e/b.txt')), False) self.assertEqual(bool(pm(b'd/e/f/b.txt')), True) self.assertEqual(m.visitdir(b'.'), True) self.assertEqual(m.visitdir(b'e'), True) self.assertEqual(m.visitdir(b'e/f'), True) self.assertEqual(m.visitdir(b'e/f/g'), False) self.assertEqual(pm.visitdir(b'.'), True) self.assertEqual(pm.visitdir(b'd'), True) self.assertEqual(pm.visitdir(b'd/e'), True) self.assertEqual(pm.visitdir(b'd/e/f'), True) self.assertEqual(pm.visitdir(b'd/e/f/g'), False)
def evalpath(striplen): score = 0 for s in srcs: t = os.path.join(dest, util.localpath(s[0])[striplen:]) if os.path.lexists(t): score += 1 return score
def savefile(self): filenames = self.filelist.getSelectedFiles() if not filenames: return rev = self.ctx.rev() for curfile in filenames: wfile = util.localpath(curfile) wfile, ext = os.path.splitext(os.path.basename(wfile)) if wfile: filename = "%s@%d%s" % (wfile, rev, ext) else: filename = "%s@%d" % (ext, rev) result = QFileDialog.getSaveFileName(parent=self, caption=_("Save file to"), directory=filename) if not result: continue cwd = os.getcwd() try: os.chdir(self.repo.root) try: commands.cat(self.repo.ui, self.repo, curfile, rev = rev, output = hglib.fromunicode(result)) except (util.Abort, IOError), e: QMessageBox.critical(self, _('Unable to save file'), hglib.tounicode(str(e))) finally: os.chdir(cwd)
def _do_reload_status(self): """Clear out the existing ListStore model and reload it from the repository status. Also recheck and reselect files that remain in the list. """ self.repo.dirstate.invalidate() self.repo.invalidate() # The following code was copied from the status function in mercurial\commands.py # and modified slightly to work here # node2 is None (the working dir) when 0 or 1 rev is specificed self._node1, self._node2 = cmdutil.revpair(self.repo, self.opts.get('rev')) files, matchfn, anypats = cmdutil.matchpats(self.repo, self.pats, self.opts) cwd = (self.pats and self.repo.getcwd()) or '' modified, added, removed, deleted, unknown, ignored, clean = [ n for n in self.repo.status(node1=self._node1, node2=self._node2, files=files, match=matchfn, list_ignored=self.test_opt('ignored'), list_clean=self.test_opt('clean'))] changetypes = (('modified', 'M', modified), ('added', 'A', added), ('removed', 'R', removed), ('deleted', '!', deleted), ('unknown', '?', unknown), ('ignored', 'I', ignored)) explicit_changetypes = changetypes + (('clean', 'C', clean),) # List of the currently checked and selected files to pass on to the new data recheck = [entry[2] for entry in self.model if entry[0]] reselect = [self.model[iter][2] for iter in self.tree.get_selection().get_selected_rows()[1]] # Load the new data into the tree's model self.tree.hide() self.model.clear() for opt, char, changes in ([ct for ct in explicit_changetypes if self.test_opt(ct[0])] or changetypes) : for file in changes: file = util.localpath(file) self.model.append([file in recheck, char, toutf(file), file]) self._update_check_count() selection = self.tree.get_selection() selected = False for row in self.model: if row[2] in reselect: selection.select_iter(row.iter) selected = True if not selected: selection.select_path((0,)) self.tree.show() self.tree.grab_focus() return True
def targetpathfn(pat, dest, srcs): if os.path.isdir(pat): abspfx = scmutil.canonpath(repo.root, cwd, pat) abspfx = util.localpath(abspfx) if destdirexists: striplen = len(os.path.split(abspfx)[0]) else: striplen = len(abspfx) if striplen: striplen += len(os.sep) res = lambda p: os.path.join(dest, util.localpath(p)[striplen:]) elif destdirexists: res = lambda p: os.path.join(dest, os.path.basename(util.localpath(p))) else: res = lambda p: dest return res
def clone(ui, source, dest=None, **opts): """make a clone of an existing forest of repositories Create a clone of an existing forest in a new directory. Look at the help text for the clone command for more information. """ die_on_numeric_revs(opts['rev']) source = ui.expandpath(source) or source islocalsrc = hg.islocal(source) if islocalsrc: source = os.path.abspath(urltopath(source)) if dest: if hg.islocal(dest): dest = os.path.normpath(dest) else: pass else: dest = hg.defaultdest(source) toprepo = hg.repository(ui, source) forests = toprepo.forests(walkhgenabled(ui, opts['walkhg'])) for rpath in forests: if rpath == '.': rpath = '' if islocalsrc: srcpath = source srcpath = os.path.join(source, util.localpath(rpath)) else: srcpath = '/'.join((source, rpath)) if rpath: destpath = os.path.join(dest, util.localpath(rpath)) else: destpath = dest try: qclone(ui=ui, source=srcpath, sroot=source, dest=destpath, rpath=os.path.normpath(rpath), opts=opts) except util.Abort, err: ui.warn(_("skipped: %s\n") % err) ui.status("\n")
def targetpathafterfn(pat, dest, srcs): if matchmod.patkind(pat): # a mercurial pattern res = lambda p: os.path.join(dest, os.path.basename(util.localpath(p))) else: abspfx = scmutil.canonpath(repo.root, cwd, pat) if len(abspfx) < len(srcs[0][0]): # A directory. Either the target path contains the last # component of the source path or it does not. def evalpath(striplen): score = 0 for s in srcs: t = os.path.join(dest, util.localpath(s[0])[striplen:]) if os.path.lexists(t): score += 1 return score abspfx = util.localpath(abspfx) striplen = len(abspfx) if striplen: striplen += len(os.sep) if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])): score = evalpath(striplen) striplen1 = len(os.path.split(abspfx)[0]) if striplen1: striplen1 += len(os.sep) if evalpath(striplen1) > score: striplen = striplen1 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:]) else: # a file if destdirexists: res = lambda p: os.path.join(dest, os.path.basename(util.localpath(p))) else: res = lambda p: dest return res
def close(self): if not self._fp.closed: self._fp.close() filename = util.localpath(self.__name) oldstat = self._checkambig and util.filestat(filename) if oldstat and oldstat.stat: util.rename(self._tempname, filename) newstat = util.filestat(filename) if newstat.isambig(oldstat): # stat of changed file is ambiguous to original one advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff os.utime(filename, (advanced, advanced)) else: util.rename(self._tempname, filename)
def read(self, snapfile, toppath="."): """Loads the information in snapfile into this forest. snapfile is the filename of a snapshot file toppath is the path of the top of this forest """ if not toppath: toppath = "." cfg = ConfigParser.RawConfigParser() if not cfg.read([snapfile]): raise util.Abort("%s: %s" % (snapfile, os.strerror(errno.ENOENT))) seen_root = False sections = {} for section in cfg.sections(): if section.endswith('.paths'): # Compatibility with old Forest snapshot files paths = dict(cfg.items(section)) section = section[:-6] if section in sections: sections[section].paths.update(paths) else: sections[section] = Forest.Tree(paths=paths) else: root = cfg.get(section, 'root') if root == '.': seen_root = True root = toppath else: root = os.path.join(toppath, util.localpath(root)) root = os.path.normpath(root) rev = cfg.get(section, 'revision') if not rev: rev = [] paths = dict([(k[5:], v) for k, v in cfg.items(section) if k.startswith('path')]) if section in sections: sections[section].root = root sections[section].revs = [rev] sections[section].paths.update(paths) else: sections[section] = Forest.Tree(root=root, revs=[rev], paths=paths) if not seen_root: raise Forest.SnapshotError("Could not find 'root = .' in '%s'" % snapfile) self.trees = sections.values() self.trees.sort(key=(lambda tree: tree.root))
def _save_file_rev(self, menuitem): file = util.localpath(self.curfile) file, ext = os.path.splitext(os.path.basename(file)) filename = "%s@%d%s" % (file, self.currev, ext) fd = NativeSaveFileDialogWrapper(Title = "Save file to", InitialDir=self.cwd, FileName=filename) result = fd.run() if result: import Queue import hglib q = Queue.Queue() cpath = util.canonpath(self.repo.root, self.cwd, self.curfile) hglib.hgcmd_toq(self.repo.root, q, 'cat', '--rev', str(self.currev), '--output', result, cpath)
def scan(self, walkhg): """Scans for sub-repositories within this forest. This method modifies this forest in-place. It searches within the forest's directories and enumerates all the repositories it finds. """ trees = [] top = self.top() ui = top.repo.ui for relpath in top.repo.forests(walkhg): if relpath != '.': abspath = os.path.join(top.root, util.localpath(relpath)) trees.append(Forest.Tree(hg.repository(ui, abspath))) trees.sort(key=(lambda tree: tree.root)) trees.insert(0, Forest.Tree(hg.repository(ui, top.root))) self.trees = trees
def editfiles(repo, files, lineno=None, search=None, parent=None, editor=None): if len(files) == 1: filename = files[0].strip() if not filename: return files = [filename] path = repo.wjoin(filename) cwd = os.path.dirname(path) files = [os.path.basename(path)] else: cwd = repo.root files = [util.shellquote(util.localpath(f)) for f in files] editor = repo.ui.config('tortoisehg', 'editor') assert len(files) == 1 or lineno == None if not editor: editor = repo.ui.config('tortoisehg', 'editor') if editor: try: regexp = re.compile('\[([^\]]*)\]') expanded = [] pos = 0 for m in regexp.finditer(editor): expanded.append(editor[pos:m.start() - 1]) phrase = editor[m.start() + 1:m.end() - 1] pos = m.end() + 1 if '$LINENUM' in phrase: if lineno is None: # throw away phrase continue phrase = phrase.replace('$LINENUM', str(lineno)) elif '$SEARCH' in phrase: if search is None: # throw away phrase continue phrase = phrase.replace('$SEARCH', search) if '$FILE' in phrase: phrase = phrase.replace('$FILE', files[0]) files = [] expanded.append(phrase) expanded.append(editor[pos:]) cmdline = ' '.join(expanded + files) except ValueError, e: # '[' or ']' not found cmdline = ' '.join([editor] + files) except TypeError, e: # variable expansion failed cmdline = ' '.join([editor] + files)
def pull(ui, top, source="default", pathalias=None, **opts): """pull changes from the specified forest Pull changes from a remote forest to a local one. You may specify a snapshot file, which is generated by the fsnap command. For each tree in this file, pull the specified revision from the specified source path. By default, pull new remote repositories that it discovers. If you use the -p option, pull only the repositories available locally. Look at the help text for the pull command for more information. """ die_on_numeric_revs(opts['rev']) if pathalias: # Compatibility with old 'hg fpull SNAPFILE PATH-ALIAS' syntax snapfile = source source = pathalias else: snapfile = opts['snapfile'] source = [source] walkhg = walkhgenabled(ui, opts['walkhg']) forest = Forest(top=top, snapfile=snapfile, walkhg=walkhg) toproot = forest.top().root if not snapfile: # Look for new remote paths from source srcpath = forest.top().getpath(source) or "" srcrepo = hg.repository(ui, srcpath) srcforests = None try: srcforests = srcrepo.forests(walkhg) except util.Abort, err: ui.note(_("skipped new forests: %s\n") % err) if srcforests: ui.note(_("looking for new forests\n")) newrepos = [util.localpath(root) for root in srcforests] for tree in forest.trees: try: newrepos.remove(relpath(toproot, tree.root)) except Exception, err: pass ui.note(_("found new forests: %s\n") % newrepos) forest.trees.extend([Forest.Tree(root=os.path.join(toproot, new)) for new in newrepos]) forest.trees.sort(key=(lambda tree: tree.root))
def editfiles(repo, files, lineno=None, search=None, parent=None, editor=None): if len(files) == 1: filename = files[0].strip() if not filename: return files = [filename] path = repo.wjoin(filename) cwd = os.path.dirname(path) files = [os.path.basename(path)] else: cwd = repo.root files = [util.shellquote(util.localpath(f)) for f in files] editor = repo.ui.config('tortoisehg', 'editor') assert len(files) == 1 or lineno == None if not editor: editor = repo.ui.config('tortoisehg', 'editor') if editor: try: regexp = re.compile('\[([^\]]*)\]') expanded = [] pos = 0 for m in regexp.finditer(editor): expanded.append(editor[pos:m.start()-1]) phrase = editor[m.start()+1:m.end()-1] pos = m.end()+1 if '$LINENUM' in phrase: if lineno is None: # throw away phrase continue phrase = phrase.replace('$LINENUM', str(lineno)) elif '$SEARCH' in phrase: if search is None: # throw away phrase continue phrase = phrase.replace('$SEARCH', search) if '$FILE' in phrase: phrase = phrase.replace('$FILE', files[0]) files = [] expanded.append(phrase) expanded.append(editor[pos:]) cmdline = ' '.join(expanded + files) except ValueError, e: # '[' or ']' not found cmdline = ' '.join([editor] + files) except TypeError, e: # variable expansion failed cmdline = ' '.join([editor] + files)
def trees(ui, top, **opts): """show the roots of the repositories Show the roots of the trees in the forest. By default, show the absolute path of each repository. With --convert, show the portable Mercurial path. """ forest = Forest(top=top, walkhg=walkhgenabled(ui, opts['walkhg'])) convert = opts['convert'] for tree in forest.trees: if convert: ui.write("%s\n" % relpath(top.root, tree.root)) else: ui.write("%s\n" % util.localpath(tree.root))
def mq_applied(self): rpath = urltopath(self.root) if not hg.islocal(rpath): raise util.Abort(_("'%s' is not a local repository") % rpath) rpath = util.localpath(rpath) rpath = os.path.join(rpath, ".hg") if not os.path.isdir(rpath): return False for entry in os.listdir(rpath): path = os.path.join(rpath, entry) if (os.path.isdir(path) and os.path.isfile(os.path.join(path, 'series'))): try: s = os.stat(os.path.join(path, "status")) if s.st_size > 0: return path except OSError, err: if err.errno != errno.ENOENT: raise
def save_file_rev(self, menuitem): wfile = util.localpath(self.curfile) wfile, ext = os.path.splitext(os.path.basename(wfile)) if wfile: filename = "%s@%d%s" % (wfile, self.currev, ext) else: filename = "%s@%d" % (ext, self.currev) result = gtklib.NativeSaveFileDialogWrapper(title=_("Save file to"), initial=self.cwd, filename=filename).run() if not result: return try: q = Queue.Queue() hglib.hgcmd_toq(q, False, ('cat', '--rev', str(self.currev), '--output', hglib.fromutf(result), self.curfile)) except (util.Abort, IOError), e: gdialog.Prompt(_('Unable to save file'), str(e), self).run()
def filter_patch(ui, chunks): accepted = [] for chunk in chunks: file = util.localpath(chunk.filename()) if file not in wfiles: # file was not selected for inclusion continue if file not in self.chunks: # file was never filtered, accept all chunks accepted.append(chunk) continue schunks = self.chunks[file] for i, c in enumerate(schunks): if chunk != c: continue if i == 0 or c.active: # take header and active chunks accepted.append(chunk) break return accepted
def testVisitchildrenset(self): m = matchmod.match(util.localpath(b'root/d'), b'e/f', [b'../a.txt', b'b.txt']) pm = matchmod.prefixdirmatcher(b'root', b'd/e/f', b'd', m) # OPT: visitchildrenset could possibly return {'e'} and {'f'} for these # next two, respectively; patternmatcher does not have this # optimization. self.assertEqual(m.visitchildrenset(b'.'), b'this') self.assertEqual(m.visitchildrenset(b'e'), b'this') self.assertEqual(m.visitchildrenset(b'e/f'), b'this') self.assertEqual(m.visitchildrenset(b'e/f/g'), set()) # OPT: visitchildrenset could possibly return {'d'}, {'e'}, and {'f'} # for these next three, respectively; patternmatcher does not have this # optimization. self.assertEqual(pm.visitchildrenset(b'.'), b'this') self.assertEqual(pm.visitchildrenset(b'd'), b'this') self.assertEqual(pm.visitchildrenset(b'd/e'), b'this') self.assertEqual(pm.visitchildrenset(b'd/e/f'), b'this') self.assertEqual(pm.visitchildrenset(b'd/e/f/g'), set())
def function(tree, path, opts): path = util.localpath(path) if files: pats = files[tree] else: pats = () if path == top.root: path = '' else: path = relpath(top.root, path) def prefix(output): """This function shims the root in before the filename.""" if opts['no_status']: return os.path.join(path, output) else: prefix, filename = output.split(' ', 1) return ' '.join((prefix, os.path.join(path, filename))) localui = munge_ui(prefix, ui) try: commands.status(localui, tree.repo, *pats, **opts) except RepoError, err: ui.warn(_("skipped: %s\n") % err)
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): """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 util.Abort(msg) elif change: node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = scmutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.p2() else: node1b = nullid # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False matcher = scmutil.match(repo[node2], pats, opts) mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) if do3way: mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[: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 = tempfile.mkdtemp(prefix="extdiff.") try: # 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)[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)[0] rev1b = "@%d" % repo[node1b].rev() else: dir1b = None rev1b = "" fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it dir2root = "" rev2 = "" if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot)[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, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) 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 # 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 + util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = r"""(['"]?)([^\s'"$]*)""" r"\$(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" % (cmdline, tmproot)) ui.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.lstat(copy_fn).st_mtime != mtime: 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)
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 copypath(self): absfiles = [ util.localpath(self.repo.wjoin(f)) for f in self._selectedfiles ] QApplication.clipboard().setText( hglib.tounicode(os.linesep.join(absfiles)))
''' import socket from mercurial import util, demandimport try: demandimport.disable() import ipaddress except ImportError: # for backwards compatibility for people referencing dynapath.py # directly rather than as a module such that we can still find # and import ipaddress relative to dynapath.py import os.path import imp ipaddressfile = util.localpath( os.path.join(os.path.dirname(__file__), 'ipaddress.py')) ipaddress = imp.load_source('ipaddress', ipaddressfile) finally: demandimport.enable() from mercurial.i18n import _ from mercurial import httppeer from mercurial import extensions, util testedwith = '3.8' def localips(ui, probeip): ui.debug("finding addresses for %s\n" % socket.gethostname()) try: for _af, _socktype, _proto, _canonname, sa in socket.getaddrinfo(
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: node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = scmutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.p2() else: node1b = nullid # 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 = tempfile.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 = '' fns_and_mtime = [] # 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, fns_and_mtime = 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' cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()], template=repo.vfs.reljoin(tmproot, template), match=matcher) label1a = cmdutil.makefilename(repo, template, node1a) label2 = cmdutil.makefilename(repo, template, node2) dir1a = repo.vfs.reljoin(tmproot, label1a) dir2 = repo.vfs.reljoin(tmproot, label2) dir1b = None label1b = None fns_and_mtime = [] # 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 + util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = (r'''(['"]?)([^\s'"$]*)''' r'\$(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' % (cmdline, tmproot)) ui.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.lstat(copy_fn).st_mtime != mtime: 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)
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 util.Abort(msg) elif change: node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = scmutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.p2() else: node1b = nullid # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False matcher = scmutil.match(repo[node2], pats, opts) mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) if do3way: mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[: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 = tempfile.mkdtemp(prefix='extdiff.') try: # 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)[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)[0] rev1b = '@%d' % repo[node1b].rev() else: dir1b = None rev1b = '' fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it dir2root = '' rev2 = '' if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot)[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, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) 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 # 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 + util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = (r'''(['"]?)([^\s'"$]*)''' r'\$(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' % (cmdline, tmproot)) ui.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.lstat(copy_fn).st_mtime != mtime: 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)
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall 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') if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1 = repo[node2].parents()[0].node() else: node1, node2 = cmdutil.revpair(repo, revs) matcher = cmdutil.match(repo, pats, opts) modified, added, removed = repo.status(node1, node2, matcher)[:3] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] changes = len(modified) + len(removed) + len(added) # If node2 in not the wc or there is >1 change, copy it if node2 or changes > 1: dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root fns_and_mtime = [] # If only one change, diff the files instead of the directories if changes == 1 : if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed) : dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug(_('running %r in %s\n') % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: 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)
def diffrevs( ui, repo, ctx1a, ctx1b, ctx2, matcher, tmproot, cmdline, do3way, guitool, opts, ): subrepos = opts.get(b'subrepos') # calculate list of files changed between both revs st = ctx1a.status(ctx2, matcher, listsubrepos=subrepos) mod_a, add_a, rem_a = set(st.modified), set(st.added), set(st.removed) if do3way: stb = ctx1b.status(ctx2, matcher, listsubrepos=subrepos) mod_b, add_b, rem_b = ( set(stb.modified), set(stb.added), set(stb.removed), ) 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 # Always make a copy of ctx1a (and ctx1b, if applicable) # dir1a should contain files which are: # * modified or removed from ctx1a to ctx2 # * modified or added from ctx1b to ctx2 # (except file added from ctx1a to ctx2 as they were not present in # ctx1a) dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) dir1a = snapshot(ui, repo, dir1a_files, ctx1a.node(), tmproot, subrepos)[0] rev1a = b'' if ctx1a.rev() is None else b'@%d' % ctx1a.rev() if do3way: # file calculation criteria same as dir1a dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) dir1b = snapshot( ui, repo, dir1b_files, ctx1b.node(), tmproot, subrepos )[0] rev1b = b'@%d' % ctx1b.rev() else: dir1b = None rev1b = b'' fnsandstat = [] # If ctx2 is not the wc or there is >1 change, copy it dir2root = b'' rev2 = b'' if ctx2.node() is not None: dir2 = snapshot(ui, repo, modadd, ctx2.node(), tmproot, subrepos)[0] rev2 = b'@%d' % ctx2.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 not opts.get(b'per_file'): # 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 = pycompat.osdevnull if do3way: dir1b = os.path.join(tmproot, dir1b, common_file) label1b = common_file + rev1b if not os.path.isfile(dir1b): dir1b = pycompat.osdevnull dir2 = os.path.join(dir2root, dir2, common_file) label2 = common_file + rev2 # 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=opts.get(b'confirm'), commonfiles=common, tmproot=tmproot, dir1a=os.path.join(tmproot, dir1a), dir1b=os.path.join(tmproot, dir1b) if do3way else None, dir2=os.path.join(dir2root, 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
def _view_file(self, stat, file, force_left=False): import atexit def cleanup(): shutil.rmtree(self.tmproot) if not self.tmproot: self.tmproot = tempfile.mkdtemp(prefix="gtools.") atexit.register(cleanup) def snapshot_node(ui, repo, files, node, tmproot): """ snapshot files as of some revision (adapted from Extdiff extension) """ mf = repo.changectx(node).manifest() dirname = os.path.basename(repo.root) if dirname == "": dirname = "root" dirname = "%s.%s" % (dirname, short(node)) base = os.path.join(tmproot, dirname) try: os.mkdir(base) except: pass ui.note(_("making snapshot of %d files from rev %s\n") % (len(files), short(node))) for fn in files: if not fn in mf: # skipping new file after a merge ? continue wfn = util.pconvert(fn) ui.note(" %s\n" % wfn) dest = os.path.join(base, wfn) destdir = os.path.dirname(dest) if not os.path.isdir(destdir): os.makedirs(destdir) data = repo.wwritedata(wfn, repo.file(wfn).read(mf[wfn])) open(dest, "wb").write(data) return dirname def doedit(): pathroot = self.repo.root copynode = None # if we aren't looking at the wc, copy the node... if stat in "R!" or force_left: copynode = self._node1 elif self._node2: copynode = self._node2 if copynode: copydir = snapshot_node(self.ui, self.repo, [util.pconvert(file)], copynode, self.tmproot) pathroot = os.path.join(self.tmproot, copydir) file_path = os.path.join(pathroot, file) util.system( '%s "%s"' % (editor, file_path), environ={"HGUSER": self.ui.username()}, onerr=util.Abort, errprefix=_("edit failed"), ) editor = ( self.ui.config("tortoisehg", "editor") or self.ui.config("gtools", "editor") or os.environ.get("HGEDITOR") or self.ui.config("ui", "editor") or os.environ.get("EDITOR", "vi") ) if os.path.basename(editor) in ("vi", "vim", "hgeditor"): Prompt("No visual editor configured", "Please configure a visual editor.", self).run() dlg = ConfigDialog(self.repo.root, False) dlg.show_all() dlg.focus_field("tortoisehg.editor") dlg.run() dlg.hide() self.ui = ui.ui() self._parse_config() return file = util.localpath(file) thread = threading.Thread(target=doedit, name="edit:" + file) thread.setDaemon(True) thread.start()
def dodiff(): assert not (hascopies and len(MAR) > 1), \ 'dodiff cannot handle copies when diffing dirs' sa = [mod_a, add_a, rem_a] sb = [mod_b, add_b, rem_b] ctxs = [ctx1a, ctx1b, ctx2] # If more than one file, diff on working dir copy. copyworkingdir = len(MAR) > 1 dirs, labels, fns_and_mtimes = snapshotset(repo, ctxs, sa, sb, cpy, copyworkingdir) dir1a, dir1b, dir2 = dirs label1a, label1b, label2 = labels fns_and_mtime = fns_and_mtimes[2] if len(MAR) > 1 and label2 == '': label2 = 'working files' def getfile(fname, dir, label): file = os.path.join(qtlib.gettempdir(), dir, fname) if os.path.isfile(file): return fname + label, file nullfile = os.path.join(qtlib.gettempdir(), 'empty') fp = open(nullfile, 'w') fp.close() return (hglib.fromunicode(_nonexistant, 'replace') + label, nullfile) # If only one change, diff the files instead of the directories # Handle bogus modifies correctly by checking if the files exist if len(MAR) == 1: file2 = MAR.pop() file2local = util.localpath(file2) if file2 in cto: file1 = util.localpath(cpy[file2]) else: file1 = file2 label1a, dir1a = getfile(file1, dir1a, label1a) if do3way: label1b, dir1b = getfile(file1, dir1b, label1b) label2, dir2 = getfile(file2local, dir2, label2) if do3way: label1a += '[local]' label1b += '[other]' label2 += '[merged]' replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, plabel1=label1a, plabel2=label1b, phash1=str(ctx1a), phash2=str(ctx1b), repo=hglib.fromunicode(repo.displayname), clabel=label2, child=dir2, chash=str(ctx2)) launchtool(diffcmd, args, replace, True) # detect if changes were made to mirrored working files for copy_fn, working_fn, mtime in fns_and_mtime: try: if os.lstat(copy_fn).st_mtime != mtime: ui.debug('file changed while diffing. ' 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) except EnvironmentError: pass # Ignore I/O errors or missing files
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall 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') args = ' '.join(diffopts) do3way = '$parent2' in args if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = cmdutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.parents()[1] else: node1b = nullid # Disable 3-way merge if there is only one parent if do3way: if node1b == nullid: do3way = False matcher = cmdutil.match(repo, pats, opts) mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) if do3way: mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[: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 = tempfile.mkdtemp(prefix='extdiff.') try: # 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)[0] if do3way: dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0] else: dir1b = None fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it dir2root = '' if node2: dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0] 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, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root # 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(dir1a, common_file) if not os.path.isfile(os.path.join(tmproot, dir1a)): dir1a = os.devnull if do3way: dir1b = os.path.join(dir1b, common_file) if not os.path.isfile(os.path.join(tmproot, dir1b)): dir1b = os.devnull dir2 = os.path.join(dir2root, dir2, common_file) # 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 = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, child=dir2) def quote(match): key = match.group()[1:] if not do3way and key == 'parent2': return '' return util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = '\$(parent2|parent1?|child)' if not do3way and not re.search(regex, args): args += ' $parent1 $child' args = re.sub(regex, quote, args) cmdline = util.shellquote(diffcmd) + ' ' + args ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: 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)
def _view_files(self, files, otherparent): from tortoisehg.hgtk import thgconfig def cleanup(): shutil.rmtree(self.tmproot) if not self.tmproot: self.tmproot = tempfile.mkdtemp(prefix='gtools.') atexit.register(cleanup) def snapshot_node(ui, repo, files, node, tmproot): ''' snapshot files as of some revision (adapted from Extdiff extension) ''' ctx = repo[node] mf = ctx.manifest() dirname = os.path.basename(repo.root) if dirname == '': dirname = 'root' dirname = '%s.%s' % (dirname, str(ctx)) base = os.path.join(tmproot, dirname) try: os.mkdir(base) except: pass ui.note(_('making snapshot of %d files from rev %s\n') % (len(files), str(ctx))) for fn in files: if not fn in mf: # skipping new file after a merge ? continue wfn = util.pconvert(fn) ui.note(' %s\n' % wfn) dest = os.path.join(base, wfn) destdir = os.path.dirname(dest) if not os.path.isdir(destdir): os.makedirs(destdir) data = repo.wwritedata(wfn, repo.file(wfn).read(mf[wfn])) open(dest, 'wb').write(data) return dirname def doedit(): pathroot = self.repo.root copynode = None # if we aren't looking at the wc, copy the node... if otherparent: copynode = self._node1 elif self._node2: copynode = self._node2 if copynode: pf = [util.pconvert(f) for f in files] copydir = snapshot_node(self.ui, self.repo, pf, copynode, self.tmproot) pathroot = os.path.join(self.tmproot, copydir) paths = ['"%s"' % os.path.join(pathroot, f) for f in files] command = '%s %s' % (editor, ' '.join(paths)) util.system(command, onerr=self.ui, errprefix=_('edit failed')) editor = (self.ui.config('tortoisehg', 'editor') or self.ui.config('gtools', 'editor') or os.environ.get('HGEDITOR') or self.ui.config('ui', 'editor') or os.environ.get('EDITOR', 'vi')) if os.path.basename(editor) in ('vi', 'vim', 'hgeditor'): Prompt(_('No visual editor configured'), _('Please configure a visual editor.'), self).run() dlg = thgconfig.ConfigDialog(False, focus='tortoisehg.editor') dlg.show_all() dlg.run() dlg.hide() self.ui = ui.ui() self._parse_config() return lfile = util.localpath(files[0]) thread = threading.Thread(target=doedit, name='edit:'+lfile) thread.setDaemon(True) thread.start()
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: node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) else: node1a, node2 = scmutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.p2() else: node1b = nullid # 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 = list( map(set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3])) if do3way: mod_b, add_b, rem_b = list( 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 = tempfile.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' cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()], fntemplate=repo.vfs.reljoin(tmproot, template), match=matcher) label1a = cmdutil.makefilename(repo, template, node1a) label2 = cmdutil.makefilename(repo, template, node2) 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 + util.shellquote(replace[key]) # Match parent2 first, so 'parent1?' will match both parent1 and parent regex = (r'''(['"]?)([^\s'"$]*)''' r'\$(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' % (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.st_mtime != st.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)
def editfiles(repo, files, lineno=None, search=None, parent=None): if len(files) == 1: # if editing a single file, open in cwd context of that file filename = files[0].strip() if not filename: return files = [filename] path = repo.wjoin(filename) cwd = os.path.dirname(path) files = [os.path.basename(path)] else: # else edit in cwd context of repo root cwd = repo.root toolpath, args, argsln, argssearch = editor.detecteditor(repo, files) if os.path.basename(toolpath) in ('vi', 'vim', 'hgeditor'): res = QMessageBox.critical(parent, _('No visual editor configured'), _('Please configure a visual editor.')) from tortoisehg.hgqt.settings import SettingsDialog dlg = SettingsDialog(False, focus='tortoisehg.editor') dlg.exec_() return files = [util.shellquote(util.localpath(f)) for f in files] assert len(files) == 1 or lineno == None cmdline = None if search: assert lineno is not None if argssearch: cmdline = ' '.join([toolpath, argssearch]) cmdline = cmdline.replace('$LINENUM', str(lineno)) cmdline = cmdline.replace('$SEARCH', search) elif argsln: cmdline = ' '.join([toolpath, argsln]) cmdline = cmdline.replace('$LINENUM', str(lineno)) elif args: cmdline = ' '.join([toolpath, args]) elif lineno: if argsln: cmdline = ' '.join([toolpath, argsln]) cmdline = cmdline.replace('$LINENUM', str(lineno)) elif args: cmdline = ' '.join([toolpath, args]) else: if args: cmdline = ' '.join([toolpath, args]) if cmdline is None: # editor was not specified by editor-tools configuration, fall # back to older tortoisehg.editor OpenAtLine parsing cmdline = ' '.join([toolpath] + files) # default try: regexp = re.compile('\[([^\]]*)\]') expanded = [] pos = 0 for m in regexp.finditer(toolpath): expanded.append(toolpath[pos:m.start() - 1]) phrase = toolpath[m.start() + 1:m.end() - 1] pos = m.end() + 1 if '$LINENUM' in phrase: if lineno is None: # throw away phrase continue phrase = phrase.replace('$LINENUM', str(lineno)) elif '$SEARCH' in phrase: if search is None: # throw away phrase continue phrase = phrase.replace('$SEARCH', search) if '$FILE' in phrase: phrase = phrase.replace('$FILE', files[0]) files = [] expanded.append(phrase) expanded.append(toolpath[pos:]) cmdline = ' '.join(expanded + files) except ValueError, e: # '[' or ']' not found pass except TypeError, e: # variable expansion failed pass
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall 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') if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) node1 = repo[node2].parents()[0].node() else: node1, node2 = cmdutil.revpair(repo, revs) matcher = cmdutil.match(repo, pats, opts) modified, added, removed = repo.status(node1, node2, matcher)[:3] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] changes = len(modified) + len(removed) + len(added) # If node2 in not the wc or there is >1 change, copy it if node2 or changes > 1: dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root fns_and_mtime = [] # If only one change, diff the files instead of the directories if changes == 1: if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed): dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug(_('running %r in %s\n') % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: 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)
def rename(self): if not self.closed: posixfile_utf8.close(self) util.rename(self.temp, util.localpath(self.__name))
def dodiff(ui, repo, diffcmd, diffopts, pats, opts): '''Do the actuall 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 ''' node1, node2 = cmdutil.revpair(repo, opts['rev']) files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) modified, added, removed, deleted, unknown = repo.status( node1, node2, files, match=matchfn)[:5] if not (modified or added or removed): return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') dir2root = '' try: # Always make a copy of node1 dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot) changes = len(modified) + len(removed) + len(added) fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it if node2: dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot) elif changes > 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, fns_and_mtime = snapshot_wdir(ui, repo, modified + added, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root # If only one change, diff the files instead of the directories if changes == 1 : if len(modified): dir1 = os.path.join(dir1, util.localpath(modified[0])) dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) elif len(removed) : dir1 = os.path.join(dir1, util.localpath(removed[0])) dir2 = os.devnull else: dir1 = os.devnull dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) cmdline = ('%s %s %s %s' % (util.shellquote(diffcmd), ' '.join(diffopts), util.shellquote(dir1), util.shellquote(dir2))) ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: 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)
def copypath(self): absfiles = [util.localpath(self.repo.wjoin(f)) for f in self._selectedfiles] QApplication.clipboard().setText( hglib.tounicode(os.linesep.join(absfiles)))
def editfiles(repo, files, lineno=None, search=None, parent=None): if len(files) == 1: # if editing a single file, open in cwd context of that file filename = files[0].strip() if not filename: return files = [filename] path = repo.wjoin(filename) cwd = os.path.dirname(path) files = [os.path.basename(path)] else: # else edit in cwd context of repo root cwd = repo.root toolpath, args, argsln, argssearch = editor.detecteditor(repo, files) if os.path.basename(toolpath) in ('vi', 'vim', 'hgeditor'): res = QMessageBox.critical(parent, _('No visual editor configured'), _('Please configure a visual editor.')) from tortoisehg.hgqt.settings import SettingsDialog dlg = SettingsDialog(False, focus='tortoisehg.editor') dlg.exec_() return files = [util.shellquote(util.localpath(f)) for f in files] assert len(files) == 1 or lineno == None cmdline = None if search: assert lineno is not None if argssearch: cmdline = ' '.join([toolpath, argssearch]) cmdline = cmdline.replace('$LINENUM', str(lineno)) cmdline = cmdline.replace('$SEARCH', search) elif argsln: cmdline = ' '.join([toolpath, argsln]) cmdline = cmdline.replace('$LINENUM', str(lineno)) elif args: cmdline = ' '.join([toolpath, args]) elif lineno: if argsln: cmdline = ' '.join([toolpath, argsln]) cmdline = cmdline.replace('$LINENUM', str(lineno)) elif args: cmdline = ' '.join([toolpath, args]) else: if args: cmdline = ' '.join([toolpath, args]) if cmdline is None: # editor was not specified by editor-tools configuration, fall # back to older tortoisehg.editor OpenAtLine parsing cmdline = ' '.join([toolpath] + files) # default try: regexp = re.compile('\[([^\]]*)\]') expanded = [] pos = 0 for m in regexp.finditer(toolpath): expanded.append(toolpath[pos:m.start()-1]) phrase = toolpath[m.start()+1:m.end()-1] pos = m.end()+1 if '$LINENUM' in phrase: if lineno is None: # throw away phrase continue phrase = phrase.replace('$LINENUM', str(lineno)) elif '$SEARCH' in phrase: if search is None: # throw away phrase continue phrase = phrase.replace('$SEARCH', search) if '$FILE' in phrase: phrase = phrase.replace('$FILE', files[0]) files = [] expanded.append(phrase) expanded.append(toolpath[pos:]) cmdline = ' '.join(expanded + files) except ValueError, e: # '[' or ']' not found pass except TypeError, e: # variable expansion failed pass
def close(self): if not self.closed: posixfile_utf8.close(self) util.rename(self._tempname, util.localpath(self.__name))