##// END OF EJS Templates
Merge with crew-stable
Patrick Mezard -
r8127:17ab4dab merge default
parent child Browse files
Show More
@@ -0,0 +1,30 b''
1 #!/bin/sh
2
3 "$TESTDIR/hghave" bzr114 || exit 80
4
5 . "$TESTDIR/bzr-definitions"
6
7 # The file/directory replacement can only be reproduced on
8 # bzr >= 1.4. Merge it back in test-convert-bzr-directories once
9 # this version becomes mainstream.
10 echo % replace file with dir
11 mkdir test-replace-file-with-dir
12 cd test-replace-file-with-dir
13 bzr init -q source
14 cd source
15 echo d > d
16 bzr add -q d
17 bzr commit -q -m 'add d file'
18 rm d
19 mkdir d
20 bzr add -q d
21 bzr commit -q -m 'replace with d dir'
22 echo a > d/a
23 bzr add -q d/a
24 bzr commit -q -m 'add d/a'
25 cd ..
26 hg convert source source-hg
27 manifest source-hg tip
28 cd source-hg
29 hg update
30 cd ../..
@@ -0,0 +1,11 b''
1 % replace file with dir
2 initializing destination source-hg repository
3 scanning source...
4 sorting...
5 converting...
6 2 add d file
7 1 replace with d dir
8 0 add d/a
9 % manifest of tip
10 644 d/a
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -1,219 +1,224 b''
1 1 # bzr support for the convert extension
2 2 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
3 3 # it cannot access 'bar' repositories, but they were never used very much
4 4
5 5 import os
6 6 from mercurial import demandimport
7 7 # these do not work with demandimport, blacklist
8 8 demandimport.ignore.extend([
9 9 'bzrlib.transactions',
10 10 'bzrlib.urlutils',
11 11 ])
12 12
13 13 from mercurial.i18n import _
14 14 from mercurial import util
15 15 from common import NoRepo, commit, converter_source
16 16
17 17 try:
18 18 # bazaar imports
19 19 from bzrlib import branch, revision, errors
20 20 from bzrlib.revisionspec import RevisionSpec
21 21 except ImportError:
22 22 pass
23 23
24 24 supportedkinds = ('file', 'symlink')
25 25
26 26 class bzr_source(converter_source):
27 27 """Reads Bazaar repositories by using the Bazaar Python libraries"""
28 28
29 29 def __init__(self, ui, path, rev=None):
30 30 super(bzr_source, self).__init__(ui, path, rev=rev)
31 31
32 32 if not os.path.exists(os.path.join(path, '.bzr')):
33 33 raise NoRepo('%s does not look like a Bazaar repo' % path)
34 34
35 35 try:
36 36 # access bzrlib stuff
37 37 branch
38 38 except NameError:
39 39 raise NoRepo('Bazaar modules could not be loaded')
40 40
41 41 path = os.path.abspath(path)
42 42 self.branch = branch.Branch.open(path)
43 43 self.sourcerepo = self.branch.repository
44 44 self._parentids = {}
45 45
46 46 def before(self):
47 47 """Before the conversion begins, acquire a read lock
48 48 for all the operations that might need it. Fortunately
49 49 read locks don't block other reads or writes to the
50 50 repository, so this shouldn't have any impact on the usage of
51 51 the source repository.
52 52
53 53 The alternative would be locking on every operation that
54 54 needs locks (there are currently two: getting the file and
55 55 getting the parent map) and releasing immediately after,
56 56 but this approach can take even 40% longer."""
57 57 self.sourcerepo.lock_read()
58 58
59 59 def after(self):
60 60 self.sourcerepo.unlock()
61 61
62 62 def getheads(self):
63 63 if not self.rev:
64 64 return [self.branch.last_revision()]
65 65 try:
66 66 r = RevisionSpec.from_string(self.rev)
67 67 info = r.in_history(self.branch)
68 68 except errors.BzrError:
69 69 raise util.Abort(_('%s is not a valid revision in current branch')
70 70 % self.rev)
71 71 return [info.rev_id]
72 72
73 73 def getfile(self, name, rev):
74 74 revtree = self.sourcerepo.revision_tree(rev)
75 75 fileid = revtree.path2id(name)
76 76 if fileid is None or revtree.kind(fileid) not in supportedkinds:
77 77 # the file is not available anymore - was deleted
78 78 raise IOError(_('%s is not available in %s anymore') %
79 79 (name, rev))
80 80 sio = revtree.get_file(fileid)
81 81 return sio.read()
82 82
83 83 def getmode(self, name, rev):
84 84 return self._modecache[(name, rev)]
85 85
86 86 def getchanges(self, version):
87 87 # set up caches: modecache and revtree
88 88 self._modecache = {}
89 89 self._revtree = self.sourcerepo.revision_tree(version)
90 90 # get the parentids from the cache
91 91 parentids = self._parentids.pop(version)
92 92 # only diff against first parent id
93 93 prevtree = self.sourcerepo.revision_tree(parentids[0])
94 94 return self._gettreechanges(self._revtree, prevtree)
95 95
96 96 def getcommit(self, version):
97 97 rev = self.sourcerepo.get_revision(version)
98 98 # populate parent id cache
99 99 if not rev.parent_ids:
100 100 parents = []
101 101 self._parentids[version] = (revision.NULL_REVISION,)
102 102 else:
103 103 parents = self._filterghosts(rev.parent_ids)
104 104 self._parentids[version] = parents
105 105
106 106 return commit(parents=parents,
107 107 # bzr uses 1 second timezone precision
108 108 date='%d %d' % (rev.timestamp, rev.timezone / 3600),
109 109 author=self.recode(rev.committer),
110 110 # bzr returns bytestrings or unicode, depending on the content
111 111 desc=self.recode(rev.message),
112 112 rev=version)
113 113
114 114 def gettags(self):
115 115 if not self.branch.supports_tags():
116 116 return {}
117 117 tagdict = self.branch.tags.get_tag_dict()
118 118 bytetags = {}
119 119 for name, rev in tagdict.iteritems():
120 120 bytetags[self.recode(name)] = rev
121 121 return bytetags
122 122
123 123 def getchangedfiles(self, rev, i):
124 124 self._modecache = {}
125 125 curtree = self.sourcerepo.revision_tree(rev)
126 126 parentids = self._parentids.pop(rev)
127 127 if i is not None:
128 128 parentid = parentids[i]
129 129 else:
130 130 # no parent id, get the empty revision
131 131 parentid = revision.NULL_REVISION
132 132
133 133 prevtree = self.sourcerepo.revision_tree(parentid)
134 134 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
135 135 return changes
136 136
137 137 def _gettreechanges(self, current, origin):
138 138 revid = current._revision_id;
139 139 changes = []
140 140 renames = {}
141 141 for (fileid, paths, changed_content, versioned, parent, name,
142 142 kind, executable) in current.iter_changes(origin):
143 143
144 144 if paths[0] == u'' or paths[1] == u'':
145 145 # ignore changes to tree root
146 146 continue
147 147
148 148 # bazaar tracks directories, mercurial does not, so
149 149 # we have to rename the directory contents
150 150 if kind[1] == 'directory':
151 if kind[0] not in (None, 'directory'):
152 # Replacing 'something' with a directory, record it
153 # so it can be removed.
154 changes.append((self.recode(paths[0]), revid))
155
151 156 if None not in paths and paths[0] != paths[1]:
152 157 # neither an add nor an delete - a move
153 158 # rename all directory contents manually
154 159 subdir = origin.inventory.path2id(paths[0])
155 160 # get all child-entries of the directory
156 161 for name, entry in origin.inventory.iter_entries(subdir):
157 162 # hg does not track directory renames
158 163 if entry.kind == 'directory':
159 164 continue
160 165 frompath = self.recode(paths[0] + '/' + name)
161 166 topath = self.recode(paths[1] + '/' + name)
162 167 # register the files as changed
163 168 changes.append((frompath, revid))
164 169 changes.append((topath, revid))
165 170 # add to mode cache
166 171 mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's')
167 172 or '')
168 173 self._modecache[(topath, revid)] = mode
169 174 # register the change as move
170 175 renames[topath] = frompath
171 176
172 177 # no futher changes, go to the next change
173 178 continue
174 179
175 180 # we got unicode paths, need to convert them
176 181 path, topath = [self.recode(part) for part in paths]
177 182
178 183 if topath is None:
179 184 # file deleted
180 185 changes.append((path, revid))
181 186 continue
182 187
183 188 # renamed
184 189 if path and path != topath:
185 190 renames[topath] = path
186 191 changes.append((path, revid))
187 192
188 193 # populate the mode cache
189 194 kind, executable = [e[1] for e in (kind, executable)]
190 195 mode = ((executable and 'x') or (kind == 'symlink' and 's')
191 196 or '')
192 197 self._modecache[(topath, revid)] = mode
193 198 changes.append((topath, revid))
194 199
195 200 return changes, renames
196 201
197 202 def _filterghosts(self, ids):
198 203 """Filters out ghost revisions which hg does not support, see
199 204 <http://bazaar-vcs.org/GhostRevision>
200 205 """
201 206 parentmap = self.sourcerepo.get_parent_map(ids)
202 207 parents = tuple([parent for parent in ids if parent in parentmap])
203 208 return parents
204 209
205 210 def recode(self, s, encoding=None):
206 211 """This version of recode tries to encode unicode to bytecode,
207 212 and preferably using the UTF-8 codec.
208 213 Other types than Unicode are silently returned, this is by
209 214 intention, e.g. the None-type is not going to be encoded but instead
210 215 just passed through
211 216 """
212 217 if not encoding:
213 218 encoding = self.encoding or 'utf-8'
214 219
215 220 if isinstance(s, unicode):
216 221 return s.encode(encoding)
217 222 else:
218 223 # leave it alone
219 224 return s
@@ -1,216 +1,222 b''
1 1 # monotone support for the convert extension
2 2
3 3 import os, re
4 4 from mercurial import util
5 5 from common import NoRepo, commit, converter_source, checktool
6 6 from common import commandline
7 7 from mercurial.i18n import _
8 8
9 9 class monotone_source(converter_source, commandline):
10 10 def __init__(self, ui, path=None, rev=None):
11 11 converter_source.__init__(self, ui, path, rev)
12 12 commandline.__init__(self, ui, 'mtn')
13 13
14 14 self.ui = ui
15 15 self.path = path
16 16
17 17 norepo = NoRepo (_("%s does not look like a monotone repo") % path)
18 18 if not os.path.exists(os.path.join(path, '_MTN')):
19 19 # Could be a monotone repository (SQLite db file)
20 20 try:
21 21 header = file(path, 'rb').read(16)
22 22 except:
23 23 header = ''
24 24 if header != 'SQLite format 3\x00':
25 25 raise norepo
26 26
27 27 # regular expressions for parsing monotone output
28 28 space = r'\s*'
29 29 name = r'\s+"((?:\\"|[^"])*)"\s*'
30 30 value = name
31 31 revision = r'\s+\[(\w+)\]\s*'
32 32 lines = r'(?:.|\n)+'
33 33
34 34 self.dir_re = re.compile(space + "dir" + name)
35 35 self.file_re = re.compile(space + "file" + name + "content" + revision)
36 36 self.add_file_re = re.compile(space + "add_file" + name + "content" + revision)
37 37 self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision)
38 38 self.rename_re = re.compile(space + "rename" + name + "to" + name)
39 39 self.delete_re = re.compile(space + "delete" + name)
40 40 self.tag_re = re.compile(space + "tag" + name + "revision" + revision)
41 41 self.cert_re = re.compile(lines + space + "name" + name + "value" + value)
42 42
43 43 attr = space + "file" + lines + space + "attr" + space
44 44 self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"')
45 45
46 46 # cached data
47 47 self.manifest_rev = None
48 48 self.manifest = None
49 49 self.files = None
50 50 self.dirs = None
51 51
52 52 checktool('mtn', abort=False)
53 53
54 54 # test if there are any revisions
55 55 self.rev = None
56 56 try:
57 57 self.getheads()
58 58 except:
59 59 raise norepo
60 60 self.rev = rev
61 61
62 62 def mtnrun(self, *args, **kwargs):
63 63 kwargs['d'] = self.path
64 64 return self.run0('automate', *args, **kwargs)
65 65
66 66 def mtnloadmanifest(self, rev):
67 67 if self.manifest_rev == rev:
68 68 return
69 69 self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
70 70 self.manifest_rev = rev
71 71 self.files = {}
72 72 self.dirs = {}
73 73
74 74 for e in self.manifest:
75 75 m = self.file_re.match(e)
76 76 if m:
77 77 attr = ""
78 78 name = m.group(1)
79 79 node = m.group(2)
80 80 if self.attr_execute_re.match(e):
81 81 attr += "x"
82 82 self.files[name] = (node, attr)
83 83 m = self.dir_re.match(e)
84 84 if m:
85 85 self.dirs[m.group(1)] = True
86 86
87 87 def mtnisfile(self, name, rev):
88 88 # a non-file could be a directory or a deleted or renamed file
89 89 self.mtnloadmanifest(rev)
90 90 try:
91 91 self.files[name]
92 92 return True
93 93 except KeyError:
94 94 return False
95 95
96 96 def mtnisdir(self, name, rev):
97 97 self.mtnloadmanifest(rev)
98 98 try:
99 99 self.dirs[name]
100 100 return True
101 101 except KeyError:
102 102 return False
103 103
104 104 def mtngetcerts(self, rev):
105 105 certs = {"author":"<missing>", "date":"<missing>",
106 106 "changelog":"<missing>", "branch":"<missing>"}
107 107 cert_list = self.mtnrun("certs", rev).split('\n\n key "')
108 108 for e in cert_list:
109 109 m = self.cert_re.match(e)
110 110 if m:
111 111 name, value = m.groups()
112 112 value = value.replace(r'\"', '"')
113 113 value = value.replace(r'\\', '\\')
114 114 certs[name] = value
115 115 # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306
116 certs["date"] = certs["date"].split('.')[0]
116 # and all times are stored in UTC
117 certs["date"] = certs["date"].split('.')[0] + " UTC"
117 118 return certs
118 119
119 120 # implement the converter_source interface:
120 121
121 122 def getheads(self):
122 123 if not self.rev:
123 124 return self.mtnrun("leaves").splitlines()
124 125 else:
125 126 return [self.rev]
126 127
127 128 def getchanges(self, rev):
128 129 #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
129 130 revision = self.mtnrun("get_revision", rev).split("\n\n")
130 131 files = {}
131 addedfiles = {}
132 ignoremove = {}
132 133 renameddirs = []
133 134 copies = {}
134 135 for e in revision:
135 136 m = self.add_file_re.match(e)
136 137 if m:
137 138 files[m.group(1)] = rev
138 addedfiles[m.group(1)] = rev
139 ignoremove[m.group(1)] = rev
139 140 m = self.patch_re.match(e)
140 141 if m:
141 142 files[m.group(1)] = rev
142 143 # Delete/rename is handled later when the convert engine
143 144 # discovers an IOError exception from getfile,
144 145 # but only if we add the "from" file to the list of changes.
145 146 m = self.delete_re.match(e)
146 147 if m:
147 148 files[m.group(1)] = rev
148 149 m = self.rename_re.match(e)
149 150 if m:
150 151 toname = m.group(2)
151 152 fromname = m.group(1)
152 153 if self.mtnisfile(toname, rev):
154 ignoremove[toname] = 1
153 155 copies[toname] = fromname
154 156 files[toname] = rev
155 157 files[fromname] = rev
156 158 elif self.mtnisdir(toname, rev):
157 159 renameddirs.append((fromname, toname))
158 160
159 161 # Directory renames can be handled only once we have recorded
160 162 # all new files
161 163 for fromdir, todir in renameddirs:
162 164 renamed = {}
163 165 for tofile in self.files:
164 if tofile in addedfiles:
166 if tofile in ignoremove:
165 167 continue
166 168 if tofile.startswith(todir + '/'):
167 169 renamed[tofile] = fromdir + tofile[len(todir):]
170 # Avoid chained moves like:
171 # d1(/a) => d3/d1(/a)
172 # d2 => d3
173 ignoremove[tofile] = 1
168 174 for tofile, fromfile in renamed.items():
169 175 self.ui.debug (_("copying file in renamed directory "
170 176 "from '%s' to '%s'")
171 177 % (fromfile, tofile), '\n')
172 178 files[tofile] = rev
173 179 copies[tofile] = fromfile
174 180 for fromfile in renamed.values():
175 181 files[fromfile] = rev
176 182
177 183 return (files.items(), copies)
178 184
179 185 def getmode(self, name, rev):
180 186 self.mtnloadmanifest(rev)
181 187 try:
182 188 node, attr = self.files[name]
183 189 return attr
184 190 except KeyError:
185 191 return ""
186 192
187 193 def getfile(self, name, rev):
188 194 if not self.mtnisfile(name, rev):
189 195 raise IOError() # file was deleted or renamed
190 196 try:
191 197 return self.mtnrun("get_file_of", name, r=rev)
192 198 except:
193 199 raise IOError() # file was deleted or renamed
194 200
195 201 def getcommit(self, rev):
196 202 certs = self.mtngetcerts(rev)
197 203 return commit(
198 204 author=certs["author"],
199 205 date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
200 206 desc=certs["changelog"],
201 207 rev=rev,
202 208 parents=self.mtnrun("parents", rev).splitlines(),
203 209 branch=certs["branch"])
204 210
205 211 def gettags(self):
206 212 tags = {}
207 213 for e in self.mtnrun("tags").split("\n\n"):
208 214 m = self.tag_re.match(e)
209 215 if m:
210 216 tags[m.group(1)] = m.group(2)
211 217 return tags
212 218
213 219 def getchangedfiles(self, rev, i):
214 220 # This function is only needed to support --filemap
215 221 # ... and we don't support that
216 222 raise NotImplementedError()
@@ -1,255 +1,264 b''
1 1 #!/usr/bin/env python
2 2 """Test the running system for features availability. Exit with zero
3 3 if all features are there, non-zero otherwise. If a feature name is
4 4 prefixed with "no-", the absence of feature is tested.
5 5 """
6 6 import optparse
7 7 import os
8 8 import re
9 9 import sys
10 10 import tempfile
11 11
12 12 tempprefix = 'hg-hghave-'
13 13
14 14 def matchoutput(cmd, regexp, ignorestatus=False):
15 15 """Return True if cmd executes successfully and its output
16 16 is matched by the supplied regular expression.
17 17 """
18 18 r = re.compile(regexp)
19 19 fh = os.popen(cmd)
20 20 s = fh.read()
21 21 ret = fh.close()
22 22 return (ignorestatus or ret is None) and r.search(s)
23 23
24 24 def has_baz():
25 25 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
26 26
27 27 def has_bzr():
28 28 try:
29 29 import bzrlib
30 30 return bzrlib.__doc__ != None
31 31 except ImportError:
32 32 return False
33 33
34 def has_bzr114():
35 try:
36 import bzrlib
37 return (bzrlib.__doc__ != None
38 and bzrlib.version_info[:2] == (1, 14))
39 except ImportError:
40 return False
41
34 42 def has_cvs():
35 43 re = r'Concurrent Versions System.*?server'
36 44 return matchoutput('cvs --version 2>&1', re)
37 45
38 46 def has_cvsps():
39 47 return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
40 48
41 49 def has_darcs():
42 50 return matchoutput('darcs', r'darcs version', True)
43 51
44 52 def has_mtn():
45 53 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
46 54 'mtn --version', r'monotone 0\.(\d|[12]\d|3[01])[^\d]', True)
47 55
48 56 def has_eol_in_paths():
49 57 try:
50 58 fd, path = tempfile.mkstemp(prefix=tempprefix, suffix='\n\r')
51 59 os.close(fd)
52 60 os.remove(path)
53 61 return True
54 62 except:
55 63 return False
56 64
57 65 def has_executablebit():
58 66 fd, path = tempfile.mkstemp(prefix=tempprefix)
59 67 os.close(fd)
60 68 try:
61 69 s = os.lstat(path).st_mode
62 70 os.chmod(path, s | 0100)
63 71 return (os.lstat(path).st_mode & 0100 != 0)
64 72 finally:
65 73 os.remove(path)
66 74
67 75 def has_icasefs():
68 76 # Stolen from mercurial.util
69 77 fd, path = tempfile.mkstemp(prefix=tempprefix)
70 78 os.close(fd)
71 79 try:
72 80 s1 = os.stat(path)
73 81 d, b = os.path.split(path)
74 82 p2 = os.path.join(d, b.upper())
75 83 if path == p2:
76 84 p2 = os.path.join(d, b.lower())
77 85 try:
78 86 s2 = os.stat(p2)
79 87 return s2 == s1
80 88 except:
81 89 return False
82 90 finally:
83 91 os.remove(path)
84 92
85 93 def has_inotify():
86 94 try:
87 95 import hgext.inotify.linux.watcher
88 96 return True
89 97 except ImportError:
90 98 return False
91 99
92 100 def has_fifo():
93 101 return hasattr(os, "mkfifo")
94 102
95 103 def has_hotshot():
96 104 try:
97 105 # hotshot.stats tests hotshot and many problematic dependencies
98 106 # like profile.
99 107 import hotshot.stats
100 108 return True
101 109 except ImportError:
102 110 return False
103 111
104 112 def has_lsprof():
105 113 try:
106 114 import _lsprof
107 115 return True
108 116 except ImportError:
109 117 return False
110 118
111 119 def has_git():
112 120 return matchoutput('git --version 2>&1', r'^git version')
113 121
114 122 def has_svn():
115 123 return matchoutput('svn --version 2>&1', r'^svn, version') and \
116 124 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
117 125
118 126 def has_svn_bindings():
119 127 try:
120 128 import svn.core
121 129 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
122 130 if version < (1, 4):
123 131 return False
124 132 return True
125 133 except ImportError:
126 134 return False
127 135
128 136 def has_p4():
129 137 return matchoutput('p4 -V', r'Rev\. P4/') and matchoutput('p4d -V', r'Rev\. P4D/')
130 138
131 139 def has_symlink():
132 140 return hasattr(os, "symlink")
133 141
134 142 def has_tla():
135 143 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
136 144
137 145 def has_unix_permissions():
138 146 d = tempfile.mkdtemp(prefix=tempprefix, dir=".")
139 147 try:
140 148 fname = os.path.join(d, 'foo')
141 149 for umask in (077, 007, 022):
142 150 os.umask(umask)
143 151 f = open(fname, 'w')
144 152 f.close()
145 153 mode = os.stat(fname).st_mode
146 154 os.unlink(fname)
147 155 if mode & 0777 != ~umask & 0666:
148 156 return False
149 157 return True
150 158 finally:
151 159 os.rmdir(d)
152 160
153 161 def has_pygments():
154 162 try:
155 163 import pygments
156 164 return True
157 165 except ImportError:
158 166 return False
159 167
160 168 def has_outer_repo():
161 169 return matchoutput('hg root 2>&1', r'')
162 170
163 171 checks = {
164 172 "baz": (has_baz, "GNU Arch baz client"),
165 173 "bzr": (has_bzr, "Canonical's Bazaar client"),
174 "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
166 175 "cvs": (has_cvs, "cvs client/server"),
167 176 "cvsps": (has_cvsps, "cvsps utility"),
168 177 "darcs": (has_darcs, "darcs client"),
169 178 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
170 179 "execbit": (has_executablebit, "executable bit"),
171 180 "fifo": (has_fifo, "named pipes"),
172 181 "git": (has_git, "git command line client"),
173 182 "hotshot": (has_hotshot, "python hotshot module"),
174 183 "icasefs": (has_icasefs, "case insensitive file system"),
175 184 "inotify": (has_inotify, "inotify extension support"),
176 185 "lsprof": (has_lsprof, "python lsprof module"),
177 186 "mtn": (has_mtn, "monotone client (> 0.31)"),
178 187 "outer-repo": (has_outer_repo, "outer repo"),
179 188 "p4": (has_p4, "Perforce server and client"),
180 189 "pygments": (has_pygments, "Pygments source highlighting library"),
181 190 "svn": (has_svn, "subversion client and admin tools"),
182 191 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
183 192 "symlink": (has_symlink, "symbolic links"),
184 193 "tla": (has_tla, "GNU Arch tla client"),
185 194 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
186 195 }
187 196
188 197 def list_features():
189 198 for name, feature in checks.iteritems():
190 199 desc = feature[1]
191 200 print name + ':', desc
192 201
193 202 def test_features():
194 203 failed = 0
195 204 for name, feature in checks.iteritems():
196 205 check, _ = feature
197 206 try:
198 207 check()
199 208 except Exception, e:
200 209 print "feature %s failed: %s" % (name, e)
201 210 failed += 1
202 211 return failed
203 212
204 213 parser = optparse.OptionParser("%prog [options] [features]")
205 214 parser.add_option("--test-features", action="store_true",
206 215 help="test available features")
207 216 parser.add_option("--list-features", action="store_true",
208 217 help="list available features")
209 218 parser.add_option("-q", "--quiet", action="store_true",
210 219 help="check features silently")
211 220
212 221 if __name__ == '__main__':
213 222 options, args = parser.parse_args()
214 223 if options.list_features:
215 224 list_features()
216 225 sys.exit(0)
217 226
218 227 if options.test_features:
219 228 sys.exit(test_features())
220 229
221 230 quiet = options.quiet
222 231
223 232 failures = 0
224 233
225 234 def error(msg):
226 235 global failures
227 236 if not quiet:
228 237 sys.stderr.write(msg + '\n')
229 238 failures += 1
230 239
231 240 for feature in args:
232 241 negate = feature.startswith('no-')
233 242 if negate:
234 243 feature = feature[3:]
235 244
236 245 if feature not in checks:
237 246 error('skipped: unknown feature: ' + feature)
238 247 continue
239 248
240 249 check, desc = checks[feature]
241 250 try:
242 251 available = check()
243 252 except Exception, e:
244 253 error('hghave check failed: ' + feature)
245 254 continue
246 255
247 256 if not negate and not available:
248 257 error('skipped: missing feature: ' + desc)
249 258 elif negate and available:
250 259 error('skipped: system supports %s' % desc)
251 260
252 261 if failures != 0:
253 262 sys.exit(1)
254 263
255 264
@@ -1,112 +1,146 b''
1 1 #!/bin/sh
2 2
3 3 "$TESTDIR/hghave" mtn || exit 80
4 4
5 5 # Monotone directory is called .monotone on *nix and monotone
6 6 # on Windows. Having a variable here ease test patching.
7 7 mtndir=.monotone
8 8 echo "[extensions]" >> $HGRCPATH
9 9 echo "convert=" >> $HGRCPATH
10 10 echo 'hgext.graphlog =' >> $HGRCPATH
11 11
12 12 HOME=`pwd`/do_not_use_HOME_mtn; export HOME
13 13 # Windows version of monotone home
14 14 APPDATA=$HOME; export APPDATA
15 15
16 16 echo % tedious monotone keys configuration
17 17 # The /dev/null redirection is necessary under Windows, or
18 18 # it complains about home directory permissions
19 19 mtn --quiet genkey test@selenic.com 1>/dev/null 2>&1 <<EOF
20 20 passphrase
21 21 passphrase
22 22 EOF
23 23 cat >> $HOME/$mtndir/monotonerc <<EOF
24 24 function get_passphrase(keypair_id)
25 25 return "passphrase"
26 26 end
27 27 EOF
28 28
29 29 echo % create monotone repository
30 30 mtn db init --db=repo.mtn
31 31 mtn --db=repo.mtn --branch=com.selenic.test setup workingdir
32 32 cd workingdir
33 33 echo a > a
34 34 mkdir dir
35 35 echo b > dir/b
36 36 echo d > dir/d
37 37 python -c 'file("bin", "wb").write("a\\x00b")'
38 38 echo c > c
39 39 mtn add a dir/b dir/d c bin
40 40 mtn ci -m initialize
41 41 echo % update monotone working directory
42 42 mtn mv a dir/a
43 43 echo a >> dir/a
44 44 echo b >> dir/b
45 45 mtn drop c
46 46 python -c 'file("bin", "wb").write("b\\x00c")'
47 47 mtn ci -m update1
48 48 cd ..
49 49
50 50 echo % convert once
51 51 hg convert -s mtn repo.mtn
52 52
53 53 cd workingdir
54 54 echo e > e
55 55 mtn add e
56 56 mtn drop dir/b
57 57 mtn mv bin bin2
58 58 mtn ci -m 'update2 "with" quotes'
59 59 echo '% test directory move'
60 60 mkdir -p dir1/subdir1
61 61 mkdir -p dir1/subdir2_other
62 62 echo file1 > dir1/subdir1/file1
63 63 echo file2 > dir1/subdir2_other/file1
64 64 mtn add dir1/subdir1/file1 dir1/subdir2_other/file1
65 65 mtn ci -m createdir1
66 66 mtn rename dir1/subdir1 dir1/subdir2
67 67 mtn ci -m movedir1
68 68 echo '% test subdirectory move'
69 69 mtn mv dir dir2
70 70 echo newfile > dir2/newfile
71 71 mtn drop dir2/d
72 72 mtn add dir2/newfile
73 73 mtn ci -m movedir
74 74 # Test directory removal with empty directory
75 75 mkdir dir2/dir
76 76 mkdir dir2/dir/subdir
77 77 echo f > dir2/dir/subdir/f
78 78 mkdir dir2/dir/emptydir
79 79 mtn add --quiet -R dir2/dir
80 80 mtn ci -m emptydir
81 81 mtn drop -R dir2/dir
82 82 mtn ci -m dropdirectory
83 echo '% test directory and file move'
84 mkdir -p dir3/d1
85 echo a > dir3/a
86 mtn add dir3/a dir3/d1
87 mtn ci -m dirfilemove
88 mtn mv dir3/a dir3/d1/a
89 mtn mv dir3/d1 dir3/d2
90 mtn ci -m dirfilemove2
91 echo '% test directory move into another directory move'
92 mkdir dir4
93 mkdir dir5
94 echo a > dir4/a
95 mtn add dir4/a dir5
96 mtn ci -m dirdirmove
97 mtn mv dir5 dir6
98 mtn mv dir4 dir6/dir4
99 mtn ci -m dirdirmove2
100 echo '% test diverging directory moves'
101 mkdir -p dir7/dir9/dir8
102 echo a > dir7/dir9/dir8/a
103 echo b > dir7/dir9/b
104 echo c > dir7/c
105 mtn add -R dir7
106 mtn ci -m divergentdirmove
107 mtn mv dir7 dir7-2
108 mtn mv dir7-2/dir9 dir9-2
109 mtn mv dir9-2/dir8 dir8-2
110 mtn ci -m divergentdirmove2
83 111 cd ..
84 112
85 113 echo % convert incrementally
86 114 hg convert -s mtn repo.mtn
87 115
88 116 glog()
89 117 {
90 118 hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@"
91 119 }
92 120
93 121 cd repo.mtn-hg
94 122 hg up -C
95 123 glog
96 124 echo % manifest
97 125 hg manifest
98 126 echo % contents
99 127 cat dir2/a
100 128 test -d dir2/dir && echo 'removed dir2/dir is still there!'
101 129
102 130 echo % file move
103 131 hg log -v -C -r 1 | grep copies
104 132 echo % check directory move
105 133 hg manifest -r 4
106 134 test -d dir1/subdir2 || echo 'new dir1/subdir2 does not exist!'
107 135 test -d dir1/subdir1 && echo 'renamed dir1/subdir1 is still there!'
108 136 hg log -v -C -r 4 | grep copies
109 137 echo % check file remove with directory move
110 138 hg manifest -r 5
139 echo % check file move with directory move
140 hg manifest -r 9
141 echo % check file directory directory move
142 hg manifest -r 11
143 echo % check divergent directory moves
144 hg manifest -r 13
111 145 exit 0
112 146
@@ -1,110 +1,199 b''
1 1 % tedious monotone keys configuration
2 2 % create monotone repository
3 3 mtn: adding a to workspace manifest
4 4 mtn: adding bin to workspace manifest
5 5 mtn: adding c to workspace manifest
6 6 mtn: adding dir to workspace manifest
7 7 mtn: adding dir/b to workspace manifest
8 8 mtn: adding dir/d to workspace manifest
9 9 mtn: beginning commit on branch 'com.selenic.test'
10 10 mtn: committed revision 0f6e5e4f2e7d2a8ef312408f57618abf026afd90
11 11 % update monotone working directory
12 12 mtn: skipping dir, already accounted for in workspace
13 13 mtn: renaming a to dir/a in workspace manifest
14 14 mtn: dropping c from workspace manifest
15 15 mtn: beginning commit on branch 'com.selenic.test'
16 16 mtn: committed revision 51d0a982464573a2a2cf5ee2c9219c652aaebeff
17 17 % convert once
18 18 assuming destination repo.mtn-hg
19 19 initializing destination repo.mtn-hg repository
20 20 scanning source...
21 21 sorting...
22 22 converting...
23 23 1 initialize
24 24 0 update1
25 25 mtn: adding e to workspace manifest
26 26 mtn: dropping dir/b from workspace manifest
27 27 mtn: renaming bin to bin2 in workspace manifest
28 28 mtn: beginning commit on branch 'com.selenic.test'
29 29 mtn: committed revision ebe58335d85d8cb176b6d0a12be04f5314b998da
30 30 % test directory move
31 31 mtn: adding dir1 to workspace manifest
32 32 mtn: adding dir1/subdir1 to workspace manifest
33 33 mtn: adding dir1/subdir1/file1 to workspace manifest
34 34 mtn: adding dir1/subdir2_other to workspace manifest
35 35 mtn: adding dir1/subdir2_other/file1 to workspace manifest
36 36 mtn: beginning commit on branch 'com.selenic.test'
37 37 mtn: committed revision a8d62bc04fee4d2936d28e98bbcc81686dd74306
38 38 mtn: skipping dir1, already accounted for in workspace
39 39 mtn: renaming dir1/subdir1 to dir1/subdir2 in workspace manifest
40 40 mtn: beginning commit on branch 'com.selenic.test'
41 41 mtn: committed revision 2c3d241bbbfe538b1b51d910f5676407e3f4d3a6
42 42 % test subdirectory move
43 43 mtn: renaming dir to dir2 in workspace manifest
44 44 mtn: dropping dir2/d from workspace manifest
45 45 mtn: adding dir2/newfile to workspace manifest
46 46 mtn: beginning commit on branch 'com.selenic.test'
47 47 mtn: committed revision fdb5a02dae8bfce3a79b3393680af471016e1b4c
48 48 mtn: beginning commit on branch 'com.selenic.test'
49 49 mtn: committed revision 8bbf76d717001d24964e4604739fdcd0f539fc88
50 50 mtn: dropping dir2/dir/subdir/f from workspace manifest
51 51 mtn: dropping dir2/dir/subdir from workspace manifest
52 52 mtn: dropping dir2/dir/emptydir from workspace manifest
53 53 mtn: dropping dir2/dir from workspace manifest
54 54 mtn: beginning commit on branch 'com.selenic.test'
55 55 mtn: committed revision 2323d4bc324e6c82628dc04d47a9fd32ad24e322
56 % test directory and file move
57 mtn: adding dir3 to workspace manifest
58 mtn: adding dir3/a to workspace manifest
59 mtn: adding dir3/d1 to workspace manifest
60 mtn: beginning commit on branch 'com.selenic.test'
61 mtn: committed revision 47b192f720faa622f48c68d1eb075b26d405aa8b
62 mtn: skipping dir3/d1, already accounted for in workspace
63 mtn: renaming dir3/a to dir3/d1/a in workspace manifest
64 mtn: skipping dir3, already accounted for in workspace
65 mtn: renaming dir3/d1 to dir3/d2 in workspace manifest
66 mtn: beginning commit on branch 'com.selenic.test'
67 mtn: committed revision 8b543a400d3ee7f6d4bb1835b9b9e3747c8cb632
68 % test directory move into another directory move
69 mtn: adding dir4 to workspace manifest
70 mtn: adding dir4/a to workspace manifest
71 mtn: adding dir5 to workspace manifest
72 mtn: beginning commit on branch 'com.selenic.test'
73 mtn: committed revision 466e0b2afc7a55aa2b4ab2f57cb240bb6cd66fc7
74 mtn: renaming dir5 to dir6 in workspace manifest
75 mtn: skipping dir6, already accounted for in workspace
76 mtn: renaming dir4 to dir6/dir4 in workspace manifest
77 mtn: beginning commit on branch 'com.selenic.test'
78 mtn: committed revision 3d1f77ebad0c23a5d14911be3b670f990991b749
79 % test diverging directory moves
80 mtn: adding dir7 to workspace manifest
81 mtn: adding dir7/c to workspace manifest
82 mtn: adding dir7/dir9 to workspace manifest
83 mtn: adding dir7/dir9/b to workspace manifest
84 mtn: adding dir7/dir9/dir8 to workspace manifest
85 mtn: adding dir7/dir9/dir8/a to workspace manifest
86 mtn: beginning commit on branch 'com.selenic.test'
87 mtn: committed revision 08a08511f18b428d840199b062de90d0396bc2ed
88 mtn: renaming dir7 to dir7-2 in workspace manifest
89 mtn: renaming dir7-2/dir9 to dir9-2 in workspace manifest
90 mtn: renaming dir9-2/dir8 to dir8-2 in workspace manifest
91 mtn: beginning commit on branch 'com.selenic.test'
92 mtn: committed revision 4a736634505795f17786fffdf2c9cbf5b11df6f6
56 93 % convert incrementally
57 94 assuming destination repo.mtn-hg
58 95 scanning source...
59 96 sorting...
60 97 converting...
61 5 update2 "with" quotes
62 4 createdir1
63 3 movedir1
64 2 movedir
65 1 emptydir
66 0 dropdirectory
67 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 @ 7 "dropdirectory" files: dir2/dir/subdir/f
98 11 update2 "with" quotes
99 10 createdir1
100 9 movedir1
101 8 movedir
102 7 emptydir
103 6 dropdirectory
104 5 dirfilemove
105 4 dirfilemove2
106 3 dirdirmove
107 2 dirdirmove2
108 1 divergentdirmove
109 0 divergentdirmove2
110 11 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 @ 13 "divergentdirmove2" files: dir7-2/c dir7/c dir7/dir9/b dir7/dir9/dir8/a dir8-2/a dir9-2/b
112 |
113 o 12 "divergentdirmove" files: dir7/c dir7/dir9/b dir7/dir9/dir8/a
114 |
115 o 11 "dirdirmove2" files: dir4/a dir6/dir4/a
116 |
117 o 10 "dirdirmove" files: dir4/a
118 |
119 o 9 "dirfilemove2" files: dir3/a dir3/d2/a
120 |
121 o 8 "dirfilemove" files: dir3/a
122 |
123 o 7 "dropdirectory" files: dir2/dir/subdir/f
69 124 |
70 125 o 6 "emptydir" files: dir2/dir/subdir/f
71 126 |
72 127 o 5 "movedir" files: dir/a dir/d dir2/a dir2/newfile
73 128 |
74 129 o 4 "movedir1" files: dir1/subdir1/file1 dir1/subdir2/file1
75 130 |
76 131 o 3 "createdir1" files: dir1/subdir1/file1 dir1/subdir2_other/file1
77 132 |
78 133 o 2 "update2 "with" quotes" files: bin bin2 dir/b e
79 134 |
80 135 o 1 "update1" files: a bin c dir/a dir/b
81 136 |
82 137 o 0 "initialize" files: a bin c dir/b dir/d
83 138
84 139 % manifest
85 140 bin2
86 141 dir1/subdir2/file1
87 142 dir1/subdir2_other/file1
88 143 dir2/a
89 144 dir2/newfile
145 dir3/d2/a
146 dir6/dir4/a
147 dir7-2/c
148 dir8-2/a
149 dir9-2/b
90 150 e
91 151 % contents
92 152 a
93 153 a
94 154 % file move
95 155 copies: dir/a (a)
96 156 % check directory move
97 157 bin2
98 158 dir/a
99 159 dir/d
100 160 dir1/subdir2/file1
101 161 dir1/subdir2_other/file1
102 162 e
103 163 copies: dir1/subdir2/file1 (dir1/subdir1/file1)
104 164 % check file remove with directory move
105 165 bin2
106 166 dir1/subdir2/file1
107 167 dir1/subdir2_other/file1
108 168 dir2/a
109 169 dir2/newfile
110 170 e
171 % check file move with directory move
172 bin2
173 dir1/subdir2/file1
174 dir1/subdir2_other/file1
175 dir2/a
176 dir2/newfile
177 dir3/d2/a
178 e
179 % check file directory directory move
180 bin2
181 dir1/subdir2/file1
182 dir1/subdir2_other/file1
183 dir2/a
184 dir2/newfile
185 dir3/d2/a
186 dir6/dir4/a
187 e
188 % check divergent directory moves
189 bin2
190 dir1/subdir2/file1
191 dir1/subdir2_other/file1
192 dir2/a
193 dir2/newfile
194 dir3/d2/a
195 dir6/dir4/a
196 dir7-2/c
197 dir8-2/a
198 dir9-2/b
199 e
General Comments 0
You need to be logged in to leave comments. Login now