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