mercurial/hg.py
changeset 5124 06154aff2b1a
parent 4961 126f527b3ba3
child 5180 0d5d03844927
child 5184 92236732d5a1
equal deleted inserted replaced
5123:f94dbc6c7eaf 5124:06154aff2b1a
     8 
     8 
     9 from node import *
     9 from node import *
    10 from repo import *
    10 from repo import *
    11 from i18n import _
    11 from i18n import _
    12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
    12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
    13 import errno, lock, os, shutil, util, cmdutil
    13 import errno, lock, os, shutil, util, cmdutil, extensions
    14 import merge as _merge
    14 import merge as _merge
    15 import verify as _verify
    15 import verify as _verify
    16 
    16 
    17 def _local(path):
    17 def _local(path):
    18     return (os.path.isfile(util.drop_scheme('file', path)) and
    18     return (os.path.isfile(util.drop_scheme('file', path)) and
    19             bundlerepo or localrepo)
    19             bundlerepo or localrepo)
    20 
    20 
    21 schemes = {
    21 schemes = {
    22     'bundle': bundlerepo,
    22     'bundle': bundlerepo,
    23     'file': _local,
    23     'file': _local,
    24     'hg': httprepo,
       
    25     'http': httprepo,
    24     'http': httprepo,
    26     'https': httprepo,
    25     'https': httprepo,
    27     'old-http': statichttprepo,
       
    28     'ssh': sshrepo,
    26     'ssh': sshrepo,
    29     'static-http': statichttprepo,
    27     'static-http': statichttprepo,
    30     }
    28 }
    31 
    29 
    32 def _lookup(path):
    30 def _lookup(path):
    33     scheme = 'file'
    31     scheme = 'file'
    34     if path:
    32     if path:
    35         c = path.find(':')
    33         c = path.find(':')
    48             return _lookup(repo).islocal(repo)
    46             return _lookup(repo).islocal(repo)
    49         except AttributeError:
    47         except AttributeError:
    50             return False
    48             return False
    51     return repo.local()
    49     return repo.local()
    52 
    50 
    53 repo_setup_hooks = []
       
    54 
       
    55 def repository(ui, path='', create=False):
    51 def repository(ui, path='', create=False):
    56     """return a repository object for the specified path"""
    52     """return a repository object for the specified path"""
    57     repo = _lookup(path).instance(ui, path, create)
    53     repo = _lookup(path).instance(ui, path, create)
    58     ui = getattr(repo, "ui", ui)
    54     ui = getattr(repo, "ui", ui)
    59     for hook in repo_setup_hooks:
    55     for hook in extensions.setuphooks:
    60         hook(ui, repo)
    56         hook(ui, repo)
    61     return repo
    57     return repo
    62 
    58 
    63 def defaultdest(source):
    59 def defaultdest(source):
    64     '''return default destination of clone if none is given'''
    60     '''return default destination of clone if none is given'''
   132             self.dir_ = None
   128             self.dir_ = None
   133         def __del__(self):
   129         def __del__(self):
   134             if self.dir_:
   130             if self.dir_:
   135                 self.rmtree(self.dir_, True)
   131                 self.rmtree(self.dir_, True)
   136 
   132 
   137     dir_cleanup = None
   133     src_lock = dest_lock = dir_cleanup = None
   138     if islocal(dest):
   134     try:
   139         dir_cleanup = DirCleanup(dest)
   135         if islocal(dest):
   140 
   136             dir_cleanup = DirCleanup(dest)
   141     abspath = origsource
   137 
   142     copy = False
   138         abspath = origsource
   143     if src_repo.local() and islocal(dest):
   139         copy = False
   144         abspath = os.path.abspath(origsource)
   140         if src_repo.local() and islocal(dest):
   145         copy = not pull and not rev
   141             abspath = os.path.abspath(origsource)
   146 
   142             copy = not pull and not rev
   147     src_lock, dest_lock = None, None
   143 
   148     if copy:
   144         if copy:
   149         try:
       
   150             # we use a lock here because if we race with commit, we
       
   151             # can end up with extra data in the cloned revlogs that's
       
   152             # not pointed to by changesets, thus causing verify to
       
   153             # fail
       
   154             src_lock = src_repo.lock()
       
   155         except lock.LockException:
       
   156             copy = False
       
   157 
       
   158     if copy:
       
   159         def force_copy(src, dst):
       
   160             try:
   145             try:
   161                 util.copyfiles(src, dst)
   146                 # we use a lock here because if we race with commit, we
   162             except OSError, inst:
   147                 # can end up with extra data in the cloned revlogs that's
   163                 if inst.errno != errno.ENOENT:
   148                 # not pointed to by changesets, thus causing verify to
   164                     raise
   149                 # fail
   165 
   150                 src_lock = src_repo.lock()
   166         src_store = os.path.realpath(src_repo.spath)
   151             except lock.LockException:
   167         if not os.path.exists(dest):
   152                 copy = False
   168             os.mkdir(dest)
   153 
   169         dest_path = os.path.realpath(os.path.join(dest, ".hg"))
   154         if copy:
   170         os.mkdir(dest_path)
   155             def force_copy(src, dst):
   171         if src_repo.spath != src_repo.path:
   156                 try:
   172             dest_store = os.path.join(dest_path, "store")
   157                     util.copyfiles(src, dst)
   173             os.mkdir(dest_store)
   158                 except OSError, inst:
       
   159                     if inst.errno != errno.ENOENT:
       
   160                         raise
       
   161 
       
   162             src_store = os.path.realpath(src_repo.spath)
       
   163             if not os.path.exists(dest):
       
   164                 os.mkdir(dest)
       
   165             dest_path = os.path.realpath(os.path.join(dest, ".hg"))
       
   166             os.mkdir(dest_path)
       
   167             if src_repo.spath != src_repo.path:
       
   168                 dest_store = os.path.join(dest_path, "store")
       
   169                 os.mkdir(dest_store)
       
   170             else:
       
   171                 dest_store = dest_path
       
   172             # copy the requires file
       
   173             force_copy(src_repo.join("requires"),
       
   174                        os.path.join(dest_path, "requires"))
       
   175             # we lock here to avoid premature writing to the target
       
   176             dest_lock = lock.lock(os.path.join(dest_store, "lock"))
       
   177 
       
   178             files = ("data",
       
   179                      "00manifest.d", "00manifest.i",
       
   180                      "00changelog.d", "00changelog.i")
       
   181             for f in files:
       
   182                 src = os.path.join(src_store, f)
       
   183                 dst = os.path.join(dest_store, f)
       
   184                 force_copy(src, dst)
       
   185 
       
   186             # we need to re-init the repo after manually copying the data
       
   187             # into it
       
   188             dest_repo = repository(ui, dest)
       
   189 
   174         else:
   190         else:
   175             dest_store = dest_path
   191             dest_repo = repository(ui, dest, create=True)
   176         # copy the requires file
   192 
   177         force_copy(src_repo.join("requires"),
   193             revs = None
   178                    os.path.join(dest_path, "requires"))
   194             if rev:
   179         # we lock here to avoid premature writing to the target
   195                 if 'lookup' not in src_repo.capabilities:
   180         dest_lock = lock.lock(os.path.join(dest_store, "lock"))
   196                     raise util.Abort(_("src repository does not support revision "
   181 
   197                                        "lookup and so doesn't support clone by "
   182         files = ("data",
   198                                        "revision"))
   183                  "00manifest.d", "00manifest.i",
   199                 revs = [src_repo.lookup(r) for r in rev]
   184                  "00changelog.d", "00changelog.i")
   200 
   185         for f in files:
   201             if dest_repo.local():
   186             src = os.path.join(src_store, f)
   202                 dest_repo.clone(src_repo, heads=revs, stream=stream)
   187             dst = os.path.join(dest_store, f)
   203             elif src_repo.local():
   188             force_copy(src, dst)
   204                 src_repo.push(dest_repo, revs=revs)
   189 
   205             else:
   190         # we need to re-init the repo after manually copying the data
   206                 raise util.Abort(_("clone from remote to remote not supported"))
   191         # into it
       
   192         dest_repo = repository(ui, dest)
       
   193 
       
   194     else:
       
   195         dest_repo = repository(ui, dest, create=True)
       
   196 
       
   197         revs = None
       
   198         if rev:
       
   199             if 'lookup' not in src_repo.capabilities:
       
   200                 raise util.Abort(_("src repository does not support revision "
       
   201                                    "lookup and so doesn't support clone by "
       
   202                                    "revision"))
       
   203             revs = [src_repo.lookup(r) for r in rev]
       
   204 
   207 
   205         if dest_repo.local():
   208         if dest_repo.local():
   206             dest_repo.clone(src_repo, heads=revs, stream=stream)
   209             fp = dest_repo.opener("hgrc", "w", text=True)
   207         elif src_repo.local():
   210             fp.write("[paths]\n")
   208             src_repo.push(dest_repo, revs=revs)
   211             fp.write("default = %s\n" % abspath)
   209         else:
   212             fp.close()
   210             raise util.Abort(_("clone from remote to remote not supported"))
   213 
   211 
   214             if update:
   212     if src_lock:
   215                 try:
   213         src_lock.release()
   216                     checkout = dest_repo.lookup("default")
   214 
   217                 except:
   215     if dest_repo.local():
   218                     checkout = dest_repo.changelog.tip()
   216         fp = dest_repo.opener("hgrc", "w", text=True)
   219                 _update(dest_repo, checkout)
   217         fp.write("[paths]\n")
   220         if dir_cleanup:
   218         fp.write("default = %s\n" % abspath)
   221             dir_cleanup.close()
   219         fp.close()
   222 
   220 
   223         return src_repo, dest_repo
   221         if dest_lock:
   224     finally:
   222             dest_lock.release()
   225         del src_lock, dest_lock, dir_cleanup
   223 
       
   224         if update:
       
   225             try:
       
   226                 checkout = dest_repo.lookup("default")
       
   227             except:
       
   228                 checkout = dest_repo.changelog.tip()
       
   229             _update(dest_repo, checkout)
       
   230     if dir_cleanup:
       
   231         dir_cleanup.close()
       
   232 
       
   233     return src_repo, dest_repo
       
   234 
   226 
   235 def _showstats(repo, stats):
   227 def _showstats(repo, stats):
   236     stats = ((stats[0], _("updated")),
   228     stats = ((stats[0], _("updated")),
   237              (stats[1], _("merged")),
   229              (stats[1], _("merged")),
   238              (stats[2], _("removed")),
   230              (stats[2], _("removed")),
   243 def _update(repo, node): return update(repo, node)
   235 def _update(repo, node): return update(repo, node)
   244 
   236 
   245 def update(repo, node):
   237 def update(repo, node):
   246     """update the working directory to node, merging linear changes"""
   238     """update the working directory to node, merging linear changes"""
   247     pl = repo.parents()
   239     pl = repo.parents()
   248     stats = _merge.update(repo, node, False, False, None, None)
   240     stats = _merge.update(repo, node, False, False, None)
   249     _showstats(repo, stats)
   241     _showstats(repo, stats)
   250     if stats[3]:
   242     if stats[3]:
   251         repo.ui.status(_("There are unresolved merges with"
   243         repo.ui.status(_("There are unresolved merges with"
   252                          " locally modified files.\n"))
   244                          " locally modified files.\n"))
   253         if stats[1]:
   245         if stats[1]:
   257         # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
   249         # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
   258         repo.ui.status(_("  hg update %s\n  hg update %s\n")
   250         repo.ui.status(_("  hg update %s\n  hg update %s\n")
   259                        % (pl[0].rev(), repo.changectx(node).rev()))
   251                        % (pl[0].rev(), repo.changectx(node).rev()))
   260     return stats[3]
   252     return stats[3]
   261 
   253 
   262 def clean(repo, node, wlock=None, show_stats=True):
   254 def clean(repo, node, show_stats=True):
   263     """forcibly switch the working directory to node, clobbering changes"""
   255     """forcibly switch the working directory to node, clobbering changes"""
   264     stats = _merge.update(repo, node, False, True, None, wlock)
   256     stats = _merge.update(repo, node, False, True, None)
   265     if show_stats: _showstats(repo, stats)
   257     if show_stats: _showstats(repo, stats)
   266     return stats[3]
   258     return stats[3]
   267 
   259 
   268 def merge(repo, node, force=None, remind=True, wlock=None):
   260 def merge(repo, node, force=None, remind=True):
   269     """branch merge with node, resolving changes"""
   261     """branch merge with node, resolving changes"""
   270     stats = _merge.update(repo, node, True, force, False, wlock)
   262     stats = _merge.update(repo, node, True, force, False)
   271     _showstats(repo, stats)
   263     _showstats(repo, stats)
   272     if stats[3]:
   264     if stats[3]:
   273         pl = repo.parents()
   265         pl = repo.parents()
   274         repo.ui.status(_("There are unresolved merges,"
   266         repo.ui.status(_("There are unresolved merges,"
   275                          " you can redo the full merge using:\n"
   267                          " you can redo the full merge using:\n"
   278                        % (pl[0].rev(), pl[1].rev()))
   270                        % (pl[0].rev(), pl[1].rev()))
   279     elif remind:
   271     elif remind:
   280         repo.ui.status(_("(branch merge, don't forget to commit)\n"))
   272         repo.ui.status(_("(branch merge, don't forget to commit)\n"))
   281     return stats[3]
   273     return stats[3]
   282 
   274 
   283 def revert(repo, node, choose, wlock):
   275 def revert(repo, node, choose):
   284     """revert changes to revision in node without updating dirstate"""
   276     """revert changes to revision in node without updating dirstate"""
   285     return _merge.update(repo, node, False, True, choose, wlock)[3]
   277     return _merge.update(repo, node, False, True, choose)[3]
   286 
   278 
   287 def verify(repo):
   279 def verify(repo):
   288     """verify the consistency of a repository"""
   280     """verify the consistency of a repository"""
   289     return _verify.verify(repo)
   281     return _verify.verify(repo)