##// END OF EJS Templates
lfs: register the flag processors per repository...
Matt Harbison -
r40304:9c4cbbb0 default
parent child Browse files
Show More
@@ -1,401 +1,416
1 # lfs - hash-preserving large file support using Git-LFS protocol
1 # lfs - hash-preserving large file support using Git-LFS protocol
2 #
2 #
3 # Copyright 2017 Facebook, Inc.
3 # Copyright 2017 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """lfs - large file support (EXPERIMENTAL)
8 """lfs - large file support (EXPERIMENTAL)
9
9
10 This extension allows large files to be tracked outside of the normal
10 This extension allows large files to be tracked outside of the normal
11 repository storage and stored on a centralized server, similar to the
11 repository storage and stored on a centralized server, similar to the
12 ``largefiles`` extension. The ``git-lfs`` protocol is used when
12 ``largefiles`` extension. The ``git-lfs`` protocol is used when
13 communicating with the server, so existing git infrastructure can be
13 communicating with the server, so existing git infrastructure can be
14 harnessed. Even though the files are stored outside of the repository,
14 harnessed. Even though the files are stored outside of the repository,
15 they are still integrity checked in the same manner as normal files.
15 they are still integrity checked in the same manner as normal files.
16
16
17 The files stored outside of the repository are downloaded on demand,
17 The files stored outside of the repository are downloaded on demand,
18 which reduces the time to clone, and possibly the local disk usage.
18 which reduces the time to clone, and possibly the local disk usage.
19 This changes fundamental workflows in a DVCS, so careful thought
19 This changes fundamental workflows in a DVCS, so careful thought
20 should be given before deploying it. :hg:`convert` can be used to
20 should be given before deploying it. :hg:`convert` can be used to
21 convert LFS repositories to normal repositories that no longer
21 convert LFS repositories to normal repositories that no longer
22 require this extension, and do so without changing the commit hashes.
22 require this extension, and do so without changing the commit hashes.
23 This allows the extension to be disabled if the centralized workflow
23 This allows the extension to be disabled if the centralized workflow
24 becomes burdensome. However, the pre and post convert clones will
24 becomes burdensome. However, the pre and post convert clones will
25 not be able to communicate with each other unless the extension is
25 not be able to communicate with each other unless the extension is
26 enabled on both.
26 enabled on both.
27
27
28 To start a new repository, or to add LFS files to an existing one, just
28 To start a new repository, or to add LFS files to an existing one, just
29 create an ``.hglfs`` file as described below in the root directory of
29 create an ``.hglfs`` file as described below in the root directory of
30 the repository. Typically, this file should be put under version
30 the repository. Typically, this file should be put under version
31 control, so that the settings will propagate to other repositories with
31 control, so that the settings will propagate to other repositories with
32 push and pull. During any commit, Mercurial will consult this file to
32 push and pull. During any commit, Mercurial will consult this file to
33 determine if an added or modified file should be stored externally. The
33 determine if an added or modified file should be stored externally. The
34 type of storage depends on the characteristics of the file at each
34 type of storage depends on the characteristics of the file at each
35 commit. A file that is near a size threshold may switch back and forth
35 commit. A file that is near a size threshold may switch back and forth
36 between LFS and normal storage, as needed.
36 between LFS and normal storage, as needed.
37
37
38 Alternately, both normal repositories and largefile controlled
38 Alternately, both normal repositories and largefile controlled
39 repositories can be converted to LFS by using :hg:`convert` and the
39 repositories can be converted to LFS by using :hg:`convert` and the
40 ``lfs.track`` config option described below. The ``.hglfs`` file
40 ``lfs.track`` config option described below. The ``.hglfs`` file
41 should then be created and added, to control subsequent LFS selection.
41 should then be created and added, to control subsequent LFS selection.
42 The hashes are also unchanged in this case. The LFS and non-LFS
42 The hashes are also unchanged in this case. The LFS and non-LFS
43 repositories can be distinguished because the LFS repository will
43 repositories can be distinguished because the LFS repository will
44 abort any command if this extension is disabled.
44 abort any command if this extension is disabled.
45
45
46 Committed LFS files are held locally, until the repository is pushed.
46 Committed LFS files are held locally, until the repository is pushed.
47 Prior to pushing the normal repository data, the LFS files that are
47 Prior to pushing the normal repository data, the LFS files that are
48 tracked by the outgoing commits are automatically uploaded to the
48 tracked by the outgoing commits are automatically uploaded to the
49 configured central server. No LFS files are transferred on
49 configured central server. No LFS files are transferred on
50 :hg:`pull` or :hg:`clone`. Instead, the files are downloaded on
50 :hg:`pull` or :hg:`clone`. Instead, the files are downloaded on
51 demand as they need to be read, if a cached copy cannot be found
51 demand as they need to be read, if a cached copy cannot be found
52 locally. Both committing and downloading an LFS file will link the
52 locally. Both committing and downloading an LFS file will link the
53 file to a usercache, to speed up future access. See the `usercache`
53 file to a usercache, to speed up future access. See the `usercache`
54 config setting described below.
54 config setting described below.
55
55
56 .hglfs::
56 .hglfs::
57
57
58 The extension reads its configuration from a versioned ``.hglfs``
58 The extension reads its configuration from a versioned ``.hglfs``
59 configuration file found in the root of the working directory. The
59 configuration file found in the root of the working directory. The
60 ``.hglfs`` file uses the same syntax as all other Mercurial
60 ``.hglfs`` file uses the same syntax as all other Mercurial
61 configuration files. It uses a single section, ``[track]``.
61 configuration files. It uses a single section, ``[track]``.
62
62
63 The ``[track]`` section specifies which files are stored as LFS (or
63 The ``[track]`` section specifies which files are stored as LFS (or
64 not). Each line is keyed by a file pattern, with a predicate value.
64 not). Each line is keyed by a file pattern, with a predicate value.
65 The first file pattern match is used, so put more specific patterns
65 The first file pattern match is used, so put more specific patterns
66 first. The available predicates are ``all()``, ``none()``, and
66 first. The available predicates are ``all()``, ``none()``, and
67 ``size()``. See "hg help filesets.size" for the latter.
67 ``size()``. See "hg help filesets.size" for the latter.
68
68
69 Example versioned ``.hglfs`` file::
69 Example versioned ``.hglfs`` file::
70
70
71 [track]
71 [track]
72 # No Makefile or python file, anywhere, will be LFS
72 # No Makefile or python file, anywhere, will be LFS
73 **Makefile = none()
73 **Makefile = none()
74 **.py = none()
74 **.py = none()
75
75
76 **.zip = all()
76 **.zip = all()
77 **.exe = size(">1MB")
77 **.exe = size(">1MB")
78
78
79 # Catchall for everything not matched above
79 # Catchall for everything not matched above
80 ** = size(">10MB")
80 ** = size(">10MB")
81
81
82 Configs::
82 Configs::
83
83
84 [lfs]
84 [lfs]
85 # Remote endpoint. Multiple protocols are supported:
85 # Remote endpoint. Multiple protocols are supported:
86 # - http(s)://user:pass@example.com/path
86 # - http(s)://user:pass@example.com/path
87 # git-lfs endpoint
87 # git-lfs endpoint
88 # - file:///tmp/path
88 # - file:///tmp/path
89 # local filesystem, usually for testing
89 # local filesystem, usually for testing
90 # if unset, lfs will assume the remote repository also handles blob storage
90 # if unset, lfs will assume the remote repository also handles blob storage
91 # for http(s) URLs. Otherwise, lfs will prompt to set this when it must
91 # for http(s) URLs. Otherwise, lfs will prompt to set this when it must
92 # use this value.
92 # use this value.
93 # (default: unset)
93 # (default: unset)
94 url = https://example.com/repo.git/info/lfs
94 url = https://example.com/repo.git/info/lfs
95
95
96 # Which files to track in LFS. Path tests are "**.extname" for file
96 # Which files to track in LFS. Path tests are "**.extname" for file
97 # extensions, and "path:under/some/directory" for path prefix. Both
97 # extensions, and "path:under/some/directory" for path prefix. Both
98 # are relative to the repository root.
98 # are relative to the repository root.
99 # File size can be tested with the "size()" fileset, and tests can be
99 # File size can be tested with the "size()" fileset, and tests can be
100 # joined with fileset operators. (See "hg help filesets.operators".)
100 # joined with fileset operators. (See "hg help filesets.operators".)
101 #
101 #
102 # Some examples:
102 # Some examples:
103 # - all() # everything
103 # - all() # everything
104 # - none() # nothing
104 # - none() # nothing
105 # - size(">20MB") # larger than 20MB
105 # - size(">20MB") # larger than 20MB
106 # - !**.txt # anything not a *.txt file
106 # - !**.txt # anything not a *.txt file
107 # - **.zip | **.tar.gz | **.7z # some types of compressed files
107 # - **.zip | **.tar.gz | **.7z # some types of compressed files
108 # - path:bin # files under "bin" in the project root
108 # - path:bin # files under "bin" in the project root
109 # - (**.php & size(">2MB")) | (**.js & size(">5MB")) | **.tar.gz
109 # - (**.php & size(">2MB")) | (**.js & size(">5MB")) | **.tar.gz
110 # | (path:bin & !path:/bin/README) | size(">1GB")
110 # | (path:bin & !path:/bin/README) | size(">1GB")
111 # (default: none())
111 # (default: none())
112 #
112 #
113 # This is ignored if there is a tracked '.hglfs' file, and this setting
113 # This is ignored if there is a tracked '.hglfs' file, and this setting
114 # will eventually be deprecated and removed.
114 # will eventually be deprecated and removed.
115 track = size(">10M")
115 track = size(">10M")
116
116
117 # how many times to retry before giving up on transferring an object
117 # how many times to retry before giving up on transferring an object
118 retry = 5
118 retry = 5
119
119
120 # the local directory to store lfs files for sharing across local clones.
120 # the local directory to store lfs files for sharing across local clones.
121 # If not set, the cache is located in an OS specific cache location.
121 # If not set, the cache is located in an OS specific cache location.
122 usercache = /path/to/global/cache
122 usercache = /path/to/global/cache
123 """
123 """
124
124
125 from __future__ import absolute_import
125 from __future__ import absolute_import
126
126
127 import sys
128
127 from mercurial.i18n import _
129 from mercurial.i18n import _
128
130
129 from mercurial import (
131 from mercurial import (
130 bundle2,
132 bundle2,
131 changegroup,
133 changegroup,
132 cmdutil,
134 cmdutil,
133 config,
135 config,
134 context,
136 context,
135 error,
137 error,
136 exchange,
138 exchange,
137 extensions,
139 extensions,
138 filelog,
140 filelog,
139 filesetlang,
141 filesetlang,
140 localrepo,
142 localrepo,
141 minifileset,
143 minifileset,
142 node,
144 node,
143 pycompat,
145 pycompat,
144 registrar,
146 registrar,
145 repository,
147 repository,
146 revlog,
148 revlog,
147 scmutil,
149 scmutil,
148 templateutil,
150 templateutil,
149 upgrade,
151 upgrade,
150 util,
152 util,
151 vfs as vfsmod,
153 vfs as vfsmod,
152 wireprotoserver,
154 wireprotoserver,
153 wireprotov1server,
155 wireprotov1server,
154 )
156 )
155
157
156 from . import (
158 from . import (
157 blobstore,
159 blobstore,
158 wireprotolfsserver,
160 wireprotolfsserver,
159 wrapper,
161 wrapper,
160 )
162 )
161
163
162 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
164 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
163 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
165 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
164 # be specifying the version(s) of Mercurial they are tested with, or
166 # be specifying the version(s) of Mercurial they are tested with, or
165 # leave the attribute unspecified.
167 # leave the attribute unspecified.
166 testedwith = 'ships-with-hg-core'
168 testedwith = 'ships-with-hg-core'
167
169
168 configtable = {}
170 configtable = {}
169 configitem = registrar.configitem(configtable)
171 configitem = registrar.configitem(configtable)
170
172
171 configitem('experimental', 'lfs.serve',
173 configitem('experimental', 'lfs.serve',
172 default=True,
174 default=True,
173 )
175 )
174 configitem('experimental', 'lfs.user-agent',
176 configitem('experimental', 'lfs.user-agent',
175 default=None,
177 default=None,
176 )
178 )
177 configitem('experimental', 'lfs.disableusercache',
179 configitem('experimental', 'lfs.disableusercache',
178 default=False,
180 default=False,
179 )
181 )
180 configitem('experimental', 'lfs.worker-enable',
182 configitem('experimental', 'lfs.worker-enable',
181 default=False,
183 default=False,
182 )
184 )
183
185
184 configitem('lfs', 'url',
186 configitem('lfs', 'url',
185 default=None,
187 default=None,
186 )
188 )
187 configitem('lfs', 'usercache',
189 configitem('lfs', 'usercache',
188 default=None,
190 default=None,
189 )
191 )
190 # Deprecated
192 # Deprecated
191 configitem('lfs', 'threshold',
193 configitem('lfs', 'threshold',
192 default=None,
194 default=None,
193 )
195 )
194 configitem('lfs', 'track',
196 configitem('lfs', 'track',
195 default='none()',
197 default='none()',
196 )
198 )
197 configitem('lfs', 'retry',
199 configitem('lfs', 'retry',
198 default=5,
200 default=5,
199 )
201 )
200
202
201 cmdtable = {}
203 cmdtable = {}
202 command = registrar.command(cmdtable)
204 command = registrar.command(cmdtable)
203
205
204 templatekeyword = registrar.templatekeyword()
206 templatekeyword = registrar.templatekeyword()
205 filesetpredicate = registrar.filesetpredicate()
207 filesetpredicate = registrar.filesetpredicate()
206
208
209 lfsprocessor = (
210 wrapper.readfromstore,
211 wrapper.writetostore,
212 wrapper.bypasscheckhash,
213 )
214
207 def featuresetup(ui, supported):
215 def featuresetup(ui, supported):
208 # don't die on seeing a repo with the lfs requirement
216 # don't die on seeing a repo with the lfs requirement
209 supported |= {'lfs'}
217 supported |= {'lfs'}
210
218
211 def uisetup(ui):
219 def uisetup(ui):
212 localrepo.featuresetupfuncs.add(featuresetup)
220 localrepo.featuresetupfuncs.add(featuresetup)
213
221
214 def reposetup(ui, repo):
222 def reposetup(ui, repo):
215 # Nothing to do with a remote repo
223 # Nothing to do with a remote repo
216 if not repo.local():
224 if not repo.local():
217 return
225 return
218
226
219 repo.svfs.lfslocalblobstore = blobstore.local(repo)
227 repo.svfs.lfslocalblobstore = blobstore.local(repo)
220 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
228 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
221
229
222 class lfsrepo(repo.__class__):
230 class lfsrepo(repo.__class__):
223 @localrepo.unfilteredmethod
231 @localrepo.unfilteredmethod
224 def commitctx(self, ctx, error=False):
232 def commitctx(self, ctx, error=False):
225 repo.svfs.options['lfstrack'] = _trackedmatcher(self)
233 repo.svfs.options['lfstrack'] = _trackedmatcher(self)
226 return super(lfsrepo, self).commitctx(ctx, error)
234 return super(lfsrepo, self).commitctx(ctx, error)
227
235
228 repo.__class__ = lfsrepo
236 repo.__class__ = lfsrepo
229
237
230 if 'lfs' not in repo.requirements:
238 if 'lfs' not in repo.requirements:
231 def checkrequireslfs(ui, repo, **kwargs):
239 def checkrequireslfs(ui, repo, **kwargs):
232 if 'lfs' not in repo.requirements:
240 if 'lfs' not in repo.requirements:
233 last = kwargs.get(r'node_last')
241 last = kwargs.get(r'node_last')
234 _bin = node.bin
242 _bin = node.bin
235 if last:
243 if last:
236 s = repo.set('%n:%n', _bin(kwargs[r'node']), _bin(last))
244 s = repo.set('%n:%n', _bin(kwargs[r'node']), _bin(last))
237 else:
245 else:
238 s = repo.set('%n', _bin(kwargs[r'node']))
246 s = repo.set('%n', _bin(kwargs[r'node']))
239 match = repo.narrowmatch()
247 match = repo.narrowmatch()
240 for ctx in s:
248 for ctx in s:
241 # TODO: is there a way to just walk the files in the commit?
249 # TODO: is there a way to just walk the files in the commit?
242 if any(ctx[f].islfs() for f in ctx.files()
250 if any(ctx[f].islfs() for f in ctx.files()
243 if f in ctx and match(f)):
251 if f in ctx and match(f)):
244 repo.requirements.add('lfs')
252 repo.requirements.add('lfs')
245 repo.features.add(repository.REPO_FEATURE_LFS)
253 repo.features.add(repository.REPO_FEATURE_LFS)
246 repo._writerequirements()
254 repo._writerequirements()
247 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
255 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
248 break
256 break
249
257
250 ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
258 ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
251 ui.setconfig('hooks', 'pretxnchangegroup.lfs', checkrequireslfs, 'lfs')
259 ui.setconfig('hooks', 'pretxnchangegroup.lfs', checkrequireslfs, 'lfs')
252 else:
260 else:
253 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
261 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
254
262
255 def _trackedmatcher(repo):
263 def _trackedmatcher(repo):
256 """Return a function (path, size) -> bool indicating whether or not to
264 """Return a function (path, size) -> bool indicating whether or not to
257 track a given file with lfs."""
265 track a given file with lfs."""
258 if not repo.wvfs.exists('.hglfs'):
266 if not repo.wvfs.exists('.hglfs'):
259 # No '.hglfs' in wdir. Fallback to config for now.
267 # No '.hglfs' in wdir. Fallback to config for now.
260 trackspec = repo.ui.config('lfs', 'track')
268 trackspec = repo.ui.config('lfs', 'track')
261
269
262 # deprecated config: lfs.threshold
270 # deprecated config: lfs.threshold
263 threshold = repo.ui.configbytes('lfs', 'threshold')
271 threshold = repo.ui.configbytes('lfs', 'threshold')
264 if threshold:
272 if threshold:
265 filesetlang.parse(trackspec) # make sure syntax errors are confined
273 filesetlang.parse(trackspec) # make sure syntax errors are confined
266 trackspec = "(%s) | size('>%d')" % (trackspec, threshold)
274 trackspec = "(%s) | size('>%d')" % (trackspec, threshold)
267
275
268 return minifileset.compile(trackspec)
276 return minifileset.compile(trackspec)
269
277
270 data = repo.wvfs.tryread('.hglfs')
278 data = repo.wvfs.tryread('.hglfs')
271 if not data:
279 if not data:
272 return lambda p, s: False
280 return lambda p, s: False
273
281
274 # Parse errors here will abort with a message that points to the .hglfs file
282 # Parse errors here will abort with a message that points to the .hglfs file
275 # and line number.
283 # and line number.
276 cfg = config.config()
284 cfg = config.config()
277 cfg.parse('.hglfs', data)
285 cfg.parse('.hglfs', data)
278
286
279 try:
287 try:
280 rules = [(minifileset.compile(pattern), minifileset.compile(rule))
288 rules = [(minifileset.compile(pattern), minifileset.compile(rule))
281 for pattern, rule in cfg.items('track')]
289 for pattern, rule in cfg.items('track')]
282 except error.ParseError as e:
290 except error.ParseError as e:
283 # The original exception gives no indicator that the error is in the
291 # The original exception gives no indicator that the error is in the
284 # .hglfs file, so add that.
292 # .hglfs file, so add that.
285
293
286 # TODO: See if the line number of the file can be made available.
294 # TODO: See if the line number of the file can be made available.
287 raise error.Abort(_('parse error in .hglfs: %s') % e)
295 raise error.Abort(_('parse error in .hglfs: %s') % e)
288
296
289 def _match(path, size):
297 def _match(path, size):
290 for pat, rule in rules:
298 for pat, rule in rules:
291 if pat(path, size):
299 if pat(path, size):
292 return rule(path, size)
300 return rule(path, size)
293
301
294 return False
302 return False
295
303
296 return _match
304 return _match
297
305
298 def wrapfilelog(filelog):
306 def wrapfilelog(filelog):
299 wrapfunction = extensions.wrapfunction
307 wrapfunction = extensions.wrapfunction
300
308
301 wrapfunction(filelog, 'addrevision', wrapper.filelogaddrevision)
309 wrapfunction(filelog, 'addrevision', wrapper.filelogaddrevision)
302 wrapfunction(filelog, 'renamed', wrapper.filelogrenamed)
310 wrapfunction(filelog, 'renamed', wrapper.filelogrenamed)
303 wrapfunction(filelog, 'size', wrapper.filelogsize)
311 wrapfunction(filelog, 'size', wrapper.filelogsize)
304
312
313 def _resolverevlogstorevfsoptions(orig, ui, requirements, features):
314 opts = orig(ui, requirements, features)
315 for name, module in extensions.extensions(ui):
316 if module is sys.modules[__name__]:
317 if revlog.REVIDX_EXTSTORED in opts[b'flagprocessors']:
318 msg = (_(b"cannot register multiple processors on flag '%#x'.")
319 % revlog.REVIDX_EXTSTORED)
320 raise error.Abort(msg)
321
322 opts[b'flagprocessors'][revlog.REVIDX_EXTSTORED] = lfsprocessor
323 break
324
325 return opts
326
305 def extsetup(ui):
327 def extsetup(ui):
306 wrapfilelog(filelog.filelog)
328 wrapfilelog(filelog.filelog)
307
329
308 wrapfunction = extensions.wrapfunction
330 wrapfunction = extensions.wrapfunction
309
331
310 wrapfunction(localrepo, 'makefilestorage', wrapper.localrepomakefilestorage)
332 wrapfunction(localrepo, 'makefilestorage', wrapper.localrepomakefilestorage)
333 wrapfunction(localrepo, 'resolverevlogstorevfsoptions',
334 _resolverevlogstorevfsoptions)
311
335
312 wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter)
336 wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter)
313 wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink)
337 wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink)
314
338
315 wrapfunction(upgrade, '_finishdatamigration',
339 wrapfunction(upgrade, '_finishdatamigration',
316 wrapper.upgradefinishdatamigration)
340 wrapper.upgradefinishdatamigration)
317
341
318 wrapfunction(upgrade, 'preservedrequirements',
342 wrapfunction(upgrade, 'preservedrequirements',
319 wrapper.upgraderequirements)
343 wrapper.upgraderequirements)
320
344
321 wrapfunction(upgrade, 'supporteddestrequirements',
345 wrapfunction(upgrade, 'supporteddestrequirements',
322 wrapper.upgraderequirements)
346 wrapper.upgraderequirements)
323
347
324 wrapfunction(changegroup,
348 wrapfunction(changegroup,
325 'allsupportedversions',
349 'allsupportedversions',
326 wrapper.allsupportedversions)
350 wrapper.allsupportedversions)
327
351
328 wrapfunction(exchange, 'push', wrapper.push)
352 wrapfunction(exchange, 'push', wrapper.push)
329 wrapfunction(wireprotov1server, '_capabilities', wrapper._capabilities)
353 wrapfunction(wireprotov1server, '_capabilities', wrapper._capabilities)
330 wrapfunction(wireprotoserver, 'handlewsgirequest',
354 wrapfunction(wireprotoserver, 'handlewsgirequest',
331 wireprotolfsserver.handlewsgirequest)
355 wireprotolfsserver.handlewsgirequest)
332
356
333 wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp)
357 wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp)
334 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
358 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
335 context.basefilectx.islfs = wrapper.filectxislfs
359 context.basefilectx.islfs = wrapper.filectxislfs
336
360
337 revlog.addflagprocessor(
338 revlog.REVIDX_EXTSTORED,
339 (
340 wrapper.readfromstore,
341 wrapper.writetostore,
342 wrapper.bypasscheckhash,
343 ),
344 )
345
346 scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles)
361 scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles)
347
362
348 # Make bundle choose changegroup3 instead of changegroup2. This affects
363 # Make bundle choose changegroup3 instead of changegroup2. This affects
349 # "hg bundle" command. Note: it does not cover all bundle formats like
364 # "hg bundle" command. Note: it does not cover all bundle formats like
350 # "packed1". Using "packed1" with lfs will likely cause trouble.
365 # "packed1". Using "packed1" with lfs will likely cause trouble.
351 exchange._bundlespeccontentopts["v2"]["cg.version"] = "03"
366 exchange._bundlespeccontentopts["v2"]["cg.version"] = "03"
352
367
353 # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
368 # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
354 # options and blob stores are passed from othervfs to the new readonlyvfs.
369 # options and blob stores are passed from othervfs to the new readonlyvfs.
355 wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit)
370 wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit)
356
371
357 # when writing a bundle via "hg bundle" command, upload related LFS blobs
372 # when writing a bundle via "hg bundle" command, upload related LFS blobs
358 wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle)
373 wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle)
359
374
360 @filesetpredicate('lfs()')
375 @filesetpredicate('lfs()')
361 def lfsfileset(mctx, x):
376 def lfsfileset(mctx, x):
362 """File that uses LFS storage."""
377 """File that uses LFS storage."""
363 # i18n: "lfs" is a keyword
378 # i18n: "lfs" is a keyword
364 filesetlang.getargs(x, 0, 0, _("lfs takes no arguments"))
379 filesetlang.getargs(x, 0, 0, _("lfs takes no arguments"))
365 ctx = mctx.ctx
380 ctx = mctx.ctx
366 def lfsfilep(f):
381 def lfsfilep(f):
367 return wrapper.pointerfromctx(ctx, f, removed=True) is not None
382 return wrapper.pointerfromctx(ctx, f, removed=True) is not None
368 return mctx.predicate(lfsfilep, predrepr='<lfs>')
383 return mctx.predicate(lfsfilep, predrepr='<lfs>')
369
384
370 @templatekeyword('lfs_files', requires={'ctx'})
385 @templatekeyword('lfs_files', requires={'ctx'})
371 def lfsfiles(context, mapping):
386 def lfsfiles(context, mapping):
372 """List of strings. All files modified, added, or removed by this
387 """List of strings. All files modified, added, or removed by this
373 changeset."""
388 changeset."""
374 ctx = context.resource(mapping, 'ctx')
389 ctx = context.resource(mapping, 'ctx')
375
390
376 pointers = wrapper.pointersfromctx(ctx, removed=True) # {path: pointer}
391 pointers = wrapper.pointersfromctx(ctx, removed=True) # {path: pointer}
377 files = sorted(pointers.keys())
392 files = sorted(pointers.keys())
378
393
379 def pointer(v):
394 def pointer(v):
380 # In the file spec, version is first and the other keys are sorted.
395 # In the file spec, version is first and the other keys are sorted.
381 sortkeyfunc = lambda x: (x[0] != 'version', x)
396 sortkeyfunc = lambda x: (x[0] != 'version', x)
382 items = sorted(pointers[v].iteritems(), key=sortkeyfunc)
397 items = sorted(pointers[v].iteritems(), key=sortkeyfunc)
383 return util.sortdict(items)
398 return util.sortdict(items)
384
399
385 makemap = lambda v: {
400 makemap = lambda v: {
386 'file': v,
401 'file': v,
387 'lfsoid': pointers[v].oid() if pointers[v] else None,
402 'lfsoid': pointers[v].oid() if pointers[v] else None,
388 'lfspointer': templateutil.hybriddict(pointer(v)),
403 'lfspointer': templateutil.hybriddict(pointer(v)),
389 }
404 }
390
405
391 # TODO: make the separator ', '?
406 # TODO: make the separator ', '?
392 f = templateutil._showcompatlist(context, mapping, 'lfs_file', files)
407 f = templateutil._showcompatlist(context, mapping, 'lfs_file', files)
393 return templateutil.hybrid(f, files, makemap, pycompat.identity)
408 return templateutil.hybrid(f, files, makemap, pycompat.identity)
394
409
395 @command('debuglfsupload',
410 @command('debuglfsupload',
396 [('r', 'rev', [], _('upload large files introduced by REV'))])
411 [('r', 'rev', [], _('upload large files introduced by REV'))])
397 def debuglfsupload(ui, repo, **opts):
412 def debuglfsupload(ui, repo, **opts):
398 """upload lfs blobs added by the working copy parent or given revisions"""
413 """upload lfs blobs added by the working copy parent or given revisions"""
399 revs = opts.get(r'rev', [])
414 revs = opts.get(r'rev', [])
400 pointers = wrapper.extractpointers(repo, scmutil.revrange(repo, revs))
415 pointers = wrapper.extractpointers(repo, scmutil.revrange(repo, revs))
401 wrapper.uploadblobs(repo, pointers)
416 wrapper.uploadblobs(repo, pointers)
@@ -1,523 +1,644
1 #testcases lfsremote-on lfsremote-off
1 #testcases lfsremote-on lfsremote-off
2 #require serve no-reposimplestore no-chg
2 #require serve no-reposimplestore no-chg
3
3
4 This test splits `hg serve` with and without using the extension into separate
4 This test splits `hg serve` with and without using the extension into separate
5 tests cases. The tests are broken down as follows, where "LFS"/"No-LFS"
5 tests cases. The tests are broken down as follows, where "LFS"/"No-LFS"
6 indicates whether or not there are commits that use an LFS file, and "D"/"E"
6 indicates whether or not there are commits that use an LFS file, and "D"/"E"
7 indicates whether or not the extension is loaded. The "X" cases are not tested
7 indicates whether or not the extension is loaded. The "X" cases are not tested
8 individually, because the lfs requirement causes the process to bail early if
8 individually, because the lfs requirement causes the process to bail early if
9 the extension is disabled.
9 the extension is disabled.
10
10
11 . Server
11 . Server
12 .
12 .
13 . No-LFS LFS
13 . No-LFS LFS
14 . +----------------------------+
14 . +----------------------------+
15 . | || D | E | D | E |
15 . | || D | E | D | E |
16 . |---++=======================|
16 . |---++=======================|
17 . C | D || N/A | #1 | X | #4 |
17 . C | D || N/A | #1 | X | #4 |
18 . l No +---++-----------------------|
18 . l No +---++-----------------------|
19 . i LFS | E || #2 | #2 | X | #5 |
19 . i LFS | E || #2 | #2 | X | #5 |
20 . e +---++-----------------------|
20 . e +---++-----------------------|
21 . n | D || X | X | X | X |
21 . n | D || X | X | X | X |
22 . t LFS |---++-----------------------|
22 . t LFS |---++-----------------------|
23 . | E || #3 | #3 | X | #6 |
23 . | E || #3 | #3 | X | #6 |
24 . |---++-----------------------+
24 . |---++-----------------------+
25
25
26 make command server magic visible
26 make command server magic visible
27
27
28 #if windows
28 #if windows
29 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
29 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
30 #else
30 #else
31 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
31 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
32 #endif
32 #endif
33 $ export PYTHONPATH
33 $ export PYTHONPATH
34
34
35 $ hg init server
35 $ hg init server
36 $ SERVER_REQUIRES="$TESTTMP/server/.hg/requires"
36 $ SERVER_REQUIRES="$TESTTMP/server/.hg/requires"
37
37
38 $ cat > $TESTTMP/debugprocessors.py <<EOF
39 > from mercurial import (
40 > cmdutil,
41 > commands,
42 > pycompat,
43 > registrar,
44 > )
45 > cmdtable = {}
46 > command = registrar.command(cmdtable)
47 > @command(b'debugprocessors', [], b'FILE')
48 > def debugprocessors(ui, repo, file_=None, **opts):
49 > opts = pycompat.byteskwargs(opts)
50 > opts[b'changelog'] = False
51 > opts[b'manifest'] = False
52 > opts[b'dir'] = False
53 > rl = cmdutil.openrevlog(repo, b'debugprocessors', file_, opts)
54 > for flag, proc in rl._flagprocessors.iteritems():
55 > ui.status(b"registered processor '%#x'\n" % (flag))
56 > EOF
57
38 Skip the experimental.changegroup3=True config. Failure to agree on this comes
58 Skip the experimental.changegroup3=True config. Failure to agree on this comes
39 first, and causes a "ValueError: no common changegroup version" or "abort:
59 first, and causes a "ValueError: no common changegroup version" or "abort:
40 HTTP Error 500: Internal Server Error", if the extension is only loaded on one
60 HTTP Error 500: Internal Server Error", if the extension is only loaded on one
41 side. If that *is* enabled, the subsequent failure is "abort: missing processor
61 side. If that *is* enabled, the subsequent failure is "abort: missing processor
42 for flag '0x2000'!" if the extension is only loaded on one side (possibly also
62 for flag '0x2000'!" if the extension is only loaded on one side (possibly also
43 masked by the Internal Server Error message).
63 masked by the Internal Server Error message).
44 $ cat >> $HGRCPATH <<EOF
64 $ cat >> $HGRCPATH <<EOF
65 > [extensions]
66 > debugprocessors = $TESTTMP/debugprocessors.py
45 > [experimental]
67 > [experimental]
46 > lfs.disableusercache = True
68 > lfs.disableusercache = True
47 > [lfs]
69 > [lfs]
48 > threshold=10
70 > threshold=10
49 > [web]
71 > [web]
50 > allow_push=*
72 > allow_push=*
51 > push_ssl=False
73 > push_ssl=False
52 > EOF
74 > EOF
53
75
76 $ cp $HGRCPATH $HGRCPATH.orig
77
54 #if lfsremote-on
78 #if lfsremote-on
55 $ hg --config extensions.lfs= -R server \
79 $ hg --config extensions.lfs= -R server \
56 > serve -p $HGPORT -d --pid-file=hg.pid --errorlog=$TESTTMP/errors.log
80 > serve -p $HGPORT -d --pid-file=hg.pid --errorlog=$TESTTMP/errors.log
57 #else
81 #else
58 $ hg --config extensions.lfs=! -R server \
82 $ hg --config extensions.lfs=! -R server \
59 > serve -p $HGPORT -d --pid-file=hg.pid --errorlog=$TESTTMP/errors.log
83 > serve -p $HGPORT -d --pid-file=hg.pid --errorlog=$TESTTMP/errors.log
60 #endif
84 #endif
61
85
62 $ cat hg.pid >> $DAEMON_PIDS
86 $ cat hg.pid >> $DAEMON_PIDS
63 $ hg clone -q http://localhost:$HGPORT client
87 $ hg clone -q http://localhost:$HGPORT client
64 $ grep 'lfs' client/.hg/requires $SERVER_REQUIRES
88 $ grep 'lfs' client/.hg/requires $SERVER_REQUIRES
65 [1]
89 [1]
66
90
67 This trivial repo will force commandserver to load the extension, but not call
91 This trivial repo will force commandserver to load the extension, but not call
68 reposetup() on another repo actually being operated on. This gives coverage
92 reposetup() on another repo actually being operated on. This gives coverage
69 that wrapper functions are not assuming reposetup() was called.
93 that wrapper functions are not assuming reposetup() was called.
70
94
71 $ hg init $TESTTMP/cmdservelfs
95 $ hg init $TESTTMP/cmdservelfs
72 $ cat >> $TESTTMP/cmdservelfs/.hg/hgrc << EOF
96 $ cat >> $TESTTMP/cmdservelfs/.hg/hgrc << EOF
73 > [extensions]
97 > [extensions]
74 > lfs =
98 > lfs =
75 > EOF
99 > EOF
76
100
77 --------------------------------------------------------------------------------
101 --------------------------------------------------------------------------------
78 Case #1: client with non-lfs content and the extension disabled; server with
102 Case #1: client with non-lfs content and the extension disabled; server with
79 non-lfs content, and the extension enabled.
103 non-lfs content, and the extension enabled.
80
104
81 $ cd client
105 $ cd client
82 $ echo 'non-lfs' > nonlfs.txt
106 $ echo 'non-lfs' > nonlfs.txt
83 >>> from __future__ import absolute_import
107 >>> from __future__ import absolute_import
84 >>> from hgclient import check, readchannel, runcommand
108 >>> from hgclient import check, readchannel, runcommand
85 >>> @check
109 >>> @check
86 ... def diff(server):
110 ... def diff(server):
87 ... readchannel(server)
111 ... readchannel(server)
88 ... # run an arbitrary command in the repo with the extension loaded
112 ... # run an arbitrary command in the repo with the extension loaded
89 ... runcommand(server, ['id', '-R', '../cmdservelfs'])
113 ... runcommand(server, ['id', '-R', '../cmdservelfs'])
90 ... # now run a command in a repo without the extension to ensure that
114 ... # now run a command in a repo without the extension to ensure that
91 ... # files are added safely..
115 ... # files are added safely..
92 ... runcommand(server, ['ci', '-Aqm', 'non-lfs'])
116 ... runcommand(server, ['ci', '-Aqm', 'non-lfs'])
93 ... # .. and that scmutil.prefetchfiles() safely no-ops..
117 ... # .. and that scmutil.prefetchfiles() safely no-ops..
94 ... runcommand(server, ['diff', '-r', '.~1'])
118 ... runcommand(server, ['diff', '-r', '.~1'])
95 ... # .. and that debugupgraderepo safely no-ops.
119 ... # .. and that debugupgraderepo safely no-ops.
96 ... runcommand(server, ['debugupgraderepo', '-q', '--run'])
120 ... runcommand(server, ['debugupgraderepo', '-q', '--run'])
97 *** runcommand id -R ../cmdservelfs
121 *** runcommand id -R ../cmdservelfs
98 000000000000 tip
122 000000000000 tip
99 *** runcommand ci -Aqm non-lfs
123 *** runcommand ci -Aqm non-lfs
100 *** runcommand diff -r .~1
124 *** runcommand diff -r .~1
101 diff -r 000000000000 nonlfs.txt
125 diff -r 000000000000 nonlfs.txt
102 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103 +++ b/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
127 +++ b/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
104 @@ -0,0 +1,1 @@
128 @@ -0,0 +1,1 @@
105 +non-lfs
129 +non-lfs
106 *** runcommand debugupgraderepo -q --run
130 *** runcommand debugupgraderepo -q --run
107 upgrade will perform the following actions:
131 upgrade will perform the following actions:
108
132
109 requirements
133 requirements
110 preserved: dotencode, fncache, generaldelta, revlogv1, store
134 preserved: dotencode, fncache, generaldelta, revlogv1, store
111
135
112 beginning upgrade...
136 beginning upgrade...
113 repository locked and read-only
137 repository locked and read-only
114 creating temporary repository to stage migrated data: * (glob)
138 creating temporary repository to stage migrated data: * (glob)
115 (it is safe to interrupt this process any time before data migration completes)
139 (it is safe to interrupt this process any time before data migration completes)
116 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
140 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
117 migrating 324 bytes in store; 129 bytes tracked data
141 migrating 324 bytes in store; 129 bytes tracked data
118 migrating 1 filelogs containing 1 revisions (73 bytes in store; 8 bytes tracked data)
142 migrating 1 filelogs containing 1 revisions (73 bytes in store; 8 bytes tracked data)
119 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
143 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
120 migrating 1 manifests containing 1 revisions (117 bytes in store; 52 bytes tracked data)
144 migrating 1 manifests containing 1 revisions (117 bytes in store; 52 bytes tracked data)
121 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
145 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
122 migrating changelog containing 1 revisions (134 bytes in store; 69 bytes tracked data)
146 migrating changelog containing 1 revisions (134 bytes in store; 69 bytes tracked data)
123 finished migrating 1 changelog revisions; change in size: 0 bytes
147 finished migrating 1 changelog revisions; change in size: 0 bytes
124 finished migrating 3 total revisions; total change in store size: 0 bytes
148 finished migrating 3 total revisions; total change in store size: 0 bytes
125 copying phaseroots
149 copying phaseroots
126 data fully migrated to temporary repository
150 data fully migrated to temporary repository
127 marking source repository as being upgraded; clients will be unable to read from repository
151 marking source repository as being upgraded; clients will be unable to read from repository
128 starting in-place swap of repository data
152 starting in-place swap of repository data
129 replaced files will be backed up at * (glob)
153 replaced files will be backed up at * (glob)
130 replacing store...
154 replacing store...
131 store replacement complete; repository was inconsistent for *s (glob)
155 store replacement complete; repository was inconsistent for *s (glob)
132 finalizing requirements file and making repository readable again
156 finalizing requirements file and making repository readable again
133 removing temporary repository * (glob)
157 removing temporary repository * (glob)
134 copy of old repository backed up at * (glob)
158 copy of old repository backed up at * (glob)
135 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
159 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
136
160
137 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
161 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
138 [1]
162 [1]
139
163
140 #if lfsremote-on
164 #if lfsremote-on
141
165
142 $ hg push -q
166 $ hg push -q
143 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
167 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
144 [1]
168 [1]
145
169
146 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client1_clone
170 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client1_clone
147 $ grep 'lfs' $TESTTMP/client1_clone/.hg/requires $SERVER_REQUIRES
171 $ grep 'lfs' $TESTTMP/client1_clone/.hg/requires $SERVER_REQUIRES
148 [1]
172 [1]
149
173
150 $ hg init $TESTTMP/client1_pull
174 $ hg init $TESTTMP/client1_pull
151 $ hg -R $TESTTMP/client1_pull pull -q http://localhost:$HGPORT
175 $ hg -R $TESTTMP/client1_pull pull -q http://localhost:$HGPORT
152 $ grep 'lfs' $TESTTMP/client1_pull/.hg/requires $SERVER_REQUIRES
176 $ grep 'lfs' $TESTTMP/client1_pull/.hg/requires $SERVER_REQUIRES
153 [1]
177 [1]
154
178
155 $ hg identify http://localhost:$HGPORT
179 $ hg identify http://localhost:$HGPORT
156 d437e1d24fbd
180 d437e1d24fbd
157
181
158 #endif
182 #endif
159
183
160 --------------------------------------------------------------------------------
184 --------------------------------------------------------------------------------
161 Case #2: client with non-lfs content and the extension enabled; server with
185 Case #2: client with non-lfs content and the extension enabled; server with
162 non-lfs content, and the extension state controlled by #testcases.
186 non-lfs content, and the extension state controlled by #testcases.
163
187
164 $ cat >> $HGRCPATH <<EOF
188 $ cat >> $HGRCPATH <<EOF
165 > [extensions]
189 > [extensions]
166 > lfs =
190 > lfs =
167 > EOF
191 > EOF
168 $ echo 'non-lfs' > nonlfs2.txt
192 $ echo 'non-lfs' > nonlfs2.txt
169 $ hg ci -Aqm 'non-lfs file with lfs client'
193 $ hg ci -Aqm 'non-lfs file with lfs client'
170
194
171 Since no lfs content has been added yet, the push is allowed, even when the
195 Since no lfs content has been added yet, the push is allowed, even when the
172 extension is not enabled remotely.
196 extension is not enabled remotely.
173
197
174 $ hg push -q
198 $ hg push -q
175 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
199 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
176 [1]
200 [1]
177
201
178 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client2_clone
202 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client2_clone
179 $ grep 'lfs' $TESTTMP/client2_clone/.hg/requires $SERVER_REQUIRES
203 $ grep 'lfs' $TESTTMP/client2_clone/.hg/requires $SERVER_REQUIRES
180 [1]
204 [1]
181
205
182 $ hg init $TESTTMP/client2_pull
206 $ hg init $TESTTMP/client2_pull
183 $ hg -R $TESTTMP/client2_pull pull -q http://localhost:$HGPORT
207 $ hg -R $TESTTMP/client2_pull pull -q http://localhost:$HGPORT
184 $ grep 'lfs' $TESTTMP/client2_pull/.hg/requires $SERVER_REQUIRES
208 $ grep 'lfs' $TESTTMP/client2_pull/.hg/requires $SERVER_REQUIRES
185 [1]
209 [1]
186
210
187 $ hg identify http://localhost:$HGPORT
211 $ hg identify http://localhost:$HGPORT
188 1477875038c6
212 1477875038c6
189
213
190 --------------------------------------------------------------------------------
214 --------------------------------------------------------------------------------
191 Case #3: client with lfs content and the extension enabled; server with
215 Case #3: client with lfs content and the extension enabled; server with
192 non-lfs content, and the extension state controlled by #testcases. The server
216 non-lfs content, and the extension state controlled by #testcases. The server
193 should have an 'lfs' requirement after it picks up its first commit with a blob.
217 should have an 'lfs' requirement after it picks up its first commit with a blob.
194
218
195 $ echo 'this is a big lfs file' > lfs.bin
219 $ echo 'this is a big lfs file' > lfs.bin
196 $ hg ci -Aqm 'lfs'
220 $ hg ci -Aqm 'lfs'
197 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
221 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
198 .hg/requires:lfs
222 .hg/requires:lfs
199
223
200 #if lfsremote-off
224 #if lfsremote-off
201 $ hg push -q
225 $ hg push -q
202 abort: required features are not supported in the destination: lfs
226 abort: required features are not supported in the destination: lfs
203 (enable the lfs extension on the server)
227 (enable the lfs extension on the server)
204 [255]
228 [255]
205 #else
229 #else
206 $ hg push -q
230 $ hg push -q
207 #endif
231 #endif
208 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
232 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
209 .hg/requires:lfs
233 .hg/requires:lfs
210 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
234 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
211
235
212 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client3_clone
236 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client3_clone
213 $ grep 'lfs' $TESTTMP/client3_clone/.hg/requires $SERVER_REQUIRES || true
237 $ grep 'lfs' $TESTTMP/client3_clone/.hg/requires $SERVER_REQUIRES || true
214 $TESTTMP/client3_clone/.hg/requires:lfs (lfsremote-on !)
238 $TESTTMP/client3_clone/.hg/requires:lfs (lfsremote-on !)
215 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
239 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
216
240
217 $ hg init $TESTTMP/client3_pull
241 $ hg init $TESTTMP/client3_pull
218 $ hg -R $TESTTMP/client3_pull pull -q http://localhost:$HGPORT
242 $ hg -R $TESTTMP/client3_pull pull -q http://localhost:$HGPORT
219 $ grep 'lfs' $TESTTMP/client3_pull/.hg/requires $SERVER_REQUIRES || true
243 $ grep 'lfs' $TESTTMP/client3_pull/.hg/requires $SERVER_REQUIRES || true
220 $TESTTMP/client3_pull/.hg/requires:lfs (lfsremote-on !)
244 $TESTTMP/client3_pull/.hg/requires:lfs (lfsremote-on !)
221 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
245 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
222
246
223 The difference here is the push failed above when the extension isn't
247 The difference here is the push failed above when the extension isn't
224 enabled on the server.
248 enabled on the server.
225 $ hg identify http://localhost:$HGPORT
249 $ hg identify http://localhost:$HGPORT
226 8374dc4052cb (lfsremote-on !)
250 8374dc4052cb (lfsremote-on !)
227 1477875038c6 (lfsremote-off !)
251 1477875038c6 (lfsremote-off !)
228
252
229 Don't bother testing the lfsremote-off cases- the server won't be able
253 Don't bother testing the lfsremote-off cases- the server won't be able
230 to launch if there's lfs content and the extension is disabled.
254 to launch if there's lfs content and the extension is disabled.
231
255
232 #if lfsremote-on
256 #if lfsremote-on
233
257
234 --------------------------------------------------------------------------------
258 --------------------------------------------------------------------------------
235 Case #4: client with non-lfs content and the extension disabled; server with
259 Case #4: client with non-lfs content and the extension disabled; server with
236 lfs content, and the extension enabled.
260 lfs content, and the extension enabled.
237
261
238 $ cat >> $HGRCPATH <<EOF
262 $ cat >> $HGRCPATH <<EOF
239 > [extensions]
263 > [extensions]
240 > lfs = !
264 > lfs = !
241 > EOF
265 > EOF
242
266
243 $ hg init $TESTTMP/client4
267 $ hg init $TESTTMP/client4
244 $ cd $TESTTMP/client4
268 $ cd $TESTTMP/client4
245 $ cat >> .hg/hgrc <<EOF
269 $ cat >> .hg/hgrc <<EOF
246 > [paths]
270 > [paths]
247 > default = http://localhost:$HGPORT
271 > default = http://localhost:$HGPORT
248 > EOF
272 > EOF
249 $ echo 'non-lfs' > nonlfs2.txt
273 $ echo 'non-lfs' > nonlfs2.txt
250 $ hg ci -Aqm 'non-lfs'
274 $ hg ci -Aqm 'non-lfs'
251 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
275 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
252 $TESTTMP/server/.hg/requires:lfs
276 $TESTTMP/server/.hg/requires:lfs
253
277
254 $ hg push -q --force
278 $ hg push -q --force
255 warning: repository is unrelated
279 warning: repository is unrelated
256 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
280 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
257 $TESTTMP/server/.hg/requires:lfs
281 $TESTTMP/server/.hg/requires:lfs
258
282
259 TODO: fail more gracefully.
283 TODO: fail more gracefully.
260
284
261 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client4_clone
285 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client4_clone
262 abort: HTTP Error 500: Internal Server Error
286 abort: HTTP Error 500: Internal Server Error
263 [255]
287 [255]
264 $ grep 'lfs' $TESTTMP/client4_clone/.hg/requires $SERVER_REQUIRES
288 $ grep 'lfs' $TESTTMP/client4_clone/.hg/requires $SERVER_REQUIRES
265 grep: $TESTTMP/client4_clone/.hg/requires: $ENOENT$
289 grep: $TESTTMP/client4_clone/.hg/requires: $ENOENT$
266 $TESTTMP/server/.hg/requires:lfs
290 $TESTTMP/server/.hg/requires:lfs
267 [2]
291 [2]
268
292
269 TODO: fail more gracefully.
293 TODO: fail more gracefully.
270
294
271 $ hg init $TESTTMP/client4_pull
295 $ hg init $TESTTMP/client4_pull
272 $ hg -R $TESTTMP/client4_pull pull -q http://localhost:$HGPORT
296 $ hg -R $TESTTMP/client4_pull pull -q http://localhost:$HGPORT
273 abort: HTTP Error 500: Internal Server Error
297 abort: HTTP Error 500: Internal Server Error
274 [255]
298 [255]
275 $ grep 'lfs' $TESTTMP/client4_pull/.hg/requires $SERVER_REQUIRES
299 $ grep 'lfs' $TESTTMP/client4_pull/.hg/requires $SERVER_REQUIRES
276 $TESTTMP/server/.hg/requires:lfs
300 $TESTTMP/server/.hg/requires:lfs
277
301
278 $ hg identify http://localhost:$HGPORT
302 $ hg identify http://localhost:$HGPORT
279 03b080fa9d93
303 03b080fa9d93
280
304
281 --------------------------------------------------------------------------------
305 --------------------------------------------------------------------------------
282 Case #5: client with non-lfs content and the extension enabled; server with
306 Case #5: client with non-lfs content and the extension enabled; server with
283 lfs content, and the extension enabled.
307 lfs content, and the extension enabled.
284
308
285 $ cat >> $HGRCPATH <<EOF
309 $ cat >> $HGRCPATH <<EOF
286 > [extensions]
310 > [extensions]
287 > lfs =
311 > lfs =
288 > EOF
312 > EOF
289 $ echo 'non-lfs' > nonlfs3.txt
313 $ echo 'non-lfs' > nonlfs3.txt
290 $ hg ci -Aqm 'non-lfs file with lfs client'
314 $ hg ci -Aqm 'non-lfs file with lfs client'
291
315
292 $ hg push -q
316 $ hg push -q
293 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
317 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
294 $TESTTMP/server/.hg/requires:lfs
318 $TESTTMP/server/.hg/requires:lfs
295
319
296 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client5_clone
320 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client5_clone
297 $ grep 'lfs' $TESTTMP/client5_clone/.hg/requires $SERVER_REQUIRES
321 $ grep 'lfs' $TESTTMP/client5_clone/.hg/requires $SERVER_REQUIRES
298 $TESTTMP/client5_clone/.hg/requires:lfs
322 $TESTTMP/client5_clone/.hg/requires:lfs
299 $TESTTMP/server/.hg/requires:lfs
323 $TESTTMP/server/.hg/requires:lfs
300
324
301 $ hg init $TESTTMP/client5_pull
325 $ hg init $TESTTMP/client5_pull
302 $ hg -R $TESTTMP/client5_pull pull -q http://localhost:$HGPORT
326 $ hg -R $TESTTMP/client5_pull pull -q http://localhost:$HGPORT
303 $ grep 'lfs' $TESTTMP/client5_pull/.hg/requires $SERVER_REQUIRES
327 $ grep 'lfs' $TESTTMP/client5_pull/.hg/requires $SERVER_REQUIRES
304 $TESTTMP/client5_pull/.hg/requires:lfs
328 $TESTTMP/client5_pull/.hg/requires:lfs
305 $TESTTMP/server/.hg/requires:lfs
329 $TESTTMP/server/.hg/requires:lfs
306
330
307 $ hg identify http://localhost:$HGPORT
331 $ hg identify http://localhost:$HGPORT
308 c729025cc5e3
332 c729025cc5e3
309
333
334 $ mv $HGRCPATH $HGRCPATH.tmp
335 $ cp $HGRCPATH.orig $HGRCPATH
336
337 >>> from __future__ import absolute_import
338 >>> from hgclient import check, readchannel, runcommand
339 >>> @check
340 ... def checkflags(server):
341 ... readchannel(server)
342 ... print('')
343 ... print('# LFS required- both lfs and non-lfs revlogs have 0x2000 flag')
344 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
345 ... '../server'])
346 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
347 ... '../server'])
348 ... runcommand(server, ['config', 'extensions', '--cwd',
349 ... '../server'])
350 ...
351 ... print("\n# LFS not enabled- revlogs don't have 0x2000 flag")
352 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
353 ... runcommand(server, ['config', 'extensions'])
354
355 # LFS required- both lfs and non-lfs revlogs have 0x2000 flag
356 *** runcommand debugprocessors lfs.bin -R ../server
357 registered processor '0x8000'
358 registered processor '0x2000'
359 *** runcommand debugprocessors nonlfs2.txt -R ../server
360 registered processor '0x8000'
361 registered processor '0x2000'
362 *** runcommand config extensions --cwd ../server
363 extensions.debugprocessors=$TESTTMP/debugprocessors.py
364 extensions.lfs=
365
366 # LFS not enabled- revlogs don't have 0x2000 flag
367 *** runcommand debugprocessors nonlfs3.txt
368 registered processor '0x8000'
369 *** runcommand config extensions
370 extensions.debugprocessors=$TESTTMP/debugprocessors.py
371
372 $ rm $HGRCPATH
373 $ mv $HGRCPATH.tmp $HGRCPATH
374
375 $ hg clone $TESTTMP/client $TESTTMP/nonlfs -qr 0 --config extensions.lfs=
376 $ cat >> $TESTTMP/nonlfs/.hg/hgrc <<EOF
377 > [extensions]
378 > lfs = !
379 > EOF
380
381 >>> from __future__ import absolute_import, print_function
382 >>> from hgclient import check, readchannel, runcommand
383 >>> @check
384 ... def checkflags2(server):
385 ... readchannel(server)
386 ... print('')
387 ... print('# LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag')
388 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
389 ... '../server'])
390 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
391 ... '../server'])
392 ... runcommand(server, ['config', 'extensions', '--cwd',
393 ... '../server'])
394 ...
395 ... print('\n# LFS enabled without requirement- revlogs have 0x2000 flag')
396 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
397 ... runcommand(server, ['config', 'extensions'])
398 ...
399 ... print("\n# LFS disabled locally- revlogs don't have 0x2000 flag")
400 ... runcommand(server, ['debugprocessors', 'nonlfs.txt', '-R',
401 ... '../nonlfs'])
402 ... runcommand(server, ['config', 'extensions', '--cwd',
403 ... '../nonlfs'])
404
405 # LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag
406 *** runcommand debugprocessors lfs.bin -R ../server
407 registered processor '0x8000'
408 registered processor '0x2000'
409 *** runcommand debugprocessors nonlfs2.txt -R ../server
410 registered processor '0x8000'
411 registered processor '0x2000'
412 *** runcommand config extensions --cwd ../server
413 extensions.debugprocessors=$TESTTMP/debugprocessors.py
414 extensions.lfs=
415
416 # LFS enabled without requirement- revlogs have 0x2000 flag
417 *** runcommand debugprocessors nonlfs3.txt
418 registered processor '0x8000'
419 registered processor '0x2000'
420 *** runcommand config extensions
421 extensions.debugprocessors=$TESTTMP/debugprocessors.py
422 extensions.lfs=
423
424 # LFS disabled locally- revlogs don't have 0x2000 flag
425 *** runcommand debugprocessors nonlfs.txt -R ../nonlfs
426 registered processor '0x8000'
427 *** runcommand config extensions --cwd ../nonlfs
428 extensions.debugprocessors=$TESTTMP/debugprocessors.py
429 extensions.lfs=!
430
310 --------------------------------------------------------------------------------
431 --------------------------------------------------------------------------------
311 Case #6: client with lfs content and the extension enabled; server with
432 Case #6: client with lfs content and the extension enabled; server with
312 lfs content, and the extension enabled.
433 lfs content, and the extension enabled.
313
434
314 $ echo 'this is another lfs file' > lfs2.txt
435 $ echo 'this is another lfs file' > lfs2.txt
315 $ hg ci -Aqm 'lfs file with lfs client'
436 $ hg ci -Aqm 'lfs file with lfs client'
316
437
317 $ hg --config paths.default= push -v http://localhost:$HGPORT
438 $ hg --config paths.default= push -v http://localhost:$HGPORT
318 pushing to http://localhost:$HGPORT/
439 pushing to http://localhost:$HGPORT/
319 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
440 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
320 searching for changes
441 searching for changes
321 remote has heads on branch 'default' that are not known locally: 8374dc4052cb
442 remote has heads on branch 'default' that are not known locally: 8374dc4052cb
322 lfs: uploading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
443 lfs: uploading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
323 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
444 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
324 lfs: uploaded 1 files (25 bytes)
445 lfs: uploaded 1 files (25 bytes)
325 1 changesets found
446 1 changesets found
326 uncompressed size of bundle content:
447 uncompressed size of bundle content:
327 206 (changelog)
448 206 (changelog)
328 172 (manifests)
449 172 (manifests)
329 275 lfs2.txt
450 275 lfs2.txt
330 remote: adding changesets
451 remote: adding changesets
331 remote: adding manifests
452 remote: adding manifests
332 remote: adding file changes
453 remote: adding file changes
333 remote: added 1 changesets with 1 changes to 1 files
454 remote: added 1 changesets with 1 changes to 1 files
334 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
455 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
335 .hg/requires:lfs
456 .hg/requires:lfs
336 $TESTTMP/server/.hg/requires:lfs
457 $TESTTMP/server/.hg/requires:lfs
337
458
338 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client6_clone
459 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client6_clone
339 $ grep 'lfs' $TESTTMP/client6_clone/.hg/requires $SERVER_REQUIRES
460 $ grep 'lfs' $TESTTMP/client6_clone/.hg/requires $SERVER_REQUIRES
340 $TESTTMP/client6_clone/.hg/requires:lfs
461 $TESTTMP/client6_clone/.hg/requires:lfs
341 $TESTTMP/server/.hg/requires:lfs
462 $TESTTMP/server/.hg/requires:lfs
342
463
343 $ hg init $TESTTMP/client6_pull
464 $ hg init $TESTTMP/client6_pull
344 $ hg -R $TESTTMP/client6_pull pull -u -v http://localhost:$HGPORT
465 $ hg -R $TESTTMP/client6_pull pull -u -v http://localhost:$HGPORT
345 pulling from http://localhost:$HGPORT/
466 pulling from http://localhost:$HGPORT/
346 requesting all changes
467 requesting all changes
347 adding changesets
468 adding changesets
348 adding manifests
469 adding manifests
349 adding file changes
470 adding file changes
350 added 6 changesets with 5 changes to 5 files (+1 heads)
471 added 6 changesets with 5 changes to 5 files (+1 heads)
351 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
472 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
352 new changesets d437e1d24fbd:d3b84d50eacb
473 new changesets d437e1d24fbd:d3b84d50eacb
353 resolving manifests
474 resolving manifests
354 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
475 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
355 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
476 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
356 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
477 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
357 lfs: downloaded 1 files (25 bytes)
478 lfs: downloaded 1 files (25 bytes)
358 getting lfs2.txt
479 getting lfs2.txt
359 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
480 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
360 getting nonlfs2.txt
481 getting nonlfs2.txt
361 getting nonlfs3.txt
482 getting nonlfs3.txt
362 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 updated to "d3b84d50eacb: lfs file with lfs client"
484 updated to "d3b84d50eacb: lfs file with lfs client"
364 1 other heads for branch "default"
485 1 other heads for branch "default"
365 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
486 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
366 $ grep 'lfs' $TESTTMP/client6_pull/.hg/requires $SERVER_REQUIRES
487 $ grep 'lfs' $TESTTMP/client6_pull/.hg/requires $SERVER_REQUIRES
367 $TESTTMP/client6_pull/.hg/requires:lfs
488 $TESTTMP/client6_pull/.hg/requires:lfs
368 $TESTTMP/server/.hg/requires:lfs
489 $TESTTMP/server/.hg/requires:lfs
369
490
370 $ hg identify http://localhost:$HGPORT
491 $ hg identify http://localhost:$HGPORT
371 d3b84d50eacb
492 d3b84d50eacb
372
493
373 --------------------------------------------------------------------------------
494 --------------------------------------------------------------------------------
374 Misc: process dies early if a requirement exists and the extension is disabled
495 Misc: process dies early if a requirement exists and the extension is disabled
375
496
376 $ hg --config extensions.lfs=! summary
497 $ hg --config extensions.lfs=! summary
377 abort: repository requires features unknown to this Mercurial: lfs!
498 abort: repository requires features unknown to this Mercurial: lfs!
378 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
499 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
379 [255]
500 [255]
380
501
381 $ echo 'this is an lfs file' > $TESTTMP/client6_clone/lfspair1.bin
502 $ echo 'this is an lfs file' > $TESTTMP/client6_clone/lfspair1.bin
382 $ echo 'this is an lfs file too' > $TESTTMP/client6_clone/lfspair2.bin
503 $ echo 'this is an lfs file too' > $TESTTMP/client6_clone/lfspair2.bin
383 $ hg -R $TESTTMP/client6_clone ci -Aqm 'add lfs pair'
504 $ hg -R $TESTTMP/client6_clone ci -Aqm 'add lfs pair'
384 $ hg -R $TESTTMP/client6_clone push -q
505 $ hg -R $TESTTMP/client6_clone push -q
385
506
386 $ hg clone -qU http://localhost:$HGPORT $TESTTMP/bulkfetch
507 $ hg clone -qU http://localhost:$HGPORT $TESTTMP/bulkfetch
387
508
388 Export will prefetch all needed files across all needed revisions
509 Export will prefetch all needed files across all needed revisions
389
510
390 $ hg -R $TESTTMP/bulkfetch -v export -r 0:tip -o all.export
511 $ hg -R $TESTTMP/bulkfetch -v export -r 0:tip -o all.export
391 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
512 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
392 exporting patches:
513 exporting patches:
393 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
514 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
394 lfs: need to transfer 4 objects (92 bytes)
515 lfs: need to transfer 4 objects (92 bytes)
395 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
516 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
396 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
517 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
397 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
518 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
398 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
519 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
399 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
520 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
400 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
521 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
401 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
522 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
402 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
523 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
403 lfs: downloaded 4 files (92 bytes)
524 lfs: downloaded 4 files (92 bytes)
404 all.export
525 all.export
405 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
526 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
406 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
527 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
407 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
528 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
408 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
529 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
409
530
410 Export with selected files is used with `extdiff --patch`
531 Export with selected files is used with `extdiff --patch`
411
532
412 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
533 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
413 $ hg --config extensions.extdiff= \
534 $ hg --config extensions.extdiff= \
414 > -R $TESTTMP/bulkfetch -v extdiff -r 2:tip --patch $TESTTMP/bulkfetch/lfs.bin
535 > -R $TESTTMP/bulkfetch -v extdiff -r 2:tip --patch $TESTTMP/bulkfetch/lfs.bin
415 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
536 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
416 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
537 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
417 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
538 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
418 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
539 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
419 lfs: downloaded 1 files (23 bytes)
540 lfs: downloaded 1 files (23 bytes)
420 */hg-8374dc4052cb.patch (glob)
541 */hg-8374dc4052cb.patch (glob)
421 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
542 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
422 */hg-9640b57e77b1.patch (glob)
543 */hg-9640b57e77b1.patch (glob)
423 --- */hg-8374dc4052cb.patch * (glob)
544 --- */hg-8374dc4052cb.patch * (glob)
424 +++ */hg-9640b57e77b1.patch * (glob)
545 +++ */hg-9640b57e77b1.patch * (glob)
425 @@ -2,12 +2,7 @@
546 @@ -2,12 +2,7 @@
426 # User test
547 # User test
427 # Date 0 0
548 # Date 0 0
428 # Thu Jan 01 00:00:00 1970 +0000
549 # Thu Jan 01 00:00:00 1970 +0000
429 -# Node ID 8374dc4052cbd388e79d9dc4ddb29784097aa354
550 -# Node ID 8374dc4052cbd388e79d9dc4ddb29784097aa354
430 -# Parent 1477875038c60152e391238920a16381c627b487
551 -# Parent 1477875038c60152e391238920a16381c627b487
431 -lfs
552 -lfs
432 +# Node ID 9640b57e77b14c3a0144fb4478b6cc13e13ea0d1
553 +# Node ID 9640b57e77b14c3a0144fb4478b6cc13e13ea0d1
433 +# Parent d3b84d50eacbd56638e11abce6b8616aaba54420
554 +# Parent d3b84d50eacbd56638e11abce6b8616aaba54420
434 +add lfs pair
555 +add lfs pair
435
556
436 -diff -r 1477875038c6 -r 8374dc4052cb lfs.bin
557 -diff -r 1477875038c6 -r 8374dc4052cb lfs.bin
437 ---- /dev/null Thu Jan 01 00:00:00 1970 +0000
558 ---- /dev/null Thu Jan 01 00:00:00 1970 +0000
438 -+++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
559 -+++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
439 -@@ -0,0 +1,1 @@
560 -@@ -0,0 +1,1 @@
440 -+this is a big lfs file
561 -+this is a big lfs file
441 cleaning up temp directory
562 cleaning up temp directory
442 [1]
563 [1]
443
564
444 Diff will prefetch files
565 Diff will prefetch files
445
566
446 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
567 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
447 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip
568 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip
448 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
569 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
449 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
570 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
450 lfs: need to transfer 4 objects (92 bytes)
571 lfs: need to transfer 4 objects (92 bytes)
451 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
572 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
452 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
573 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
453 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
574 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
454 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
575 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
455 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
576 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
456 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
577 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
457 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
578 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
458 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
579 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
459 lfs: downloaded 4 files (92 bytes)
580 lfs: downloaded 4 files (92 bytes)
460 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
581 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
461 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
582 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
462 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
583 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
463 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
584 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
464 diff -r 8374dc4052cb -r 9640b57e77b1 lfs.bin
585 diff -r 8374dc4052cb -r 9640b57e77b1 lfs.bin
465 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
586 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
466 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
587 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
467 @@ -1,1 +0,0 @@
588 @@ -1,1 +0,0 @@
468 -this is a big lfs file
589 -this is a big lfs file
469 diff -r 8374dc4052cb -r 9640b57e77b1 lfs2.txt
590 diff -r 8374dc4052cb -r 9640b57e77b1 lfs2.txt
470 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
591 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
471 +++ b/lfs2.txt Thu Jan 01 00:00:00 1970 +0000
592 +++ b/lfs2.txt Thu Jan 01 00:00:00 1970 +0000
472 @@ -0,0 +1,1 @@
593 @@ -0,0 +1,1 @@
473 +this is another lfs file
594 +this is another lfs file
474 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair1.bin
595 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair1.bin
475 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
596 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
476 +++ b/lfspair1.bin Thu Jan 01 00:00:00 1970 +0000
597 +++ b/lfspair1.bin Thu Jan 01 00:00:00 1970 +0000
477 @@ -0,0 +1,1 @@
598 @@ -0,0 +1,1 @@
478 +this is an lfs file
599 +this is an lfs file
479 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
600 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
480 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
601 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
481 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
602 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
482 @@ -0,0 +1,1 @@
603 @@ -0,0 +1,1 @@
483 +this is an lfs file too
604 +this is an lfs file too
484 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs.txt
605 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs.txt
485 --- a/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
606 --- a/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
486 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
607 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
487 @@ -1,1 +0,0 @@
608 @@ -1,1 +0,0 @@
488 -non-lfs
609 -non-lfs
489 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs3.txt
610 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs3.txt
490 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
611 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
491 +++ b/nonlfs3.txt Thu Jan 01 00:00:00 1970 +0000
612 +++ b/nonlfs3.txt Thu Jan 01 00:00:00 1970 +0000
492 @@ -0,0 +1,1 @@
613 @@ -0,0 +1,1 @@
493 +non-lfs
614 +non-lfs
494
615
495 Only the files required by diff are prefetched
616 Only the files required by diff are prefetched
496
617
497 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
618 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
498 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip $TESTTMP/bulkfetch/lfspair2.bin
619 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip $TESTTMP/bulkfetch/lfspair2.bin
499 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
620 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
500 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
621 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
501 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
622 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
502 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
623 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
503 lfs: downloaded 1 files (24 bytes)
624 lfs: downloaded 1 files (24 bytes)
504 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
625 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
505 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
626 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
506 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
627 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
507 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
628 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
508 @@ -0,0 +1,1 @@
629 @@ -0,0 +1,1 @@
509 +this is an lfs file too
630 +this is an lfs file too
510
631
511 #endif
632 #endif
512
633
513 $ "$PYTHON" $TESTDIR/killdaemons.py $DAEMON_PIDS
634 $ "$PYTHON" $TESTDIR/killdaemons.py $DAEMON_PIDS
514
635
515 #if lfsremote-on
636 #if lfsremote-on
516 $ cat $TESTTMP/errors.log | grep '^[A-Z]'
637 $ cat $TESTTMP/errors.log | grep '^[A-Z]'
517 Traceback (most recent call last):
638 Traceback (most recent call last):
518 ValueError: no common changegroup version
639 ValueError: no common changegroup version
519 Traceback (most recent call last):
640 Traceback (most recent call last):
520 ValueError: no common changegroup version
641 ValueError: no common changegroup version
521 #else
642 #else
522 $ cat $TESTTMP/errors.log
643 $ cat $TESTTMP/errors.log
523 #endif
644 #endif
General Comments 0
You need to be logged in to leave comments. Login now