Show More
@@ -956,107 +956,15 b' def clone(ui, source, dest=None, **opts)' | |||||
956 | .hg/hgrc will be created on the remote side. Look at the help text |
|
956 | .hg/hgrc will be created on the remote side. Look at the help text | |
957 | for the pull command for important details about ssh:// URLs. |
|
957 | for the pull command for important details about ssh:// URLs. | |
958 | """ |
|
958 | """ | |
959 | if dest is None: |
|
|||
960 | dest = os.path.basename(os.path.normpath(source)) |
|
|||
961 |
|
||||
962 | if os.path.exists(dest): |
|
|||
963 | raise util.Abort(_("destination '%s' already exists"), dest) |
|
|||
964 |
|
||||
965 | class Dircleanup(object): |
|
|||
966 | def __init__(self, dir_): |
|
|||
967 | self.rmtree = shutil.rmtree |
|
|||
968 | self.dir_ = dir_ |
|
|||
969 | def close(self): |
|
|||
970 | self.dir_ = None |
|
|||
971 | def __del__(self): |
|
|||
972 | if self.dir_: |
|
|||
973 | self.rmtree(self.dir_, True) |
|
|||
974 |
|
||||
975 | if opts['ssh']: |
|
959 | if opts['ssh']: | |
976 | ui.setconfig("ui", "ssh", opts['ssh']) |
|
960 | ui.setconfig("ui", "ssh", opts['ssh']) | |
977 | if opts['remotecmd']: |
|
961 | if opts['remotecmd']: | |
978 | ui.setconfig("ui", "remotecmd", opts['remotecmd']) |
|
962 | ui.setconfig("ui", "remotecmd", opts['remotecmd']) | |
979 |
|
963 | |||
980 |
|
|
964 | hg.clone(ui, ui.expandpath(source), dest, | |
981 | src_repo = hg.repository(ui, source) |
|
965 | pull=opts['pull'], | |
982 |
|
966 | rev=opts['rev'], | ||
983 | dest_repo = None |
|
967 | update=not opts['noupdate']) | |
984 | try: |
|
|||
985 | dest_repo = hg.repository(ui, dest) |
|
|||
986 | raise util.Abort(_("destination '%s' already exists." % dest)) |
|
|||
987 | except hg.RepoError: |
|
|||
988 | dest_repo = hg.repository(ui, dest, create=1) |
|
|||
989 |
|
||||
990 | dest_path = None |
|
|||
991 | d = None |
|
|||
992 | if dest_repo.local(): |
|
|||
993 | dest_path = os.path.realpath(dest) |
|
|||
994 | d = Dircleanup(dest_path) |
|
|||
995 |
|
||||
996 | abspath = source |
|
|||
997 | copy = False |
|
|||
998 | if src_repo.local() and dest_repo.local(): |
|
|||
999 | abspath = os.path.abspath(source) |
|
|||
1000 | if not opts['pull'] and not opts['rev']: |
|
|||
1001 | copy = True |
|
|||
1002 |
|
||||
1003 | if copy: |
|
|||
1004 | try: |
|
|||
1005 | # we use a lock here because if we race with commit, we |
|
|||
1006 | # can end up with extra data in the cloned revlogs that's |
|
|||
1007 | # not pointed to by changesets, thus causing verify to |
|
|||
1008 | # fail |
|
|||
1009 | l1 = src_repo.lock() |
|
|||
1010 | except lock.LockException: |
|
|||
1011 | copy = False |
|
|||
1012 |
|
||||
1013 | if copy: |
|
|||
1014 | # we lock here to avoid premature writing to the target |
|
|||
1015 | l2 = lock.lock(os.path.join(dest_path, ".hg", "lock")) |
|
|||
1016 |
|
||||
1017 | # we need to remove the (empty) data dir in dest so copyfiles can do it's work |
|
|||
1018 | os.rmdir( os.path.join(dest_path, ".hg", "data") ) |
|
|||
1019 | files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i" |
|
|||
1020 | for f in files.split(): |
|
|||
1021 | src = os.path.join(source, ".hg", f) |
|
|||
1022 | dst = os.path.join(dest_path, ".hg", f) |
|
|||
1023 | try: |
|
|||
1024 | util.copyfiles(src, dst) |
|
|||
1025 | except OSError, inst: |
|
|||
1026 | if inst.errno != errno.ENOENT: |
|
|||
1027 | raise |
|
|||
1028 |
|
||||
1029 | # we need to re-init the repo after manually copying the data into it |
|
|||
1030 | dest_repo = hg.repository(ui, dest) |
|
|||
1031 |
|
||||
1032 | else: |
|
|||
1033 | revs = None |
|
|||
1034 | if opts['rev']: |
|
|||
1035 | if not src_repo.local(): |
|
|||
1036 | error = _("clone -r not supported yet for remote repositories.") |
|
|||
1037 | raise util.Abort(error) |
|
|||
1038 | else: |
|
|||
1039 | revs = [src_repo.lookup(rev) for rev in opts['rev']] |
|
|||
1040 |
|
||||
1041 | if dest_repo.local(): |
|
|||
1042 | dest_repo.pull(src_repo, heads = revs) |
|
|||
1043 | elif src_repo.local(): |
|
|||
1044 | src_repo.push(dest_repo, revs = revs) |
|
|||
1045 | else: |
|
|||
1046 | error = _("clone from remote to remote not supported.") |
|
|||
1047 | raise util.Abort(error) |
|
|||
1048 |
|
||||
1049 | if dest_repo.local(): |
|
|||
1050 | f = dest_repo.opener("hgrc", "w", text=True) |
|
|||
1051 | f.write("[paths]\n") |
|
|||
1052 | f.write("default = %s\n" % abspath) |
|
|||
1053 | f.close() |
|
|||
1054 |
|
||||
1055 | if not opts['noupdate']: |
|
|||
1056 | doupdate(dest_repo.ui, dest_repo) |
|
|||
1057 |
|
||||
1058 | if d: |
|
|||
1059 | d.close() |
|
|||
1060 |
|
968 | |||
1061 | def commit(ui, repo, *pats, **opts): |
|
969 | def commit(ui, repo, *pats, **opts): | |
1062 | """commit the specified files or all outstanding changes |
|
970 | """commit the specified files or all outstanding changes |
@@ -10,7 +10,7 b' 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(), "os util") |
|
13 | demandload(globals(), "errno lock os shutil util") | |
14 |
|
14 | |||
15 | def bundle(ui, path): |
|
15 | def bundle(ui, path): | |
16 | if path.startswith('bundle://'): |
|
16 | if path.startswith('bundle://'): | |
@@ -73,3 +73,133 b' def repository(ui, path=None, create=0):' | |||||
73 | raise util.Abort(_('cannot create new repository over "%s" protocol') % |
|
73 | raise util.Abort(_('cannot create new repository over "%s" protocol') % | |
74 | scheme) |
|
74 | scheme) | |
75 | return ctor(ui, path) |
|
75 | return ctor(ui, path) | |
|
76 | ||||
|
77 | def clone(ui, source, dest=None, pull=False, rev=None, update=True): | |||
|
78 | """Make a copy of an existing repository. | |||
|
79 | ||||
|
80 | Create a copy of an existing repository in a new directory. The | |||
|
81 | source and destination are URLs, as passed to the repository | |||
|
82 | function. Returns a pair of repository objects, the source and | |||
|
83 | newly created destination. | |||
|
84 | ||||
|
85 | The location of the source is added to the new repository's | |||
|
86 | .hg/hgrc file, as the default to be used for future pulls and | |||
|
87 | pushes. | |||
|
88 | ||||
|
89 | If an exception is raised, the partly cloned/updated destination | |||
|
90 | repository will be deleted. | |||
|
91 | ||||
|
92 | Keyword arguments: | |||
|
93 | ||||
|
94 | dest: URL of destination repository to create (defaults to base | |||
|
95 | name of source repository) | |||
|
96 | ||||
|
97 | pull: always pull from source repository, even in local case | |||
|
98 | ||||
|
99 | rev: revision to clone up to (implies pull=True) | |||
|
100 | ||||
|
101 | update: update working directory after clone completes, if | |||
|
102 | destination is local repository | |||
|
103 | """ | |||
|
104 | if dest is None: | |||
|
105 | dest = os.path.basename(os.path.normpath(source)) | |||
|
106 | ||||
|
107 | if os.path.exists(dest): | |||
|
108 | raise util.Abort(_("destination '%s' already exists"), dest) | |||
|
109 | ||||
|
110 | class DirCleanup(object): | |||
|
111 | def __init__(self, dir_): | |||
|
112 | self.rmtree = shutil.rmtree | |||
|
113 | self.dir_ = dir_ | |||
|
114 | def close(self): | |||
|
115 | self.dir_ = None | |||
|
116 | def __del__(self): | |||
|
117 | if self.dir_: | |||
|
118 | self.rmtree(self.dir_, True) | |||
|
119 | ||||
|
120 | src_repo = repository(ui, source) | |||
|
121 | ||||
|
122 | dest_repo = None | |||
|
123 | try: | |||
|
124 | dest_repo = repository(ui, dest) | |||
|
125 | raise util.Abort(_("destination '%s' already exists." % dest)) | |||
|
126 | except RepoError: | |||
|
127 | dest_repo = repository(ui, dest, create=True) | |||
|
128 | ||||
|
129 | dest_path = None | |||
|
130 | dir_cleanup = None | |||
|
131 | if dest_repo.local(): | |||
|
132 | dest_path = os.path.realpath(dest) | |||
|
133 | dir_cleanup = DirCleanup(dest_path) | |||
|
134 | ||||
|
135 | abspath = source | |||
|
136 | copy = False | |||
|
137 | if src_repo.local() and dest_repo.local(): | |||
|
138 | abspath = os.path.abspath(source) | |||
|
139 | copy = not pull and not rev | |||
|
140 | ||||
|
141 | src_lock, dest_lock = None, None | |||
|
142 | if copy: | |||
|
143 | try: | |||
|
144 | # 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 | # not pointed to by changesets, thus causing verify to | |||
|
147 | # fail | |||
|
148 | src_lock = src_repo.lock() | |||
|
149 | except lock.LockException: | |||
|
150 | copy = False | |||
|
151 | ||||
|
152 | if copy: | |||
|
153 | # we lock here to avoid premature writing to the target | |||
|
154 | dest_lock = lock.lock(os.path.join(dest_path, ".hg", "lock")) | |||
|
155 | ||||
|
156 | # we need to remove the (empty) data dir in dest so copyfiles | |||
|
157 | # can do its work | |||
|
158 | os.rmdir(os.path.join(dest_path, ".hg", "data")) | |||
|
159 | files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i" | |||
|
160 | for f in files.split(): | |||
|
161 | src = os.path.join(source, ".hg", f) | |||
|
162 | dst = os.path.join(dest_path, ".hg", f) | |||
|
163 | try: | |||
|
164 | util.copyfiles(src, dst) | |||
|
165 | except OSError, inst: | |||
|
166 | if inst.errno != errno.ENOENT: | |||
|
167 | raise | |||
|
168 | ||||
|
169 | # we need to re-init the repo after manually copying the data | |||
|
170 | # into it | |||
|
171 | dest_repo = repository(ui, dest) | |||
|
172 | ||||
|
173 | else: | |||
|
174 | revs = None | |||
|
175 | if rev: | |||
|
176 | if not src_repo.local(): | |||
|
177 | raise util.Abort(_("clone by revision not supported yet " | |||
|
178 | "for remote repositories")) | |||
|
179 | revs = [src_repo.lookup(r) for r in rev] | |||
|
180 | ||||
|
181 | if dest_repo.local(): | |||
|
182 | dest_repo.pull(src_repo, heads=revs) | |||
|
183 | elif src_repo.local(): | |||
|
184 | src_repo.push(dest_repo, revs=revs) | |||
|
185 | else: | |||
|
186 | raise util.Abort(_("clone from remote to remote not supported")) | |||
|
187 | ||||
|
188 | if src_lock: | |||
|
189 | src_lock.release() | |||
|
190 | ||||
|
191 | if dest_repo.local(): | |||
|
192 | fp = dest_repo.opener("hgrc", "w", text=True) | |||
|
193 | fp.write("[paths]\n") | |||
|
194 | fp.write("default = %s\n" % abspath) | |||
|
195 | fp.close() | |||
|
196 | ||||
|
197 | if dest_lock: | |||
|
198 | dest_lock.release() | |||
|
199 | ||||
|
200 | if update: | |||
|
201 | dest_repo.update(dest_repo.changelog.tip()) | |||
|
202 | if dir_cleanup: | |||
|
203 | dir_cleanup.close() | |||
|
204 | ||||
|
205 | return src_repo, dest_repo |
General Comments 0
You need to be logged in to leave comments.
Login now