##// END OF EJS Templates
archive: store number of changes since latest tag as well...
Siddharth Agarwal -
r23645:242d1181 default
parent child Browse files
Show More
@@ -1,313 +1,316 b''
1 1 # archival.py - revision archival for mercurial
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 from node import hex
10 10 import match as matchmod
11 11 import cmdutil
12 12 import scmutil, util, encoding
13 13 import cStringIO, os, tarfile, time, zipfile
14 14 import zlib, gzip
15 15 import struct
16 16 import error
17 17
18 18 # from unzip source code:
19 19 _UNX_IFREG = 0x8000
20 20 _UNX_IFLNK = 0xa000
21 21
22 22 def tidyprefix(dest, kind, prefix):
23 23 '''choose prefix to use for names in archive. make sure prefix is
24 24 safe for consumers.'''
25 25
26 26 if prefix:
27 27 prefix = util.normpath(prefix)
28 28 else:
29 29 if not isinstance(dest, str):
30 30 raise ValueError('dest must be string if no prefix')
31 31 prefix = os.path.basename(dest)
32 32 lower = prefix.lower()
33 33 for sfx in exts.get(kind, []):
34 34 if lower.endswith(sfx):
35 35 prefix = prefix[:-len(sfx)]
36 36 break
37 37 lpfx = os.path.normpath(util.localpath(prefix))
38 38 prefix = util.pconvert(lpfx)
39 39 if not prefix.endswith('/'):
40 40 prefix += '/'
41 41 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
42 42 raise util.Abort(_('archive prefix contains illegal components'))
43 43 return prefix
44 44
45 45 exts = {
46 46 'tar': ['.tar'],
47 47 'tbz2': ['.tbz2', '.tar.bz2'],
48 48 'tgz': ['.tgz', '.tar.gz'],
49 49 'zip': ['.zip'],
50 50 }
51 51
52 52 def guesskind(dest):
53 53 for kind, extensions in exts.iteritems():
54 54 if util.any(dest.endswith(ext) for ext in extensions):
55 55 return kind
56 56 return None
57 57
58 58
59 59 class tarit(object):
60 60 '''write archive to tar file or stream. can write uncompressed,
61 61 or compress with gzip or bzip2.'''
62 62
63 63 class GzipFileWithTime(gzip.GzipFile):
64 64
65 65 def __init__(self, *args, **kw):
66 66 timestamp = None
67 67 if 'timestamp' in kw:
68 68 timestamp = kw.pop('timestamp')
69 69 if timestamp is None:
70 70 self.timestamp = time.time()
71 71 else:
72 72 self.timestamp = timestamp
73 73 gzip.GzipFile.__init__(self, *args, **kw)
74 74
75 75 def _write_gzip_header(self):
76 76 self.fileobj.write('\037\213') # magic header
77 77 self.fileobj.write('\010') # compression method
78 78 # Python 2.6 introduced self.name and deprecated self.filename
79 79 try:
80 80 fname = self.name
81 81 except AttributeError:
82 82 fname = self.filename
83 83 if fname and fname.endswith('.gz'):
84 84 fname = fname[:-3]
85 85 flags = 0
86 86 if fname:
87 87 flags = gzip.FNAME
88 88 self.fileobj.write(chr(flags))
89 89 gzip.write32u(self.fileobj, long(self.timestamp))
90 90 self.fileobj.write('\002')
91 91 self.fileobj.write('\377')
92 92 if fname:
93 93 self.fileobj.write(fname + '\000')
94 94
95 95 def __init__(self, dest, mtime, kind=''):
96 96 self.mtime = mtime
97 97 self.fileobj = None
98 98
99 99 def taropen(name, mode, fileobj=None):
100 100 if kind == 'gz':
101 101 mode = mode[0]
102 102 if not fileobj:
103 103 fileobj = open(name, mode + 'b')
104 104 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
105 105 zlib.Z_BEST_COMPRESSION,
106 106 fileobj, timestamp=mtime)
107 107 self.fileobj = gzfileobj
108 108 return tarfile.TarFile.taropen(name, mode, gzfileobj)
109 109 else:
110 110 return tarfile.open(name, mode + kind, fileobj)
111 111
112 112 if isinstance(dest, str):
113 113 self.z = taropen(dest, mode='w:')
114 114 else:
115 115 # Python 2.5-2.5.1 have a regression that requires a name arg
116 116 self.z = taropen(name='', mode='w|', fileobj=dest)
117 117
118 118 def addfile(self, name, mode, islink, data):
119 119 i = tarfile.TarInfo(name)
120 120 i.mtime = self.mtime
121 121 i.size = len(data)
122 122 if islink:
123 123 i.type = tarfile.SYMTYPE
124 124 i.mode = 0777
125 125 i.linkname = data
126 126 data = None
127 127 i.size = 0
128 128 else:
129 129 i.mode = mode
130 130 data = cStringIO.StringIO(data)
131 131 self.z.addfile(i, data)
132 132
133 133 def done(self):
134 134 self.z.close()
135 135 if self.fileobj:
136 136 self.fileobj.close()
137 137
138 138 class tellable(object):
139 139 '''provide tell method for zipfile.ZipFile when writing to http
140 140 response file object.'''
141 141
142 142 def __init__(self, fp):
143 143 self.fp = fp
144 144 self.offset = 0
145 145
146 146 def __getattr__(self, key):
147 147 return getattr(self.fp, key)
148 148
149 149 def write(self, s):
150 150 self.fp.write(s)
151 151 self.offset += len(s)
152 152
153 153 def tell(self):
154 154 return self.offset
155 155
156 156 class zipit(object):
157 157 '''write archive to zip file or stream. can write uncompressed,
158 158 or compressed with deflate.'''
159 159
160 160 def __init__(self, dest, mtime, compress=True):
161 161 if not isinstance(dest, str):
162 162 try:
163 163 dest.tell()
164 164 except (AttributeError, IOError):
165 165 dest = tellable(dest)
166 166 self.z = zipfile.ZipFile(dest, 'w',
167 167 compress and zipfile.ZIP_DEFLATED or
168 168 zipfile.ZIP_STORED)
169 169
170 170 # Python's zipfile module emits deprecation warnings if we try
171 171 # to store files with a date before 1980.
172 172 epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0))
173 173 if mtime < epoch:
174 174 mtime = epoch
175 175
176 176 self.mtime = mtime
177 177 self.date_time = time.gmtime(mtime)[:6]
178 178
179 179 def addfile(self, name, mode, islink, data):
180 180 i = zipfile.ZipInfo(name, self.date_time)
181 181 i.compress_type = self.z.compression
182 182 # unzip will not honor unix file modes unless file creator is
183 183 # set to unix (id 3).
184 184 i.create_system = 3
185 185 ftype = _UNX_IFREG
186 186 if islink:
187 187 mode = 0777
188 188 ftype = _UNX_IFLNK
189 189 i.external_attr = (mode | ftype) << 16L
190 190 # add "extended-timestamp" extra block, because zip archives
191 191 # without this will be extracted with unexpected timestamp,
192 192 # if TZ is not configured as GMT
193 193 i.extra += struct.pack('<hhBl',
194 194 0x5455, # block type: "extended-timestamp"
195 195 1 + 4, # size of this block
196 196 1, # "modification time is present"
197 197 int(self.mtime)) # last modification (UTC)
198 198 self.z.writestr(i, data)
199 199
200 200 def done(self):
201 201 self.z.close()
202 202
203 203 class fileit(object):
204 204 '''write archive as files in directory.'''
205 205
206 206 def __init__(self, name, mtime):
207 207 self.basedir = name
208 208 self.opener = scmutil.opener(self.basedir)
209 209
210 210 def addfile(self, name, mode, islink, data):
211 211 if islink:
212 212 self.opener.symlink(data, name)
213 213 return
214 214 f = self.opener(name, "w", atomictemp=True)
215 215 f.write(data)
216 216 f.close()
217 217 destfile = os.path.join(self.basedir, name)
218 218 os.chmod(destfile, mode)
219 219
220 220 def done(self):
221 221 pass
222 222
223 223 archivers = {
224 224 'files': fileit,
225 225 'tar': tarit,
226 226 'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'),
227 227 'tgz': lambda name, mtime: tarit(name, mtime, 'gz'),
228 228 'uzip': lambda name, mtime: zipit(name, mtime, False),
229 229 'zip': zipit,
230 230 }
231 231
232 232 def archive(repo, dest, node, kind, decode=True, matchfn=None,
233 233 prefix=None, mtime=None, subrepos=False):
234 234 '''create archive of repo as it was at node.
235 235
236 236 dest can be name of directory, name of archive file, or file
237 237 object to write archive to.
238 238
239 239 kind is type of archive to create.
240 240
241 241 decode tells whether to put files through decode filters from
242 242 hgrc.
243 243
244 244 matchfn is function to filter names of files to write to archive.
245 245
246 246 prefix is name of path to put before every archive member.'''
247 247
248 248 if kind == 'files':
249 249 if prefix:
250 250 raise util.Abort(_('cannot give prefix when archiving to files'))
251 251 else:
252 252 prefix = tidyprefix(dest, kind, prefix)
253 253
254 254 def write(name, mode, islink, getdata):
255 255 data = getdata()
256 256 if decode:
257 257 data = repo.wwritedata(name, data)
258 258 archiver.addfile(prefix + name, mode, islink, data)
259 259
260 260 if kind not in archivers:
261 261 raise util.Abort(_("unknown archive type '%s'") % kind)
262 262
263 263 ctx = repo[node]
264 264 archiver = archivers[kind](dest, mtime or ctx.date()[0])
265 265
266 266 if repo.ui.configbool("ui", "archivemeta", True):
267 267 def metadata():
268 268 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
269 269 repo[0].hex(), hex(node), encoding.fromlocal(ctx.branch()))
270 270
271 271 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
272 272 if repo.tagtype(t) == 'global')
273 273 if not tags:
274 274 repo.ui.pushbuffer()
275 275 opts = {'template': '{latesttag}\n{latesttagdistance}',
276 276 'style': '', 'patch': None, 'git': None}
277 277 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
278 278 ltags, dist = repo.ui.popbuffer().split('\n')
279 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
279 ltags = ltags.split(':')
280 changessince = len(repo.revs('only(.,%s)', ltags[0]))
281 tags = ''.join('latesttag: %s\n' % t for t in ltags)
280 282 tags += 'latesttagdistance: %s\n' % dist
283 tags += 'changessincelatesttag: %s\n' % changessince
281 284
282 285 return base + tags
283 286
284 287 name = '.hg_archival.txt'
285 288 if not matchfn or matchfn(name):
286 289 write(name, 0644, False, metadata)
287 290
288 291 if matchfn:
289 292 files = [f for f in ctx.manifest().keys() if matchfn(f)]
290 293 else:
291 294 files = ctx.manifest().keys()
292 295 total = len(files)
293 296 if total:
294 297 files.sort()
295 298 repo.ui.progress(_('archiving'), 0, unit=_('files'), total=total)
296 299 for i, f in enumerate(files):
297 300 ff = ctx.flags(f)
298 301 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
299 302 repo.ui.progress(_('archiving'), i + 1, item=f,
300 303 unit=_('files'), total=total)
301 304 repo.ui.progress(_('archiving'), None)
302 305
303 306 if subrepos:
304 307 for subpath in sorted(ctx.substate):
305 308 sub = ctx.sub(subpath)
306 309 submatch = matchmod.narrowmatcher(subpath, matchfn)
307 310 total += sub.archive(archiver, prefix, submatch)
308 311
309 312 if total == 0:
310 313 raise error.Abort(_('no files match the archive pattern'))
311 314
312 315 archiver.done()
313 316 return total
@@ -1,368 +1,369 b''
1 1 #require serve
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo foo>foo
6 6 $ hg commit -Am 1 -d '1 0'
7 7 adding foo
8 8 $ echo bar>bar
9 9 $ hg commit -Am 2 -d '2 0'
10 10 adding bar
11 11 $ mkdir baz
12 12 $ echo bletch>baz/bletch
13 13 $ hg commit -Am 3 -d '1000000000 0'
14 14 adding baz/bletch
15 15 $ hg init subrepo
16 16 $ touch subrepo/sub
17 17 $ hg -q -R subrepo ci -Am "init subrepo"
18 18 $ echo "subrepo = subrepo" > .hgsub
19 19 $ hg add .hgsub
20 20 $ hg ci -m "add subrepo"
21 21 $ echo "[web]" >> .hg/hgrc
22 22 $ echo "name = test-archive" >> .hg/hgrc
23 23 $ echo "archivesubrepos = True" >> .hg/hgrc
24 24 $ cp .hg/hgrc .hg/hgrc-base
25 25 > test_archtype() {
26 26 > echo "allow_archive = $1" >> .hg/hgrc
27 27 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
28 28 > cat hg.pid >> $DAEMON_PIDS
29 29 > echo % $1 allowed should give 200
30 30 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$2" | head -n 1
31 31 > echo % $3 and $4 disallowed should both give 403
32 32 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$3" | head -n 1
33 33 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$4" | head -n 1
34 34 > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
35 35 > cat errors.log
36 36 > cp .hg/hgrc-base .hg/hgrc
37 37 > }
38 38
39 39 check http return codes
40 40
41 41 $ test_archtype gz tar.gz tar.bz2 zip
42 42 % gz allowed should give 200
43 43 200 Script output follows
44 44 % tar.bz2 and zip disallowed should both give 403
45 45 403 Archive type not allowed: bz2
46 46 403 Archive type not allowed: zip
47 47 $ test_archtype bz2 tar.bz2 zip tar.gz
48 48 % bz2 allowed should give 200
49 49 200 Script output follows
50 50 % zip and tar.gz disallowed should both give 403
51 51 403 Archive type not allowed: zip
52 52 403 Archive type not allowed: gz
53 53 $ test_archtype zip zip tar.gz tar.bz2
54 54 % zip allowed should give 200
55 55 200 Script output follows
56 56 % tar.gz and tar.bz2 disallowed should both give 403
57 57 403 Archive type not allowed: gz
58 58 403 Archive type not allowed: bz2
59 59
60 60 $ echo "allow_archive = gz bz2 zip" >> .hg/hgrc
61 61 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
62 62 $ cat hg.pid >> $DAEMON_PIDS
63 63
64 64 invalid arch type should give 404
65 65
66 66 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.invalid" | head -n 1
67 67 404 Unsupported archive type: None
68 68
69 69 $ TIP=`hg id -v | cut -f1 -d' '`
70 70 $ QTIP=`hg id -q`
71 71 $ cat > getarchive.py <<EOF
72 72 > import os, sys, urllib2
73 73 > try:
74 74 > # Set stdout to binary mode for win32 platforms
75 75 > import msvcrt
76 76 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
77 77 > except ImportError:
78 78 > pass
79 79 > if len(sys.argv) <= 3:
80 80 > node, archive = sys.argv[1:]
81 81 > requeststr = 'cmd=archive;node=%s;type=%s' % (node, archive)
82 82 > else:
83 83 > node, archive, file = sys.argv[1:]
84 84 > requeststr = 'cmd=archive;node=%s;type=%s;file=%s' % (node, archive, file)
85 85 > try:
86 86 > f = urllib2.urlopen('http://127.0.0.1:%s/?%s'
87 87 > % (os.environ['HGPORT'], requeststr))
88 88 > sys.stdout.write(f.read())
89 89 > except urllib2.HTTPError, e:
90 90 > sys.stderr.write(str(e) + '\n')
91 91 > EOF
92 92 $ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
93 93 test-archive-1701ef1f1510/.hg_archival.txt
94 94 test-archive-1701ef1f1510/.hgsub
95 95 test-archive-1701ef1f1510/.hgsubstate
96 96 test-archive-1701ef1f1510/bar
97 97 test-archive-1701ef1f1510/baz/bletch
98 98 test-archive-1701ef1f1510/foo
99 99 test-archive-1701ef1f1510/subrepo/sub
100 100 $ python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
101 101 test-archive-1701ef1f1510/.hg_archival.txt
102 102 test-archive-1701ef1f1510/.hgsub
103 103 test-archive-1701ef1f1510/.hgsubstate
104 104 test-archive-1701ef1f1510/bar
105 105 test-archive-1701ef1f1510/baz/bletch
106 106 test-archive-1701ef1f1510/foo
107 107 test-archive-1701ef1f1510/subrepo/sub
108 108 $ python getarchive.py "$TIP" zip > archive.zip
109 109 $ unzip -t archive.zip
110 110 Archive: archive.zip
111 111 testing: test-archive-1701ef1f1510/.hg_archival.txt OK
112 112 testing: test-archive-1701ef1f1510/.hgsub OK
113 113 testing: test-archive-1701ef1f1510/.hgsubstate OK
114 114 testing: test-archive-1701ef1f1510/bar OK
115 115 testing: test-archive-1701ef1f1510/baz/bletch OK
116 116 testing: test-archive-1701ef1f1510/foo OK
117 117 testing: test-archive-1701ef1f1510/subrepo/sub OK
118 118 No errors detected in compressed data of archive.zip.
119 119
120 120 test that we can download single directories and files
121 121
122 122 $ python getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null
123 123 test-archive-1701ef1f1510/baz/bletch
124 124 $ python getarchive.py "$TIP" gz foo | gunzip | tar tf - 2>/dev/null
125 125 test-archive-1701ef1f1510/foo
126 126
127 127 test that we detect file patterns that match no files
128 128
129 129 $ python getarchive.py "$TIP" gz foobar
130 130 HTTP Error 404: file(s) not found: foobar
131 131
132 132 test that we reject unsafe patterns
133 133
134 134 $ python getarchive.py "$TIP" gz relre:baz
135 135 HTTP Error 404: file(s) not found: relre:baz
136 136
137 137 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
138 138
139 139 $ hg archive -t tar test.tar
140 140 $ tar tf test.tar
141 141 test/.hg_archival.txt
142 142 test/.hgsub
143 143 test/.hgsubstate
144 144 test/bar
145 145 test/baz/bletch
146 146 test/foo
147 147
148 148 $ hg archive --debug -t tbz2 -X baz test.tar.bz2
149 149 archiving: 0/4 files (0.00%)
150 150 archiving: .hgsub 1/4 files (25.00%)
151 151 archiving: .hgsubstate 2/4 files (50.00%)
152 152 archiving: bar 3/4 files (75.00%)
153 153 archiving: foo 4/4 files (100.00%)
154 154 $ bunzip2 -dc test.tar.bz2 | tar tf - 2>/dev/null
155 155 test/.hg_archival.txt
156 156 test/.hgsub
157 157 test/.hgsubstate
158 158 test/bar
159 159 test/foo
160 160
161 161 $ hg archive -t tgz -p %b-%h test-%h.tar.gz
162 162 $ gzip -dc test-$QTIP.tar.gz | tar tf - 2>/dev/null
163 163 test-1701ef1f1510/.hg_archival.txt
164 164 test-1701ef1f1510/.hgsub
165 165 test-1701ef1f1510/.hgsubstate
166 166 test-1701ef1f1510/bar
167 167 test-1701ef1f1510/baz/bletch
168 168 test-1701ef1f1510/foo
169 169
170 170 $ hg archive autodetected_test.tar
171 171 $ tar tf autodetected_test.tar
172 172 autodetected_test/.hg_archival.txt
173 173 autodetected_test/.hgsub
174 174 autodetected_test/.hgsubstate
175 175 autodetected_test/bar
176 176 autodetected_test/baz/bletch
177 177 autodetected_test/foo
178 178
179 179 The '-t' should override autodetection
180 180
181 181 $ hg archive -t tar autodetect_override_test.zip
182 182 $ tar tf autodetect_override_test.zip
183 183 autodetect_override_test.zip/.hg_archival.txt
184 184 autodetect_override_test.zip/.hgsub
185 185 autodetect_override_test.zip/.hgsubstate
186 186 autodetect_override_test.zip/bar
187 187 autodetect_override_test.zip/baz/bletch
188 188 autodetect_override_test.zip/foo
189 189
190 190 $ for ext in tar tar.gz tgz tar.bz2 tbz2 zip; do
191 191 > hg archive auto_test.$ext
192 192 > if [ -d auto_test.$ext ]; then
193 193 > echo "extension $ext was not autodetected."
194 194 > fi
195 195 > done
196 196
197 197 $ cat > md5comp.py <<EOF
198 198 > try:
199 199 > from hashlib import md5
200 200 > except ImportError:
201 201 > from md5 import md5
202 202 > import sys
203 203 > f1, f2 = sys.argv[1:3]
204 204 > h1 = md5(file(f1, 'rb').read()).hexdigest()
205 205 > h2 = md5(file(f2, 'rb').read()).hexdigest()
206 206 > print h1 == h2 or "md5 differ: " + repr((h1, h2))
207 207 > EOF
208 208
209 209 archive name is stored in the archive, so create similar archives and
210 210 rename them afterwards.
211 211
212 212 $ hg archive -t tgz tip.tar.gz
213 213 $ mv tip.tar.gz tip1.tar.gz
214 214 $ sleep 1
215 215 $ hg archive -t tgz tip.tar.gz
216 216 $ mv tip.tar.gz tip2.tar.gz
217 217 $ python md5comp.py tip1.tar.gz tip2.tar.gz
218 218 True
219 219
220 220 $ hg archive -t zip -p /illegal test.zip
221 221 abort: archive prefix contains illegal components
222 222 [255]
223 223 $ hg archive -t zip -p very/../bad test.zip
224 224
225 225 $ hg archive --config ui.archivemeta=false -t zip -r 2 test.zip
226 226 $ unzip -t test.zip
227 227 Archive: test.zip
228 228 testing: test/bar OK
229 229 testing: test/baz/bletch OK
230 230 testing: test/foo OK
231 231 No errors detected in compressed data of test.zip.
232 232
233 233 $ hg archive -t tar - | tar tf - 2>/dev/null
234 234 test-1701ef1f1510/.hg_archival.txt
235 235 test-1701ef1f1510/.hgsub
236 236 test-1701ef1f1510/.hgsubstate
237 237 test-1701ef1f1510/bar
238 238 test-1701ef1f1510/baz/bletch
239 239 test-1701ef1f1510/foo
240 240
241 241 $ hg archive -r 0 -t tar rev-%r.tar
242 242 $ [ -f rev-0.tar ]
243 243
244 244 test .hg_archival.txt
245 245
246 246 $ hg archive ../test-tags
247 247 $ cat ../test-tags/.hg_archival.txt
248 248 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
249 249 node: 1701ef1f151069b8747038e93b5186bb43a47504
250 250 branch: default
251 251 latesttag: null
252 252 latesttagdistance: 4
253 changessincelatesttag: 4
253 254 $ hg tag -r 2 mytag
254 255 $ hg tag -r 2 anothertag
255 256 $ hg archive -r 2 ../test-lasttag
256 257 $ cat ../test-lasttag/.hg_archival.txt
257 258 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
258 259 node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
259 260 branch: default
260 261 tag: anothertag
261 262 tag: mytag
262 263
263 264 $ hg archive -t bogus test.bogus
264 265 abort: unknown archive type 'bogus'
265 266 [255]
266 267
267 268 enable progress extension:
268 269
269 270 $ cp $HGRCPATH $HGRCPATH.no-progress
270 271 $ cat >> $HGRCPATH <<EOF
271 272 > [extensions]
272 273 > progress =
273 274 > [progress]
274 275 > assume-tty = 1
275 276 > format = topic bar number
276 277 > delay = 0
277 278 > refresh = 0
278 279 > width = 60
279 280 > EOF
280 281
281 282 $ hg archive ../with-progress
282 283 \r (no-eol) (esc)
283 284 archiving [ ] 0/6\r (no-eol) (esc)
284 285 archiving [ ] 0/6\r (no-eol) (esc)
285 286 archiving [======> ] 1/6\r (no-eol) (esc)
286 287 archiving [======> ] 1/6\r (no-eol) (esc)
287 288 archiving [=============> ] 2/6\r (no-eol) (esc)
288 289 archiving [=============> ] 2/6\r (no-eol) (esc)
289 290 archiving [====================> ] 3/6\r (no-eol) (esc)
290 291 archiving [====================> ] 3/6\r (no-eol) (esc)
291 292 archiving [===========================> ] 4/6\r (no-eol) (esc)
292 293 archiving [===========================> ] 4/6\r (no-eol) (esc)
293 294 archiving [==================================> ] 5/6\r (no-eol) (esc)
294 295 archiving [==================================> ] 5/6\r (no-eol) (esc)
295 296 archiving [==========================================>] 6/6\r (no-eol) (esc)
296 297 archiving [==========================================>] 6/6\r (no-eol) (esc)
297 298 \r (no-eol) (esc)
298 299
299 300 cleanup after progress extension test:
300 301
301 302 $ cp $HGRCPATH.no-progress $HGRCPATH
302 303
303 304 server errors
304 305
305 306 $ cat errors.log
306 307
307 308 empty repo
308 309
309 310 $ hg init ../empty
310 311 $ cd ../empty
311 312 $ hg archive ../test-empty
312 313 abort: no working directory: please specify a revision
313 314 [255]
314 315
315 316 old file -- date clamped to 1980
316 317
317 318 $ touch -t 197501010000 old
318 319 $ hg add old
319 320 $ hg commit -m old
320 321 $ hg archive ../old.zip
321 322 $ unzip -l ../old.zip
322 323 Archive: ../old.zip
323 324 \s*Length.* (re)
324 325 *-----* (glob)
325 *147*80*00:00*old/.hg_archival.txt (glob)
326 *172*80*00:00*old/.hg_archival.txt (glob)
326 327 *0*80*00:00*old/old (glob)
327 328 *-----* (glob)
328 \s*147\s+2 files (re)
329 \s*172\s+2 files (re)
329 330
330 331 show an error when a provided pattern matches no files
331 332
332 333 $ hg archive -I file_that_does_not_exist.foo ../empty.zip
333 334 abort: no files match the archive pattern
334 335 [255]
335 336
336 337 $ hg archive -X * ../empty.zip
337 338 abort: no files match the archive pattern
338 339 [255]
339 340
340 341 $ cd ..
341 342
342 343 issue3600: check whether "hg archive" can create archive files which
343 344 are extracted with expected timestamp, even though TZ is not
344 345 configured as GMT.
345 346
346 347 $ mkdir issue3600
347 348 $ cd issue3600
348 349
349 350 $ hg init repo
350 351 $ echo a > repo/a
351 352 $ hg -R repo add repo/a
352 353 $ hg -R repo commit -m '#0' -d '456789012 21600'
353 354 $ cat > show_mtime.py <<EOF
354 355 > import sys, os
355 356 > print int(os.stat(sys.argv[1]).st_mtime)
356 357 > EOF
357 358
358 359 $ hg -R repo archive --prefix tar-extracted archive.tar
359 360 $ (TZ=UTC-3; export TZ; tar xf archive.tar)
360 361 $ python show_mtime.py tar-extracted/a
361 362 456789012
362 363
363 364 $ hg -R repo archive --prefix zip-extracted archive.zip
364 365 $ (TZ=UTC-3; export TZ; unzip -q archive.zip)
365 366 $ python show_mtime.py zip-extracted/a
366 367 456789012
367 368
368 369 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now