##// END OF EJS Templates
Show the destionation for clone if not specified manually.
Thomas Arendsen Hein -
r3841:aaeb7f5d default
parent child Browse files
Show More
@@ -1,256 +1,257
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 9 from node import *
10 10 from repo import *
11 11 from demandload import *
12 12 from i18n import gettext as _
13 13 demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo")
14 14 demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify")
15 15
16 16 def _local(path):
17 17 return (os.path.isfile(util.drop_scheme('file', path)) and
18 18 bundlerepo or localrepo)
19 19
20 20 schemes = {
21 21 'bundle': bundlerepo,
22 22 'file': _local,
23 23 'hg': httprepo,
24 24 'http': httprepo,
25 25 'https': httprepo,
26 26 'old-http': statichttprepo,
27 27 'ssh': sshrepo,
28 28 'static-http': statichttprepo,
29 29 }
30 30
31 31 def _lookup(path):
32 32 scheme = 'file'
33 33 if path:
34 34 c = path.find(':')
35 35 if c > 0:
36 36 scheme = path[:c]
37 37 thing = schemes.get(scheme) or schemes['file']
38 38 try:
39 39 return thing(path)
40 40 except TypeError:
41 41 return thing
42 42
43 43 def islocal(repo):
44 44 '''return true if repo or path is local'''
45 45 if isinstance(repo, str):
46 46 try:
47 47 return _lookup(repo).islocal(repo)
48 48 except AttributeError:
49 49 return False
50 50 return repo.local()
51 51
52 52 repo_setup_hooks = []
53 53
54 54 def repository(ui, path='', create=False):
55 55 """return a repository object for the specified path"""
56 56 repo = _lookup(path).instance(ui, path, create)
57 57 for hook in repo_setup_hooks:
58 58 hook(ui, repo)
59 59 return repo
60 60
61 61 def defaultdest(source):
62 62 '''return default destination of clone if none is given'''
63 63 return os.path.basename(os.path.normpath(source))
64 64
65 65 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
66 66 stream=False):
67 67 """Make a copy of an existing repository.
68 68
69 69 Create a copy of an existing repository in a new directory. The
70 70 source and destination are URLs, as passed to the repository
71 71 function. Returns a pair of repository objects, the source and
72 72 newly created destination.
73 73
74 74 The location of the source is added to the new repository's
75 75 .hg/hgrc file, as the default to be used for future pulls and
76 76 pushes.
77 77
78 78 If an exception is raised, the partly cloned/updated destination
79 79 repository will be deleted.
80 80
81 81 Arguments:
82 82
83 83 source: repository object or URL
84 84
85 85 dest: URL of destination repository to create (defaults to base
86 86 name of source repository)
87 87
88 88 pull: always pull from source repository, even in local case
89 89
90 90 stream: stream raw data uncompressed from repository (fast over
91 91 LAN, slow over WAN)
92 92
93 93 rev: revision to clone up to (implies pull=True)
94 94
95 95 update: update working directory after clone completes, if
96 96 destination is local repository
97 97 """
98 98 if isinstance(source, str):
99 99 src_repo = repository(ui, source)
100 100 else:
101 101 src_repo = source
102 102 source = src_repo.url()
103 103
104 104 if dest is None:
105 105 dest = defaultdest(source)
106 ui.status(_("destination directory: %s\n") % dest)
106 107
107 108 def localpath(path):
108 109 if path.startswith('file://'):
109 110 return path[7:]
110 111 if path.startswith('file:'):
111 112 return path[5:]
112 113 return path
113 114
114 115 dest = localpath(dest)
115 116 source = localpath(source)
116 117
117 118 if os.path.exists(dest):
118 119 raise util.Abort(_("destination '%s' already exists") % dest)
119 120
120 121 class DirCleanup(object):
121 122 def __init__(self, dir_):
122 123 self.rmtree = shutil.rmtree
123 124 self.dir_ = dir_
124 125 def close(self):
125 126 self.dir_ = None
126 127 def __del__(self):
127 128 if self.dir_:
128 129 self.rmtree(self.dir_, True)
129 130
130 131 dest_repo = repository(ui, dest, create=True)
131 132
132 133 dir_cleanup = None
133 134 if dest_repo.local():
134 135 dir_cleanup = DirCleanup(os.path.realpath(dest_repo.root))
135 136
136 137 abspath = source
137 138 copy = False
138 139 if src_repo.local() and dest_repo.local():
139 140 abspath = os.path.abspath(source)
140 141 copy = not pull and not rev
141 142
142 143 src_lock, dest_lock = None, None
143 144 if copy:
144 145 try:
145 146 # we use a lock here because if we race with commit, we
146 147 # can end up with extra data in the cloned revlogs that's
147 148 # not pointed to by changesets, thus causing verify to
148 149 # fail
149 150 src_lock = src_repo.lock()
150 151 except lock.LockException:
151 152 copy = False
152 153
153 154 if copy:
154 155 # we lock here to avoid premature writing to the target
155 156 src_store = os.path.realpath(src_repo.spath)
156 157 dest_store = os.path.realpath(dest_repo.spath)
157 158 dest_lock = lock.lock(os.path.join(dest_store, "lock"))
158 159
159 160 files = ("data",
160 161 "00manifest.d", "00manifest.i",
161 162 "00changelog.d", "00changelog.i")
162 163 for f in files:
163 164 src = os.path.join(src_store, f)
164 165 dst = os.path.join(dest_store, f)
165 166 try:
166 167 util.copyfiles(src, dst)
167 168 except OSError, inst:
168 169 if inst.errno != errno.ENOENT:
169 170 raise
170 171
171 172 # we need to re-init the repo after manually copying the data
172 173 # into it
173 174 dest_repo = repository(ui, dest)
174 175
175 176 else:
176 177 revs = None
177 178 if rev:
178 179 if 'lookup' not in src_repo.capabilities:
179 180 raise util.Abort(_("src repository does not support revision "
180 181 "lookup and so doesn't support clone by "
181 182 "revision"))
182 183 revs = [src_repo.lookup(r) for r in rev]
183 184
184 185 if dest_repo.local():
185 186 dest_repo.clone(src_repo, heads=revs, stream=stream)
186 187 elif src_repo.local():
187 188 src_repo.push(dest_repo, revs=revs)
188 189 else:
189 190 raise util.Abort(_("clone from remote to remote not supported"))
190 191
191 192 if src_lock:
192 193 src_lock.release()
193 194
194 195 if dest_repo.local():
195 196 fp = dest_repo.opener("hgrc", "w", text=True)
196 197 fp.write("[paths]\n")
197 198 fp.write("default = %s\n" % abspath)
198 199 fp.close()
199 200
200 201 if dest_lock:
201 202 dest_lock.release()
202 203
203 204 if update:
204 205 _update(dest_repo, dest_repo.changelog.tip())
205 206 if dir_cleanup:
206 207 dir_cleanup.close()
207 208
208 209 return src_repo, dest_repo
209 210
210 211 def _showstats(repo, stats):
211 212 stats = ((stats[0], _("updated")),
212 213 (stats[1], _("merged")),
213 214 (stats[2], _("removed")),
214 215 (stats[3], _("unresolved")))
215 216 note = ", ".join([_("%d files %s") % s for s in stats])
216 217 repo.ui.status("%s\n" % note)
217 218
218 219 def _update(repo, node): return update(repo, node)
219 220
220 221 def update(repo, node):
221 222 """update the working directory to node, merging linear changes"""
222 223 stats = _merge.update(repo, node, False, False, None, None)
223 224 _showstats(repo, stats)
224 225 if stats[3]:
225 226 repo.ui.status(_("There are unresolved merges with"
226 227 " locally modified files.\n"))
227 228 return stats[3]
228 229
229 230 def clean(repo, node, wlock=None, show_stats=True):
230 231 """forcibly switch the working directory to node, clobbering changes"""
231 232 stats = _merge.update(repo, node, False, True, None, wlock)
232 233 if show_stats: _showstats(repo, stats)
233 234 return stats[3]
234 235
235 236 def merge(repo, node, force=None, remind=True, wlock=None):
236 237 """branch merge with node, resolving changes"""
237 238 stats = _merge.update(repo, node, True, force, False, wlock)
238 239 _showstats(repo, stats)
239 240 if stats[3]:
240 241 pl = repo.parents()
241 242 repo.ui.status(_("There are unresolved merges,"
242 243 " you can redo the full merge using:\n"
243 244 " hg update -C %s\n"
244 245 " hg merge %s\n")
245 246 % (pl[0].rev(), pl[1].rev()))
246 247 elif remind:
247 248 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
248 249 return stats[3]
249 250
250 251 def revert(repo, node, choose, wlock):
251 252 """revert changes to revision in node without updating dirstate"""
252 253 return _merge.update(repo, node, False, True, choose, wlock)[3]
253 254
254 255 def verify(repo):
255 256 """verify the consistency of a repository"""
256 257 return _verify.verify(repo)
@@ -1,11 +1,12
1 1 abort: repository a not found!
2 2 255
3 3 abort: error: Connection refused
4 4 255
5 5 abort: repository a not found!
6 6 255
7 7 abort: destination '../a' already exists
8 8 255
9 9 abort: repository a not found!
10 10 255
11 destination directory: q
11 12 abort: destination 'q' already exists
@@ -1,15 +1,16
1 1 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2 2 a
3 3 checking changesets
4 4 checking manifests
5 5 crosschecking files in changesets and manifests
6 6 checking files
7 7 1 files, 1 changesets, 1 total revisions
8 8 a not present
9 9 checking changesets
10 10 checking manifests
11 11 crosschecking files in changesets and manifests
12 12 checking files
13 13 1 files, 1 changesets, 1 total revisions
14 destination directory: a
14 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 16 a
General Comments 0
You need to be logged in to leave comments. Login now