##// END OF EJS Templates
archive: add support for progress extension
Martin Geisler -
r13143:c2e55c21 default
parent child Browse files
Show More
@@ -1,274 +1,279 b''
1 # archival.py - revision archival for mercurial
1 # archival.py - revision archival for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 from node import hex
9 from node import hex
10 import cmdutil
10 import cmdutil
11 import util, encoding
11 import util, encoding
12 import cStringIO, os, stat, tarfile, time, zipfile
12 import cStringIO, os, stat, tarfile, time, zipfile
13 import zlib, gzip
13 import zlib, gzip
14
14
15 def tidyprefix(dest, kind, prefix):
15 def tidyprefix(dest, kind, prefix):
16 '''choose prefix to use for names in archive. make sure prefix is
16 '''choose prefix to use for names in archive. make sure prefix is
17 safe for consumers.'''
17 safe for consumers.'''
18
18
19 if prefix:
19 if prefix:
20 prefix = util.normpath(prefix)
20 prefix = util.normpath(prefix)
21 else:
21 else:
22 if not isinstance(dest, str):
22 if not isinstance(dest, str):
23 raise ValueError('dest must be string if no prefix')
23 raise ValueError('dest must be string if no prefix')
24 prefix = os.path.basename(dest)
24 prefix = os.path.basename(dest)
25 lower = prefix.lower()
25 lower = prefix.lower()
26 for sfx in exts.get(kind, []):
26 for sfx in exts.get(kind, []):
27 if lower.endswith(sfx):
27 if lower.endswith(sfx):
28 prefix = prefix[:-len(sfx)]
28 prefix = prefix[:-len(sfx)]
29 break
29 break
30 lpfx = os.path.normpath(util.localpath(prefix))
30 lpfx = os.path.normpath(util.localpath(prefix))
31 prefix = util.pconvert(lpfx)
31 prefix = util.pconvert(lpfx)
32 if not prefix.endswith('/'):
32 if not prefix.endswith('/'):
33 prefix += '/'
33 prefix += '/'
34 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
34 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
35 raise util.Abort(_('archive prefix contains illegal components'))
35 raise util.Abort(_('archive prefix contains illegal components'))
36 return prefix
36 return prefix
37
37
38 exts = {
38 exts = {
39 'tar': ['.tar'],
39 'tar': ['.tar'],
40 'tbz2': ['.tbz2', '.tar.bz2'],
40 'tbz2': ['.tbz2', '.tar.bz2'],
41 'tgz': ['.tgz', '.tar.gz'],
41 'tgz': ['.tgz', '.tar.gz'],
42 'zip': ['.zip'],
42 'zip': ['.zip'],
43 }
43 }
44
44
45 def guesskind(dest):
45 def guesskind(dest):
46 for kind, extensions in exts.iteritems():
46 for kind, extensions in exts.iteritems():
47 if util.any(dest.endswith(ext) for ext in extensions):
47 if util.any(dest.endswith(ext) for ext in extensions):
48 return kind
48 return kind
49 return None
49 return None
50
50
51
51
52 class tarit(object):
52 class tarit(object):
53 '''write archive to tar file or stream. can write uncompressed,
53 '''write archive to tar file or stream. can write uncompressed,
54 or compress with gzip or bzip2.'''
54 or compress with gzip or bzip2.'''
55
55
56 class GzipFileWithTime(gzip.GzipFile):
56 class GzipFileWithTime(gzip.GzipFile):
57
57
58 def __init__(self, *args, **kw):
58 def __init__(self, *args, **kw):
59 timestamp = None
59 timestamp = None
60 if 'timestamp' in kw:
60 if 'timestamp' in kw:
61 timestamp = kw.pop('timestamp')
61 timestamp = kw.pop('timestamp')
62 if timestamp is None:
62 if timestamp is None:
63 self.timestamp = time.time()
63 self.timestamp = time.time()
64 else:
64 else:
65 self.timestamp = timestamp
65 self.timestamp = timestamp
66 gzip.GzipFile.__init__(self, *args, **kw)
66 gzip.GzipFile.__init__(self, *args, **kw)
67
67
68 def _write_gzip_header(self):
68 def _write_gzip_header(self):
69 self.fileobj.write('\037\213') # magic header
69 self.fileobj.write('\037\213') # magic header
70 self.fileobj.write('\010') # compression method
70 self.fileobj.write('\010') # compression method
71 # Python 2.6 deprecates self.filename
71 # Python 2.6 deprecates self.filename
72 fname = getattr(self, 'name', None) or self.filename
72 fname = getattr(self, 'name', None) or self.filename
73 if fname and fname.endswith('.gz'):
73 if fname and fname.endswith('.gz'):
74 fname = fname[:-3]
74 fname = fname[:-3]
75 flags = 0
75 flags = 0
76 if fname:
76 if fname:
77 flags = gzip.FNAME
77 flags = gzip.FNAME
78 self.fileobj.write(chr(flags))
78 self.fileobj.write(chr(flags))
79 gzip.write32u(self.fileobj, long(self.timestamp))
79 gzip.write32u(self.fileobj, long(self.timestamp))
80 self.fileobj.write('\002')
80 self.fileobj.write('\002')
81 self.fileobj.write('\377')
81 self.fileobj.write('\377')
82 if fname:
82 if fname:
83 self.fileobj.write(fname + '\000')
83 self.fileobj.write(fname + '\000')
84
84
85 def __init__(self, dest, mtime, kind=''):
85 def __init__(self, dest, mtime, kind=''):
86 self.mtime = mtime
86 self.mtime = mtime
87
87
88 def taropen(name, mode, fileobj=None):
88 def taropen(name, mode, fileobj=None):
89 if kind == 'gz':
89 if kind == 'gz':
90 mode = mode[0]
90 mode = mode[0]
91 if not fileobj:
91 if not fileobj:
92 fileobj = open(name, mode + 'b')
92 fileobj = open(name, mode + 'b')
93 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
93 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
94 zlib.Z_BEST_COMPRESSION,
94 zlib.Z_BEST_COMPRESSION,
95 fileobj, timestamp=mtime)
95 fileobj, timestamp=mtime)
96 return tarfile.TarFile.taropen(name, mode, gzfileobj)
96 return tarfile.TarFile.taropen(name, mode, gzfileobj)
97 else:
97 else:
98 return tarfile.open(name, mode + kind, fileobj)
98 return tarfile.open(name, mode + kind, fileobj)
99
99
100 if isinstance(dest, str):
100 if isinstance(dest, str):
101 self.z = taropen(dest, mode='w:')
101 self.z = taropen(dest, mode='w:')
102 else:
102 else:
103 # Python 2.5-2.5.1 have a regression that requires a name arg
103 # Python 2.5-2.5.1 have a regression that requires a name arg
104 self.z = taropen(name='', mode='w|', fileobj=dest)
104 self.z = taropen(name='', mode='w|', fileobj=dest)
105
105
106 def addfile(self, name, mode, islink, data):
106 def addfile(self, name, mode, islink, data):
107 i = tarfile.TarInfo(name)
107 i = tarfile.TarInfo(name)
108 i.mtime = self.mtime
108 i.mtime = self.mtime
109 i.size = len(data)
109 i.size = len(data)
110 if islink:
110 if islink:
111 i.type = tarfile.SYMTYPE
111 i.type = tarfile.SYMTYPE
112 i.mode = 0777
112 i.mode = 0777
113 i.linkname = data
113 i.linkname = data
114 data = None
114 data = None
115 i.size = 0
115 i.size = 0
116 else:
116 else:
117 i.mode = mode
117 i.mode = mode
118 data = cStringIO.StringIO(data)
118 data = cStringIO.StringIO(data)
119 self.z.addfile(i, data)
119 self.z.addfile(i, data)
120
120
121 def done(self):
121 def done(self):
122 self.z.close()
122 self.z.close()
123
123
124 class tellable(object):
124 class tellable(object):
125 '''provide tell method for zipfile.ZipFile when writing to http
125 '''provide tell method for zipfile.ZipFile when writing to http
126 response file object.'''
126 response file object.'''
127
127
128 def __init__(self, fp):
128 def __init__(self, fp):
129 self.fp = fp
129 self.fp = fp
130 self.offset = 0
130 self.offset = 0
131
131
132 def __getattr__(self, key):
132 def __getattr__(self, key):
133 return getattr(self.fp, key)
133 return getattr(self.fp, key)
134
134
135 def write(self, s):
135 def write(self, s):
136 self.fp.write(s)
136 self.fp.write(s)
137 self.offset += len(s)
137 self.offset += len(s)
138
138
139 def tell(self):
139 def tell(self):
140 return self.offset
140 return self.offset
141
141
142 class zipit(object):
142 class zipit(object):
143 '''write archive to zip file or stream. can write uncompressed,
143 '''write archive to zip file or stream. can write uncompressed,
144 or compressed with deflate.'''
144 or compressed with deflate.'''
145
145
146 def __init__(self, dest, mtime, compress=True):
146 def __init__(self, dest, mtime, compress=True):
147 if not isinstance(dest, str):
147 if not isinstance(dest, str):
148 try:
148 try:
149 dest.tell()
149 dest.tell()
150 except (AttributeError, IOError):
150 except (AttributeError, IOError):
151 dest = tellable(dest)
151 dest = tellable(dest)
152 self.z = zipfile.ZipFile(dest, 'w',
152 self.z = zipfile.ZipFile(dest, 'w',
153 compress and zipfile.ZIP_DEFLATED or
153 compress and zipfile.ZIP_DEFLATED or
154 zipfile.ZIP_STORED)
154 zipfile.ZIP_STORED)
155
155
156 # Python's zipfile module emits deprecation warnings if we try
156 # Python's zipfile module emits deprecation warnings if we try
157 # to store files with a date before 1980.
157 # to store files with a date before 1980.
158 epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0))
158 epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0))
159 if mtime < epoch:
159 if mtime < epoch:
160 mtime = epoch
160 mtime = epoch
161
161
162 self.date_time = time.gmtime(mtime)[:6]
162 self.date_time = time.gmtime(mtime)[:6]
163
163
164 def addfile(self, name, mode, islink, data):
164 def addfile(self, name, mode, islink, data):
165 i = zipfile.ZipInfo(name, self.date_time)
165 i = zipfile.ZipInfo(name, self.date_time)
166 i.compress_type = self.z.compression
166 i.compress_type = self.z.compression
167 # unzip will not honor unix file modes unless file creator is
167 # unzip will not honor unix file modes unless file creator is
168 # set to unix (id 3).
168 # set to unix (id 3).
169 i.create_system = 3
169 i.create_system = 3
170 ftype = stat.S_IFREG
170 ftype = stat.S_IFREG
171 if islink:
171 if islink:
172 mode = 0777
172 mode = 0777
173 ftype = stat.S_IFLNK
173 ftype = stat.S_IFLNK
174 i.external_attr = (mode | ftype) << 16L
174 i.external_attr = (mode | ftype) << 16L
175 self.z.writestr(i, data)
175 self.z.writestr(i, data)
176
176
177 def done(self):
177 def done(self):
178 self.z.close()
178 self.z.close()
179
179
180 class fileit(object):
180 class fileit(object):
181 '''write archive as files in directory.'''
181 '''write archive as files in directory.'''
182
182
183 def __init__(self, name, mtime):
183 def __init__(self, name, mtime):
184 self.basedir = name
184 self.basedir = name
185 self.opener = util.opener(self.basedir)
185 self.opener = util.opener(self.basedir)
186
186
187 def addfile(self, name, mode, islink, data):
187 def addfile(self, name, mode, islink, data):
188 if islink:
188 if islink:
189 self.opener.symlink(data, name)
189 self.opener.symlink(data, name)
190 return
190 return
191 f = self.opener(name, "w", atomictemp=True)
191 f = self.opener(name, "w", atomictemp=True)
192 f.write(data)
192 f.write(data)
193 f.rename()
193 f.rename()
194 destfile = os.path.join(self.basedir, name)
194 destfile = os.path.join(self.basedir, name)
195 os.chmod(destfile, mode)
195 os.chmod(destfile, mode)
196
196
197 def done(self):
197 def done(self):
198 pass
198 pass
199
199
200 archivers = {
200 archivers = {
201 'files': fileit,
201 'files': fileit,
202 'tar': tarit,
202 'tar': tarit,
203 'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'),
203 'tbz2': lambda name, mtime: tarit(name, mtime, 'bz2'),
204 'tgz': lambda name, mtime: tarit(name, mtime, 'gz'),
204 'tgz': lambda name, mtime: tarit(name, mtime, 'gz'),
205 'uzip': lambda name, mtime: zipit(name, mtime, False),
205 'uzip': lambda name, mtime: zipit(name, mtime, False),
206 'zip': zipit,
206 'zip': zipit,
207 }
207 }
208
208
209 def archive(repo, dest, node, kind, decode=True, matchfn=None,
209 def archive(repo, dest, node, kind, decode=True, matchfn=None,
210 prefix=None, mtime=None, subrepos=False):
210 prefix=None, mtime=None, subrepos=False):
211 '''create archive of repo as it was at node.
211 '''create archive of repo as it was at node.
212
212
213 dest can be name of directory, name of archive file, or file
213 dest can be name of directory, name of archive file, or file
214 object to write archive to.
214 object to write archive to.
215
215
216 kind is type of archive to create.
216 kind is type of archive to create.
217
217
218 decode tells whether to put files through decode filters from
218 decode tells whether to put files through decode filters from
219 hgrc.
219 hgrc.
220
220
221 matchfn is function to filter names of files to write to archive.
221 matchfn is function to filter names of files to write to archive.
222
222
223 prefix is name of path to put before every archive member.'''
223 prefix is name of path to put before every archive member.'''
224
224
225 if kind == 'files':
225 if kind == 'files':
226 if prefix:
226 if prefix:
227 raise util.Abort(_('cannot give prefix when archiving to files'))
227 raise util.Abort(_('cannot give prefix when archiving to files'))
228 else:
228 else:
229 prefix = tidyprefix(dest, kind, prefix)
229 prefix = tidyprefix(dest, kind, prefix)
230
230
231 def write(name, mode, islink, getdata):
231 def write(name, mode, islink, getdata):
232 if matchfn and not matchfn(name):
232 if matchfn and not matchfn(name):
233 return
233 return
234 data = getdata()
234 data = getdata()
235 if decode:
235 if decode:
236 data = repo.wwritedata(name, data)
236 data = repo.wwritedata(name, data)
237 archiver.addfile(prefix + name, mode, islink, data)
237 archiver.addfile(prefix + name, mode, islink, data)
238
238
239 if kind not in archivers:
239 if kind not in archivers:
240 raise util.Abort(_("unknown archive type '%s'") % kind)
240 raise util.Abort(_("unknown archive type '%s'") % kind)
241
241
242 ctx = repo[node]
242 ctx = repo[node]
243 archiver = archivers[kind](dest, mtime or ctx.date()[0])
243 archiver = archivers[kind](dest, mtime or ctx.date()[0])
244
244
245 if repo.ui.configbool("ui", "archivemeta", True):
245 if repo.ui.configbool("ui", "archivemeta", True):
246 def metadata():
246 def metadata():
247 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
247 base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
248 repo[0].hex(), hex(node), encoding.fromlocal(ctx.branch()))
248 repo[0].hex(), hex(node), encoding.fromlocal(ctx.branch()))
249
249
250 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
250 tags = ''.join('tag: %s\n' % t for t in ctx.tags()
251 if repo.tagtype(t) == 'global')
251 if repo.tagtype(t) == 'global')
252 if not tags:
252 if not tags:
253 repo.ui.pushbuffer()
253 repo.ui.pushbuffer()
254 opts = {'template': '{latesttag}\n{latesttagdistance}',
254 opts = {'template': '{latesttag}\n{latesttagdistance}',
255 'style': '', 'patch': None, 'git': None}
255 'style': '', 'patch': None, 'git': None}
256 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
256 cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
257 ltags, dist = repo.ui.popbuffer().split('\n')
257 ltags, dist = repo.ui.popbuffer().split('\n')
258 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
258 tags = ''.join('latesttag: %s\n' % t for t in ltags.split(':'))
259 tags += 'latesttagdistance: %s\n' % dist
259 tags += 'latesttagdistance: %s\n' % dist
260
260
261 return base + tags
261 return base + tags
262
262
263 write('.hg_archival.txt', 0644, False, metadata)
263 write('.hg_archival.txt', 0644, False, metadata)
264
264
265 for f in ctx:
265 total = len(ctx.manifest())
266 repo.ui.progress(_('archiving'), 0, unit=_('files'), total=total)
267 for i, f in enumerate(ctx):
266 ff = ctx.flags(f)
268 ff = ctx.flags(f)
267 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
269 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
270 repo.ui.progress(_('archiving'), i + 1, item=f,
271 unit=_('files'), total=total)
272 repo.ui.progress(_('archiving'), None)
268
273
269 if subrepos:
274 if subrepos:
270 for subpath in ctx.substate:
275 for subpath in ctx.substate:
271 sub = ctx.sub(subpath)
276 sub = ctx.sub(subpath)
272 sub.archive(archiver, prefix)
277 sub.archive(archiver, prefix)
273
278
274 archiver.done()
279 archiver.done()
@@ -1,234 +1,265 b''
1 $ mkdir test
1 $ mkdir test
2 $ cd test
2 $ cd test
3 $ hg init
3 $ hg init
4 $ echo foo>foo
4 $ echo foo>foo
5 $ hg commit -Am 1 -d '1 0'
5 $ hg commit -Am 1 -d '1 0'
6 adding foo
6 adding foo
7 $ echo bar>bar
7 $ echo bar>bar
8 $ hg commit -Am 2 -d '2 0'
8 $ hg commit -Am 2 -d '2 0'
9 adding bar
9 adding bar
10 $ mkdir baz
10 $ mkdir baz
11 $ echo bletch>baz/bletch
11 $ echo bletch>baz/bletch
12 $ hg commit -Am 3 -d '1000000000 0'
12 $ hg commit -Am 3 -d '1000000000 0'
13 adding baz/bletch
13 adding baz/bletch
14 $ echo "[web]" >> .hg/hgrc
14 $ echo "[web]" >> .hg/hgrc
15 $ echo "name = test-archive" >> .hg/hgrc
15 $ echo "name = test-archive" >> .hg/hgrc
16 $ cp .hg/hgrc .hg/hgrc-base
16 $ cp .hg/hgrc .hg/hgrc-base
17 > test_archtype() {
17 > test_archtype() {
18 > echo "allow_archive = $1" >> .hg/hgrc
18 > echo "allow_archive = $1" >> .hg/hgrc
19 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
19 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
20 > cat hg.pid >> $DAEMON_PIDS
20 > cat hg.pid >> $DAEMON_PIDS
21 > echo % $1 allowed should give 200
21 > echo % $1 allowed should give 200
22 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$2" | head -n 1
22 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$2" | head -n 1
23 > echo % $3 and $4 disallowed should both give 403
23 > echo % $3 and $4 disallowed should both give 403
24 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$3" | head -n 1
24 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$3" | head -n 1
25 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$4" | head -n 1
25 > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.$4" | head -n 1
26 > "$TESTDIR/killdaemons.py"
26 > "$TESTDIR/killdaemons.py"
27 > cat errors.log
27 > cat errors.log
28 > cp .hg/hgrc-base .hg/hgrc
28 > cp .hg/hgrc-base .hg/hgrc
29 > }
29 > }
30
30
31 check http return codes
31 check http return codes
32
32
33 $ test_archtype gz tar.gz tar.bz2 zip
33 $ test_archtype gz tar.gz tar.bz2 zip
34 % gz allowed should give 200
34 % gz allowed should give 200
35 200 Script output follows
35 200 Script output follows
36 % tar.bz2 and zip disallowed should both give 403
36 % tar.bz2 and zip disallowed should both give 403
37 403 Archive type not allowed: bz2
37 403 Archive type not allowed: bz2
38 403 Archive type not allowed: zip
38 403 Archive type not allowed: zip
39 $ test_archtype bz2 tar.bz2 zip tar.gz
39 $ test_archtype bz2 tar.bz2 zip tar.gz
40 % bz2 allowed should give 200
40 % bz2 allowed should give 200
41 200 Script output follows
41 200 Script output follows
42 % zip and tar.gz disallowed should both give 403
42 % zip and tar.gz disallowed should both give 403
43 403 Archive type not allowed: zip
43 403 Archive type not allowed: zip
44 403 Archive type not allowed: gz
44 403 Archive type not allowed: gz
45 $ test_archtype zip zip tar.gz tar.bz2
45 $ test_archtype zip zip tar.gz tar.bz2
46 % zip allowed should give 200
46 % zip allowed should give 200
47 200 Script output follows
47 200 Script output follows
48 % tar.gz and tar.bz2 disallowed should both give 403
48 % tar.gz and tar.bz2 disallowed should both give 403
49 403 Archive type not allowed: gz
49 403 Archive type not allowed: gz
50 403 Archive type not allowed: bz2
50 403 Archive type not allowed: bz2
51
51
52 $ echo "allow_archive = gz bz2 zip" >> .hg/hgrc
52 $ echo "allow_archive = gz bz2 zip" >> .hg/hgrc
53 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
53 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
54 $ cat hg.pid >> $DAEMON_PIDS
54 $ cat hg.pid >> $DAEMON_PIDS
55
55
56 invalid arch type should give 404
56 invalid arch type should give 404
57
57
58 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.invalid" | head -n 1
58 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "/archive/tip.invalid" | head -n 1
59 404 Unsupported archive type: None
59 404 Unsupported archive type: None
60
60
61 $ TIP=`hg id -v | cut -f1 -d' '`
61 $ TIP=`hg id -v | cut -f1 -d' '`
62 $ QTIP=`hg id -q`
62 $ QTIP=`hg id -q`
63 $ cat > getarchive.py <<EOF
63 $ cat > getarchive.py <<EOF
64 > import os, sys, urllib2
64 > import os, sys, urllib2
65 > try:
65 > try:
66 > # Set stdout to binary mode for win32 platforms
66 > # Set stdout to binary mode for win32 platforms
67 > import msvcrt
67 > import msvcrt
68 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
68 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
69 > except ImportError:
69 > except ImportError:
70 > pass
70 > pass
71 > node, archive = sys.argv[1:]
71 > node, archive = sys.argv[1:]
72 > f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
72 > f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
73 > % (os.environ['HGPORT'], node, archive))
73 > % (os.environ['HGPORT'], node, archive))
74 > sys.stdout.write(f.read())
74 > sys.stdout.write(f.read())
75 > EOF
75 > EOF
76 $ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
76 $ python getarchive.py "$TIP" gz | gunzip | tar tf - 2>/dev/null
77 test-archive-2c0277f05ed4/.hg_archival.txt
77 test-archive-2c0277f05ed4/.hg_archival.txt
78 test-archive-2c0277f05ed4/bar
78 test-archive-2c0277f05ed4/bar
79 test-archive-2c0277f05ed4/baz/bletch
79 test-archive-2c0277f05ed4/baz/bletch
80 test-archive-2c0277f05ed4/foo
80 test-archive-2c0277f05ed4/foo
81 $ python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
81 $ python getarchive.py "$TIP" bz2 | bunzip2 | tar tf - 2>/dev/null
82 test-archive-2c0277f05ed4/.hg_archival.txt
82 test-archive-2c0277f05ed4/.hg_archival.txt
83 test-archive-2c0277f05ed4/bar
83 test-archive-2c0277f05ed4/bar
84 test-archive-2c0277f05ed4/baz/bletch
84 test-archive-2c0277f05ed4/baz/bletch
85 test-archive-2c0277f05ed4/foo
85 test-archive-2c0277f05ed4/foo
86 $ python getarchive.py "$TIP" zip > archive.zip
86 $ python getarchive.py "$TIP" zip > archive.zip
87 $ unzip -t archive.zip
87 $ unzip -t archive.zip
88 Archive: archive.zip
88 Archive: archive.zip
89 testing: test-archive-2c0277f05ed4/.hg_archival.txt OK
89 testing: test-archive-2c0277f05ed4/.hg_archival.txt OK
90 testing: test-archive-2c0277f05ed4/bar OK
90 testing: test-archive-2c0277f05ed4/bar OK
91 testing: test-archive-2c0277f05ed4/baz/bletch OK
91 testing: test-archive-2c0277f05ed4/baz/bletch OK
92 testing: test-archive-2c0277f05ed4/foo OK
92 testing: test-archive-2c0277f05ed4/foo OK
93 No errors detected in compressed data of archive.zip.
93 No errors detected in compressed data of archive.zip.
94
94
95 $ "$TESTDIR/killdaemons.py"
95 $ "$TESTDIR/killdaemons.py"
96
96
97 $ hg archive -t tar test.tar
97 $ hg archive -t tar test.tar
98 $ tar tf test.tar
98 $ tar tf test.tar
99 test/.hg_archival.txt
99 test/.hg_archival.txt
100 test/bar
100 test/bar
101 test/baz/bletch
101 test/baz/bletch
102 test/foo
102 test/foo
103
103
104 $ hg archive -t tbz2 -X baz test.tar.bz2
104 $ hg archive -t tbz2 -X baz test.tar.bz2
105 $ bunzip2 -dc test.tar.bz2 | tar tf - 2>/dev/null
105 $ bunzip2 -dc test.tar.bz2 | tar tf - 2>/dev/null
106 test/.hg_archival.txt
106 test/.hg_archival.txt
107 test/bar
107 test/bar
108 test/foo
108 test/foo
109
109
110 $ hg archive -t tgz -p %b-%h test-%h.tar.gz
110 $ hg archive -t tgz -p %b-%h test-%h.tar.gz
111 $ gzip -dc test-$QTIP.tar.gz | tar tf - 2>/dev/null
111 $ gzip -dc test-$QTIP.tar.gz | tar tf - 2>/dev/null
112 test-2c0277f05ed4/.hg_archival.txt
112 test-2c0277f05ed4/.hg_archival.txt
113 test-2c0277f05ed4/bar
113 test-2c0277f05ed4/bar
114 test-2c0277f05ed4/baz/bletch
114 test-2c0277f05ed4/baz/bletch
115 test-2c0277f05ed4/foo
115 test-2c0277f05ed4/foo
116
116
117 $ hg archive autodetected_test.tar
117 $ hg archive autodetected_test.tar
118 $ tar tf autodetected_test.tar
118 $ tar tf autodetected_test.tar
119 autodetected_test/.hg_archival.txt
119 autodetected_test/.hg_archival.txt
120 autodetected_test/bar
120 autodetected_test/bar
121 autodetected_test/baz/bletch
121 autodetected_test/baz/bletch
122 autodetected_test/foo
122 autodetected_test/foo
123
123
124 The '-t' should override autodetection
124 The '-t' should override autodetection
125
125
126 $ hg archive -t tar autodetect_override_test.zip
126 $ hg archive -t tar autodetect_override_test.zip
127 $ tar tf autodetect_override_test.zip
127 $ tar tf autodetect_override_test.zip
128 autodetect_override_test.zip/.hg_archival.txt
128 autodetect_override_test.zip/.hg_archival.txt
129 autodetect_override_test.zip/bar
129 autodetect_override_test.zip/bar
130 autodetect_override_test.zip/baz/bletch
130 autodetect_override_test.zip/baz/bletch
131 autodetect_override_test.zip/foo
131 autodetect_override_test.zip/foo
132
132
133 $ for ext in tar tar.gz tgz tar.bz2 tbz2 zip; do
133 $ for ext in tar tar.gz tgz tar.bz2 tbz2 zip; do
134 > hg archive auto_test.$ext
134 > hg archive auto_test.$ext
135 > if [ -d auto_test.$ext ]; then
135 > if [ -d auto_test.$ext ]; then
136 > echo "extension $ext was not autodetected."
136 > echo "extension $ext was not autodetected."
137 > fi
137 > fi
138 > done
138 > done
139
139
140 $ cat > md5comp.py <<EOF
140 $ cat > md5comp.py <<EOF
141 > try:
141 > try:
142 > from hashlib import md5
142 > from hashlib import md5
143 > except ImportError:
143 > except ImportError:
144 > from md5 import md5
144 > from md5 import md5
145 > import sys
145 > import sys
146 > f1, f2 = sys.argv[1:3]
146 > f1, f2 = sys.argv[1:3]
147 > h1 = md5(file(f1, 'rb').read()).hexdigest()
147 > h1 = md5(file(f1, 'rb').read()).hexdigest()
148 > h2 = md5(file(f2, 'rb').read()).hexdigest()
148 > h2 = md5(file(f2, 'rb').read()).hexdigest()
149 > print h1 == h2 or "md5 differ: " + repr((h1, h2))
149 > print h1 == h2 or "md5 differ: " + repr((h1, h2))
150 > EOF
150 > EOF
151
151
152 archive name is stored in the archive, so create similar archives and
152 archive name is stored in the archive, so create similar archives and
153 rename them afterwards.
153 rename them afterwards.
154
154
155 $ hg archive -t tgz tip.tar.gz
155 $ hg archive -t tgz tip.tar.gz
156 $ mv tip.tar.gz tip1.tar.gz
156 $ mv tip.tar.gz tip1.tar.gz
157 $ sleep 1
157 $ sleep 1
158 $ hg archive -t tgz tip.tar.gz
158 $ hg archive -t tgz tip.tar.gz
159 $ mv tip.tar.gz tip2.tar.gz
159 $ mv tip.tar.gz tip2.tar.gz
160 $ python md5comp.py tip1.tar.gz tip2.tar.gz
160 $ python md5comp.py tip1.tar.gz tip2.tar.gz
161 True
161 True
162
162
163 $ hg archive -t zip -p /illegal test.zip
163 $ hg archive -t zip -p /illegal test.zip
164 abort: archive prefix contains illegal components
164 abort: archive prefix contains illegal components
165 [255]
165 [255]
166 $ hg archive -t zip -p very/../bad test.zip
166 $ hg archive -t zip -p very/../bad test.zip
167
167
168 $ hg archive --config ui.archivemeta=false -t zip -r 2 test.zip
168 $ hg archive --config ui.archivemeta=false -t zip -r 2 test.zip
169 $ unzip -t test.zip
169 $ unzip -t test.zip
170 Archive: test.zip
170 Archive: test.zip
171 testing: test/bar OK
171 testing: test/bar OK
172 testing: test/baz/bletch OK
172 testing: test/baz/bletch OK
173 testing: test/foo OK
173 testing: test/foo OK
174 No errors detected in compressed data of test.zip.
174 No errors detected in compressed data of test.zip.
175
175
176 $ hg archive -t tar - | tar tf - 2>/dev/null
176 $ hg archive -t tar - | tar tf - 2>/dev/null
177 test-2c0277f05ed4/.hg_archival.txt
177 test-2c0277f05ed4/.hg_archival.txt
178 test-2c0277f05ed4/bar
178 test-2c0277f05ed4/bar
179 test-2c0277f05ed4/baz/bletch
179 test-2c0277f05ed4/baz/bletch
180 test-2c0277f05ed4/foo
180 test-2c0277f05ed4/foo
181
181
182 $ hg archive -r 0 -t tar rev-%r.tar
182 $ hg archive -r 0 -t tar rev-%r.tar
183 $ if [ -f rev-0.tar ]; then
183 $ if [ -f rev-0.tar ]; then
184 $ fi
184 $ fi
185
185
186 test .hg_archival.txt
186 test .hg_archival.txt
187
187
188 $ hg archive ../test-tags
188 $ hg archive ../test-tags
189 $ cat ../test-tags/.hg_archival.txt
189 $ cat ../test-tags/.hg_archival.txt
190 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
190 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
191 node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
191 node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
192 branch: default
192 branch: default
193 latesttag: null
193 latesttag: null
194 latesttagdistance: 3
194 latesttagdistance: 3
195 $ hg tag -r 2 mytag
195 $ hg tag -r 2 mytag
196 $ hg tag -r 2 anothertag
196 $ hg tag -r 2 anothertag
197 $ hg archive -r 2 ../test-lasttag
197 $ hg archive -r 2 ../test-lasttag
198 $ cat ../test-lasttag/.hg_archival.txt
198 $ cat ../test-lasttag/.hg_archival.txt
199 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
199 repo: daa7f7c60e0a224faa4ff77ca41b2760562af264
200 node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
200 node: 2c0277f05ed49d1c8328fb9ba92fba7a5ebcb33e
201 branch: default
201 branch: default
202 tag: anothertag
202 tag: anothertag
203 tag: mytag
203 tag: mytag
204
204
205 $ hg archive -t bogus test.bogus
205 $ hg archive -t bogus test.bogus
206 abort: unknown archive type 'bogus'
206 abort: unknown archive type 'bogus'
207 [255]
207 [255]
208
208
209 enable progress extension:
210
211 $ cp $HGRCPATH $HGRCPATH.no-progress
212 $ cat >> $HGRCPATH <<EOF
213 > [extensions]
214 > progress =
215 > [progress]
216 > assume-tty = 1
217 > delay = 0
218 > refresh = 0
219 > width = 60
220 > EOF
221
222 $ hg archive ../with-progress 2>&1 | $TESTDIR/filtercr.py
223
224 archiving [ ] 0/4
225 archiving [ ] 0/4
226 archiving [=========> ] 1/4
227 archiving [=========> ] 1/4
228 archiving [====================> ] 2/4
229 archiving [====================> ] 2/4
230 archiving [===============================> ] 3/4
231 archiving [===============================> ] 3/4
232 archiving [==========================================>] 4/4
233 archiving [==========================================>] 4/4
234 \r (esc)
235
236 cleanup after progress extension test:
237
238 $ cp $HGRCPATH.no-progress $HGRCPATH
239
209 server errors
240 server errors
210
241
211 $ cat errors.log
242 $ cat errors.log
212
243
213 empty repo
244 empty repo
214
245
215 $ hg init ../empty
246 $ hg init ../empty
216 $ cd ../empty
247 $ cd ../empty
217 $ hg archive ../test-empty
248 $ hg archive ../test-empty
218 abort: no working directory: please specify a revision
249 abort: no working directory: please specify a revision
219 [255]
250 [255]
220
251
221 old file -- date clamped to 1980
252 old file -- date clamped to 1980
222
253
223 $ touch -t 197501010000 old
254 $ touch -t 197501010000 old
224 $ hg add old
255 $ hg add old
225 $ hg commit -m old
256 $ hg commit -m old
226 $ hg archive ../old.zip
257 $ hg archive ../old.zip
227 $ unzip -l ../old.zip
258 $ unzip -l ../old.zip
228 Archive: ../old.zip
259 Archive: ../old.zip
229 \s*Length.* (re)
260 \s*Length.* (re)
230 *-----* (glob)
261 *-----* (glob)
231 *147*80*00:00*old/.hg_archival.txt (glob)
262 *147*80*00:00*old/.hg_archival.txt (glob)
232 *0*80*00:00*old/old (glob)
263 *0*80*00:00*old/old (glob)
233 *-----* (glob)
264 *-----* (glob)
234 \s*147\s+2 files (re)
265 \s*147\s+2 files (re)
General Comments 0
You need to be logged in to leave comments. Login now