58 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
58 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
59 # be specifying the version(s) of Mercurial they are tested with, or |
59 # be specifying the version(s) of Mercurial they are tested with, or |
60 # leave the attribute unspecified. |
60 # leave the attribute unspecified. |
61 testedwith = 'ships-with-hg-core' |
61 testedwith = 'ships-with-hg-core' |
62 |
62 |
63 @command('share', |
63 |
64 [('U', 'noupdate', None, _('do not create a working directory')), |
64 @command( |
65 ('B', 'bookmarks', None, _('also share bookmarks')), |
65 'share', |
66 ('', 'relative', None, _('point to source using a relative path ' |
66 [ |
67 '(EXPERIMENTAL)')), |
67 ('U', 'noupdate', None, _('do not create a working directory')), |
|
68 ('B', 'bookmarks', None, _('also share bookmarks')), |
|
69 ( |
|
70 '', |
|
71 'relative', |
|
72 None, |
|
73 _('point to source using a relative path ' '(EXPERIMENTAL)'), |
|
74 ), |
68 ], |
75 ], |
69 _('[-U] [-B] SOURCE [DEST]'), |
76 _('[-U] [-B] SOURCE [DEST]'), |
70 helpcategory=command.CATEGORY_REPO_CREATION, |
77 helpcategory=command.CATEGORY_REPO_CREATION, |
71 norepo=True) |
78 norepo=True, |
72 def share(ui, source, dest=None, noupdate=False, bookmarks=False, |
79 ) |
73 relative=False): |
80 def share( |
|
81 ui, source, dest=None, noupdate=False, bookmarks=False, relative=False |
|
82 ): |
74 """create a new shared repository |
83 """create a new shared repository |
75 |
84 |
76 Initialize a new repository and working directory that shares its |
85 Initialize a new repository and working directory that shares its |
77 history (and optionally bookmarks) with another repository. |
86 history (and optionally bookmarks) with another repository. |
78 |
87 |
86 operations will fail with "abort: working directory has unknown |
95 operations will fail with "abort: working directory has unknown |
87 parent". The only known workaround is to use debugsetparents on |
96 parent". The only known workaround is to use debugsetparents on |
88 the broken clone to reset it to a changeset that still exists. |
97 the broken clone to reset it to a changeset that still exists. |
89 """ |
98 """ |
90 |
99 |
91 hg.share(ui, source, dest=dest, update=not noupdate, |
100 hg.share( |
92 bookmarks=bookmarks, relative=relative) |
101 ui, |
|
102 source, |
|
103 dest=dest, |
|
104 update=not noupdate, |
|
105 bookmarks=bookmarks, |
|
106 relative=relative, |
|
107 ) |
93 return 0 |
108 return 0 |
|
109 |
94 |
110 |
95 @command('unshare', [], '', helpcategory=command.CATEGORY_MAINTENANCE) |
111 @command('unshare', [], '', helpcategory=command.CATEGORY_MAINTENANCE) |
96 def unshare(ui, repo): |
112 def unshare(ui, repo): |
97 """convert a shared repository to a normal one |
113 """convert a shared repository to a normal one |
98 |
114 |
101 |
117 |
102 if not repo.shared(): |
118 if not repo.shared(): |
103 raise error.Abort(_("this is not a shared repo")) |
119 raise error.Abort(_("this is not a shared repo")) |
104 |
120 |
105 hg.unshare(ui, repo) |
121 hg.unshare(ui, repo) |
|
122 |
106 |
123 |
107 # Wrap clone command to pass auto share options. |
124 # Wrap clone command to pass auto share options. |
108 def clone(orig, ui, source, *args, **opts): |
125 def clone(orig, ui, source, *args, **opts): |
109 pool = ui.config('share', 'pool') |
126 pool = ui.config('share', 'pool') |
110 if pool: |
127 if pool: |
115 'mode': ui.config('share', 'poolnaming'), |
132 'mode': ui.config('share', 'poolnaming'), |
116 } |
133 } |
117 |
134 |
118 return orig(ui, source, *args, **opts) |
135 return orig(ui, source, *args, **opts) |
119 |
136 |
|
137 |
120 def extsetup(ui): |
138 def extsetup(ui): |
121 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile) |
139 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile) |
122 extensions.wrapfunction(bookmarks.bmstore, '_recordchange', recordchange) |
140 extensions.wrapfunction(bookmarks.bmstore, '_recordchange', recordchange) |
123 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo) |
141 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo) |
124 extensions.wrapcommand(commands.table, 'clone', clone) |
142 extensions.wrapcommand(commands.table, 'clone', clone) |
|
143 |
125 |
144 |
126 def _hassharedbookmarks(repo): |
145 def _hassharedbookmarks(repo): |
127 """Returns whether this repo has shared bookmarks""" |
146 """Returns whether this repo has shared bookmarks""" |
128 if bookmarks.bookmarksinstore(repo): |
147 if bookmarks.bookmarksinstore(repo): |
129 # Kind of a lie, but it means that we skip our custom reads and writes |
148 # Kind of a lie, but it means that we skip our custom reads and writes |
135 if inst.errno != errno.ENOENT: |
154 if inst.errno != errno.ENOENT: |
136 raise |
155 raise |
137 return False |
156 return False |
138 return hg.sharedbookmarks in shared |
157 return hg.sharedbookmarks in shared |
139 |
158 |
|
159 |
140 def getbkfile(orig, repo): |
160 def getbkfile(orig, repo): |
141 if _hassharedbookmarks(repo): |
161 if _hassharedbookmarks(repo): |
142 srcrepo = hg.sharedreposource(repo) |
162 srcrepo = hg.sharedreposource(repo) |
143 if srcrepo is not None: |
163 if srcrepo is not None: |
144 # just orig(srcrepo) doesn't work as expected, because |
164 # just orig(srcrepo) doesn't work as expected, because |
145 # HG_PENDING refers repo.root. |
165 # HG_PENDING refers repo.root. |
146 try: |
166 try: |
147 fp, pending = txnutil.trypending(repo.root, repo.vfs, |
167 fp, pending = txnutil.trypending( |
148 'bookmarks') |
168 repo.root, repo.vfs, 'bookmarks' |
|
169 ) |
149 if pending: |
170 if pending: |
150 # only in this case, bookmark information in repo |
171 # only in this case, bookmark information in repo |
151 # is up-to-date. |
172 # is up-to-date. |
152 return fp |
173 return fp |
153 fp.close() |
174 fp.close() |
163 # TODO: Pending changes in repo are still invisible in |
184 # TODO: Pending changes in repo are still invisible in |
164 # srcrepo, because bookmarks.pending is written only into repo. |
185 # srcrepo, because bookmarks.pending is written only into repo. |
165 # See also https://www.mercurial-scm.org/wiki/SharedRepository |
186 # See also https://www.mercurial-scm.org/wiki/SharedRepository |
166 return orig(repo) |
187 return orig(repo) |
167 |
188 |
|
189 |
168 def recordchange(orig, self, tr): |
190 def recordchange(orig, self, tr): |
169 # Continue with write to local bookmarks file as usual |
191 # Continue with write to local bookmarks file as usual |
170 orig(self, tr) |
192 orig(self, tr) |
171 |
193 |
172 if _hassharedbookmarks(self._repo): |
194 if _hassharedbookmarks(self._repo): |
173 srcrepo = hg.sharedreposource(self._repo) |
195 srcrepo = hg.sharedreposource(self._repo) |
174 if srcrepo is not None: |
196 if srcrepo is not None: |
175 category = 'share-bookmarks' |
197 category = 'share-bookmarks' |
176 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo)) |
198 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo)) |
177 |
199 |
|
200 |
178 def writerepo(orig, self, repo): |
201 def writerepo(orig, self, repo): |
179 # First write local bookmarks file in case we ever unshare |
202 # First write local bookmarks file in case we ever unshare |
180 orig(self, repo) |
203 orig(self, repo) |
181 |
204 |
182 if _hassharedbookmarks(self._repo): |
205 if _hassharedbookmarks(self._repo): |