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