##// END OF EJS Templates
merge with stable
Augie Fackler -
r40349:ef0baff1 merge default
parent child Browse files
Show More
@@ -1,416 +1,418 b''
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
127 import sys
128
128
129 from mercurial.i18n import _
129 from mercurial.i18n import _
130
130
131 from mercurial import (
131 from mercurial import (
132 bundle2,
132 bundle2,
133 changegroup,
133 changegroup,
134 cmdutil,
134 cmdutil,
135 config,
135 config,
136 context,
136 context,
137 error,
137 error,
138 exchange,
138 exchange,
139 extensions,
139 extensions,
140 filelog,
140 filelog,
141 filesetlang,
141 filesetlang,
142 localrepo,
142 localrepo,
143 minifileset,
143 minifileset,
144 node,
144 node,
145 pycompat,
145 pycompat,
146 registrar,
146 registrar,
147 repository,
147 repository,
148 revlog,
148 revlog,
149 scmutil,
149 scmutil,
150 templateutil,
150 templateutil,
151 upgrade,
151 upgrade,
152 util,
152 util,
153 vfs as vfsmod,
153 vfs as vfsmod,
154 wireprotoserver,
154 wireprotoserver,
155 wireprotov1server,
155 wireprotov1server,
156 )
156 )
157
157
158 from . import (
158 from . import (
159 blobstore,
159 blobstore,
160 wireprotolfsserver,
160 wireprotolfsserver,
161 wrapper,
161 wrapper,
162 )
162 )
163
163
164 # 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
165 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
165 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
166 # 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
167 # leave the attribute unspecified.
167 # leave the attribute unspecified.
168 testedwith = 'ships-with-hg-core'
168 testedwith = 'ships-with-hg-core'
169
169
170 configtable = {}
170 configtable = {}
171 configitem = registrar.configitem(configtable)
171 configitem = registrar.configitem(configtable)
172
172
173 configitem('experimental', 'lfs.serve',
173 configitem('experimental', 'lfs.serve',
174 default=True,
174 default=True,
175 )
175 )
176 configitem('experimental', 'lfs.user-agent',
176 configitem('experimental', 'lfs.user-agent',
177 default=None,
177 default=None,
178 )
178 )
179 configitem('experimental', 'lfs.disableusercache',
179 configitem('experimental', 'lfs.disableusercache',
180 default=False,
180 default=False,
181 )
181 )
182 configitem('experimental', 'lfs.worker-enable',
182 configitem('experimental', 'lfs.worker-enable',
183 default=False,
183 default=False,
184 )
184 )
185
185
186 configitem('lfs', 'url',
186 configitem('lfs', 'url',
187 default=None,
187 default=None,
188 )
188 )
189 configitem('lfs', 'usercache',
189 configitem('lfs', 'usercache',
190 default=None,
190 default=None,
191 )
191 )
192 # Deprecated
192 # Deprecated
193 configitem('lfs', 'threshold',
193 configitem('lfs', 'threshold',
194 default=None,
194 default=None,
195 )
195 )
196 configitem('lfs', 'track',
196 configitem('lfs', 'track',
197 default='none()',
197 default='none()',
198 )
198 )
199 configitem('lfs', 'retry',
199 configitem('lfs', 'retry',
200 default=5,
200 default=5,
201 )
201 )
202
202
203 cmdtable = {}
203 cmdtable = {}
204 command = registrar.command(cmdtable)
204 command = registrar.command(cmdtable)
205
205
206 templatekeyword = registrar.templatekeyword()
206 templatekeyword = registrar.templatekeyword()
207 filesetpredicate = registrar.filesetpredicate()
207 filesetpredicate = registrar.filesetpredicate()
208
208
209 lfsprocessor = (
209 lfsprocessor = (
210 wrapper.readfromstore,
210 wrapper.readfromstore,
211 wrapper.writetostore,
211 wrapper.writetostore,
212 wrapper.bypasscheckhash,
212 wrapper.bypasscheckhash,
213 )
213 )
214
214
215 def featuresetup(ui, supported):
215 def featuresetup(ui, supported):
216 # don't die on seeing a repo with the lfs requirement
216 # don't die on seeing a repo with the lfs requirement
217 supported |= {'lfs'}
217 supported |= {'lfs'}
218
218
219 def uisetup(ui):
219 def uisetup(ui):
220 localrepo.featuresetupfuncs.add(featuresetup)
220 localrepo.featuresetupfuncs.add(featuresetup)
221
221
222 def reposetup(ui, repo):
222 def reposetup(ui, repo):
223 # Nothing to do with a remote repo
223 # Nothing to do with a remote repo
224 if not repo.local():
224 if not repo.local():
225 return
225 return
226
226
227 repo.svfs.lfslocalblobstore = blobstore.local(repo)
227 repo.svfs.lfslocalblobstore = blobstore.local(repo)
228 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
228 repo.svfs.lfsremoteblobstore = blobstore.remote(repo)
229
229
230 class lfsrepo(repo.__class__):
230 class lfsrepo(repo.__class__):
231 @localrepo.unfilteredmethod
231 @localrepo.unfilteredmethod
232 def commitctx(self, ctx, error=False):
232 def commitctx(self, ctx, error=False):
233 repo.svfs.options['lfstrack'] = _trackedmatcher(self)
233 repo.svfs.options['lfstrack'] = _trackedmatcher(self)
234 return super(lfsrepo, self).commitctx(ctx, error)
234 return super(lfsrepo, self).commitctx(ctx, error)
235
235
236 repo.__class__ = lfsrepo
236 repo.__class__ = lfsrepo
237
237
238 if 'lfs' not in repo.requirements:
238 if 'lfs' not in repo.requirements:
239 def checkrequireslfs(ui, repo, **kwargs):
239 def checkrequireslfs(ui, repo, **kwargs):
240 if 'lfs' not in repo.requirements:
240 if 'lfs' in repo.requirements:
241 last = kwargs.get(r'node_last')
241 return 0
242 _bin = node.bin
242
243 if last:
243 last = kwargs.get(r'node_last')
244 s = repo.set('%n:%n', _bin(kwargs[r'node']), _bin(last))
244 _bin = node.bin
245 else:
245 if last:
246 s = repo.set('%n', _bin(kwargs[r'node']))
246 s = repo.set('%n:%n', _bin(kwargs[r'node']), _bin(last))
247 else:
248 s = repo.set('%n', _bin(kwargs[r'node']))
247 match = repo.narrowmatch()
249 match = repo.narrowmatch()
248 for ctx in s:
250 for ctx in s:
249 # TODO: is there a way to just walk the files in the commit?
251 # TODO: is there a way to just walk the files in the commit?
250 if any(ctx[f].islfs() for f in ctx.files()
252 if any(ctx[f].islfs() for f in ctx.files()
251 if f in ctx and match(f)):
253 if f in ctx and match(f)):
252 repo.requirements.add('lfs')
254 repo.requirements.add('lfs')
253 repo.features.add(repository.REPO_FEATURE_LFS)
255 repo.features.add(repository.REPO_FEATURE_LFS)
254 repo._writerequirements()
256 repo._writerequirements()
255 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
257 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
256 break
258 break
257
259
258 ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
260 ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
259 ui.setconfig('hooks', 'pretxnchangegroup.lfs', checkrequireslfs, 'lfs')
261 ui.setconfig('hooks', 'pretxnchangegroup.lfs', checkrequireslfs, 'lfs')
260 else:
262 else:
261 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
263 repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
262
264
263 def _trackedmatcher(repo):
265 def _trackedmatcher(repo):
264 """Return a function (path, size) -> bool indicating whether or not to
266 """Return a function (path, size) -> bool indicating whether or not to
265 track a given file with lfs."""
267 track a given file with lfs."""
266 if not repo.wvfs.exists('.hglfs'):
268 if not repo.wvfs.exists('.hglfs'):
267 # No '.hglfs' in wdir. Fallback to config for now.
269 # No '.hglfs' in wdir. Fallback to config for now.
268 trackspec = repo.ui.config('lfs', 'track')
270 trackspec = repo.ui.config('lfs', 'track')
269
271
270 # deprecated config: lfs.threshold
272 # deprecated config: lfs.threshold
271 threshold = repo.ui.configbytes('lfs', 'threshold')
273 threshold = repo.ui.configbytes('lfs', 'threshold')
272 if threshold:
274 if threshold:
273 filesetlang.parse(trackspec) # make sure syntax errors are confined
275 filesetlang.parse(trackspec) # make sure syntax errors are confined
274 trackspec = "(%s) | size('>%d')" % (trackspec, threshold)
276 trackspec = "(%s) | size('>%d')" % (trackspec, threshold)
275
277
276 return minifileset.compile(trackspec)
278 return minifileset.compile(trackspec)
277
279
278 data = repo.wvfs.tryread('.hglfs')
280 data = repo.wvfs.tryread('.hglfs')
279 if not data:
281 if not data:
280 return lambda p, s: False
282 return lambda p, s: False
281
283
282 # Parse errors here will abort with a message that points to the .hglfs file
284 # Parse errors here will abort with a message that points to the .hglfs file
283 # and line number.
285 # and line number.
284 cfg = config.config()
286 cfg = config.config()
285 cfg.parse('.hglfs', data)
287 cfg.parse('.hglfs', data)
286
288
287 try:
289 try:
288 rules = [(minifileset.compile(pattern), minifileset.compile(rule))
290 rules = [(minifileset.compile(pattern), minifileset.compile(rule))
289 for pattern, rule in cfg.items('track')]
291 for pattern, rule in cfg.items('track')]
290 except error.ParseError as e:
292 except error.ParseError as e:
291 # The original exception gives no indicator that the error is in the
293 # The original exception gives no indicator that the error is in the
292 # .hglfs file, so add that.
294 # .hglfs file, so add that.
293
295
294 # TODO: See if the line number of the file can be made available.
296 # TODO: See if the line number of the file can be made available.
295 raise error.Abort(_('parse error in .hglfs: %s') % e)
297 raise error.Abort(_('parse error in .hglfs: %s') % e)
296
298
297 def _match(path, size):
299 def _match(path, size):
298 for pat, rule in rules:
300 for pat, rule in rules:
299 if pat(path, size):
301 if pat(path, size):
300 return rule(path, size)
302 return rule(path, size)
301
303
302 return False
304 return False
303
305
304 return _match
306 return _match
305
307
306 def wrapfilelog(filelog):
308 def wrapfilelog(filelog):
307 wrapfunction = extensions.wrapfunction
309 wrapfunction = extensions.wrapfunction
308
310
309 wrapfunction(filelog, 'addrevision', wrapper.filelogaddrevision)
311 wrapfunction(filelog, 'addrevision', wrapper.filelogaddrevision)
310 wrapfunction(filelog, 'renamed', wrapper.filelogrenamed)
312 wrapfunction(filelog, 'renamed', wrapper.filelogrenamed)
311 wrapfunction(filelog, 'size', wrapper.filelogsize)
313 wrapfunction(filelog, 'size', wrapper.filelogsize)
312
314
313 def _resolverevlogstorevfsoptions(orig, ui, requirements, features):
315 def _resolverevlogstorevfsoptions(orig, ui, requirements, features):
314 opts = orig(ui, requirements, features)
316 opts = orig(ui, requirements, features)
315 for name, module in extensions.extensions(ui):
317 for name, module in extensions.extensions(ui):
316 if module is sys.modules[__name__]:
318 if module is sys.modules[__name__]:
317 if revlog.REVIDX_EXTSTORED in opts[b'flagprocessors']:
319 if revlog.REVIDX_EXTSTORED in opts[b'flagprocessors']:
318 msg = (_(b"cannot register multiple processors on flag '%#x'.")
320 msg = (_(b"cannot register multiple processors on flag '%#x'.")
319 % revlog.REVIDX_EXTSTORED)
321 % revlog.REVIDX_EXTSTORED)
320 raise error.Abort(msg)
322 raise error.Abort(msg)
321
323
322 opts[b'flagprocessors'][revlog.REVIDX_EXTSTORED] = lfsprocessor
324 opts[b'flagprocessors'][revlog.REVIDX_EXTSTORED] = lfsprocessor
323 break
325 break
324
326
325 return opts
327 return opts
326
328
327 def extsetup(ui):
329 def extsetup(ui):
328 wrapfilelog(filelog.filelog)
330 wrapfilelog(filelog.filelog)
329
331
330 wrapfunction = extensions.wrapfunction
332 wrapfunction = extensions.wrapfunction
331
333
332 wrapfunction(localrepo, 'makefilestorage', wrapper.localrepomakefilestorage)
334 wrapfunction(localrepo, 'makefilestorage', wrapper.localrepomakefilestorage)
333 wrapfunction(localrepo, 'resolverevlogstorevfsoptions',
335 wrapfunction(localrepo, 'resolverevlogstorevfsoptions',
334 _resolverevlogstorevfsoptions)
336 _resolverevlogstorevfsoptions)
335
337
336 wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter)
338 wrapfunction(cmdutil, '_updatecatformatter', wrapper._updatecatformatter)
337 wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink)
339 wrapfunction(scmutil, 'wrapconvertsink', wrapper.convertsink)
338
340
339 wrapfunction(upgrade, '_finishdatamigration',
341 wrapfunction(upgrade, '_finishdatamigration',
340 wrapper.upgradefinishdatamigration)
342 wrapper.upgradefinishdatamigration)
341
343
342 wrapfunction(upgrade, 'preservedrequirements',
344 wrapfunction(upgrade, 'preservedrequirements',
343 wrapper.upgraderequirements)
345 wrapper.upgraderequirements)
344
346
345 wrapfunction(upgrade, 'supporteddestrequirements',
347 wrapfunction(upgrade, 'supporteddestrequirements',
346 wrapper.upgraderequirements)
348 wrapper.upgraderequirements)
347
349
348 wrapfunction(changegroup,
350 wrapfunction(changegroup,
349 'allsupportedversions',
351 'allsupportedversions',
350 wrapper.allsupportedversions)
352 wrapper.allsupportedversions)
351
353
352 wrapfunction(exchange, 'push', wrapper.push)
354 wrapfunction(exchange, 'push', wrapper.push)
353 wrapfunction(wireprotov1server, '_capabilities', wrapper._capabilities)
355 wrapfunction(wireprotov1server, '_capabilities', wrapper._capabilities)
354 wrapfunction(wireprotoserver, 'handlewsgirequest',
356 wrapfunction(wireprotoserver, 'handlewsgirequest',
355 wireprotolfsserver.handlewsgirequest)
357 wireprotolfsserver.handlewsgirequest)
356
358
357 wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp)
359 wrapfunction(context.basefilectx, 'cmp', wrapper.filectxcmp)
358 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
360 wrapfunction(context.basefilectx, 'isbinary', wrapper.filectxisbinary)
359 context.basefilectx.islfs = wrapper.filectxislfs
361 context.basefilectx.islfs = wrapper.filectxislfs
360
362
361 scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles)
363 scmutil.fileprefetchhooks.add('lfs', wrapper._prefetchfiles)
362
364
363 # Make bundle choose changegroup3 instead of changegroup2. This affects
365 # Make bundle choose changegroup3 instead of changegroup2. This affects
364 # "hg bundle" command. Note: it does not cover all bundle formats like
366 # "hg bundle" command. Note: it does not cover all bundle formats like
365 # "packed1". Using "packed1" with lfs will likely cause trouble.
367 # "packed1". Using "packed1" with lfs will likely cause trouble.
366 exchange._bundlespeccontentopts["v2"]["cg.version"] = "03"
368 exchange._bundlespeccontentopts["v2"]["cg.version"] = "03"
367
369
368 # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
370 # bundlerepo uses "vfsmod.readonlyvfs(othervfs)", we need to make sure lfs
369 # options and blob stores are passed from othervfs to the new readonlyvfs.
371 # options and blob stores are passed from othervfs to the new readonlyvfs.
370 wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit)
372 wrapfunction(vfsmod.readonlyvfs, '__init__', wrapper.vfsinit)
371
373
372 # when writing a bundle via "hg bundle" command, upload related LFS blobs
374 # when writing a bundle via "hg bundle" command, upload related LFS blobs
373 wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle)
375 wrapfunction(bundle2, 'writenewbundle', wrapper.writenewbundle)
374
376
375 @filesetpredicate('lfs()')
377 @filesetpredicate('lfs()')
376 def lfsfileset(mctx, x):
378 def lfsfileset(mctx, x):
377 """File that uses LFS storage."""
379 """File that uses LFS storage."""
378 # i18n: "lfs" is a keyword
380 # i18n: "lfs" is a keyword
379 filesetlang.getargs(x, 0, 0, _("lfs takes no arguments"))
381 filesetlang.getargs(x, 0, 0, _("lfs takes no arguments"))
380 ctx = mctx.ctx
382 ctx = mctx.ctx
381 def lfsfilep(f):
383 def lfsfilep(f):
382 return wrapper.pointerfromctx(ctx, f, removed=True) is not None
384 return wrapper.pointerfromctx(ctx, f, removed=True) is not None
383 return mctx.predicate(lfsfilep, predrepr='<lfs>')
385 return mctx.predicate(lfsfilep, predrepr='<lfs>')
384
386
385 @templatekeyword('lfs_files', requires={'ctx'})
387 @templatekeyword('lfs_files', requires={'ctx'})
386 def lfsfiles(context, mapping):
388 def lfsfiles(context, mapping):
387 """List of strings. All files modified, added, or removed by this
389 """List of strings. All files modified, added, or removed by this
388 changeset."""
390 changeset."""
389 ctx = context.resource(mapping, 'ctx')
391 ctx = context.resource(mapping, 'ctx')
390
392
391 pointers = wrapper.pointersfromctx(ctx, removed=True) # {path: pointer}
393 pointers = wrapper.pointersfromctx(ctx, removed=True) # {path: pointer}
392 files = sorted(pointers.keys())
394 files = sorted(pointers.keys())
393
395
394 def pointer(v):
396 def pointer(v):
395 # In the file spec, version is first and the other keys are sorted.
397 # In the file spec, version is first and the other keys are sorted.
396 sortkeyfunc = lambda x: (x[0] != 'version', x)
398 sortkeyfunc = lambda x: (x[0] != 'version', x)
397 items = sorted(pointers[v].iteritems(), key=sortkeyfunc)
399 items = sorted(pointers[v].iteritems(), key=sortkeyfunc)
398 return util.sortdict(items)
400 return util.sortdict(items)
399
401
400 makemap = lambda v: {
402 makemap = lambda v: {
401 'file': v,
403 'file': v,
402 'lfsoid': pointers[v].oid() if pointers[v] else None,
404 'lfsoid': pointers[v].oid() if pointers[v] else None,
403 'lfspointer': templateutil.hybriddict(pointer(v)),
405 'lfspointer': templateutil.hybriddict(pointer(v)),
404 }
406 }
405
407
406 # TODO: make the separator ', '?
408 # TODO: make the separator ', '?
407 f = templateutil._showcompatlist(context, mapping, 'lfs_file', files)
409 f = templateutil._showcompatlist(context, mapping, 'lfs_file', files)
408 return templateutil.hybrid(f, files, makemap, pycompat.identity)
410 return templateutil.hybrid(f, files, makemap, pycompat.identity)
409
411
410 @command('debuglfsupload',
412 @command('debuglfsupload',
411 [('r', 'rev', [], _('upload large files introduced by REV'))])
413 [('r', 'rev', [], _('upload large files introduced by REV'))])
412 def debuglfsupload(ui, repo, **opts):
414 def debuglfsupload(ui, repo, **opts):
413 """upload lfs blobs added by the working copy parent or given revisions"""
415 """upload lfs blobs added by the working copy parent or given revisions"""
414 revs = opts.get(r'rev', [])
416 revs = opts.get(r'rev', [])
415 pointers = wrapper.extractpointers(repo, scmutil.revrange(repo, revs))
417 pointers = wrapper.extractpointers(repo, scmutil.revrange(repo, revs))
416 wrapper.uploadblobs(repo, pointers)
418 wrapper.uploadblobs(repo, pointers)
@@ -1,644 +1,668 b''
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
38 $ cat > $TESTTMP/debugprocessors.py <<EOF
39 > from mercurial import (
39 > from mercurial import (
40 > cmdutil,
40 > cmdutil,
41 > commands,
41 > commands,
42 > pycompat,
42 > pycompat,
43 > registrar,
43 > registrar,
44 > )
44 > )
45 > cmdtable = {}
45 > cmdtable = {}
46 > command = registrar.command(cmdtable)
46 > command = registrar.command(cmdtable)
47 > @command(b'debugprocessors', [], b'FILE')
47 > @command(b'debugprocessors', [], b'FILE')
48 > def debugprocessors(ui, repo, file_=None, **opts):
48 > def debugprocessors(ui, repo, file_=None, **opts):
49 > opts = pycompat.byteskwargs(opts)
49 > opts = pycompat.byteskwargs(opts)
50 > opts[b'changelog'] = False
50 > opts[b'changelog'] = False
51 > opts[b'manifest'] = False
51 > opts[b'manifest'] = False
52 > opts[b'dir'] = False
52 > opts[b'dir'] = False
53 > rl = cmdutil.openrevlog(repo, b'debugprocessors', file_, opts)
53 > rl = cmdutil.openrevlog(repo, b'debugprocessors', file_, opts)
54 > for flag, proc in rl._flagprocessors.iteritems():
54 > for flag, proc in rl._flagprocessors.iteritems():
55 > ui.status(b"registered processor '%#x'\n" % (flag))
55 > ui.status(b"registered processor '%#x'\n" % (flag))
56 > EOF
56 > EOF
57
57
58 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
59 first, and causes a "ValueError: no common changegroup version" or "abort:
59 first, and causes a "ValueError: no common changegroup version" or "abort:
60 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
61 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
62 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
63 masked by the Internal Server Error message).
63 masked by the Internal Server Error message).
64 $ cat >> $HGRCPATH <<EOF
64 $ cat >> $HGRCPATH <<EOF
65 > [extensions]
65 > [extensions]
66 > debugprocessors = $TESTTMP/debugprocessors.py
66 > debugprocessors = $TESTTMP/debugprocessors.py
67 > [experimental]
67 > [experimental]
68 > lfs.disableusercache = True
68 > lfs.disableusercache = True
69 > [lfs]
69 > [lfs]
70 > threshold=10
70 > threshold=10
71 > [web]
71 > [web]
72 > allow_push=*
72 > allow_push=*
73 > push_ssl=False
73 > push_ssl=False
74 > EOF
74 > EOF
75
75
76 $ cp $HGRCPATH $HGRCPATH.orig
76 $ cp $HGRCPATH $HGRCPATH.orig
77
77
78 #if lfsremote-on
78 #if lfsremote-on
79 $ hg --config extensions.lfs= -R server \
79 $ hg --config extensions.lfs= -R server \
80 > 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
81 #else
81 #else
82 $ hg --config extensions.lfs=! -R server \
82 $ hg --config extensions.lfs=! -R server \
83 > 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
84 #endif
84 #endif
85
85
86 $ cat hg.pid >> $DAEMON_PIDS
86 $ cat hg.pid >> $DAEMON_PIDS
87 $ hg clone -q http://localhost:$HGPORT client
87 $ hg clone -q http://localhost:$HGPORT client
88 $ grep 'lfs' client/.hg/requires $SERVER_REQUIRES
88 $ grep 'lfs' client/.hg/requires $SERVER_REQUIRES
89 [1]
89 [1]
90
90
91 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
92 reposetup() on another repo actually being operated on. This gives coverage
92 reposetup() on another repo actually being operated on. This gives coverage
93 that wrapper functions are not assuming reposetup() was called.
93 that wrapper functions are not assuming reposetup() was called.
94
94
95 $ hg init $TESTTMP/cmdservelfs
95 $ hg init $TESTTMP/cmdservelfs
96 $ cat >> $TESTTMP/cmdservelfs/.hg/hgrc << EOF
96 $ cat >> $TESTTMP/cmdservelfs/.hg/hgrc << EOF
97 > [extensions]
97 > [extensions]
98 > lfs =
98 > lfs =
99 > EOF
99 > EOF
100
100
101 --------------------------------------------------------------------------------
101 --------------------------------------------------------------------------------
102 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
103 non-lfs content, and the extension enabled.
103 non-lfs content, and the extension enabled.
104
104
105 $ cd client
105 $ cd client
106 $ echo 'non-lfs' > nonlfs.txt
106 $ echo 'non-lfs' > nonlfs.txt
107 >>> from __future__ import absolute_import
107 >>> from __future__ import absolute_import
108 >>> from hgclient import check, readchannel, runcommand
108 >>> from hgclient import check, readchannel, runcommand
109 >>> @check
109 >>> @check
110 ... def diff(server):
110 ... def diff(server):
111 ... readchannel(server)
111 ... readchannel(server)
112 ... # run an arbitrary command in the repo with the extension loaded
112 ... # run an arbitrary command in the repo with the extension loaded
113 ... runcommand(server, ['id', '-R', '../cmdservelfs'])
113 ... runcommand(server, ['id', '-R', '../cmdservelfs'])
114 ... # 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
115 ... # files are added safely..
115 ... # files are added safely..
116 ... runcommand(server, ['ci', '-Aqm', 'non-lfs'])
116 ... runcommand(server, ['ci', '-Aqm', 'non-lfs'])
117 ... # .. and that scmutil.prefetchfiles() safely no-ops..
117 ... # .. and that scmutil.prefetchfiles() safely no-ops..
118 ... runcommand(server, ['diff', '-r', '.~1'])
118 ... runcommand(server, ['diff', '-r', '.~1'])
119 ... # .. and that debugupgraderepo safely no-ops.
119 ... # .. and that debugupgraderepo safely no-ops.
120 ... runcommand(server, ['debugupgraderepo', '-q', '--run'])
120 ... runcommand(server, ['debugupgraderepo', '-q', '--run'])
121 *** runcommand id -R ../cmdservelfs
121 *** runcommand id -R ../cmdservelfs
122 000000000000 tip
122 000000000000 tip
123 *** runcommand ci -Aqm non-lfs
123 *** runcommand ci -Aqm non-lfs
124 *** runcommand diff -r .~1
124 *** runcommand diff -r .~1
125 diff -r 000000000000 nonlfs.txt
125 diff -r 000000000000 nonlfs.txt
126 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127 +++ b/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
127 +++ b/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
128 @@ -0,0 +1,1 @@
128 @@ -0,0 +1,1 @@
129 +non-lfs
129 +non-lfs
130 *** runcommand debugupgraderepo -q --run
130 *** runcommand debugupgraderepo -q --run
131 upgrade will perform the following actions:
131 upgrade will perform the following actions:
132
132
133 requirements
133 requirements
134 preserved: dotencode, fncache, generaldelta, revlogv1, store
134 preserved: dotencode, fncache, generaldelta, revlogv1, store
135
135
136 beginning upgrade...
136 beginning upgrade...
137 repository locked and read-only
137 repository locked and read-only
138 creating temporary repository to stage migrated data: * (glob)
138 creating temporary repository to stage migrated data: * (glob)
139 (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)
140 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)
141 migrating 324 bytes in store; 129 bytes tracked data
141 migrating 324 bytes in store; 129 bytes tracked data
142 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)
143 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
144 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)
145 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
146 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)
147 finished migrating 1 changelog revisions; change in size: 0 bytes
147 finished migrating 1 changelog revisions; change in size: 0 bytes
148 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
149 copying phaseroots
149 copying phaseroots
150 data fully migrated to temporary repository
150 data fully migrated to temporary repository
151 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
152 starting in-place swap of repository data
152 starting in-place swap of repository data
153 replaced files will be backed up at * (glob)
153 replaced files will be backed up at * (glob)
154 replacing store...
154 replacing store...
155 store replacement complete; repository was inconsistent for *s (glob)
155 store replacement complete; repository was inconsistent for *s (glob)
156 finalizing requirements file and making repository readable again
156 finalizing requirements file and making repository readable again
157 removing temporary repository * (glob)
157 removing temporary repository * (glob)
158 copy of old repository backed up at * (glob)
158 copy of old repository backed up at * (glob)
159 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
160
160
161 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
161 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
162 [1]
162 [1]
163
163
164 #if lfsremote-on
164 #if lfsremote-on
165
165
166 $ hg push -q
166 $ hg push -q
167 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
167 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
168 [1]
168 [1]
169
169
170 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client1_clone
170 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client1_clone
171 $ grep 'lfs' $TESTTMP/client1_clone/.hg/requires $SERVER_REQUIRES
171 $ grep 'lfs' $TESTTMP/client1_clone/.hg/requires $SERVER_REQUIRES
172 [1]
172 [1]
173
173
174 $ hg init $TESTTMP/client1_pull
174 $ hg init $TESTTMP/client1_pull
175 $ hg -R $TESTTMP/client1_pull pull -q http://localhost:$HGPORT
175 $ hg -R $TESTTMP/client1_pull pull -q http://localhost:$HGPORT
176 $ grep 'lfs' $TESTTMP/client1_pull/.hg/requires $SERVER_REQUIRES
176 $ grep 'lfs' $TESTTMP/client1_pull/.hg/requires $SERVER_REQUIRES
177 [1]
177 [1]
178
178
179 $ hg identify http://localhost:$HGPORT
179 $ hg identify http://localhost:$HGPORT
180 d437e1d24fbd
180 d437e1d24fbd
181
181
182 #endif
182 #endif
183
183
184 --------------------------------------------------------------------------------
184 --------------------------------------------------------------------------------
185 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
186 non-lfs content, and the extension state controlled by #testcases.
186 non-lfs content, and the extension state controlled by #testcases.
187
187
188 $ cat >> $HGRCPATH <<EOF
188 $ cat >> $HGRCPATH <<EOF
189 > [extensions]
189 > [extensions]
190 > lfs =
190 > lfs =
191 > EOF
191 > EOF
192 $ echo 'non-lfs' > nonlfs2.txt
192 $ echo 'non-lfs' > nonlfs2.txt
193 $ hg ci -Aqm 'non-lfs file with lfs client'
193 $ hg ci -Aqm 'non-lfs file with lfs client'
194
194
195 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
196 extension is not enabled remotely.
196 extension is not enabled remotely.
197
197
198 $ hg push -q
198 $ hg push -q
199 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
199 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
200 [1]
200 [1]
201
201
202 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client2_clone
202 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client2_clone
203 $ grep 'lfs' $TESTTMP/client2_clone/.hg/requires $SERVER_REQUIRES
203 $ grep 'lfs' $TESTTMP/client2_clone/.hg/requires $SERVER_REQUIRES
204 [1]
204 [1]
205
205
206 $ hg init $TESTTMP/client2_pull
206 $ hg init $TESTTMP/client2_pull
207 $ hg -R $TESTTMP/client2_pull pull -q http://localhost:$HGPORT
207 $ hg -R $TESTTMP/client2_pull pull -q http://localhost:$HGPORT
208 $ grep 'lfs' $TESTTMP/client2_pull/.hg/requires $SERVER_REQUIRES
208 $ grep 'lfs' $TESTTMP/client2_pull/.hg/requires $SERVER_REQUIRES
209 [1]
209 [1]
210
210
211 $ hg identify http://localhost:$HGPORT
211 $ hg identify http://localhost:$HGPORT
212 1477875038c6
212 1477875038c6
213
213
214 --------------------------------------------------------------------------------
214 --------------------------------------------------------------------------------
215 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
216 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
217 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.
218
218
219 $ echo 'this is a big lfs file' > lfs.bin
219 $ echo 'this is a big lfs file' > lfs.bin
220 $ hg ci -Aqm 'lfs'
220 $ hg ci -Aqm 'lfs'
221 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
221 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
222 .hg/requires:lfs
222 .hg/requires:lfs
223
223
224 #if lfsremote-off
224 #if lfsremote-off
225 $ hg push -q
225 $ hg push -q
226 abort: required features are not supported in the destination: lfs
226 abort: required features are not supported in the destination: lfs
227 (enable the lfs extension on the server)
227 (enable the lfs extension on the server)
228 [255]
228 [255]
229 #else
229 #else
230 $ hg push -q
230 $ hg push -q
231 #endif
231 #endif
232 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
232 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
233 .hg/requires:lfs
233 .hg/requires:lfs
234 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
234 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
235
235
236 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client3_clone
236 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client3_clone
237 $ grep 'lfs' $TESTTMP/client3_clone/.hg/requires $SERVER_REQUIRES || true
237 $ grep 'lfs' $TESTTMP/client3_clone/.hg/requires $SERVER_REQUIRES || true
238 $TESTTMP/client3_clone/.hg/requires:lfs (lfsremote-on !)
238 $TESTTMP/client3_clone/.hg/requires:lfs (lfsremote-on !)
239 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
239 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
240
240
241 $ hg init $TESTTMP/client3_pull
241 $ hg init $TESTTMP/client3_pull
242 $ hg -R $TESTTMP/client3_pull pull -q http://localhost:$HGPORT
242 $ hg -R $TESTTMP/client3_pull pull -q http://localhost:$HGPORT
243 $ grep 'lfs' $TESTTMP/client3_pull/.hg/requires $SERVER_REQUIRES || true
243 $ grep 'lfs' $TESTTMP/client3_pull/.hg/requires $SERVER_REQUIRES || true
244 $TESTTMP/client3_pull/.hg/requires:lfs (lfsremote-on !)
244 $TESTTMP/client3_pull/.hg/requires:lfs (lfsremote-on !)
245 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
245 $TESTTMP/server/.hg/requires:lfs (lfsremote-on !)
246
246
247 Test that the commit/changegroup requirement check hook can be run multiple
248 times.
249
250 $ hg clone -qr 0 http://localhost:$HGPORT $TESTTMP/cmdserve_client3
251
252 $ cd ../cmdserve_client3
253
254 >>> from __future__ import absolute_import
255 >>> from hgclient import check, readchannel, runcommand
256 >>> @check
257 ... def addrequirement(server):
258 ... readchannel(server)
259 ... # change the repo in a way that adds the lfs requirement
260 ... runcommand(server, ['pull', '-qu'])
261 ... # Now cause the requirement adding hook to fire again, without going
262 ... # through reposetup() again.
263 ... with open('file.txt', 'wb') as fp:
264 ... fp.write('data')
265 ... runcommand(server, ['ci', '-Aqm', 'non-lfs'])
266 *** runcommand pull -qu
267 *** runcommand ci -Aqm non-lfs
268
269 $ cd ../client
270
247 The difference here is the push failed above when the extension isn't
271 The difference here is the push failed above when the extension isn't
248 enabled on the server.
272 enabled on the server.
249 $ hg identify http://localhost:$HGPORT
273 $ hg identify http://localhost:$HGPORT
250 8374dc4052cb (lfsremote-on !)
274 8374dc4052cb (lfsremote-on !)
251 1477875038c6 (lfsremote-off !)
275 1477875038c6 (lfsremote-off !)
252
276
253 Don't bother testing the lfsremote-off cases- the server won't be able
277 Don't bother testing the lfsremote-off cases- the server won't be able
254 to launch if there's lfs content and the extension is disabled.
278 to launch if there's lfs content and the extension is disabled.
255
279
256 #if lfsremote-on
280 #if lfsremote-on
257
281
258 --------------------------------------------------------------------------------
282 --------------------------------------------------------------------------------
259 Case #4: client with non-lfs content and the extension disabled; server with
283 Case #4: client with non-lfs content and the extension disabled; server with
260 lfs content, and the extension enabled.
284 lfs content, and the extension enabled.
261
285
262 $ cat >> $HGRCPATH <<EOF
286 $ cat >> $HGRCPATH <<EOF
263 > [extensions]
287 > [extensions]
264 > lfs = !
288 > lfs = !
265 > EOF
289 > EOF
266
290
267 $ hg init $TESTTMP/client4
291 $ hg init $TESTTMP/client4
268 $ cd $TESTTMP/client4
292 $ cd $TESTTMP/client4
269 $ cat >> .hg/hgrc <<EOF
293 $ cat >> .hg/hgrc <<EOF
270 > [paths]
294 > [paths]
271 > default = http://localhost:$HGPORT
295 > default = http://localhost:$HGPORT
272 > EOF
296 > EOF
273 $ echo 'non-lfs' > nonlfs2.txt
297 $ echo 'non-lfs' > nonlfs2.txt
274 $ hg ci -Aqm 'non-lfs'
298 $ hg ci -Aqm 'non-lfs'
275 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
299 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
276 $TESTTMP/server/.hg/requires:lfs
300 $TESTTMP/server/.hg/requires:lfs
277
301
278 $ hg push -q --force
302 $ hg push -q --force
279 warning: repository is unrelated
303 warning: repository is unrelated
280 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
304 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
281 $TESTTMP/server/.hg/requires:lfs
305 $TESTTMP/server/.hg/requires:lfs
282
306
283 TODO: fail more gracefully.
307 TODO: fail more gracefully.
284
308
285 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client4_clone
309 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client4_clone
286 abort: HTTP Error 500: Internal Server Error
310 abort: HTTP Error 500: Internal Server Error
287 [255]
311 [255]
288 $ grep 'lfs' $TESTTMP/client4_clone/.hg/requires $SERVER_REQUIRES
312 $ grep 'lfs' $TESTTMP/client4_clone/.hg/requires $SERVER_REQUIRES
289 grep: $TESTTMP/client4_clone/.hg/requires: $ENOENT$
313 grep: $TESTTMP/client4_clone/.hg/requires: $ENOENT$
290 $TESTTMP/server/.hg/requires:lfs
314 $TESTTMP/server/.hg/requires:lfs
291 [2]
315 [2]
292
316
293 TODO: fail more gracefully.
317 TODO: fail more gracefully.
294
318
295 $ hg init $TESTTMP/client4_pull
319 $ hg init $TESTTMP/client4_pull
296 $ hg -R $TESTTMP/client4_pull pull -q http://localhost:$HGPORT
320 $ hg -R $TESTTMP/client4_pull pull -q http://localhost:$HGPORT
297 abort: HTTP Error 500: Internal Server Error
321 abort: HTTP Error 500: Internal Server Error
298 [255]
322 [255]
299 $ grep 'lfs' $TESTTMP/client4_pull/.hg/requires $SERVER_REQUIRES
323 $ grep 'lfs' $TESTTMP/client4_pull/.hg/requires $SERVER_REQUIRES
300 $TESTTMP/server/.hg/requires:lfs
324 $TESTTMP/server/.hg/requires:lfs
301
325
302 $ hg identify http://localhost:$HGPORT
326 $ hg identify http://localhost:$HGPORT
303 03b080fa9d93
327 03b080fa9d93
304
328
305 --------------------------------------------------------------------------------
329 --------------------------------------------------------------------------------
306 Case #5: client with non-lfs content and the extension enabled; server with
330 Case #5: client with non-lfs content and the extension enabled; server with
307 lfs content, and the extension enabled.
331 lfs content, and the extension enabled.
308
332
309 $ cat >> $HGRCPATH <<EOF
333 $ cat >> $HGRCPATH <<EOF
310 > [extensions]
334 > [extensions]
311 > lfs =
335 > lfs =
312 > EOF
336 > EOF
313 $ echo 'non-lfs' > nonlfs3.txt
337 $ echo 'non-lfs' > nonlfs3.txt
314 $ hg ci -Aqm 'non-lfs file with lfs client'
338 $ hg ci -Aqm 'non-lfs file with lfs client'
315
339
316 $ hg push -q
340 $ hg push -q
317 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
341 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
318 $TESTTMP/server/.hg/requires:lfs
342 $TESTTMP/server/.hg/requires:lfs
319
343
320 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client5_clone
344 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client5_clone
321 $ grep 'lfs' $TESTTMP/client5_clone/.hg/requires $SERVER_REQUIRES
345 $ grep 'lfs' $TESTTMP/client5_clone/.hg/requires $SERVER_REQUIRES
322 $TESTTMP/client5_clone/.hg/requires:lfs
346 $TESTTMP/client5_clone/.hg/requires:lfs
323 $TESTTMP/server/.hg/requires:lfs
347 $TESTTMP/server/.hg/requires:lfs
324
348
325 $ hg init $TESTTMP/client5_pull
349 $ hg init $TESTTMP/client5_pull
326 $ hg -R $TESTTMP/client5_pull pull -q http://localhost:$HGPORT
350 $ hg -R $TESTTMP/client5_pull pull -q http://localhost:$HGPORT
327 $ grep 'lfs' $TESTTMP/client5_pull/.hg/requires $SERVER_REQUIRES
351 $ grep 'lfs' $TESTTMP/client5_pull/.hg/requires $SERVER_REQUIRES
328 $TESTTMP/client5_pull/.hg/requires:lfs
352 $TESTTMP/client5_pull/.hg/requires:lfs
329 $TESTTMP/server/.hg/requires:lfs
353 $TESTTMP/server/.hg/requires:lfs
330
354
331 $ hg identify http://localhost:$HGPORT
355 $ hg identify http://localhost:$HGPORT
332 c729025cc5e3
356 c729025cc5e3
333
357
334 $ mv $HGRCPATH $HGRCPATH.tmp
358 $ mv $HGRCPATH $HGRCPATH.tmp
335 $ cp $HGRCPATH.orig $HGRCPATH
359 $ cp $HGRCPATH.orig $HGRCPATH
336
360
337 >>> from __future__ import absolute_import
361 >>> from __future__ import absolute_import
338 >>> from hgclient import check, readchannel, runcommand
362 >>> from hgclient import check, readchannel, runcommand
339 >>> @check
363 >>> @check
340 ... def checkflags(server):
364 ... def checkflags(server):
341 ... readchannel(server)
365 ... readchannel(server)
342 ... print('')
366 ... print('')
343 ... print('# LFS required- both lfs and non-lfs revlogs have 0x2000 flag')
367 ... print('# LFS required- both lfs and non-lfs revlogs have 0x2000 flag')
344 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
368 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
345 ... '../server'])
369 ... '../server'])
346 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
370 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
347 ... '../server'])
371 ... '../server'])
348 ... runcommand(server, ['config', 'extensions', '--cwd',
372 ... runcommand(server, ['config', 'extensions', '--cwd',
349 ... '../server'])
373 ... '../server'])
350 ...
374 ...
351 ... print("\n# LFS not enabled- revlogs don't have 0x2000 flag")
375 ... print("\n# LFS not enabled- revlogs don't have 0x2000 flag")
352 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
376 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
353 ... runcommand(server, ['config', 'extensions'])
377 ... runcommand(server, ['config', 'extensions'])
354
378
355 # LFS required- both lfs and non-lfs revlogs have 0x2000 flag
379 # LFS required- both lfs and non-lfs revlogs have 0x2000 flag
356 *** runcommand debugprocessors lfs.bin -R ../server
380 *** runcommand debugprocessors lfs.bin -R ../server
357 registered processor '0x8000'
381 registered processor '0x8000'
358 registered processor '0x2000'
382 registered processor '0x2000'
359 *** runcommand debugprocessors nonlfs2.txt -R ../server
383 *** runcommand debugprocessors nonlfs2.txt -R ../server
360 registered processor '0x8000'
384 registered processor '0x8000'
361 registered processor '0x2000'
385 registered processor '0x2000'
362 *** runcommand config extensions --cwd ../server
386 *** runcommand config extensions --cwd ../server
363 extensions.debugprocessors=$TESTTMP/debugprocessors.py
387 extensions.debugprocessors=$TESTTMP/debugprocessors.py
364 extensions.lfs=
388 extensions.lfs=
365
389
366 # LFS not enabled- revlogs don't have 0x2000 flag
390 # LFS not enabled- revlogs don't have 0x2000 flag
367 *** runcommand debugprocessors nonlfs3.txt
391 *** runcommand debugprocessors nonlfs3.txt
368 registered processor '0x8000'
392 registered processor '0x8000'
369 *** runcommand config extensions
393 *** runcommand config extensions
370 extensions.debugprocessors=$TESTTMP/debugprocessors.py
394 extensions.debugprocessors=$TESTTMP/debugprocessors.py
371
395
372 $ rm $HGRCPATH
396 $ rm $HGRCPATH
373 $ mv $HGRCPATH.tmp $HGRCPATH
397 $ mv $HGRCPATH.tmp $HGRCPATH
374
398
375 $ hg clone $TESTTMP/client $TESTTMP/nonlfs -qr 0 --config extensions.lfs=
399 $ hg clone $TESTTMP/client $TESTTMP/nonlfs -qr 0 --config extensions.lfs=
376 $ cat >> $TESTTMP/nonlfs/.hg/hgrc <<EOF
400 $ cat >> $TESTTMP/nonlfs/.hg/hgrc <<EOF
377 > [extensions]
401 > [extensions]
378 > lfs = !
402 > lfs = !
379 > EOF
403 > EOF
380
404
381 >>> from __future__ import absolute_import, print_function
405 >>> from __future__ import absolute_import, print_function
382 >>> from hgclient import check, readchannel, runcommand
406 >>> from hgclient import check, readchannel, runcommand
383 >>> @check
407 >>> @check
384 ... def checkflags2(server):
408 ... def checkflags2(server):
385 ... readchannel(server)
409 ... readchannel(server)
386 ... print('')
410 ... print('')
387 ... print('# LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag')
411 ... print('# LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag')
388 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
412 ... runcommand(server, ['debugprocessors', 'lfs.bin', '-R',
389 ... '../server'])
413 ... '../server'])
390 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
414 ... runcommand(server, ['debugprocessors', 'nonlfs2.txt', '-R',
391 ... '../server'])
415 ... '../server'])
392 ... runcommand(server, ['config', 'extensions', '--cwd',
416 ... runcommand(server, ['config', 'extensions', '--cwd',
393 ... '../server'])
417 ... '../server'])
394 ...
418 ...
395 ... print('\n# LFS enabled without requirement- revlogs have 0x2000 flag')
419 ... print('\n# LFS enabled without requirement- revlogs have 0x2000 flag')
396 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
420 ... runcommand(server, ['debugprocessors', 'nonlfs3.txt'])
397 ... runcommand(server, ['config', 'extensions'])
421 ... runcommand(server, ['config', 'extensions'])
398 ...
422 ...
399 ... print("\n# LFS disabled locally- revlogs don't have 0x2000 flag")
423 ... print("\n# LFS disabled locally- revlogs don't have 0x2000 flag")
400 ... runcommand(server, ['debugprocessors', 'nonlfs.txt', '-R',
424 ... runcommand(server, ['debugprocessors', 'nonlfs.txt', '-R',
401 ... '../nonlfs'])
425 ... '../nonlfs'])
402 ... runcommand(server, ['config', 'extensions', '--cwd',
426 ... runcommand(server, ['config', 'extensions', '--cwd',
403 ... '../nonlfs'])
427 ... '../nonlfs'])
404
428
405 # LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag
429 # LFS enabled- both lfs and non-lfs revlogs have 0x2000 flag
406 *** runcommand debugprocessors lfs.bin -R ../server
430 *** runcommand debugprocessors lfs.bin -R ../server
407 registered processor '0x8000'
431 registered processor '0x8000'
408 registered processor '0x2000'
432 registered processor '0x2000'
409 *** runcommand debugprocessors nonlfs2.txt -R ../server
433 *** runcommand debugprocessors nonlfs2.txt -R ../server
410 registered processor '0x8000'
434 registered processor '0x8000'
411 registered processor '0x2000'
435 registered processor '0x2000'
412 *** runcommand config extensions --cwd ../server
436 *** runcommand config extensions --cwd ../server
413 extensions.debugprocessors=$TESTTMP/debugprocessors.py
437 extensions.debugprocessors=$TESTTMP/debugprocessors.py
414 extensions.lfs=
438 extensions.lfs=
415
439
416 # LFS enabled without requirement- revlogs have 0x2000 flag
440 # LFS enabled without requirement- revlogs have 0x2000 flag
417 *** runcommand debugprocessors nonlfs3.txt
441 *** runcommand debugprocessors nonlfs3.txt
418 registered processor '0x8000'
442 registered processor '0x8000'
419 registered processor '0x2000'
443 registered processor '0x2000'
420 *** runcommand config extensions
444 *** runcommand config extensions
421 extensions.debugprocessors=$TESTTMP/debugprocessors.py
445 extensions.debugprocessors=$TESTTMP/debugprocessors.py
422 extensions.lfs=
446 extensions.lfs=
423
447
424 # LFS disabled locally- revlogs don't have 0x2000 flag
448 # LFS disabled locally- revlogs don't have 0x2000 flag
425 *** runcommand debugprocessors nonlfs.txt -R ../nonlfs
449 *** runcommand debugprocessors nonlfs.txt -R ../nonlfs
426 registered processor '0x8000'
450 registered processor '0x8000'
427 *** runcommand config extensions --cwd ../nonlfs
451 *** runcommand config extensions --cwd ../nonlfs
428 extensions.debugprocessors=$TESTTMP/debugprocessors.py
452 extensions.debugprocessors=$TESTTMP/debugprocessors.py
429 extensions.lfs=!
453 extensions.lfs=!
430
454
431 --------------------------------------------------------------------------------
455 --------------------------------------------------------------------------------
432 Case #6: client with lfs content and the extension enabled; server with
456 Case #6: client with lfs content and the extension enabled; server with
433 lfs content, and the extension enabled.
457 lfs content, and the extension enabled.
434
458
435 $ echo 'this is another lfs file' > lfs2.txt
459 $ echo 'this is another lfs file' > lfs2.txt
436 $ hg ci -Aqm 'lfs file with lfs client'
460 $ hg ci -Aqm 'lfs file with lfs client'
437
461
438 $ hg --config paths.default= push -v http://localhost:$HGPORT
462 $ hg --config paths.default= push -v http://localhost:$HGPORT
439 pushing to http://localhost:$HGPORT/
463 pushing to http://localhost:$HGPORT/
440 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
464 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
441 searching for changes
465 searching for changes
442 remote has heads on branch 'default' that are not known locally: 8374dc4052cb
466 remote has heads on branch 'default' that are not known locally: 8374dc4052cb
443 lfs: uploading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
467 lfs: uploading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
444 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
468 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
445 lfs: uploaded 1 files (25 bytes)
469 lfs: uploaded 1 files (25 bytes)
446 1 changesets found
470 1 changesets found
447 uncompressed size of bundle content:
471 uncompressed size of bundle content:
448 206 (changelog)
472 206 (changelog)
449 172 (manifests)
473 172 (manifests)
450 275 lfs2.txt
474 275 lfs2.txt
451 remote: adding changesets
475 remote: adding changesets
452 remote: adding manifests
476 remote: adding manifests
453 remote: adding file changes
477 remote: adding file changes
454 remote: added 1 changesets with 1 changes to 1 files
478 remote: added 1 changesets with 1 changes to 1 files
455 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
479 $ grep 'lfs' .hg/requires $SERVER_REQUIRES
456 .hg/requires:lfs
480 .hg/requires:lfs
457 $TESTTMP/server/.hg/requires:lfs
481 $TESTTMP/server/.hg/requires:lfs
458
482
459 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client6_clone
483 $ hg clone -q http://localhost:$HGPORT $TESTTMP/client6_clone
460 $ grep 'lfs' $TESTTMP/client6_clone/.hg/requires $SERVER_REQUIRES
484 $ grep 'lfs' $TESTTMP/client6_clone/.hg/requires $SERVER_REQUIRES
461 $TESTTMP/client6_clone/.hg/requires:lfs
485 $TESTTMP/client6_clone/.hg/requires:lfs
462 $TESTTMP/server/.hg/requires:lfs
486 $TESTTMP/server/.hg/requires:lfs
463
487
464 $ hg init $TESTTMP/client6_pull
488 $ hg init $TESTTMP/client6_pull
465 $ hg -R $TESTTMP/client6_pull pull -u -v http://localhost:$HGPORT
489 $ hg -R $TESTTMP/client6_pull pull -u -v http://localhost:$HGPORT
466 pulling from http://localhost:$HGPORT/
490 pulling from http://localhost:$HGPORT/
467 requesting all changes
491 requesting all changes
468 adding changesets
492 adding changesets
469 adding manifests
493 adding manifests
470 adding file changes
494 adding file changes
471 added 6 changesets with 5 changes to 5 files (+1 heads)
495 added 6 changesets with 5 changes to 5 files (+1 heads)
472 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
496 calling hook pretxnchangegroup.lfs: hgext.lfs.checkrequireslfs
473 new changesets d437e1d24fbd:d3b84d50eacb
497 new changesets d437e1d24fbd:d3b84d50eacb
474 resolving manifests
498 resolving manifests
475 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
499 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
476 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
500 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
477 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
501 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
478 lfs: downloaded 1 files (25 bytes)
502 lfs: downloaded 1 files (25 bytes)
479 getting lfs2.txt
503 getting lfs2.txt
480 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
504 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
481 getting nonlfs2.txt
505 getting nonlfs2.txt
482 getting nonlfs3.txt
506 getting nonlfs3.txt
483 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
507 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
484 updated to "d3b84d50eacb: lfs file with lfs client"
508 updated to "d3b84d50eacb: lfs file with lfs client"
485 1 other heads for branch "default"
509 1 other heads for branch "default"
486 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
510 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
487 $ grep 'lfs' $TESTTMP/client6_pull/.hg/requires $SERVER_REQUIRES
511 $ grep 'lfs' $TESTTMP/client6_pull/.hg/requires $SERVER_REQUIRES
488 $TESTTMP/client6_pull/.hg/requires:lfs
512 $TESTTMP/client6_pull/.hg/requires:lfs
489 $TESTTMP/server/.hg/requires:lfs
513 $TESTTMP/server/.hg/requires:lfs
490
514
491 $ hg identify http://localhost:$HGPORT
515 $ hg identify http://localhost:$HGPORT
492 d3b84d50eacb
516 d3b84d50eacb
493
517
494 --------------------------------------------------------------------------------
518 --------------------------------------------------------------------------------
495 Misc: process dies early if a requirement exists and the extension is disabled
519 Misc: process dies early if a requirement exists and the extension is disabled
496
520
497 $ hg --config extensions.lfs=! summary
521 $ hg --config extensions.lfs=! summary
498 abort: repository requires features unknown to this Mercurial: lfs!
522 abort: repository requires features unknown to this Mercurial: lfs!
499 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
523 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
500 [255]
524 [255]
501
525
502 $ echo 'this is an lfs file' > $TESTTMP/client6_clone/lfspair1.bin
526 $ echo 'this is an lfs file' > $TESTTMP/client6_clone/lfspair1.bin
503 $ echo 'this is an lfs file too' > $TESTTMP/client6_clone/lfspair2.bin
527 $ echo 'this is an lfs file too' > $TESTTMP/client6_clone/lfspair2.bin
504 $ hg -R $TESTTMP/client6_clone ci -Aqm 'add lfs pair'
528 $ hg -R $TESTTMP/client6_clone ci -Aqm 'add lfs pair'
505 $ hg -R $TESTTMP/client6_clone push -q
529 $ hg -R $TESTTMP/client6_clone push -q
506
530
507 $ hg clone -qU http://localhost:$HGPORT $TESTTMP/bulkfetch
531 $ hg clone -qU http://localhost:$HGPORT $TESTTMP/bulkfetch
508
532
509 Export will prefetch all needed files across all needed revisions
533 Export will prefetch all needed files across all needed revisions
510
534
511 $ hg -R $TESTTMP/bulkfetch -v export -r 0:tip -o all.export
535 $ hg -R $TESTTMP/bulkfetch -v export -r 0:tip -o all.export
512 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
536 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
513 exporting patches:
537 exporting patches:
514 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
538 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
515 lfs: need to transfer 4 objects (92 bytes)
539 lfs: need to transfer 4 objects (92 bytes)
516 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
540 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
517 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
541 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
518 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
542 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
519 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
543 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
520 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
544 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
521 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
545 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
522 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
546 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
523 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
547 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
524 lfs: downloaded 4 files (92 bytes)
548 lfs: downloaded 4 files (92 bytes)
525 all.export
549 all.export
526 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
550 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
527 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
551 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
528 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
552 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
529 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
553 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
530
554
531 Export with selected files is used with `extdiff --patch`
555 Export with selected files is used with `extdiff --patch`
532
556
533 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
557 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
534 $ hg --config extensions.extdiff= \
558 $ hg --config extensions.extdiff= \
535 > -R $TESTTMP/bulkfetch -v extdiff -r 2:tip --patch $TESTTMP/bulkfetch/lfs.bin
559 > -R $TESTTMP/bulkfetch -v extdiff -r 2:tip --patch $TESTTMP/bulkfetch/lfs.bin
536 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
560 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
537 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
561 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
538 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
562 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
539 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
563 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
540 lfs: downloaded 1 files (23 bytes)
564 lfs: downloaded 1 files (23 bytes)
541 */hg-8374dc4052cb.patch (glob)
565 */hg-8374dc4052cb.patch (glob)
542 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
566 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
543 */hg-9640b57e77b1.patch (glob)
567 */hg-9640b57e77b1.patch (glob)
544 --- */hg-8374dc4052cb.patch * (glob)
568 --- */hg-8374dc4052cb.patch * (glob)
545 +++ */hg-9640b57e77b1.patch * (glob)
569 +++ */hg-9640b57e77b1.patch * (glob)
546 @@ -2,12 +2,7 @@
570 @@ -2,12 +2,7 @@
547 # User test
571 # User test
548 # Date 0 0
572 # Date 0 0
549 # Thu Jan 01 00:00:00 1970 +0000
573 # Thu Jan 01 00:00:00 1970 +0000
550 -# Node ID 8374dc4052cbd388e79d9dc4ddb29784097aa354
574 -# Node ID 8374dc4052cbd388e79d9dc4ddb29784097aa354
551 -# Parent 1477875038c60152e391238920a16381c627b487
575 -# Parent 1477875038c60152e391238920a16381c627b487
552 -lfs
576 -lfs
553 +# Node ID 9640b57e77b14c3a0144fb4478b6cc13e13ea0d1
577 +# Node ID 9640b57e77b14c3a0144fb4478b6cc13e13ea0d1
554 +# Parent d3b84d50eacbd56638e11abce6b8616aaba54420
578 +# Parent d3b84d50eacbd56638e11abce6b8616aaba54420
555 +add lfs pair
579 +add lfs pair
556
580
557 -diff -r 1477875038c6 -r 8374dc4052cb lfs.bin
581 -diff -r 1477875038c6 -r 8374dc4052cb lfs.bin
558 ---- /dev/null Thu Jan 01 00:00:00 1970 +0000
582 ---- /dev/null Thu Jan 01 00:00:00 1970 +0000
559 -+++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
583 -+++ b/lfs.bin Thu Jan 01 00:00:00 1970 +0000
560 -@@ -0,0 +1,1 @@
584 -@@ -0,0 +1,1 @@
561 -+this is a big lfs file
585 -+this is a big lfs file
562 cleaning up temp directory
586 cleaning up temp directory
563 [1]
587 [1]
564
588
565 Diff will prefetch files
589 Diff will prefetch files
566
590
567 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
591 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
568 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip
592 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip
569 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
593 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
570 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
594 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
571 lfs: need to transfer 4 objects (92 bytes)
595 lfs: need to transfer 4 objects (92 bytes)
572 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
596 lfs: downloading a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de (25 bytes)
573 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
597 lfs: processed: a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de
574 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
598 lfs: downloading bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc (23 bytes)
575 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
599 lfs: processed: bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc
576 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
600 lfs: downloading cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 (20 bytes)
577 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
601 lfs: processed: cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782
578 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
602 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
579 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
603 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
580 lfs: downloaded 4 files (92 bytes)
604 lfs: downloaded 4 files (92 bytes)
581 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
605 lfs: found bed80f00180ac404b843628ab56a1c1984d6145c391cd1628a7dd7d2598d71fc in the local lfs store
582 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
606 lfs: found a82f1c5cea0d40e3bb3a849686bb4e6ae47ca27e614de55c1ed0325698ef68de in the local lfs store
583 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
607 lfs: found cf1b2787b74e66547d931b6ebe28ff63303e803cb2baa14a8f57c4383d875782 in the local lfs store
584 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
608 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
585 diff -r 8374dc4052cb -r 9640b57e77b1 lfs.bin
609 diff -r 8374dc4052cb -r 9640b57e77b1 lfs.bin
586 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
610 --- a/lfs.bin Thu Jan 01 00:00:00 1970 +0000
587 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
611 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
588 @@ -1,1 +0,0 @@
612 @@ -1,1 +0,0 @@
589 -this is a big lfs file
613 -this is a big lfs file
590 diff -r 8374dc4052cb -r 9640b57e77b1 lfs2.txt
614 diff -r 8374dc4052cb -r 9640b57e77b1 lfs2.txt
591 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
615 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
592 +++ b/lfs2.txt Thu Jan 01 00:00:00 1970 +0000
616 +++ b/lfs2.txt Thu Jan 01 00:00:00 1970 +0000
593 @@ -0,0 +1,1 @@
617 @@ -0,0 +1,1 @@
594 +this is another lfs file
618 +this is another lfs file
595 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair1.bin
619 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair1.bin
596 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
620 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
597 +++ b/lfspair1.bin Thu Jan 01 00:00:00 1970 +0000
621 +++ b/lfspair1.bin Thu Jan 01 00:00:00 1970 +0000
598 @@ -0,0 +1,1 @@
622 @@ -0,0 +1,1 @@
599 +this is an lfs file
623 +this is an lfs file
600 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
624 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
601 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
625 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
602 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
626 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
603 @@ -0,0 +1,1 @@
627 @@ -0,0 +1,1 @@
604 +this is an lfs file too
628 +this is an lfs file too
605 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs.txt
629 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs.txt
606 --- a/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
630 --- a/nonlfs.txt Thu Jan 01 00:00:00 1970 +0000
607 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
631 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
608 @@ -1,1 +0,0 @@
632 @@ -1,1 +0,0 @@
609 -non-lfs
633 -non-lfs
610 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs3.txt
634 diff -r 8374dc4052cb -r 9640b57e77b1 nonlfs3.txt
611 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
635 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
612 +++ b/nonlfs3.txt Thu Jan 01 00:00:00 1970 +0000
636 +++ b/nonlfs3.txt Thu Jan 01 00:00:00 1970 +0000
613 @@ -0,0 +1,1 @@
637 @@ -0,0 +1,1 @@
614 +non-lfs
638 +non-lfs
615
639
616 Only the files required by diff are prefetched
640 Only the files required by diff are prefetched
617
641
618 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
642 $ rm -r $TESTTMP/bulkfetch/.hg/store/lfs
619 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip $TESTTMP/bulkfetch/lfspair2.bin
643 $ hg -R $TESTTMP/bulkfetch -v diff -r 2:tip $TESTTMP/bulkfetch/lfspair2.bin
620 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
644 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
621 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
645 lfs: assuming remote store: http://localhost:$HGPORT/.git/info/lfs
622 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
646 lfs: downloading d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e (24 bytes)
623 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
647 lfs: processed: d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e
624 lfs: downloaded 1 files (24 bytes)
648 lfs: downloaded 1 files (24 bytes)
625 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
649 lfs: found d96eda2c74b56e95cfb5ffb66b6503e198cc6fc4a09dc877de925feebc65786e in the local lfs store
626 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
650 diff -r 8374dc4052cb -r 9640b57e77b1 lfspair2.bin
627 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
651 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
628 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
652 +++ b/lfspair2.bin Thu Jan 01 00:00:00 1970 +0000
629 @@ -0,0 +1,1 @@
653 @@ -0,0 +1,1 @@
630 +this is an lfs file too
654 +this is an lfs file too
631
655
632 #endif
656 #endif
633
657
634 $ "$PYTHON" $TESTDIR/killdaemons.py $DAEMON_PIDS
658 $ "$PYTHON" $TESTDIR/killdaemons.py $DAEMON_PIDS
635
659
636 #if lfsremote-on
660 #if lfsremote-on
637 $ cat $TESTTMP/errors.log | grep '^[A-Z]'
661 $ cat $TESTTMP/errors.log | grep '^[A-Z]'
638 Traceback (most recent call last):
662 Traceback (most recent call last):
639 ValueError: no common changegroup version
663 ValueError: no common changegroup version
640 Traceback (most recent call last):
664 Traceback (most recent call last):
641 ValueError: no common changegroup version
665 ValueError: no common changegroup version
642 #else
666 #else
643 $ cat $TESTTMP/errors.log
667 $ cat $TESTTMP/errors.log
644 #endif
668 #endif
General Comments 0
You need to be logged in to leave comments. Login now