##// END OF EJS Templates
largefiles: file storage should be relative to repo, not relative to cwd...
Mads Kiilerich -
r15553:e89385e4 stable
parent child Browse files
Show More
@@ -1,453 +1,453 b''
1 # Copyright 2009-2010 Gregory P. Ward
1 # Copyright 2009-2010 Gregory P. Ward
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
3 # Copyright 2010-2011 Fog Creek Software
3 # Copyright 2010-2011 Fog Creek Software
4 # Copyright 2010-2011 Unity Technologies
4 # Copyright 2010-2011 Unity Technologies
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''largefiles utility code: must not import other modules in this package.'''
9 '''largefiles utility code: must not import other modules in this package.'''
10
10
11 import os
11 import os
12 import errno
12 import errno
13 import platform
13 import platform
14 import shutil
14 import shutil
15 import stat
15 import stat
16 import tempfile
16 import tempfile
17
17
18 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
18 from mercurial import dirstate, httpconnection, match as match_, util, scmutil
19 from mercurial.i18n import _
19 from mercurial.i18n import _
20
20
21 shortname = '.hglf'
21 shortname = '.hglf'
22 longname = 'largefiles'
22 longname = 'largefiles'
23
23
24
24
25 # -- Portability wrappers ----------------------------------------------
25 # -- Portability wrappers ----------------------------------------------
26
26
27 def dirstate_walk(dirstate, matcher, unknown=False, ignored=False):
27 def dirstate_walk(dirstate, matcher, unknown=False, ignored=False):
28 return dirstate.walk(matcher, [], unknown, ignored)
28 return dirstate.walk(matcher, [], unknown, ignored)
29
29
30 def repo_add(repo, list):
30 def repo_add(repo, list):
31 add = repo[None].add
31 add = repo[None].add
32 return add(list)
32 return add(list)
33
33
34 def repo_remove(repo, list, unlink=False):
34 def repo_remove(repo, list, unlink=False):
35 def remove(list, unlink):
35 def remove(list, unlink):
36 wlock = repo.wlock()
36 wlock = repo.wlock()
37 try:
37 try:
38 if unlink:
38 if unlink:
39 for f in list:
39 for f in list:
40 try:
40 try:
41 util.unlinkpath(repo.wjoin(f))
41 util.unlinkpath(repo.wjoin(f))
42 except OSError, inst:
42 except OSError, inst:
43 if inst.errno != errno.ENOENT:
43 if inst.errno != errno.ENOENT:
44 raise
44 raise
45 repo[None].forget(list)
45 repo[None].forget(list)
46 finally:
46 finally:
47 wlock.release()
47 wlock.release()
48 return remove(list, unlink=unlink)
48 return remove(list, unlink=unlink)
49
49
50 def repo_forget(repo, list):
50 def repo_forget(repo, list):
51 forget = repo[None].forget
51 forget = repo[None].forget
52 return forget(list)
52 return forget(list)
53
53
54 def findoutgoing(repo, remote, force):
54 def findoutgoing(repo, remote, force):
55 from mercurial import discovery
55 from mercurial import discovery
56 common, _anyinc, _heads = discovery.findcommonincoming(repo,
56 common, _anyinc, _heads = discovery.findcommonincoming(repo,
57 remote, force=force)
57 remote, force=force)
58 return repo.changelog.findmissing(common)
58 return repo.changelog.findmissing(common)
59
59
60 # -- Private worker functions ------------------------------------------
60 # -- Private worker functions ------------------------------------------
61
61
62 def getminsize(ui, assumelfiles, opt, default=10):
62 def getminsize(ui, assumelfiles, opt, default=10):
63 lfsize = opt
63 lfsize = opt
64 if not lfsize and assumelfiles:
64 if not lfsize and assumelfiles:
65 lfsize = ui.config(longname, 'minsize', default=default)
65 lfsize = ui.config(longname, 'minsize', default=default)
66 if lfsize:
66 if lfsize:
67 try:
67 try:
68 lfsize = float(lfsize)
68 lfsize = float(lfsize)
69 except ValueError:
69 except ValueError:
70 raise util.Abort(_('largefiles: size must be number (not %s)\n')
70 raise util.Abort(_('largefiles: size must be number (not %s)\n')
71 % lfsize)
71 % lfsize)
72 if lfsize is None:
72 if lfsize is None:
73 raise util.Abort(_('minimum size for largefiles must be specified'))
73 raise util.Abort(_('minimum size for largefiles must be specified'))
74 return lfsize
74 return lfsize
75
75
76 def link(src, dest):
76 def link(src, dest):
77 try:
77 try:
78 util.oslink(src, dest)
78 util.oslink(src, dest)
79 except OSError:
79 except OSError:
80 # if hardlinks fail, fallback on copy
80 # if hardlinks fail, fallback on copy
81 shutil.copyfile(src, dest)
81 shutil.copyfile(src, dest)
82 os.chmod(dest, os.stat(src).st_mode)
82 os.chmod(dest, os.stat(src).st_mode)
83
83
84 def usercachepath(ui, hash):
84 def usercachepath(ui, hash):
85 path = ui.configpath(longname, 'usercache', None)
85 path = ui.configpath(longname, 'usercache', None)
86 if path:
86 if path:
87 path = os.path.join(path, hash)
87 path = os.path.join(path, hash)
88 else:
88 else:
89 if os.name == 'nt':
89 if os.name == 'nt':
90 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
90 appdata = os.getenv('LOCALAPPDATA', os.getenv('APPDATA'))
91 path = os.path.join(appdata, longname, hash)
91 path = os.path.join(appdata, longname, hash)
92 elif platform.system() == 'Darwin':
92 elif platform.system() == 'Darwin':
93 path = os.path.join(os.getenv('HOME'), 'Library', 'Caches',
93 path = os.path.join(os.getenv('HOME'), 'Library', 'Caches',
94 longname, hash)
94 longname, hash)
95 elif os.name == 'posix':
95 elif os.name == 'posix':
96 path = os.getenv('XDG_CACHE_HOME')
96 path = os.getenv('XDG_CACHE_HOME')
97 if path:
97 if path:
98 path = os.path.join(path, longname, hash)
98 path = os.path.join(path, longname, hash)
99 else:
99 else:
100 path = os.path.join(os.getenv('HOME'), '.cache', longname, hash)
100 path = os.path.join(os.getenv('HOME'), '.cache', longname, hash)
101 else:
101 else:
102 raise util.Abort(_('unknown operating system: %s\n') % os.name)
102 raise util.Abort(_('unknown operating system: %s\n') % os.name)
103 return path
103 return path
104
104
105 def inusercache(ui, hash):
105 def inusercache(ui, hash):
106 return os.path.exists(usercachepath(ui, hash))
106 return os.path.exists(usercachepath(ui, hash))
107
107
108 def findfile(repo, hash):
108 def findfile(repo, hash):
109 if instore(repo, hash):
109 if instore(repo, hash):
110 repo.ui.note(_('Found %s in store\n') % hash)
110 repo.ui.note(_('Found %s in store\n') % hash)
111 elif inusercache(repo.ui, hash):
111 elif inusercache(repo.ui, hash):
112 repo.ui.note(_('Found %s in system cache\n') % hash)
112 repo.ui.note(_('Found %s in system cache\n') % hash)
113 path = storepath(repo, hash)
113 path = storepath(repo, hash)
114 util.makedirs(os.path.dirname(path))
114 util.makedirs(os.path.dirname(path))
115 link(usercachepath(repo.ui, hash), path)
115 link(usercachepath(repo.ui, hash), path)
116 else:
116 else:
117 return None
117 return None
118 return storepath(repo, hash)
118 return storepath(repo, hash)
119
119
120 class largefiles_dirstate(dirstate.dirstate):
120 class largefiles_dirstate(dirstate.dirstate):
121 def __getitem__(self, key):
121 def __getitem__(self, key):
122 return super(largefiles_dirstate, self).__getitem__(unixpath(key))
122 return super(largefiles_dirstate, self).__getitem__(unixpath(key))
123 def normal(self, f):
123 def normal(self, f):
124 return super(largefiles_dirstate, self).normal(unixpath(f))
124 return super(largefiles_dirstate, self).normal(unixpath(f))
125 def remove(self, f):
125 def remove(self, f):
126 return super(largefiles_dirstate, self).remove(unixpath(f))
126 return super(largefiles_dirstate, self).remove(unixpath(f))
127 def add(self, f):
127 def add(self, f):
128 return super(largefiles_dirstate, self).add(unixpath(f))
128 return super(largefiles_dirstate, self).add(unixpath(f))
129 def drop(self, f):
129 def drop(self, f):
130 return super(largefiles_dirstate, self).drop(unixpath(f))
130 return super(largefiles_dirstate, self).drop(unixpath(f))
131 def forget(self, f):
131 def forget(self, f):
132 return super(largefiles_dirstate, self).forget(unixpath(f))
132 return super(largefiles_dirstate, self).forget(unixpath(f))
133
133
134 def openlfdirstate(ui, repo):
134 def openlfdirstate(ui, repo):
135 '''
135 '''
136 Return a dirstate object that tracks largefiles: i.e. its root is
136 Return a dirstate object that tracks largefiles: i.e. its root is
137 the repo root, but it is saved in .hg/largefiles/dirstate.
137 the repo root, but it is saved in .hg/largefiles/dirstate.
138 '''
138 '''
139 admin = repo.join(longname)
139 admin = repo.join(longname)
140 opener = scmutil.opener(admin)
140 opener = scmutil.opener(admin)
141 lfdirstate = largefiles_dirstate(opener, ui, repo.root,
141 lfdirstate = largefiles_dirstate(opener, ui, repo.root,
142 repo.dirstate._validate)
142 repo.dirstate._validate)
143
143
144 # If the largefiles dirstate does not exist, populate and create
144 # If the largefiles dirstate does not exist, populate and create
145 # it. This ensures that we create it on the first meaningful
145 # it. This ensures that we create it on the first meaningful
146 # largefiles operation in a new clone. It also gives us an easy
146 # largefiles operation in a new clone. It also gives us an easy
147 # way to forcibly rebuild largefiles state:
147 # way to forcibly rebuild largefiles state:
148 # rm .hg/largefiles/dirstate && hg status
148 # rm .hg/largefiles/dirstate && hg status
149 # Or even, if things are really messed up:
149 # Or even, if things are really messed up:
150 # rm -rf .hg/largefiles && hg status
150 # rm -rf .hg/largefiles && hg status
151 if not os.path.exists(os.path.join(admin, 'dirstate')):
151 if not os.path.exists(os.path.join(admin, 'dirstate')):
152 util.makedirs(admin)
152 util.makedirs(admin)
153 matcher = getstandinmatcher(repo)
153 matcher = getstandinmatcher(repo)
154 for standin in dirstate_walk(repo.dirstate, matcher):
154 for standin in dirstate_walk(repo.dirstate, matcher):
155 lfile = splitstandin(standin)
155 lfile = splitstandin(standin)
156 hash = readstandin(repo, lfile)
156 hash = readstandin(repo, lfile)
157 lfdirstate.normallookup(lfile)
157 lfdirstate.normallookup(lfile)
158 try:
158 try:
159 if hash == hashfile(lfile):
159 if hash == hashfile(repo.wjoin(lfile)):
160 lfdirstate.normal(lfile)
160 lfdirstate.normal(lfile)
161 except OSError, err:
161 except OSError, err:
162 if err.errno != errno.ENOENT:
162 if err.errno != errno.ENOENT:
163 raise
163 raise
164
164
165 lfdirstate.write()
165 lfdirstate.write()
166
166
167 return lfdirstate
167 return lfdirstate
168
168
169 def lfdirstate_status(lfdirstate, repo, rev):
169 def lfdirstate_status(lfdirstate, repo, rev):
170 wlock = repo.wlock()
170 wlock = repo.wlock()
171 try:
171 try:
172 match = match_.always(repo.root, repo.getcwd())
172 match = match_.always(repo.root, repo.getcwd())
173 s = lfdirstate.status(match, [], False, False, False)
173 s = lfdirstate.status(match, [], False, False, False)
174 unsure, modified, added, removed, missing, unknown, ignored, clean = s
174 unsure, modified, added, removed, missing, unknown, ignored, clean = s
175 for lfile in unsure:
175 for lfile in unsure:
176 if repo[rev][standin(lfile)].data().strip() != \
176 if repo[rev][standin(lfile)].data().strip() != \
177 hashfile(repo.wjoin(lfile)):
177 hashfile(repo.wjoin(lfile)):
178 modified.append(lfile)
178 modified.append(lfile)
179 else:
179 else:
180 clean.append(lfile)
180 clean.append(lfile)
181 lfdirstate.normal(lfile)
181 lfdirstate.normal(lfile)
182 lfdirstate.write()
182 lfdirstate.write()
183 finally:
183 finally:
184 wlock.release()
184 wlock.release()
185 return (modified, added, removed, missing, unknown, ignored, clean)
185 return (modified, added, removed, missing, unknown, ignored, clean)
186
186
187 def listlfiles(repo, rev=None, matcher=None):
187 def listlfiles(repo, rev=None, matcher=None):
188 '''return a list of largefiles in the working copy or the
188 '''return a list of largefiles in the working copy or the
189 specified changeset'''
189 specified changeset'''
190
190
191 if matcher is None:
191 if matcher is None:
192 matcher = getstandinmatcher(repo)
192 matcher = getstandinmatcher(repo)
193
193
194 # ignore unknown files in working directory
194 # ignore unknown files in working directory
195 return [splitstandin(f)
195 return [splitstandin(f)
196 for f in repo[rev].walk(matcher)
196 for f in repo[rev].walk(matcher)
197 if rev is not None or repo.dirstate[f] != '?']
197 if rev is not None or repo.dirstate[f] != '?']
198
198
199 def instore(repo, hash):
199 def instore(repo, hash):
200 return os.path.exists(storepath(repo, hash))
200 return os.path.exists(storepath(repo, hash))
201
201
202 def storepath(repo, hash):
202 def storepath(repo, hash):
203 return repo.join(os.path.join(longname, hash))
203 return repo.join(os.path.join(longname, hash))
204
204
205 def copyfromcache(repo, hash, filename):
205 def copyfromcache(repo, hash, filename):
206 '''Copy the specified largefile from the repo or system cache to
206 '''Copy the specified largefile from the repo or system cache to
207 filename in the repository. Return true on success or false if the
207 filename in the repository. Return true on success or false if the
208 file was not found in either cache (which should not happened:
208 file was not found in either cache (which should not happened:
209 this is meant to be called only after ensuring that the needed
209 this is meant to be called only after ensuring that the needed
210 largefile exists in the cache).'''
210 largefile exists in the cache).'''
211 path = findfile(repo, hash)
211 path = findfile(repo, hash)
212 if path is None:
212 if path is None:
213 return False
213 return False
214 util.makedirs(os.path.dirname(repo.wjoin(filename)))
214 util.makedirs(os.path.dirname(repo.wjoin(filename)))
215 shutil.copy(path, repo.wjoin(filename))
215 shutil.copy(path, repo.wjoin(filename))
216 return True
216 return True
217
217
218 def copytostore(repo, rev, file, uploaded=False):
218 def copytostore(repo, rev, file, uploaded=False):
219 hash = readstandin(repo, file)
219 hash = readstandin(repo, file)
220 if instore(repo, hash):
220 if instore(repo, hash):
221 return
221 return
222 copytostoreabsolute(repo, repo.wjoin(file), hash)
222 copytostoreabsolute(repo, repo.wjoin(file), hash)
223
223
224 def copytostoreabsolute(repo, file, hash):
224 def copytostoreabsolute(repo, file, hash):
225 util.makedirs(os.path.dirname(storepath(repo, hash)))
225 util.makedirs(os.path.dirname(storepath(repo, hash)))
226 if inusercache(repo.ui, hash):
226 if inusercache(repo.ui, hash):
227 link(usercachepath(repo.ui, hash), storepath(repo, hash))
227 link(usercachepath(repo.ui, hash), storepath(repo, hash))
228 else:
228 else:
229 shutil.copyfile(file, storepath(repo, hash))
229 shutil.copyfile(file, storepath(repo, hash))
230 os.chmod(storepath(repo, hash), os.stat(file).st_mode)
230 os.chmod(storepath(repo, hash), os.stat(file).st_mode)
231 linktousercache(repo, hash)
231 linktousercache(repo, hash)
232
232
233 def linktousercache(repo, hash):
233 def linktousercache(repo, hash):
234 util.makedirs(os.path.dirname(usercachepath(repo.ui, hash)))
234 util.makedirs(os.path.dirname(usercachepath(repo.ui, hash)))
235 link(storepath(repo, hash), usercachepath(repo.ui, hash))
235 link(storepath(repo, hash), usercachepath(repo.ui, hash))
236
236
237 def getstandinmatcher(repo, pats=[], opts={}):
237 def getstandinmatcher(repo, pats=[], opts={}):
238 '''Return a match object that applies pats to the standin directory'''
238 '''Return a match object that applies pats to the standin directory'''
239 standindir = repo.pathto(shortname)
239 standindir = repo.pathto(shortname)
240 if pats:
240 if pats:
241 # patterns supplied: search standin directory relative to current dir
241 # patterns supplied: search standin directory relative to current dir
242 cwd = repo.getcwd()
242 cwd = repo.getcwd()
243 if os.path.isabs(cwd):
243 if os.path.isabs(cwd):
244 # cwd is an absolute path for hg -R <reponame>
244 # cwd is an absolute path for hg -R <reponame>
245 # work relative to the repository root in this case
245 # work relative to the repository root in this case
246 cwd = ''
246 cwd = ''
247 pats = [os.path.join(standindir, cwd, pat) for pat in pats]
247 pats = [os.path.join(standindir, cwd, pat) for pat in pats]
248 elif os.path.isdir(standindir):
248 elif os.path.isdir(standindir):
249 # no patterns: relative to repo root
249 # no patterns: relative to repo root
250 pats = [standindir]
250 pats = [standindir]
251 else:
251 else:
252 # no patterns and no standin dir: return matcher that matches nothing
252 # no patterns and no standin dir: return matcher that matches nothing
253 match = match_.match(repo.root, None, [], exact=True)
253 match = match_.match(repo.root, None, [], exact=True)
254 match.matchfn = lambda f: False
254 match.matchfn = lambda f: False
255 return match
255 return match
256 return getmatcher(repo, pats, opts, showbad=False)
256 return getmatcher(repo, pats, opts, showbad=False)
257
257
258 def getmatcher(repo, pats=[], opts={}, showbad=True):
258 def getmatcher(repo, pats=[], opts={}, showbad=True):
259 '''Wrapper around scmutil.match() that adds showbad: if false,
259 '''Wrapper around scmutil.match() that adds showbad: if false,
260 neuter the match object's bad() method so it does not print any
260 neuter the match object's bad() method so it does not print any
261 warnings about missing files or directories.'''
261 warnings about missing files or directories.'''
262 match = scmutil.match(repo[None], pats, opts)
262 match = scmutil.match(repo[None], pats, opts)
263
263
264 if not showbad:
264 if not showbad:
265 match.bad = lambda f, msg: None
265 match.bad = lambda f, msg: None
266 return match
266 return match
267
267
268 def composestandinmatcher(repo, rmatcher):
268 def composestandinmatcher(repo, rmatcher):
269 '''Return a matcher that accepts standins corresponding to the
269 '''Return a matcher that accepts standins corresponding to the
270 files accepted by rmatcher. Pass the list of files in the matcher
270 files accepted by rmatcher. Pass the list of files in the matcher
271 as the paths specified by the user.'''
271 as the paths specified by the user.'''
272 smatcher = getstandinmatcher(repo, rmatcher.files())
272 smatcher = getstandinmatcher(repo, rmatcher.files())
273 isstandin = smatcher.matchfn
273 isstandin = smatcher.matchfn
274 def composed_matchfn(f):
274 def composed_matchfn(f):
275 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
275 return isstandin(f) and rmatcher.matchfn(splitstandin(f))
276 smatcher.matchfn = composed_matchfn
276 smatcher.matchfn = composed_matchfn
277
277
278 return smatcher
278 return smatcher
279
279
280 def standin(filename):
280 def standin(filename):
281 '''Return the repo-relative path to the standin for the specified big
281 '''Return the repo-relative path to the standin for the specified big
282 file.'''
282 file.'''
283 # Notes:
283 # Notes:
284 # 1) Most callers want an absolute path, but _create_standin() needs
284 # 1) Most callers want an absolute path, but _create_standin() needs
285 # it repo-relative so lfadd() can pass it to repo_add(). So leave
285 # it repo-relative so lfadd() can pass it to repo_add(). So leave
286 # it up to the caller to use repo.wjoin() to get an absolute path.
286 # it up to the caller to use repo.wjoin() to get an absolute path.
287 # 2) Join with '/' because that's what dirstate always uses, even on
287 # 2) Join with '/' because that's what dirstate always uses, even on
288 # Windows. Change existing separator to '/' first in case we are
288 # Windows. Change existing separator to '/' first in case we are
289 # passed filenames from an external source (like the command line).
289 # passed filenames from an external source (like the command line).
290 return shortname + '/' + filename.replace(os.sep, '/')
290 return shortname + '/' + filename.replace(os.sep, '/')
291
291
292 def isstandin(filename):
292 def isstandin(filename):
293 '''Return true if filename is a big file standin. filename must be
293 '''Return true if filename is a big file standin. filename must be
294 in Mercurial's internal form (slash-separated).'''
294 in Mercurial's internal form (slash-separated).'''
295 return filename.startswith(shortname + '/')
295 return filename.startswith(shortname + '/')
296
296
297 def splitstandin(filename):
297 def splitstandin(filename):
298 # Split on / because that's what dirstate always uses, even on Windows.
298 # Split on / because that's what dirstate always uses, even on Windows.
299 # Change local separator to / first just in case we are passed filenames
299 # Change local separator to / first just in case we are passed filenames
300 # from an external source (like the command line).
300 # from an external source (like the command line).
301 bits = filename.replace(os.sep, '/').split('/', 1)
301 bits = filename.replace(os.sep, '/').split('/', 1)
302 if len(bits) == 2 and bits[0] == shortname:
302 if len(bits) == 2 and bits[0] == shortname:
303 return bits[1]
303 return bits[1]
304 else:
304 else:
305 return None
305 return None
306
306
307 def updatestandin(repo, standin):
307 def updatestandin(repo, standin):
308 file = repo.wjoin(splitstandin(standin))
308 file = repo.wjoin(splitstandin(standin))
309 if os.path.exists(file):
309 if os.path.exists(file):
310 hash = hashfile(file)
310 hash = hashfile(file)
311 executable = getexecutable(file)
311 executable = getexecutable(file)
312 writestandin(repo, standin, hash, executable)
312 writestandin(repo, standin, hash, executable)
313
313
314 def readstandin(repo, filename, node=None):
314 def readstandin(repo, filename, node=None):
315 '''read hex hash from standin for filename at given node, or working
315 '''read hex hash from standin for filename at given node, or working
316 directory if no node is given'''
316 directory if no node is given'''
317 return repo[node][standin(filename)].data().strip()
317 return repo[node][standin(filename)].data().strip()
318
318
319 def writestandin(repo, standin, hash, executable):
319 def writestandin(repo, standin, hash, executable):
320 '''write hash to <repo.root>/<standin>'''
320 '''write hash to <repo.root>/<standin>'''
321 writehash(hash, repo.wjoin(standin), executable)
321 writehash(hash, repo.wjoin(standin), executable)
322
322
323 def copyandhash(instream, outfile):
323 def copyandhash(instream, outfile):
324 '''Read bytes from instream (iterable) and write them to outfile,
324 '''Read bytes from instream (iterable) and write them to outfile,
325 computing the SHA-1 hash of the data along the way. Close outfile
325 computing the SHA-1 hash of the data along the way. Close outfile
326 when done and return the binary hash.'''
326 when done and return the binary hash.'''
327 hasher = util.sha1('')
327 hasher = util.sha1('')
328 for data in instream:
328 for data in instream:
329 hasher.update(data)
329 hasher.update(data)
330 outfile.write(data)
330 outfile.write(data)
331
331
332 # Blecch: closing a file that somebody else opened is rude and
332 # Blecch: closing a file that somebody else opened is rude and
333 # wrong. But it's so darn convenient and practical! After all,
333 # wrong. But it's so darn convenient and practical! After all,
334 # outfile was opened just to copy and hash.
334 # outfile was opened just to copy and hash.
335 outfile.close()
335 outfile.close()
336
336
337 return hasher.digest()
337 return hasher.digest()
338
338
339 def hashrepofile(repo, file):
339 def hashrepofile(repo, file):
340 return hashfile(repo.wjoin(file))
340 return hashfile(repo.wjoin(file))
341
341
342 def hashfile(file):
342 def hashfile(file):
343 if not os.path.exists(file):
343 if not os.path.exists(file):
344 return ''
344 return ''
345 hasher = util.sha1('')
345 hasher = util.sha1('')
346 fd = open(file, 'rb')
346 fd = open(file, 'rb')
347 for data in blockstream(fd):
347 for data in blockstream(fd):
348 hasher.update(data)
348 hasher.update(data)
349 fd.close()
349 fd.close()
350 return hasher.hexdigest()
350 return hasher.hexdigest()
351
351
352 class limitreader(object):
352 class limitreader(object):
353 def __init__(self, f, limit):
353 def __init__(self, f, limit):
354 self.f = f
354 self.f = f
355 self.limit = limit
355 self.limit = limit
356
356
357 def read(self, length):
357 def read(self, length):
358 if self.limit == 0:
358 if self.limit == 0:
359 return ''
359 return ''
360 length = length > self.limit and self.limit or length
360 length = length > self.limit and self.limit or length
361 self.limit -= length
361 self.limit -= length
362 return self.f.read(length)
362 return self.f.read(length)
363
363
364 def close(self):
364 def close(self):
365 pass
365 pass
366
366
367 def blockstream(infile, blocksize=128 * 1024):
367 def blockstream(infile, blocksize=128 * 1024):
368 """Generator that yields blocks of data from infile and closes infile."""
368 """Generator that yields blocks of data from infile and closes infile."""
369 while True:
369 while True:
370 data = infile.read(blocksize)
370 data = infile.read(blocksize)
371 if not data:
371 if not data:
372 break
372 break
373 yield data
373 yield data
374 # same blecch as copyandhash() above
374 # same blecch as copyandhash() above
375 infile.close()
375 infile.close()
376
376
377 def readhash(filename):
377 def readhash(filename):
378 rfile = open(filename, 'rb')
378 rfile = open(filename, 'rb')
379 hash = rfile.read(40)
379 hash = rfile.read(40)
380 rfile.close()
380 rfile.close()
381 if len(hash) < 40:
381 if len(hash) < 40:
382 raise util.Abort(_('bad hash in \'%s\' (only %d bytes long)')
382 raise util.Abort(_('bad hash in \'%s\' (only %d bytes long)')
383 % (filename, len(hash)))
383 % (filename, len(hash)))
384 return hash
384 return hash
385
385
386 def writehash(hash, filename, executable):
386 def writehash(hash, filename, executable):
387 util.makedirs(os.path.dirname(filename))
387 util.makedirs(os.path.dirname(filename))
388 if os.path.exists(filename):
388 if os.path.exists(filename):
389 os.unlink(filename)
389 os.unlink(filename)
390 wfile = open(filename, 'wb')
390 wfile = open(filename, 'wb')
391
391
392 try:
392 try:
393 wfile.write(hash)
393 wfile.write(hash)
394 wfile.write('\n')
394 wfile.write('\n')
395 finally:
395 finally:
396 wfile.close()
396 wfile.close()
397 if os.path.exists(filename):
397 if os.path.exists(filename):
398 os.chmod(filename, getmode(executable))
398 os.chmod(filename, getmode(executable))
399
399
400 def getexecutable(filename):
400 def getexecutable(filename):
401 mode = os.stat(filename).st_mode
401 mode = os.stat(filename).st_mode
402 return ((mode & stat.S_IXUSR) and
402 return ((mode & stat.S_IXUSR) and
403 (mode & stat.S_IXGRP) and
403 (mode & stat.S_IXGRP) and
404 (mode & stat.S_IXOTH))
404 (mode & stat.S_IXOTH))
405
405
406 def getmode(executable):
406 def getmode(executable):
407 if executable:
407 if executable:
408 return 0755
408 return 0755
409 else:
409 else:
410 return 0644
410 return 0644
411
411
412 def urljoin(first, second, *arg):
412 def urljoin(first, second, *arg):
413 def join(left, right):
413 def join(left, right):
414 if not left.endswith('/'):
414 if not left.endswith('/'):
415 left += '/'
415 left += '/'
416 if right.startswith('/'):
416 if right.startswith('/'):
417 right = right[1:]
417 right = right[1:]
418 return left + right
418 return left + right
419
419
420 url = join(first, second)
420 url = join(first, second)
421 for a in arg:
421 for a in arg:
422 url = join(url, a)
422 url = join(url, a)
423 return url
423 return url
424
424
425 def hexsha1(data):
425 def hexsha1(data):
426 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
426 """hexsha1 returns the hex-encoded sha1 sum of the data in the file-like
427 object data"""
427 object data"""
428 h = util.sha1()
428 h = util.sha1()
429 for chunk in util.filechunkiter(data):
429 for chunk in util.filechunkiter(data):
430 h.update(chunk)
430 h.update(chunk)
431 return h.hexdigest()
431 return h.hexdigest()
432
432
433 def httpsendfile(ui, filename):
433 def httpsendfile(ui, filename):
434 return httpconnection.httpsendfile(ui, filename, 'rb')
434 return httpconnection.httpsendfile(ui, filename, 'rb')
435
435
436 def unixpath(path):
436 def unixpath(path):
437 '''Return a version of path normalized for use with the lfdirstate.'''
437 '''Return a version of path normalized for use with the lfdirstate.'''
438 return os.path.normpath(path).replace(os.sep, '/')
438 return os.path.normpath(path).replace(os.sep, '/')
439
439
440 def islfilesrepo(repo):
440 def islfilesrepo(repo):
441 return ('largefiles' in repo.requirements and
441 return ('largefiles' in repo.requirements and
442 util.any(shortname + '/' in f[0] for f in repo.store.datafiles()))
442 util.any(shortname + '/' in f[0] for f in repo.store.datafiles()))
443
443
444 def mkstemp(repo, prefix):
444 def mkstemp(repo, prefix):
445 '''Returns a file descriptor and a filename corresponding to a temporary
445 '''Returns a file descriptor and a filename corresponding to a temporary
446 file in the repo's largefiles store.'''
446 file in the repo's largefiles store.'''
447 path = repo.join(longname)
447 path = repo.join(longname)
448 util.makedirs(path)
448 util.makedirs(path)
449 return tempfile.mkstemp(prefix=prefix, dir=path)
449 return tempfile.mkstemp(prefix=prefix, dir=path)
450
450
451 class storeprotonotcapable(Exception):
451 class storeprotonotcapable(Exception):
452 def __init__(self, storetypes):
452 def __init__(self, storetypes):
453 self.storetypes = storetypes
453 self.storetypes = storetypes
@@ -1,841 +1,847 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > largefiles=
3 > largefiles=
4 > purge=
4 > purge=
5 > rebase=
5 > rebase=
6 > transplant=
6 > transplant=
7 > [largefiles]
7 > [largefiles]
8 > minsize=2
8 > minsize=2
9 > patterns=glob:**.dat
9 > patterns=glob:**.dat
10 > EOF
10 > EOF
11
11
12 Create the repo with a couple of revisions of both large and normal
12 Create the repo with a couple of revisions of both large and normal
13 files, testing that status correctly shows largefiles.
13 files, testing that status correctly shows largefiles.
14
14
15 $ hg init a
15 $ hg init a
16 $ cd a
16 $ cd a
17 $ mkdir sub
17 $ mkdir sub
18 $ echo normal1 > normal1
18 $ echo normal1 > normal1
19 $ echo normal2 > sub/normal2
19 $ echo normal2 > sub/normal2
20 $ echo large1 > large1
20 $ echo large1 > large1
21 $ echo large2 > sub/large2
21 $ echo large2 > sub/large2
22 $ hg add normal1 sub/normal2
22 $ hg add normal1 sub/normal2
23 $ hg add --large large1 sub/large2
23 $ hg add --large large1 sub/large2
24 $ hg commit -m "add files"
24 $ hg commit -m "add files"
25 $ echo normal11 > normal1
25 $ echo normal11 > normal1
26 $ echo normal22 > sub/normal2
26 $ echo normal22 > sub/normal2
27 $ echo large11 > large1
27 $ echo large11 > large1
28 $ echo large22 > sub/large2
28 $ echo large22 > sub/large2
29 $ hg st
29 $ hg st
30 M large1
30 M large1
31 M normal1
31 M normal1
32 M sub/large2
32 M sub/large2
33 M sub/normal2
33 M sub/normal2
34 $ hg commit -m "edit files"
34 $ hg commit -m "edit files"
35
35
36 Commit preserved largefile contents.
36 Commit preserved largefile contents.
37
37
38 $ cat normal1
38 $ cat normal1
39 normal11
39 normal11
40 $ cat large1
40 $ cat large1
41 large11
41 large11
42 $ cat sub/normal2
42 $ cat sub/normal2
43 normal22
43 normal22
44 $ cat sub/large2
44 $ cat sub/large2
45 large22
45 large22
46
46
47 Remove both largefiles and normal files.
47 Remove both largefiles and normal files.
48
48
49 $ hg remove normal1 large1
49 $ hg remove normal1 large1
50 $ hg commit -m "remove files"
50 $ hg commit -m "remove files"
51 $ ls
51 $ ls
52 sub
52 sub
53
53
54 Copy both largefiles and normal files.
54 Copy both largefiles and normal files.
55
55
56 $ hg cp sub/normal2 normal1
56 $ hg cp sub/normal2 normal1
57 $ hg cp sub/large2 large1
57 $ hg cp sub/large2 large1
58 $ hg commit -m "copy files"
58 $ hg commit -m "copy files"
59 $ cat normal1
59 $ cat normal1
60 normal22
60 normal22
61 $ cat large1
61 $ cat large1
62 large22
62 large22
63
63
64 Test moving largefiles and verify that normal files are also unaffected.
64 Test moving largefiles and verify that normal files are also unaffected.
65
65
66 $ hg mv normal1 normal3
66 $ hg mv normal1 normal3
67 $ hg mv large1 large3
67 $ hg mv large1 large3
68 $ hg mv sub/normal2 sub/normal4
68 $ hg mv sub/normal2 sub/normal4
69 $ hg mv sub/large2 sub/large4
69 $ hg mv sub/large2 sub/large4
70 $ hg commit -m "move files"
70 $ hg commit -m "move files"
71 $ cat normal3
71 $ cat normal3
72 normal22
72 normal22
73 $ cat large3
73 $ cat large3
74 large22
74 large22
75 $ cat sub/normal4
75 $ cat sub/normal4
76 normal22
76 normal22
77 $ cat sub/large4
77 $ cat sub/large4
78 large22
78 large22
79
79
80 Test archiving the various revisions. These hit corner cases known with
80 Test archiving the various revisions. These hit corner cases known with
81 archiving.
81 archiving.
82
82
83 $ hg archive -r 0 ../archive0
83 $ hg archive -r 0 ../archive0
84 $ hg archive -r 1 ../archive1
84 $ hg archive -r 1 ../archive1
85 $ hg archive -r 2 ../archive2
85 $ hg archive -r 2 ../archive2
86 $ hg archive -r 3 ../archive3
86 $ hg archive -r 3 ../archive3
87 $ hg archive -r 4 ../archive4
87 $ hg archive -r 4 ../archive4
88 $ cd ../archive0
88 $ cd ../archive0
89 $ cat normal1
89 $ cat normal1
90 normal1
90 normal1
91 $ cat large1
91 $ cat large1
92 large1
92 large1
93 $ cat sub/normal2
93 $ cat sub/normal2
94 normal2
94 normal2
95 $ cat sub/large2
95 $ cat sub/large2
96 large2
96 large2
97 $ cd ../archive1
97 $ cd ../archive1
98 $ cat normal1
98 $ cat normal1
99 normal11
99 normal11
100 $ cat large1
100 $ cat large1
101 large11
101 large11
102 $ cat sub/normal2
102 $ cat sub/normal2
103 normal22
103 normal22
104 $ cat sub/large2
104 $ cat sub/large2
105 large22
105 large22
106 $ cd ../archive2
106 $ cd ../archive2
107 $ ls
107 $ ls
108 sub
108 sub
109 $ cat sub/normal2
109 $ cat sub/normal2
110 normal22
110 normal22
111 $ cat sub/large2
111 $ cat sub/large2
112 large22
112 large22
113 $ cd ../archive3
113 $ cd ../archive3
114 $ cat normal1
114 $ cat normal1
115 normal22
115 normal22
116 $ cat large1
116 $ cat large1
117 large22
117 large22
118 $ cat sub/normal2
118 $ cat sub/normal2
119 normal22
119 normal22
120 $ cat sub/large2
120 $ cat sub/large2
121 large22
121 large22
122 $ cd ../archive4
122 $ cd ../archive4
123 $ cat normal3
123 $ cat normal3
124 normal22
124 normal22
125 $ cat large3
125 $ cat large3
126 large22
126 large22
127 $ cat sub/normal4
127 $ cat sub/normal4
128 normal22
128 normal22
129 $ cat sub/large4
129 $ cat sub/large4
130 large22
130 large22
131
131
132 Commit corner case: specify files to commit.
132 Commit corner case: specify files to commit.
133
133
134 $ cd ../a
134 $ cd ../a
135 $ echo normal3 > normal3
135 $ echo normal3 > normal3
136 $ echo large3 > large3
136 $ echo large3 > large3
137 $ echo normal4 > sub/normal4
137 $ echo normal4 > sub/normal4
138 $ echo large4 > sub/large4
138 $ echo large4 > sub/large4
139 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
139 $ hg commit normal3 large3 sub/normal4 sub/large4 -m "edit files again"
140 $ cat normal3
140 $ cat normal3
141 normal3
141 normal3
142 $ cat large3
142 $ cat large3
143 large3
143 large3
144 $ cat sub/normal4
144 $ cat sub/normal4
145 normal4
145 normal4
146 $ cat sub/large4
146 $ cat sub/large4
147 large4
147 large4
148
148
149 One more commit corner case: commit from a subdirectory.
149 One more commit corner case: commit from a subdirectory.
150
150
151 $ cd ../a
151 $ cd ../a
152 $ echo normal33 > normal3
152 $ echo normal33 > normal3
153 $ echo large33 > large3
153 $ echo large33 > large3
154 $ echo normal44 > sub/normal4
154 $ echo normal44 > sub/normal4
155 $ echo large44 > sub/large4
155 $ echo large44 > sub/large4
156 $ cd sub
156 $ cd sub
157 $ hg commit -m "edit files yet again"
157 $ hg commit -m "edit files yet again"
158 $ cat ../normal3
158 $ cat ../normal3
159 normal33
159 normal33
160 $ cat ../large3
160 $ cat ../large3
161 large33
161 large33
162 $ cat normal4
162 $ cat normal4
163 normal44
163 normal44
164 $ cat large4
164 $ cat large4
165 large44
165 large44
166
166
167 Committing standins is not allowed.
167 Committing standins is not allowed.
168
168
169 $ cd ..
169 $ cd ..
170 $ echo large3 > large3
170 $ echo large3 > large3
171 $ hg commit .hglf/large3 -m "try to commit standin"
171 $ hg commit .hglf/large3 -m "try to commit standin"
172 abort: file ".hglf/large3" is a largefile standin
172 abort: file ".hglf/large3" is a largefile standin
173 (commit the largefile itself instead)
173 (commit the largefile itself instead)
174 [255]
174 [255]
175
175
176 Corner cases for adding largefiles.
176 Corner cases for adding largefiles.
177
177
178 $ echo large5 > large5
178 $ echo large5 > large5
179 $ hg add --large large5
179 $ hg add --large large5
180 $ hg add --large large5
180 $ hg add --large large5
181 large5 already a largefile
181 large5 already a largefile
182 $ mkdir sub2
182 $ mkdir sub2
183 $ echo large6 > sub2/large6
183 $ echo large6 > sub2/large6
184 $ echo large7 > sub2/large7
184 $ echo large7 > sub2/large7
185 $ hg add --large sub2
185 $ hg add --large sub2
186 adding sub2/large6 as a largefile
186 adding sub2/large6 as a largefile
187 adding sub2/large7 as a largefile
187 adding sub2/large7 as a largefile
188 $ hg st
188 $ hg st
189 M large3
189 M large3
190 A large5
190 A large5
191 A sub2/large6
191 A sub2/large6
192 A sub2/large7
192 A sub2/large7
193
193
194 Config settings (pattern **.dat, minsize 2 MB) are respected.
194 Config settings (pattern **.dat, minsize 2 MB) are respected.
195
195
196 $ echo testdata > test.dat
196 $ echo testdata > test.dat
197 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
197 $ dd bs=1k count=2k if=/dev/zero of=reallylarge > /dev/null 2> /dev/null
198 $ hg add
198 $ hg add
199 adding reallylarge as a largefile
199 adding reallylarge as a largefile
200 adding test.dat as a largefile
200 adding test.dat as a largefile
201
201
202 Test that minsize and --lfsize handle float values;
202 Test that minsize and --lfsize handle float values;
203 also tests that --lfsize overrides largefiles.minsize.
203 also tests that --lfsize overrides largefiles.minsize.
204 (0.250 MB = 256 kB = 262144 B)
204 (0.250 MB = 256 kB = 262144 B)
205
205
206 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
206 $ dd if=/dev/zero of=ratherlarge bs=1024 count=256 > /dev/null 2> /dev/null
207 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
207 $ dd if=/dev/zero of=medium bs=1024 count=128 > /dev/null 2> /dev/null
208 $ hg --config largefiles.minsize=.25 add
208 $ hg --config largefiles.minsize=.25 add
209 adding ratherlarge as a largefile
209 adding ratherlarge as a largefile
210 adding medium
210 adding medium
211 $ hg forget medium
211 $ hg forget medium
212 $ hg --config largefiles.minsize=.25 add --lfsize=.125
212 $ hg --config largefiles.minsize=.25 add --lfsize=.125
213 adding medium as a largefile
213 adding medium as a largefile
214 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
214 $ dd if=/dev/zero of=notlarge bs=1024 count=127 > /dev/null 2> /dev/null
215 $ hg --config largefiles.minsize=.25 add --lfsize=.125
215 $ hg --config largefiles.minsize=.25 add --lfsize=.125
216 adding notlarge
216 adding notlarge
217 $ hg forget notlarge
217 $ hg forget notlarge
218
218
219 Test forget on largefiles.
219 Test forget on largefiles.
220
220
221 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
221 $ hg forget large3 large5 test.dat reallylarge ratherlarge medium
222 $ hg st
222 $ hg st
223 A sub2/large6
223 A sub2/large6
224 A sub2/large7
224 A sub2/large7
225 R large3
225 R large3
226 ? large5
226 ? large5
227 ? medium
227 ? medium
228 ? notlarge
228 ? notlarge
229 ? ratherlarge
229 ? ratherlarge
230 ? reallylarge
230 ? reallylarge
231 ? test.dat
231 ? test.dat
232 $ hg commit -m "add/edit more largefiles"
232 $ hg commit -m "add/edit more largefiles"
233 $ hg st
233 $ hg st
234 ? large3
234 ? large3
235 ? large5
235 ? large5
236 ? medium
236 ? medium
237 ? notlarge
237 ? notlarge
238 ? ratherlarge
238 ? ratherlarge
239 ? reallylarge
239 ? reallylarge
240 ? test.dat
240 ? test.dat
241
241
242 Purge with largefiles: verify that largefiles are still in the working
242 Purge with largefiles: verify that largefiles are still in the working
243 dir after a purge.
243 dir after a purge.
244
244
245 $ hg purge --all
245 $ hg purge --all
246 $ cat sub/large4
246 $ cat sub/large4
247 large44
247 large44
248 $ cat sub2/large6
248 $ cat sub2/large6
249 large6
249 large6
250 $ cat sub2/large7
250 $ cat sub2/large7
251 large7
251 large7
252
252
253 Clone a largefiles repo.
253 Clone a largefiles repo.
254
254
255 $ hg clone . ../b
255 $ hg clone . ../b
256 updating to branch default
256 updating to branch default
257 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 getting changed largefiles
258 getting changed largefiles
259 3 largefiles updated, 0 removed
259 3 largefiles updated, 0 removed
260 $ hg debugstate --nodates
261 n 644 41 .hglf/sub/large4
262 n 0 -1 .hglf/sub2/large6
263 n 0 -1 .hglf/sub2/large7
264 n 644 9 normal3
265 n 644 9 sub/normal4
260 $ cd ../b
266 $ cd ../b
261 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
267 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
262 7:daea875e9014 add/edit more largefiles
268 7:daea875e9014 add/edit more largefiles
263 6:4355d653f84f edit files yet again
269 6:4355d653f84f edit files yet again
264 5:9d5af5072dbd edit files again
270 5:9d5af5072dbd edit files again
265 4:74c02385b94c move files
271 4:74c02385b94c move files
266 3:9e8fbc4bce62 copy files
272 3:9e8fbc4bce62 copy files
267 2:51a0ae4d5864 remove files
273 2:51a0ae4d5864 remove files
268 1:ce8896473775 edit files
274 1:ce8896473775 edit files
269 0:30d30fe6a5be add files
275 0:30d30fe6a5be add files
270 $ cat normal3
276 $ cat normal3
271 normal33
277 normal33
272 $ cat sub/normal4
278 $ cat sub/normal4
273 normal44
279 normal44
274 $ cat sub/large4
280 $ cat sub/large4
275 large44
281 large44
276 $ cat sub2/large6
282 $ cat sub2/large6
277 large6
283 large6
278 $ cat sub2/large7
284 $ cat sub2/large7
279 large7
285 large7
280 $ cd ..
286 $ cd ..
281 $ hg clone a -r 3 c
287 $ hg clone a -r 3 c
282 adding changesets
288 adding changesets
283 adding manifests
289 adding manifests
284 adding file changes
290 adding file changes
285 added 4 changesets with 10 changes to 4 files
291 added 4 changesets with 10 changes to 4 files
286 updating to branch default
292 updating to branch default
287 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 getting changed largefiles
294 getting changed largefiles
289 2 largefiles updated, 0 removed
295 2 largefiles updated, 0 removed
290 $ cd c
296 $ cd c
291 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
297 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
292 3:9e8fbc4bce62 copy files
298 3:9e8fbc4bce62 copy files
293 2:51a0ae4d5864 remove files
299 2:51a0ae4d5864 remove files
294 1:ce8896473775 edit files
300 1:ce8896473775 edit files
295 0:30d30fe6a5be add files
301 0:30d30fe6a5be add files
296 $ cat normal1
302 $ cat normal1
297 normal22
303 normal22
298 $ cat large1
304 $ cat large1
299 large22
305 large22
300 $ cat sub/normal2
306 $ cat sub/normal2
301 normal22
307 normal22
302 $ cat sub/large2
308 $ cat sub/large2
303 large22
309 large22
304
310
305 Old revisions of a clone have correct largefiles content (this also
311 Old revisions of a clone have correct largefiles content (this also
306 tests update).
312 tests update).
307
313
308 $ hg update -r 1
314 $ hg update -r 1
309 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
310 getting changed largefiles
316 getting changed largefiles
311 1 largefiles updated, 0 removed
317 1 largefiles updated, 0 removed
312 $ cat large1
318 $ cat large1
313 large11
319 large11
314 $ cat sub/large2
320 $ cat sub/large2
315 large22
321 large22
316
322
317 Rebasing between two repositories does not revert largefiles to old
323 Rebasing between two repositories does not revert largefiles to old
318 revisions (this was a very bad bug that took a lot of work to fix).
324 revisions (this was a very bad bug that took a lot of work to fix).
319
325
320 $ cd ..
326 $ cd ..
321 $ hg clone a d
327 $ hg clone a d
322 updating to branch default
328 updating to branch default
323 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 getting changed largefiles
330 getting changed largefiles
325 3 largefiles updated, 0 removed
331 3 largefiles updated, 0 removed
326 $ cd b
332 $ cd b
327 $ echo large4-modified > sub/large4
333 $ echo large4-modified > sub/large4
328 $ echo normal3-modified > normal3
334 $ echo normal3-modified > normal3
329 $ hg commit -m "modify normal file and largefile in repo b"
335 $ hg commit -m "modify normal file and largefile in repo b"
330 $ cd ../d
336 $ cd ../d
331 $ echo large6-modified > sub2/large6
337 $ echo large6-modified > sub2/large6
332 $ echo normal4-modified > sub/normal4
338 $ echo normal4-modified > sub/normal4
333 $ hg commit -m "modify normal file largefile in repo d"
339 $ hg commit -m "modify normal file largefile in repo d"
334 $ cd ..
340 $ cd ..
335 $ hg clone d e
341 $ hg clone d e
336 updating to branch default
342 updating to branch default
337 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 getting changed largefiles
344 getting changed largefiles
339 3 largefiles updated, 0 removed
345 3 largefiles updated, 0 removed
340 $ cd d
346 $ cd d
341 $ hg pull --rebase ../b
347 $ hg pull --rebase ../b
342 pulling from ../b
348 pulling from ../b
343 searching for changes
349 searching for changes
344 adding changesets
350 adding changesets
345 adding manifests
351 adding manifests
346 adding file changes
352 adding file changes
347 added 1 changesets with 2 changes to 2 files (+1 heads)
353 added 1 changesets with 2 changes to 2 files (+1 heads)
348 getting changed largefiles
354 getting changed largefiles
349 1 largefiles updated, 0 removed
355 1 largefiles updated, 0 removed
350 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
356 saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg
351 nothing to rebase
357 nothing to rebase
352 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
358 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
353 9:598410d3eb9a modify normal file largefile in repo d
359 9:598410d3eb9a modify normal file largefile in repo d
354 8:a381d2c8c80e modify normal file and largefile in repo b
360 8:a381d2c8c80e modify normal file and largefile in repo b
355 7:daea875e9014 add/edit more largefiles
361 7:daea875e9014 add/edit more largefiles
356 6:4355d653f84f edit files yet again
362 6:4355d653f84f edit files yet again
357 5:9d5af5072dbd edit files again
363 5:9d5af5072dbd edit files again
358 4:74c02385b94c move files
364 4:74c02385b94c move files
359 3:9e8fbc4bce62 copy files
365 3:9e8fbc4bce62 copy files
360 2:51a0ae4d5864 remove files
366 2:51a0ae4d5864 remove files
361 1:ce8896473775 edit files
367 1:ce8896473775 edit files
362 0:30d30fe6a5be add files
368 0:30d30fe6a5be add files
363 $ cat normal3
369 $ cat normal3
364 normal3-modified
370 normal3-modified
365 $ cat sub/normal4
371 $ cat sub/normal4
366 normal4-modified
372 normal4-modified
367 $ cat sub/large4
373 $ cat sub/large4
368 large4-modified
374 large4-modified
369 $ cat sub2/large6
375 $ cat sub2/large6
370 large6-modified
376 large6-modified
371 $ cat sub2/large7
377 $ cat sub2/large7
372 large7
378 large7
373 $ cd ../e
379 $ cd ../e
374 $ hg pull ../b
380 $ hg pull ../b
375 pulling from ../b
381 pulling from ../b
376 searching for changes
382 searching for changes
377 adding changesets
383 adding changesets
378 adding manifests
384 adding manifests
379 adding file changes
385 adding file changes
380 added 1 changesets with 2 changes to 2 files (+1 heads)
386 added 1 changesets with 2 changes to 2 files (+1 heads)
381 (run 'hg heads' to see heads, 'hg merge' to merge)
387 (run 'hg heads' to see heads, 'hg merge' to merge)
382 $ hg rebase
388 $ hg rebase
383 getting changed largefiles
389 getting changed largefiles
384 1 largefiles updated, 0 removed
390 1 largefiles updated, 0 removed
385 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
391 saved backup bundle to $TESTTMP/e/.hg/strip-backup/f574fb32bb45-backup.hg
386 $ hg log
392 $ hg log
387 changeset: 9:598410d3eb9a
393 changeset: 9:598410d3eb9a
388 tag: tip
394 tag: tip
389 user: test
395 user: test
390 date: Thu Jan 01 00:00:00 1970 +0000
396 date: Thu Jan 01 00:00:00 1970 +0000
391 summary: modify normal file largefile in repo d
397 summary: modify normal file largefile in repo d
392
398
393 changeset: 8:a381d2c8c80e
399 changeset: 8:a381d2c8c80e
394 user: test
400 user: test
395 date: Thu Jan 01 00:00:00 1970 +0000
401 date: Thu Jan 01 00:00:00 1970 +0000
396 summary: modify normal file and largefile in repo b
402 summary: modify normal file and largefile in repo b
397
403
398 changeset: 7:daea875e9014
404 changeset: 7:daea875e9014
399 user: test
405 user: test
400 date: Thu Jan 01 00:00:00 1970 +0000
406 date: Thu Jan 01 00:00:00 1970 +0000
401 summary: add/edit more largefiles
407 summary: add/edit more largefiles
402
408
403 changeset: 6:4355d653f84f
409 changeset: 6:4355d653f84f
404 user: test
410 user: test
405 date: Thu Jan 01 00:00:00 1970 +0000
411 date: Thu Jan 01 00:00:00 1970 +0000
406 summary: edit files yet again
412 summary: edit files yet again
407
413
408 changeset: 5:9d5af5072dbd
414 changeset: 5:9d5af5072dbd
409 user: test
415 user: test
410 date: Thu Jan 01 00:00:00 1970 +0000
416 date: Thu Jan 01 00:00:00 1970 +0000
411 summary: edit files again
417 summary: edit files again
412
418
413 changeset: 4:74c02385b94c
419 changeset: 4:74c02385b94c
414 user: test
420 user: test
415 date: Thu Jan 01 00:00:00 1970 +0000
421 date: Thu Jan 01 00:00:00 1970 +0000
416 summary: move files
422 summary: move files
417
423
418 changeset: 3:9e8fbc4bce62
424 changeset: 3:9e8fbc4bce62
419 user: test
425 user: test
420 date: Thu Jan 01 00:00:00 1970 +0000
426 date: Thu Jan 01 00:00:00 1970 +0000
421 summary: copy files
427 summary: copy files
422
428
423 changeset: 2:51a0ae4d5864
429 changeset: 2:51a0ae4d5864
424 user: test
430 user: test
425 date: Thu Jan 01 00:00:00 1970 +0000
431 date: Thu Jan 01 00:00:00 1970 +0000
426 summary: remove files
432 summary: remove files
427
433
428 changeset: 1:ce8896473775
434 changeset: 1:ce8896473775
429 user: test
435 user: test
430 date: Thu Jan 01 00:00:00 1970 +0000
436 date: Thu Jan 01 00:00:00 1970 +0000
431 summary: edit files
437 summary: edit files
432
438
433 changeset: 0:30d30fe6a5be
439 changeset: 0:30d30fe6a5be
434 user: test
440 user: test
435 date: Thu Jan 01 00:00:00 1970 +0000
441 date: Thu Jan 01 00:00:00 1970 +0000
436 summary: add files
442 summary: add files
437
443
438 $ cat normal3
444 $ cat normal3
439 normal3-modified
445 normal3-modified
440 $ cat sub/normal4
446 $ cat sub/normal4
441 normal4-modified
447 normal4-modified
442 $ cat sub/large4
448 $ cat sub/large4
443 large4-modified
449 large4-modified
444 $ cat sub2/large6
450 $ cat sub2/large6
445 large6-modified
451 large6-modified
446 $ cat sub2/large7
452 $ cat sub2/large7
447 large7
453 large7
448
454
449 Rollback on largefiles.
455 Rollback on largefiles.
450
456
451 $ echo large4-modified-again > sub/large4
457 $ echo large4-modified-again > sub/large4
452 $ hg commit -m "Modify large4 again"
458 $ hg commit -m "Modify large4 again"
453 $ hg rollback
459 $ hg rollback
454 repository tip rolled back to revision 9 (undo commit)
460 repository tip rolled back to revision 9 (undo commit)
455 working directory now based on revision 9
461 working directory now based on revision 9
456 $ hg st
462 $ hg st
457 M sub/large4
463 M sub/large4
458 $ hg log
464 $ hg log
459 changeset: 9:598410d3eb9a
465 changeset: 9:598410d3eb9a
460 tag: tip
466 tag: tip
461 user: test
467 user: test
462 date: Thu Jan 01 00:00:00 1970 +0000
468 date: Thu Jan 01 00:00:00 1970 +0000
463 summary: modify normal file largefile in repo d
469 summary: modify normal file largefile in repo d
464
470
465 changeset: 8:a381d2c8c80e
471 changeset: 8:a381d2c8c80e
466 user: test
472 user: test
467 date: Thu Jan 01 00:00:00 1970 +0000
473 date: Thu Jan 01 00:00:00 1970 +0000
468 summary: modify normal file and largefile in repo b
474 summary: modify normal file and largefile in repo b
469
475
470 changeset: 7:daea875e9014
476 changeset: 7:daea875e9014
471 user: test
477 user: test
472 date: Thu Jan 01 00:00:00 1970 +0000
478 date: Thu Jan 01 00:00:00 1970 +0000
473 summary: add/edit more largefiles
479 summary: add/edit more largefiles
474
480
475 changeset: 6:4355d653f84f
481 changeset: 6:4355d653f84f
476 user: test
482 user: test
477 date: Thu Jan 01 00:00:00 1970 +0000
483 date: Thu Jan 01 00:00:00 1970 +0000
478 summary: edit files yet again
484 summary: edit files yet again
479
485
480 changeset: 5:9d5af5072dbd
486 changeset: 5:9d5af5072dbd
481 user: test
487 user: test
482 date: Thu Jan 01 00:00:00 1970 +0000
488 date: Thu Jan 01 00:00:00 1970 +0000
483 summary: edit files again
489 summary: edit files again
484
490
485 changeset: 4:74c02385b94c
491 changeset: 4:74c02385b94c
486 user: test
492 user: test
487 date: Thu Jan 01 00:00:00 1970 +0000
493 date: Thu Jan 01 00:00:00 1970 +0000
488 summary: move files
494 summary: move files
489
495
490 changeset: 3:9e8fbc4bce62
496 changeset: 3:9e8fbc4bce62
491 user: test
497 user: test
492 date: Thu Jan 01 00:00:00 1970 +0000
498 date: Thu Jan 01 00:00:00 1970 +0000
493 summary: copy files
499 summary: copy files
494
500
495 changeset: 2:51a0ae4d5864
501 changeset: 2:51a0ae4d5864
496 user: test
502 user: test
497 date: Thu Jan 01 00:00:00 1970 +0000
503 date: Thu Jan 01 00:00:00 1970 +0000
498 summary: remove files
504 summary: remove files
499
505
500 changeset: 1:ce8896473775
506 changeset: 1:ce8896473775
501 user: test
507 user: test
502 date: Thu Jan 01 00:00:00 1970 +0000
508 date: Thu Jan 01 00:00:00 1970 +0000
503 summary: edit files
509 summary: edit files
504
510
505 changeset: 0:30d30fe6a5be
511 changeset: 0:30d30fe6a5be
506 user: test
512 user: test
507 date: Thu Jan 01 00:00:00 1970 +0000
513 date: Thu Jan 01 00:00:00 1970 +0000
508 summary: add files
514 summary: add files
509
515
510 $ cat sub/large4
516 $ cat sub/large4
511 large4-modified-again
517 large4-modified-again
512
518
513 "update --check" refuses to update with uncommitted changes.
519 "update --check" refuses to update with uncommitted changes.
514 $ hg update --check 8
520 $ hg update --check 8
515 abort: uncommitted local changes
521 abort: uncommitted local changes
516 [255]
522 [255]
517
523
518 "update --clean" leaves correct largefiles in working copy.
524 "update --clean" leaves correct largefiles in working copy.
519
525
520 $ hg update --clean
526 $ hg update --clean
521 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
527 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
522 getting changed largefiles
528 getting changed largefiles
523 1 largefiles updated, 0 removed
529 1 largefiles updated, 0 removed
524 $ cat normal3
530 $ cat normal3
525 normal3-modified
531 normal3-modified
526 $ cat sub/normal4
532 $ cat sub/normal4
527 normal4-modified
533 normal4-modified
528 $ cat sub/large4
534 $ cat sub/large4
529 large4-modified
535 large4-modified
530 $ cat sub2/large6
536 $ cat sub2/large6
531 large6-modified
537 large6-modified
532 $ cat sub2/large7
538 $ cat sub2/large7
533 large7
539 large7
534
540
535 Now "update check" is happy.
541 Now "update check" is happy.
536 $ hg update --check 8
542 $ hg update --check 8
537 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
543 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 getting changed largefiles
544 getting changed largefiles
539 1 largefiles updated, 0 removed
545 1 largefiles updated, 0 removed
540 $ hg update --check
546 $ hg update --check
541 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
547 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
542 getting changed largefiles
548 getting changed largefiles
543 1 largefiles updated, 0 removed
549 1 largefiles updated, 0 removed
544
550
545 "revert" works on largefiles (and normal files too).
551 "revert" works on largefiles (and normal files too).
546 $ echo hack3 >> normal3
552 $ echo hack3 >> normal3
547 $ echo hack4 >> sub/normal4
553 $ echo hack4 >> sub/normal4
548 $ echo hack4 >> sub/large4
554 $ echo hack4 >> sub/large4
549 $ hg rm sub2/large6
555 $ hg rm sub2/large6
550 $ echo new >> sub2/large8
556 $ echo new >> sub2/large8
551 $ hg add --large sub2/large8
557 $ hg add --large sub2/large8
552 # XXX we don't really want to report that we're reverting the standin;
558 # XXX we don't really want to report that we're reverting the standin;
553 # that's just an implementation detail. But I don't see an obvious fix. ;-(
559 # that's just an implementation detail. But I don't see an obvious fix. ;-(
554 $ hg revert sub
560 $ hg revert sub
555 reverting .hglf/sub/large4
561 reverting .hglf/sub/large4
556 reverting sub/normal4
562 reverting sub/normal4
557 $ hg status
563 $ hg status
558 M normal3
564 M normal3
559 A sub2/large8
565 A sub2/large8
560 R sub2/large6
566 R sub2/large6
561 ? sub/large4.orig
567 ? sub/large4.orig
562 ? sub/normal4.orig
568 ? sub/normal4.orig
563 $ cat sub/normal4
569 $ cat sub/normal4
564 normal4-modified
570 normal4-modified
565 $ cat sub/large4
571 $ cat sub/large4
566 large4-modified
572 large4-modified
567 $ hg revert -a --no-backup
573 $ hg revert -a --no-backup
568 undeleting .hglf/sub2/large6
574 undeleting .hglf/sub2/large6
569 forgetting .hglf/sub2/large8
575 forgetting .hglf/sub2/large8
570 reverting normal3
576 reverting normal3
571 $ hg status
577 $ hg status
572 ? sub/large4.orig
578 ? sub/large4.orig
573 ? sub/normal4.orig
579 ? sub/normal4.orig
574 ? sub2/large8
580 ? sub2/large8
575 $ cat normal3
581 $ cat normal3
576 normal3-modified
582 normal3-modified
577 $ cat sub2/large6
583 $ cat sub2/large6
578 large6-modified
584 large6-modified
579 $ rm sub/*.orig sub2/large8
585 $ rm sub/*.orig sub2/large8
580
586
581 revert some files to an older revision
587 revert some files to an older revision
582 $ hg revert --no-backup -r 8 sub2
588 $ hg revert --no-backup -r 8 sub2
583 reverting .hglf/sub2/large6
589 reverting .hglf/sub2/large6
584 $ cat sub2/large6
590 $ cat sub2/large6
585 large6
591 large6
586 $ hg revert --no-backup sub2
592 $ hg revert --no-backup sub2
587 reverting .hglf/sub2/large6
593 reverting .hglf/sub2/large6
588 $ hg status
594 $ hg status
589
595
590 "verify --large" actually verifies largefiles
596 "verify --large" actually verifies largefiles
591
597
592 $ hg verify --large
598 $ hg verify --large
593 checking changesets
599 checking changesets
594 checking manifests
600 checking manifests
595 crosschecking files in changesets and manifests
601 crosschecking files in changesets and manifests
596 checking files
602 checking files
597 10 files, 10 changesets, 28 total revisions
603 10 files, 10 changesets, 28 total revisions
598 searching 1 changesets for largefiles
604 searching 1 changesets for largefiles
599 verified existence of 3 revisions of 3 largefiles
605 verified existence of 3 revisions of 3 largefiles
600
606
601 Merging does not revert to old versions of largefiles (this has also
607 Merging does not revert to old versions of largefiles (this has also
602 been very problematic).
608 been very problematic).
603
609
604 $ cd ..
610 $ cd ..
605 $ hg clone -r 7 e f
611 $ hg clone -r 7 e f
606 adding changesets
612 adding changesets
607 adding manifests
613 adding manifests
608 adding file changes
614 adding file changes
609 added 8 changesets with 24 changes to 10 files
615 added 8 changesets with 24 changes to 10 files
610 updating to branch default
616 updating to branch default
611 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
617 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
612 getting changed largefiles
618 getting changed largefiles
613 3 largefiles updated, 0 removed
619 3 largefiles updated, 0 removed
614 $ cd f
620 $ cd f
615 $ echo "large4-merge-test" > sub/large4
621 $ echo "large4-merge-test" > sub/large4
616 $ hg commit -m "Modify large4 to test merge"
622 $ hg commit -m "Modify large4 to test merge"
617 $ hg pull ../e
623 $ hg pull ../e
618 pulling from ../e
624 pulling from ../e
619 searching for changes
625 searching for changes
620 adding changesets
626 adding changesets
621 adding manifests
627 adding manifests
622 adding file changes
628 adding file changes
623 added 2 changesets with 4 changes to 4 files (+1 heads)
629 added 2 changesets with 4 changes to 4 files (+1 heads)
624 (run 'hg heads' to see heads, 'hg merge' to merge)
630 (run 'hg heads' to see heads, 'hg merge' to merge)
625 $ hg merge
631 $ hg merge
626 merging sub/large4
632 merging sub/large4
627 largefile sub/large4 has a merge conflict
633 largefile sub/large4 has a merge conflict
628 keep (l)ocal or take (o)ther? l
634 keep (l)ocal or take (o)ther? l
629 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
635 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
630 (branch merge, don't forget to commit)
636 (branch merge, don't forget to commit)
631 getting changed largefiles
637 getting changed largefiles
632 1 largefiles updated, 0 removed
638 1 largefiles updated, 0 removed
633 $ hg commit -m "Merge repos e and f"
639 $ hg commit -m "Merge repos e and f"
634 $ cat normal3
640 $ cat normal3
635 normal3-modified
641 normal3-modified
636 $ cat sub/normal4
642 $ cat sub/normal4
637 normal4-modified
643 normal4-modified
638 $ cat sub/large4
644 $ cat sub/large4
639 large4-merge-test
645 large4-merge-test
640 $ cat sub2/large6
646 $ cat sub2/large6
641 large6-modified
647 large6-modified
642 $ cat sub2/large7
648 $ cat sub2/large7
643 large7
649 large7
644
650
645 Test that a normal file and a largefile with the same name and path cannot
651 Test that a normal file and a largefile with the same name and path cannot
646 coexist.
652 coexist.
647
653
648 $ rm sub2/large7
654 $ rm sub2/large7
649 $ echo "largeasnormal" > sub2/large7
655 $ echo "largeasnormal" > sub2/large7
650 $ hg add sub2/large7
656 $ hg add sub2/large7
651 sub2/large7 already a largefile
657 sub2/large7 already a largefile
652
658
653 Test that transplanting a largefile change works correctly.
659 Test that transplanting a largefile change works correctly.
654
660
655 $ cd ..
661 $ cd ..
656 $ hg clone -r 8 d g
662 $ hg clone -r 8 d g
657 adding changesets
663 adding changesets
658 adding manifests
664 adding manifests
659 adding file changes
665 adding file changes
660 added 9 changesets with 26 changes to 10 files
666 added 9 changesets with 26 changes to 10 files
661 updating to branch default
667 updating to branch default
662 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
668 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
663 getting changed largefiles
669 getting changed largefiles
664 3 largefiles updated, 0 removed
670 3 largefiles updated, 0 removed
665 $ cd g
671 $ cd g
666 $ hg transplant -s ../d 598410d3eb9a
672 $ hg transplant -s ../d 598410d3eb9a
667 searching for changes
673 searching for changes
668 searching for changes
674 searching for changes
669 adding changesets
675 adding changesets
670 adding manifests
676 adding manifests
671 adding file changes
677 adding file changes
672 added 1 changesets with 2 changes to 2 files
678 added 1 changesets with 2 changes to 2 files
673 getting changed largefiles
679 getting changed largefiles
674 1 largefiles updated, 0 removed
680 1 largefiles updated, 0 removed
675 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
681 $ hg log --template '{rev}:{node|short} {desc|firstline}\n'
676 9:598410d3eb9a modify normal file largefile in repo d
682 9:598410d3eb9a modify normal file largefile in repo d
677 8:a381d2c8c80e modify normal file and largefile in repo b
683 8:a381d2c8c80e modify normal file and largefile in repo b
678 7:daea875e9014 add/edit more largefiles
684 7:daea875e9014 add/edit more largefiles
679 6:4355d653f84f edit files yet again
685 6:4355d653f84f edit files yet again
680 5:9d5af5072dbd edit files again
686 5:9d5af5072dbd edit files again
681 4:74c02385b94c move files
687 4:74c02385b94c move files
682 3:9e8fbc4bce62 copy files
688 3:9e8fbc4bce62 copy files
683 2:51a0ae4d5864 remove files
689 2:51a0ae4d5864 remove files
684 1:ce8896473775 edit files
690 1:ce8896473775 edit files
685 0:30d30fe6a5be add files
691 0:30d30fe6a5be add files
686 $ cat normal3
692 $ cat normal3
687 normal3-modified
693 normal3-modified
688 $ cat sub/normal4
694 $ cat sub/normal4
689 normal4-modified
695 normal4-modified
690 $ cat sub/large4
696 $ cat sub/large4
691 large4-modified
697 large4-modified
692 $ cat sub2/large6
698 $ cat sub2/large6
693 large6-modified
699 large6-modified
694 $ cat sub2/large7
700 $ cat sub2/large7
695 large7
701 large7
696 $ cd ..
702 $ cd ..
697
703
698 vanilla clients not locked out from largefiles servers on vanilla repos
704 vanilla clients not locked out from largefiles servers on vanilla repos
699 $ mkdir r1
705 $ mkdir r1
700 $ cd r1
706 $ cd r1
701 $ hg init
707 $ hg init
702 $ echo c1 > f1
708 $ echo c1 > f1
703 $ hg add f1
709 $ hg add f1
704 $ hg com -m "m1"
710 $ hg com -m "m1"
705 $ cd ..
711 $ cd ..
706 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
712 $ hg serve -R r1 -d -p $HGPORT --pid-file hg.pid
707 $ cat hg.pid >> $DAEMON_PIDS
713 $ cat hg.pid >> $DAEMON_PIDS
708 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
714 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT r2
709 requesting all changes
715 requesting all changes
710 adding changesets
716 adding changesets
711 adding manifests
717 adding manifests
712 adding file changes
718 adding file changes
713 added 1 changesets with 1 changes to 1 files
719 added 1 changesets with 1 changes to 1 files
714 updating to branch default
720 updating to branch default
715 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
716
722
717 largefiles clients still work with vanilla servers
723 largefiles clients still work with vanilla servers
718 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
724 $ hg --config extensions.largefiles=! serve -R r1 -d -p $HGPORT1 --pid-file hg.pid
719 $ cat hg.pid >> $DAEMON_PIDS
725 $ cat hg.pid >> $DAEMON_PIDS
720 $ hg clone http://localhost:$HGPORT1 r3
726 $ hg clone http://localhost:$HGPORT1 r3
721 requesting all changes
727 requesting all changes
722 adding changesets
728 adding changesets
723 adding manifests
729 adding manifests
724 adding file changes
730 adding file changes
725 added 1 changesets with 1 changes to 1 files
731 added 1 changesets with 1 changes to 1 files
726 updating to branch default
732 updating to branch default
727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
728
734
729 vanilla clients locked out from largefiles http repos
735 vanilla clients locked out from largefiles http repos
730 $ mkdir r4
736 $ mkdir r4
731 $ cd r4
737 $ cd r4
732 $ hg init
738 $ hg init
733 $ echo c1 > f1
739 $ echo c1 > f1
734 $ hg add --large f1
740 $ hg add --large f1
735 $ hg com -m "m1"
741 $ hg com -m "m1"
736 $ cd ..
742 $ cd ..
737 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
743 $ hg serve -R r4 -d -p $HGPORT2 --pid-file hg.pid
738 $ cat hg.pid >> $DAEMON_PIDS
744 $ cat hg.pid >> $DAEMON_PIDS
739 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
745 $ hg --config extensions.largefiles=! clone http://localhost:$HGPORT2 r5
740 abort: remote error:
746 abort: remote error:
741
747
742 This repository uses the largefiles extension.
748 This repository uses the largefiles extension.
743
749
744 Please enable it in your Mercurial config file.
750 Please enable it in your Mercurial config file.
745 [255]
751 [255]
746
752
747 used all HGPORTs, kill all daemons
753 used all HGPORTs, kill all daemons
748 $ "$TESTDIR/killdaemons.py"
754 $ "$TESTDIR/killdaemons.py"
749
755
750 vanilla clients locked out from largefiles ssh repos
756 vanilla clients locked out from largefiles ssh repos
751 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
757 $ hg --config extensions.largefiles=! clone -e "python $TESTDIR/dummyssh" ssh://user@dummy/r4 r5
752 abort: remote error:
758 abort: remote error:
753
759
754 This repository uses the largefiles extension.
760 This repository uses the largefiles extension.
755
761
756 Please enable it in your Mercurial config file.
762 Please enable it in your Mercurial config file.
757 [255]
763 [255]
758
764
759 largefiles clients refuse to push largefiles repos to vanilla servers
765 largefiles clients refuse to push largefiles repos to vanilla servers
760 $ mkdir r6
766 $ mkdir r6
761 $ cd r6
767 $ cd r6
762 $ hg init
768 $ hg init
763 $ echo c1 > f1
769 $ echo c1 > f1
764 $ hg add f1
770 $ hg add f1
765 $ hg com -m "m1"
771 $ hg com -m "m1"
766 $ cat >> .hg/hgrc <<!
772 $ cat >> .hg/hgrc <<!
767 > [web]
773 > [web]
768 > push_ssl = false
774 > push_ssl = false
769 > allow_push = *
775 > allow_push = *
770 > !
776 > !
771 $ cd ..
777 $ cd ..
772 $ hg clone r6 r7
778 $ hg clone r6 r7
773 updating to branch default
779 updating to branch default
774 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
780 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
775 $ cd r7
781 $ cd r7
776 $ echo c2 > f2
782 $ echo c2 > f2
777 $ hg add --large f2
783 $ hg add --large f2
778 $ hg com -m "m2"
784 $ hg com -m "m2"
779 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
785 $ hg --config extensions.largefiles=! -R ../r6 serve -d -p $HGPORT --pid-file ../hg.pid
780 $ cat ../hg.pid >> $DAEMON_PIDS
786 $ cat ../hg.pid >> $DAEMON_PIDS
781 $ hg push http://localhost:$HGPORT
787 $ hg push http://localhost:$HGPORT
782 pushing to http://localhost:$HGPORT/
788 pushing to http://localhost:$HGPORT/
783 searching for changes
789 searching for changes
784 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
790 abort: http://localhost:$HGPORT/ does not appear to be a largefile store
785 [255]
791 [255]
786 $ cd ..
792 $ cd ..
787
793
788 $ cd ..
794 $ cd ..
789
795
790 Clone a local repository owned by another user
796 Clone a local repository owned by another user
791 We have to simulate that here by setting $HOME and removing write permissions
797 We have to simulate that here by setting $HOME and removing write permissions
792 $ ORIGHOME="$HOME"
798 $ ORIGHOME="$HOME"
793 $ mkdir alice
799 $ mkdir alice
794 $ HOME="`pwd`/alice"
800 $ HOME="`pwd`/alice"
795 $ cd alice
801 $ cd alice
796 $ hg init pubrepo
802 $ hg init pubrepo
797 $ cd pubrepo
803 $ cd pubrepo
798 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
804 $ dd if=/dev/urandom bs=1k count=11k > a-large-file 2> /dev/null
799 $ hg add --large a-large-file
805 $ hg add --large a-large-file
800 $ hg commit -m "Add a large file"
806 $ hg commit -m "Add a large file"
801 $ cd ..
807 $ cd ..
802 $ chmod -R a-w pubrepo
808 $ chmod -R a-w pubrepo
803 $ cd ..
809 $ cd ..
804 $ mkdir bob
810 $ mkdir bob
805 $ HOME="`pwd`/bob"
811 $ HOME="`pwd`/bob"
806 $ cd bob
812 $ cd bob
807 $ hg clone --pull ../alice/pubrepo pubrepo
813 $ hg clone --pull ../alice/pubrepo pubrepo
808 requesting all changes
814 requesting all changes
809 adding changesets
815 adding changesets
810 adding manifests
816 adding manifests
811 adding file changes
817 adding file changes
812 added 1 changesets with 1 changes to 1 files
818 added 1 changesets with 1 changes to 1 files
813 updating to branch default
819 updating to branch default
814 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
820 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
815 getting changed largefiles
821 getting changed largefiles
816 1 largefiles updated, 0 removed
822 1 largefiles updated, 0 removed
817 $ cd ..
823 $ cd ..
818 $ HOME="$ORIGHOME"
824 $ HOME="$ORIGHOME"
819
825
820 Symlink to a large largefile should behave the same as a symlink to a normal file
826 Symlink to a large largefile should behave the same as a symlink to a normal file
821 $ hg init largesymlink
827 $ hg init largesymlink
822 $ cd largesymlink
828 $ cd largesymlink
823 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
829 $ dd if=/dev/zero bs=1k count=10k of=largefile 2>/dev/null
824 $ hg add --large largefile
830 $ hg add --large largefile
825 $ hg commit -m "commit a large file"
831 $ hg commit -m "commit a large file"
826 $ ln -s largefile largelink
832 $ ln -s largefile largelink
827 $ hg add largelink
833 $ hg add largelink
828 $ hg commit -m "commit a large symlink"
834 $ hg commit -m "commit a large symlink"
829 $ rm -f largelink
835 $ rm -f largelink
830 $ hg up >/dev/null
836 $ hg up >/dev/null
831 $ test -f largelink
837 $ test -f largelink
832 [1]
838 [1]
833 $ test -L largelink
839 $ test -L largelink
834 [1]
840 [1]
835 $ rm -f largelink # make next part of the test independent of the previous
841 $ rm -f largelink # make next part of the test independent of the previous
836 $ hg up -C >/dev/null
842 $ hg up -C >/dev/null
837 $ test -f largelink
843 $ test -f largelink
838 $ test -L largelink
844 $ test -L largelink
839 $ cd ..
845 $ cd ..
840
846
841
847
General Comments 0
You need to be logged in to leave comments. Login now