##// END OF EJS Templates
share: make option docs more check-config friendly
Matt Mackall -
r25851:bf3d10f0 default
parent child Browse files
Show More
@@ -1,175 +1,175 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 ``pool``
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 ``poolnaming``
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
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 76 return hg.share(ui, source, dest, not noupdate, bookmarks)
77 77
78 78 @command('unshare', [], '')
79 79 def unshare(ui, repo):
80 80 """convert a shared repository to a normal one
81 81
82 82 Copy the store data to the repo and remove the sharedpath data.
83 83 """
84 84
85 85 if not repo.shared():
86 86 raise util.Abort(_("this is not a shared repo"))
87 87
88 88 destlock = lock = None
89 89 lock = repo.lock()
90 90 try:
91 91 # we use locks here because if we race with commit, we
92 92 # can end up with extra data in the cloned revlogs that's
93 93 # not pointed to by changesets, thus causing verify to
94 94 # fail
95 95
96 96 destlock = hg.copystore(ui, repo, repo.path)
97 97
98 98 sharefile = repo.join('sharedpath')
99 99 util.rename(sharefile, sharefile + '.old')
100 100
101 101 repo.requirements.discard('sharedpath')
102 102 repo._writerequirements()
103 103 finally:
104 104 destlock and destlock.release()
105 105 lock and lock.release()
106 106
107 107 # update store, spath, svfs and sjoin of repo
108 108 repo.unfiltered().__init__(repo.baseui, repo.root)
109 109
110 110 # Wrap clone command to pass auto share options.
111 111 def clone(orig, ui, source, *args, **opts):
112 112 pool = ui.config('share', 'pool', None)
113 113 if pool:
114 114 pool = util.expandpath(pool)
115 115
116 116 opts['shareopts'] = dict(
117 117 pool=pool,
118 118 mode=ui.config('share', 'poolnaming', 'identity'),
119 119 )
120 120
121 121 return orig(ui, source, *args, **opts)
122 122
123 123 def extsetup(ui):
124 124 extensions.wrapfunction(bookmarks.bmstore, 'getbkfile', getbkfile)
125 125 extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
126 126 extensions.wrapfunction(bookmarks.bmstore, 'write', write)
127 127 extensions.wrapcommand(commands.table, 'clone', clone)
128 128
129 129 def _hassharedbookmarks(repo):
130 130 """Returns whether this repo has shared bookmarks"""
131 131 try:
132 132 shared = repo.vfs.read('shared').splitlines()
133 133 except IOError as inst:
134 134 if inst.errno != errno.ENOENT:
135 135 raise
136 136 return False
137 137 return 'bookmarks' in shared
138 138
139 139 def _getsrcrepo(repo):
140 140 """
141 141 Returns the source repository object for a given shared repository.
142 142 If repo is not a shared repository, return None.
143 143 """
144 144 if repo.sharedpath == repo.path:
145 145 return None
146 146
147 147 # the sharedpath always ends in the .hg; we want the path to the repo
148 148 source = repo.vfs.split(repo.sharedpath)[0]
149 149 srcurl, branches = parseurl(source)
150 150 return repository(repo.ui, srcurl)
151 151
152 152 def getbkfile(orig, self, repo):
153 153 if _hassharedbookmarks(repo):
154 154 srcrepo = _getsrcrepo(repo)
155 155 if srcrepo is not None:
156 156 repo = srcrepo
157 157 return orig(self, repo)
158 158
159 159 def recordchange(orig, self, tr):
160 160 # Continue with write to local bookmarks file as usual
161 161 orig(self, tr)
162 162
163 163 if _hassharedbookmarks(self._repo):
164 164 srcrepo = _getsrcrepo(self._repo)
165 165 if srcrepo is not None:
166 166 category = 'share-bookmarks'
167 167 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
168 168
169 169 def write(orig, self):
170 170 # First write local bookmarks file in case we ever unshare
171 171 orig(self)
172 172 if _hassharedbookmarks(self._repo):
173 173 srcrepo = _getsrcrepo(self._repo)
174 174 if srcrepo is not None:
175 175 self._writerepo(srcrepo)
General Comments 0
You need to be logged in to leave comments. Login now