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