##// END OF EJS Templates
convert: added gnu arch (baz) tests
Aleix Conchillo Flaque -
r6078:ebc23d34 default
parent child Browse files
Show More
@@ -0,0 +1,66 b''
1 #!/bin/sh
2
3 "$TESTDIR/hghave" baz || exit 80
4
5 echo "[extensions]" >> $HGRCPATH
6 echo "convert=" >> $HGRCPATH
7 echo 'hgext.graphlog =' >> $HGRCPATH
8
9 echo % create baz archive
10 baz make-archive baz@mercurial--convert hg-test-convert-baz
11
12 echo % initialize baz repo
13 mkdir baz-repo
14 cd baz-repo/
15 baz init-tree baz@mercurial--convert/baz--test--0
16 baz import
17
18 echo % create initial files
19 echo 'this is a file' > a
20 baz add a
21 mkdir src
22 baz add src
23 cd src
24 dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null
25 baz add b
26 baz commit -s "added a file, src and src/b (binary)"
27
28 echo % create link file and modify a
29 ln -s ../a a-link
30 baz add a-link
31 echo 'this a modification to a' >> ../a
32 baz commit -s "added link to a and modify a"
33
34 echo % create second link and modify b
35 ln -s ../a a-link-2
36 baz add a-link-2
37 dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null
38 baz commit -s "added second link and modify b"
39
40 echo % b file to link and a-link-2 to regular file
41 rm -f a-link-2
42 echo 'this is now a regular file' > a-link-2
43 ln -sf ../a b
44 baz commit -s "file to link and link to file test"
45
46 echo % move a-link-2 file and src directory
47 cd ..
48 baz mv src/a-link-2 c
49 baz mv src test
50 baz commit -s "move and rename a-link-2 file and src directory"
51
52 cd ..
53
54 echo % converting baz repo to Mercurial
55 hg convert baz-repo baz-repo-hg
56
57 baz register-archive -d baz@mercurial--convert
58
59 glog()
60 {
61 hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@"
62 }
63
64 echo % show graph log
65 glog -R baz-repo-hg
66 hg -R baz-repo-hg manifest --debug
@@ -0,0 +1,75 b''
1 % create baz archive
2 % initialize baz repo
3 * creating version baz@mercurial--convert/baz--test--0
4 * imported baz@mercurial--convert/baz--test--0
5 % create initial files
6 * build pristine tree for baz@mercurial--convert/baz--test--0--base-0
7 * Scanning for full-tree revision: .
8 * from import revision: baz@mercurial--convert/baz--test--0--base-0
9 A/ .arch-ids
10 A/ src
11 A/ src/.arch-ids
12 A .arch-ids/a.id
13 A a
14 A src/.arch-ids/=id
15 A src/.arch-ids/b.id
16 A src/b
17 * update pristine tree (baz@mercurial--convert/baz--test--0--base-0 => baz--test--0--patch-1)
18 * committed baz@mercurial--convert/baz--test--0--patch-1
19 % create link file and modify a
20 A src/.arch-ids/a-link.id
21 A src/a-link
22 M a
23 * update pristine tree (baz@mercurial--convert/baz--test--0--patch-1 => baz--test--0--patch-2)
24 * committed baz@mercurial--convert/baz--test--0--patch-2
25 % create second link and modify b
26 A src/.arch-ids/a-link-2.id
27 A src/a-link-2
28 Mb src/b
29 * update pristine tree (baz@mercurial--convert/baz--test--0--patch-2 => baz--test--0--patch-3)
30 * committed baz@mercurial--convert/baz--test--0--patch-3
31 % b file to link and a-link-2 to regular file
32 fl src/b
33 lf src/a-link-2
34 * update pristine tree (baz@mercurial--convert/baz--test--0--patch-3 => baz--test--0--patch-4)
35 * committed baz@mercurial--convert/baz--test--0--patch-4
36 % move a-link-2 file and src directory
37 D/ src/.arch-ids
38 A/ test/.arch-ids
39 /> src test
40 => src/.arch-ids/a-link-2.id .arch-ids/c.id
41 => src/a-link-2 c
42 => src/.arch-ids/=id test/.arch-ids/=id
43 => src/.arch-ids/a-link.id test/.arch-ids/a-link.id
44 => src/.arch-ids/b.id test/.arch-ids/b.id
45 * update pristine tree (baz@mercurial--convert/baz--test--0--patch-4 => baz--test--0--patch-5)
46 * committed baz@mercurial--convert/baz--test--0--patch-5
47 % converting baz repo to Mercurial
48 initializing destination baz-repo-hg repository
49 analyzing tree version baz@mercurial--convert/baz--test--0...
50 scanning source...
51 sorting...
52 converting...
53 5 initial import
54 4 added a file, src and src/b (binary)
55 3 added link to a and modify a
56 2 added second link and modify b
57 1 file to link and link to file test
58 0 move and rename a-link-2 file and src directory
59 % show graph log
60 o 5 "move and rename a-link-2 file and src directory" files: c src/a-link src/a-link-2 src/b test/a-link test/b
61 |
62 o 4 "file to link and link to file test" files: src/a-link-2 src/b
63 |
64 o 3 "added second link and modify b" files: src/a-link-2 src/b
65 |
66 o 2 "added link to a and modify a" files: a src/a-link
67 |
68 o 1 "added a file, src and src/b (binary)" files: a src/b
69 |
70 o 0 "initial import" files:
71
72 c4072c4b72e1cabace081888efa148ee80ca3cbb 644 a
73 e3207be798aaf87a444a62903621edab4ddc1fb6 644 c
74 1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/a-link
75 1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/b
@@ -1,292 +1,292 b''
1 # GNU Arch support for the convert extension
1 # GNU Arch support for the convert extension
2
2
3 from common import NoRepo, checktool, commandline, commit, converter_source
3 from common import NoRepo, checktool, commandline, commit, converter_source
4 from mercurial.i18n import _
4 from mercurial.i18n import _
5 from mercurial import util
5 from mercurial import util
6 import os, shutil, tempfile, stat
6 import os, shutil, tempfile, stat
7
7
8 class gnuarch_source(converter_source, commandline):
8 class gnuarch_source(converter_source, commandline):
9
9
10 class gnuarch_rev:
10 class gnuarch_rev:
11 def __init__(self, rev):
11 def __init__(self, rev):
12 self.rev = rev
12 self.rev = rev
13 self.summary = ''
13 self.summary = ''
14 self.date = None
14 self.date = None
15 self.author = ''
15 self.author = ''
16 self.add_files = []
16 self.add_files = []
17 self.mod_files = []
17 self.mod_files = []
18 self.del_files = []
18 self.del_files = []
19 self.ren_files = {}
19 self.ren_files = {}
20 self.ren_dirs = {}
20 self.ren_dirs = {}
21
21
22 def __init__(self, ui, path, rev=None):
22 def __init__(self, ui, path, rev=None):
23 super(gnuarch_source, self).__init__(ui, path, rev=rev)
23 super(gnuarch_source, self).__init__(ui, path, rev=rev)
24
24
25 if not os.path.exists(os.path.join(path, '{arch}')):
25 if not os.path.exists(os.path.join(path, '{arch}')):
26 raise NoRepo(_("couldn't open GNU Arch repo %s" % path))
26 raise NoRepo(_("%s does not look like a GNU Arch repo" % path))
27
27
28 # Could use checktool, but we want to check for baz or tla.
28 # Could use checktool, but we want to check for baz or tla.
29 self.execmd = None
29 self.execmd = None
30 if util.find_exe('tla'):
30 if util.find_exe('tla'):
31 self.execmd = 'tla'
31 self.execmd = 'tla'
32 else:
32 else:
33 if util.find_exe('baz'):
33 if util.find_exe('baz'):
34 self.execmd = 'baz'
34 self.execmd = 'baz'
35 else:
35 else:
36 raise util.Abort(_('cannot find a GNU Arch tool'))
36 raise util.Abort(_('cannot find a GNU Arch tool'))
37
37
38 commandline.__init__(self, ui, self.execmd)
38 commandline.__init__(self, ui, self.execmd)
39
39
40 self.path = os.path.realpath(path)
40 self.path = os.path.realpath(path)
41 self.tmppath = None
41 self.tmppath = None
42
42
43 self.treeversion = None
43 self.treeversion = None
44 self.lastrev = None
44 self.lastrev = None
45 self.changes = {}
45 self.changes = {}
46 self.parents = {}
46 self.parents = {}
47 self.tags = {}
47 self.tags = {}
48 self.modecache = {}
48 self.modecache = {}
49
49
50 def before(self):
50 def before(self):
51 if self.execmd == 'tla':
51 if self.execmd == 'tla':
52 output = self.run0('tree-version', self.path)
52 output = self.run0('tree-version', self.path)
53 else:
53 else:
54 output = self.run0('tree-version', '-d', self.path)
54 output = self.run0('tree-version', '-d', self.path)
55 self.treeversion = output.strip()
55 self.treeversion = output.strip()
56
56
57 self.ui.status(_('analyzing tree version %s...\n' % self.treeversion))
57 self.ui.status(_('analyzing tree version %s...\n' % self.treeversion))
58
58
59 # Get name of temporary directory
59 # Get name of temporary directory
60 version = self.treeversion.split('/')
60 version = self.treeversion.split('/')
61 self.tmppath = os.path.join(tempfile.gettempdir(),
61 self.tmppath = os.path.join(tempfile.gettempdir(),
62 'hg-%s' % version[1])
62 'hg-%s' % version[1])
63
63
64 # Generate parents dictionary
64 # Generate parents dictionary
65 child = []
65 child = []
66 output, status = self.runlines('revisions', self.treeversion)
66 output, status = self.runlines('revisions', self.treeversion)
67 self.checkexit(status, 'archive registered?')
67 self.checkexit(status, 'archive registered?')
68 for l in output:
68 for l in output:
69 rev = l.strip()
69 rev = l.strip()
70 self.changes[rev] = self.gnuarch_rev(rev)
70 self.changes[rev] = self.gnuarch_rev(rev)
71
71
72 # Read author, date and summary
72 # Read author, date and summary
73 catlog = self.runlines0('cat-log', '-d', self.path, rev)
73 catlog = self.runlines0('cat-log', '-d', self.path, rev)
74 self._parsecatlog(catlog, rev)
74 self._parsecatlog(catlog, rev)
75
75
76 self.parents[rev] = child
76 self.parents[rev] = child
77 child = [rev]
77 child = [rev]
78 if rev == self.rev:
78 if rev == self.rev:
79 break
79 break
80 self.parents[None] = child
80 self.parents[None] = child
81
81
82 def after(self):
82 def after(self):
83 self.ui.debug(_('cleaning up %s\n' % self.tmppath))
83 self.ui.debug(_('cleaning up %s\n' % self.tmppath))
84 shutil.rmtree(self.tmppath, ignore_errors=True)
84 shutil.rmtree(self.tmppath, ignore_errors=True)
85
85
86 def getheads(self):
86 def getheads(self):
87 return self.parents[None]
87 return self.parents[None]
88
88
89 def getfile(self, name, rev):
89 def getfile(self, name, rev):
90 if rev != self.lastrev:
90 if rev != self.lastrev:
91 raise util.Abort(_('internal calling inconsistency'))
91 raise util.Abort(_('internal calling inconsistency'))
92
92
93 # Raise IOError if necessary (i.e. deleted files).
93 # Raise IOError if necessary (i.e. deleted files).
94 if not os.path.exists(os.path.join(self.tmppath, name)):
94 if not os.path.exists(os.path.join(self.tmppath, name)):
95 raise IOError
95 raise IOError
96
96
97 data, mode = self._getfile(name, rev)
97 data, mode = self._getfile(name, rev)
98 self.modecache[(name, rev)] = mode
98 self.modecache[(name, rev)] = mode
99
99
100 return data
100 return data
101
101
102 def getmode(self, name, rev):
102 def getmode(self, name, rev):
103 return self.modecache[(name, rev)]
103 return self.modecache[(name, rev)]
104
104
105 def getchanges(self, rev):
105 def getchanges(self, rev):
106 self.modecache = {}
106 self.modecache = {}
107 self._update(rev)
107 self._update(rev)
108 changes = []
108 changes = []
109 copies = {}
109 copies = {}
110
110
111 for f in self.changes[rev].add_files:
111 for f in self.changes[rev].add_files:
112 changes.append((f, rev))
112 changes.append((f, rev))
113
113
114 for f in self.changes[rev].mod_files:
114 for f in self.changes[rev].mod_files:
115 changes.append((f, rev))
115 changes.append((f, rev))
116
116
117 for f in self.changes[rev].del_files:
117 for f in self.changes[rev].del_files:
118 changes.append((f, rev))
118 changes.append((f, rev))
119
119
120 for src in self.changes[rev].ren_files:
120 for src in self.changes[rev].ren_files:
121 to = self.changes[rev].ren_files[src]
121 to = self.changes[rev].ren_files[src]
122 changes.append((src, rev))
122 changes.append((src, rev))
123 changes.append((to, rev))
123 changes.append((to, rev))
124 copies[src] = to
124 copies[src] = to
125
125
126 for src in self.changes[rev].ren_dirs:
126 for src in self.changes[rev].ren_dirs:
127 to = self.changes[rev].ren_dirs[src]
127 to = self.changes[rev].ren_dirs[src]
128 chgs, cps = self._rendirchanges(src, to);
128 chgs, cps = self._rendirchanges(src, to);
129 changes += [(f, rev) for f in chgs]
129 changes += [(f, rev) for f in chgs]
130 for c in cps:
130 for c in cps:
131 copies[c] = cps[c]
131 copies[c] = cps[c]
132
132
133 changes.sort()
133 changes.sort()
134 self.lastrev = rev
134 self.lastrev = rev
135
135
136 return changes, copies
136 return changes, copies
137
137
138 def getcommit(self, rev):
138 def getcommit(self, rev):
139 changes = self.changes[rev]
139 changes = self.changes[rev]
140 return commit(author = changes.author, date = changes.date,
140 return commit(author = changes.author, date = changes.date,
141 desc = changes.summary, parents = self.parents[rev])
141 desc = changes.summary, parents = self.parents[rev])
142
142
143 def gettags(self):
143 def gettags(self):
144 return self.tags
144 return self.tags
145
145
146 def _execute(self, cmd, *args, **kwargs):
146 def _execute(self, cmd, *args, **kwargs):
147 cmdline = [self.execmd, cmd]
147 cmdline = [self.execmd, cmd]
148 cmdline += args
148 cmdline += args
149 cmdline = [util.shellquote(arg) for arg in cmdline]
149 cmdline = [util.shellquote(arg) for arg in cmdline]
150 cmdline += ['>', util.nulldev, '2>', util.nulldev]
150 cmdline += ['>', util.nulldev, '2>', util.nulldev]
151 cmdline = util.quotecommand(' '.join(cmdline))
151 cmdline = util.quotecommand(' '.join(cmdline))
152 self.ui.debug(cmdline, '\n')
152 self.ui.debug(cmdline, '\n')
153 return os.system(cmdline)
153 return os.system(cmdline)
154
154
155 def _update(self, rev):
155 def _update(self, rev):
156 if rev == 'base-0':
156 if rev == 'base-0':
157 # Initialise 'base-0' revision
157 # Initialise 'base-0' revision
158 self._obtainrevision(rev)
158 self._obtainrevision(rev)
159 else:
159 else:
160 self.ui.debug(_('applying revision %s...\n' % rev))
160 self.ui.debug(_('applying revision %s...\n' % rev))
161 revision = '%s--%s' % (self.treeversion, rev)
161 revision = '%s--%s' % (self.treeversion, rev)
162 changeset, status = self.runlines('replay', '-d', self.tmppath,
162 changeset, status = self.runlines('replay', '-d', self.tmppath,
163 revision)
163 revision)
164 if status:
164 if status:
165 # Something went wrong while merging (baz or tla
165 # Something went wrong while merging (baz or tla
166 # issue?), get latest revision and try from there
166 # issue?), get latest revision and try from there
167 shutil.rmtree(self.tmppath, ignore_errors=True)
167 shutil.rmtree(self.tmppath, ignore_errors=True)
168 self._obtainrevision(rev)
168 self._obtainrevision(rev)
169 else:
169 else:
170 old_rev = self.parents[rev][0]
170 old_rev = self.parents[rev][0]
171 self.ui.debug(_('computing changeset between %s and %s...\n' \
171 self.ui.debug(_('computing changeset between %s and %s...\n' \
172 % (old_rev, rev)))
172 % (old_rev, rev)))
173 rev_a = '%s--%s' % (self.treeversion, old_rev)
173 rev_a = '%s--%s' % (self.treeversion, old_rev)
174 rev_b = '%s--%s' % (self.treeversion, rev)
174 rev_b = '%s--%s' % (self.treeversion, rev)
175 self._parsechangeset(changeset, rev)
175 self._parsechangeset(changeset, rev)
176
176
177 def _getfile(self, name, rev):
177 def _getfile(self, name, rev):
178 mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
178 mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
179 if stat.S_ISLNK(mode):
179 if stat.S_ISLNK(mode):
180 data = os.readlink(os.path.join(self.tmppath, name))
180 data = os.readlink(os.path.join(self.tmppath, name))
181 mode = mode and 'l' or ''
181 mode = mode and 'l' or ''
182 else:
182 else:
183 data = open(os.path.join(self.tmppath, name), 'rb').read()
183 data = open(os.path.join(self.tmppath, name), 'rb').read()
184 mode = (mode & 0111) and 'x' or ''
184 mode = (mode & 0111) and 'x' or ''
185 return data, mode
185 return data, mode
186
186
187 def _exclude(self, name):
187 def _exclude(self, name):
188 exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ]
188 exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ]
189 for exc in exclude:
189 for exc in exclude:
190 if name.find(exc) != -1:
190 if name.find(exc) != -1:
191 return True
191 return True
192 return False
192 return False
193
193
194 def _readcontents(self, path):
194 def _readcontents(self, path):
195 files = []
195 files = []
196 contents = os.listdir(path)
196 contents = os.listdir(path)
197 while len(contents) > 0:
197 while len(contents) > 0:
198 c = contents.pop()
198 c = contents.pop()
199 p = os.path.join(path, c)
199 p = os.path.join(path, c)
200 # os.walk could be used, but here we avoid internal GNU
200 # os.walk could be used, but here we avoid internal GNU
201 # Arch files and directories, thus saving a lot time.
201 # Arch files and directories, thus saving a lot time.
202 if not self._exclude(p):
202 if not self._exclude(p):
203 if os.path.isdir(p):
203 if os.path.isdir(p):
204 contents += [os.path.join(c, f) for f in os.listdir(p)]
204 contents += [os.path.join(c, f) for f in os.listdir(p)]
205 else:
205 else:
206 files.append(c)
206 files.append(c)
207 return files
207 return files
208
208
209 def _rendirchanges(self, src, dest):
209 def _rendirchanges(self, src, dest):
210 changes = []
210 changes = []
211 copies = {}
211 copies = {}
212 files = self._readcontents(os.path.join(self.tmppath, dest))
212 files = self._readcontents(os.path.join(self.tmppath, dest))
213 for f in files:
213 for f in files:
214 s = os.path.join(src, f)
214 s = os.path.join(src, f)
215 d = os.path.join(dest, f)
215 d = os.path.join(dest, f)
216 changes.append(s)
216 changes.append(s)
217 changes.append(d)
217 changes.append(d)
218 copies[s] = d
218 copies[s] = d
219 return changes, copies
219 return changes, copies
220
220
221 def _obtainrevision(self, rev):
221 def _obtainrevision(self, rev):
222 self.ui.debug(_('obtaining revision %s...\n' % rev))
222 self.ui.debug(_('obtaining revision %s...\n' % rev))
223 revision = '%s--%s' % (self.treeversion, rev)
223 revision = '%s--%s' % (self.treeversion, rev)
224 output = self._execute('get', revision, self.tmppath)
224 output = self._execute('get', revision, self.tmppath)
225 self.checkexit(output)
225 self.checkexit(output)
226 self.ui.debug(_('analysing revision %s...\n' % rev))
226 self.ui.debug(_('analysing revision %s...\n' % rev))
227 files = self._readcontents(self.tmppath)
227 files = self._readcontents(self.tmppath)
228 self.changes[rev].add_files += files
228 self.changes[rev].add_files += files
229
229
230 def _parsecatlog(self, data, rev):
230 def _parsecatlog(self, data, rev):
231 summary = []
231 summary = []
232 for l in data:
232 for l in data:
233 l = l.strip()
233 l = l.strip()
234 if summary:
234 if summary:
235 summary.append(l)
235 summary.append(l)
236 elif l.startswith('Summary:'):
236 elif l.startswith('Summary:'):
237 summary.append(l[len('Summary: '):])
237 summary.append(l[len('Summary: '):])
238 elif l.startswith('Standard-date:'):
238 elif l.startswith('Standard-date:'):
239 date = l[len('Standard-date: '):]
239 date = l[len('Standard-date: '):]
240 strdate = util.strdate(date, '%Y-%m-%d %H:%M:%S')
240 strdate = util.strdate(date, '%Y-%m-%d %H:%M:%S')
241 self.changes[rev].date = util.datestr(strdate)
241 self.changes[rev].date = util.datestr(strdate)
242 elif l.startswith('Creator:'):
242 elif l.startswith('Creator:'):
243 self.changes[rev].author = l[len('Creator: '):]
243 self.changes[rev].author = l[len('Creator: '):]
244 self.changes[rev].summary = '\n'.join(summary)
244 self.changes[rev].summary = '\n'.join(summary)
245
245
246 def _parsechangeset(self, data, rev):
246 def _parsechangeset(self, data, rev):
247 for l in data:
247 for l in data:
248 l = l.strip()
248 l = l.strip()
249 # Added file (ignore added directory)
249 # Added file (ignore added directory)
250 if l.startswith('A') and not l.startswith('A/'):
250 if l.startswith('A') and not l.startswith('A/'):
251 file = l[1:].strip()
251 file = l[1:].strip()
252 if not self._exclude(file):
252 if not self._exclude(file):
253 self.changes[rev].add_files.append(file)
253 self.changes[rev].add_files.append(file)
254 # Deleted file (ignore deleted directory)
254 # Deleted file (ignore deleted directory)
255 elif l.startswith('D') and not l.startswith('D/'):
255 elif l.startswith('D') and not l.startswith('D/'):
256 file = l[1:].strip()
256 file = l[1:].strip()
257 if not self._exclude(file):
257 if not self._exclude(file):
258 self.changes[rev].del_files.append(file)
258 self.changes[rev].del_files.append(file)
259 # Modified binary file
259 # Modified binary file
260 elif l.startswith('Mb'):
260 elif l.startswith('Mb'):
261 file = l[2:].strip()
261 file = l[2:].strip()
262 if not self._exclude(file):
262 if not self._exclude(file):
263 self.changes[rev].mod_files.append(file)
263 self.changes[rev].mod_files.append(file)
264 # Modified link
264 # Modified link
265 elif l.startswith('M->'):
265 elif l.startswith('M->'):
266 file = l[3:].strip()
266 file = l[3:].strip()
267 if not self._exclude(file):
267 if not self._exclude(file):
268 self.changes[rev].mod_files.append(file)
268 self.changes[rev].mod_files.append(file)
269 # Modified file
269 # Modified file
270 elif l.startswith('M'):
270 elif l.startswith('M'):
271 file = l[1:].strip()
271 file = l[1:].strip()
272 if not self._exclude(file):
272 if not self._exclude(file):
273 self.changes[rev].mod_files.append(file)
273 self.changes[rev].mod_files.append(file)
274 # Renamed file (or link)
274 # Renamed file (or link)
275 elif l.startswith('=>'):
275 elif l.startswith('=>'):
276 files = l[2:].strip().split(' ')
276 files = l[2:].strip().split(' ')
277 if len(files) == 1:
277 if len(files) == 1:
278 files = l[2:].strip().split('\t')
278 files = l[2:].strip().split('\t')
279 if not self._exclude(files[0]) and not self._exclude(files[1]):
279 if not self._exclude(files[0]) and not self._exclude(files[1]):
280 self.changes[rev].ren_files[files[0]] = files[1]
280 self.changes[rev].ren_files[files[0]] = files[1]
281 # Conversion from file to link or from link to file (modified)
281 # Conversion from file to link or from link to file (modified)
282 elif l.startswith('ch'):
282 elif l.startswith('ch'):
283 file = l[2:].strip()
283 file = l[2:].strip()
284 if not self._exclude(file):
284 if not self._exclude(file):
285 self.changes[rev].mod_files.append(file)
285 self.changes[rev].mod_files.append(file)
286 # Renamed directory
286 # Renamed directory
287 elif l.startswith('/>'):
287 elif l.startswith('/>'):
288 dirs = l[2:].strip().split(' ')
288 dirs = l[2:].strip().split(' ')
289 if len(dirs) == 1:
289 if len(dirs) == 1:
290 dirs = l[2:].strip().split('\t')
290 dirs = l[2:].strip().split('\t')
291 if not self._exclude(dirs[0]) and not self._exclude(dirs[1]):
291 if not self._exclude(dirs[0]) and not self._exclude(dirs[1]):
292 self.changes[rev].ren_dirs[dirs[0]] = dirs[1]
292 self.changes[rev].ren_dirs[dirs[0]] = dirs[1]
@@ -1,165 +1,169 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Test the running system for features availability. Exit with zero
2 """Test the running system for features availability. Exit with zero
3 if all features are there, non-zero otherwise. If a feature name is
3 if all features are there, non-zero otherwise. If a feature name is
4 prefixed with "no-", the absence of feature is tested.
4 prefixed with "no-", the absence of feature is tested.
5 """
5 """
6 import optparse
6 import optparse
7 import os
7 import os
8 import re
8 import re
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11
11
12 tempprefix = 'hg-hghave-'
12 tempprefix = 'hg-hghave-'
13
13
14 def matchoutput(cmd, regexp, ignorestatus=False):
14 def matchoutput(cmd, regexp, ignorestatus=False):
15 """Return True if cmd executes successfully and its output
15 """Return True if cmd executes successfully and its output
16 is matched by the supplied regular expression.
16 is matched by the supplied regular expression.
17 """
17 """
18 r = re.compile(regexp)
18 r = re.compile(regexp)
19 fh = os.popen(cmd)
19 fh = os.popen(cmd)
20 s = fh.read()
20 s = fh.read()
21 ret = fh.close()
21 ret = fh.close()
22 return (ignorestatus or ret is None) and r.search(s)
22 return (ignorestatus or ret is None) and r.search(s)
23
23
24 def has_baz():
25 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
26
24 def has_cvs():
27 def has_cvs():
25 return matchoutput('cvs --version 2>&1', r'Concurrent Versions System')
28 return matchoutput('cvs --version 2>&1', r'Concurrent Versions System')
26
29
27 def has_cvsps():
30 def has_cvsps():
28 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
31 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
29
32
30 def has_darcs():
33 def has_darcs():
31 return matchoutput('darcs', 'darcs version', True)
34 return matchoutput('darcs', 'darcs version', True)
32
35
33 def has_eol_in_paths():
36 def has_eol_in_paths():
34 try:
37 try:
35 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
38 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
36 os.close(fd)
39 os.close(fd)
37 os.remove(path)
40 os.remove(path)
38 return True
41 return True
39 except:
42 except:
40 return False
43 return False
41
44
42 def has_executablebit():
45 def has_executablebit():
43 fd, path = tempfile.mkstemp(prefix=tempprefix)
46 fd, path = tempfile.mkstemp(prefix=tempprefix)
44 os.close(fd)
47 os.close(fd)
45 try:
48 try:
46 s = os.lstat(path).st_mode
49 s = os.lstat(path).st_mode
47 os.chmod(path, s | 0100)
50 os.chmod(path, s | 0100)
48 return (os.lstat(path).st_mode & 0100 != 0)
51 return (os.lstat(path).st_mode & 0100 != 0)
49 finally:
52 finally:
50 os.remove(path)
53 os.remove(path)
51
54
52 def has_fifo():
55 def has_fifo():
53 return hasattr(os, "mkfifo")
56 return hasattr(os, "mkfifo")
54
57
55 def has_hotshot():
58 def has_hotshot():
56 try:
59 try:
57 # hotshot.stats tests hotshot and many problematic dependencies
60 # hotshot.stats tests hotshot and many problematic dependencies
58 # like profile.
61 # like profile.
59 import hotshot.stats
62 import hotshot.stats
60 return True
63 return True
61 except ImportError:
64 except ImportError:
62 return False
65 return False
63
66
64 def has_lsprof():
67 def has_lsprof():
65 try:
68 try:
66 import _lsprof
69 import _lsprof
67 return True
70 return True
68 except ImportError:
71 except ImportError:
69 return False
72 return False
70
73
71 def has_git():
74 def has_git():
72 return matchoutput('git --version 2>&1', r'^git version')
75 return matchoutput('git --version 2>&1', r'^git version')
73
76
74 def has_svn():
77 def has_svn():
75 return matchoutput('svn --version 2>&1', r'^svn, version') and \
78 return matchoutput('svn --version 2>&1', r'^svn, version') and \
76 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
79 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
77
80
78 def has_svn_bindings():
81 def has_svn_bindings():
79 try:
82 try:
80 import svn.core
83 import svn.core
81 return True
84 return True
82 except ImportError:
85 except ImportError:
83 return False
86 return False
84
87
85 def has_symlink():
88 def has_symlink():
86 return hasattr(os, "symlink")
89 return hasattr(os, "symlink")
87
90
88 def has_unix_permissions():
91 def has_unix_permissions():
89 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
92 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
90 try:
93 try:
91 fname = os.path.join(d, 'foo')
94 fname = os.path.join(d, 'foo')
92 for umask in (077, 007, 022):
95 for umask in (077, 007, 022):
93 os.umask(umask)
96 os.umask(umask)
94 f = open(fname, 'w')
97 f = open(fname, 'w')
95 f.close()
98 f.close()
96 mode = os.stat(fname).st_mode
99 mode = os.stat(fname).st_mode
97 os.unlink(fname)
100 os.unlink(fname)
98 if mode & 0777 != ~umask & 0666:
101 if mode & 0777 != ~umask & 0666:
99 return False
102 return False
100 return True
103 return True
101 finally:
104 finally:
102 os.rmdir(d)
105 os.rmdir(d)
103
106
104 checks = {
107 checks = {
108 "baz": (has_baz, "GNU Arch baz client"),
105 "cvs": (has_cvs, "cvs client"),
109 "cvs": (has_cvs, "cvs client"),
106 "cvsps": (has_cvsps, "cvsps utility"),
110 "cvsps": (has_cvsps, "cvsps utility"),
107 "darcs": (has_darcs, "darcs client"),
111 "darcs": (has_darcs, "darcs client"),
108 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
112 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
109 "execbit": (has_executablebit, "executable bit"),
113 "execbit": (has_executablebit, "executable bit"),
110 "fifo": (has_fifo, "named pipes"),
114 "fifo": (has_fifo, "named pipes"),
111 "git": (has_git, "git command line client"),
115 "git": (has_git, "git command line client"),
112 "hotshot": (has_hotshot, "python hotshot module"),
116 "hotshot": (has_hotshot, "python hotshot module"),
113 "lsprof": (has_lsprof, "python lsprof module"),
117 "lsprof": (has_lsprof, "python lsprof module"),
114 "svn": (has_svn, "subversion client and admin tools"),
118 "svn": (has_svn, "subversion client and admin tools"),
115 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
119 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
116 "symlink": (has_symlink, "symbolic links"),
120 "symlink": (has_symlink, "symbolic links"),
117 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
121 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
118 }
122 }
119
123
120 def list_features():
124 def list_features():
121 for name, feature in checks.iteritems():
125 for name, feature in checks.iteritems():
122 desc = feature[1]
126 desc = feature[1]
123 print name + ':', desc
127 print name + ':', desc
124
128
125 parser = optparse.OptionParser("%prog [options] [features]")
129 parser = optparse.OptionParser("%prog [options] [features]")
126 parser.add_option("--list-features", action="store_true",
130 parser.add_option("--list-features", action="store_true",
127 help="list available features")
131 help="list available features")
128 parser.add_option("-q", "--quiet", action="store_true",
132 parser.add_option("-q", "--quiet", action="store_true",
129 help="check features silently")
133 help="check features silently")
130
134
131 if __name__ == '__main__':
135 if __name__ == '__main__':
132 options, args = parser.parse_args()
136 options, args = parser.parse_args()
133 if options.list_features:
137 if options.list_features:
134 list_features()
138 list_features()
135 sys.exit(0)
139 sys.exit(0)
136
140
137 quiet = options.quiet
141 quiet = options.quiet
138
142
139 failures = 0
143 failures = 0
140
144
141 def error(msg):
145 def error(msg):
142 global failures
146 global failures
143 if not quiet:
147 if not quiet:
144 sys.stderr.write(msg + '\n')
148 sys.stderr.write(msg + '\n')
145 failures += 1
149 failures += 1
146
150
147 for feature in args:
151 for feature in args:
148 negate = feature.startswith('no-')
152 negate = feature.startswith('no-')
149 if negate:
153 if negate:
150 feature = feature[3:]
154 feature = feature[3:]
151
155
152 if feature not in checks:
156 if feature not in checks:
153 error('skipped: unknown feature: ' + feature)
157 error('skipped: unknown feature: ' + feature)
154 continue
158 continue
155
159
156 check, desc = checks[feature]
160 check, desc = checks[feature]
157 if not negate and not check():
161 if not negate and not check():
158 error('skipped: missing feature: ' + desc)
162 error('skipped: missing feature: ' + desc)
159 elif negate and check():
163 elif negate and check():
160 error('skipped: system supports %s' % desc)
164 error('skipped: system supports %s' % desc)
161
165
162 if failures != 0:
166 if failures != 0:
163 sys.exit(1)
167 sys.exit(1)
164
168
165
169
General Comments 0
You need to be logged in to leave comments. Login now