##// END OF EJS Templates
largefiles: drop --cache-largefiles again...
Mads Kiilerich -
r18980:9717a326 default
parent child Browse files
Show More
@@ -1,123 +1,121 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''track large binary files
10 10
11 11 Large binary files tend to be not very compressible, not very
12 12 diffable, and not at all mergeable. Such files are not handled
13 13 efficiently by Mercurial's storage format (revlog), which is based on
14 14 compressed binary deltas; storing large binary files as regular
15 15 Mercurial files wastes bandwidth and disk space and increases
16 16 Mercurial's memory usage. The largefiles extension addresses these
17 17 problems by adding a centralized client-server layer on top of
18 18 Mercurial: largefiles live in a *central store* out on the network
19 19 somewhere, and you only fetch the revisions that you need when you
20 20 need them.
21 21
22 22 largefiles works by maintaining a "standin file" in .hglf/ for each
23 23 largefile. The standins are small (41 bytes: an SHA-1 hash plus
24 24 newline) and are tracked by Mercurial. Largefile revisions are
25 25 identified by the SHA-1 hash of their contents, which is written to
26 26 the standin. largefiles uses that revision ID to get/put largefile
27 27 revisions from/to the central store. This saves both disk space and
28 28 bandwidth, since you don't need to retrieve all historical revisions
29 29 of large files when you clone or pull.
30 30
31 31 To start a new repository or add new large binary files, just add
32 32 --large to your :hg:`add` command. For example::
33 33
34 34 $ dd if=/dev/urandom of=randomdata count=2000
35 35 $ hg add --large randomdata
36 36 $ hg commit -m 'add randomdata as a largefile'
37 37
38 38 When you push a changeset that adds/modifies largefiles to a remote
39 39 repository, its largefile revisions will be uploaded along with it.
40 40 Note that the remote Mercurial must also have the largefiles extension
41 41 enabled for this to work.
42 42
43 43 When you pull a changeset that affects largefiles from a remote
44 44 repository, the largefiles for the changeset will by default not be
45 45 pulled down. However, when you update to such a revision, any
46 46 largefiles needed by that revision are downloaded and cached (if
47 47 they have never been downloaded before). One way to pull largefiles
48 48 when pulling is thus to use --update, which will update your working
49 49 copy to the latest pulled revision (and thereby downloading any new
50 50 largefiles).
51 51
52 52 If you want to pull largefiles you don't need for update yet, then
53 53 you can use pull with the `--lfrev` option or the :hg:`lfpull` command.
54 54
55 55 If you know you are pulling from a non-default location and want do
56 56 download all the largefiles that corresponds to the new changesets at
57 57 the same time, then you can pull with `--lfrev "pulled()"`.
58 58
59 59 If you just want to ensure that you will have the largefiles needed to
60 60 merge or rebase with new heads that you are pulling, then you can pull
61 61 with `--lfrev "head(pulled())"` flag to pre-emptively download any largefiles
62 that are new in the heads you are pulling. You can also pull with the
63 `--cache-largefiles` flag to pre-emptively download any largefiles
64 62 that are new in the heads you are pulling.
65 63
66 64 Keep in mind that network access may now be required to update to
67 65 changesets that you have not previously updated to. The nature of the
68 66 largefiles extension means that updating is no longer guaranteed to
69 67 be a local-only operation.
70 68
71 69 If you already have large files tracked by Mercurial without the
72 70 largefiles extension, you will need to convert your repository in
73 71 order to benefit from largefiles. This is done with the
74 72 :hg:`lfconvert` command::
75 73
76 74 $ hg lfconvert --size 10 oldrepo newrepo
77 75
78 76 In repositories that already have largefiles in them, any new file
79 77 over 10MB will automatically be added as a largefile. To change this
80 78 threshold, set ``largefiles.minsize`` in your Mercurial config file
81 79 to the minimum size in megabytes to track as a largefile, or use the
82 80 --lfsize option to the add command (also in megabytes)::
83 81
84 82 [largefiles]
85 83 minsize = 2
86 84
87 85 $ hg add --lfsize 2
88 86
89 87 The ``largefiles.patterns`` config option allows you to specify a list
90 88 of filename patterns (see :hg:`help patterns`) that should always be
91 89 tracked as largefiles::
92 90
93 91 [largefiles]
94 92 patterns =
95 93 *.jpg
96 94 re:.*\.(png|bmp)$
97 95 library.zip
98 96 content/audio/*
99 97
100 98 Files that match one of these patterns will be added as largefiles
101 99 regardless of their size.
102 100
103 101 The ``largefiles.minsize`` and ``largefiles.patterns`` config options
104 102 will be ignored for any repositories not already containing a
105 103 largefile. To add the first largefile to a repository, you must
106 104 explicitly do so with the --large flag passed to the :hg:`add`
107 105 command.
108 106 '''
109 107
110 108 from mercurial import commands
111 109
112 110 import lfcommands
113 111 import reposetup
114 112 import uisetup
115 113
116 114 testedwith = 'internal'
117 115
118 116 reposetup = reposetup.reposetup
119 117 uisetup = uisetup.uisetup
120 118
121 119 commands.norepo += " lfconvert"
122 120
123 121 cmdtable = lfcommands.cmdtable
@@ -1,427 +1,419 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''largefiles utility code: must not import other modules in this package.'''
10 10
11 11 import os
12 12 import errno
13 13 import platform
14 14 import shutil
15 15 import stat
16 16
17 17 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 18 from mercurial.i18n import _
19 19
20 20 shortname = '.hglf'
21 21 shortnameslash = shortname + '/'
22 22 longname = 'largefiles'
23 23
24 24
25 25 # -- Private worker functions ------------------------------------------
26 26
27 27 def getminsize(ui, assumelfiles, opt, default=10):
28 28 lfsize = opt
29 29 if not lfsize and assumelfiles:
30 30 lfsize = ui.config(longname, 'minsize', default=default)
31 31 if lfsize:
32 32 try:
33 33 lfsize = float(lfsize)
34 34 except ValueError:
35 35 raise util.Abort(_('largefiles: size must be number (not %s)\n')
36 36 % lfsize)
37 37 if lfsize is None:
38 38 raise util.Abort(_('minimum size for largefiles must be specified'))
39 39 return lfsize
40 40
41 41 def link(src, dest):
42 42 try:
43 43 util.oslink(src, dest)
44 44 except OSError:
45 45 # if hardlinks fail, fallback on atomic copy
46 46 dst = util.atomictempfile(dest)
47 47 for chunk in util.filechunkiter(open(src, 'rb')):
48 48 dst.write(chunk)
49 49 dst.close()
50 50 os.chmod(dest, os.stat(src).st_mode)
51 51
52 52 def usercachepath(ui, hash):
53 53 path = ui.configpath(longname, 'usercache', None)
54 54 if path:
55 55 path = os.path.join(path, hash)
56 56 else:
57 57 if os.name == 'nt':
58 58 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
59 59 if appdata:
60 60 path = os.path.join(appdata, longname, hash)
61 61 elif platform.system() == 'Darwin':
62 62 home = os.getenv('HOME')
63 63 if home:
64 64 path = os.path.join(home, 'Library', 'Caches',
65 65 longname, hash)
66 66 elif os.name == 'posix':
67 67 path = os.getenv('XDG_CACHE_HOME')
68 68 if path:
69 69 path = os.path.join(path, longname, hash)
70 70 else:
71 71 home = os.getenv('HOME')
72 72 if home:
73 73 path = os.path.join(home, '.cache', longname, hash)
74 74 else:
75 75 raise util.Abort(_('unknown operating system: %s\n') % os.name)
76 76 return path
77 77
78 78 def inusercache(ui, hash):
79 79 path = usercachepath(ui, hash)
80 80 return path and os.path.exists(path)
81 81
82 82 def findfile(repo, hash):
83 83 if instore(repo, hash):
84 84 repo.ui.note(_('found %s in store\n') % hash)
85 85 return storepath(repo, hash)
86 86 elif inusercache(repo.ui, hash):
87 87 repo.ui.note(_('found %s in system cache\n') % hash)
88 88 path = storepath(repo, hash)
89 89 util.makedirs(os.path.dirname(path))
90 90 link(usercachepath(repo.ui, hash), path)
91 91 return path
92 92 return None
93 93
94 94 class largefilesdirstate(dirstate.dirstate):
95 95 def __getitem__(self, key):
96 96 return super(largefilesdirstate, self).__getitem__(unixpath(key))
97 97 def normal(self, f):
98 98 return super(largefilesdirstate, self).normal(unixpath(f))
99 99 def remove(self, f):
100 100 return super(largefilesdirstate, self).remove(unixpath(f))
101 101 def add(self, f):
102 102 return super(largefilesdirstate, self).add(unixpath(f))
103 103 def drop(self, f):
104 104 return super(largefilesdirstate, self).drop(unixpath(f))
105 105 def forget(self, f):
106 106 return super(largefilesdirstate, self).forget(unixpath(f))
107 107 def normallookup(self, f):
108 108 return super(largefilesdirstate, self).normallookup(unixpath(f))
109 109 def _ignore(self):
110 110 return False
111 111
112 112 def openlfdirstate(ui, repo, create=True):
113 113 '''
114 114 Return a dirstate object that tracks largefiles: i.e. its root is
115 115 the repo root, but it is saved in .hg/largefiles/dirstate.
116 116 '''
117 117 lfstoredir = repo.join(longname)
118 118 opener = scmutil.opener(lfstoredir)
119 119 lfdirstate = largefilesdirstate(opener, ui, repo.root,
120 120 repo.dirstate._validate)
121 121
122 122 # If the largefiles dirstate does not exist, populate and create
123 123 # it. This ensures that we create it on the first meaningful
124 124 # largefiles operation in a new clone.
125 125 if create and not os.path.exists(os.path.join(lfstoredir, 'dirstate')):
126 126 util.makedirs(lfstoredir)
127 127 matcher = getstandinmatcher(repo)
128 128 for standin in repo.dirstate.walk(matcher, [], False, False):
129 129 lfile = splitstandin(standin)
130 130 hash = readstandin(repo, lfile)
131 131 lfdirstate.normallookup(lfile)
132 132 try:
133 133 if hash == hashfile(repo.wjoin(lfile)):
134 134 lfdirstate.normal(lfile)
135 135 except OSError, err:
136 136 if err.errno != errno.ENOENT:
137 137 raise
138 138 return lfdirstate
139 139
140 140 def lfdirstatestatus(lfdirstate, repo, rev):
141 141 match = match_.always(repo.root, repo.getcwd())
142 142 s = lfdirstate.status(match, [], False, False, False)
143 143 unsure, modified, added, removed, missing, unknown, ignored, clean = s
144 144 for lfile in unsure:
145 145 try:
146 146 fctx = repo[rev][standin(lfile)]
147 147 except LookupError:
148 148 fctx = None
149 149 if not fctx or fctx.data().strip() != hashfile(repo.wjoin(lfile)):
150 150 modified.append(lfile)
151 151 else:
152 152 clean.append(lfile)
153 153 lfdirstate.normal(lfile)
154 154 return (modified, added, removed, missing, unknown, ignored, clean)
155 155
156 156 def listlfiles(repo, rev=None, matcher=None):
157 157 '''return a list of largefiles in the working copy or the
158 158 specified changeset'''
159 159
160 160 if matcher is None:
161 161 matcher = getstandinmatcher(repo)
162 162
163 163 # ignore unknown files in working directory
164 164 return [splitstandin(f)
165 165 for f in repo[rev].walk(matcher)
166 166 if rev is not None or repo.dirstate[f] != '?']
167 167
168 168 def instore(repo, hash):
169 169 return os.path.exists(storepath(repo, hash))
170 170
171 171 def storepath(repo, hash):
172 172 return repo.join(os.path.join(longname, hash))
173 173
174 174 def copyfromcache(repo, hash, filename):
175 175 '''Copy the specified largefile from the repo or system cache to
176 176 filename in the repository. Return true on success or false if the
177 177 file was not found in either cache (which should not happened:
178 178 this is meant to be called only after ensuring that the needed
179 179 largefile exists in the cache).'''
180 180 path = findfile(repo, hash)
181 181 if path is None:
182 182 return False
183 183 util.makedirs(os.path.dirname(repo.wjoin(filename)))
184 184 # The write may fail before the file is fully written, but we
185 185 # don't use atomic writes in the working copy.
186 186 shutil.copy(path, repo.wjoin(filename))
187 187 return True
188 188
189 189 def copytostore(repo, rev, file, uploaded=False):
190 190 hash = readstandin(repo, file, rev)
191 191 if instore(repo, hash):
192 192 return
193 193 copytostoreabsolute(repo, repo.wjoin(file), hash)
194 194
195 195 def copyalltostore(repo, node):
196 196 '''Copy all largefiles in a given revision to the store'''
197 197
198 198 ctx = repo[node]
199 199 for filename in ctx.files():
200 200 if isstandin(filename) and filename in ctx.manifest():
201 201 realfile = splitstandin(filename)
202 202 copytostore(repo, ctx.node(), realfile)
203 203
204 204
205 205 def copytostoreabsolute(repo, file, hash):
206 206 util.makedirs(os.path.dirname(storepath(repo, hash)))
207 207 if inusercache(repo.ui, hash):
208 208 link(usercachepath(repo.ui, hash), storepath(repo, hash))
209 209 elif not getattr(repo, "_isconverting", False):
210 210 dst = util.atomictempfile(storepath(repo, hash),
211 211 createmode=repo.store.createmode)
212 212 for chunk in util.filechunkiter(open(file, 'rb')):
213 213 dst.write(chunk)
214 214 dst.close()
215 215 linktousercache(repo, hash)
216 216
217 217 def linktousercache(repo, hash):
218 218 path = usercachepath(repo.ui, hash)
219 219 if path:
220 220 util.makedirs(os.path.dirname(path))
221 221 link(storepath(repo, hash), path)
222 222
223 223 def getstandinmatcher(repo, pats=[], opts={}):
224 224 '''Return a match object that applies pats to the standin directory'''
225 225 standindir = repo.wjoin(shortname)
226 226 if pats:
227 227 pats = [os.path.join(standindir, pat) for pat in pats]
228 228 else:
229 229 # no patterns: relative to repo root
230 230 pats = [standindir]
231 231 # no warnings about missing files or directories
232 232 match = scmutil.match(repo[None], pats, opts)
233 233 match.bad = lambda f, msg: None
234 234 return match
235 235
236 236 def composestandinmatcher(repo, rmatcher):
237 237 '''Return a matcher that accepts standins corresponding to the
238 238 files accepted by rmatcher. Pass the list of files in the matcher
239 239 as the paths specified by the user.'''
240 240 smatcher = getstandinmatcher(repo, rmatcher.files())
241 241 isstandin = smatcher.matchfn
242 242 def composedmatchfn(f):
243 243 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
244 244 smatcher.matchfn = composedmatchfn
245 245
246 246 return smatcher
247 247
248 248 def standin(filename):
249 249 '''Return the repo-relative path to the standin for the specified big
250 250 file.'''
251 251 # Notes:
252 252 # 1) Some callers want an absolute path, but for instance addlargefiles
253 253 # needs it repo-relative so it can be passed to repo[None].add(). So
254 254 # leave it up to the caller to use repo.wjoin() to get an absolute path.
255 255 # 2) Join with '/' because that's what dirstate always uses, even on
256 256 # Windows. Change existing separator to '/' first in case we are
257 257 # passed filenames from an external source (like the command line).
258 258 return shortnameslash + util.pconvert(filename)
259 259
260 260 def isstandin(filename):
261 261 '''Return true if filename is a big file standin. filename must be
262 262 in Mercurial's internal form (slash-separated).'''
263 263 return filename.startswith(shortnameslash)
264 264
265 265 def splitstandin(filename):
266 266 # Split on / because that's what dirstate always uses, even on Windows.
267 267 # Change local separator to / first just in case we are passed filenames
268 268 # from an external source (like the command line).
269 269 bits = util.pconvert(filename).split('/', 1)
270 270 if len(bits) == 2 and bits[0] == shortname:
271 271 return bits[1]
272 272 else:
273 273 return None
274 274
275 275 def updatestandin(repo, standin):
276 276 file = repo.wjoin(splitstandin(standin))
277 277 if os.path.exists(file):
278 278 hash = hashfile(file)
279 279 executable = getexecutable(file)
280 280 writestandin(repo, standin, hash, executable)
281 281
282 282 def readstandin(repo, filename, node=None):
283 283 '''read hex hash from standin for filename at given node, or working
284 284 directory if no node is given'''
285 285 return repo[node][standin(filename)].data().strip()
286 286
287 287 def writestandin(repo, standin, hash, executable):
288 288 '''write hash to <repo.root>/<standin>'''
289 289 writehash(hash, repo.wjoin(standin), executable)
290 290
291 291 def copyandhash(instream, outfile):
292 292 '''Read bytes from instream (iterable) and write them to outfile,
293 293 computing the SHA-1 hash of the data along the way. Close outfile
294 294 when done and return the binary hash.'''
295 295 hasher = util.sha1('')
296 296 for data in instream:
297 297 hasher.update(data)
298 298 outfile.write(data)
299 299
300 300 # Blecch: closing a file that somebody else opened is rude and
301 301 # wrong. But it's so darn convenient and practical! After all,
302 302 # outfile was opened just to copy and hash.
303 303 outfile.close()
304 304
305 305 return hasher.digest()
306 306
307 307 def hashrepofile(repo, file):
308 308 return hashfile(repo.wjoin(file))
309 309
310 310 def hashfile(file):
311 311 if not os.path.exists(file):
312 312 return ''
313 313 hasher = util.sha1('')
314 314 fd = open(file, 'rb')
315 315 for data in blockstream(fd):
316 316 hasher.update(data)
317 317 fd.close()
318 318 return hasher.hexdigest()
319 319
320 320 class limitreader(object):
321 321 def __init__(self, f, limit):
322 322 self.f = f
323 323 self.limit = limit
324 324
325 325 def read(self, length):
326 326 if self.limit == 0:
327 327 return ''
328 328 length = length > self.limit and self.limit or length
329 329 self.limit -= length
330 330 return self.f.read(length)
331 331
332 332 def close(self):
333 333 pass
334 334
335 335 def blockstream(infile, blocksize=128 * 1024):
336 336 """Generator that yields blocks of data from infile and closes infile."""
337 337 while True:
338 338 data = infile.read(blocksize)
339 339 if not data:
340 340 break
341 341 yield data
342 342 # same blecch as copyandhash() above
343 343 infile.close()
344 344
345 345 def writehash(hash, filename, executable):
346 346 util.makedirs(os.path.dirname(filename))
347 347 util.writefile(filename, hash + '\n')
348 348 os.chmod(filename, getmode(executable))
349 349
350 350 def getexecutable(filename):
351 351 mode = os.stat(filename).st_mode
352 352 return ((mode & stat.S_IXUSR) and
353 353 (mode & stat.S_IXGRP) and
354 354 (mode & stat.S_IXOTH))
355 355
356 356 def getmode(executable):
357 357 if executable:
358 358 return 0755
359 359 else:
360 360 return 0644
361 361
362 362 def urljoin(first, second, *arg):
363 363 def join(left, right):
364 364 if not left.endswith('/'):
365 365 left += '/'
366 366 if right.startswith('/'):
367 367 right = right[1:]
368 368 return left + right
369 369
370 370 url = join(first, second)
371 371 for a in arg:
372 372 url = join(url, a)
373 373 return url
374 374
375 375 def hexsha1(data):
376 376 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
377 377 object data"""
378 378 h = util.sha1()
379 379 for chunk in util.filechunkiter(data):
380 380 h.update(chunk)
381 381 return h.hexdigest()
382 382
383 383 def httpsendfile(ui, filename):
384 384 return httpconnection.httpsendfile(ui, filename, 'rb')
385 385
386 386 def unixpath(path):
387 387 '''Return a version of path normalized for use with the lfdirstate.'''
388 388 return util.pconvert(os.path.normpath(path))
389 389
390 390 def islfilesrepo(repo):
391 391 if ('largefiles' in repo.requirements and
392 392 util.any(shortnameslash in f[0] for f in repo.store.datafiles())):
393 393 return True
394 394
395 395 return util.any(openlfdirstate(repo.ui, repo, False))
396 396
397 397 class storeprotonotcapable(Exception):
398 398 def __init__(self, storetypes):
399 399 self.storetypes = storetypes
400 400
401 def getcurrentheads(repo):
402 branches = repo.branchmap()
403 heads = []
404 for branch in branches:
405 newheads = repo.branchheads(branch)
406 heads = heads + newheads
407 return heads
408
409 401 def getstandinsstate(repo):
410 402 standins = []
411 403 matcher = getstandinmatcher(repo)
412 404 for standin in repo.dirstate.walk(matcher, [], False, False):
413 405 lfile = splitstandin(standin)
414 406 try:
415 407 hash = readstandin(repo, lfile)
416 408 except IOError:
417 409 hash = None
418 410 standins.append((lfile, hash))
419 411 return standins
420 412
421 413 def getlfilestoupdate(oldstandins, newstandins):
422 414 changedstandins = set(oldstandins).symmetric_difference(set(newstandins))
423 415 filelist = []
424 416 for f in changedstandins:
425 417 if f[0] not in filelist:
426 418 filelist.append(f[0])
427 419 return filelist
@@ -1,1233 +1,1217 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''Overridden Mercurial commands and functions for the largefiles extension'''
10 10
11 11 import os
12 12 import copy
13 13
14 14 from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \
15 15 node, archival, error, merge, discovery
16 16 from mercurial.i18n import _
17 17 from mercurial.node import hex
18 18 from hgext import rebase
19 19
20 20 import lfutil
21 21 import lfcommands
22 22 import basestore
23 23
24 24 # -- Utility functions: commonly/repeatedly needed functionality ---------------
25 25
26 26 def installnormalfilesmatchfn(manifest):
27 27 '''overrides scmutil.match so that the matcher it returns will ignore all
28 28 largefiles'''
29 29 oldmatch = None # for the closure
30 30 def overridematch(ctx, pats=[], opts={}, globbed=False,
31 31 default='relpath'):
32 32 match = oldmatch(ctx, pats, opts, globbed, default)
33 33 m = copy.copy(match)
34 34 notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
35 35 manifest)
36 36 m._files = filter(notlfile, m._files)
37 37 m._fmap = set(m._files)
38 38 m._always = False
39 39 origmatchfn = m.matchfn
40 40 m.matchfn = lambda f: notlfile(f) and origmatchfn(f) or None
41 41 return m
42 42 oldmatch = installmatchfn(overridematch)
43 43
44 44 def installmatchfn(f):
45 45 oldmatch = scmutil.match
46 46 setattr(f, 'oldmatch', oldmatch)
47 47 scmutil.match = f
48 48 return oldmatch
49 49
50 50 def restorematchfn():
51 51 '''restores scmutil.match to what it was before installnormalfilesmatchfn
52 52 was called. no-op if scmutil.match is its original function.
53 53
54 54 Note that n calls to installnormalfilesmatchfn will require n calls to
55 55 restore matchfn to reverse'''
56 56 scmutil.match = getattr(scmutil.match, 'oldmatch', scmutil.match)
57 57
58 58 def addlargefiles(ui, repo, *pats, **opts):
59 59 large = opts.pop('large', None)
60 60 lfsize = lfutil.getminsize(
61 61 ui, lfutil.islfilesrepo(repo), opts.pop('lfsize', None))
62 62
63 63 lfmatcher = None
64 64 if lfutil.islfilesrepo(repo):
65 65 lfpats = ui.configlist(lfutil.longname, 'patterns', default=[])
66 66 if lfpats:
67 67 lfmatcher = match_.match(repo.root, '', list(lfpats))
68 68
69 69 lfnames = []
70 70 m = scmutil.match(repo[None], pats, opts)
71 71 m.bad = lambda x, y: None
72 72 wctx = repo[None]
73 73 for f in repo.walk(m):
74 74 exact = m.exact(f)
75 75 lfile = lfutil.standin(f) in wctx
76 76 nfile = f in wctx
77 77 exists = lfile or nfile
78 78
79 79 # Don't warn the user when they attempt to add a normal tracked file.
80 80 # The normal add code will do that for us.
81 81 if exact and exists:
82 82 if lfile:
83 83 ui.warn(_('%s already a largefile\n') % f)
84 84 continue
85 85
86 86 if (exact or not exists) and not lfutil.isstandin(f):
87 87 wfile = repo.wjoin(f)
88 88
89 89 # In case the file was removed previously, but not committed
90 90 # (issue3507)
91 91 if not os.path.exists(wfile):
92 92 continue
93 93
94 94 abovemin = (lfsize and
95 95 os.lstat(wfile).st_size >= lfsize * 1024 * 1024)
96 96 if large or abovemin or (lfmatcher and lfmatcher(f)):
97 97 lfnames.append(f)
98 98 if ui.verbose or not exact:
99 99 ui.status(_('adding %s as a largefile\n') % m.rel(f))
100 100
101 101 bad = []
102 102 standins = []
103 103
104 104 # Need to lock, otherwise there could be a race condition between
105 105 # when standins are created and added to the repo.
106 106 wlock = repo.wlock()
107 107 try:
108 108 if not opts.get('dry_run'):
109 109 lfdirstate = lfutil.openlfdirstate(ui, repo)
110 110 for f in lfnames:
111 111 standinname = lfutil.standin(f)
112 112 lfutil.writestandin(repo, standinname, hash='',
113 113 executable=lfutil.getexecutable(repo.wjoin(f)))
114 114 standins.append(standinname)
115 115 if lfdirstate[f] == 'r':
116 116 lfdirstate.normallookup(f)
117 117 else:
118 118 lfdirstate.add(f)
119 119 lfdirstate.write()
120 120 bad += [lfutil.splitstandin(f)
121 121 for f in repo[None].add(standins)
122 122 if f in m.files()]
123 123 finally:
124 124 wlock.release()
125 125 return bad
126 126
127 127 def removelargefiles(ui, repo, *pats, **opts):
128 128 after = opts.get('after')
129 129 if not pats and not after:
130 130 raise util.Abort(_('no files specified'))
131 131 m = scmutil.match(repo[None], pats, opts)
132 132 try:
133 133 repo.lfstatus = True
134 134 s = repo.status(match=m, clean=True)
135 135 finally:
136 136 repo.lfstatus = False
137 137 manifest = repo[None].manifest()
138 138 modified, added, deleted, clean = [[f for f in list
139 139 if lfutil.standin(f) in manifest]
140 140 for list in [s[0], s[1], s[3], s[6]]]
141 141
142 142 def warn(files, msg):
143 143 for f in files:
144 144 ui.warn(msg % m.rel(f))
145 145 return int(len(files) > 0)
146 146
147 147 result = 0
148 148
149 149 if after:
150 150 remove, forget = deleted, []
151 151 result = warn(modified + added + clean,
152 152 _('not removing %s: file still exists\n'))
153 153 else:
154 154 remove, forget = deleted + clean, []
155 155 result = warn(modified, _('not removing %s: file is modified (use -f'
156 156 ' to force removal)\n'))
157 157 result = warn(added, _('not removing %s: file has been marked for add'
158 158 ' (use forget to undo)\n')) or result
159 159
160 160 for f in sorted(remove + forget):
161 161 if ui.verbose or not m.exact(f):
162 162 ui.status(_('removing %s\n') % m.rel(f))
163 163
164 164 # Need to lock because standin files are deleted then removed from the
165 165 # repository and we could race in-between.
166 166 wlock = repo.wlock()
167 167 try:
168 168 lfdirstate = lfutil.openlfdirstate(ui, repo)
169 169 for f in remove:
170 170 if not after:
171 171 # If this is being called by addremove, notify the user that we
172 172 # are removing the file.
173 173 if getattr(repo, "_isaddremove", False):
174 174 ui.status(_('removing %s\n') % f)
175 175 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
176 176 lfdirstate.remove(f)
177 177 lfdirstate.write()
178 178 forget = [lfutil.standin(f) for f in forget]
179 179 remove = [lfutil.standin(f) for f in remove]
180 180 repo[None].forget(forget)
181 181 # If this is being called by addremove, let the original addremove
182 182 # function handle this.
183 183 if not getattr(repo, "_isaddremove", False):
184 184 for f in remove:
185 185 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
186 186 repo[None].forget(remove)
187 187 finally:
188 188 wlock.release()
189 189
190 190 return result
191 191
192 192 # For overriding mercurial.hgweb.webcommands so that largefiles will
193 193 # appear at their right place in the manifests.
194 194 def decodepath(orig, path):
195 195 return lfutil.splitstandin(path) or path
196 196
197 197 # -- Wrappers: modify existing commands --------------------------------
198 198
199 199 # Add works by going through the files that the user wanted to add and
200 200 # checking if they should be added as largefiles. Then it makes a new
201 201 # matcher which matches only the normal files and runs the original
202 202 # version of add.
203 203 def overrideadd(orig, ui, repo, *pats, **opts):
204 204 normal = opts.pop('normal')
205 205 if normal:
206 206 if opts.get('large'):
207 207 raise util.Abort(_('--normal cannot be used with --large'))
208 208 return orig(ui, repo, *pats, **opts)
209 209 bad = addlargefiles(ui, repo, *pats, **opts)
210 210 installnormalfilesmatchfn(repo[None].manifest())
211 211 result = orig(ui, repo, *pats, **opts)
212 212 restorematchfn()
213 213
214 214 return (result == 1 or bad) and 1 or 0
215 215
216 216 def overrideremove(orig, ui, repo, *pats, **opts):
217 217 installnormalfilesmatchfn(repo[None].manifest())
218 218 result = orig(ui, repo, *pats, **opts)
219 219 restorematchfn()
220 220 return removelargefiles(ui, repo, *pats, **opts) or result
221 221
222 222 def overridestatusfn(orig, repo, rev2, **opts):
223 223 try:
224 224 repo._repo.lfstatus = True
225 225 return orig(repo, rev2, **opts)
226 226 finally:
227 227 repo._repo.lfstatus = False
228 228
229 229 def overridestatus(orig, ui, repo, *pats, **opts):
230 230 try:
231 231 repo.lfstatus = True
232 232 return orig(ui, repo, *pats, **opts)
233 233 finally:
234 234 repo.lfstatus = False
235 235
236 236 def overridedirty(orig, repo, ignoreupdate=False):
237 237 try:
238 238 repo._repo.lfstatus = True
239 239 return orig(repo, ignoreupdate)
240 240 finally:
241 241 repo._repo.lfstatus = False
242 242
243 243 def overridelog(orig, ui, repo, *pats, **opts):
244 244 def overridematch(ctx, pats=[], opts={}, globbed=False,
245 245 default='relpath'):
246 246 """Matcher that merges root directory with .hglf, suitable for log.
247 247 It is still possible to match .hglf directly.
248 248 For any listed files run log on the standin too.
249 249 matchfn tries both the given filename and with .hglf stripped.
250 250 """
251 251 match = oldmatch(ctx, pats, opts, globbed, default)
252 252 m = copy.copy(match)
253 253 standins = [lfutil.standin(f) for f in m._files]
254 254 m._files.extend(standins)
255 255 m._fmap = set(m._files)
256 256 m._always = False
257 257 origmatchfn = m.matchfn
258 258 def lfmatchfn(f):
259 259 lf = lfutil.splitstandin(f)
260 260 if lf is not None and origmatchfn(lf):
261 261 return True
262 262 r = origmatchfn(f)
263 263 return r
264 264 m.matchfn = lfmatchfn
265 265 return m
266 266 oldmatch = installmatchfn(overridematch)
267 267 try:
268 268 repo.lfstatus = True
269 269 return orig(ui, repo, *pats, **opts)
270 270 finally:
271 271 repo.lfstatus = False
272 272 restorematchfn()
273 273
274 274 def overrideverify(orig, ui, repo, *pats, **opts):
275 275 large = opts.pop('large', False)
276 276 all = opts.pop('lfa', False)
277 277 contents = opts.pop('lfc', False)
278 278
279 279 result = orig(ui, repo, *pats, **opts)
280 280 if large or all or contents:
281 281 result = result or lfcommands.verifylfiles(ui, repo, all, contents)
282 282 return result
283 283
284 284 def overridedebugstate(orig, ui, repo, *pats, **opts):
285 285 large = opts.pop('large', False)
286 286 if large:
287 287 lfcommands.debugdirstate(ui, repo)
288 288 else:
289 289 orig(ui, repo, *pats, **opts)
290 290
291 291 # Override needs to refresh standins so that update's normal merge
292 292 # will go through properly. Then the other update hook (overriding repo.update)
293 293 # will get the new files. Filemerge is also overridden so that the merge
294 294 # will merge standins correctly.
295 295 def overrideupdate(orig, ui, repo, *pats, **opts):
296 296 lfdirstate = lfutil.openlfdirstate(ui, repo)
297 297 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
298 298 False, False)
299 299 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
300 300
301 301 # Need to lock between the standins getting updated and their
302 302 # largefiles getting updated
303 303 wlock = repo.wlock()
304 304 try:
305 305 if opts['check']:
306 306 mod = len(modified) > 0
307 307 for lfile in unsure:
308 308 standin = lfutil.standin(lfile)
309 309 if repo['.'][standin].data().strip() != \
310 310 lfutil.hashfile(repo.wjoin(lfile)):
311 311 mod = True
312 312 else:
313 313 lfdirstate.normal(lfile)
314 314 lfdirstate.write()
315 315 if mod:
316 316 raise util.Abort(_('uncommitted local changes'))
317 317 # XXX handle removed differently
318 318 if not opts['clean']:
319 319 for lfile in unsure + modified + added:
320 320 lfutil.updatestandin(repo, lfutil.standin(lfile))
321 321 finally:
322 322 wlock.release()
323 323 return orig(ui, repo, *pats, **opts)
324 324
325 325 # Before starting the manifest merge, merge.updates will call
326 326 # _checkunknown to check if there are any files in the merged-in
327 327 # changeset that collide with unknown files in the working copy.
328 328 #
329 329 # The largefiles are seen as unknown, so this prevents us from merging
330 330 # in a file 'foo' if we already have a largefile with the same name.
331 331 #
332 332 # The overridden function filters the unknown files by removing any
333 333 # largefiles. This makes the merge proceed and we can then handle this
334 334 # case further in the overridden manifestmerge function below.
335 335 def overridecheckunknownfile(origfn, repo, wctx, mctx, f):
336 336 if lfutil.standin(f) in wctx:
337 337 return False
338 338 return origfn(repo, wctx, mctx, f)
339 339
340 340 # The manifest merge handles conflicts on the manifest level. We want
341 341 # to handle changes in largefile-ness of files at this level too.
342 342 #
343 343 # The strategy is to run the original manifestmerge and then process
344 344 # the action list it outputs. There are two cases we need to deal with:
345 345 #
346 346 # 1. Normal file in p1, largefile in p2. Here the largefile is
347 347 # detected via its standin file, which will enter the working copy
348 348 # with a "get" action. It is not "merge" since the standin is all
349 349 # Mercurial is concerned with at this level -- the link to the
350 350 # existing normal file is not relevant here.
351 351 #
352 352 # 2. Largefile in p1, normal file in p2. Here we get a "merge" action
353 353 # since the largefile will be present in the working copy and
354 354 # different from the normal file in p2. Mercurial therefore
355 355 # triggers a merge action.
356 356 #
357 357 # In both cases, we prompt the user and emit new actions to either
358 358 # remove the standin (if the normal file was kept) or to remove the
359 359 # normal file and get the standin (if the largefile was kept). The
360 360 # default prompt answer is to use the largefile version since it was
361 361 # presumably changed on purpose.
362 362 #
363 363 # Finally, the merge.applyupdates function will then take care of
364 364 # writing the files into the working copy and lfcommands.updatelfiles
365 365 # will update the largefiles.
366 366 def overridemanifestmerge(origfn, repo, p1, p2, pa, branchmerge, force,
367 367 partial, acceptremote=False):
368 368 overwrite = force and not branchmerge
369 369 actions = origfn(repo, p1, p2, pa, branchmerge, force, partial,
370 370 acceptremote)
371 371 processed = []
372 372
373 373 for action in actions:
374 374 if overwrite:
375 375 processed.append(action)
376 376 continue
377 377 f, m, args, msg = action
378 378
379 379 choices = (_('&Largefile'), _('&Normal file'))
380 380
381 381 splitstandin = lfutil.splitstandin(f)
382 382 if (m == "g" and splitstandin is not None and
383 383 splitstandin in p1 and f in p2):
384 384 # Case 1: normal file in the working copy, largefile in
385 385 # the second parent
386 386 lfile = splitstandin
387 387 standin = f
388 388 msg = _('%s has been turned into a largefile\n'
389 389 'use (l)argefile or keep as (n)ormal file?') % lfile
390 390 if repo.ui.promptchoice(msg, choices, 0) == 0:
391 391 processed.append((lfile, "r", None, msg))
392 392 processed.append((standin, "g", (p2.flags(standin),), msg))
393 393 else:
394 394 processed.append((standin, "r", None, msg))
395 395 elif m == "g" and lfutil.standin(f) in p1 and f in p2:
396 396 # Case 2: largefile in the working copy, normal file in
397 397 # the second parent
398 398 standin = lfutil.standin(f)
399 399 lfile = f
400 400 msg = _('%s has been turned into a normal file\n'
401 401 'keep as (l)argefile or use (n)ormal file?') % lfile
402 402 if repo.ui.promptchoice(msg, choices, 0) == 0:
403 403 processed.append((lfile, "r", None, msg))
404 404 else:
405 405 processed.append((standin, "r", None, msg))
406 406 processed.append((lfile, "g", (p2.flags(lfile),), msg))
407 407 else:
408 408 processed.append(action)
409 409
410 410 return processed
411 411
412 412 # Override filemerge to prompt the user about how they wish to merge
413 413 # largefiles. This will handle identical edits, and copy/rename +
414 414 # edit without prompting the user.
415 415 def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca):
416 416 # Use better variable names here. Because this is a wrapper we cannot
417 417 # change the variable names in the function declaration.
418 418 fcdest, fcother, fcancestor = fcd, fco, fca
419 419 if not lfutil.isstandin(orig):
420 420 return origfn(repo, mynode, orig, fcdest, fcother, fcancestor)
421 421 else:
422 422 if not fcother.cmp(fcdest): # files identical?
423 423 return None
424 424
425 425 # backwards, use working dir parent as ancestor
426 426 if fcancestor == fcother:
427 427 fcancestor = fcdest.parents()[0]
428 428
429 429 if orig != fcother.path():
430 430 repo.ui.status(_('merging %s and %s to %s\n')
431 431 % (lfutil.splitstandin(orig),
432 432 lfutil.splitstandin(fcother.path()),
433 433 lfutil.splitstandin(fcdest.path())))
434 434 else:
435 435 repo.ui.status(_('merging %s\n')
436 436 % lfutil.splitstandin(fcdest.path()))
437 437
438 438 if fcancestor.path() != fcother.path() and fcother.data() == \
439 439 fcancestor.data():
440 440 return 0
441 441 if fcancestor.path() != fcdest.path() and fcdest.data() == \
442 442 fcancestor.data():
443 443 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
444 444 return 0
445 445
446 446 if repo.ui.promptchoice(_('largefile %s has a merge conflict\n'
447 447 'keep (l)ocal or take (o)ther?') %
448 448 lfutil.splitstandin(orig),
449 449 (_('&Local'), _('&Other')), 0) == 0:
450 450 return 0
451 451 else:
452 452 repo.wwrite(fcdest.path(), fcother.data(), fcother.flags())
453 453 return 0
454 454
455 455 # Copy first changes the matchers to match standins instead of
456 456 # largefiles. Then it overrides util.copyfile in that function it
457 457 # checks if the destination largefile already exists. It also keeps a
458 458 # list of copied files so that the largefiles can be copied and the
459 459 # dirstate updated.
460 460 def overridecopy(orig, ui, repo, pats, opts, rename=False):
461 461 # doesn't remove largefile on rename
462 462 if len(pats) < 2:
463 463 # this isn't legal, let the original function deal with it
464 464 return orig(ui, repo, pats, opts, rename)
465 465
466 466 def makestandin(relpath):
467 467 path = scmutil.canonpath(repo.root, repo.getcwd(), relpath)
468 468 return os.path.join(repo.wjoin(lfutil.standin(path)))
469 469
470 470 fullpats = scmutil.expandpats(pats)
471 471 dest = fullpats[-1]
472 472
473 473 if os.path.isdir(dest):
474 474 if not os.path.isdir(makestandin(dest)):
475 475 os.makedirs(makestandin(dest))
476 476 # This could copy both lfiles and normal files in one command,
477 477 # but we don't want to do that. First replace their matcher to
478 478 # only match normal files and run it, then replace it to just
479 479 # match largefiles and run it again.
480 480 nonormalfiles = False
481 481 nolfiles = False
482 482 try:
483 483 try:
484 484 installnormalfilesmatchfn(repo[None].manifest())
485 485 result = orig(ui, repo, pats, opts, rename)
486 486 except util.Abort, e:
487 487 if str(e) != _('no files to copy'):
488 488 raise e
489 489 else:
490 490 nonormalfiles = True
491 491 result = 0
492 492 finally:
493 493 restorematchfn()
494 494
495 495 # The first rename can cause our current working directory to be removed.
496 496 # In that case there is nothing left to copy/rename so just quit.
497 497 try:
498 498 repo.getcwd()
499 499 except OSError:
500 500 return result
501 501
502 502 try:
503 503 try:
504 504 # When we call orig below it creates the standins but we don't add
505 505 # them to the dir state until later so lock during that time.
506 506 wlock = repo.wlock()
507 507
508 508 manifest = repo[None].manifest()
509 509 oldmatch = None # for the closure
510 510 def overridematch(ctx, pats=[], opts={}, globbed=False,
511 511 default='relpath'):
512 512 newpats = []
513 513 # The patterns were previously mangled to add the standin
514 514 # directory; we need to remove that now
515 515 for pat in pats:
516 516 if match_.patkind(pat) is None and lfutil.shortname in pat:
517 517 newpats.append(pat.replace(lfutil.shortname, ''))
518 518 else:
519 519 newpats.append(pat)
520 520 match = oldmatch(ctx, newpats, opts, globbed, default)
521 521 m = copy.copy(match)
522 522 lfile = lambda f: lfutil.standin(f) in manifest
523 523 m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
524 524 m._fmap = set(m._files)
525 525 m._always = False
526 526 origmatchfn = m.matchfn
527 527 m.matchfn = lambda f: (lfutil.isstandin(f) and
528 528 (f in manifest) and
529 529 origmatchfn(lfutil.splitstandin(f)) or
530 530 None)
531 531 return m
532 532 oldmatch = installmatchfn(overridematch)
533 533 listpats = []
534 534 for pat in pats:
535 535 if match_.patkind(pat) is not None:
536 536 listpats.append(pat)
537 537 else:
538 538 listpats.append(makestandin(pat))
539 539
540 540 try:
541 541 origcopyfile = util.copyfile
542 542 copiedfiles = []
543 543 def overridecopyfile(src, dest):
544 544 if (lfutil.shortname in src and
545 545 dest.startswith(repo.wjoin(lfutil.shortname))):
546 546 destlfile = dest.replace(lfutil.shortname, '')
547 547 if not opts['force'] and os.path.exists(destlfile):
548 548 raise IOError('',
549 549 _('destination largefile already exists'))
550 550 copiedfiles.append((src, dest))
551 551 origcopyfile(src, dest)
552 552
553 553 util.copyfile = overridecopyfile
554 554 result += orig(ui, repo, listpats, opts, rename)
555 555 finally:
556 556 util.copyfile = origcopyfile
557 557
558 558 lfdirstate = lfutil.openlfdirstate(ui, repo)
559 559 for (src, dest) in copiedfiles:
560 560 if (lfutil.shortname in src and
561 561 dest.startswith(repo.wjoin(lfutil.shortname))):
562 562 srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
563 563 destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
564 564 destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
565 565 if not os.path.isdir(destlfiledir):
566 566 os.makedirs(destlfiledir)
567 567 if rename:
568 568 os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
569 569 lfdirstate.remove(srclfile)
570 570 else:
571 571 util.copyfile(repo.wjoin(srclfile),
572 572 repo.wjoin(destlfile))
573 573
574 574 lfdirstate.add(destlfile)
575 575 lfdirstate.write()
576 576 except util.Abort, e:
577 577 if str(e) != _('no files to copy'):
578 578 raise e
579 579 else:
580 580 nolfiles = True
581 581 finally:
582 582 restorematchfn()
583 583 wlock.release()
584 584
585 585 if nolfiles and nonormalfiles:
586 586 raise util.Abort(_('no files to copy'))
587 587
588 588 return result
589 589
590 590 # When the user calls revert, we have to be careful to not revert any
591 591 # changes to other largefiles accidentally. This means we have to keep
592 592 # track of the largefiles that are being reverted so we only pull down
593 593 # the necessary largefiles.
594 594 #
595 595 # Standins are only updated (to match the hash of largefiles) before
596 596 # commits. Update the standins then run the original revert, changing
597 597 # the matcher to hit standins instead of largefiles. Based on the
598 598 # resulting standins update the largefiles. Then return the standins
599 599 # to their proper state
600 600 def overriderevert(orig, ui, repo, *pats, **opts):
601 601 # Because we put the standins in a bad state (by updating them)
602 602 # and then return them to a correct state we need to lock to
603 603 # prevent others from changing them in their incorrect state.
604 604 wlock = repo.wlock()
605 605 try:
606 606 lfdirstate = lfutil.openlfdirstate(ui, repo)
607 607 (modified, added, removed, missing, unknown, ignored, clean) = \
608 608 lfutil.lfdirstatestatus(lfdirstate, repo, repo['.'].rev())
609 609 lfdirstate.write()
610 610 for lfile in modified:
611 611 lfutil.updatestandin(repo, lfutil.standin(lfile))
612 612 for lfile in missing:
613 613 if (os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
614 614 os.unlink(repo.wjoin(lfutil.standin(lfile)))
615 615
616 616 try:
617 617 ctx = scmutil.revsingle(repo, opts.get('rev'))
618 618 oldmatch = None # for the closure
619 619 def overridematch(ctx, pats=[], opts={}, globbed=False,
620 620 default='relpath'):
621 621 match = oldmatch(ctx, pats, opts, globbed, default)
622 622 m = copy.copy(match)
623 623 def tostandin(f):
624 624 if lfutil.standin(f) in ctx:
625 625 return lfutil.standin(f)
626 626 elif lfutil.standin(f) in repo[None]:
627 627 return None
628 628 return f
629 629 m._files = [tostandin(f) for f in m._files]
630 630 m._files = [f for f in m._files if f is not None]
631 631 m._fmap = set(m._files)
632 632 m._always = False
633 633 origmatchfn = m.matchfn
634 634 def matchfn(f):
635 635 if lfutil.isstandin(f):
636 636 # We need to keep track of what largefiles are being
637 637 # matched so we know which ones to update later --
638 638 # otherwise we accidentally revert changes to other
639 639 # largefiles. This is repo-specific, so duckpunch the
640 640 # repo object to keep the list of largefiles for us
641 641 # later.
642 642 if origmatchfn(lfutil.splitstandin(f)) and \
643 643 (f in repo[None] or f in ctx):
644 644 lfileslist = getattr(repo, '_lfilestoupdate', [])
645 645 lfileslist.append(lfutil.splitstandin(f))
646 646 repo._lfilestoupdate = lfileslist
647 647 return True
648 648 else:
649 649 return False
650 650 return origmatchfn(f)
651 651 m.matchfn = matchfn
652 652 return m
653 653 oldmatch = installmatchfn(overridematch)
654 654 scmutil.match
655 655 matches = overridematch(repo[None], pats, opts)
656 656 orig(ui, repo, *pats, **opts)
657 657 finally:
658 658 restorematchfn()
659 659 lfileslist = getattr(repo, '_lfilestoupdate', [])
660 660 lfcommands.updatelfiles(ui, repo, filelist=lfileslist,
661 661 printmessage=False)
662 662
663 663 # empty out the largefiles list so we start fresh next time
664 664 repo._lfilestoupdate = []
665 665 for lfile in modified:
666 666 if lfile in lfileslist:
667 667 if os.path.exists(repo.wjoin(lfutil.standin(lfile))) and lfile\
668 668 in repo['.']:
669 669 lfutil.writestandin(repo, lfutil.standin(lfile),
670 670 repo['.'][lfile].data().strip(),
671 671 'x' in repo['.'][lfile].flags())
672 672 lfdirstate = lfutil.openlfdirstate(ui, repo)
673 673 for lfile in added:
674 674 standin = lfutil.standin(lfile)
675 675 if standin not in ctx and (standin in matches or opts.get('all')):
676 676 if lfile in lfdirstate:
677 677 lfdirstate.drop(lfile)
678 678 util.unlinkpath(repo.wjoin(standin))
679 679 lfdirstate.write()
680 680 finally:
681 681 wlock.release()
682 682
683 683 def hgupdaterepo(orig, repo, node, overwrite):
684 684 if not overwrite:
685 685 # Only call updatelfiles on the standins that have changed to save time
686 686 oldstandins = lfutil.getstandinsstate(repo)
687 687
688 688 result = orig(repo, node, overwrite)
689 689
690 690 filelist = None
691 691 if not overwrite:
692 692 newstandins = lfutil.getstandinsstate(repo)
693 693 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
694 694 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist)
695 695 return result
696 696
697 697 def hgmerge(orig, repo, node, force=None, remind=True):
698 698 result = orig(repo, node, force, remind)
699 699 lfcommands.updatelfiles(repo.ui, repo)
700 700 return result
701 701
702 702 # When we rebase a repository with remotely changed largefiles, we need to
703 703 # take some extra care so that the largefiles are correctly updated in the
704 704 # working copy
705 705 def overridepull(orig, ui, repo, source=None, **opts):
706 706 revsprepull = len(repo)
707 707 if not source:
708 708 source = 'default'
709 709 repo.lfpullsource = source
710 710 if opts.get('rebase', False):
711 711 repo._isrebasing = True
712 712 try:
713 713 if opts.get('update'):
714 714 del opts['update']
715 715 ui.debug('--update and --rebase are not compatible, ignoring '
716 716 'the update flag\n')
717 717 del opts['rebase']
718 718 cmdutil.bailifchanged(repo)
719 719 origpostincoming = commands.postincoming
720 720 def _dummy(*args, **kwargs):
721 721 pass
722 722 commands.postincoming = _dummy
723 723 try:
724 724 result = commands.pull(ui, repo, source, **opts)
725 725 finally:
726 726 commands.postincoming = origpostincoming
727 727 revspostpull = len(repo)
728 728 if revspostpull > revsprepull:
729 729 result = result or rebase.rebase(ui, repo)
730 730 finally:
731 731 repo._isrebasing = False
732 732 else:
733 oldheads = lfutil.getcurrentheads(repo)
734 733 result = orig(ui, repo, source, **opts)
735 if opts.get('cache_largefiles'):
736 # If you are pulling from a remote location that is not your
737 # default location, you may want to cache largefiles for new heads
738 # that have been pulled, so you can easily merge or rebase with
739 # them later
740 numcached = 0
741 heads = lfutil.getcurrentheads(repo)
742 newheads = set(heads).difference(set(oldheads))
743 if len(newheads) > 0:
744 ui.status(_("caching largefiles for %s heads\n") %
745 len(newheads))
746 for head in newheads:
747 (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
748 numcached += len(cached)
749 ui.status(_("%d largefiles cached\n") % numcached)
750 734 revspostpull = len(repo)
751 735 if opts.get('all_largefiles'):
752 736 revs = []
753 737 for rev in xrange(revsprepull, revspostpull):
754 738 revs.append(repo[rev].rev())
755 739 lfcommands.downloadlfiles(ui, repo, revs)
756 740 lfrevs = opts.get('lfrev', [])
757 741 if lfrevs and revspostpull > revsprepull:
758 742 numcached = 0
759 743 repo.firstpulled = revsprepull # for pulled() revset expression
760 744 try:
761 745 for rev in scmutil.revrange(repo, lfrevs):
762 746 ui.note(_('pulling largefiles for revision %s\n') % rev)
763 747 (cached, missing) = lfcommands.cachelfiles(ui, repo, rev)
764 748 numcached += len(cached)
765 749 finally:
766 750 del repo.firstpulled
767 751 ui.status(_("%d largefiles cached\n") % numcached)
768 752 return result
769 753
770 754 def pulledrevsetsymbol(repo, subset, x):
771 755 """``pulled()``
772 756 Changesets that just has been pulled.
773 757
774 758 Only available with largefiles from pull --lfrev expressions.
775 759
776 760 .. container:: verbose
777 761
778 762 Some examples:
779 763
780 764 - pull largefiles for all new changesets::
781 765
782 766 hg pull -lfrev "pulled()"
783 767
784 768 - pull largefiles for all new branch heads::
785 769
786 770 hg pull -lfrev "head(pulled()) and not closed()"
787 771
788 772 """
789 773
790 774 try:
791 775 firstpulled = repo.firstpulled
792 776 except AttributeError:
793 777 raise util.Abort(_("pulled() only available in --lfrev"))
794 778 return [r for r in subset if r >= firstpulled]
795 779
796 780 def overrideclone(orig, ui, source, dest=None, **opts):
797 781 d = dest
798 782 if d is None:
799 783 d = hg.defaultdest(source)
800 784 if opts.get('all_largefiles') and not hg.islocal(d):
801 785 raise util.Abort(_(
802 786 '--all-largefiles is incompatible with non-local destination %s' %
803 787 d))
804 788
805 789 return orig(ui, source, dest, **opts)
806 790
807 791 def hgclone(orig, ui, opts, *args, **kwargs):
808 792 result = orig(ui, opts, *args, **kwargs)
809 793
810 794 if result is not None:
811 795 sourcerepo, destrepo = result
812 796 repo = destrepo.local()
813 797
814 798 # Caching is implicitly limited to 'rev' option, since the dest repo was
815 799 # truncated at that point. The user may expect a download count with
816 800 # this option, so attempt whether or not this is a largefile repo.
817 801 if opts.get('all_largefiles'):
818 802 success, missing = lfcommands.downloadlfiles(ui, repo, None)
819 803
820 804 if missing != 0:
821 805 return None
822 806
823 807 return result
824 808
825 809 def overriderebase(orig, ui, repo, **opts):
826 810 repo._isrebasing = True
827 811 try:
828 812 return orig(ui, repo, **opts)
829 813 finally:
830 814 repo._isrebasing = False
831 815
832 816 def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
833 817 prefix=None, mtime=None, subrepos=None):
834 818 # No need to lock because we are only reading history and
835 819 # largefile caches, neither of which are modified.
836 820 lfcommands.cachelfiles(repo.ui, repo, node)
837 821
838 822 if kind not in archival.archivers:
839 823 raise util.Abort(_("unknown archive type '%s'") % kind)
840 824
841 825 ctx = repo[node]
842 826
843 827 if kind == 'files':
844 828 if prefix:
845 829 raise util.Abort(
846 830 _('cannot give prefix when archiving to files'))
847 831 else:
848 832 prefix = archival.tidyprefix(dest, kind, prefix)
849 833
850 834 def write(name, mode, islink, getdata):
851 835 if matchfn and not matchfn(name):
852 836 return
853 837 data = getdata()
854 838 if decode:
855 839 data = repo.wwritedata(name, data)
856 840 archiver.addfile(prefix + name, mode, islink, data)
857 841
858 842 archiver = archival.archivers[kind](dest, mtime or ctx.date()[0])
859 843
860 844 if repo.ui.configbool("ui", "archivemeta", True):
861 845 def metadata():
862 846 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
863 847 hex(repo.changelog.node(0)), hex(node), ctx.branch())
864 848
865 849 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
866 850 if repo.tagtype(t) == 'global')
867 851 if not tags:
868 852 repo.ui.pushbuffer()
869 853 opts = {'template': '{latesttag}\n{latesttagdistance}',
870 854 'style': '', 'patch': None, 'git': None}
871 855 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
872 856 ltags, dist = repo.ui.popbuffer().split('\n')
873 857 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
874 858 tags += 'latesttagdistance: %s\n' % dist
875 859
876 860 return base + tags
877 861
878 862 write('.hg_archival.txt', 0644, False, metadata)
879 863
880 864 for f in ctx:
881 865 ff = ctx.flags(f)
882 866 getdata = ctx[f].data
883 867 if lfutil.isstandin(f):
884 868 path = lfutil.findfile(repo, getdata().strip())
885 869 if path is None:
886 870 raise util.Abort(
887 871 _('largefile %s not found in repo store or system cache')
888 872 % lfutil.splitstandin(f))
889 873 f = lfutil.splitstandin(f)
890 874
891 875 def getdatafn():
892 876 fd = None
893 877 try:
894 878 fd = open(path, 'rb')
895 879 return fd.read()
896 880 finally:
897 881 if fd:
898 882 fd.close()
899 883
900 884 getdata = getdatafn
901 885 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
902 886
903 887 if subrepos:
904 888 for subpath in sorted(ctx.substate):
905 889 sub = ctx.sub(subpath)
906 890 submatch = match_.narrowmatcher(subpath, matchfn)
907 891 sub.archive(repo.ui, archiver, prefix, submatch)
908 892
909 893 archiver.done()
910 894
911 895 def hgsubrepoarchive(orig, repo, ui, archiver, prefix, match=None):
912 896 repo._get(repo._state + ('hg',))
913 897 rev = repo._state[1]
914 898 ctx = repo._repo[rev]
915 899
916 900 lfcommands.cachelfiles(ui, repo._repo, ctx.node())
917 901
918 902 def write(name, mode, islink, getdata):
919 903 # At this point, the standin has been replaced with the largefile name,
920 904 # so the normal matcher works here without the lfutil variants.
921 905 if match and not match(f):
922 906 return
923 907 data = getdata()
924 908
925 909 archiver.addfile(prefix + repo._path + '/' + name, mode, islink, data)
926 910
927 911 for f in ctx:
928 912 ff = ctx.flags(f)
929 913 getdata = ctx[f].data
930 914 if lfutil.isstandin(f):
931 915 path = lfutil.findfile(repo._repo, getdata().strip())
932 916 if path is None:
933 917 raise util.Abort(
934 918 _('largefile %s not found in repo store or system cache')
935 919 % lfutil.splitstandin(f))
936 920 f = lfutil.splitstandin(f)
937 921
938 922 def getdatafn():
939 923 fd = None
940 924 try:
941 925 fd = open(os.path.join(prefix, path), 'rb')
942 926 return fd.read()
943 927 finally:
944 928 if fd:
945 929 fd.close()
946 930
947 931 getdata = getdatafn
948 932
949 933 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, getdata)
950 934
951 935 for subpath in sorted(ctx.substate):
952 936 sub = ctx.sub(subpath)
953 937 submatch = match_.narrowmatcher(subpath, match)
954 938 sub.archive(ui, archiver, os.path.join(prefix, repo._path) + '/',
955 939 submatch)
956 940
957 941 # If a largefile is modified, the change is not reflected in its
958 942 # standin until a commit. cmdutil.bailifchanged() raises an exception
959 943 # if the repo has uncommitted changes. Wrap it to also check if
960 944 # largefiles were changed. This is used by bisect and backout.
961 945 def overridebailifchanged(orig, repo):
962 946 orig(repo)
963 947 repo.lfstatus = True
964 948 modified, added, removed, deleted = repo.status()[:4]
965 949 repo.lfstatus = False
966 950 if modified or added or removed or deleted:
967 951 raise util.Abort(_('outstanding uncommitted changes'))
968 952
969 953 # Fetch doesn't use cmdutil.bailifchanged so override it to add the check
970 954 def overridefetch(orig, ui, repo, *pats, **opts):
971 955 repo.lfstatus = True
972 956 modified, added, removed, deleted = repo.status()[:4]
973 957 repo.lfstatus = False
974 958 if modified or added or removed or deleted:
975 959 raise util.Abort(_('outstanding uncommitted changes'))
976 960 return orig(ui, repo, *pats, **opts)
977 961
978 962 def overrideforget(orig, ui, repo, *pats, **opts):
979 963 installnormalfilesmatchfn(repo[None].manifest())
980 964 result = orig(ui, repo, *pats, **opts)
981 965 restorematchfn()
982 966 m = scmutil.match(repo[None], pats, opts)
983 967
984 968 try:
985 969 repo.lfstatus = True
986 970 s = repo.status(match=m, clean=True)
987 971 finally:
988 972 repo.lfstatus = False
989 973 forget = sorted(s[0] + s[1] + s[3] + s[6])
990 974 forget = [f for f in forget if lfutil.standin(f) in repo[None].manifest()]
991 975
992 976 for f in forget:
993 977 if lfutil.standin(f) not in repo.dirstate and not \
994 978 os.path.isdir(m.rel(lfutil.standin(f))):
995 979 ui.warn(_('not removing %s: file is already untracked\n')
996 980 % m.rel(f))
997 981 result = 1
998 982
999 983 for f in forget:
1000 984 if ui.verbose or not m.exact(f):
1001 985 ui.status(_('removing %s\n') % m.rel(f))
1002 986
1003 987 # Need to lock because standin files are deleted then removed from the
1004 988 # repository and we could race in-between.
1005 989 wlock = repo.wlock()
1006 990 try:
1007 991 lfdirstate = lfutil.openlfdirstate(ui, repo)
1008 992 for f in forget:
1009 993 if lfdirstate[f] == 'a':
1010 994 lfdirstate.drop(f)
1011 995 else:
1012 996 lfdirstate.remove(f)
1013 997 lfdirstate.write()
1014 998 standins = [lfutil.standin(f) for f in forget]
1015 999 for f in standins:
1016 1000 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
1017 1001 repo[None].forget(standins)
1018 1002 finally:
1019 1003 wlock.release()
1020 1004
1021 1005 return result
1022 1006
1023 1007 def getoutgoinglfiles(ui, repo, dest=None, **opts):
1024 1008 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1025 1009 dest, branches = hg.parseurl(dest, opts.get('branch'))
1026 1010 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
1027 1011 if revs:
1028 1012 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
1029 1013
1030 1014 try:
1031 1015 remote = hg.peer(repo, opts, dest)
1032 1016 except error.RepoError:
1033 1017 return None
1034 1018 outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=False)
1035 1019 if not outgoing.missing:
1036 1020 return outgoing.missing
1037 1021 o = repo.changelog.nodesbetween(outgoing.missing, revs)[0]
1038 1022 if opts.get('newest_first'):
1039 1023 o.reverse()
1040 1024
1041 1025 toupload = set()
1042 1026 for n in o:
1043 1027 parents = [p for p in repo.changelog.parents(n) if p != node.nullid]
1044 1028 ctx = repo[n]
1045 1029 files = set(ctx.files())
1046 1030 if len(parents) == 2:
1047 1031 mc = ctx.manifest()
1048 1032 mp1 = ctx.parents()[0].manifest()
1049 1033 mp2 = ctx.parents()[1].manifest()
1050 1034 for f in mp1:
1051 1035 if f not in mc:
1052 1036 files.add(f)
1053 1037 for f in mp2:
1054 1038 if f not in mc:
1055 1039 files.add(f)
1056 1040 for f in mc:
1057 1041 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
1058 1042 files.add(f)
1059 1043 toupload = toupload.union(
1060 1044 set([f for f in files if lfutil.isstandin(f) and f in ctx]))
1061 1045 return sorted(toupload)
1062 1046
1063 1047 def overrideoutgoing(orig, ui, repo, dest=None, **opts):
1064 1048 result = orig(ui, repo, dest, **opts)
1065 1049
1066 1050 if opts.pop('large', None):
1067 1051 toupload = getoutgoinglfiles(ui, repo, dest, **opts)
1068 1052 if toupload is None:
1069 1053 ui.status(_('largefiles: No remote repo\n'))
1070 1054 elif not toupload:
1071 1055 ui.status(_('largefiles: no files to upload\n'))
1072 1056 else:
1073 1057 ui.status(_('largefiles to upload:\n'))
1074 1058 for file in toupload:
1075 1059 ui.status(lfutil.splitstandin(file) + '\n')
1076 1060 ui.status('\n')
1077 1061
1078 1062 return result
1079 1063
1080 1064 def overridesummary(orig, ui, repo, *pats, **opts):
1081 1065 try:
1082 1066 repo.lfstatus = True
1083 1067 orig(ui, repo, *pats, **opts)
1084 1068 finally:
1085 1069 repo.lfstatus = False
1086 1070
1087 1071 if opts.pop('large', None):
1088 1072 toupload = getoutgoinglfiles(ui, repo, None, **opts)
1089 1073 if toupload is None:
1090 1074 # i18n: column positioning for "hg summary"
1091 1075 ui.status(_('largefiles: (no remote repo)\n'))
1092 1076 elif not toupload:
1093 1077 # i18n: column positioning for "hg summary"
1094 1078 ui.status(_('largefiles: (no files to upload)\n'))
1095 1079 else:
1096 1080 # i18n: column positioning for "hg summary"
1097 1081 ui.status(_('largefiles: %d to upload\n') % len(toupload))
1098 1082
1099 1083 def scmutiladdremove(orig, repo, pats=[], opts={}, dry_run=None,
1100 1084 similarity=None):
1101 1085 if not lfutil.islfilesrepo(repo):
1102 1086 return orig(repo, pats, opts, dry_run, similarity)
1103 1087 # Get the list of missing largefiles so we can remove them
1104 1088 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1105 1089 s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), [], False,
1106 1090 False, False)
1107 1091 (unsure, modified, added, removed, missing, unknown, ignored, clean) = s
1108 1092
1109 1093 # Call into the normal remove code, but the removing of the standin, we want
1110 1094 # to have handled by original addremove. Monkey patching here makes sure
1111 1095 # we don't remove the standin in the largefiles code, preventing a very
1112 1096 # confused state later.
1113 1097 if missing:
1114 1098 m = [repo.wjoin(f) for f in missing]
1115 1099 repo._isaddremove = True
1116 1100 removelargefiles(repo.ui, repo, *m, **opts)
1117 1101 repo._isaddremove = False
1118 1102 # Call into the normal add code, and any files that *should* be added as
1119 1103 # largefiles will be
1120 1104 addlargefiles(repo.ui, repo, *pats, **opts)
1121 1105 # Now that we've handled largefiles, hand off to the original addremove
1122 1106 # function to take care of the rest. Make sure it doesn't do anything with
1123 1107 # largefiles by installing a matcher that will ignore them.
1124 1108 installnormalfilesmatchfn(repo[None].manifest())
1125 1109 result = orig(repo, pats, opts, dry_run, similarity)
1126 1110 restorematchfn()
1127 1111 return result
1128 1112
1129 1113 # Calling purge with --all will cause the largefiles to be deleted.
1130 1114 # Override repo.status to prevent this from happening.
1131 1115 def overridepurge(orig, ui, repo, *dirs, **opts):
1132 1116 # XXX large file status is buggy when used on repo proxy.
1133 1117 # XXX this needs to be investigate.
1134 1118 repo = repo.unfiltered()
1135 1119 oldstatus = repo.status
1136 1120 def overridestatus(node1='.', node2=None, match=None, ignored=False,
1137 1121 clean=False, unknown=False, listsubrepos=False):
1138 1122 r = oldstatus(node1, node2, match, ignored, clean, unknown,
1139 1123 listsubrepos)
1140 1124 lfdirstate = lfutil.openlfdirstate(ui, repo)
1141 1125 modified, added, removed, deleted, unknown, ignored, clean = r
1142 1126 unknown = [f for f in unknown if lfdirstate[f] == '?']
1143 1127 ignored = [f for f in ignored if lfdirstate[f] == '?']
1144 1128 return modified, added, removed, deleted, unknown, ignored, clean
1145 1129 repo.status = overridestatus
1146 1130 orig(ui, repo, *dirs, **opts)
1147 1131 repo.status = oldstatus
1148 1132
1149 1133 def overriderollback(orig, ui, repo, **opts):
1150 1134 result = orig(ui, repo, **opts)
1151 1135 merge.update(repo, node=None, branchmerge=False, force=True,
1152 1136 partial=lfutil.isstandin)
1153 1137 wlock = repo.wlock()
1154 1138 try:
1155 1139 lfdirstate = lfutil.openlfdirstate(ui, repo)
1156 1140 lfiles = lfutil.listlfiles(repo)
1157 1141 oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev())
1158 1142 for file in lfiles:
1159 1143 if file in oldlfiles:
1160 1144 lfdirstate.normallookup(file)
1161 1145 else:
1162 1146 lfdirstate.add(file)
1163 1147 lfdirstate.write()
1164 1148 finally:
1165 1149 wlock.release()
1166 1150 return result
1167 1151
1168 1152 def overridetransplant(orig, ui, repo, *revs, **opts):
1169 1153 try:
1170 1154 oldstandins = lfutil.getstandinsstate(repo)
1171 1155 repo._istransplanting = True
1172 1156 result = orig(ui, repo, *revs, **opts)
1173 1157 newstandins = lfutil.getstandinsstate(repo)
1174 1158 filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
1175 1159 lfcommands.updatelfiles(repo.ui, repo, filelist=filelist,
1176 1160 printmessage=True)
1177 1161 finally:
1178 1162 repo._istransplanting = False
1179 1163 return result
1180 1164
1181 1165 def overridecat(orig, ui, repo, file1, *pats, **opts):
1182 1166 ctx = scmutil.revsingle(repo, opts.get('rev'))
1183 1167 err = 1
1184 1168 notbad = set()
1185 1169 m = scmutil.match(ctx, (file1,) + pats, opts)
1186 1170 origmatchfn = m.matchfn
1187 1171 def lfmatchfn(f):
1188 1172 lf = lfutil.splitstandin(f)
1189 1173 if lf is None:
1190 1174 return origmatchfn(f)
1191 1175 notbad.add(lf)
1192 1176 return origmatchfn(lf)
1193 1177 m.matchfn = lfmatchfn
1194 1178 origbadfn = m.bad
1195 1179 def lfbadfn(f, msg):
1196 1180 if not f in notbad:
1197 1181 return origbadfn(f, msg)
1198 1182 m.bad = lfbadfn
1199 1183 for f in ctx.walk(m):
1200 1184 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1201 1185 pathname=f)
1202 1186 lf = lfutil.splitstandin(f)
1203 1187 if lf is None:
1204 1188 # duplicating unreachable code from commands.cat
1205 1189 data = ctx[f].data()
1206 1190 if opts.get('decode'):
1207 1191 data = repo.wwritedata(f, data)
1208 1192 fp.write(data)
1209 1193 else:
1210 1194 hash = lfutil.readstandin(repo, lf, ctx.rev())
1211 1195 if not lfutil.inusercache(repo.ui, hash):
1212 1196 store = basestore._openstore(repo)
1213 1197 success, missing = store.get([(lf, hash)])
1214 1198 if len(success) != 1:
1215 1199 raise util.Abort(
1216 1200 _('largefile %s is not in cache and could not be '
1217 1201 'downloaded') % lf)
1218 1202 path = lfutil.usercachepath(repo.ui, hash)
1219 1203 fpin = open(path, "rb")
1220 1204 for chunk in lfutil.blockstream(fpin):
1221 1205 fp.write(chunk)
1222 1206 fpin.close()
1223 1207 fp.close()
1224 1208 err = 0
1225 1209 return err
1226 1210
1227 1211 def mercurialsinkbefore(orig, sink):
1228 1212 sink.repo._isconverting = True
1229 1213 orig(sink)
1230 1214
1231 1215 def mercurialsinkafter(orig, sink):
1232 1216 sink.repo._isconverting = False
1233 1217 orig(sink)
@@ -1,180 +1,178 b''
1 1 # Copyright 2009-2010 Gregory P. Ward
2 2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 3 # Copyright 2010-2011 Fog Creek Software
4 4 # Copyright 2010-2011 Unity Technologies
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 '''setup for largefiles extension: uisetup'''
10 10
11 11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
12 12 httppeer, localrepo, merge, scmutil, sshpeer, wireproto, revset
13 13 from mercurial.i18n import _
14 14 from mercurial.hgweb import hgweb_mod, webcommands
15 15 from mercurial.subrepo import hgsubrepo
16 16
17 17 import overrides
18 18 import proto
19 19
20 20 def uisetup(ui):
21 21 # Disable auto-status for some commands which assume that all
22 22 # files in the result are under Mercurial's control
23 23
24 24 entry = extensions.wrapcommand(commands.table, 'add',
25 25 overrides.overrideadd)
26 26 addopt = [('', 'large', None, _('add as largefile')),
27 27 ('', 'normal', None, _('add as normal file')),
28 28 ('', 'lfsize', '', _('add all files above this size '
29 29 '(in megabytes) as largefiles '
30 30 '(default: 10)'))]
31 31 entry[1].extend(addopt)
32 32
33 33 # The scmutil function is called both by the (trivial) addremove command,
34 34 # and in the process of handling commit -A (issue3542)
35 35 entry = extensions.wrapfunction(scmutil, 'addremove',
36 36 overrides.scmutiladdremove)
37 37 entry = extensions.wrapcommand(commands.table, 'remove',
38 38 overrides.overrideremove)
39 39 entry = extensions.wrapcommand(commands.table, 'forget',
40 40 overrides.overrideforget)
41 41
42 42 # Subrepos call status function
43 43 entry = extensions.wrapcommand(commands.table, 'status',
44 44 overrides.overridestatus)
45 45 entry = extensions.wrapfunction(hgsubrepo, 'status',
46 46 overrides.overridestatusfn)
47 47
48 48 entry = extensions.wrapcommand(commands.table, 'log',
49 49 overrides.overridelog)
50 50 entry = extensions.wrapcommand(commands.table, 'rollback',
51 51 overrides.overriderollback)
52 52 entry = extensions.wrapcommand(commands.table, 'verify',
53 53 overrides.overrideverify)
54 54
55 55 verifyopt = [('', 'large', None,
56 56 _('verify that all largefiles in current revision exists')),
57 57 ('', 'lfa', None,
58 58 _('verify largefiles in all revisions, not just current')),
59 59 ('', 'lfc', None,
60 60 _('verify local largefile contents, not just existence'))]
61 61 entry[1].extend(verifyopt)
62 62
63 63 entry = extensions.wrapcommand(commands.table, 'debugstate',
64 64 overrides.overridedebugstate)
65 65 debugstateopt = [('', 'large', None, _('display largefiles dirstate'))]
66 66 entry[1].extend(debugstateopt)
67 67
68 68 entry = extensions.wrapcommand(commands.table, 'outgoing',
69 69 overrides.overrideoutgoing)
70 70 outgoingopt = [('', 'large', None, _('display outgoing largefiles'))]
71 71 entry[1].extend(outgoingopt)
72 72 entry = extensions.wrapcommand(commands.table, 'summary',
73 73 overrides.overridesummary)
74 74 summaryopt = [('', 'large', None, _('display outgoing largefiles'))]
75 75 entry[1].extend(summaryopt)
76 76
77 77 entry = extensions.wrapcommand(commands.table, 'update',
78 78 overrides.overrideupdate)
79 79 entry = extensions.wrapcommand(commands.table, 'pull',
80 80 overrides.overridepull)
81 81 pullopt = [('', 'all-largefiles', None,
82 82 _('download all pulled versions of largefiles')),
83 ('', 'cache-largefiles', None,
84 _('caches new largefiles in all pulled heads')),
85 83 ('', 'lfrev', [],
86 84 _('download largefiles for these revisions'), _('REV'))]
87 85 entry[1].extend(pullopt)
88 86 revset.symbols['pulled'] = overrides.pulledrevsetsymbol
89 87
90 88 entry = extensions.wrapcommand(commands.table, 'clone',
91 89 overrides.overrideclone)
92 90 cloneopt = [('', 'all-largefiles', None,
93 91 _('download all versions of all largefiles'))]
94 92 entry[1].extend(cloneopt)
95 93 entry = extensions.wrapfunction(hg, 'clone', overrides.hgclone)
96 94
97 95 entry = extensions.wrapcommand(commands.table, 'cat',
98 96 overrides.overridecat)
99 97 entry = extensions.wrapfunction(merge, '_checkunknownfile',
100 98 overrides.overridecheckunknownfile)
101 99 entry = extensions.wrapfunction(merge, 'manifestmerge',
102 100 overrides.overridemanifestmerge)
103 101 entry = extensions.wrapfunction(filemerge, 'filemerge',
104 102 overrides.overridefilemerge)
105 103 entry = extensions.wrapfunction(cmdutil, 'copy',
106 104 overrides.overridecopy)
107 105
108 106 # Summary calls dirty on the subrepos
109 107 entry = extensions.wrapfunction(hgsubrepo, 'dirty',
110 108 overrides.overridedirty)
111 109
112 110 # Backout calls revert so we need to override both the command and the
113 111 # function
114 112 entry = extensions.wrapcommand(commands.table, 'revert',
115 113 overrides.overriderevert)
116 114 entry = extensions.wrapfunction(commands, 'revert',
117 115 overrides.overriderevert)
118 116
119 117 extensions.wrapfunction(hg, 'updaterepo', overrides.hgupdaterepo)
120 118 extensions.wrapfunction(hg, 'merge', overrides.hgmerge)
121 119
122 120 extensions.wrapfunction(archival, 'archive', overrides.overridearchive)
123 121 extensions.wrapfunction(hgsubrepo, 'archive', overrides.hgsubrepoarchive)
124 122 extensions.wrapfunction(cmdutil, 'bailifchanged',
125 123 overrides.overridebailifchanged)
126 124
127 125 # create the new wireproto commands ...
128 126 wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
129 127 wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
130 128 wireproto.commands['statlfile'] = (proto.statlfile, 'sha')
131 129
132 130 # ... and wrap some existing ones
133 131 wireproto.commands['capabilities'] = (proto.capabilities, '')
134 132 wireproto.commands['heads'] = (proto.heads, '')
135 133 wireproto.commands['lheads'] = (wireproto.heads, '')
136 134
137 135 # make putlfile behave the same as push and {get,stat}lfile behave
138 136 # the same as pull w.r.t. permissions checks
139 137 hgweb_mod.perms['putlfile'] = 'push'
140 138 hgweb_mod.perms['getlfile'] = 'pull'
141 139 hgweb_mod.perms['statlfile'] = 'pull'
142 140
143 141 extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
144 142
145 143 # the hello wireproto command uses wireproto.capabilities, so it won't see
146 144 # our largefiles capability unless we replace the actual function as well.
147 145 proto.capabilitiesorig = wireproto.capabilities
148 146 wireproto.capabilities = proto.capabilities
149 147
150 148 # can't do this in reposetup because it needs to have happened before
151 149 # wirerepo.__init__ is called
152 150 proto.ssholdcallstream = sshpeer.sshpeer._callstream
153 151 proto.httpoldcallstream = httppeer.httppeer._callstream
154 152 sshpeer.sshpeer._callstream = proto.sshrepocallstream
155 153 httppeer.httppeer._callstream = proto.httprepocallstream
156 154
157 155 # don't die on seeing a repo with the largefiles requirement
158 156 localrepo.localrepository.supported |= set(['largefiles'])
159 157
160 158 # override some extensions' stuff as well
161 159 for name, module in extensions.extensions():
162 160 if name == 'fetch':
163 161 extensions.wrapcommand(getattr(module, 'cmdtable'), 'fetch',
164 162 overrides.overridefetch)
165 163 if name == 'purge':
166 164 extensions.wrapcommand(getattr(module, 'cmdtable'), 'purge',
167 165 overrides.overridepurge)
168 166 if name == 'rebase':
169 167 extensions.wrapcommand(getattr(module, 'cmdtable'), 'rebase',
170 168 overrides.overriderebase)
171 169 if name == 'transplant':
172 170 extensions.wrapcommand(getattr(module, 'cmdtable'), 'transplant',
173 171 overrides.overridetransplant)
174 172 if name == 'convert':
175 173 convcmd = getattr(module, 'convcmd')
176 174 hgsink = getattr(convcmd, 'mercurial_sink')
177 175 extensions.wrapfunction(hgsink, 'before',
178 176 overrides.mercurialsinkbefore)
179 177 extensions.wrapfunction(hgsink, 'after',
180 178 overrides.mercurialsinkafter)
@@ -1,2218 +1,2217 b''
1 1 $ USERCACHE="$TESTTMP/cache"; export USERCACHE
2 2 $ mkdir "${USERCACHE}"
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > largefiles=
6 6 > purge=
7 7 > rebase=
8 8 > transplant=
9 9 > [phases]
10 10 > publish=False
11 11 > [largefiles]
12 12 > minsize=2
13 13 > patterns=glob:**.dat
14 14 > usercache=${USERCACHE}
15 15 > [hooks]
16 16 > precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
17 17 > EOF
18 18
19 19 Create the repo with a couple of revisions of both large and normal
20 20 files.
21 21 Test status and dirstate of largefiles and that summary output is correct.
22 22
23 23 $ hg init a
24 24 $ cd a
25 25 $ mkdir sub
26 26 $ echo normal1 > normal1
27 27 $ echo normal2 > sub/normal2
28 28 $ echo large1 > large1
29 29 $ echo large2 > sub/large2
30 30 $ hg add normal1 sub/normal2
31 31 $ hg add --large large1 sub/large2
32 32 $ hg commit -m "add files"
33 33 Invoking status precommit hook
34 34 A large1
35 35 A normal1
36 36 A sub/large2
37 37 A sub/normal2
38 38 $ touch large1 sub/large2
39 39 $ sleep 1
40 40 $ hg st
41 41 $ hg debugstate --nodates
42 42 n 644 41 .hglf/large1
43 43 n 644 41 .hglf/sub/large2
44 44 n 644 8 normal1
45 45 n 644 8 sub/normal2
46 46 $ hg debugstate --large
47 47 n 644 7 large1
48 48 n 644 7 sub/large2
49 49 $ echo normal11 > normal1
50 50 $ echo normal22 > sub/normal2
51 51 $ echo large11 > large1
52 52 $ echo large22 > sub/large2
53 53 $ hg commit -m "edit files"
54 54 Invoking status precommit hook
55 55 M large1
56 56 M normal1
57 57 M sub/large2
58 58 M sub/normal2
59 59 $ hg sum --large
60 60 parent: 1:ce8896473775 tip
61 61 edit files
62 62 branch: default
63 63 commit: (clean)
64 64 update: (current)
65 65 largefiles: (no remote repo)
66 66
67 67 Commit preserved largefile contents.
68 68
69 69 $ cat normal1
70 70 normal11
71 71 $ cat large1
72 72 large11
73 73 $ cat sub/normal2
74 74 normal22
75 75 $ cat sub/large2
76 76 large22
77 77
78 78 Test status, subdir and unknown files
79 79
80 80 $ echo unknown > sub/unknown
81 81 $ hg st --all
82 82 ? sub/unknown
83 83 C large1
84 84 C normal1
85 85 C sub/large2
86 86 C sub/normal2
87 87 $ hg st --all sub
88 88 ? sub/unknown
89 89 C sub/large2
90 90 C sub/normal2
91 91 $ rm sub/unknown
92 92
93 93 Test messages and exit codes for remove warning cases
94 94
95 95 $ hg remove -A large1
96 96 not removing large1: file still exists
97 97 [1]
98 98 $ echo 'modified' > large1
99 99 $ hg remove large1
100 100 not removing large1: file is modified (use -f to force removal)
101 101 [1]
102 102 $ echo 'new' > normalnew
103 103 $ hg add normalnew
104 104 $ echo 'new' > largenew
105 105 $ hg add --large normalnew
106 106 normalnew already tracked!
107 107 $ hg remove normalnew largenew
108 108 not removing largenew: file is untracked
109 109 not removing normalnew: file has been marked for add (use forget to undo)
110 110 [1]
111 111 $ rm normalnew largenew
112 112 $ hg up -Cq
113 113
114 114 Remove both largefiles and normal files.
115 115
116 116 $ hg remove normal1 large1
117 117 $ hg status large1
118 118 R large1
119 119 $ hg commit -m "remove files"
120 120 Invoking status precommit hook
121 121 R large1
122 122 R normal1
123 123 $ ls
124 124 sub
125 125 $ echo "testlargefile" > large1-test
126 126 $ hg add --large large1-test
127 127 $ hg st
128 128 A large1-test
129 129 $ hg rm large1-test
130 130 not removing large1-test: file has been marked for add (use forget to undo)
131 131 [1]
132 132 $ hg st
133 133 A large1-test
134 134 $ hg forget large1-test
135 135 $ hg st
136 136 ? large1-test
137 137 $ hg remove large1-test
138 138 not removing large1-test: file is untracked
139 139 [1]
140 140 $ hg forget large1-test
141 141 not removing large1-test: file is already untracked
142 142 [1]
143 143 $ rm large1-test
144 144
145 145 Copy both largefiles and normal files (testing that status output is correct).
146 146
147 147 $ hg cp sub/normal2 normal1
148 148 $ hg cp sub/large2 large1
149 149 $ hg commit -m "copy files"
150 150 Invoking status precommit hook
151 151 A large1
152 152 A normal1
153 153 $ cat normal1
154 154 normal22
155 155 $ cat large1
156 156 large22
157 157
158 158 Test moving largefiles and verify that normal files are also unaffected.
159 159
160 160 $ hg mv normal1 normal3
161 161 $ hg mv large1 large3
162 162 $ hg mv sub/normal2 sub/normal4
163 163 $ hg mv sub/large2 sub/large4
164 164 $ hg commit -m "move files"
165 165 Invoking status precommit hook
166 166 A large3
167 167 A normal3
168 168 A sub/large4
169 169 A sub/normal4
170 170 R large1
171 171 R normal1
172 172 R sub/large2
173 173 R sub/normal2
174 174 $ cat normal3
175 175 normal22
176 176 $ cat large3
177 177 large22
178 178 $ cat sub/normal4
179 179 normal22
180 180 $ cat sub/large4
181 181 large22
182 182
183 183 Test repo method wrapping detection
184 184
185 185 $ cat > $TESTTMP/wrapping1.py <<EOF
186 186 > from hgext import largefiles
187 187 > def reposetup(ui, repo):
188 188 > class derived(repo.__class__):
189 189 > def push(self, *args, **kwargs):
190 190 > return super(derived, self).push(*args, **kwargs)
191 191 > repo.__class__ = derived
192 192 > largefiles.reposetup(ui, repo)
193 193 > uisetup = largefiles.uisetup
194 194 > EOF
195 195 $ hg --config extensions.largefiles=$TESTTMP/wrapping1.py status
196 196 largefiles: repo method 'push' appears to have already been wrapped by another extension: largefiles may behave incorrectly
197 197
198 198 $ cat > $TESTTMP/wrapping2.py <<EOF
199 199 > from hgext import largefiles
200 200 > def reposetup(ui, repo):
201 201 > orgpush = repo.push
202 202 > def push(*args, **kwargs):
203 203 > return orgpush(*args, **kwargs)
204 204 > repo.push = push
205 205 > largefiles.reposetup(ui, repo)
206 206 > uisetup = largefiles.uisetup
207 207 > EOF
208 208 $ hg --config extensions.largefiles=$TESTTMP/wrapping2.py status
209 209 largefiles: repo method 'push' appears to have already been wrapped by another extension: largefiles may behave incorrectly
210 210
211 211 Test copies and moves from a directory other than root (issue3516)
212 212
213 213 $ cd ..
214 214 $ hg init lf_cpmv
215 215 $ cd lf_cpmv
216 216 $ mkdir dira
217 217 $ mkdir dira/dirb
218 218 $ touch dira/dirb/largefile
219 219 $ hg add --large dira/dirb/largefile
220 220 $ hg commit -m "added"
221 221 Invoking status precommit hook
222 222 A dira/dirb/largefile
223 223 $ cd dira
224 224 $ hg cp dirb/largefile foo/largefile
225 225 $ hg ci -m "deep copy"
226 226 Invoking status precommit hook
227 227 A dira/foo/largefile
228 228 $ find . | sort
229 229 .
230 230 ./dirb
231 231 ./dirb/largefile
232 232 ./foo
233 233 ./foo/largefile
234 234 $ hg mv foo/largefile baz/largefile
235 235 $ hg ci -m "moved"
236 236 Invoking status precommit hook
237 237 A dira/baz/largefile
238 238 R dira/foo/largefile
239 239 $ find . | sort
240 240 .
241 241 ./baz
242 242 ./baz/largefile
243 243 ./dirb
244 244 ./dirb/largefile
245 245 ./foo
246 246 $ cd ../../a
247 247
248 248 #if serve
249 249 Test display of largefiles in hgweb
250 250
251 251 $ hg serve -d -p $HGPORT --pid-file ../hg.pid
252 252 $ cat ../hg.pid >> $DAEMON_PIDS
253 253 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
254 254 200 Script output follows
255 255
256 256
257 257 drwxr-xr-x sub
258 258 -rw-r--r-- 41 large3
259 259 -rw-r--r-- 9 normal3
260 260
261 261
262 262 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
263 263 200 Script output follows
264 264
265 265
266 266 -rw-r--r-- 41 large4
267 267 -rw-r--r-- 9 normal4
268 268
269 269
270 270 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
271 271 #endif
272 272
273 273 Test archiving the various revisions. These hit corner cases known with
274 274 archiving.
275 275
276 276 $ hg archive -r 0 ../archive0
277 277 $ hg archive -r 1 ../archive1
278 278 $ hg archive -r 2 ../archive2
279 279 $ hg archive -r 3 ../archive3
280 280 $ hg archive -r 4 ../archive4
281 281 $ cd ../archive0
282 282 $ cat normal1
283 283 normal1
284 284 $ cat large1
285 285 large1
286 286 $ cat sub/normal2
287 287 normal2
288 288 $ cat sub/large2
289 289 large2
290 290 $ cd ../archive1
291 291 $ cat normal1
292 292 normal11
293 293 $ cat large1
294 294 large11
295 295 $ cat sub/normal2
296 296 normal22
297 297 $ cat sub/large2
298 298 large22
299 299 $ cd ../archive2
300 300 $ ls
301 301 sub
302 302 $ cat sub/normal2
303 303 normal22
304 304 $ cat sub/large2
305 305 large22
306 306 $ cd ../archive3
307 307 $ cat normal1
308 308 normal22
309 309 $ cat large1
310 310 large22
311 311 $ cat sub/normal2
312 312 normal22
313 313 $ cat sub/large2
314 314 large22
315 315 $ cd ../archive4
316 316 $ cat normal3
317 317 normal22
318 318 $ cat large3
319 319 large22
320 320 $ cat sub/normal4
321 321 normal22
322 322 $ cat sub/large4
323 323 large22
324 324
325 325 Commit corner case: specify files to commit.
326 326
327 327 $ cd ../a
328 328 $ echo normal3 > normal3
329 329 $ echo large3 > large3
330 330 $ echo normal4 > sub/normal4
331 331 $ echo large4 > sub/large4
332 332 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
333 333 Invoking status precommit hook
334 334 M large3
335 335 M normal3
336 336 M sub/large4
337 337 M sub/normal4
338 338 $ cat normal3
339 339 normal3
340 340 $ cat large3
341 341 large3
342 342 $ cat sub/normal4
343 343 normal4
344 344 $ cat sub/large4
345 345 large4
346 346
347 347 One more commit corner case: commit from a subdirectory.
348 348
349 349 $ cd ../a
350 350 $ echo normal33 > normal3
351 351 $ echo large33 > large3
352 352 $ echo normal44 > sub/normal4
353 353 $ echo large44 > sub/large4
354 354 $ cd sub
355 355 $ hg commit -m "edit files yet again"
356 356 Invoking status precommit hook
357 357 M large3
358 358 M normal3
359 359 M sub/large4
360 360 M sub/normal4
361 361 $ cat ../normal3
362 362 normal33
363 363 $ cat ../large3
364 364 large33
365 365 $ cat normal4
366 366 normal44
367 367 $ cat large4
368 368 large44
369 369
370 370 Committing standins is not allowed.
371 371
372 372 $ cd ..
373 373 $ echo large3 > large3
374 374 $ hg commit .hglf/large3 -m "try to commit standin"
375 375 abort: file ".hglf/large3" is a largefile standin
376 376 (commit the largefile itself instead)
377 377 [255]
378 378
379 379 Corner cases for adding largefiles.
380 380
381 381 $ echo large5 > large5
382 382 $ hg add --large large5
383 383 $ hg add --large large5
384 384 large5 already a largefile
385 385 $ mkdir sub2
386 386 $ echo large6 > sub2/large6
387 387 $ echo large7 > sub2/large7
388 388 $ hg add --large sub2
389 389 adding sub2/large6 as a largefile (glob)
390 390 adding sub2/large7 as a largefile (glob)
391 391 $ hg st
392 392 M large3
393 393 A large5
394 394 A sub2/large6
395 395 A sub2/large7
396 396
397 397 Committing directories containing only largefiles.
398 398
399 399 $ mkdir -p z/y/x/m
400 400 $ touch z/y/x/m/large1
401 401 $ touch z/y/x/large2
402 402 $ hg add --large z/y/x/m/large1 z/y/x/large2
403 403 $ hg commit -m "Subdir with directory only containing largefiles" z
404 404 Invoking status precommit hook
405 405 M large3
406 406 A large5
407 407 A sub2/large6
408 408 A sub2/large7
409 409 A z/y/x/large2
410 410 A z/y/x/m/large1
411 411 $ hg rollback --quiet
412 412 $ touch z/y/x/m/normal
413 413 $ hg add z/y/x/m/normal
414 414 $ hg commit -m "Subdir with mixed contents" z
415 415 Invoking status precommit hook
416 416 M large3
417 417 A large5
418 418 A sub2/large6
419 419 A sub2/large7
420 420 A z/y/x/large2
421 421 A z/y/x/m/large1
422 422 A z/y/x/m/normal
423 423 $ hg st
424 424 M large3
425 425 A large5
426 426 A sub2/large6
427 427 A sub2/large7
428 428 $ hg rollback --quiet
429 429 $ hg revert z/y/x/large2 z/y/x/m/large1
430 430 $ rm z/y/x/large2 z/y/x/m/large1
431 431 $ hg commit -m "Subdir with normal contents" z
432 432 Invoking status precommit hook
433 433 M large3
434 434 A large5
435 435 A sub2/large6
436 436 A sub2/large7
437 437 A z/y/x/m/normal
438 438 $ hg st
439 439 M large3
440 440 A large5
441 441 A sub2/large6
442 442 A sub2/large7
443 443 $ hg rollback --quiet
444 444 $ hg revert --quiet z
445 445 $ hg commit -m "Empty subdir" z
446 446 abort: z: no match under directory!
447 447 [255]
448 448 $ rm -rf z
449 449 $ hg ci -m "standin" .hglf
450 450 abort: file ".hglf" is a largefile standin
451 451 (commit the largefile itself instead)
452 452 [255]
453 453
454 454 Test "hg status" with combination of 'file pattern' and 'directory
455 455 pattern' for largefiles:
456 456
457 457 $ hg status sub2/large6 sub2
458 458 A sub2/large6
459 459 A sub2/large7
460 460
461 461 Config settings (pattern **.dat, minsize 2 MB) are respected.
462 462
463 463 $ echo testdata > test.dat
464 464 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
465 465 $ hg add
466 466 adding reallylarge as a largefile
467 467 adding test.dat as a largefile
468 468
469 469 Test that minsize and --lfsize handle float values;
470 470 also tests that --lfsize overrides largefiles.minsize.
471 471 (0.250 MB = 256 kB = 262144 B)
472 472
473 473 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
474 474 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
475 475 $ hg --config largefiles.minsize=.25 add
476 476 adding ratherlarge as a largefile
477 477 adding medium
478 478 $ hg forget medium
479 479 $ hg --config largefiles.minsize=.25 add --lfsize=.125
480 480 adding medium as a largefile
481 481 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
482 482 $ hg --config largefiles.minsize=.25 add --lfsize=.125
483 483 adding notlarge
484 484 $ hg forget notlarge
485 485
486 486 Test forget on largefiles.
487 487
488 488 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
489 489 $ hg commit -m "add/edit more largefiles"
490 490 Invoking status precommit hook
491 491 A sub2/large6
492 492 A sub2/large7
493 493 R large3
494 494 ? large5
495 495 ? medium
496 496 ? notlarge
497 497 ? ratherlarge
498 498 ? reallylarge
499 499 ? test.dat
500 500 $ hg st
501 501 ? large3
502 502 ? large5
503 503 ? medium
504 504 ? notlarge
505 505 ? ratherlarge
506 506 ? reallylarge
507 507 ? test.dat
508 508
509 509 Purge with largefiles: verify that largefiles are still in the working
510 510 dir after a purge.
511 511
512 512 $ hg purge --all
513 513 $ cat sub/large4
514 514 large44
515 515 $ cat sub2/large6
516 516 large6
517 517 $ cat sub2/large7
518 518 large7
519 519
520 520 Test addremove: verify that files that should be added as largfiles are added as
521 521 such and that already-existing largfiles are not added as normal files by
522 522 accident.
523 523
524 524 $ rm normal3
525 525 $ rm sub/large4
526 526 $ echo "testing addremove with patterns" > testaddremove.dat
527 527 $ echo "normaladdremove" > normaladdremove
528 528 $ hg addremove
529 529 removing sub/large4
530 530 adding testaddremove.dat as a largefile
531 531 removing normal3
532 532 adding normaladdremove
533 533
534 534 Test addremove with -R
535 535
536 536 $ hg up -C
537 537 getting changed largefiles
538 538 1 largefiles updated, 0 removed
539 539 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 540 $ rm normal3
541 541 $ rm sub/large4
542 542 $ echo "testing addremove with patterns" > testaddremove.dat
543 543 $ echo "normaladdremove" > normaladdremove
544 544 $ cd ..
545 545 $ hg -R a addremove
546 546 removing sub/large4
547 547 adding a/testaddremove.dat as a largefile (glob)
548 548 removing normal3
549 549 adding normaladdremove
550 550 $ cd a
551 551
552 552 Test 3364
553 553 $ hg clone . ../addrm
554 554 updating to branch default
555 555 getting changed largefiles
556 556 3 largefiles updated, 0 removed
557 557 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
558 558 $ cd ../addrm
559 559 $ cat >> .hg/hgrc <<EOF
560 560 > [hooks]
561 561 > post-commit.stat=sh -c "echo \\"Invoking status postcommit hook\\"; hg status -A"
562 562 > EOF
563 563 $ touch foo
564 564 $ hg add --large foo
565 565 $ hg ci -m "add foo"
566 566 Invoking status precommit hook
567 567 A foo
568 568 Invoking status postcommit hook
569 569 C foo
570 570 C normal3
571 571 C sub/large4
572 572 C sub/normal4
573 573 C sub2/large6
574 574 C sub2/large7
575 575 $ rm foo
576 576 $ hg st
577 577 ! foo
578 578 hmm.. no precommit invoked, but there is a postcommit??
579 579 $ hg ci -m "will not checkin"
580 580 nothing changed
581 581 Invoking status postcommit hook
582 582 ! foo
583 583 C normal3
584 584 C sub/large4
585 585 C sub/normal4
586 586 C sub2/large6
587 587 C sub2/large7
588 588 [1]
589 589 $ hg addremove
590 590 removing foo
591 591 $ hg st
592 592 R foo
593 593 $ hg ci -m "used to say nothing changed"
594 594 Invoking status precommit hook
595 595 R foo
596 596 Invoking status postcommit hook
597 597 C normal3
598 598 C sub/large4
599 599 C sub/normal4
600 600 C sub2/large6
601 601 C sub2/large7
602 602 $ hg st
603 603
604 604 Test 3507 (both normal files and largefiles were a problem)
605 605
606 606 $ touch normal
607 607 $ touch large
608 608 $ hg add normal
609 609 $ hg add --large large
610 610 $ hg ci -m "added"
611 611 Invoking status precommit hook
612 612 A large
613 613 A normal
614 614 Invoking status postcommit hook
615 615 C large
616 616 C normal
617 617 C normal3
618 618 C sub/large4
619 619 C sub/normal4
620 620 C sub2/large6
621 621 C sub2/large7
622 622 $ hg remove normal
623 623 $ hg addremove --traceback
624 624 $ hg ci -m "addremoved normal"
625 625 Invoking status precommit hook
626 626 R normal
627 627 Invoking status postcommit hook
628 628 C large
629 629 C normal3
630 630 C sub/large4
631 631 C sub/normal4
632 632 C sub2/large6
633 633 C sub2/large7
634 634 $ hg up -C '.^'
635 635 getting changed largefiles
636 636 0 largefiles updated, 0 removed
637 637 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
638 638 $ hg remove large
639 639 $ hg addremove --traceback
640 640 $ hg ci -m "removed large"
641 641 Invoking status precommit hook
642 642 R large
643 643 created new head
644 644 Invoking status postcommit hook
645 645 C normal
646 646 C normal3
647 647 C sub/large4
648 648 C sub/normal4
649 649 C sub2/large6
650 650 C sub2/large7
651 651
652 652 Test commit -A (issue 3542)
653 653 $ echo large8 > large8
654 654 $ hg add --large large8
655 655 $ hg ci -Am 'this used to add large8 as normal and commit both'
656 656 Invoking status precommit hook
657 657 A large8
658 658 Invoking status postcommit hook
659 659 C large8
660 660 C normal
661 661 C normal3
662 662 C sub/large4
663 663 C sub/normal4
664 664 C sub2/large6
665 665 C sub2/large7
666 666 $ rm large8
667 667 $ hg ci -Am 'this used to not notice the rm'
668 668 removing large8
669 669 Invoking status precommit hook
670 670 R large8
671 671 Invoking status postcommit hook
672 672 C normal
673 673 C normal3
674 674 C sub/large4
675 675 C sub/normal4
676 676 C sub2/large6
677 677 C sub2/large7
678 678
679 679 Test that a standin can't be added as a large file
680 680
681 681 $ touch large
682 682 $ hg add --large large
683 683 $ hg ci -m "add"
684 684 Invoking status precommit hook
685 685 A large
686 686 Invoking status postcommit hook
687 687 C large
688 688 C normal
689 689 C normal3
690 690 C sub/large4
691 691 C sub/normal4
692 692 C sub2/large6
693 693 C sub2/large7
694 694 $ hg remove large
695 695 $ touch large
696 696 $ hg addremove --config largefiles.patterns=**large --traceback
697 697 adding large as a largefile
698 698
699 699 Test that outgoing --large works (with revsets too)
700 700 $ hg outgoing --rev '.^' --large
701 701 comparing with $TESTTMP/a (glob)
702 702 searching for changes
703 703 changeset: 8:c02fd3b77ec4
704 704 user: test
705 705 date: Thu Jan 01 00:00:00 1970 +0000
706 706 summary: add foo
707 707
708 708 changeset: 9:289dd08c9bbb
709 709 user: test
710 710 date: Thu Jan 01 00:00:00 1970 +0000
711 711 summary: used to say nothing changed
712 712
713 713 changeset: 10:34f23ac6ac12
714 714 user: test
715 715 date: Thu Jan 01 00:00:00 1970 +0000
716 716 summary: added
717 717
718 718 changeset: 12:710c1b2f523c
719 719 parent: 10:34f23ac6ac12
720 720 user: test
721 721 date: Thu Jan 01 00:00:00 1970 +0000
722 722 summary: removed large
723 723
724 724 changeset: 13:0a3e75774479
725 725 user: test
726 726 date: Thu Jan 01 00:00:00 1970 +0000
727 727 summary: this used to add large8 as normal and commit both
728 728
729 729 changeset: 14:84f3d378175c
730 730 user: test
731 731 date: Thu Jan 01 00:00:00 1970 +0000
732 732 summary: this used to not notice the rm
733 733
734 734 searching for changes
735 735 largefiles to upload:
736 736 foo
737 737 large
738 738 large8
739 739
740 740 $ cd ../a
741 741
742 742 Clone a largefiles repo.
743 743
744 744 $ hg clone . ../b
745 745 updating to branch default
746 746 getting changed largefiles
747 747 3 largefiles updated, 0 removed
748 748 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
749 749 $ cd ../b
750 750 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
751 751 7:daea875e9014 add/edit more largefiles
752 752 6:4355d653f84f edit files yet again
753 753 5:9d5af5072dbd edit files again
754 754 4:74c02385b94c move files
755 755 3:9e8fbc4bce62 copy files
756 756 2:51a0ae4d5864 remove files
757 757 1:ce8896473775 edit files
758 758 0:30d30fe6a5be add files
759 759 $ cat normal3
760 760 normal33
761 761 $ cat sub/normal4
762 762 normal44
763 763 $ cat sub/large4
764 764 large44
765 765 $ cat sub2/large6
766 766 large6
767 767 $ cat sub2/large7
768 768 large7
769 769 $ cd ..
770 770 $ hg clone a -r 3 c
771 771 adding changesets
772 772 adding manifests
773 773 adding file changes
774 774 added 4 changesets with 10 changes to 4 files
775 775 updating to branch default
776 776 getting changed largefiles
777 777 2 largefiles updated, 0 removed
778 778 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
779 779 $ cd c
780 780 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
781 781 3:9e8fbc4bce62 copy files
782 782 2:51a0ae4d5864 remove files
783 783 1:ce8896473775 edit files
784 784 0:30d30fe6a5be add files
785 785 $ cat normal1
786 786 normal22
787 787 $ cat large1
788 788 large22
789 789 $ cat sub/normal2
790 790 normal22
791 791 $ cat sub/large2
792 792 large22
793 793
794 794 Old revisions of a clone have correct largefiles content (this also
795 795 tests update).
796 796
797 797 $ hg update -r 1
798 798 getting changed largefiles
799 799 1 largefiles updated, 0 removed
800 800 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
801 801 $ cat large1
802 802 large11
803 803 $ cat sub/large2
804 804 large22
805 805 $ cd ..
806 806
807 807 Test cloning with --all-largefiles flag
808 808
809 809 $ rm "${USERCACHE}"/*
810 810 $ hg clone --all-largefiles a a-backup
811 811 updating to branch default
812 812 getting changed largefiles
813 813 3 largefiles updated, 0 removed
814 814 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
815 815 8 additional largefiles cached
816 816
817 817 $ rm "${USERCACHE}"/*
818 818 $ hg clone --all-largefiles -u 0 a a-clone0
819 819 updating to branch default
820 820 getting changed largefiles
821 821 2 largefiles updated, 0 removed
822 822 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
823 823 9 additional largefiles cached
824 824 $ hg -R a-clone0 sum
825 825 parent: 0:30d30fe6a5be
826 826 add files
827 827 branch: default
828 828 commit: (clean)
829 829 update: 7 new changesets (update)
830 830
831 831 $ rm "${USERCACHE}"/*
832 832 $ hg clone --all-largefiles -u 1 a a-clone1
833 833 updating to branch default
834 834 getting changed largefiles
835 835 2 largefiles updated, 0 removed
836 836 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
837 837 8 additional largefiles cached
838 838 $ hg -R a-clone1 verify --large --lfa --lfc
839 839 checking changesets
840 840 checking manifests
841 841 crosschecking files in changesets and manifests
842 842 checking files
843 843 10 files, 8 changesets, 24 total revisions
844 844 searching 8 changesets for largefiles
845 845 verified contents of 13 revisions of 6 largefiles
846 846 $ hg -R a-clone1 sum
847 847 parent: 1:ce8896473775
848 848 edit files
849 849 branch: default
850 850 commit: (clean)
851 851 update: 6 new changesets (update)
852 852
853 853 $ rm "${USERCACHE}"/*
854 854 $ hg clone --all-largefiles -U a a-clone-u
855 855 11 additional largefiles cached
856 856 $ hg -R a-clone-u sum
857 857 parent: -1:000000000000 (no revision checked out)
858 858 branch: default
859 859 commit: (clean)
860 860 update: 8 new changesets (update)
861 861
862 862 Show computed destination directory:
863 863
864 864 $ mkdir xyz
865 865 $ cd xyz
866 866 $ hg clone ../a
867 867 destination directory: a
868 868 updating to branch default
869 869 getting changed largefiles
870 870 3 largefiles updated, 0 removed
871 871 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
872 872 $ cd ..
873 873
874 874 Clone URL without path:
875 875
876 876 $ hg clone file://
877 877 abort: repository / not found!
878 878 [255]
879 879
880 880 Ensure base clone command argument validation
881 881
882 882 $ hg clone -U -u 0 a a-clone-failure
883 883 abort: cannot specify both --noupdate and --updaterev
884 884 [255]
885 885
886 886 $ hg clone --all-largefiles a ssh://localhost/a
887 887 abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a
888 888 [255]
889 889
890 890 Test pulling with --all-largefiles flag. Also test that the largefiles are
891 891 downloaded from 'default' instead of 'default-push' when no source is specified
892 892 (issue3584)
893 893
894 894 $ rm -Rf a-backup
895 895 $ hg clone -r 1 a a-backup
896 896 adding changesets
897 897 adding manifests
898 898 adding file changes
899 899 added 2 changesets with 8 changes to 4 files
900 900 updating to branch default
901 901 getting changed largefiles
902 902 2 largefiles updated, 0 removed
903 903 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
904 904 $ rm "${USERCACHE}"/*
905 905 $ cd a-backup
906 906 $ hg pull --all-largefiles --config paths.default-push=bogus/path
907 907 pulling from $TESTTMP/a (glob)
908 908 searching for changes
909 909 adding changesets
910 910 adding manifests
911 911 adding file changes
912 912 added 6 changesets with 16 changes to 8 files
913 913 (run 'hg update' to get a working copy)
914 914 6 additional largefiles cached
915 915
916 916 redo pull with --lfrev and check it pulls largefiles for the right revs
917 917
918 918 $ hg rollback
919 919 repository tip rolled back to revision 1 (undo pull)
920 920 $ hg pull -v --lfrev 'heads(pulled())+min(pulled())'
921 921 pulling from $TESTTMP/a (glob)
922 922 searching for changes
923 923 all local heads known remotely
924 924 6 changesets found
925 925 adding changesets
926 926 adding manifests
927 927 adding file changes
928 928 added 6 changesets with 16 changes to 8 files
929 929 calling hook changegroup.lfiles: <function checkrequireslfiles at *> (glob)
930 930 (run 'hg update' to get a working copy)
931 931 pulling largefiles for revision 7
932 932 found 971fb41e78fea4f8e0ba5244784239371cb00591 in store
933 933 found 0d6d75887db61b2c7e6c74b5dd8fc6ad50c0cc30 in store
934 934 found bb3151689acb10f0c3125c560d5e63df914bc1af in store
935 935 pulling largefiles for revision 2
936 936 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
937 937 0 largefiles cached
938 938
939 939 lfpull
940 940
941 941 $ hg lfpull -r : --config largefiles.usercache=usercache-lfpull
942 942 2 largefiles cached
943 943 $ hg lfpull -v -r 4+2 --config largefiles.usercache=usercache-lfpull
944 944 pulling largefiles for revision 4
945 945 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
946 946 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
947 947 pulling largefiles for revision 2
948 948 found eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 in store
949 949 0 largefiles cached
950 950
951 951 $ ls usercache-lfpull/* | sort
952 952 usercache-lfpull/1deebade43c8c498a3c8daddac0244dc55d1331d
953 953 usercache-lfpull/4669e532d5b2c093a78eca010077e708a071bb64
954 954
955 955 $ cd ..
956 956
957 957 Rebasing between two repositories does not revert largefiles to old
958 958 revisions (this was a very bad bug that took a lot of work to fix).
959 959
960 960 $ hg clone a d
961 961 updating to branch default
962 962 getting changed largefiles
963 963 3 largefiles updated, 0 removed
964 964 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
965 965 $ cd b
966 966 $ echo large4-modified > sub/large4
967 967 $ echo normal3-modified > normal3
968 968 $ hg commit -m "modify normal file and largefile in repo b"
969 969 Invoking status precommit hook
970 970 M normal3
971 971 M sub/large4
972 972 $ cd ../d
973 973 $ echo large6-modified > sub2/large6
974 974 $ echo normal4-modified > sub/normal4
975 975 $ hg commit -m "modify normal file largefile in repo d"
976 976 Invoking status precommit hook
977 977 M sub/normal4
978 978 M sub2/large6
979 979 $ cd ..
980 980 $ hg clone d e
981 981 updating to branch default
982 982 getting changed largefiles
983 983 3 largefiles updated, 0 removed
984 984 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
985 985 $ cd d
986 986
987 987 More rebase testing, but also test that the largefiles are downloaded from
988 988 'default-push' when no source is specified (issue3584). (The largefile from the
989 989 pulled revision is however not downloaded but found in the local cache.)
990 990 Largefiles are fetched for the new pulled revision, not for existing revisions,
991 991 rebased or not.
992 992
993 993 $ [ ! -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
994 994 $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
995 995 pulling from $TESTTMP/b (glob)
996 996 searching for changes
997 997 adding changesets
998 998 adding manifests
999 999 adding file changes
1000 1000 added 1 changesets with 2 changes to 2 files (+1 heads)
1001 1001 Invoking status precommit hook
1002 1002 M sub/normal4
1003 1003 M sub2/large6
1004 1004 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
1005 1005 0 additional largefiles cached
1006 1006 nothing to rebase
1007 1007 $ [ -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
1008 1008 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1009 1009 9:598410d3eb9a modify normal file largefile in repo d
1010 1010 8:a381d2c8c80e modify normal file and largefile in repo b
1011 1011 7:daea875e9014 add/edit more largefiles
1012 1012 6:4355d653f84f edit files yet again
1013 1013 5:9d5af5072dbd edit files again
1014 1014 4:74c02385b94c move files
1015 1015 3:9e8fbc4bce62 copy files
1016 1016 2:51a0ae4d5864 remove files
1017 1017 1:ce8896473775 edit files
1018 1018 0:30d30fe6a5be add files
1019 1019 $ cat normal3
1020 1020 normal3-modified
1021 1021 $ cat sub/normal4
1022 1022 normal4-modified
1023 1023 $ cat sub/large4
1024 1024 large4-modified
1025 1025 $ cat sub2/large6
1026 1026 large6-modified
1027 1027 $ cat sub2/large7
1028 1028 large7
1029 1029 $ cd ../e
1030 1030 $ hg pull ../b
1031 1031 pulling from ../b
1032 1032 searching for changes
1033 1033 adding changesets
1034 1034 adding manifests
1035 1035 adding file changes
1036 1036 added 1 changesets with 2 changes to 2 files (+1 heads)
1037 1037 (run 'hg heads' to see heads, 'hg merge' to merge)
1038 1038 $ hg rebase
1039 1039 Invoking status precommit hook
1040 1040 M sub/normal4
1041 1041 M sub2/large6
1042 1042 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
1043 1043 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1044 1044 9:598410d3eb9a modify normal file largefile in repo d
1045 1045 8:a381d2c8c80e modify normal file and largefile in repo b
1046 1046 7:daea875e9014 add/edit more largefiles
1047 1047 6:4355d653f84f edit files yet again
1048 1048 5:9d5af5072dbd edit files again
1049 1049 4:74c02385b94c move files
1050 1050 3:9e8fbc4bce62 copy files
1051 1051 2:51a0ae4d5864 remove files
1052 1052 1:ce8896473775 edit files
1053 1053 0:30d30fe6a5be add files
1054 1054 $ cat normal3
1055 1055 normal3-modified
1056 1056 $ cat sub/normal4
1057 1057 normal4-modified
1058 1058 $ cat sub/large4
1059 1059 large4-modified
1060 1060 $ cat sub2/large6
1061 1061 large6-modified
1062 1062 $ cat sub2/large7
1063 1063 large7
1064 1064
1065 1065 Log on largefiles
1066 1066
1067 1067 - same output
1068 1068 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub/large4
1069 1069 8:a381d2c8c80e modify normal file and largefile in repo b
1070 1070 6:4355d653f84f edit files yet again
1071 1071 5:9d5af5072dbd edit files again
1072 1072 4:74c02385b94c move files
1073 1073 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub/large4
1074 1074 8:a381d2c8c80e modify normal file and largefile in repo b
1075 1075 6:4355d653f84f edit files yet again
1076 1076 5:9d5af5072dbd edit files again
1077 1077 4:74c02385b94c move files
1078 1078
1079 1079 - .hglf only matches largefiles, without .hglf it matches 9 bco sub/normal
1080 1080 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' .hglf/sub
1081 1081 8:a381d2c8c80e modify normal file and largefile in repo b
1082 1082 6:4355d653f84f edit files yet again
1083 1083 5:9d5af5072dbd edit files again
1084 1084 4:74c02385b94c move files
1085 1085 1:ce8896473775 edit files
1086 1086 0:30d30fe6a5be add files
1087 1087 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' sub
1088 1088 9:598410d3eb9a modify normal file largefile in repo d
1089 1089 8:a381d2c8c80e modify normal file and largefile in repo b
1090 1090 6:4355d653f84f edit files yet again
1091 1091 5:9d5af5072dbd edit files again
1092 1092 4:74c02385b94c move files
1093 1093 1:ce8896473775 edit files
1094 1094 0:30d30fe6a5be add files
1095 1095
1096 1096 - globbing gives same result
1097 1097 $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 'glob:sub/*'
1098 1098 9:598410d3eb9a modify normal file largefile in repo d
1099 1099 8:a381d2c8c80e modify normal file and largefile in repo b
1100 1100 6:4355d653f84f edit files yet again
1101 1101 5:9d5af5072dbd edit files again
1102 1102 4:74c02385b94c move files
1103 1103 1:ce8896473775 edit files
1104 1104 0:30d30fe6a5be add files
1105 1105
1106 1106 Rollback on largefiles.
1107 1107
1108 1108 $ echo large4-modified-again > sub/large4
1109 1109 $ hg commit -m "Modify large4 again"
1110 1110 Invoking status precommit hook
1111 1111 M sub/large4
1112 1112 $ hg rollback
1113 1113 repository tip rolled back to revision 9 (undo commit)
1114 1114 working directory now based on revision 9
1115 1115 $ hg st
1116 1116 M sub/large4
1117 1117 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1118 1118 9:598410d3eb9a modify normal file largefile in repo d
1119 1119 8:a381d2c8c80e modify normal file and largefile in repo b
1120 1120 7:daea875e9014 add/edit more largefiles
1121 1121 6:4355d653f84f edit files yet again
1122 1122 5:9d5af5072dbd edit files again
1123 1123 4:74c02385b94c move files
1124 1124 3:9e8fbc4bce62 copy files
1125 1125 2:51a0ae4d5864 remove files
1126 1126 1:ce8896473775 edit files
1127 1127 0:30d30fe6a5be add files
1128 1128 $ cat sub/large4
1129 1129 large4-modified-again
1130 1130
1131 1131 "update --check" refuses to update with uncommitted changes.
1132 1132 $ hg update --check 8
1133 1133 abort: uncommitted local changes
1134 1134 [255]
1135 1135
1136 1136 "update --clean" leaves correct largefiles in working copy, even when there is
1137 1137 .orig files from revert in .hglf.
1138 1138
1139 1139 $ echo mistake > sub2/large7
1140 1140 $ hg revert sub2/large7
1141 1141 $ hg -q update --clean -r null
1142 1142 $ hg update --clean
1143 1143 getting changed largefiles
1144 1144 3 largefiles updated, 0 removed
1145 1145 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1146 1146 $ cat normal3
1147 1147 normal3-modified
1148 1148 $ cat sub/normal4
1149 1149 normal4-modified
1150 1150 $ cat sub/large4
1151 1151 large4-modified
1152 1152 $ cat sub2/large6
1153 1153 large6-modified
1154 1154 $ cat sub2/large7
1155 1155 large7
1156 1156 $ cat sub2/large7.orig
1157 1157 mistake
1158 1158 $ cat .hglf/sub2/large7.orig
1159 1159 9dbfb2c79b1c40981b258c3efa1b10b03f18ad31
1160 1160
1161 1161 demonstrate misfeature: .orig file is overwritten on every update -C,
1162 1162 also when clean:
1163 1163 $ hg update --clean
1164 1164 getting changed largefiles
1165 1165 0 largefiles updated, 0 removed
1166 1166 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1167 1167 $ cat sub2/large7.orig
1168 1168 large7
1169 1169 $ rm sub2/large7.orig .hglf/sub2/large7.orig
1170 1170
1171 1171 Now "update check" is happy.
1172 1172 $ hg update --check 8
1173 1173 getting changed largefiles
1174 1174 1 largefiles updated, 0 removed
1175 1175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1176 1176 $ hg update --check
1177 1177 getting changed largefiles
1178 1178 1 largefiles updated, 0 removed
1179 1179 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1180 1180
1181 1181 Test removing empty largefiles directories on update
1182 1182 $ test -d sub2 && echo "sub2 exists"
1183 1183 sub2 exists
1184 1184 $ hg update -q null
1185 1185 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1186 1186 [1]
1187 1187 $ hg update -q
1188 1188
1189 1189 Test hg remove removes empty largefiles directories
1190 1190 $ test -d sub2 && echo "sub2 exists"
1191 1191 sub2 exists
1192 1192 $ hg remove sub2/*
1193 1193 $ test -d sub2 && echo "error: sub2 should not exist anymore"
1194 1194 [1]
1195 1195 $ hg revert sub2/large6 sub2/large7
1196 1196
1197 1197 "revert" works on largefiles (and normal files too).
1198 1198 $ echo hack3 >> normal3
1199 1199 $ echo hack4 >> sub/normal4
1200 1200 $ echo hack4 >> sub/large4
1201 1201 $ rm sub2/large6
1202 1202 $ hg revert sub2/large6
1203 1203 $ hg rm sub2/large6
1204 1204 $ echo new >> sub2/large8
1205 1205 $ hg add --large sub2/large8
1206 1206 # XXX we don't really want to report that we're reverting the standin;
1207 1207 # that's just an implementation detail. But I don't see an obvious fix. ;-(
1208 1208 $ hg revert sub
1209 1209 reverting .hglf/sub/large4 (glob)
1210 1210 reverting sub/normal4 (glob)
1211 1211 $ hg status
1212 1212 M normal3
1213 1213 A sub2/large8
1214 1214 R sub2/large6
1215 1215 ? sub/large4.orig
1216 1216 ? sub/normal4.orig
1217 1217 $ cat sub/normal4
1218 1218 normal4-modified
1219 1219 $ cat sub/large4
1220 1220 large4-modified
1221 1221 $ hg revert -a --no-backup
1222 1222 undeleting .hglf/sub2/large6 (glob)
1223 1223 forgetting .hglf/sub2/large8 (glob)
1224 1224 reverting normal3
1225 1225 $ hg status
1226 1226 ? sub/large4.orig
1227 1227 ? sub/normal4.orig
1228 1228 ? sub2/large8
1229 1229 $ cat normal3
1230 1230 normal3-modified
1231 1231 $ cat sub2/large6
1232 1232 large6-modified
1233 1233 $ rm sub/*.orig sub2/large8
1234 1234
1235 1235 revert some files to an older revision
1236 1236 $ hg revert --no-backup -r 8 sub2
1237 1237 reverting .hglf/sub2/large6 (glob)
1238 1238 $ cat sub2/large6
1239 1239 large6
1240 1240 $ hg revert --no-backup -C -r '.^' sub2
1241 1241 reverting .hglf/sub2/large6 (glob)
1242 1242 $ hg revert --no-backup sub2
1243 1243 reverting .hglf/sub2/large6 (glob)
1244 1244 $ hg status
1245 1245
1246 1246 "verify --large" actually verifies largefiles
1247 1247
1248 1248 - Where Do We Come From? What Are We? Where Are We Going?
1249 1249 $ pwd
1250 1250 $TESTTMP/e
1251 1251 $ hg paths
1252 1252 default = $TESTTMP/d (glob)
1253 1253
1254 1254 $ hg verify --large
1255 1255 checking changesets
1256 1256 checking manifests
1257 1257 crosschecking files in changesets and manifests
1258 1258 checking files
1259 1259 10 files, 10 changesets, 28 total revisions
1260 1260 searching 1 changesets for largefiles
1261 1261 verified existence of 3 revisions of 3 largefiles
1262 1262
1263 1263 - introduce missing blob in local store repo and make sure that this is caught:
1264 1264 $ mv $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 .
1265 1265 $ hg verify --large
1266 1266 checking changesets
1267 1267 checking manifests
1268 1268 crosschecking files in changesets and manifests
1269 1269 checking files
1270 1270 10 files, 10 changesets, 28 total revisions
1271 1271 searching 1 changesets for largefiles
1272 1272 changeset 9:598410d3eb9a: sub/large4 references missing $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1273 1273 verified existence of 3 revisions of 3 largefiles
1274 1274 [1]
1275 1275
1276 1276 - introduce corruption and make sure that it is caught when checking content:
1277 1277 $ echo '5 cents' > $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928
1278 1278 $ hg verify -q --large --lfc
1279 1279 changeset 9:598410d3eb9a: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 (glob)
1280 1280 [1]
1281 1281
1282 1282 - cleanup
1283 1283 $ mv e166e74c7303192238d60af5a9c4ce9bef0b7928 $TESTTMP/d/.hg/largefiles/
1284 1284
1285 1285 - verifying all revisions will fail because we didn't clone all largefiles to d:
1286 1286 $ echo 'T-shirt' > $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1287 1287 $ hg verify -q --lfa --lfc
1288 1288 changeset 0:30d30fe6a5be: large1 references missing $TESTTMP/d/.hg/largefiles/4669e532d5b2c093a78eca010077e708a071bb64 (glob)
1289 1289 changeset 0:30d30fe6a5be: sub/large2 references missing $TESTTMP/d/.hg/largefiles/1deebade43c8c498a3c8daddac0244dc55d1331d (glob)
1290 1290 changeset 1:ce8896473775: large1 references missing $TESTTMP/d/.hg/largefiles/5f78770c0e77ba4287ad6ef3071c9bf9c379742f (glob)
1291 1291 changeset 1:ce8896473775: sub/large2 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1292 1292 changeset 3:9e8fbc4bce62: large1 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1293 1293 changeset 4:74c02385b94c: large3 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1294 1294 changeset 4:74c02385b94c: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
1295 1295 changeset 5:9d5af5072dbd: large3 references missing $TESTTMP/d/.hg/largefiles/baaf12afde9d8d67f25dab6dced0d2bf77dba47c (glob)
1296 1296 changeset 5:9d5af5072dbd: sub/large4 references missing $TESTTMP/d/.hg/largefiles/aeb2210d19f02886dde00dac279729a48471e2f9 (glob)
1297 1297 changeset 6:4355d653f84f: large3 references missing $TESTTMP/d/.hg/largefiles/7838695e10da2bb75ac1156565f40a2595fa2fa0 (glob)
1298 1298 [1]
1299 1299
1300 1300 - cleanup
1301 1301 $ rm $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
1302 1302 $ rm -f .hglf/sub/*.orig
1303 1303
1304 1304 Update to revision with missing largefile - and make sure it really is missing
1305 1305
1306 1306 $ rm ${USERCACHE}/7838695e10da2bb75ac1156565f40a2595fa2fa0
1307 1307 $ hg up -r 6
1308 1308 getting changed largefiles
1309 1309 error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
1310 1310 1 largefiles updated, 2 removed
1311 1311 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
1312 1312 $ rm normal3
1313 1313 $ echo >> sub/normal4
1314 1314 $ hg ci -m 'commit with missing files'
1315 1315 Invoking status precommit hook
1316 1316 M sub/normal4
1317 1317 ! large3
1318 1318 ! normal3
1319 1319 created new head
1320 1320 $ hg st
1321 1321 ! large3
1322 1322 ! normal3
1323 1323 $ hg up -r.
1324 1324 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1325 1325 $ hg st
1326 1326 ! large3
1327 1327 ! normal3
1328 1328 $ hg up -Cr.
1329 1329 getting changed largefiles
1330 1330 error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
1331 1331 0 largefiles updated, 0 removed
1332 1332 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1333 1333 $ hg st
1334 1334 ! large3
1335 1335 $ hg rollback
1336 1336 repository tip rolled back to revision 9 (undo commit)
1337 1337 working directory now based on revision 6
1338 1338
1339 1339 Merge with revision with missing largefile - and make sure it tries to fetch it.
1340 1340
1341 1341 $ hg up -Cqr null
1342 1342 $ echo f > f
1343 1343 $ hg ci -Am branch
1344 1344 adding f
1345 1345 Invoking status precommit hook
1346 1346 A f
1347 1347 created new head
1348 1348 $ hg merge -r 6
1349 1349 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1350 1350 (branch merge, don't forget to commit)
1351 1351 getting changed largefiles
1352 1352 error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
1353 1353 1 largefiles updated, 0 removed
1354 1354
1355 1355 $ hg rollback -q
1356 1356 $ hg up -Cq
1357 1357
1358 1358 Pulling 0 revisions with --all-largefiles should not fetch for all revisions
1359 1359
1360 1360 $ hg pull --all-largefiles
1361 1361 pulling from $TESTTMP/d (glob)
1362 1362 searching for changes
1363 1363 no changes found
1364 1364 0 additional largefiles cached
1365 1365
1366 1366 Merging does not revert to old versions of largefiles and also check
1367 1367 that merging after having pulled from a non-default remote works
1368 1368 correctly.
1369 1369
1370 1370 $ cd ..
1371 1371 $ hg clone -r 7 e temp
1372 1372 adding changesets
1373 1373 adding manifests
1374 1374 adding file changes
1375 1375 added 8 changesets with 24 changes to 10 files
1376 1376 updating to branch default
1377 1377 getting changed largefiles
1378 1378 3 largefiles updated, 0 removed
1379 1379 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1380 1380 $ hg clone temp f
1381 1381 updating to branch default
1382 1382 getting changed largefiles
1383 1383 3 largefiles updated, 0 removed
1384 1384 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1385 1385 # Delete the largefiles in the largefiles system cache so that we have an
1386 1386 # opportunity to test that caching after a pull works.
1387 1387 $ rm "${USERCACHE}"/*
1388 1388 $ cd f
1389 1389 $ echo "large4-merge-test" > sub/large4
1390 1390 $ hg commit -m "Modify large4 to test merge"
1391 1391 Invoking status precommit hook
1392 1392 M sub/large4
1393 1393 # Test --cache-largefiles flag
1394 $ hg pull --cache-largefiles ../e
1394 $ hg pull --lfrev 'heads(pulled())' ../e
1395 1395 pulling from ../e
1396 1396 searching for changes
1397 1397 adding changesets
1398 1398 adding manifests
1399 1399 adding file changes
1400 1400 added 2 changesets with 4 changes to 4 files (+1 heads)
1401 1401 (run 'hg heads' to see heads, 'hg merge' to merge)
1402 caching largefiles for 1 heads
1403 1402 2 largefiles cached
1404 1403 $ hg merge
1405 1404 merging sub/large4
1406 1405 largefile sub/large4 has a merge conflict
1407 1406 keep (l)ocal or take (o)ther? l
1408 1407 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
1409 1408 (branch merge, don't forget to commit)
1410 1409 getting changed largefiles
1411 1410 1 largefiles updated, 0 removed
1412 1411 $ hg commit -m "Merge repos e and f"
1413 1412 Invoking status precommit hook
1414 1413 M normal3
1415 1414 M sub/normal4
1416 1415 M sub2/large6
1417 1416 $ cat normal3
1418 1417 normal3-modified
1419 1418 $ cat sub/normal4
1420 1419 normal4-modified
1421 1420 $ cat sub/large4
1422 1421 large4-merge-test
1423 1422 $ cat sub2/large6
1424 1423 large6-modified
1425 1424 $ cat sub2/large7
1426 1425 large7
1427 1426
1428 1427 Test status after merging with a branch that introduces a new largefile:
1429 1428
1430 1429 $ echo large > large
1431 1430 $ hg add --large large
1432 1431 $ hg commit -m 'add largefile'
1433 1432 Invoking status precommit hook
1434 1433 A large
1435 1434 $ hg update -q ".^"
1436 1435 $ echo change >> normal3
1437 1436 $ hg commit -m 'some change'
1438 1437 Invoking status precommit hook
1439 1438 M normal3
1440 1439 created new head
1441 1440 $ hg merge
1442 1441 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1443 1442 (branch merge, don't forget to commit)
1444 1443 getting changed largefiles
1445 1444 1 largefiles updated, 0 removed
1446 1445 $ hg status
1447 1446 M large
1448 1447
1449 1448 - make sure update of merge with removed largefiles fails as expected
1450 1449 $ hg rm sub2/large6
1451 1450 $ hg up -r.
1452 1451 abort: outstanding uncommitted merges
1453 1452 [255]
1454 1453
1455 1454 - revert should be able to revert files introduced in a pending merge
1456 1455 $ hg revert --all -r .
1457 1456 removing .hglf/large (glob)
1458 1457 undeleting .hglf/sub2/large6 (glob)
1459 1458
1460 1459 Test that a normal file and a largefile with the same name and path cannot
1461 1460 coexist.
1462 1461
1463 1462 $ rm sub2/large7
1464 1463 $ echo "largeasnormal" > sub2/large7
1465 1464 $ hg add sub2/large7
1466 1465 sub2/large7 already a largefile
1467 1466
1468 1467 Test that transplanting a largefile change works correctly.
1469 1468
1470 1469 $ cd ..
1471 1470 $ hg clone -r 8 d g
1472 1471 adding changesets
1473 1472 adding manifests
1474 1473 adding file changes
1475 1474 added 9 changesets with 26 changes to 10 files
1476 1475 updating to branch default
1477 1476 getting changed largefiles
1478 1477 3 largefiles updated, 0 removed
1479 1478 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1480 1479 $ cd g
1481 1480 $ hg transplant -s ../d 598410d3eb9a
1482 1481 searching for changes
1483 1482 searching for changes
1484 1483 adding changesets
1485 1484 adding manifests
1486 1485 adding file changes
1487 1486 added 1 changesets with 2 changes to 2 files
1488 1487 getting changed largefiles
1489 1488 1 largefiles updated, 0 removed
1490 1489 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
1491 1490 9:598410d3eb9a modify normal file largefile in repo d
1492 1491 8:a381d2c8c80e modify normal file and largefile in repo b
1493 1492 7:daea875e9014 add/edit more largefiles
1494 1493 6:4355d653f84f edit files yet again
1495 1494 5:9d5af5072dbd edit files again
1496 1495 4:74c02385b94c move files
1497 1496 3:9e8fbc4bce62 copy files
1498 1497 2:51a0ae4d5864 remove files
1499 1498 1:ce8896473775 edit files
1500 1499 0:30d30fe6a5be add files
1501 1500 $ cat normal3
1502 1501 normal3-modified
1503 1502 $ cat sub/normal4
1504 1503 normal4-modified
1505 1504 $ cat sub/large4
1506 1505 large4-modified
1507 1506 $ cat sub2/large6
1508 1507 large6-modified
1509 1508 $ cat sub2/large7
1510 1509 large7
1511 1510
1512 1511 Cat a largefile
1513 1512 $ hg cat normal3
1514 1513 normal3-modified
1515 1514 $ hg cat sub/large4
1516 1515 large4-modified
1517 1516 $ rm "${USERCACHE}"/*
1518 1517 $ hg cat -r a381d2c8c80e -o cat.out sub/large4
1519 1518 $ cat cat.out
1520 1519 large4-modified
1521 1520 $ rm cat.out
1522 1521 $ hg cat -r a381d2c8c80e normal3
1523 1522 normal3-modified
1524 1523 $ hg cat -r '.^' normal3
1525 1524 normal3-modified
1526 1525 $ hg cat -r '.^' sub/large4 doesntexist
1527 1526 large4-modified
1528 1527 doesntexist: no such file in rev a381d2c8c80e
1529 1528 $ hg --cwd sub cat -r '.^' large4
1530 1529 large4-modified
1531 1530 $ hg --cwd sub cat -r '.^' ../normal3
1532 1531 normal3-modified
1533 1532
1534 1533 Test that renaming a largefile results in correct output for status
1535 1534
1536 1535 $ hg rename sub/large4 large4-renamed
1537 1536 $ hg commit -m "test rename output"
1538 1537 Invoking status precommit hook
1539 1538 A large4-renamed
1540 1539 R sub/large4
1541 1540 $ cat large4-renamed
1542 1541 large4-modified
1543 1542 $ cd sub2
1544 1543 $ hg rename large6 large6-renamed
1545 1544 $ hg st
1546 1545 A sub2/large6-renamed
1547 1546 R sub2/large6
1548 1547 $ cd ..
1549 1548
1550 1549 Test --normal flag
1551 1550
1552 1551 $ dd if=/dev/zero bs=2k count=11k > new-largefile 2> /dev/null
1553 1552 $ hg add --normal --large new-largefile
1554 1553 abort: --normal cannot be used with --large
1555 1554 [255]
1556 1555 $ hg add --normal new-largefile
1557 1556 new-largefile: up to 69 MB of RAM may be required to manage this file
1558 1557 (use 'hg revert new-largefile' to cancel the pending addition)
1559 1558 $ cd ..
1560 1559
1561 1560 #if serve
1562 1561 vanilla clients not locked out from largefiles servers on vanilla repos
1563 1562 $ mkdir r1
1564 1563 $ cd r1
1565 1564 $ hg init
1566 1565 $ echo c1 > f1
1567 1566 $ hg add f1
1568 1567 $ hg commit -m "m1"
1569 1568 Invoking status precommit hook
1570 1569 A f1
1571 1570 $ cd ..
1572 1571 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
1573 1572 $ cat hg.pid >> $DAEMON_PIDS
1574 1573 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
1575 1574 requesting all changes
1576 1575 adding changesets
1577 1576 adding manifests
1578 1577 adding file changes
1579 1578 added 1 changesets with 1 changes to 1 files
1580 1579 updating to branch default
1581 1580 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1582 1581
1583 1582 largefiles clients still work with vanilla servers
1584 1583 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
1585 1584 $ cat hg.pid >> $DAEMON_PIDS
1586 1585 $ hg clone http://localhost:$HGPORT1 r3
1587 1586 requesting all changes
1588 1587 adding changesets
1589 1588 adding manifests
1590 1589 adding file changes
1591 1590 added 1 changesets with 1 changes to 1 files
1592 1591 updating to branch default
1593 1592 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1594 1593 #endif
1595 1594
1596 1595
1597 1596 vanilla clients locked out from largefiles http repos
1598 1597 $ mkdir r4
1599 1598 $ cd r4
1600 1599 $ hg init
1601 1600 $ echo c1 > f1
1602 1601 $ hg add --large f1
1603 1602 $ hg commit -m "m1"
1604 1603 Invoking status precommit hook
1605 1604 A f1
1606 1605 $ cd ..
1607 1606
1608 1607 largefiles can be pushed locally (issue3583)
1609 1608 $ hg init dest
1610 1609 $ cd r4
1611 1610 $ hg outgoing ../dest
1612 1611 comparing with ../dest
1613 1612 searching for changes
1614 1613 changeset: 0:639881c12b4c
1615 1614 tag: tip
1616 1615 user: test
1617 1616 date: Thu Jan 01 00:00:00 1970 +0000
1618 1617 summary: m1
1619 1618
1620 1619 $ hg push ../dest
1621 1620 pushing to ../dest
1622 1621 searching for changes
1623 1622 searching for changes
1624 1623 adding changesets
1625 1624 adding manifests
1626 1625 adding file changes
1627 1626 added 1 changesets with 1 changes to 1 files
1628 1627
1629 1628 exit code with nothing outgoing (issue3611)
1630 1629 $ hg outgoing ../dest
1631 1630 comparing with ../dest
1632 1631 searching for changes
1633 1632 no changes found
1634 1633 [1]
1635 1634 $ cd ..
1636 1635
1637 1636 #if serve
1638 1637 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
1639 1638 $ cat hg.pid >> $DAEMON_PIDS
1640 1639 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
1641 1640 abort: remote error:
1642 1641
1643 1642 This repository uses the largefiles extension.
1644 1643
1645 1644 Please enable it in your Mercurial config file.
1646 1645 [255]
1647 1646
1648 1647 used all HGPORTs, kill all daemons
1649 1648 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1650 1649 #endif
1651 1650
1652 1651 vanilla clients locked out from largefiles ssh repos
1653 1652 $ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
1654 1653 abort: remote error:
1655 1654
1656 1655 This repository uses the largefiles extension.
1657 1656
1658 1657 Please enable it in your Mercurial config file.
1659 1658 [255]
1660 1659
1661 1660 #if serve
1662 1661
1663 1662 largefiles clients refuse to push largefiles repos to vanilla servers
1664 1663 $ mkdir r6
1665 1664 $ cd r6
1666 1665 $ hg init
1667 1666 $ echo c1 > f1
1668 1667 $ hg add f1
1669 1668 $ hg commit -m "m1"
1670 1669 Invoking status precommit hook
1671 1670 A f1
1672 1671 $ cat >> .hg/hgrc <<!
1673 1672 > [web]
1674 1673 > push_ssl = false
1675 1674 > allow_push = *
1676 1675 > !
1677 1676 $ cd ..
1678 1677 $ hg clone r6 r7
1679 1678 updating to branch default
1680 1679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1681 1680 $ cd r7
1682 1681 $ echo c2 > f2
1683 1682 $ hg add --large f2
1684 1683 $ hg commit -m "m2"
1685 1684 Invoking status precommit hook
1686 1685 A f2
1687 1686 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
1688 1687 $ cat ../hg.pid >> $DAEMON_PIDS
1689 1688 $ hg push http://localhost:$HGPORT
1690 1689 pushing to http://localhost:$HGPORT/
1691 1690 searching for changes
1692 1691 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
1693 1692 [255]
1694 1693 $ cd ..
1695 1694
1696 1695 putlfile errors are shown (issue3123)
1697 1696 Corrupt the cached largefile in r7 and move it out of the servers usercache
1698 1697 $ mv r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 .
1699 1698 $ echo 'client side corruption' > r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1700 1699 $ rm "$USERCACHE/4cdac4d8b084d0b599525cf732437fb337d422a8"
1701 1700 $ hg init empty
1702 1701 $ hg serve -R empty -d -p $HGPORT1 --pid-file hg.pid \
1703 1702 > --config 'web.allow_push=*' --config web.push_ssl=False
1704 1703 $ cat hg.pid >> $DAEMON_PIDS
1705 1704 $ hg push -R r7 http://localhost:$HGPORT1
1706 1705 pushing to http://localhost:$HGPORT1/
1707 1706 searching for changes
1708 1707 remote: largefiles: failed to put 4cdac4d8b084d0b599525cf732437fb337d422a8 into store: largefile contents do not match hash
1709 1708 abort: remotestore: could not put $TESTTMP/r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8 to remote store http://localhost:$HGPORT1/ (glob)
1710 1709 [255]
1711 1710 $ mv 4cdac4d8b084d0b599525cf732437fb337d422a8 r7/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1712 1711 Push of file that exists on server but is corrupted - magic healing would be nice ... but too magic
1713 1712 $ echo "server side corruption" > empty/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1714 1713 $ hg push -R r7 http://localhost:$HGPORT1
1715 1714 pushing to http://localhost:$HGPORT1/
1716 1715 searching for changes
1717 1716 searching for changes
1718 1717 remote: adding changesets
1719 1718 remote: adding manifests
1720 1719 remote: adding file changes
1721 1720 remote: added 2 changesets with 2 changes to 2 files
1722 1721 $ cat empty/.hg/largefiles/4cdac4d8b084d0b599525cf732437fb337d422a8
1723 1722 server side corruption
1724 1723 $ rm -rf empty
1725 1724
1726 1725 Push a largefiles repository to a served empty repository
1727 1726 $ hg init r8
1728 1727 $ echo c3 > r8/f1
1729 1728 $ hg add --large r8/f1 -R r8
1730 1729 $ hg commit -m "m1" -R r8
1731 1730 Invoking status precommit hook
1732 1731 A f1
1733 1732 $ hg init empty
1734 1733 $ hg serve -R empty -d -p $HGPORT2 --pid-file hg.pid \
1735 1734 > --config 'web.allow_push=*' --config web.push_ssl=False
1736 1735 $ cat hg.pid >> $DAEMON_PIDS
1737 1736 $ rm "${USERCACHE}"/*
1738 1737 $ hg push -R r8 http://localhost:$HGPORT2/#default
1739 1738 pushing to http://localhost:$HGPORT2/
1740 1739 searching for changes
1741 1740 searching for changes
1742 1741 remote: adding changesets
1743 1742 remote: adding manifests
1744 1743 remote: adding file changes
1745 1744 remote: added 1 changesets with 1 changes to 1 files
1746 1745 $ [ -f "${USERCACHE}"/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1747 1746 $ [ -f empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1748 1747
1749 1748 Clone over http, no largefiles pulled on clone.
1750 1749
1751 1750 $ hg clone http://localhost:$HGPORT2/#default http-clone -U
1752 1751 adding changesets
1753 1752 adding manifests
1754 1753 adding file changes
1755 1754 added 1 changesets with 1 changes to 1 files
1756 1755
1757 1756 test 'verify' with remotestore:
1758 1757
1759 1758 $ rm "${USERCACHE}"/02a439e5c31c526465ab1a0ca1f431f76b827b90
1760 1759 $ mv empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 .
1761 1760 $ hg -R http-clone verify --large --lfa
1762 1761 checking changesets
1763 1762 checking manifests
1764 1763 crosschecking files in changesets and manifests
1765 1764 checking files
1766 1765 1 files, 1 changesets, 1 total revisions
1767 1766 searching 1 changesets for largefiles
1768 1767 changeset 0:cf03e5bb9936: f1 missing
1769 1768 verified existence of 1 revisions of 1 largefiles
1770 1769 [1]
1771 1770 $ mv 02a439e5c31c526465ab1a0ca1f431f76b827b90 empty/.hg/largefiles/
1772 1771 $ hg -R http-clone -q verify --large --lfa
1773 1772
1774 1773 largefiles pulled on update - a largefile missing on the server:
1775 1774 $ mv empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 .
1776 1775 $ hg -R http-clone up --config largefiles.usercache=http-clone-usercache
1777 1776 getting changed largefiles
1778 1777 abort: remotestore: largefile 02a439e5c31c526465ab1a0ca1f431f76b827b90 is missing
1779 1778 [255]
1780 1779 $ hg -R http-clone up -Cqr null
1781 1780
1782 1781 largefiles pulled on update - a largefile corrupted on the server:
1783 1782 $ echo corruption > empty/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90
1784 1783 $ hg -R http-clone up --config largefiles.usercache=http-clone-usercache
1785 1784 getting changed largefiles
1786 1785 f1: data corruption (expected 02a439e5c31c526465ab1a0ca1f431f76b827b90, got 6a7bb2556144babe3899b25e5428123735bb1e27)
1787 1786 0 largefiles updated, 0 removed
1788 1787 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1789 1788 $ hg -R http-clone st
1790 1789 ! f1
1791 1790 $ [ ! -f http-clone/.hg/largefiles/02a439e5c31c526465ab1a0ca1f431f76b827b90 ]
1792 1791 $ [ ! -f http-clone/f1 ]
1793 1792 $ [ ! -f http-clone-usercache ]
1794 1793 $ hg -R http-clone verify --large --lfc
1795 1794 checking changesets
1796 1795 checking manifests
1797 1796 crosschecking files in changesets and manifests
1798 1797 checking files
1799 1798 1 files, 1 changesets, 1 total revisions
1800 1799 searching 1 changesets for largefiles
1801 1800 verified contents of 1 revisions of 1 largefiles
1802 1801 $ hg -R http-clone up -Cqr null
1803 1802
1804 1803 largefiles pulled on update - no server side problems:
1805 1804 $ mv 02a439e5c31c526465ab1a0ca1f431f76b827b90 empty/.hg/largefiles/
1806 1805 $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
1807 1806 resolving manifests
1808 1807 branchmerge: False, force: False, partial: False
1809 1808 ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
1810 1809 .hglf/f1: remote created -> g
1811 1810 getting .hglf/f1
1812 1811 updating: .hglf/f1 1/1 files (100.00%)
1813 1812 getting changed largefiles
1814 1813 using http://localhost:$HGPORT2/
1815 1814 sending capabilities command
1816 1815 getting largefiles: 0/1 lfile (0.00%)
1817 1816 getting f1:02a439e5c31c526465ab1a0ca1f431f76b827b90
1818 1817 sending batch command
1819 1818 sending getlfile command
1820 1819 found 02a439e5c31c526465ab1a0ca1f431f76b827b90 in store
1821 1820 1 largefiles updated, 0 removed
1822 1821 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1823 1822
1824 1823 $ ls http-clone-usercache/*
1825 1824 http-clone-usercache/02a439e5c31c526465ab1a0ca1f431f76b827b90
1826 1825
1827 1826 $ rm -rf empty http-clone*
1828 1827
1829 1828 used all HGPORTs, kill all daemons
1830 1829 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1831 1830
1832 1831 #endif
1833 1832
1834 1833
1835 1834 #if unix-permissions
1836 1835
1837 1836 Clone a local repository owned by another user
1838 1837 We have to simulate that here by setting $HOME and removing write permissions
1839 1838 $ ORIGHOME="$HOME"
1840 1839 $ mkdir alice
1841 1840 $ HOME="`pwd`/alice"
1842 1841 $ cd alice
1843 1842 $ hg init pubrepo
1844 1843 $ cd pubrepo
1845 1844 $ dd if=/dev/zero bs=1k count=11k > a-large-file 2> /dev/null
1846 1845 $ hg add --large a-large-file
1847 1846 $ hg commit -m "Add a large file"
1848 1847 Invoking status precommit hook
1849 1848 A a-large-file
1850 1849 $ cd ..
1851 1850 $ chmod -R a-w pubrepo
1852 1851 $ cd ..
1853 1852 $ mkdir bob
1854 1853 $ HOME="`pwd`/bob"
1855 1854 $ cd bob
1856 1855 $ hg clone --pull ../alice/pubrepo pubrepo
1857 1856 requesting all changes
1858 1857 adding changesets
1859 1858 adding manifests
1860 1859 adding file changes
1861 1860 added 1 changesets with 1 changes to 1 files
1862 1861 updating to branch default
1863 1862 getting changed largefiles
1864 1863 1 largefiles updated, 0 removed
1865 1864 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1866 1865 $ cd ..
1867 1866 $ chmod -R u+w alice/pubrepo
1868 1867 $ HOME="$ORIGHOME"
1869 1868
1870 1869 #endif
1871 1870
1872 1871 #if symlink
1873 1872
1874 1873 Symlink to a large largefile should behave the same as a symlink to a normal file
1875 1874 $ hg init largesymlink
1876 1875 $ cd largesymlink
1877 1876 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
1878 1877 $ hg add --large largefile
1879 1878 $ hg commit -m "commit a large file"
1880 1879 Invoking status precommit hook
1881 1880 A largefile
1882 1881 $ ln -s largefile largelink
1883 1882 $ hg add largelink
1884 1883 $ hg commit -m "commit a large symlink"
1885 1884 Invoking status precommit hook
1886 1885 A largelink
1887 1886 $ rm -f largelink
1888 1887 $ hg up >/dev/null
1889 1888 $ test -f largelink
1890 1889 [1]
1891 1890 $ test -L largelink
1892 1891 [1]
1893 1892 $ rm -f largelink # make next part of the test independent of the previous
1894 1893 $ hg up -C >/dev/null
1895 1894 $ test -f largelink
1896 1895 $ test -L largelink
1897 1896 $ cd ..
1898 1897
1899 1898 #endif
1900 1899
1901 1900 test for pattern matching on 'hg status':
1902 1901 to boost performance, largefiles checks whether specified patterns are
1903 1902 related to largefiles in working directory (NOT to STANDIN) or not.
1904 1903
1905 1904 $ hg init statusmatch
1906 1905 $ cd statusmatch
1907 1906
1908 1907 $ mkdir -p a/b/c/d
1909 1908 $ echo normal > a/b/c/d/e.normal.txt
1910 1909 $ hg add a/b/c/d/e.normal.txt
1911 1910 $ echo large > a/b/c/d/e.large.txt
1912 1911 $ hg add --large a/b/c/d/e.large.txt
1913 1912 $ mkdir -p a/b/c/x
1914 1913 $ echo normal > a/b/c/x/y.normal.txt
1915 1914 $ hg add a/b/c/x/y.normal.txt
1916 1915 $ hg commit -m 'add files'
1917 1916 Invoking status precommit hook
1918 1917 A a/b/c/d/e.large.txt
1919 1918 A a/b/c/d/e.normal.txt
1920 1919 A a/b/c/x/y.normal.txt
1921 1920
1922 1921 (1) no pattern: no performance boost
1923 1922 $ hg status -A
1924 1923 C a/b/c/d/e.large.txt
1925 1924 C a/b/c/d/e.normal.txt
1926 1925 C a/b/c/x/y.normal.txt
1927 1926
1928 1927 (2) pattern not related to largefiles: performance boost
1929 1928 $ hg status -A a/b/c/x
1930 1929 C a/b/c/x/y.normal.txt
1931 1930
1932 1931 (3) pattern related to largefiles: no performance boost
1933 1932 $ hg status -A a/b/c/d
1934 1933 C a/b/c/d/e.large.txt
1935 1934 C a/b/c/d/e.normal.txt
1936 1935
1937 1936 (4) pattern related to STANDIN (not to largefiles): performance boost
1938 1937 $ hg status -A .hglf/a
1939 1938 C .hglf/a/b/c/d/e.large.txt
1940 1939
1941 1940 (5) mixed case: no performance boost
1942 1941 $ hg status -A a/b/c/x a/b/c/d
1943 1942 C a/b/c/d/e.large.txt
1944 1943 C a/b/c/d/e.normal.txt
1945 1944 C a/b/c/x/y.normal.txt
1946 1945
1947 1946 verify that largefiles doesn't break filesets
1948 1947
1949 1948 $ hg log --rev . --exclude "set:binary()"
1950 1949 changeset: 0:41bd42f10efa
1951 1950 tag: tip
1952 1951 user: test
1953 1952 date: Thu Jan 01 00:00:00 1970 +0000
1954 1953 summary: add files
1955 1954
1956 1955 verify that large files in subrepos handled properly
1957 1956 $ hg init subrepo
1958 1957 $ echo "subrepo = subrepo" > .hgsub
1959 1958 $ hg add .hgsub
1960 1959 $ hg ci -m "add subrepo"
1961 1960 Invoking status precommit hook
1962 1961 A .hgsub
1963 1962 ? .hgsubstate
1964 1963 $ echo "rev 1" > subrepo/large.txt
1965 1964 $ hg -R subrepo add --large subrepo/large.txt
1966 1965 $ hg sum
1967 1966 parent: 1:8ee150ea2e9c tip
1968 1967 add subrepo
1969 1968 branch: default
1970 1969 commit: 1 subrepos
1971 1970 update: (current)
1972 1971 $ hg st
1973 1972 $ hg st -S
1974 1973 A subrepo/large.txt
1975 1974 $ hg ci -S -m "commit top repo"
1976 1975 committing subrepository subrepo
1977 1976 Invoking status precommit hook
1978 1977 A large.txt
1979 1978 Invoking status precommit hook
1980 1979 M .hgsubstate
1981 1980 # No differences
1982 1981 $ hg st -S
1983 1982 $ hg sum
1984 1983 parent: 2:ce4cd0c527a6 tip
1985 1984 commit top repo
1986 1985 branch: default
1987 1986 commit: (clean)
1988 1987 update: (current)
1989 1988 $ echo "rev 2" > subrepo/large.txt
1990 1989 $ hg st -S
1991 1990 M subrepo/large.txt
1992 1991 $ hg sum
1993 1992 parent: 2:ce4cd0c527a6 tip
1994 1993 commit top repo
1995 1994 branch: default
1996 1995 commit: 1 subrepos
1997 1996 update: (current)
1998 1997 $ hg ci -m "this commit should fail without -S"
1999 1998 abort: uncommitted changes in subrepo subrepo
2000 1999 (use --subrepos for recursive commit)
2001 2000 [255]
2002 2001
2003 2002 Add a normal file to the subrepo, then test archiving
2004 2003
2005 2004 $ echo 'normal file' > subrepo/normal.txt
2006 2005 $ hg -R subrepo add subrepo/normal.txt
2007 2006
2008 2007 Lock in subrepo, otherwise the change isn't archived
2009 2008
2010 2009 $ hg ci -S -m "add normal file to top level"
2011 2010 committing subrepository subrepo
2012 2011 Invoking status precommit hook
2013 2012 M large.txt
2014 2013 A normal.txt
2015 2014 Invoking status precommit hook
2016 2015 M .hgsubstate
2017 2016 $ hg archive -S ../lf_subrepo_archive
2018 2017 $ find ../lf_subrepo_archive | sort
2019 2018 ../lf_subrepo_archive
2020 2019 ../lf_subrepo_archive/.hg_archival.txt
2021 2020 ../lf_subrepo_archive/.hgsub
2022 2021 ../lf_subrepo_archive/.hgsubstate
2023 2022 ../lf_subrepo_archive/a
2024 2023 ../lf_subrepo_archive/a/b
2025 2024 ../lf_subrepo_archive/a/b/c
2026 2025 ../lf_subrepo_archive/a/b/c/d
2027 2026 ../lf_subrepo_archive/a/b/c/d/e.large.txt
2028 2027 ../lf_subrepo_archive/a/b/c/d/e.normal.txt
2029 2028 ../lf_subrepo_archive/a/b/c/x
2030 2029 ../lf_subrepo_archive/a/b/c/x/y.normal.txt
2031 2030 ../lf_subrepo_archive/subrepo
2032 2031 ../lf_subrepo_archive/subrepo/large.txt
2033 2032 ../lf_subrepo_archive/subrepo/normal.txt
2034 2033
2035 2034 Test update with subrepos.
2036 2035
2037 2036 $ hg update 0
2038 2037 getting changed largefiles
2039 2038 0 largefiles updated, 1 removed
2040 2039 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
2041 2040 $ hg status -S
2042 2041 $ hg update tip
2043 2042 getting changed largefiles
2044 2043 1 largefiles updated, 0 removed
2045 2044 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
2046 2045 $ hg status -S
2047 2046 # modify a large file
2048 2047 $ echo "modified" > subrepo/large.txt
2049 2048 $ hg st -S
2050 2049 M subrepo/large.txt
2051 2050 # update -C should revert the change.
2052 2051 $ hg update -C
2053 2052 getting changed largefiles
2054 2053 1 largefiles updated, 0 removed
2055 2054 getting changed largefiles
2056 2055 0 largefiles updated, 0 removed
2057 2056 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2058 2057 $ hg status -S
2059 2058
2060 2059 Test archiving a revision that references a subrepo that is not yet
2061 2060 cloned (see test-subrepo-recursion.t):
2062 2061
2063 2062 $ hg clone -U . ../empty
2064 2063 $ cd ../empty
2065 2064 $ hg archive --subrepos -r tip ../archive.tar.gz
2066 2065 cloning subrepo subrepo from $TESTTMP/statusmatch/subrepo
2067 2066 $ cd ..
2068 2067
2069 2068 Test that addremove picks up largefiles prior to the initial commit (issue3541)
2070 2069
2071 2070 $ hg init addrm2
2072 2071 $ cd addrm2
2073 2072 $ touch large.dat
2074 2073 $ touch large2.dat
2075 2074 $ touch normal
2076 2075 $ hg add --large large.dat
2077 2076 $ hg addremove -v
2078 2077 adding large2.dat as a largefile
2079 2078 adding normal
2080 2079
2081 2080 Test that forgetting all largefiles reverts to islfilesrepo() == False
2082 2081 (addremove will add *.dat as normal files now)
2083 2082 $ hg forget large.dat
2084 2083 $ hg forget large2.dat
2085 2084 $ hg addremove -v
2086 2085 adding large.dat
2087 2086 adding large2.dat
2088 2087
2089 2088 Test commit's addremove option prior to the first commit
2090 2089 $ hg forget large.dat
2091 2090 $ hg forget large2.dat
2092 2091 $ hg add --large large.dat
2093 2092 $ hg ci -Am "commit"
2094 2093 adding large2.dat as a largefile
2095 2094 Invoking status precommit hook
2096 2095 A large.dat
2097 2096 A large2.dat
2098 2097 A normal
2099 2098 $ find .hglf | sort
2100 2099 .hglf
2101 2100 .hglf/large.dat
2102 2101 .hglf/large2.dat
2103 2102
2104 2103 Test actions on largefiles using relative paths from subdir
2105 2104
2106 2105 $ mkdir sub
2107 2106 $ cd sub
2108 2107 $ echo anotherlarge > anotherlarge
2109 2108 $ hg add --large anotherlarge
2110 2109 $ hg st
2111 2110 A sub/anotherlarge
2112 2111 $ hg st anotherlarge
2113 2112 A anotherlarge
2114 2113 $ hg commit -m anotherlarge anotherlarge
2115 2114 Invoking status precommit hook
2116 2115 A sub/anotherlarge
2117 2116 $ hg log anotherlarge
2118 2117 changeset: 1:9627a577c5e9
2119 2118 tag: tip
2120 2119 user: test
2121 2120 date: Thu Jan 01 00:00:00 1970 +0000
2122 2121 summary: anotherlarge
2123 2122
2124 2123 $ echo more >> anotherlarge
2125 2124 $ hg st .
2126 2125 M anotherlarge
2127 2126 $ hg cat anotherlarge
2128 2127 anotherlarge
2129 2128 $ hg revert anotherlarge
2130 2129 $ hg st
2131 2130 ? sub/anotherlarge.orig
2132 2131 $ cd ..
2133 2132
2134 2133 $ cd ..
2135 2134
2136 2135 issue3651: summary/outgoing with largefiles shows "no remote repo"
2137 2136 unexpectedly
2138 2137
2139 2138 $ mkdir issue3651
2140 2139 $ cd issue3651
2141 2140
2142 2141 $ hg init src
2143 2142 $ echo a > src/a
2144 2143 $ hg -R src add --large src/a
2145 2144 $ hg -R src commit -m '#0'
2146 2145 Invoking status precommit hook
2147 2146 A a
2148 2147
2149 2148 check messages when no remote repository is specified:
2150 2149 "no remote repo" route for "hg outgoing --large" is not tested here,
2151 2150 because it can't be reproduced easily.
2152 2151
2153 2152 $ hg init clone1
2154 2153 $ hg -R clone1 -q pull src
2155 2154 $ hg -R clone1 -q update
2156 2155 $ hg -R clone1 paths | grep default
2157 2156 [1]
2158 2157
2159 2158 $ hg -R clone1 summary --large
2160 2159 parent: 0:fc0bd45326d3 tip
2161 2160 #0
2162 2161 branch: default
2163 2162 commit: (clean)
2164 2163 update: (current)
2165 2164 largefiles: (no remote repo)
2166 2165
2167 2166 check messages when there is no files to upload:
2168 2167
2169 2168 $ hg -q clone src clone2
2170 2169 $ hg -R clone2 paths | grep default
2171 2170 default = $TESTTMP/issue3651/src (glob)
2172 2171
2173 2172 $ hg -R clone2 summary --large
2174 2173 parent: 0:fc0bd45326d3 tip
2175 2174 #0
2176 2175 branch: default
2177 2176 commit: (clean)
2178 2177 update: (current)
2179 2178 searching for changes
2180 2179 largefiles: (no files to upload)
2181 2180 $ hg -R clone2 outgoing --large
2182 2181 comparing with $TESTTMP/issue3651/src (glob)
2183 2182 searching for changes
2184 2183 no changes found
2185 2184 searching for changes
2186 2185 largefiles: no files to upload
2187 2186 [1]
2188 2187
2189 2188 check messages when there are files to upload:
2190 2189
2191 2190 $ echo b > clone2/b
2192 2191 $ hg -R clone2 add --large clone2/b
2193 2192 $ hg -R clone2 commit -m '#1'
2194 2193 Invoking status precommit hook
2195 2194 A b
2196 2195 $ hg -R clone2 summary --large
2197 2196 parent: 1:1acbe71ce432 tip
2198 2197 #1
2199 2198 branch: default
2200 2199 commit: (clean)
2201 2200 update: (current)
2202 2201 searching for changes
2203 2202 largefiles: 1 to upload
2204 2203 $ hg -R clone2 outgoing --large
2205 2204 comparing with $TESTTMP/issue3651/src (glob)
2206 2205 searching for changes
2207 2206 changeset: 1:1acbe71ce432
2208 2207 tag: tip
2209 2208 user: test
2210 2209 date: Thu Jan 01 00:00:00 1970 +0000
2211 2210 summary: #1
2212 2211
2213 2212 searching for changes
2214 2213 largefiles to upload:
2215 2214 b
2216 2215
2217 2216
2218 2217 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now