annotate hgext/largefiles/lfcommands.py @ 16439:290850e7aa43

largefiles: fix cat for largefiles (issue3352) This is a fix to largefiles so that 'hg cat' will work correctly when a largefile is specified. As per discussion on Issue 3352: 1) The file will be printed regardless if it is binary or large. 2) The file is downloaded if it is not readily available (not found in the system cache), so that it can be printed. If the download fails, then we abort.
author Na'Tosha Bard <natosha@unity3d.com>
date Mon, 16 Apr 2012 17:03:39 +0200
parents d87d9d8a8e03
children ebf6d38c9063
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
1 # Copyright 2009-2010 Gregory P. Ward
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
2 # Copyright 2009-2010 Intelerad Medical Systems Incorporated
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
3 # Copyright 2010-2011 Fog Creek Software
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
4 # Copyright 2010-2011 Unity Technologies
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
5 #
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
6 # This software may be used and distributed according to the terms of the
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
7 # GNU General Public License version 2 or any later version.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
8
15252
6e809bb4f969 largefiles: improve comments, internal docstrings
Greg Ward <greg@gerg.ca>
parents: 15230
diff changeset
9 '''High-level command function for lfconvert, plus the cmdtable.'''
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
10
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
11 import os
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
12 import shutil
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
13
16439
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
14 from mercurial import util, match as match_, hg, node, context, error, cmdutil
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
15 from mercurial.i18n import _
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
16
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
17 import lfutil
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
18 import basestore
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
19
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
20 # -- Commands ----------------------------------------------------------
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
21
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
22 def lfconvert(ui, src, dest, *pats, **opts):
15230
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
23 '''convert a normal repository to a largefiles repository
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
24
15230
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
25 Convert repository SOURCE to a new repository DEST, identical to
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
26 SOURCE except that certain files will be converted as largefiles:
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
27 specifically, any file that matches any PATTERN *or* whose size is
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
28 above the minimum size threshold is converted as a largefile. The
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
29 size used to determine whether or not to track a file as a
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
30 largefile is the size of the first version of the file. The
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
31 minimum size can be specified either with --size or in
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
32 configuration as ``largefiles.size``.
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
33
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
34 After running this command you will need to make sure that
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
35 largefiles is enabled anywhere you intend to push the new
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
36 repository.
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
37
15332
0db47b8d025f largefiles: rename lfconvert --tonormal option to --to-normal
Greg Ward <greg@gerg.ca>
parents: 15317
diff changeset
38 Use --to-normal to convert largefiles back to normal files; after
15230
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
39 this, the DEST repository can be used without largefiles at all.'''
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
40
15332
0db47b8d025f largefiles: rename lfconvert --tonormal option to --to-normal
Greg Ward <greg@gerg.ca>
parents: 15317
diff changeset
41 if opts['to_normal']:
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
42 tolfile = False
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
43 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
44 tolfile = True
15227
a7686abf73a6 largefiles: factor out lfutil.getminsize()
Greg Ward <greg@gerg.ca>
parents: 15224
diff changeset
45 size = lfutil.getminsize(ui, True, opts.get('size'), default=None)
15340
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
46
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
47 if not hg.islocal(src):
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
48 raise util.Abort(_('%s is not a local Mercurial repo') % src)
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
49 if not hg.islocal(dest):
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
50 raise util.Abort(_('%s is not a local Mercurial repo') % dest)
0e58513cc59a largefiles: rearrange how lfconvert detects non-local repos
Greg Ward <greg@gerg.ca>
parents: 15339
diff changeset
51
15339
be1377d19018 largefiles: test lfconvert error handling; remove redundant code
Greg Ward <greg@gerg.ca>
parents: 15332
diff changeset
52 rsrc = hg.repository(ui, src)
be1377d19018 largefiles: test lfconvert error handling; remove redundant code
Greg Ward <greg@gerg.ca>
parents: 15332
diff changeset
53 ui.status(_('initializing destination %s\n') % dest)
be1377d19018 largefiles: test lfconvert error handling; remove redundant code
Greg Ward <greg@gerg.ca>
parents: 15332
diff changeset
54 rdst = hg.repository(ui, dest, create=True)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
55
15171
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
56 success = False
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
57 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
58 # Lock destination to prevent modification while it is converted to.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
59 # Don't need to lock src because we are just reading from its history
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
60 # which can't change.
16247
d87d9d8a8e03 largefiles: remove use of underscores that breaks coding convention
Na'Tosha Bard <natosha@unity3d.com>
parents: 16231
diff changeset
61 dstlock = rdst.lock()
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
62
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
63 # Get a list of all changesets in the source. The easy way to do this
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
64 # is to simply walk the changelog, using changelog.nodesbewteen().
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
65 # Take a look at mercurial/revlog.py:639 for more details.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
66 # Use a generator instead of a list to decrease memory usage
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
67 ctxs = (rsrc[ctx] for ctx in rsrc.changelog.nodesbetween(None,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
68 rsrc.heads())[0])
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
69 revmap = {node.nullid: node.nullid}
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
70 if tolfile:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
71 lfiles = set()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
72 normalfiles = set()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
73 if not pats:
15579
6c5e6ebe0812 largefiles: use "ui.configlist()" to get largefiles.patterns configuration
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15472
diff changeset
74 pats = ui.configlist(lfutil.longname, 'patterns', default=[])
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
75 if pats:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
76 matcher = match_.match(rsrc.root, '', list(pats))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
77 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
78 matcher = None
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
79
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
80 lfiletohash = {}
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
81 for ctx in ctxs:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
82 ui.progress(_('converting revisions'), ctx.rev(),
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
83 unit=_('revision'), total=rsrc['tip'].rev())
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
84 _lfconvert_addchangeset(rsrc, rdst, ctx, revmap,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
85 lfiles, normalfiles, matcher, size, lfiletohash)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
86 ui.progress(_('converting revisions'), None)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
87
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
88 if os.path.exists(rdst.wjoin(lfutil.shortname)):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
89 shutil.rmtree(rdst.wjoin(lfutil.shortname))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
90
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
91 for f in lfiletohash.keys():
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
92 if os.path.isfile(rdst.wjoin(f)):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
93 os.unlink(rdst.wjoin(f))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
94 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
95 os.removedirs(os.path.dirname(rdst.wjoin(f)))
15171
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
96 except OSError:
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
97 pass
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
98
15303
07811b3b119b largefiles: include 'largefiles' in converted repository requirements
Eli Carter <eli.carter@tektronix.com>
parents: 15255
diff changeset
99 # If there were any files converted to largefiles, add largefiles
07811b3b119b largefiles: include 'largefiles' in converted repository requirements
Eli Carter <eli.carter@tektronix.com>
parents: 15255
diff changeset
100 # to the destination repository's requirements.
07811b3b119b largefiles: include 'largefiles' in converted repository requirements
Eli Carter <eli.carter@tektronix.com>
parents: 15255
diff changeset
101 if lfiles:
07811b3b119b largefiles: include 'largefiles' in converted repository requirements
Eli Carter <eli.carter@tektronix.com>
parents: 15255
diff changeset
102 rdst.requirements.add('largefiles')
07811b3b119b largefiles: include 'largefiles' in converted repository requirements
Eli Carter <eli.carter@tektronix.com>
parents: 15255
diff changeset
103 rdst._writerequirements()
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
104 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
105 for ctx in ctxs:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
106 ui.progress(_('converting revisions'), ctx.rev(),
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
107 unit=_('revision'), total=rsrc['tip'].rev())
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
108 _addchangeset(ui, rsrc, rdst, ctx, revmap)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
109
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
110 ui.progress(_('converting revisions'), None)
15171
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
111 success = True
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
112 finally:
15171
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
113 if not success:
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
114 # we failed, remove the new directory
547da6115d1d largefiles: eliminate naked exceptions
Matt Mackall <mpm@selenic.com>
parents: 15170
diff changeset
115 shutil.rmtree(rdst.root)
16247
d87d9d8a8e03 largefiles: remove use of underscores that breaks coding convention
Na'Tosha Bard <natosha@unity3d.com>
parents: 16231
diff changeset
116 dstlock.release()
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
117
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
118 def _addchangeset(ui, rsrc, rdst, ctx, revmap):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
119 # Convert src parents to dst parents
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
120 parents = _convertparents(ctx, revmap)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
121
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
122 # Generate list of changed files
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
123 files = _getchangedfiles(ctx, parents)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
124
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
125 def getfilectx(repo, memctx, f):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
126 if lfutil.standin(f) in files:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
127 # if the file isn't in the manifest then it was removed
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
128 # or renamed, raise IOError to indicate this
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
129 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
130 fctx = ctx.filectx(lfutil.standin(f))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
131 except error.LookupError:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
132 raise IOError()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
133 renamed = fctx.renamed()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
134 if renamed:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
135 renamed = lfutil.splitstandin(renamed[0])
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
136
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
137 hash = fctx.data().strip()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
138 path = lfutil.findfile(rsrc, hash)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
139 ### TODO: What if the file is not cached?
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
140 data = ''
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
141 fd = None
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
142 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
143 fd = open(path, 'rb')
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
144 data = fd.read()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
145 finally:
15172
fb1dcd2aae2a largefiles: fix multistatement line
Matt Mackall <mpm@selenic.com>
parents: 15171
diff changeset
146 if fd:
fb1dcd2aae2a largefiles: fix multistatement line
Matt Mackall <mpm@selenic.com>
parents: 15171
diff changeset
147 fd.close()
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
148 return context.memfilectx(f, data, 'l' in fctx.flags(),
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
149 'x' in fctx.flags(), renamed)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
150 else:
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
151 return _getnormalcontext(repo.ui, ctx, f, revmap)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
152
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
153 dstfiles = []
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
154 for file in files:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
155 if lfutil.isstandin(file):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
156 dstfiles.append(lfutil.splitstandin(file))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
157 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
158 dstfiles.append(file)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
159 # Commit
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
160 _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
161
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
162 def _lfconvert_addchangeset(rsrc, rdst, ctx, revmap, lfiles, normalfiles,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
163 matcher, size, lfiletohash):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
164 # Convert src parents to dst parents
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
165 parents = _convertparents(ctx, revmap)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
166
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
167 # Generate list of changed files
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
168 files = _getchangedfiles(ctx, parents)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
169
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
170 dstfiles = []
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
171 for f in files:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
172 if f not in lfiles and f not in normalfiles:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
173 islfile = _islfile(f, ctx, matcher, size)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
174 # If this file was renamed or copied then copy
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
175 # the lfileness of its predecessor
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
176 if f in ctx.manifest():
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
177 fctx = ctx.filectx(f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
178 renamed = fctx.renamed()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
179 renamedlfile = renamed and renamed[0] in lfiles
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
180 islfile |= renamedlfile
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
181 if 'l' in fctx.flags():
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
182 if renamedlfile:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
183 raise util.Abort(
15380
a53888685a6c largefiles: fix uppercase in abort message
Martin Geisler <mg@aragost.com>
parents: 15371
diff changeset
184 _('renamed/copied largefile %s becomes symlink')
15170
c1a4a3220711 largefiles: fix over-long lines
Matt Mackall <mpm@selenic.com>
parents: 15168
diff changeset
185 % f)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
186 islfile = False
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
187 if islfile:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
188 lfiles.add(f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
189 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
190 normalfiles.add(f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
191
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
192 if f in lfiles:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
193 dstfiles.append(lfutil.standin(f))
15254
dd03d3a9f888 largefiles: more work on cleaning up comments
Greg Ward <greg@gerg.ca>
parents: 15253
diff changeset
194 # largefile in manifest if it has not been removed/renamed
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
195 if f in ctx.manifest():
15808
62098aeb1e15 largefiles: don't reference uninitialized variable (issue3092)
Levi Bard <levi@unity3d.com>
parents: 15793
diff changeset
196 fctx = ctx.filectx(f)
62098aeb1e15 largefiles: don't reference uninitialized variable (issue3092)
Levi Bard <levi@unity3d.com>
parents: 15793
diff changeset
197 if 'l' in fctx.flags():
62098aeb1e15 largefiles: don't reference uninitialized variable (issue3092)
Levi Bard <levi@unity3d.com>
parents: 15793
diff changeset
198 renamed = fctx.renamed()
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
199 if renamed and renamed[0] in lfiles:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
200 raise util.Abort(_('largefile %s becomes symlink') % f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
201
15254
dd03d3a9f888 largefiles: more work on cleaning up comments
Greg Ward <greg@gerg.ca>
parents: 15253
diff changeset
202 # largefile was modified, update standins
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
203 fullpath = rdst.wjoin(f)
15371
f26ed4ea46d8 largefiles: remove lfutil.createdir, replace calls with util.makedirs
Hao Lian <hao@fogcreek.com>
parents: 15340
diff changeset
204 util.makedirs(os.path.dirname(fullpath))
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
205 m = util.sha1('')
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
206 m.update(ctx[f].data())
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
207 hash = m.hexdigest()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
208 if f not in lfiletohash or lfiletohash[f] != hash:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
209 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
210 fd = open(fullpath, 'wb')
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
211 fd.write(ctx[f].data())
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
212 finally:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
213 if fd:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
214 fd.close()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
215 executable = 'x' in ctx[f].flags()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
216 os.chmod(fullpath, lfutil.getmode(executable))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
217 lfutil.writestandin(rdst, lfutil.standin(f), hash,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
218 executable)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
219 lfiletohash[f] = hash
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
220 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
221 # normal file
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
222 dstfiles.append(f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
223
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
224 def getfilectx(repo, memctx, f):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
225 if lfutil.isstandin(f):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
226 # if the file isn't in the manifest then it was removed
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
227 # or renamed, raise IOError to indicate this
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
228 srcfname = lfutil.splitstandin(f)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
229 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
230 fctx = ctx.filectx(srcfname)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
231 except error.LookupError:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
232 raise IOError()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
233 renamed = fctx.renamed()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
234 if renamed:
15254
dd03d3a9f888 largefiles: more work on cleaning up comments
Greg Ward <greg@gerg.ca>
parents: 15253
diff changeset
235 # standin is always a largefile because largefile-ness
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
236 # doesn't change after rename or copy
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
237 renamed = lfutil.standin(renamed[0])
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
238
15313
3eb1a90ea409 largefiles: fix newline for lfconverted repos
Eli Carter <eli.carter@tektronix.com>
parents: 15303
diff changeset
239 return context.memfilectx(f, lfiletohash[srcfname] + '\n', 'l' in
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
240 fctx.flags(), 'x' in fctx.flags(), renamed)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
241 else:
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
242 return _getnormalcontext(repo.ui, ctx, f, revmap)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
243
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
244 # Commit
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
245 _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
246
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
247 def _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap):
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
248 mctx = context.memctx(rdst, parents, ctx.description(), dstfiles,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
249 getfilectx, ctx.user(), ctx.date(), ctx.extra())
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
250 ret = rdst.commitctx(mctx)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
251 rdst.dirstate.setparents(ret)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
252 revmap[ctx.node()] = rdst.changelog.tip()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
253
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
254 # Generate list of changed files
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
255 def _getchangedfiles(ctx, parents):
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
256 files = set(ctx.files())
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
257 if node.nullid not in parents:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
258 mc = ctx.manifest()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
259 mp1 = ctx.parents()[0].manifest()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
260 mp2 = ctx.parents()[1].manifest()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
261 files |= (set(mp1) | set(mp2)) - set(mc)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
262 for f in mc:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
263 if mc[f] != mp1.get(f, None) or mc[f] != mp2.get(f, None):
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
264 files.add(f)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
265 return files
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
266
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
267 # Convert src parents to dst parents
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
268 def _convertparents(ctx, revmap):
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
269 parents = []
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
270 for p in ctx.parents():
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
271 parents.append(revmap[p.node()])
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
272 while len(parents) < 2:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
273 parents.append(node.nullid)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
274 return parents
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
275
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
276 # Get memfilectx for a normal file
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
277 def _getnormalcontext(ui, ctx, f, revmap):
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
278 try:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
279 fctx = ctx.filectx(f)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
280 except error.LookupError:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
281 raise IOError()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
282 renamed = fctx.renamed()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
283 if renamed:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
284 renamed = renamed[0]
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
285
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
286 data = fctx.data()
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
287 if f == '.hgtags':
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
288 data = _converttags (ui, revmap, data)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
289 return context.memfilectx(f, data, 'l' in fctx.flags(),
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
290 'x' in fctx.flags(), renamed)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
291
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
292 # Remap tag data using a revision map
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
293 def _converttags(ui, revmap, data):
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
294 newdata = []
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
295 for line in data.splitlines():
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
296 try:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
297 id, name = line.split(' ', 1)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
298 except ValueError:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
299 ui.warn(_('skipping incorrectly formatted tag %s\n'
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
300 % line))
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
301 continue
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
302 try:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
303 newid = node.bin(id)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
304 except TypeError:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
305 ui.warn(_('skipping incorrectly formatted id %s\n'
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
306 % id))
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
307 continue
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
308 try:
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
309 newdata.append('%s %s\n' % (node.hex(revmap[newid]),
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
310 name))
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
311 except KeyError:
16231
ce292f1379ba i18n: fix all remaining uses of % inside _()
Matt Mackall <mpm@selenic.com>
parents: 15909
diff changeset
312 ui.warn(_('no mapping for id %s\n') % id)
15811
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
313 continue
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
314 return ''.join(newdata)
b9886dde3649 largefiles: remove pasted code
Levi Bard <levi@unity3d.com>
parents: 15809
diff changeset
315
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
316 def _islfile(file, ctx, matcher, size):
15252
6e809bb4f969 largefiles: improve comments, internal docstrings
Greg Ward <greg@gerg.ca>
parents: 15230
diff changeset
317 '''Return true if file should be considered a largefile, i.e.
6e809bb4f969 largefiles: improve comments, internal docstrings
Greg Ward <greg@gerg.ca>
parents: 15230
diff changeset
318 matcher matches it or it is larger than size.'''
6e809bb4f969 largefiles: improve comments, internal docstrings
Greg Ward <greg@gerg.ca>
parents: 15230
diff changeset
319 # never store special .hg* files as largefiles
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
320 if file == '.hgtags' or file == '.hgignore' or file == '.hgsigs':
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
321 return False
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
322 if matcher and matcher(file):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
323 return True
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
324 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
325 return ctx.filectx(file).size() >= size * 1024 * 1024
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
326 except error.LookupError:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
327 return False
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
328
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
329 def uploadlfiles(ui, rsrc, rdst, files):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
330 '''upload largefiles to the central store'''
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
331
15317
41f371150ccb largefiles: make the store primary, and the user cache secondary
Benjamin Pollack <benjamin@bitquabit.com>
parents: 15313
diff changeset
332 if not files:
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
333 return
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
334
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
335 store = basestore._openstore(rsrc, rdst, put=True)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
336
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
337 at = 0
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
338 files = filter(lambda h: not store.exists(h), files)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
339 for hash in files:
15170
c1a4a3220711 largefiles: fix over-long lines
Matt Mackall <mpm@selenic.com>
parents: 15168
diff changeset
340 ui.progress(_('uploading largefiles'), at, unit='largefile',
c1a4a3220711 largefiles: fix over-long lines
Matt Mackall <mpm@selenic.com>
parents: 15168
diff changeset
341 total=len(files))
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
342 source = lfutil.findfile(rsrc, hash)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
343 if not source:
15253
67d010779907 largefiles: improve error reporting
Greg Ward <greg@gerg.ca>
parents: 15252
diff changeset
344 raise util.Abort(_('largefile %s missing from store'
67d010779907 largefiles: improve error reporting
Greg Ward <greg@gerg.ca>
parents: 15252
diff changeset
345 ' (needs to be uploaded)') % hash)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
346 # XXX check for errors here
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
347 store.put(source, hash)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
348 at += 1
15173
3d27a8ff895f largefiles: mark a string for translation
Matt Mackall <mpm@selenic.com>
parents: 15172
diff changeset
349 ui.progress(_('uploading largefiles'), None)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
350
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
351 def verifylfiles(ui, repo, all=False, contents=False):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
352 '''Verify that every big file revision in the current changeset
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
353 exists in the central store. With --contents, also verify that
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
354 the contents of each big file revision are correct (SHA-1 hash
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
355 matches the revision ID). With --all, check every changeset in
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
356 this repository.'''
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
357 if all:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
358 # Pass a list to the function rather than an iterator because we know a
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
359 # list will work.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
360 revs = range(len(repo))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
361 else:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
362 revs = ['.']
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
363
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
364 store = basestore._openstore(repo)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
365 return store.verify(revs, contents=contents)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
366
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
367 def cachelfiles(ui, repo, node):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
368 '''cachelfiles ensures that all largefiles needed by the specified revision
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
369 are present in the repository's largefile cache.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
370
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
371 returns a tuple (cached, missing). cached is the list of files downloaded
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
372 by this operation; missing is the list of files that were needed but could
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
373 not be found.'''
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
374 lfiles = lfutil.listlfiles(repo, node)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
375 toget = []
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
376
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
377 for lfile in lfiles:
15860
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
378 # If we are mid-merge, then we have to trust the standin that is in the
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
379 # working copy to have the correct hashvalue. This is because the
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
380 # original hg.merge() already updated the standin as part of the normal
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
381 # merge process -- we just have to udpate the largefile to match.
15905
634d49a8b6db largefiles: correctly handle newly added largefile on other side of merge
Na'Tosha Bard <natosha@unity3d.com>
parents: 15860
diff changeset
382 if (getattr(repo, "_ismerging", False) and
634d49a8b6db largefiles: correctly handle newly added largefile on other side of merge
Na'Tosha Bard <natosha@unity3d.com>
parents: 15860
diff changeset
383 os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
15860
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
384 expectedhash = lfutil.readstandin(repo, lfile)
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
385 else:
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
386 expectedhash = repo[node][lfutil.standin(lfile)].data().strip()
3ecce805ac13 largefiles: correctly download new largefiles when merging
Na'Tosha Bard <natosha@unity3d.com>
parents: 15811
diff changeset
387
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
388 # if it exists and its hash matches, it might have been locally
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
389 # modified before updating and the user chose 'local'. in this case,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
390 # it will not be in any store, so don't look for it.
15255
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
391 if ((not os.path.exists(repo.wjoin(lfile)) or
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
392 expectedhash != lfutil.hashfile(repo.wjoin(lfile))) and
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
393 not lfutil.findfile(repo, expectedhash)):
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
394 toget.append((lfile, expectedhash))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
395
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
396 if toget:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
397 store = basestore._openstore(repo)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
398 ret = store.get(toget)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
399 return ret
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
400
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
401 return ([], [])
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
402
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
403 def updatelfiles(ui, repo, filelist=None, printmessage=True):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
404 wlock = repo.wlock()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
405 try:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
406 lfdirstate = lfutil.openlfdirstate(ui, repo)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
407 lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
408
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
409 if filelist is not None:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
410 lfiles = [f for f in lfiles if f in filelist]
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
411
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
412 printed = False
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
413 if printmessage and lfiles:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
414 ui.status(_('getting changed largefiles\n'))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
415 printed = True
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
416 cachelfiles(ui, repo, '.')
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
417
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
418 updated, removed = 0, 0
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
419 for i in map(lambda f: _updatelfile(repo, lfdirstate, f), lfiles):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
420 # increment the appropriate counter according to _updatelfile's
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
421 # return value
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
422 updated += i > 0 and i or 0
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
423 removed -= i < 0 and i or 0
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
424 if printmessage and (removed or updated) and not printed:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
425 ui.status(_('getting changed largefiles\n'))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
426 printed = True
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
427
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
428 lfdirstate.write()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
429 if printed and printmessage:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
430 ui.status(_('%d largefiles updated, %d removed\n') % (updated,
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
431 removed))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
432 finally:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
433 wlock.release()
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
434
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
435 def _updatelfile(repo, lfdirstate, lfile):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
436 '''updates a single largefile and copies the state of its standin from
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
437 the repository's dirstate to its state in the lfdirstate.
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
438
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
439 returns 1 if the file was modified, -1 if the file was removed, 0 if the
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
440 file was unchanged, and None if the needed largefile was missing from the
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
441 cache.'''
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
442 ret = 0
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
443 abslfile = repo.wjoin(lfile)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
444 absstandin = repo.wjoin(lfutil.standin(lfile))
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
445 if os.path.exists(absstandin):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
446 if os.path.exists(absstandin+'.orig'):
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
447 shutil.copyfile(abslfile, abslfile+'.orig')
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
448 expecthash = lfutil.readstandin(repo, lfile)
15255
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
449 if (expecthash != '' and
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
450 (not os.path.exists(abslfile) or
7ab05d752405 largefiles: cosmetics, whitespace, code style
Greg Ward <greg@gerg.ca>
parents: 15254
diff changeset
451 expecthash != lfutil.hashfile(abslfile))):
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
452 if not lfutil.copyfromcache(repo, expecthash, lfile):
15472
6a7e874390b0 largefiles: treat status of cache missed largefiles as "missing" correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15380
diff changeset
453 # use normallookup() to allocate entry in largefiles dirstate,
16247
d87d9d8a8e03 largefiles: remove use of underscores that breaks coding convention
Na'Tosha Bard <natosha@unity3d.com>
parents: 16231
diff changeset
454 # because lack of it misleads lfilesrepo.status() into
15472
6a7e874390b0 largefiles: treat status of cache missed largefiles as "missing" correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15380
diff changeset
455 # recognition that such cache missing files are REMOVED.
6a7e874390b0 largefiles: treat status of cache missed largefiles as "missing" correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15380
diff changeset
456 lfdirstate.normallookup(lfile)
6a7e874390b0 largefiles: treat status of cache missed largefiles as "missing" correctly
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15380
diff changeset
457 return None # don't try to set the mode
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
458 ret = 1
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
459 mode = os.stat(absstandin).st_mode
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
460 if mode != os.stat(abslfile).st_mode:
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
461 os.chmod(abslfile, mode)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
462 ret = 1
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
463 else:
15663
9036c7d106bf largefiles: handle merges between normal files and largefiles (issue3084)
Martin Geisler <mg@aragost.com>
parents: 15579
diff changeset
464 # Remove lfiles for which the standin is deleted, unless the
9036c7d106bf largefiles: handle merges between normal files and largefiles (issue3084)
Martin Geisler <mg@aragost.com>
parents: 15579
diff changeset
465 # lfile is added to the repository again. This happens when a
9036c7d106bf largefiles: handle merges between normal files and largefiles (issue3084)
Martin Geisler <mg@aragost.com>
parents: 15579
diff changeset
466 # largefile is converted back to a normal file: the standin
9036c7d106bf largefiles: handle merges between normal files and largefiles (issue3084)
Martin Geisler <mg@aragost.com>
parents: 15579
diff changeset
467 # disappears, but a new (normal) file appears as the lfile.
9036c7d106bf largefiles: handle merges between normal files and largefiles (issue3084)
Martin Geisler <mg@aragost.com>
parents: 15579
diff changeset
468 if os.path.exists(abslfile) and lfile not in repo[None]:
15900
29defa7d20f6 largefiles: remove empty directories upon update (issue3202)
Patrick Mezard <pmezard@gmail.com>
parents: 15663
diff changeset
469 util.unlinkpath(abslfile)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
470 ret = -1
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
471 state = repo.dirstate[lfutil.standin(lfile)]
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
472 if state == 'n':
15793
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
473 # When rebasing, we need to synchronize the standin and the largefile,
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
474 # because otherwise the largefile will get reverted. But for commit's
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
475 # sake, we have to mark the file as unclean.
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
476 if getattr(repo, "_isrebasing", False):
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
477 lfdirstate.normallookup(lfile)
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
478 else:
3ef07ecdb0d5 largefiles: correctly handle dirstate status when rebasing
Na'Tosha Bard <natosha@unity3d.com>
parents: 15663
diff changeset
479 lfdirstate.normal(lfile)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
480 elif state == 'r':
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
481 lfdirstate.remove(lfile)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
482 elif state == 'a':
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
483 lfdirstate.add(lfile)
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
484 elif state == '?':
15224
7c604d8c7e83 largefiles: remove pre-1.9 code from extension first bundled with 1.9
Na'Tosha Bard <natosha@unity3d.com>
parents: 15173
diff changeset
485 lfdirstate.drop(lfile)
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
486 return ret
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
487
16439
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
488 def catlfile(repo, lfile, rev, filename):
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
489 hash = lfutil.readstandin(repo, lfile, rev)
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
490 if not lfutil.inusercache(repo.ui, hash):
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
491 store = basestore._openstore(repo)
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
492 success, missing = store.get([(lfile, hash)])
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
493 if len(success) != 1:
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
494 raise util.Abort(
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
495 _('largefile %s is not in cache and could not be downloaded')
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
496 % lfile)
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
497 path = lfutil.usercachepath(repo.ui, hash)
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
498 fpout = cmdutil.makefileobj(repo, filename)
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
499 fpin = open(path, "rb")
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
500 fpout.write(fpin.read())
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
501 fpout.close()
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
502 fpin.close()
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
503 return 0
290850e7aa43 largefiles: fix cat for largefiles (issue3352)
Na'Tosha Bard <natosha@unity3d.com>
parents: 16247
diff changeset
504
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
505 # -- hg commands declarations ------------------------------------------------
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
506
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
507 cmdtable = {
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
508 'lfconvert': (lfconvert,
15230
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
509 [('s', 'size', '',
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
510 _('minimum size (MB) for files to be converted '
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
511 'as largefiles'),
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
512 'SIZE'),
15332
0db47b8d025f largefiles: rename lfconvert --tonormal option to --to-normal
Greg Ward <greg@gerg.ca>
parents: 15317
diff changeset
513 ('', 'to-normal', False,
15230
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
514 _('convert from a largefiles repo to a normal repo')),
697289c5d415 largefiles: improve help
Greg Ward <greg@gerg.ca>
parents: 15228
diff changeset
515 ],
15168
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
516 _('hg lfconvert SOURCE DEST [FILE ...]')),
cfccd3bee7b3 hgext: add largefiles extension
various
parents:
diff changeset
517 }