##// END OF EJS Templates
share: pass named arguments...
Gregory Szorc -
r27353:98e59d9e default
parent child Browse files
Show More
@@ -1,176 +1,177 b''
1 1 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 '''share a common history between several working directories
7 7
8 8 Automatic Pooled Storage for Clones
9 9 -----------------------------------
10 10
11 11 When this extension is active, :hg:`clone` can be configured to
12 12 automatically share/pool storage across multiple clones. This
13 13 mode effectively converts :hg:`clone` to :hg:`clone` + :hg:`share`.
14 14 The benefit of using this mode is the automatic management of
15 15 store paths and intelligent pooling of related repositories.
16 16
17 17 The following ``share.`` config options influence this feature:
18 18
19 19 ``share.pool``
20 20 Filesystem path where shared repository data will be stored. When
21 21 defined, :hg:`clone` will automatically use shared repository
22 22 storage instead of creating a store inside each clone.
23 23
24 24 ``share.poolnaming``
25 25 How directory names in ``share.pool`` are constructed.
26 26
27 27 "identity" means the name is derived from the first changeset in the
28 28 repository. In this mode, different remotes share storage if their
29 29 root/initial changeset is identical. In this mode, the local shared
30 30 repository is an aggregate of all encountered remote repositories.
31 31
32 32 "remote" means the name is derived from the source repository's
33 33 path or URL. In this mode, storage is only shared if the path or URL
34 34 requested in the :hg:`clone` command matches exactly to a repository
35 35 that was cloned before.
36 36
37 37 The default naming mode is "identity."
38 38 '''
39 39
40 40 from mercurial.i18n import _
41 41 from mercurial import cmdutil, commands, hg, util, extensions, bookmarks, error
42 42 from mercurial.hg import repository, parseurl
43 43 import errno
44 44
45 45 cmdtable = {}
46 46 command = cmdutil.command(cmdtable)
47 47 # Note for extension authors: ONLY specify testedwith = 'internal' for
48 48 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
49 49 # be specifying the version(s) of Mercurial they are tested with, or
50 50 # leave the attribute unspecified.
51 51 testedwith = 'internal'
52 52
53 53 @command('share',
54 54 [('U', 'noupdate', None, _('do not create a working directory')),
55 55 ('B', 'bookmarks', None, _('also share bookmarks'))],
56 56 _('[-U] [-B] SOURCE [DEST]'),
57 57 norepo=True)
58 58 def share(ui, source, dest=None, noupdate=False, bookmarks=False):
59 59 """create a new shared repository
60 60
61 61 Initialize a new repository and working directory that shares its
62 62 history (and optionally bookmarks) with another repository.
63 63
64 64 .. note::
65 65
66 66 using rollback or extensions that destroy/modify history (mq,
67 67 rebase, etc.) can cause considerable confusion with shared
68 68 clones. In particular, if two shared clones are both updated to
69 69 the same changeset, and one of them destroys that changeset
70 70 with rollback, the other clone will suddenly stop working: all
71 71 operations will fail with "abort: working directory has unknown
72 72 parent". The only known workaround is to use debugsetparents on
73 73 the broken clone to reset it to a changeset that still exists.
74 74 """
75 75
76 return hg.share(ui, source, dest, not noupdate, bookmarks)
76 return hg.share(ui, source, dest=dest, update=not noupdate,
77 bookmarks=bookmarks)
77 78
78 79 @command('unshare', [], '')
79 80 def unshare(ui, repo):
80 81 """convert a shared repository to a normal one
81 82
82 83 Copy the store data to the repo and remove the sharedpath data.
83 84 """
84 85
85 86 if not repo.shared():
86 87 raise error.Abort(_("this is not a shared repo"))
87 88
88 89 destlock = lock = None
89 90 lock = repo.lock()
90 91 try:
91 92 # we use locks here because if we race with commit, we
92 93 # can end up with extra data in the cloned revlogs that's
93 94 # not pointed to by changesets, thus causing verify to
94 95 # fail
95 96
96 97 destlock = hg.copystore(ui, repo, repo.path)
97 98
98 99 sharefile = repo.join('sharedpath')
99 100 util.rename(sharefile, sharefile + '.old')
100 101
101 102 repo.requirements.discard('sharedpath')
102 103 repo._writerequirements()
103 104 finally:
104 105 destlock and destlock.release()
105 106 lock and lock.release()
106 107
107 108 # update store, spath, svfs and sjoin of repo
108 109 repo.unfiltered().__init__(repo.baseui, repo.root)
109 110
110 111 # Wrap clone command to pass auto share options.
111 112 def clone(orig, ui, source, *args, **opts):
112 113 pool = ui.config('share', 'pool', None)
113 114 if pool:
114 115 pool = util.expandpath(pool)
115 116
116 117 opts['shareopts'] = dict(
117 118 pool=pool,
118 119 mode=ui.config('share', 'poolnaming', 'identity'),
119 120 )
120 121
121 122 return orig(ui, source, *args, **opts)
122 123
123 124 def extsetup(ui):
124 125 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile)
125 126 extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
126 127 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo)
127 128 extensions.wrapcommand(commands.table, 'clone', clone)
128 129
129 130 def _hassharedbookmarks(repo):
130 131 """Returns whether this repo has shared bookmarks"""
131 132 try:
132 133 shared = repo.vfs.read('shared').splitlines()
133 134 except IOError as inst:
134 135 if inst.errno != errno.ENOENT:
135 136 raise
136 137 return False
137 138 return 'bookmarks' in shared
138 139
139 140 def _getsrcrepo(repo):
140 141 """
141 142 Returns the source repository object for a given shared repository.
142 143 If repo is not a shared repository, return None.
143 144 """
144 145 if repo.sharedpath == repo.path:
145 146 return None
146 147
147 148 # the sharedpath always ends in the .hg; we want the path to the repo
148 149 source = repo.vfs.split(repo.sharedpath)[0]
149 150 srcurl, branches = parseurl(source)
150 151 return repository(repo.ui, srcurl)
151 152
152 153 def getbkfile(orig, repo):
153 154 if _hassharedbookmarks(repo):
154 155 srcrepo = _getsrcrepo(repo)
155 156 if srcrepo is not None:
156 157 repo = srcrepo
157 158 return orig(repo)
158 159
159 160 def recordchange(orig, self, tr):
160 161 # Continue with write to local bookmarks file as usual
161 162 orig(self, tr)
162 163
163 164 if _hassharedbookmarks(self._repo):
164 165 srcrepo = _getsrcrepo(self._repo)
165 166 if srcrepo is not None:
166 167 category = 'share-bookmarks'
167 168 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
168 169
169 170 def writerepo(orig, self, repo):
170 171 # First write local bookmarks file in case we ever unshare
171 172 orig(self, repo)
172 173
173 174 if _hassharedbookmarks(self._repo):
174 175 srcrepo = _getsrcrepo(self._repo)
175 176 if srcrepo is not None:
176 177 orig(self, srcrepo)
General Comments 0
You need to be logged in to leave comments. Login now