Пример #1
0
def revert(parent, ui, repo, files):
    revertopts = {'date': None, 'rev': '.', 'all': False}

    if len(repo.parents()) > 1:
        res = qtlib.CustomPrompt(
            _('Uncommited merge - please select a parent revision'),
            _('Revert files to local or other parent?'), parent,
            (_('&Local'), _('&Other'), _('Cancel')), 0, 2, files).run()
        if res == 0:
            revertopts['rev'] = repo[None].p1().rev()
        elif res == 1:
            revertopts['rev'] = repo[None].p2().rev()
        else:
            return False
        commands.revert(ui, repo, *files, **revertopts)
    else:
        wctx = repo[None]
        if [file for file in files if file in wctx.modified()]:
            res = qtlib.CustomPrompt(
                _('Confirm Revert'), _('Revert local file changes?'), parent,
                (_('&Revert with backup'), _('&Discard changes'), _('Cancel')),
                2, 2, files).run()
            if res == 2:
                return False
            if res == 1:
                revertopts['no_backup'] = True
        else:
            res = qtlib.CustomPrompt(_('Confirm Revert'),
                                     _('Revert the following files?'), parent,
                                     (_('&Revert'), _('Cancel')), 1, 1,
                                     files).run()
            if res == 1:
                return False
        commands.revert(ui, repo, *files, **revertopts)
        return True
Пример #2
0
 def revert(self, files, no_backup=True):
     opts = {
       'no_backup': no_backup,
       'date': '',
       'rev': '',
     }
     commands.revert(self.ui, self.repository, *[os.path.join(self.path, fn) for fn in files], **opts)
Пример #3
0
 def cleanup(self):
     try:
         commands.revert(self.repo.ui, self.repo, date=None, rev=None, 
                         all=True, no_backup=True)
         hg.clean(self.repo, self.branch, show_stats=False)
     except Exception, e:
         logger.error(e)
Пример #4
0
def makecollapsed(ui, repo, parent, revs):
    'Creates the collapsed revision on top of parent'

    last = max(revs)
    ui.debug(_('updating to revision %d\n') % parent)
    merge.update(repo, parent.node(), False, False, False)
    ui.debug(_('reverting to revision %d\n') % last)
    commands.revert(ui, repo, rev=last, all=True, date=None)
    msg = ''

    first = True
    for r in revs:
        if not first:
            msg += '----------------\n'
        first = False
        msg += repo[r].description() + "\n"

    msg += "\nHG: Enter commit message.  Lines beginning with 'HG:' are removed.\n"
    msg += "HG: Remove all lines to abort the collapse operation.\n"

    msg = ui.edit(msg, ui.username())

    if not msg:
        raise util.Abort(_('empty commit message, collapse won\'t proceed'))

    newrev = repo.commit(
        text=msg,
        user=repo[last].user(),
        date=repo[last].date())

    return repo[newrev]
Пример #5
0
 def removeFile(self, wfile):
     repo = self.repo
     ctx = self.ctx
     if isinstance(ctx, patchctx):
         repo.thgbackup(ctx._path)
         fp = util.atomictempfile(ctx._path, 'wb')
         try:
             if ctx._ph.comments:
                 fp.write('\n'.join(ctx._ph.comments))
                 fp.write('\n\n')
             for file in ctx._fileorder:
                 if file == wfile:
                     continue
                 for chunk in ctx._files[file]:
                     chunk.write(fp)
             fp.close()
         finally:
             del fp
         ctx.invalidate()
     else:
         fullpath = repo.wjoin(wfile)
         repo.thgbackup(fullpath)
         wasadded = wfile in repo[None].added()
         try:
             commands.revert(repo.ui, repo, fullpath, rev='.',
                             no_backup=True)
             if wasadded and os.path.exists(fullpath):
                 os.unlink(fullpath)
         except EnvironmentError:
             qtlib.InfoMsgBox(_("Unable to remove"),
                              _("Unable to remove file %s,\n"
                                "permission denied") %
                                 hglib.tounicode(wfile))
     self.fileModified.emit()
Пример #6
0
def movedescendants(ui, repo, collapsed, tomove, movemap):
    'Moves the descendants of the source revisions to the collapsed revision'

    sorted_tomove = list(tomove)
    sorted_tomove.sort()

    for r in sorted_tomove:
        ui.debug(_('moving revision %r\n') % r)
        parents = [p.rev() for p in repo[r].parents()]
        if len(parents) == 1:
            ui.debug(_('setting parent to %d\n') % movemap[parents[0]].rev())
            repo.dirstate.setparents(movemap[parents[0]].node())
        else:
            ui.debug(_('setting parents to %d and %d\n') %
                (movemap[parents[0]].rev(), movemap[parents[1]].rev()))
            repo.dirstate.setparents(movemap[parents[0]].node(),
                movemap[parents[1]].node())

        repo.dirstate.write()

        ui.debug(_('reverting to revision %d\n') % r)
        commands.revert(ui, repo, rev=r, all=True, date=None)
        newrev = repo.commit(text=repo[r].description(), user=repo[r].user(),
                            date=repo[r].date())
        ctx = repo[newrev]
        movemap[r] = ctx
Пример #7
0
    def cleanup(self, repo, pats, opts):
        '''removes all changes from the working copy and makes it so
        there isn't a patch applied'''

        # find added files in the user's chosen set
        m = cmdutil.match(repo, pats, opts)
        added = repo.status(match=m)[1]

        revertopts = { 'include': opts.get('include'),
                       'exclude': opts.get('exclude'),
                       'date': None,
                       'all': True,
                       'rev': '.',
                       'no_backup': True,
                     }
        self.ui.pushbuffer()            # silence revert
        try:
            commands.revert(self.ui, repo, *pats, **revertopts)

            # finish the job of reverting added files (safe because they are
            # saved in the attic patch)
            for fn in added:
                self.ui.status(_('removing %s\n') % fn)
                util.unlink(fn)
        finally:
            self.ui.popbuffer()

        self.applied = ''
        self.persiststate()
Пример #8
0
    def cleanup(self, repo, pats, opts):
        '''removes all changes from the working copy and makes it so
        there isn't a patch applied'''

        # find added files in the user's chosen set
        m = cmdutil.match(repo, pats, opts)
        added = repo.status(match=m)[1]

        revertopts = {
            'include': opts.get('include'),
            'exclude': opts.get('exclude'),
            'date': None,
            'all': True,
            'rev': '.',
            'no_backup': True,
        }
        self.ui.pushbuffer()  # silence revert
        try:
            commands.revert(self.ui, repo, *pats, **revertopts)

            # finish the job of reverting added files (safe because they are
            # saved in the attic patch)
            for fn in added:
                self.ui.status(_('removing %s\n') % fn)
                util.unlink(fn)
        finally:
            self.ui.popbuffer()

        self.applied = ''
        self.persiststate()
    def clean_working_copy(self):
        self.strip_outgoing()

        self.ui.pushbuffer()
        try:
            commands.update(self.ui, self.repo, clean=True)
            commands.revert(self.ui, self.repo, all=True, no_backup=True)
        finally:
            self.ui.popbuffer()
Пример #10
0
def recreaterev(ui, repo, rev):
    ui.debug(_('reverting to revision %d\n') % rev)
    commands.revert(ui, repo, rev=rev, all=True, date=None)

    wctx = repo[None]
    node = repo[rev]

    ss = node.substate

    for path, info in ss.items():
        ui.debug(_('updating subrepo %s to revision %s\n') % (path, info[1]))
        wctx.sub(path).get(info)
Пример #11
0
def recreaterev(ui, repo, rev):
    ui.debug(_('reverting to revision %d\n') % rev)
    commands.revert(ui, repo, rev=rev, all=True, date=None, no_backup=True)

    wctx = repo[None]
    node = repo[rev]

    ss = node.substate

    for path, info in ss.items():
        ui.debug(_('updating subrepo %s to revision %s\n') % (path, info[1]))
        wctx.sub(path).get(info)
Пример #12
0
 def clearShelfA(self):
     if self.comboa.currentIndex() == 0:
         if not qtlib.QuestionMsgBox(_('Are you sure?'),
                                     _('Revert all working copy changes?')):
             return
         try:
             self.repo.ui.quiet = True
             commands.revert(self.repo.ui, self.repo, all=True)
             self.repo.ui.quiet = False
         except (EnvironmentError, error.Abort), e:
             self.showMessage(hglib.tounicode(str(e)))
             self.refreshCombos()
         return
Пример #13
0
 def clearShelfA(self):
     if self.comboa.currentIndex() == 0:
         if not qtlib.QuestionMsgBox(_('Are you sure?'),
                                     _('Revert all working copy changes?')):
             return
         try:
             self.repo.ui.quiet = True
             commands.revert(self.repo.ui, self.repo, all=True)
             self.repo.ui.quiet = False
         except (EnvironmentError, error.Abort), e:
             self.showMessage(hglib.tounicode(str(e)))
             self.refreshCombos()
         return
Пример #14
0
 def cleanup(self, repo, pats=[], opts={}):
     '''removes all changes from the working copy and makes it so
     there isn't a patch applied'''
     node = repo.dirstate.parents()[0]
     if not pats and not opts.get('include') and not opts.get('exclude'):
         hg.clean(repo, node, False)
     else:
         opts['date'] = None
         opts['all'] = True # Just to trick revert
         opts['rev'] = node
         commands.revert(self.ui, repo, *pats, **opts)
     self.applied = ''
     self.persiststate()
Пример #15
0
 def revert(self, paths, rev=None):
     # XXX: how to pass opts['all']?
     if rev is None:
         parents = self.repo.parents()
         if len(parents) != 1 and rev is None:
             # XXX: better exception type?
             raise Exception(
                 "can't revert on top of a merge without explicit rev")
         rev = parents[0].rev()
     commands.revert(self.ui,
                     self.repo,
                     date=None,
                     rev=rev,
                     no_backup=False,
                     *self.joined(paths))
Пример #16
0
Файл: dv.py Проект: dmayle/DVDev
    def _revert_confirmed(self, repository, filepath):
        """Revert the given file to its pristine state."""
        # The variable passing schema we use means that we'll have problems
        # with a repository named 'on'.  We should look into a fix for that.
        # TODO Make this get require a post and spit back a confirmation form
        url = request.environ['routes.url']

        if not repository or not filepath:
            redirect(url.current(action='index'))

        found = False
        for repoobj, root in self.repositories:
            if root == repository:
                found = True
                repo = repoobj
                break
        if not found:
            redirect(url.current(action='index'))
        repochroot = Chroot(repo.root)
        try:
            fullfilepath = repochroot(path.join(repo.root, filepath))
        except IOError:
            error = 'Bad Filename'
            redirect(url.current(action='index', error=error))
        # repo.status() returns a tuple of lists, each lists containing the
        # files containing a given status.  Those are:
        # modified, added, removed, deleted, unknown, ignored, clean
        statusmapper = dict(enumerate(['modified', 'added', 'removed', 'deleted', 'unknown', 'ignored', 'clean']))

        statuses = repo.status()
        for index, status in statusmapper.iteritems():
            if status not in ['modified', 'added', 'removed', 'deleted']:
                # Unknown, ignored, and clean files can't be reverted...
                if filepath in statuses[index]:
                    c.status = status
                    c.error = "Can't revert this file"
                    return render('dv/revert.html')
                continue
            if filepath in statuses[index]:
                commands.revert(self.ui, repo, fullfilepath, rev='tip', date=None)
                if status == 'added' and request.params.get('remove'):
                    unlink(fullfilepath)
                redirect(url(repository=repository, controller='dv', action='index'))

        c.error = 'Not found'
        return render('dv/revert.html')
Пример #17
0
 def removeFile(self, wfile):
     repo = self.repo
     ctx = self.ctx
     if isinstance(ctx, patchctx):
         repo.thgbackup(ctx._path)
         fp = util.atomictempfile(ctx._path, 'wb')
         try:
             if ctx._ph.comments:
                 fp.write('\n'.join(ctx._ph.comments))
                 fp.write('\n\n')
             for file in ctx._fileorder:
                 if file == wfile:
                     continue
                 for chunk in ctx._files[file]:
                     chunk.write(fp)
             fp.close()
         finally:
             del fp
         ctx.invalidate()
     else:
         fullpath = repo.wjoin(wfile)
         repo.thgbackup(fullpath)
         wasadded = wfile in repo[None].added()
         try:
             commands.revert(repo.ui,
                             repo,
                             fullpath,
                             rev='.',
                             no_backup=True)
             if wasadded and os.path.exists(fullpath):
                 os.unlink(fullpath)
         except EnvironmentError:
             qtlib.InfoMsgBox(
                 _("Unable to remove"),
                 _("Unable to remove file %s,\n"
                   "permission denied") % hglib.tounicode(wfile))
     self.fileModified.emit()
Пример #18
0
def revert(parent, ui, repo, files):
    revertopts = {'date': None, 'rev': '.', 'all': False}

    if len(repo.parents()) > 1:
        res = qtlib.CustomPrompt(
                _('Uncommited merge - please select a parent revision'),
                _('Revert files to local or other parent?'), parent,
                (_('&Local'), _('&Other'), _('Cancel')), 0, 2, files).run()
        if res == 0:
            revertopts['rev'] = repo[None].p1().rev()
        elif res == 1:
            revertopts['rev'] = repo[None].p2().rev()
        else:
            return False
        commands.revert(ui, repo, *files, **revertopts)
    else:
        wctx = repo[None]
        if [file for file in files if file in wctx.modified()]:
            res = qtlib.CustomPrompt(
                _('Confirm Revert'),
                _('Revert local file changes?'), parent,
                (_('&Revert with backup'), _('&Discard changes'),
                _('Cancel')), 2, 2, files).run()
            if res == 2:
                return False
            if res == 1:
                revertopts['no_backup'] = True
        else:
            res = qtlib.CustomPrompt(
                    _('Confirm Revert'),
                    _('Revert the following files?'),
                    parent, (_('&Revert'), _('Cancel')), 1, 1, files).run()
            if res == 1:
                return False
        commands.revert(ui, repo, *files, **revertopts)
        return True
Пример #19
0
def revert(parent, ui, repo, files):
    revertopts = {"date": None, "rev": "."}

    if len(repo.parents()) > 1:
        res = qtlib.CustomPrompt(
            _("Uncommited merge - please select a parent revision"),
            _("Revert files to local or other parent?"),
            parent,
            (_("&Local"), _("&Other"), _("Cancel")),
            0,
            2,
            files,
        ).run()
        if res == 0:
            revertopts["rev"] = repo[None].p1().rev()
        elif res == 1:
            revertopts["rev"] = repo[None].p2().rev()
        else:
            return
        commands.revert(ui, repo, *files, **revertopts)
    else:
        res = qtlib.CustomPrompt(
            _("Confirm Revert"),
            _("Revert local file changes?"),
            parent,
            (_("&Revert with backup"), _("&Discard changes"), _("Cancel")),
            2,
            2,
            files,
        ).run()
        if res == 2:
            return False
        if res == 1:
            revertopts["no_backup"] = True
        commands.revert(ui, repo, *files, **revertopts)
        return True
Пример #20
0
def tclose(ui, repo, *args, **opts):
  """ close the current topic branch and push to the central repository """

  mustBeTopicRepo(repo)

  # Sanity check
  if not isClean(ui, repo):
    return 1

  if args:
    branches = args
  else:
    if not onTopicBranch(ui, repo):
      return 1
    branches = [repo.dirstate.branch()]

  if 'tmenu' in opts:
    if ui.prompt("Branch '%s': close it?" % branches[0]).upper() != 'Y':
      return 1
    opts = { 'nopull':False, 'nopush':False }

  pulled = False # only pull once

  for branch in branches:

    # Pull new changes from the central repo to avoid multiple-heads problem
    if not opts['nopull'] and not pulled:
      if tryCommand(ui, "pull", lambda:commands.pull(ui, repo, **opts) >= 2):
        return 1
      pulled = True

    # Can't close already closed branches, nor any of the special branches
    if not repo.branchheads(branch) or branch in repo.topicSpecialBranches:
      ui.warn("Error: %s is not an open topic branch\n" % branch)
      return 1

    # Now update to the head of the branch being closed
    if repo.dirstate.parents()[0] not in repo.branchheads(branch):
      if tryCommand(ui, "update %s" % quoteBranch(branch), lambda:commands.update(ui, repo, node=branch)):
        return 1

    # Unlike a normal hg commit, if no text is specified we supply a reasonable default.
    branch = repo.dirstate.branch()
    text = opts.get('message')
    if text is None:
      text = "Closing %s" % branch

    # Close it
    if tryCommand(ui, "commit --close-branch", lambda:repo.commit(text, extra = {'close':'True'}) is None):
      return 1

    # Aditionally, for this to not be considered a "head" it has to have a
    # child commit. So we have to merge into prod. First, update.
    #
    if tryCommand(ui, "update %s" % repo.topicProdBranch, lambda:commands.update(ui, repo, node=repo.topicProdBranch)):
      return 1

    # Now merge, ignoring all conflicts.
    mergeOpts = copy.deepcopy(opts)
    mergeOpts['tool'] = "internal:fail"
    mergeOpts['noninteractive'] = True
    # Ignore return value... ok if merge fails
    tryCommand(ui, "merge -r %s" % quoteBranch(branch), 
               lambda:commands.merge(ui, repo, node=branch, **mergeOpts),
               repo = repo)

    # Revert all files to prod (regardless of what happened on the branch)
    revertOpts = copy.deepcopy(opts)
    revertOpts['all'] = True
    revertOpts['rev'] = "."
    if tryCommand(ui, "revert -a -r .", lambda:commands.revert(ui, repo, **revertOpts), repo = repo):
      return 1

    # Were there any merge conflicts?
    resolveOpts = copy.deepcopy(opts)
    resolveOpts['list'] = True
    if tryCommand(ui, "resolve -l", lambda:commands.resolve(ui, repo, **resolveOpts), repo = repo):
      return 1

    # Anything that had a merge conflict, mark it resolved (by the revert)
    if ui.lastTryCommandOutput != '':
      resolveOpts = copy.deepcopy(opts)
      resolveOpts['all'] = True
      resolveOpts['mark'] = True
      if tryCommand(ui, "resolve -a -m", lambda:commands.resolve(ui, repo, **resolveOpts), repo = repo):
        return 1

    # Commit the merge
    if tryCommand(ui, "commit", lambda:repo.commit(text) is None):
      return 1

  # And push.
  if not opts['nopush']:
    pushOpts = copy.deepcopy(opts)
    if 'message' in pushOpts:
      del pushOpts['message']
    pushOpts['force'] = True
    nameSet = set()
    for name, path in ui.configitems("paths"):
      nameSet.add(name)
    if tryCommand(ui, "push -f -b %s -b %s default" % (quoteBranch(branch), repo.topicProdBranch), 
                  lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), **pushOpts), 
                  repo=repo) > 1:
      return 1
    if "dev" in nameSet:
      if tryCommand(ui, "push -f -b %s -b %s dev" % (quoteBranch(branch), repo.topicProdBranch), 
                    lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="dev", **pushOpts), 
                    repo=repo) > 1:
        return 1
    if "stage" in nameSet:
      if tryCommand(ui, "push -f -b %s -b %s stage" % (quoteBranch(branch), repo.topicProdBranch), 
                    lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="stage", **pushOpts), 
                    repo=repo) > 1:
        return 1
    if "prod" in nameSet:
      if tryCommand(ui, "push -f -b %s -b %s prod" % (quoteBranch(branch), repo.topicProdBranch), 
                    lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="prod", **pushOpts), 
                    repo=repo) > 1:
        return 1

  ui.status("Done.\n")
Пример #21
0
 def dohgrevert():
     commands.revert(self.stat.ui, self.stat.repo, *wfiles, **revertopts)
Пример #22
0
def split(ui, repo, *revs, **opts):
    """split a changeset into smaller changesets

    By default, split the current revision by prompting for all its hunks to be
    redistributed into new changesets.

    Use --rev to split a given changeset instead.
    """
    tr = wlock = lock = None
    newcommits = []

    revarg = (list(revs) + opts.get('rev')) or ['.']
    if len(revarg) != 1:
        msg = _("more than one revset is given")
        hnt = _("use either `hg split <rs>` or `hg split --rev <rs>`, not both")
        raise error.Abort(msg, hint=hnt)

    rev = scmutil.revsingle(repo, revarg[0])
    if opts.get('no_rebase'):
        torebase = ()
    else:
        torebase = repo.revs('descendants(%d) - (%d)', rev, rev)
    try:
        wlock = repo.wlock()
        lock = repo.lock()
        cmdutil.bailifchanged(repo)
        if torebase:
            cmdutil.checkunfinished(repo)
        tr = repo.transaction('split')
        ctx = repo[rev]
        r = ctx.rev()
        disallowunstable = not obsolete.isenabled(repo,
                                                  obsolete.allowunstableopt)
        if disallowunstable:
            # XXX We should check head revs
            if repo.revs("(%d::) - %d", rev, rev):
                raise error.Abort(_("cannot split commit: %s not a head") % ctx)

        if len(ctx.parents()) > 1:
            raise error.Abort(_("cannot split merge commits"))
        prev = ctx.p1()
        bmupdate = common.bookmarksupdater(repo, ctx.node(), tr)
        bookactive = repo._activebookmark
        if bookactive is not None:
            repo.ui.status(_("(leaving bookmark %s)\n") % repo._activebookmark)
        bookmarks.deactivate(repo)
        hg.update(repo, prev)

        commands.revert(ui, repo, rev=r, all=True)

        def haschanges():
            modified, added, removed, deleted = repo.status()[:4]
            return modified or added or removed or deleted
        msg = ("HG: This is the original pre-split commit message. "
               "Edit it as appropriate.\n\n")
        msg += ctx.description()
        opts['message'] = msg
        opts['edit'] = True
        while haschanges():
            pats = ()
            cmdutil.dorecord(ui, repo, commands.commit, 'commit', False,
                             cmdutil.recordfilter, *pats, **opts)
            # TODO: Does no seem like the best way to do this
            # We should make dorecord return the newly created commit
            newcommits.append(repo['.'])
            if haschanges():
                if ui.prompt('Done splitting? [yN]', default='n') == 'y':
                    commands.commit(ui, repo, **opts)
                    newcommits.append(repo['.'])
                    break
            else:
                ui.status(_("no more change to split\n"))

        if newcommits:
            tip = repo[newcommits[-1]]
            bmupdate(tip.node())
            if bookactive is not None:
                bookmarks.activate(repo, bookactive)
            obsolete.createmarkers(repo, [(repo[r], newcommits)],
                                   operation='split')

            if torebase:
                top = repo.revs('allsuccessors(%d)', rev).last()
                common.restackonce(ui, repo, top)
        tr.close()
    finally:
        lockmod.release(tr, lock, wlock)
Пример #23
0
 def deleteSelectedChunks(self):
     'delete currently selected chunks'
     repo = self.repo
     chunks = self.diffbrowse.curchunks
     dchunks = [c for c in chunks[1:] if c.selected]
     if not dchunks:
         self.showMessage.emit(_('No deletable chunks'))
         return
     ctx = self.ctx
     kchunks = [c for c in chunks[1:] if not c.selected]
     revertall = False
     if not kchunks:
         if isinstance(ctx, patchctx):
             revertmsg = _('Completely remove file from patch?')
         else:
             revertmsg = _('Revert all file changes?')
         revertall = qtlib.QuestionMsgBox(_('No chunks remain'), revertmsg)
     if isinstance(ctx, patchctx):
         repo.thgbackup(ctx._path)
         fp = util.atomictempfile(ctx._path, 'wb')
         buf = cStringIO.StringIO()
         try:
             if ctx._ph.comments:
                 buf.write('\n'.join(ctx._ph.comments))
                 buf.write('\n\n')
             needsnewline = False
             for wfile in ctx._fileorder:
                 if wfile == self.currentFile:
                     if revertall:
                         continue
                     chunks[0].write(buf)
                     for chunk in kchunks:
                         chunk.write(buf)
                 else:
                     if buf.tell() and buf.getvalue()[-1] != '\n':
                         buf.write('\n')
                     for chunk in ctx._files[wfile]:
                         chunk.write(buf)
             fp.write(buf.getvalue())
             fp.close()
         finally:
             del fp
         ctx.invalidate()
         self.fileModified.emit()
     else:
         path = repo.wjoin(self.currentFile)
         if not os.path.exists(path):
             self.showMessage.emit(_('file has been deleted, refresh'))
             return
         if self.mtime != os.path.getmtime(path):
             self.showMessage.emit(_('file has been modified, refresh'))
             return
         repo.thgbackup(path)
         if revertall:
             commands.revert(repo.ui, repo, path, no_backup=True)
         else:
             wlock = repo.wlock()
             try:
                 # atomictemp can preserve file permission
                 wf = repo.wopener(self.currentFile, 'wb', atomictemp=True)
                 wf.write(self.diffbrowse.origcontents)
                 wf.close()
                 fp = cStringIO.StringIO()
                 chunks[0].write(fp)
                 for c in kchunks:
                     c.write(fp)
                 fp.seek(0)
                 self.runPatcher(fp, self.currentFile, False)
             finally:
                 wlock.release()
         self.fileModified.emit()
Пример #24
0
def subpull(ui, repo, name='', **opts):
    """Pull subtree(s)"""

    # change to root directory
    if repo.getcwd() != '':
        ui.warn(
            "Working directory is not repository root. At best, this directory won't exist when subpull is done.\n"
        )
        repo.dirstate._cwd = repo.root
        os.chdir(repo.root)

    # if there are uncommitted change, abort --- we will be modifying the working copy quite drammatically
    modified, added, removed, deleted, _unknown, _ignored, _clean = repo.status(
    )
    if modified or added or removed or deleted:
        raise error.Abort(
            "Uncommitted changes in the working copy. Subtree extension needs to modify the working copy, so it cannot proceed."
        )

    # parse .hgsubtree
    hgsubtree = ui.config('subtree', 'hgsubtree', default=default_hgsubtree)
    subtrees = _parse_hgsubtree(os.path.join(repo.root, hgsubtree))

    # if names not in .hgsubtree, abort
    # if names is empty, go through all repos in .hgsubtree
    if name:
        if name not in subtrees:
            raise error.Abort("Cannot find %s in %s." % (name, hgsubtree))
        names = [name]
    else:
        if opts['source']:
            raise error.Abort(
                "Cannot use --source without specifying a repository")
        names = subtrees.keys()

    null = repo['null']
    origin = str(repo[None])
    commit_opts = {'edit': opts['edit']}
    bookmark_prefix = ui.config('subtree',
                                'bookmark',
                                default=default_bookmark_prefix)
    nocache = ui.config('subtree', 'nocache', default='')

    for name in names:
        subtree = subtrees[name]
        if 'destination' not in subtree:
            raise error.Abort('No destination found for %s' % name)

        collapse = 'collapse' in subtree and subtree['collapse']

        # figure out the revision to pull
        pull_opts = {}
        if 'rev' in subtree:
            pull_opts['rev'] = [subtree['rev']]
        if opts['rev']:
            pull_opts['rev'] = opts['rev']

        # clone or pull into cache
        source = subtree['source'] if not opts['source'] else opts['source']
        if not nocache:
            source = _clone_or_pull(ui, repo, name, source, pull_opts)

        # pull
        tip = repo['tip']
        commands.pull(ui, repo, source=source, force=True, **pull_opts)
        if tip == repo['tip']:
            ui.status("no changes: nothing for subtree to do\n")
            continue

        # collapse or update -C
        if collapse:
            # find a matching bookmark
            bookmark_name = bookmark_prefix + name
            if bookmark_name in repo._bookmarks:
                commands.update(ui, repo, bookmark_name, clean=True)
            else:
                commands.update(ui, repo, 'null', clean=True)

            # set up the correct file state and commit as a new changeset
            pulled_tip = repo['tip']
            commands.revert(ui, repo, rev='tip', all=True)
            hgsubrepo_meta = [
                os.path.join(repo.root, '.hgsubstate'),
                os.path.join(repo.root, '.hgsub')
            ]
            for fn in hgsubrepo_meta:
                if os.path.exists(fn):
                    ui.debug("removing %s\n" % fn)
                    commands.remove(ui, repo, fn, force=True)
                    os.remove(fn)
            changed = commands.commit(ui,
                                      repo,
                                      message=ui.config(
                                          'subtree', 'collapse',
                                          default_collapse_comment).format(
                                              name=name,
                                              rev=str(pulled_tip)[:12]),
                                      **commit_opts)
            commands.bookmark(ui, repo, bookmark_name, inactive=True)

            if not opts['no_strip']:
                # delete bookmarks on the changesets that will be stripped; not
                # the most efficient procedure to find them, but will do for now
                remove_bookmarks = []
                for k in repo._bookmarks.keys():
                    ctx = repo[k]
                    if pulled_tip.ancestor(ctx) != null:
                        remove_bookmarks.append(k)

                for bookmark in remove_bookmarks:
                    commands.bookmark(ui, repo, bookmark, delete=True)

                strip.stripcmd(ui,
                               repo,
                               rev=['ancestors(%s)' % str(pulled_tip)],
                               bookmark=[])

            if changed == 1:  # nothing changed
                ui.status("no changes: nothing for subtree to do\n")
                commands.update(ui, repo, origin[:12])
                continue
        else:
            commands.update(ui, repo, 'tip', clean=True)

        # move or delete
        destinations = _destinations(subtree['destination'])

        # process destinations
        keep_list = []
        for dest in destinations:
            if dest[0] == 'mkdir':
                if not os.path.exists(dest[1]):
                    os.makedirs(dest[1])
            elif dest[0] == 'mv':
                commands.rename(ui, repo, *dest[1:], force=False)
            elif dest[0] == 'cp':
                commands.copy(ui, repo, *dest[1:], force=False)
            elif dest[0] == 'rm':
                commands.remove(ui, repo, *dest[1:], force=False)
            elif dest[0] == 'keep':
                keep_list.append(' '.join(dest[1:]))

        # remove all untouched files, unless instructed to keep them
        if 'keep' not in subtree or not subtree['keep']:
            _modified, _added, _removed, _deleted, _unknown, _ignored, clean = repo.status(
                clean=True)
            for fn in clean:
                for keep_pattern in keep_list:
                    if fnmatch(fn, keep_pattern):
                        break
                else:
                    commands.remove(ui, repo, fn)

        commands.commit(
            ui,
            repo,
            message=ui.config('subtree', 'move',
                              default_move_comment).format(name=name),
            **commit_opts)
        merge_commit = str(repo[None])

        # update to original and merge with the new
        commands.update(ui, repo, origin[:12])
        commands.merge(ui, repo, merge_commit[:12])
        commands.commit(
            ui,
            repo,
            message=ui.config('subtree', 'merge',
                              default_merge_comment).format(name=name),
            **commit_opts)
        origin = str(repo[None])
Пример #25
0
 def deleteSelectedChunks(self):
     'delete currently selected chunks'
     repo = self.repo
     chunks = self.diffbrowse.curchunks
     dchunks = [c for c in chunks[1:] if c.selected]
     if not dchunks:
         self.showMessage.emit(_('No deletable chunks'))
         return
     ctx = self.ctx
     kchunks = [c for c in chunks[1:] if not c.selected]
     revertall = False
     if not kchunks:
         if isinstance(ctx, patchctx):
             revertmsg = _('Completely remove file from patch?')
         else:
             revertmsg = _('Revert all file changes?')
         revertall = qtlib.QuestionMsgBox(_('No chunks remain'), revertmsg)
     if isinstance(ctx, patchctx):
         repo.thgbackup(ctx._path)
         fp = util.atomictempfile(ctx._path, 'wb')
         buf = cStringIO.StringIO()
         try:
             if ctx._ph.comments:
                 buf.write('\n'.join(ctx._ph.comments))
                 buf.write('\n\n')
             needsnewline = False
             for wfile in ctx._fileorder:
                 if wfile == self.currentFile:
                     if revertall:
                         continue
                     chunks[0].write(buf)
                     for chunk in kchunks:
                         chunk.write(buf)
                 else:
                     if buf.tell() and buf.getvalue()[-1] != '\n':
                         buf.write('\n')
                     for chunk in ctx._files[wfile]:
                         chunk.write(buf)
             fp.write(buf.getvalue())
             fp.close()
         finally:
             del fp
         ctx.invalidate()
         self.fileModified.emit()
     else:
         path = repo.wjoin(self.currentFile)
         if not os.path.exists(path):
             self.showMessage.emit(_('file has been deleted, refresh'))
             return
         if self.mtime != os.path.getmtime(path):
             self.showMessage.emit(_('file has been modified, refresh'))
             return
         repo.thgbackup(path)
         if revertall:
             commands.revert(repo.ui, repo, path, no_backup=True)
         else:
             wlock = repo.wlock()
             try:
                 # atomictemp can preserve file permission
                 wf = repo.wopener(self.currentFile, 'wb', atomictemp=True)
                 wf.write(self.diffbrowse.origcontents)
                 wf.close()
                 fp = cStringIO.StringIO()
                 chunks[0].write(fp)
                 for c in kchunks:
                     c.write(fp)
                 fp.seek(0)
                 self.runPatcher(fp, self.currentFile, False)
             finally:
                 wlock.release()
         self.fileModified.emit()