def filter(self, filter, node, changelog, patchfile):
        """arbitrarily rewrite changeset before applying it"""

        self.ui.status(_("filtering %s\n") % patchfile)
        user, date, msg = (changelog[1], changelog[2], changelog[4])
        fd, headerfile = tempfile.mkstemp(prefix="hg-transplant-")
        fp = os.fdopen(fd, "w")
        fp.write("# HG changeset patch\n")
        fp.write("# User %s\n" % user)
        fp.write("# Date %d %d\n" % date)
        fp.write(msg + "\n")
        fp.close()

        try:
            util.system(
                "%s %s %s" % (filter, util.shellquote(headerfile), util.shellquote(patchfile)),
                environ={"HGUSER": changelog[1], "HGREVISION": revlog.hex(node)},
                onerr=util.Abort,
                errprefix=_("filter failed"),
                out=self.ui.fout,
            )
            user, date, msg = self.parselog(file(headerfile))[1:4]
        finally:
            os.unlink(headerfile)

        return (user, date, msg)
Esempio n. 2
0
    def filter(self, filter, changelog, patchfile):
        '''arbitrarily rewrite changeset before applying it'''

        self.ui.status('filtering %s\n' % patchfile)
        user, date, msg = (changelog[1], changelog[2], changelog[4])

        fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
        fp = os.fdopen(fd, 'w')
        fp.write("# HG changeset patch\n")
        fp.write("# User %s\n" % user)
        fp.write("# Date %d %d\n" % date)
        fp.write(changelog[4])
        fp.close()

        try:
            util.system('%s %s %s' % (filter, util.shellquote(headerfile),
                                      util.shellquote(patchfile)),
                        environ={'HGUSER': changelog[1]},
                        onerr=util.Abort,
                        errprefix=_('filter failed'))
            user, date, msg = self.parselog(file(headerfile))[1:4]
        finally:
            os.unlink(headerfile)

        return (user, date, msg)
Esempio n. 3
0
def view(ui, repo, *etc, **opts):
    "start interactive history viewer"
    os.chdir(repo.root)
    optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
    cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
    ui.debug("running %s\n" % cmd)
    util.system(cmd)
Esempio n. 4
0
    def filter(self, filter, node, changelog, patchfile):
        '''arbitrarily rewrite changeset before applying it'''

        self.ui.status(_('filtering %s\n') % patchfile)
        user, date, msg = (changelog[1], changelog[2], changelog[4])
        fd, headerfile = tempfile.mkstemp(prefix='hg-transplant-')
        fp = os.fdopen(fd, 'w')
        fp.write("# HG changeset patch\n")
        fp.write("# User %s\n" % user)
        fp.write("# Date %d %d\n" % date)
        fp.write(msg + '\n')
        fp.close()

        try:
            util.system('%s %s %s' % (filter, util.shellquote(headerfile),
                                   util.shellquote(patchfile)),
                        environ={'HGUSER': changelog[1],
                                 'HGREVISION': revlog.hex(node),
                                 },
                        onerr=util.Abort, errprefix=_('filter failed'),
                        out=self.ui.fout)
            user, date, msg = self.parselog(file(headerfile))[1:4]
        finally:
            os.unlink(headerfile)

        return (user, date, msg)
Esempio n. 5
0
 def execCmd(sub, cmd, kind):
     """if sub == None, cmd is executed inside repo; else, inside sub.
     If cmd == None, do nothing. If cmd == '', do only the print0 (if needed). 
     Else, do either print0 or the debugging message, then execute the command.
     kind is the type of the (sub)repo.
     """
     if sub == None:
         envargdict = dict(HG_SUBPATH='.',
                           HG_SUBURL='.',
                           HG_SUBSTATE=repo['.'].hex(),
                           HG_REPO=repo.root,
                           HG_SUBTYPE=kind)
         relpath = '.'
         cmdwd = repo.root
     else:
         # subrepo.relpath was renamed to subrepo.subrelpath in
         # 18b5b6392fcf.
         if hasattr(subrepo, 'relpath'):
             relpath = subrepo.relpath(sub)
         else:
             relpath = subrepo.subrelpath(sub)
         envargdict = dict(HG_SUBPATH=relpath,
                           HG_SUBURL=sub._path,
                           HG_SUBSTATE=sub._state[1],
                           HG_REPO=repo.root,
                           HG_SUBTYPE=kind)
         cmdwd = os.path.join(repo.root, relpath)
     if cmd != None and (repotypefilter == '' or repotypefilter == kind):
         if print0:
             ui.write(relpath, "\0")
         if cmd != '':
             if not print0: ui.note(_("executing '%s' in %s\n") % (cmd, relpath))
             util.system(cmd, environ=envargdict, cwd=cmdwd, onerr=onerr,
                         errprefix=_('terminated onsub in %s') % relpath)
Esempio n. 6
0
def view(ui, repo, *etc, **opts):
    "start interactive history viewer"
    os.chdir(repo.root)
    optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
    cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
    ui.debug(_("running %s\n") % cmd)
    util.system(cmd)
Esempio n. 7
0
def foreach(ui, repo, cmd, depthfirst, maxdepth, print0, ignoreerrors):
    """execute cmd in repo.root and in each subrepository"""
    ctx = repo['.']
    work = [(1, ctx.sub(subpath)) for subpath in sorted(ctx.substate)]
    if depthfirst:
        work.reverse()

    while work:
        if depthfirst:
            (depth, sub) = work.pop()
        else:
            (depth, sub) = work.pop(0)
        if depth > maxdepth >= 0:
            continue

        # subrepo.relpath was renamed to subrepo.subrelpath in
        # 18b5b6392fcf.
        if hasattr(subrepo, 'relpath'):
            relpath = subrepo.relpath(sub)
        else:
            relpath = subrepo.subrelpath(sub)

        if print0:
            ui.write(relpath, "\0")
        else:
            ui.note(_("executing '%s' in %s\n") % (cmd, relpath))
        if ignoreerrors:
            onerr = None
        else:
            onerr = util.Abort
        util.system(cmd,
                    environ=dict(HG_SUBPATH=relpath,
                                 HG_SUBURL=sub._path,
                                 HG_SUBSTATE=sub._state[1],
                                 HG_REPO=repo.root),
                    cwd=os.path.join(repo.root, relpath),
                    onerr=onerr,
                    errprefix=_('terminated onsub in %s') % relpath)

        if isinstance(sub, subrepo.hgsubrepo):
            rev = sub._state[1]
            ctx = sub._repo[rev]
            w = [(depth + 1, ctx.sub(subpath))
                 for subpath in sorted(ctx.substate)]
            if depthfirst:
                w.reverse()
            work.extend(w)
Esempio n. 8
0
def foreach(ui, repo, cmd, depthfirst, maxdepth, print0, ignoreerrors):
    """execute cmd in repo.root and in each subrepository"""
    ctx = repo['.']
    work = [(1, ctx.sub(subpath)) for subpath in sorted(ctx.substate)]
    if depthfirst:
        work.reverse()

    while work:
        if depthfirst:
            (depth, sub) = work.pop()
        else:
            (depth, sub) = work.pop(0)
        if depth > maxdepth >= 0:
            continue

        # subrepo.relpath was renamed to subrepo.subrelpath in
        # 18b5b6392fcf.
        if hasattr(subrepo, 'relpath'):
            relpath = subrepo.relpath(sub)
        else:
            relpath = subrepo.subrelpath(sub)

        if print0:
            ui.write(relpath, "\0")
        else:
            ui.note(_("executing '%s' in %s\n") % (cmd, relpath))
        if ignoreerrors:
            onerr = None
        else:
            onerr = util.Abort
        util.system(cmd, environ=dict(HG_SUBPATH=relpath,
                                      HG_SUBURL=sub._path,
                                      HG_SUBSTATE=sub._state[1],
                                      HG_REPO=repo.root),
                    cwd=os.path.join(repo.root, relpath),
                    onerr=onerr,
                    errprefix=_('terminated onsub in %s') % relpath)

        if isinstance(sub, subrepo.hgsubrepo):
            rev = sub._state[1]
            ctx = sub._repo[rev]
            w = [(depth + 1, ctx.sub(subpath))
                 for subpath in sorted(ctx.substate)]
            if depthfirst:
                w.reverse()
            work.extend(w)
Esempio n. 9
0
        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'))
Esempio n. 10
0
        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"),
            )
Esempio n. 11
0
 def execCmd(sub, cmd, kind):
     """if sub == None, cmd is executed inside repo; else, inside sub.
     If cmd == None, do nothing. If cmd == '', do only the print0 (if needed). 
     Else, do either print0 or the debugging message, then execute the command.
     kind is the type of the (sub)repo.
     """
     if sub == None:
         envargdict = dict(HG_SUBPATH='.',
                           HG_SUBURL='.',
                           HG_SUBSTATE=repo['.'].hex(),
                           HG_REPO=repo.root,
                           HG_SUBTYPE=kind)
         relpath = '.'
         cmdwd = repo.root
     else:
         # subrepo.relpath was renamed to subrepo.subrelpath in
         # 18b5b6392fcf.
         if hasattr(subrepo, 'relpath'):
             relpath = subrepo.relpath(sub)
         else:
             relpath = subrepo.subrelpath(sub)
         envargdict = dict(HG_SUBPATH=relpath,
                           HG_SUBURL=sub._path,
                           HG_SUBSTATE=sub._state[1],
                           HG_REPO=repo.root,
                           HG_SUBTYPE=kind)
         cmdwd = os.path.join(repo.root, relpath)
     if cmd != None and (repotypefilter == '' or repotypefilter == kind):
         if print0:
             ui.write(relpath, "\0")
         if cmd != '':
             if not print0:
                 ui.write(_("executing '%s' in %s\n") % (cmd, relpath))
             util.system(cmd,
                         environ=envargdict,
                         cwd=cmdwd,
                         onerr=onerr,
                         errprefix=_('terminated onsub in %s') % relpath)
Esempio n. 12
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)
Esempio n. 13
0
    def prompt(skipfile, skipall, query, chunk):
        """prompt query, and process base inputs

        - y/n for the rest of file
        - y/n for the rest
        - ? (help)
        - q (quit)

        Return True/False and possibly updated skipfile and skipall.
        """
        newpatches = None
        if skipall is not None:
            return skipall, skipfile, skipall, newpatches
        if skipfile is not None:
            return skipfile, skipfile, skipall, newpatches
        while True:
            resps = _(
                "[Ynesfdaq?]"
                "$$ &Yes, record this change"
                "$$ &No, skip this change"
                "$$ &Edit the change manually"
                "$$ &Skip remaining changes to this file"
                "$$ Record remaining changes to this &file"
                "$$ &Done, skip remaining changes and files"
                "$$ Record &all changes to all remaining files"
                "$$ &Quit, recording no changes"
                "$$ &?"
            )
            r = ui.promptchoice("%s %s" % (query, resps))
            ui.write("\n")
            if r == 8:  # ?
                doc = gettext(record.__doc__)
                c = doc.find("::") + 2
                for l in doc[c:].splitlines():
                    if l.startswith("      "):
                        ui.write(l.strip(), "\n")
                continue
            elif r == 0:  # yes
                ret = True
            elif r == 1:  # no
                ret = False
            elif r == 2:  # Edit patch
                if chunk is None:
                    ui.write(_("cannot edit patch for whole file"))
                    ui.write("\n")
                    continue
                if chunk.header.binary():
                    ui.write(_("cannot edit patch for binary file"))
                    ui.write("\n")
                    continue
                # Patch comment based on the Git one (based on comment at end of
                # http://mercurial.selenic.com/wiki/RecordExtension)
                phelp = "---" + _(
                    """
To remove '-' lines, make them ' ' lines (context).
To remove '+' lines, delete them.
Lines starting with # will be removed from the patch.

If the patch applies cleanly, the edited hunk will immediately be
added to the record list. If it does not apply cleanly, a rejects
file will be generated: you can use that when you try again. If
all lines of the hunk are removed, then the edit is aborted and
the hunk is left unchanged.
"""
                )
                (patchfd, patchfn) = tempfile.mkstemp(prefix="hg-editor-", suffix=".diff", text=True)
                ncpatchfp = None
                try:
                    # Write the initial patch
                    f = os.fdopen(patchfd, "w")
                    chunk.header.write(f)
                    chunk.write(f)
                    f.write("\n".join(["# " + i for i in phelp.splitlines()]))
                    f.close()
                    # Start the editor and wait for it to complete
                    editor = ui.geteditor()
                    util.system(
                        '%s "%s"' % (editor, patchfn),
                        environ={"HGUSER": ui.username()},
                        onerr=util.Abort,
                        errprefix=_("edit failed"),
                        out=ui.fout,
                    )
                    # Remove comment lines
                    patchfp = open(patchfn)
                    ncpatchfp = cStringIO.StringIO()
                    for line in patchfp:
                        if not line.startswith("#"):
                            ncpatchfp.write(line)
                    patchfp.close()
                    ncpatchfp.seek(0)
                    newpatches = parsepatch(ncpatchfp)
                finally:
                    os.unlink(patchfn)
                    del ncpatchfp
                # Signal that the chunk shouldn't be applied as-is, but
                # provide the new patch to be used instead.
                ret = False
            elif r == 3:  # Skip
                ret = skipfile = False
            elif r == 4:  # file (Record remaining)
                ret = skipfile = True
            elif r == 5:  # done, skip remaining
                ret = skipall = False
            elif r == 6:  # all
                ret = skipall = True
            elif r == 7:  # quit
                raise util.Abort(_("user quit"))
            return ret, skipfile, skipall, newpatches
Esempio n. 14
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)
Esempio n. 15
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)
Esempio n. 16
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)
Esempio n. 17
0
def dodiff(ui, repo, diffcmd, diffopts, 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")
    args = " ".join(map(util.shellquote, 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 = 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):
            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|plabel1|plabel2|clabel|root)"
        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, out=ui.fout)

        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)
Esempio n. 18
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)
Esempio n. 19
0
 def doedit():
     util.system('%s "%s"' % (editor, file))
Esempio n. 20
0
    def prompt(skipfile, skipall, query, chunk):
        """prompt query, and process base inputs

        - y/n for the rest of file
        - y/n for the rest
        - ? (help)
        - q (quit)

        Return True/False and possibly updated skipfile and skipall.
        """
        newpatches = None
        if skipall is not None:
            return skipall, skipfile, skipall, newpatches
        if skipfile is not None:
            return skipfile, skipfile, skipall, newpatches
        while True:
            resps = _('[Ynesfdaq?]'
                      '$$ &Yes, record this change'
                      '$$ &No, skip this change'
                      '$$ &Edit this change manually'
                      '$$ &Skip remaining changes to this file'
                      '$$ Record remaining changes to this &file'
                      '$$ &Done, skip remaining changes and files'
                      '$$ Record &all changes to all remaining files'
                      '$$ &Quit, recording no changes'
                      '$$ &? (display help)')
            r = ui.promptchoice("%s %s" % (query, resps))
            ui.write("\n")
            if r == 8: # ?
                for c, t in ui.extractchoices(resps)[1]:
                    ui.write('%s - %s\n' % (c, t.lower()))
                continue
            elif r == 0: # yes
                ret = True
            elif r == 1: # no
                ret = False
            elif r == 2: # Edit patch
                if chunk is None:
                    ui.write(_('cannot edit patch for whole file'))
                    ui.write("\n")
                    continue
                if chunk.header.binary():
                    ui.write(_('cannot edit patch for binary file'))
                    ui.write("\n")
                    continue
                # Patch comment based on the Git one (based on comment at end of
                # http://mercurial.selenic.com/wiki/RecordExtension)
                phelp = '---' + _("""
To remove '-' lines, make them ' ' lines (context).
To remove '+' lines, delete them.
Lines starting with # will be removed from the patch.

If the patch applies cleanly, the edited hunk will immediately be
added to the record list. If it does not apply cleanly, a rejects
file will be generated: you can use that when you try again. If
all lines of the hunk are removed, then the edit is aborted and
the hunk is left unchanged.
""")
                (patchfd, patchfn) = tempfile.mkstemp(prefix="hg-editor-",
                        suffix=".diff", text=True)
                ncpatchfp = None
                try:
                    # Write the initial patch
                    f = os.fdopen(patchfd, "w")
                    chunk.header.write(f)
                    chunk.write(f)
                    f.write('\n'.join(['# ' + i for i in phelp.splitlines()]))
                    f.close()
                    # Start the editor and wait for it to complete
                    editor = ui.geteditor()
                    util.system("%s \"%s\"" % (editor, patchfn),
                            environ={'HGUSER': ui.username()},
                            onerr=util.Abort, errprefix=_("edit failed"),
                            out=ui.fout)
                    # Remove comment lines
                    patchfp = open(patchfn)
                    ncpatchfp = cStringIO.StringIO()
                    for line in patchfp:
                        if not line.startswith('#'):
                            ncpatchfp.write(line)
                    patchfp.close()
                    ncpatchfp.seek(0)
                    newpatches = parsepatch(ncpatchfp)
                finally:
                    os.unlink(patchfn)
                    del ncpatchfp
                # Signal that the chunk shouldn't be applied as-is, but
                # provide the new patch to be used instead.
                ret = False
            elif r == 3: # Skip
                ret = skipfile = False
            elif r == 4: # file (Record remaining)
                ret = skipfile = True
            elif r == 5: # done, skip remaining
                ret = skipall = False
            elif r == 6: # all
                ret = skipall = True
            elif r == 7: # quit
                raise util.Abort(_('user quit'))
            return ret, skipfile, skipall, newpatches