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