##// END OF EJS Templates
allow None for path of hg.repository
Vadim Gelfer -
r2768:b1b1aa6f default
parent child Browse files
Show More
@@ -1,205 +1,206
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import *
9 9 from repo import *
10 10 from demandload import *
11 11 from i18n import gettext as _
12 12 demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo")
13 13 demandload(globals(), "errno lock os shutil util")
14 14
15 15 def _local(path):
16 return os.path.isfile(util.drop_scheme('file', path)) and bundlerepo or localrepo
16 return (os.path.isfile(path and util.drop_scheme('file', path)) and
17 bundlerepo or localrepo)
17 18
18 19 schemes = {
19 20 'bundle': bundlerepo,
20 21 'file': _local,
21 22 'hg': httprepo,
22 23 'http': httprepo,
23 24 'https': httprepo,
24 25 'old-http': statichttprepo,
25 26 'ssh': sshrepo,
26 27 'static-http': statichttprepo,
27 28 }
28 29
29 30 def _lookup(path):
30 31 scheme = 'file'
31 32 if path:
32 33 c = path.find(':')
33 34 if c > 0:
34 35 scheme = path[:c]
35 36 thing = schemes.get(scheme) or schemes['file']
36 37 try:
37 38 return thing(path)
38 39 except TypeError:
39 40 return thing
40 41
41 42 def islocal(repo):
42 43 '''return true if repo or path is local'''
43 44 if isinstance(repo, str):
44 45 try:
45 46 return _lookup(repo).islocal(repo)
46 47 except AttributeError:
47 48 return False
48 49 return repo.local()
49 50
50 51 def repository(ui, path=None, create=False):
51 52 return _lookup(path).instance(ui, path, create)
52 53
53 54 def defaultdest(source):
54 55 '''return default destination of clone if none is given'''
55 56 return os.path.basename(os.path.normpath(source))
56 57
57 58 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
58 59 stream=False):
59 60 """Make a copy of an existing repository.
60 61
61 62 Create a copy of an existing repository in a new directory. The
62 63 source and destination are URLs, as passed to the repository
63 64 function. Returns a pair of repository objects, the source and
64 65 newly created destination.
65 66
66 67 The location of the source is added to the new repository's
67 68 .hg/hgrc file, as the default to be used for future pulls and
68 69 pushes.
69 70
70 71 If an exception is raised, the partly cloned/updated destination
71 72 repository will be deleted.
72 73
73 74 Arguments:
74 75
75 76 source: repository object or URL
76 77
77 78 dest: URL of destination repository to create (defaults to base
78 79 name of source repository)
79 80
80 81 pull: always pull from source repository, even in local case
81 82
82 83 stream: stream raw data uncompressed from repository (fast over
83 84 LAN, slow over WAN)
84 85
85 86 rev: revision to clone up to (implies pull=True)
86 87
87 88 update: update working directory after clone completes, if
88 89 destination is local repository
89 90 """
90 91 if isinstance(source, str):
91 92 src_repo = repository(ui, source)
92 93 else:
93 94 src_repo = source
94 95 source = src_repo.url()
95 96
96 97 if dest is None:
97 98 dest = defaultdest(source)
98 99
99 100 def localpath(path):
100 101 if path.startswith('file://'):
101 102 return path[7:]
102 103 if path.startswith('file:'):
103 104 return path[5:]
104 105 return path
105 106
106 107 dest = localpath(dest)
107 108 source = localpath(source)
108 109
109 110 if os.path.exists(dest):
110 111 raise util.Abort(_("destination '%s' already exists"), dest)
111 112
112 113 class DirCleanup(object):
113 114 def __init__(self, dir_):
114 115 self.rmtree = shutil.rmtree
115 116 self.dir_ = dir_
116 117 def close(self):
117 118 self.dir_ = None
118 119 def __del__(self):
119 120 if self.dir_:
120 121 self.rmtree(self.dir_, True)
121 122
122 123 dest_repo = None
123 124 try:
124 125 dest_repo = repository(ui, dest)
125 126 raise util.Abort(_("destination '%s' already exists." % dest))
126 127 except RepoError:
127 128 dest_repo = repository(ui, dest, create=True)
128 129
129 130 dest_path = None
130 131 dir_cleanup = None
131 132 if dest_repo.local():
132 133 dest_path = os.path.realpath(dest_repo.root)
133 134 dir_cleanup = DirCleanup(dest_path)
134 135
135 136 abspath = source
136 137 copy = False
137 138 if src_repo.local() and dest_repo.local():
138 139 abspath = os.path.abspath(source)
139 140 copy = not pull and not rev
140 141
141 142 src_lock, dest_lock = None, None
142 143 if copy:
143 144 try:
144 145 # we use a lock here because if we race with commit, we
145 146 # can end up with extra data in the cloned revlogs that's
146 147 # not pointed to by changesets, thus causing verify to
147 148 # fail
148 149 src_lock = src_repo.lock()
149 150 except lock.LockException:
150 151 copy = False
151 152
152 153 if copy:
153 154 # we lock here to avoid premature writing to the target
154 155 dest_lock = lock.lock(os.path.join(dest_path, ".hg", "lock"))
155 156
156 157 # we need to remove the (empty) data dir in dest so copyfiles
157 158 # can do its work
158 159 os.rmdir(os.path.join(dest_path, ".hg", "data"))
159 160 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
160 161 for f in files.split():
161 162 src = os.path.join(source, ".hg", f)
162 163 dst = os.path.join(dest_path, ".hg", f)
163 164 try:
164 165 util.copyfiles(src, dst)
165 166 except OSError, inst:
166 167 if inst.errno != errno.ENOENT:
167 168 raise
168 169
169 170 # we need to re-init the repo after manually copying the data
170 171 # into it
171 172 dest_repo = repository(ui, dest)
172 173
173 174 else:
174 175 revs = None
175 176 if rev:
176 177 if not src_repo.local():
177 178 raise util.Abort(_("clone by revision not supported yet "
178 179 "for remote repositories"))
179 180 revs = [src_repo.lookup(r) for r in rev]
180 181
181 182 if dest_repo.local():
182 183 dest_repo.clone(src_repo, heads=revs, stream=stream)
183 184 elif src_repo.local():
184 185 src_repo.push(dest_repo, revs=revs)
185 186 else:
186 187 raise util.Abort(_("clone from remote to remote not supported"))
187 188
188 189 if src_lock:
189 190 src_lock.release()
190 191
191 192 if dest_repo.local():
192 193 fp = dest_repo.opener("hgrc", "w", text=True)
193 194 fp.write("[paths]\n")
194 195 fp.write("default = %s\n" % abspath)
195 196 fp.close()
196 197
197 198 if dest_lock:
198 199 dest_lock.release()
199 200
200 201 if update:
201 202 dest_repo.update(dest_repo.changelog.tip())
202 203 if dir_cleanup:
203 204 dir_cleanup.close()
204 205
205 206 return src_repo, dest_repo
General Comments 0
You need to be logged in to leave comments. Login now