137 if cls is object: |
135 if cls is object: |
138 raise AttributeError(_("type '%s' has no property '%s'") % (origcls, |
136 raise AttributeError(_("type '%s' has no property '%s'") % (origcls, |
139 propname)) |
137 propname)) |
140 |
138 |
141 def _setupupdates(ui): |
139 def _setupupdates(ui): |
142 def _calculateupdates(orig, repo, wctx, mctx, ancestors, branchmerge, *arg, |
140 extensions.wrapfunction(mergemod, 'calculateupdates', |
143 **kwargs): |
141 sparse.calculateupdates) |
144 """Filter updates to only lay out files that match the sparse rules. |
|
145 """ |
|
146 actions, diverge, renamedelete = orig(repo, wctx, mctx, ancestors, |
|
147 branchmerge, *arg, **kwargs) |
|
148 |
|
149 oldrevs = [pctx.rev() for pctx in wctx.parents()] |
|
150 oldsparsematch = sparse.matcher(repo, oldrevs) |
|
151 |
|
152 if oldsparsematch.always(): |
|
153 return actions, diverge, renamedelete |
|
154 |
|
155 files = set() |
|
156 prunedactions = {} |
|
157 |
|
158 if branchmerge: |
|
159 # If we're merging, use the wctx filter, since we're merging into |
|
160 # the wctx. |
|
161 sparsematch = sparse.matcher(repo, [wctx.parents()[0].rev()]) |
|
162 else: |
|
163 # If we're updating, use the target context's filter, since we're |
|
164 # moving to the target context. |
|
165 sparsematch = sparse.matcher(repo, [mctx.rev()]) |
|
166 |
|
167 temporaryfiles = [] |
|
168 for file, action in actions.iteritems(): |
|
169 type, args, msg = action |
|
170 files.add(file) |
|
171 if sparsematch(file): |
|
172 prunedactions[file] = action |
|
173 elif type == 'm': |
|
174 temporaryfiles.append(file) |
|
175 prunedactions[file] = action |
|
176 elif branchmerge: |
|
177 if type != 'k': |
|
178 temporaryfiles.append(file) |
|
179 prunedactions[file] = action |
|
180 elif type == 'f': |
|
181 prunedactions[file] = action |
|
182 elif file in wctx: |
|
183 prunedactions[file] = ('r', args, msg) |
|
184 |
|
185 if len(temporaryfiles) > 0: |
|
186 ui.status(_("temporarily included %d file(s) in the sparse checkout" |
|
187 " for merging\n") % len(temporaryfiles)) |
|
188 sparse.addtemporaryincludes(repo, temporaryfiles) |
|
189 |
|
190 # Add the new files to the working copy so they can be merged, etc |
|
191 actions = [] |
|
192 message = 'temporarily adding to sparse checkout' |
|
193 wctxmanifest = repo[None].manifest() |
|
194 for file in temporaryfiles: |
|
195 if file in wctxmanifest: |
|
196 fctx = repo[None][file] |
|
197 actions.append((file, (fctx.flags(), False), message)) |
|
198 |
|
199 typeactions = collections.defaultdict(list) |
|
200 typeactions['g'] = actions |
|
201 mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], |
|
202 False) |
|
203 |
|
204 dirstate = repo.dirstate |
|
205 for file, flags, msg in actions: |
|
206 dirstate.normal(file) |
|
207 |
|
208 profiles = sparse.activeprofiles(repo) |
|
209 changedprofiles = profiles & files |
|
210 # If an active profile changed during the update, refresh the checkout. |
|
211 # Don't do this during a branch merge, since all incoming changes should |
|
212 # have been handled by the temporary includes above. |
|
213 if changedprofiles and not branchmerge: |
|
214 mf = mctx.manifest() |
|
215 for file in mf: |
|
216 old = oldsparsematch(file) |
|
217 new = sparsematch(file) |
|
218 if not old and new: |
|
219 flags = mf.flags(file) |
|
220 prunedactions[file] = ('g', (flags, False), '') |
|
221 elif old and not new: |
|
222 prunedactions[file] = ('r', [], '') |
|
223 |
|
224 return prunedactions, diverge, renamedelete |
|
225 |
|
226 extensions.wrapfunction(mergemod, 'calculateupdates', _calculateupdates) |
|
227 |
142 |
228 def _setupcommit(ui): |
143 def _setupcommit(ui): |
229 def _refreshoncommit(orig, self, node): |
144 def _refreshoncommit(orig, self, node): |
230 """Refresh the checkout when commits touch .hgsparse |
145 """Refresh the checkout when commits touch .hgsparse |
231 """ |
146 """ |