WorkSpace.py revision 8703921742d9c7d4d3724f89a39ff0e2725cbe7b
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# This program is free software; you can redistribute it and/or modify
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# it under the terms of the GNU General Public License version 2
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# as published by the Free Software Foundation.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# This program is distributed in the hope that it will be useful,
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# but WITHOUT ANY WARRANTY; without even the implied warranty of
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# GNU General Public License for more details.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# You should have received a copy of the GNU General Public License
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# along with this program; if not, write to the Free Software
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
78add226e8da271dde8f3b5a91d340d1bf010151jmcp# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe# Copyright 2008, 2010, Richard Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# Theory:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# Workspaces have a non-binding parent/child relationship.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# All important operations apply to the changes between the two.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# However, for the sake of remote operation, the 'parent' of a
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# workspace is not seen as a literal entity, instead the figurative
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# parent contains the last changeset common to both parent and child,
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# as such the 'parent tip' is actually nothing of the sort, but instead a
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# convenient imitation.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# Any change made to a workspace is a change to a file therein, such
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# changes can be represented briefly as whether the file was
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# modified/added/removed as compared to the parent workspace, whether
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# the file has a different name in the parent and if so, whether it
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# was renamed or merely copied. Each changed file has an
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# associated ActiveEntry.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# The ActiveList being a list ActiveEntrys can thus present the entire
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# change in workspace state between a parent and its child, and is the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# important bit here (in that if it is incorrect, everything else will
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson# be as incorrect, or more)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson#
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonimport cStringIO
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonimport os
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowefrom mercurial import cmdutil, context, error, hg, node, patch, repair, util
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonfrom hgext import mq
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowefrom onbld.Scm import Version
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe#
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe# Mercurial 1.6 moves findoutgoing into a discover module
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe#
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Loweif Version.at_least("1.6"):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe from mercurial import discovery
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonclass ActiveEntry(object):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Representation of the changes made to a single file.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson MODIFIED - Contents changed, but no other changes were made
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson ADDED - File is newly created
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson REMOVED - File is being removed
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson Copies are represented by an Entry whose .parentname is non-nil
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson Truly copied files have non-nil .parentname and .renamed = False
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson Renames have non-nil .parentname and .renamed = True
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson Do not access any of this information directly, do so via the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson .is_<change>() methods.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson MODIFIED = 1
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson ADDED = 2
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson REMOVED = 3
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __init__(self, name):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.name = name
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.change = None
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.parentname = None
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # As opposed to copied (or neither)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.renamed = False
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.comments = []
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # ActiveEntrys sort by the name of the file they represent.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __cmp__(self, other):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return cmp(self.name, other.name)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def is_added(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.change == self.ADDED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def is_modified(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.change == self.MODIFIED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def is_removed(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.change == self.REMOVED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def is_renamed(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.parentname and self.renamed
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def is_copied(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.parentname and not self.renamed
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonclass ActiveList(object):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Complete representation of workspace change.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson In practice, a container for ActiveEntrys, and methods to build them,
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson update them, and deal with them en masse.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __init__(self, ws, parenttip, revs=None):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._active = {}
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ws = ws
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.revs = revs
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.base = None
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.parenttip = parenttip
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # If we couldn't find a parenttip, the two repositories must
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # be unrelated (Hg catches most of this, but this case is valid for it
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # but invalid for us)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if self.parenttip == None:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson raise util.Abort('repository is unrelated')
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.localtip = None
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if revs:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.base = revs[0]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.localtip = revs[-1]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._comments = []
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._build(revs)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def _build(self, revs):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if not revs:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson status = self.ws.status(self.parenttip.node(), self.localtip.node())
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson files = []
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for ctype in status.values():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson files.extend(ctype)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # When a file is renamed, two operations actually occur.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # A file copy from source to dest and a removal of source.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # These are represented as two distinct entries in the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # changectx and status (one on the dest file for the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # copy, one on the source file for the remove).
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Since these are unconnected in both the context and
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # status we can only make the association by explicitly
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # looking for it.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We deal with this thusly:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We maintain a dict dest -> source of all copies
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # (updating dest as appropriate, but leaving source alone).
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # After all other processing, we mark as renamed any pair
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # where source is on the removed list.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson copies = {}
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Walk revs looking for renames and adding files that
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # are in both change context and status to the active
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # list.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for ctx in revs:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson desc = ctx.description().splitlines()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._comments.extend(desc)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for fname in ctx.files():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We store comments per-entry as well, for the sake of
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # webrev and similar. We store twice to avoid the problems
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # of uniquifying comments for the general list (and possibly
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # destroying multi-line entities in the process).
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if fname not in self:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._addentry(fname)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self[fname].comments.extend(desc)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson try:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson fctx = ctx.filectx(fname)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe except error.LookupError:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson continue
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # NB: .renamed() is a misnomer, this actually checks
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # for copies.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson rn = fctx.renamed()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if rn:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # If the source file is a known copy we know its
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # ancestry leads us to the parent.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Otherwise make sure the source file is known to
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # be in the parent, we need not care otherwise.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We detect cycles at a later point. There is no
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # reason to continuously handle them.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if rn[0] in copies:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson copies[fname] = copies[rn[0]]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson elif rn[0] in self.parenttip.manifest():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson copies[fname] = rn[0]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Walk the copy list marking as copied any non-cyclic pair
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # where the destination file is still present in the local
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # tip (to avoid ephemeral changes)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Where source is removed, mark as renamed, and remove the
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # AL entry for the source file
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for fname, oldname in copies.iteritems():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if fname == oldname or fname not in self.localtip.manifest():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson continue
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self[fname].parentname = oldname
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if oldname in status['removed']:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self[fname].renamed = True
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if oldname in self:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson del self[oldname]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Walk the active list setting the change type for each active
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # file.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # In the case of modified files that are not renames or
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # copies, we do a content comparison, and drop entries that
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # are not actually modified.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We walk a copy of the AL such that we can drop entries
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # within the loop.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for entry in self._active.values():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if entry.name not in files:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson del self[entry.name]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson continue
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if entry.name in status['added']:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson entry.change = ActiveEntry.ADDED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson elif entry.name in status['removed']:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson entry.change = ActiveEntry.REMOVED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson elif entry.name in status['modified']:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson entry.change = ActiveEntry.MODIFIED
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # There are cases during a merge where a file will be in
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # the status return as modified, but in reality be an
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # addition (ie, not in the parenttip).
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We need to check whether the file is actually present
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # in the parenttip, and set it as an add, if not.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if entry.name not in self.parenttip.manifest():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson entry.change = ActiveEntry.ADDED
78add226e8da271dde8f3b5a91d340d1bf010151jmcp elif entry.is_modified():
78add226e8da271dde8f3b5a91d340d1bf010151jmcp if not self._changed_file(entry.name):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson del self[entry.name]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson continue
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson assert entry.change
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __contains__(self, fname):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return fname in self._active
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __getitem__(self, key):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self._active[key]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __setitem__(self, key, value):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self._active[key] = value
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __delitem__(self, key):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson del self._active[key]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __iter__(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson for entry in self._active.values():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson yield entry
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def _addentry(self, fname):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if fname not in self:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self[fname] = ActiveEntry(fname)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def files(self):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Return the list of pathnames of all files touched by this
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ActiveList
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe Where files have been renamed, this will include both their
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe current name and the name which they had in the parent tip.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ret = self._active.keys()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson ret.extend([x.parentname for x in self
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if x.is_renamed() and x.parentname not in ret])
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return ret
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def comments(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self._comments
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def bases(self):
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp '''Return the list of changesets that are roots of the ActiveList.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp This is the set of active changesets where neither parent
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp changeset is itself active.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp revset = set(self.revs)
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp return filter(lambda ctx: not [p for p in ctx.parents() if p in revset],
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp self.revs)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def tags(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Find tags that refer to a changeset in the ActiveList,
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe returning a list of 3-tuples (tag, node, is_local) for each.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe We return all instances of a tag that refer to such a node,
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe not just that which takes precedence.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def colliding_tags(iterable, nodes, local):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe for nd, name in [line.rstrip().split(' ', 1) for line in iterable]:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if nd in nodes:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe yield (name, self.ws.repo.lookup(nd), local)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson tags = []
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe nodes = set(node.hex(ctx.node()) for ctx in self.revs)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if os.path.exists(self.ws.repo.join('localtags')):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh = self.ws.repo.opener('localtags')
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe tags.extend(colliding_tags(fh, nodes, True))
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh.close()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # We want to use the tags file from the localtip
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if '.hgtags' in self.localtip:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe data = self.localtip.filectx('.hgtags').data().splitlines()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe tags.extend(colliding_tags(data, nodes, False))
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return tags
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def prune_tags(self, data):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Return a copy of data, which should correspond to the
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe contents of a Mercurial tags file, with any tags that refer to
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe changesets which are components of the ActiveList removed.'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe nodes = set(node.hex(ctx.node()) for ctx in self.revs)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return [t for t in data if t.split(' ', 1)[0] not in nodes]
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
78add226e8da271dde8f3b5a91d340d1bf010151jmcp def _changed_file(self, path):
78add226e8da271dde8f3b5a91d340d1bf010151jmcp '''Compare the parent and local versions of a given file.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson Return True if file changed, False otherwise.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
78add226e8da271dde8f3b5a91d340d1bf010151jmcp Note that this compares the given path in both versions, not the given
78add226e8da271dde8f3b5a91d340d1bf010151jmcp entry; renamed and copied files are compared by name, not history.
78add226e8da271dde8f3b5a91d340d1bf010151jmcp
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson The fast path compares file metadata, slow path is a
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson real comparison of file content.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if ((path in self.parenttip) != (path in self.localtip)):
78add226e8da271dde8f3b5a91d340d1bf010151jmcp return True
78add226e8da271dde8f3b5a91d340d1bf010151jmcp
78add226e8da271dde8f3b5a91d340d1bf010151jmcp parentfile = self.parenttip.filectx(path)
78add226e8da271dde8f3b5a91d340d1bf010151jmcp localfile = self.localtip.filectx(path)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # NB: Keep these ordered such as to make every attempt
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # to short-circuit the more time consuming checks.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if parentfile.size() != localfile.size():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return True
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if parentfile.flags() != localfile.flags():
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return True
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if parentfile.cmp(localfile.data()):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return True
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def context(self, message, user):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Return a Mercurial context object representing the entire
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ActiveList as one change.'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return activectx(self, message, user)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Loweclass activectx(context.memctx):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Represent an ActiveList as a Mercurial context object.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe Part of the WorkSpace.squishdeltas implementation.'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def __init__(self, active, message, user):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Build an activectx object.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe active - The ActiveList object used as the source for all data.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe message - Changeset description
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe user - Committing user'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def filectxfn(repository, ctx, fname):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fctx = active.localtip.filectx(fname)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe data = fctx.data()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # .hgtags is a special case, tags referring to active list
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # component changesets should be elided.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if fname == '.hgtags':
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe data = '\n'.join(active.prune_tags(data.splitlines()))
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return context.memfilectx(fname, data, 'l' in fctx.flags(),
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe 'x' in fctx.flags(),
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe active[fname].parentname)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.__active = active
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe parents = (active.parenttip.node(), node.nullid)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe extra = {'branch': active.localtip.branch()}
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe context.memctx.__init__(self, active.ws.repo, parents, message,
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe active.files(), filectxfn, user=user,
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe extra=extra)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def modified(self):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return [entry.name for entry in self.__active if entry.is_modified()]
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def added(self):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return [entry.name for entry in self.__active if entry.is_added()]
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def removed(self):
bb664d7ba7a656b21763d44dfc2da581c11444afRichard Lowe ret = set(entry.name for entry in self.__active if entry.is_removed())
bb664d7ba7a656b21763d44dfc2da581c11444afRichard Lowe ret.update(set(x.parentname for x in self.__active if x.is_renamed()))
bb664d7ba7a656b21763d44dfc2da581c11444afRichard Lowe return list(ret)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def files(self):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return self.__active.files()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelsonclass WorkSpace(object):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def __init__(self, repository):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.repo = repository
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ui = self.repo.ui
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.name = self.repo.root
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.activecache = {}
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def parent(self, spec=None):
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe '''Return the canonical workspace parent, either SPEC (which
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe will be expanded) if provided or the default parent
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe otherwise.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe if spec:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe return self.ui.expandpath(spec)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe p = self.ui.expandpath('default')
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe if p == 'default':
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe return None
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe else:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe return p
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe def _localtip(self, outgoing, wctx):
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe '''Return the most representative changeset to act as the
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe localtip.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe If the working directory is modified (has file changes, is a
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe merge, or has switched branches), this will be a workingctx.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe If the working directory is unmodified, this will be the most
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe recent (highest revision number) local (outgoing) head on the
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe current branch, if no heads are determined to be outgoing, it
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe will be the most recent head on the current branch.
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe '''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe # A modified working copy is seen as a proto-branch, and thus
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe # our only option as the local tip.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if (wctx.files() or len(wctx.parents()) > 1 or
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson wctx.branch() != wctx.parents()[0].branch()):
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe return wctx
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe heads = self.repo.heads(start=wctx.parents()[0].node())
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe headctxs = [self.repo.changectx(n) for n in heads]
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe localctxs = [c for c in headctxs if c.node() in outgoing]
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe ltip = sorted(localctxs or headctxs, key=lambda x: x.rev())[-1]
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe if len(heads) > 1:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe self.ui.warn('The current branch has more than one head, '
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe 'using %s\n' % ltip.rev())
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe return ltip
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe def _parenttip(self, heads, outgoing):
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe '''Return the highest-numbered, non-outgoing changeset that is
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe an ancestor of a changeset in heads.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe This is intended to find the most recent changeset on a given
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe branch that is shared between a parent and child workspace,
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe such that it can act as a stand-in for the parent workspace.
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe '''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def tipmost_shared(head, outnodes):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''Return the changeset on the same branch as head that is
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe not in outnodes and is closest to the tip.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe Walk outgoing changesets from head to the bottom of the
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe workspace (revision 0) and return the the first changeset
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe we see that is not in outnodes.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe If none is found (all revisions >= 0 are outgoing), the
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe only possible parenttip is the null node (node.nullid)
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe which is returned explicitly.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe for ctx in self._walkctxs(head, self.repo.changectx(0),
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe follow=True,
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe pick=lambda c: c.node() not in outnodes):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe return ctx
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe return self.repo.changectx(node.nullid)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe nodes = set(outgoing)
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe ptips = map(lambda x: tipmost_shared(x, nodes), heads)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe return sorted(ptips, key=lambda x: x.rev(), reverse=True)[0]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def status(self, base='.', head=None):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Translate from the hg 6-tuple status format to a hash keyed
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson on change-type'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson states = ['modified', 'added', 'removed', 'deleted', 'unknown',
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson 'ignored']
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson chngs = self.repo.status(base, head)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return dict(zip(states, chngs))
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def findoutgoing(self, parent):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Return the base set of outgoing nodes.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe A caching wrapper around mercurial.localrepo.findoutgoing().
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe Complains (to the user), if the parent workspace is
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe non-existent or inaccessible'''
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.ui.pushbuffer()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe try:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson try:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ui = self.ui
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if hasattr(cmdutil, 'remoteui'):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ui = cmdutil.remoteui(ui, {})
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe pws = hg.repository(ui, parent)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if Version.at_least("1.6"):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe return discovery.findoutgoing(self.repo, pws)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe else:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe return self.repo.findoutgoing(pws)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe except error.RepoError:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.ui.warn("Warning: Parent workspace '%s' is not "
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe "accessible\n"
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe "active list will be incomplete\n\n" % parent)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return []
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe finally:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ui.popbuffer()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe findoutgoing = util.cachefunc(findoutgoing)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def modified(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Return a list of files modified in the workspace'''
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe wctx = self.workingctx()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return sorted(wctx.files() + wctx.deleted()) or None
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def merged(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Return boolean indicating whether the workspace has an uncommitted
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson merge'''
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe wctx = self.workingctx()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return len(wctx.parents()) > 1
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def branched(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Return boolean indicating whether the workspace has an
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson uncommitted named branch'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe wctx = self.workingctx()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return wctx.branch() != wctx.parents()[0].branch()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def active(self, parent=None):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Return an ActiveList describing changes between workspace
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson and parent workspace (including uncommitted changes).
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe If workspace has no parent, ActiveList will still describe any
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe uncommitted changes.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson parent = self.parent(parent)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if parent in self.activecache:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.activecache[parent]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if parent:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson outgoing = self.findoutgoing(parent)
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe outnodes = self.repo.changelog.nodesbetween(outgoing)[0]
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson else:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson outgoing = [] # No parent, no outgoing nodes
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe outnodes = []
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe localtip = self._localtip(outnodes, self.workingctx())
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe if localtip.rev() is None:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe heads = localtip.parents()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson else:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe heads = [localtip]
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe ctxs = [self.repo.changectx(n) for n in
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe self.repo.changelog.nodesbetween(outgoing,
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe [h.node() for h in heads])[0]]
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe if localtip.rev() is None:
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe ctxs.append(localtip)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
0df7087fda4bb16f7e1cf07d1b90fcf070c19484Richard Lowe act = ActiveList(self, self._parenttip(heads, outnodes), ctxs)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.activecache[parent] = act
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return act
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
9a70fc3be3b1e966bf78825cdb8d509963a6f0a1Mark J. Nelson def pdiff(self, pats, opts, parent=None):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson 'Return diffs relative to PARENT, as best as we can make out'
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson parent = self.parent(parent)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson act = self.active(parent)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # act.localtip maybe nil, in the case of uncommitted local
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # changes.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if not act.revs:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe matchfunc = cmdutil.match(self.repo, pats, opts)
9a70fc3be3b1e966bf78825cdb8d509963a6f0a1Mark J. Nelson opts = patch.diffopts(self.ui, opts)
9a70fc3be3b1e966bf78825cdb8d509963a6f0a1Mark J. Nelson
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe return self.diff(act.parenttip.node(), act.localtip.node(),
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe match=matchfunc, opts=opts)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def squishdeltas(self, active, message, user=None):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Create a single conglomerate changeset based on a given
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe active list. Removes the original changesets comprising the
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe given active list, and any tags pointing to them.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe Operation:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe - Commit an activectx object representing the specified
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe active list,
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe - Remove any local tags pointing to changesets in the
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe specified active list.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe - Remove the changesets comprising the specified active
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe list.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe - Remove any metadata that may refer to changesets that were
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe removed.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe Calling code is expected to hold both the working copy lock
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe and repository lock of the destination workspace
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def strip_local_tags(active):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe '''Remove any local tags referring to the specified nodes.'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if os.path.exists(self.repo.join('localtags')):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh = None
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe try:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh = self.repo.opener('localtags')
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe tags = active.prune_tags(fh)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh.close()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh = self.repo.opener('localtags', 'w', atomictemp=True)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh.writelines(tags)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh.rename()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe finally:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if fh and not fh.closed:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe fh.close()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if active.files():
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe for entry in active:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Work around Mercurial issue #1666, if the source
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # file of a rename exists in the working copy
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Mercurial will complain, and remove the file.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # We preemptively remove the file to avoid the
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # complaint (the user was asked about this in
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # cdm_recommit)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if entry.is_renamed():
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe path = self.repo.wjoin(entry.parentname)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if os.path.exists(path):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe os.unlink(path)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.repo.commitctx(active.context(message, user))
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe wsstate = "recommitted"
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe destination = self.repo.changelog.tip()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson else:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # If all we're doing is stripping the old nodes, we want to
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # update the working copy such that we're not at a revision
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # that's about to go away.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe wsstate = "tip"
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe destination = active.parenttip.node()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.clean(destination)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Tags were elided by the activectx object. Local tags,
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # however, must be removed manually.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe try:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe strip_local_tags(active)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe except EnvironmentError, e:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe raise util.Abort('Could not recommit tags: %s\n' % e)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # Silence all the strip and update fun
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ui.pushbuffer()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Remove the active lists component changesets by stripping
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # the base of any active branch (of which there may be
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # several)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson try:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson try:
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp for base in active.bases():
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Any cached information about the repository is
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # likely to be invalid during the strip. The
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # caching of branch tags is especially
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # problematic.
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe #
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.repo.invalidate()
c7f512e49da83ae2cd3d4b339e1a8366544471e2jmcp repair.strip(self.ui, self.repo, base.node(), backup=False)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson except:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # If this fails, it may leave us in a surprising place in
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # the history.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We want to warn the user that something went wrong,
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # and what will happen next, re-raise the exception, and
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # bring the working copy back into a consistent state
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # (which the finally block will do)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ui.warn("stripping failed, your workspace will have "
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson "superfluous heads.\n"
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson "your workspace has been updated to the "
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe "%s changeset.\n" % wsstate)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson raise # Re-raise the exception
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson finally:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.clean()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.repo.dirstate.write() # Flush the dirstate
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.repo.invalidate() # Invalidate caches
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # We need to remove Hg's undo information (used for rollback),
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # since it refers to data that will probably not exist after
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson # the strip.
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson #
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if os.path.exists(self.repo.sjoin('undo')):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson try:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson os.unlink(self.repo.sjoin('undo'))
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson except EnvironmentError, e:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson raise util.Abort('failed to remove undo data: %s\n' % e)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson self.ui.popbuffer()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def filepath(self, path):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson 'Return the full path to a workspace file.'
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return self.repo.pathto(path)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def clean(self, rev=None):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''Bring workspace up to REV (or tip) forcefully (discarding in
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson progress changes)'''
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson if rev != None:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson rev = self.repo.lookup(rev)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson else:
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson rev = self.repo.changelog.tip()
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson hg.clean(self.repo, rev, show_stats=False)
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson def mq_applied(self):
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson '''True if the workspace has Mq patches applied'''
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson q = mq.queue(self.ui, self.repo.join(''))
cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0mjnelson return q.applied
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def workingctx(self):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return self.repo.changectx(None)
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe def diff(self, node1=None, node2=None, match=None, opts=None):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe ret = cStringIO.StringIO()
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe try:
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe for chunk in patch.diff(self.repo, node1, node2, match=match,
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe opts=opts):
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe ret.write(chunk)
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe finally:
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe # Workaround Hg bug 1651
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe if not Version.at_least("1.3"):
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe self.repo.dirstate.invalidate()
2b5878de2735cb61d008168e1f27e390d2edf915Rich Lowe
c959a081a8aebb76386b6d8ea3afa850e328f6c7Richard Lowe return ret.getvalue()
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if Version.at_least("1.6"):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe def copy(self, src, dest):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''Copy a file from src to dest
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe self.workingctx().copy(src, dest)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe else:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe def copy(self, src, dest):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''Copy a file from src to dest
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe self.repo.copy(src, dest)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if Version.at_least("1.4"):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe def _walkctxs(self, base, head, follow=False, pick=None):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''Generate changectxs between BASE and HEAD.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe Walk changesets between BASE and HEAD (in the order implied by
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe their relation), following a given branch if FOLLOW is a true
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe value, yielding changectxs where PICK (if specified) returns a
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe true value.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe PICK is a function of one argument, a changectx.'''
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe chosen = {}
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe def prep(ctx, fns):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe chosen[ctx.rev()] = not pick or pick(ctx)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe opts = {'rev': ['%s:%s' % (base.rev(), head.rev())],
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe 'follow': follow}
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe matcher = cmdutil.matchall(self.repo)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe for ctx in cmdutil.walkchangerevs(self.repo, matcher, opts, prep):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if chosen[ctx.rev()]:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe yield ctx
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe else:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe def _walkctxs(self, base, head, follow=False, pick=None):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe '''Generate changectxs between BASE and HEAD.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe Walk changesets between BASE and HEAD (in the order implied by
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe their relation), following a given branch if FOLLOW is a true
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe value, yielding changectxs where PICK (if specified) returns a
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe true value.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe PICK is a function of one argument, a changectx.'''
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe opts = {'rev': ['%s:%s' % (base.rev(), head.rev())],
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe 'follow': follow}
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe changectx = self.repo.changectx
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe getcset = util.cachefunc(lambda r: changectx(r).changeset())
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe #
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe # See the docstring of mercurial.cmdutil.walkchangerevs() for
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe # the phased approach to the iterator returned. The important
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe # part to note is that the 'add' phase gathers nodes, which
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe # the 'iter' phase then iterates through.
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe #
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe changeiter = cmdutil.walkchangerevs(self.ui, self.repo,
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe [], getcset, opts)[0]
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe matched = {}
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe for st, rev, fns in changeiter:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if st == 'add':
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe ctx = changectx(rev)
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if not pick or pick(ctx):
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe matched[rev] = ctx
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe elif st == 'iter':
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe if rev in matched:
8703921742d9c7d4d3724f89a39ff0e2725cbe7bRichard Lowe yield matched[rev]