示例#1
0
    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)
示例#2
0
 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
示例#3
0
 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
示例#4
0
 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
示例#5
0
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)
示例#6
0
    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)
示例#7
0
 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
示例#8
0
    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)
示例#9
0
    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
示例#10
0
 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")
示例#12
0
    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
示例#13
0
 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)
示例#14
0
    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))
示例#15
0
 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)
示例#16
0
    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
示例#17
0
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))
示例#19
0
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)
示例#20
0
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))
示例#21
0
 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
示例#22
0
 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()
示例#23
0
 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
示例#24
0
    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())
示例#25
0
 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)
示例#26
0
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)
示例#27
0
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)
示例#28
0
文件: extdiff.py 项目: CJX32/my_blog
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)
示例#29
0
 def copypath(self):
     absfiles = [
         util.localpath(self.repo.wjoin(f)) for f in self._selectedfiles
     ]
     QApplication.clipboard().setText(
         hglib.tounicode(os.linesep.join(absfiles)))
示例#30
0
'''

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(
示例#31
0
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)
示例#32
0
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)
示例#33
0
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)
示例#34
0
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
示例#35
0
    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()
示例#36
0
    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
示例#37
0
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)
示例#38
0
    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()
示例#39
0
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)
示例#40
0
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
示例#41
0
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)
示例#42
0
 def rename(self):
     if not self.closed:
         posixfile_utf8.close(self)
         util.rename(self.temp, util.localpath(self.__name))
示例#43
0
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)))
示例#45
0
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
示例#46
0
 def close(self):
     if not self.closed:
         posixfile_utf8.close(self)
         util.rename(self._tempname, util.localpath(self.__name))