Gentoo Archives: gentoo-commits

From: Brian Dolbec <dolsen@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:repoman commit in: pym/repoman/modules/vcs/bzr/, pym/repoman/modules/vcs/cvs/, ...
Date: Wed, 03 Feb 2016 02:11:03
Message-Id: 1454465127.30c73fe16a31683bbcc21db9583416ba4047099f.dolsen@gentoo
1 commit: 30c73fe16a31683bbcc21db9583416ba4047099f
2 Author: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
3 AuthorDate: Sat Jan 30 01:58:36 2016 +0000
4 Commit: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
5 CommitDate: Wed Feb 3 02:05:27 2016 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=30c73fe1
7
8 repoman: Migrate actions.py vcs code to the vcs modules
9
10 Add missing changes code to the existing Changes classes.
11 This removes the duplicated code in the Actions class.
12 Optimize the code for the vcs modules.
13
14 pym/repoman/actions.py | 213 +++++--------------------------
15 pym/repoman/modules/vcs/None/__init__.py | 1 +
16 pym/repoman/modules/vcs/bzr/__init__.py | 1 +
17 pym/repoman/modules/vcs/bzr/changes.py | 21 ++-
18 pym/repoman/modules/vcs/changes.py | 29 +++++
19 pym/repoman/modules/vcs/cvs/__init__.py | 1 +
20 pym/repoman/modules/vcs/cvs/changes.py | 29 ++++-
21 pym/repoman/modules/vcs/git/__init__.py | 1 +
22 pym/repoman/modules/vcs/git/changes.py | 26 +++-
23 pym/repoman/modules/vcs/hg/__init__.py | 1 +
24 pym/repoman/modules/vcs/hg/changes.py | 40 +++++-
25 pym/repoman/modules/vcs/settings.py | 5 +-
26 pym/repoman/modules/vcs/svn/__init__.py | 1 +
27 pym/repoman/modules/vcs/svn/changes.py | 38 +++++-
28 14 files changed, 190 insertions(+), 217 deletions(-)
29
30 diff --git a/pym/repoman/actions.py b/pym/repoman/actions.py
31 index 3fd940c..15a0d04 100644
32 --- a/pym/repoman/actions.py
33 +++ b/pym/repoman/actions.py
34 @@ -16,7 +16,6 @@ from itertools import chain
35 from _emerge.UserQuery import UserQuery
36
37 import portage
38 -from portage import cvstree
39 from portage import os
40 from portage import _encodings
41 from portage import _unicode_encode
42 @@ -26,8 +25,7 @@ from portage.package.ebuild.digestgen import digestgen
43 from portage.process import find_binary, spawn
44 from portage.util import writemsg_level
45
46 -from repoman._subprocess import repoman_popen, repoman_getstatusoutput
47 -from repoman.errors import err
48 +from repoman._subprocess import repoman_getstatusoutput
49 from repoman.gpg import gpgsign, need_signature
50 from repoman import utilities
51 from repoman.modules.vcs.vcs import vcs_files_to_cps
52 @@ -71,13 +69,11 @@ class Actions(object):
53
54
55 def perform(self, qa_output):
56 - myunadded, mydeleted = self._vcs_unadded()
57 + myautoadd = self._vcs_autoadd()
58
59 - myautoadd = self._vcs_autoadd(myunadded)
60 + self._vcs_deleted()
61
62 - self._vcs_deleted(mydeleted)
63 -
64 - changes = self.get_vcs_changed(mydeleted)
65 + changes = self.get_vcs_changed()
66
67 mynew, mychanged, myremoved, no_expansion, expansion = changes
68
69 @@ -127,12 +123,14 @@ class Actions(object):
70
71 print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
72
73 - if self.vcs_settings.vcs not in ('cvs', 'svn'):
74 - # With git, bzr and hg, there's never any keyword expansion, so
75 + if not self.vcs_settings.needs_keyword_expansion:
76 + # With some VCS types there's never any keyword expansion, so
77 # there's no need to regenerate manifests and all files will be
78 # committed in one big commit at the end.
79 + logging.debug("VCS type doesn't need keyword expansion")
80 print()
81 elif not self.repo_settings.repo_config.thin_manifest:
82 + logging.debug("perform: Calling thick_manifest()")
83 self.thick_manifest(myupdates, myheaders, no_expansion, expansion)
84
85 logging.info("myupdates: %s", myupdates)
86 @@ -261,62 +259,8 @@ class Actions(object):
87 sys.exit(1)
88
89
90 - def _vcs_unadded(self):
91 - myunadded = []
92 - mydeleted = []
93 - if self.vcs_settings.vcs == "cvs":
94 - try:
95 - myvcstree = portage.cvstree.getentries("./", recursive=1)
96 - myunadded = portage.cvstree.findunadded(
97 - myvcstree, recursive=1, basedir="./")
98 - except SystemExit:
99 - raise # TODO propagate this
100 - except:
101 - err("Error retrieving CVS tree; exiting.")
102 - if self.vcs_settings.vcs == "svn":
103 - try:
104 - with repoman_popen("svn status --no-ignore") as f:
105 - svnstatus = f.readlines()
106 - myunadded = [
107 - "./" + elem.rstrip().split()[1]
108 - for elem in svnstatus
109 - if elem.startswith("?") or elem.startswith("I")]
110 - except SystemExit:
111 - raise # TODO propagate this
112 - except:
113 - err("Error retrieving SVN info; exiting.")
114 - if self.vcs_settings.vcs == "git":
115 - # get list of files not under version control or missing
116 - myf = repoman_popen("git ls-files --others")
117 - myunadded = ["./" + elem[:-1] for elem in myf]
118 - myf.close()
119 - if self.vcs_settings.vcs == "bzr":
120 - try:
121 - with repoman_popen("bzr status -S .") as f:
122 - bzrstatus = f.readlines()
123 - myunadded = [
124 - "./" + elem.rstrip().split()[1].split('/')[-1:][0]
125 - for elem in bzrstatus
126 - if elem.startswith("?") or elem[0:2] == " D"]
127 - except SystemExit:
128 - raise # TODO propagate this
129 - except:
130 - err("Error retrieving bzr info; exiting.")
131 - if self.vcs_settings.vcs == "hg":
132 - with repoman_popen("hg status --no-status --unknown .") as f:
133 - myunadded = f.readlines()
134 - myunadded = ["./" + elem.rstrip() for elem in myunadded]
135 -
136 - # Mercurial doesn't handle manually deleted files as removed from
137 - # the repository, so the user need to remove them before commit,
138 - # using "hg remove [FILES]"
139 - with repoman_popen("hg status --no-status --deleted .") as f:
140 - mydeleted = f.readlines()
141 - mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
142 - return myunadded, mydeleted
143 -
144 -
145 - def _vcs_autoadd(self, myunadded):
146 + def _vcs_autoadd(self):
147 + myunadded = self.vcs_settings.changes.unadded
148 myautoadd = []
149 if myunadded:
150 for x in range(len(myunadded) - 1, -1, -1):
151 @@ -348,137 +292,38 @@ class Actions(object):
152 return myautoadd
153
154
155 - def _vcs_deleted(self, mydeleted):
156 - if self.vcs_settings.vcs == "hg" and mydeleted:
157 + def _vcs_deleted(self):
158 + if self.vcs_settings.changes.has_deleted:
159 print(red(
160 "!!! The following files are removed manually"
161 " from your local tree but are not"))
162 print(red(
163 "!!! removed from the repository."
164 - " Please remove them, using \"hg remove [FILES]\"."))
165 - for x in mydeleted:
166 + " Please remove them, using \"%s remove [FILES]\"."
167 + % self.vcs_settings.vcs))
168 + for x in self.vcs_settings.changes.deleted:
169 print(" ", x)
170 print()
171 print()
172 sys.exit(1)
173
174
175 - def get_vcs_changed(self, mydeleted):
176 + def get_vcs_changed(self):
177 '''Holding function which calls the approriate VCS module for the data'''
178 - changed = ([], [], [], [], [])
179 - if self.vcs_settings.vcs:
180 - vcs_module = getattr(self, '_get_changed_%s_' % self.vcs_settings.vcs)
181 - changed = vcs_module(mydeleted)
182 - mynew, mychanged, myremoved, no_expansion, expansion = changed
183 -
184 - a_file_is_changed = mychanged or mynew or myremoved
185 - a_file_is_deleted_hg = self.vcs_settings.vcs == "hg" and mydeleted
186 -
187 - if not (a_file_is_changed or a_file_is_deleted_hg):
188 - utilities.repoman_sez(
189 - "\"Doing nothing is not always good for QA.\"")
190 - print()
191 - print("(Didn't find any changed files...)")
192 - print()
193 - sys.exit(1)
194 - return changed
195 -
196 -
197 - def _get_changed_cvs_(self, mydeleted):
198 - mycvstree = cvstree.getentries("./", recursive=1)
199 - mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
200 - mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
201 - myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./")
202 - bin_blob_pattern = re.compile("^-kb$")
203 - no_expansion = set(portage.cvstree.findoption(
204 - mycvstree, bin_blob_pattern, recursive=1, basedir="./"))
205 - expansion = {}
206 - return (mynew, mychanged, myremoved, no_expansion, expansion)
207 -
208 - def _get_changed_svn_(self, mydeleted):
209 - with repoman_popen("svn status") as f:
210 - svnstatus = f.readlines()
211 - mychanged = [
212 - "./" + elem.split()[-1:][0]
213 - for elem in svnstatus
214 - if (elem[:1] in "MR" or elem[1:2] in "M")]
215 - mynew = [
216 - "./" + elem.split()[-1:][0]
217 - for elem in svnstatus
218 - if elem.startswith("A")]
219 - myremoved = [
220 - "./" + elem.split()[-1:][0]
221 - for elem in svnstatus
222 - if elem.startswith("D")]
223 - # Subversion expands keywords specified in svn:keywords properties.
224 - with repoman_popen("svn propget -R svn:keywords") as f:
225 - props = f.readlines()
226 - expansion = dict(
227 - ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
228 - for prop in props if " - " in prop)
229 - no_expansion = set()
230 - return (mynew, mychanged, myremoved, no_expansion, expansion)
231 -
232 - def _get_changed_git_(self, mydeleted):
233 - with repoman_popen(
234 - "git diff-index --name-only "
235 - "--relative --diff-filter=M HEAD") as f:
236 - mychanged = f.readlines()
237 - mychanged = ["./" + elem[:-1] for elem in mychanged]
238 - with repoman_popen(
239 - "git diff-index --name-only "
240 - "--relative --diff-filter=A HEAD") as f:
241 - mynew = f.readlines()
242 - mynew = ["./" + elem[:-1] for elem in mynew]
243 - with repoman_popen(
244 - "git diff-index --name-only "
245 - "--relative --diff-filter=D HEAD") as f:
246 - myremoved = f.readlines()
247 - myremoved = ["./" + elem[:-1] for elem in myremoved]
248 - no_expansion = set()
249 - expansion = {}
250 - return (mynew, mychanged, myremoved, no_expansion, expansion)
251 -
252 - def _get_changed_bzr_(self, mydeleted):
253 - with repoman_popen("bzr status -S .") as f:
254 - bzrstatus = f.readlines()
255 - mychanged = [
256 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
257 - for elem in bzrstatus
258 - if elem and elem[1:2] == "M"]
259 - mynew = [
260 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
261 - for elem in bzrstatus
262 - if elem and (elem[1:2] in "NK" or elem[0:1] == "R")]
263 - myremoved = [
264 - "./" + elem.split()[-1:][0].split('/')[-1:][0]
265 - for elem in bzrstatus
266 - if elem.startswith("-")]
267 - myremoved = [
268 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
269 - for elem in bzrstatus
270 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
271 - # Bazaar expands nothing.
272 - no_expansion = set()
273 - expansion = {}
274 - return (mynew, mychanged, myremoved, no_expansion, expansion)
275 -
276 - def _get_changed_hg_(self, mydeleted):
277 - with repoman_popen("hg status --no-status --modified .") as f:
278 - mychanged = f.readlines()
279 - mychanged = ["./" + elem.rstrip() for elem in mychanged]
280 -
281 - with repoman_popen("hg status --no-status --added .") as f:
282 - mynew = f.readlines()
283 - mynew = ["./" + elem.rstrip() for elem in mynew]
284 -
285 - with repoman_popen("hg status --no-status --removed .") as f:
286 - myremoved = f.readlines()
287 - myremoved = ["./" + elem.rstrip() for elem in myremoved]
288 - no_expansion = set()
289 - expansion = {}
290 - return (mynew, mychanged, myremoved, no_expansion, expansion)
291 + changes = self.vcs_settings.changes
292 + # re-run the scan to pick up a newly modified Manifest file
293 + logging.debug("RE-scanning for changes...")
294 + changes.scan()
295
296 + if not changes.has_changes:
297 + utilities.repoman_sez(
298 + "\"Doing nothing is not always good for QA.\"")
299 + print()
300 + print("(Didn't find any changed files...)")
301 + print()
302 + sys.exit(1)
303 + return (changes.new, changes.changed, changes.removed,
304 + changes.no_expansion, changes.expansion)
305
306 def get_commit_footer(self):
307 portage_version = getattr(portage, "VERSION", None)
308
309 diff --git a/pym/repoman/modules/vcs/None/__init__.py b/pym/repoman/modules/vcs/None/__init__.py
310 index 4146e1e..2859325 100644
311 --- a/pym/repoman/modules/vcs/None/__init__.py
312 +++ b/pym/repoman/modules/vcs/None/__init__.py
313 @@ -19,6 +19,7 @@ module_spec = {
314 'func_desc': {
315 },
316 'vcs_preserves_mtime': False,
317 + 'needs_keyword_expansion': False,
318 },
319 'None-changes': {
320 'name': "None_changes",
321
322 diff --git a/pym/repoman/modules/vcs/bzr/__init__.py b/pym/repoman/modules/vcs/bzr/__init__.py
323 index ccdbddf..1192782 100644
324 --- a/pym/repoman/modules/vcs/bzr/__init__.py
325 +++ b/pym/repoman/modules/vcs/bzr/__init__.py
326 @@ -19,6 +19,7 @@ module_spec = {
327 'func_desc': {
328 },
329 'vcs_preserves_mtime': True,
330 + 'needs_keyword_expansion': False,
331 },
332 'bzr-changes': {
333 'name': "bzr_changes",
334
335 diff --git a/pym/repoman/modules/vcs/bzr/changes.py b/pym/repoman/modules/vcs/bzr/changes.py
336 index 0f70613..41ce347 100644
337 --- a/pym/repoman/modules/vcs/bzr/changes.py
338 +++ b/pym/repoman/modules/vcs/bzr/changes.py
339 @@ -25,8 +25,19 @@ class Changes(ChangesBase):
340 "./" + elem.split()[-1:][0].split('/')[-1:][0]
341 for elem in bzrstatus
342 if elem and (elem[1:2] == "NK" or elem[0:1] == "R")]
343 - if self.options.if_modified == "y":
344 - self.removed = [
345 - "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
346 - for elem in bzrstatus
347 - if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
348 + self.removed = [
349 + "./" + elem.split()[-3:-2][0].split('/')[-1:][0]
350 + for elem in bzrstatus
351 + if elem and (elem[1:2] == "K" or elem[0:1] == "R")]
352 + # Bazaar expands nothing.
353 +
354 + @property
355 + def unadded(self):
356 + '''Bazzar method of getting the unadded files in the repository'''
357 + if self._unadded is not None:
358 + return self._unadded
359 + self._unadded = [
360 + "./" + elem.rstrip().split()[1].split('/')[-1:][0]
361 + for elem in bzrstatus
362 + if elem.startswith("?") or elem[0:2] == " D"]
363 + return self._unadded
364
365 diff --git a/pym/repoman/modules/vcs/changes.py b/pym/repoman/modules/vcs/changes.py
366 index 6553ac9..6eefaed 100644
367 --- a/pym/repoman/modules/vcs/changes.py
368 +++ b/pym/repoman/modules/vcs/changes.py
369 @@ -21,6 +21,10 @@ class ChangesBase(object):
370 self.changed = []
371 self.new = []
372 self.removed = []
373 + self.no_expansion = set()
374 + self._expansion = None
375 + self._deleted = None
376 + self._unadded = None
377
378 def scan(self):
379 self._reset()
380 @@ -37,3 +41,28 @@ class ChangesBase(object):
381 '''Placeholder for subclassing'''
382 pass
383
384 + @property
385 + def has_deleted(self):
386 + '''Placeholder for VCS that requires manual deletion of files'''
387 + return self.deleted != []
388 +
389 + @property
390 + def has_changes(self):
391 + '''Placeholder for VCS repo common has changes result'''
392 + changed = self.changed or self.new or self.removed or self.deleted
393 + return changed != []
394 +
395 + @property
396 + def unadded(self):
397 + '''Override this function as needed'''
398 + return []
399 +
400 + @property
401 + def deleted(self):
402 + '''Override this function as needed'''
403 + return []
404 +
405 + @property
406 + def expansion(self):
407 + '''Override this function as needed'''
408 + return {}
409
410 diff --git a/pym/repoman/modules/vcs/cvs/__init__.py b/pym/repoman/modules/vcs/cvs/__init__.py
411 index 6db6078..ba60e2c 100644
412 --- a/pym/repoman/modules/vcs/cvs/__init__.py
413 +++ b/pym/repoman/modules/vcs/cvs/__init__.py
414 @@ -19,6 +19,7 @@ module_spec = {
415 'func_desc': {
416 },
417 'vcs_preserves_mtime': True,
418 + 'needs_keyword_expansion': True,
419 },
420 'cvs-changes': {
421 'name': "cvs_changes",
422
423 diff --git a/pym/repoman/modules/vcs/cvs/changes.py b/pym/repoman/modules/vcs/cvs/changes.py
424 index f0893a1..cdfb4b2 100644
425 --- a/pym/repoman/modules/vcs/cvs/changes.py
426 +++ b/pym/repoman/modules/vcs/cvs/changes.py
427 @@ -1,7 +1,11 @@
428
429
430 -from portage import cvstree
431 +import re
432 +
433 +from repoman._portage import portage
434 from repoman.modules.vcs.changes import ChangesBase
435 +from portage import cvstree
436 +
437
438 class Changes(ChangesBase):
439 '''Class object to scan and hold the resultant data
440 @@ -12,11 +16,22 @@ class Changes(ChangesBase):
441
442 def __init__(self, options):
443 super(Changes, self).__init__(options)
444 + self._tree = None
445
446 def _scan(self):
447 - tree = cvstree.getentries("./", recursive=1)
448 - self.changed = cvstree.findchanged(tree, recursive=1, basedir="./")
449 - self.new = cvstree.findnew(tree, recursive=1, basedir="./")
450 - if self.options.if_modified == "y":
451 - self.removed = cvstree.findremoved(tree, recursive=1, basedir="./")
452 - del tree
453 + '''VCS type scan function, looks for all detectable changes'''
454 + self._tree = portage.cvstree.getentries("./", recursive=1)
455 + self.changed = cvstree.findchanged(self._tree, recursive=1, basedir="./")
456 + self.new = cvstree.findnew(self._tree, recursive=1, basedir="./")
457 + self.removed = cvstree.findremoved(self._tree, recursive=1, basedir="./")
458 + bin_blob_pattern = re.compile("^-kb$")
459 + self.no_expansion = set(portage.cvstree.findoption(
460 + self._tree, bin_blob_pattern, recursive=1, basedir="./"))
461 +
462 + @property
463 + def unadded(self):
464 + '''VCS method of getting the unadded files in the repository'''
465 + if self._unadded is not None:
466 + return self._unadded
467 + self._unadded = portage.cvstree.findunadded(self._tree, recursive=1, basedir="./")
468 + return self._unadded
469
470 diff --git a/pym/repoman/modules/vcs/git/__init__.py b/pym/repoman/modules/vcs/git/__init__.py
471 index 4e1d599..e077767 100644
472 --- a/pym/repoman/modules/vcs/git/__init__.py
473 +++ b/pym/repoman/modules/vcs/git/__init__.py
474 @@ -19,6 +19,7 @@ module_spec = {
475 'func_desc': {
476 },
477 'vcs_preserves_mtime': False,
478 + 'needs_keyword_expansion': False,
479 },
480 'git-changes': {
481 'name': "git_changes",
482
483 diff --git a/pym/repoman/modules/vcs/git/changes.py b/pym/repoman/modules/vcs/git/changes.py
484 index 6ee39a0..0342251 100644
485 --- a/pym/repoman/modules/vcs/git/changes.py
486 +++ b/pym/repoman/modules/vcs/git/changes.py
487 @@ -27,11 +27,23 @@ class Changes(ChangesBase):
488 "--relative --diff-filter=A HEAD") as f:
489 new = f.readlines()
490 self.new = ["./" + elem[:-1] for elem in new]
491 - if self.options.if_modified == "y":
492 - with repoman_popen(
493 - "git diff-index --name-only "
494 - "--relative --diff-filter=D HEAD") as f:
495 - removed = f.readlines()
496 - self.removed = ["./" + elem[:-1] for elem in removed]
497 - del removed
498 + del new
499
500 + with repoman_popen(
501 + "git diff-index --name-only "
502 + "--relative --diff-filter=D HEAD") as f:
503 + removed = f.readlines()
504 + self.removed = ["./" + elem[:-1] for elem in removed]
505 + del removed
506 +
507 + @property
508 + def unadded(self):
509 + '''VCS method of getting the unadded files in the repository'''
510 + if self._unadded is not None:
511 + return self._unadded
512 + # get list of files not under version control or missing
513 + with repoman_popen("git ls-files --others") as f:
514 + unadded = f.readlines()
515 + self._unadded = ["./" + elem[:-1] for elem in unadded]
516 + del unadded
517 + return self._unadded
518
519 diff --git a/pym/repoman/modules/vcs/hg/__init__.py b/pym/repoman/modules/vcs/hg/__init__.py
520 index 6f8a376..6737dfb 100644
521 --- a/pym/repoman/modules/vcs/hg/__init__.py
522 +++ b/pym/repoman/modules/vcs/hg/__init__.py
523 @@ -19,6 +19,7 @@ module_spec = {
524 'func_desc': {
525 },
526 'vcs_preserves_mtime': False,
527 + 'needs_keyword_expansion': False,
528 },
529 'hg-changes': {
530 'name': "hg_changes",
531
532 diff --git a/pym/repoman/modules/vcs/hg/changes.py b/pym/repoman/modules/vcs/hg/changes.py
533 index 86dffff..f4e1ec8 100644
534 --- a/pym/repoman/modules/vcs/hg/changes.py
535 +++ b/pym/repoman/modules/vcs/hg/changes.py
536 @@ -18,12 +18,40 @@ class Changes(ChangesBase):
537 with repoman_popen("hg status --no-status --modified .") as f:
538 changed = f.readlines()
539 self.changed = ["./" + elem.rstrip() for elem in changed]
540 + del changed
541 +
542 with repoman_popen("hg status --no-status --added .") as f:
543 new = f.readlines()
544 self.new = ["./" + elem.rstrip() for elem in new]
545 - if self.options.if_modified == "y":
546 - with repoman_popen("hg status --no-status --removed .") as f:
547 - removed = f.readlines()
548 - self.removed = ["./" + elem.rstrip() for elem in removed]
549 - del removed
550 - del changed, new
551 + del new
552 +
553 + with repoman_popen("hg status --no-status --removed .") as f:
554 + removed = f.readlines()
555 + self.removed = ["./" + elem.rstrip() for elem in removed]
556 + del removed
557 +
558 + @property
559 + def unadded(self):
560 + '''VCS method of getting the unadded files in the repository'''
561 + if self._unadded is not None:
562 + return self._unadded
563 + with repoman_popen("hg status --no-status --unknown .") as f:
564 + unadded = f.readlines()
565 + self._unadded = ["./" + elem.rstrip() for elem in unadded]
566 + del unadded
567 + return self._unadded
568 +
569 + @property
570 + def deleted(self):
571 + '''VCS method of getting the deleted files in the repository'''
572 + if self._deleted is not None:
573 + return self._deleted
574 + # Mercurial doesn't handle manually deleted files as removed from
575 + # the repository, so the user need to remove them before commit,
576 + # using "hg remove [FILES]"
577 + with repoman_popen("hg status --no-status --deleted .") as f:
578 + deleted = f.readlines()
579 + self._deleted = ["./" + elem.rstrip() for elem in deleted]
580 + del deleted
581 + return self._deleted
582 +
583
584 diff --git a/pym/repoman/modules/vcs/settings.py b/pym/repoman/modules/vcs/settings.py
585 index 34f1c78..bcd5f18 100644
586 --- a/pym/repoman/modules/vcs/settings.py
587 +++ b/pym/repoman/modules/vcs/settings.py
588 @@ -4,7 +4,6 @@ from __future__ import print_function, unicode_literals
589 import logging
590 import sys
591
592 -from repoman._portage import portage
593 from portage.output import red
594 from repoman.modules.vcs import module_controller, module_names
595 from repoman.modules.vcs.vcs import FindVCS
596 @@ -58,6 +57,8 @@ class VCSSettings(object):
597 logging.error("VCSSettings: Unknown VCS type: %s", self.vcs)
598 logging.error("Available modules: %s", module_controller.parents)
599
600 + self.needs_keyword_expansion = module_controller.modules[
601 + "%s_status" % self.vcs]['needs_keyword_expansion']
602 self.vcs_local_opts = repoman_settings.get(
603 "REPOMAN_VCS_LOCAL_OPTS", "").split()
604 self.vcs_global_opts = repoman_settings.get(
605 @@ -88,5 +89,5 @@ class VCSSettings(object):
606 def changes(self):
607 if not self._changes:
608 changes = self.module_controller.get_class('%s_changes' % self.vcs)
609 - self._changes = changes(self.options)
610 + self._changes = changes(self.options, self.vcs)
611 return self._changes
612
613 diff --git a/pym/repoman/modules/vcs/svn/__init__.py b/pym/repoman/modules/vcs/svn/__init__.py
614 index 41e481a..becb93e 100644
615 --- a/pym/repoman/modules/vcs/svn/__init__.py
616 +++ b/pym/repoman/modules/vcs/svn/__init__.py
617 @@ -19,6 +19,7 @@ module_spec = {
618 'func_desc': {
619 },
620 'vcs_preserves_mtime': False,
621 + 'needs_keyword_expansion': True,
622 },
623 'svn-changes': {
624 'name': "svn_changes",
625
626 diff --git a/pym/repoman/modules/vcs/svn/changes.py b/pym/repoman/modules/vcs/svn/changes.py
627 index 3567b61..639ee9f 100644
628 --- a/pym/repoman/modules/vcs/svn/changes.py
629 +++ b/pym/repoman/modules/vcs/svn/changes.py
630 @@ -25,9 +25,35 @@ class Changes(ChangesBase):
631 "./" + elem.split()[-1:][0]
632 for elem in svnstatus
633 if elem.startswith("A")]
634 - if self.options.if_modified == "y":
635 - self.removed = [
636 - "./" + elem.split()[-1:][0]
637 - for elem in svnstatus
638 - if elem.startswith("D")]
639 -
640 + self.removed = [
641 + "./" + elem.split()[-1:][0]
642 + for elem in svnstatus
643 + if elem.startswith("D")]
644 +
645 + @property
646 + def expansion(self):
647 + '''VCS method of getting the expanded keywords in the repository'''
648 + if self._expansion is not None:
649 + return self._expansion
650 + # Subversion expands keywords specified in svn:keywords properties.
651 + with repoman_popen("svn propget -R svn:keywords") as f:
652 + props = f.readlines()
653 + self._expansion = dict(
654 + ("./" + prop.split(" - ")[0], prop.split(" - ")[1].split())
655 + for prop in props if " - " in prop)
656 + del props
657 + return self._expansion
658 +
659 + @property
660 + def unadded(self):
661 + '''VCS method of getting the unadded files in the repository'''
662 + if self._unadded is not None:
663 + return self._unadded
664 + with repoman_popen("svn status --no-ignore") as f:
665 + svnstatus = f.readlines()
666 + self._unadded = [
667 + "./" + elem.rstrip().split()[1]
668 + for elem in svnstatus
669 + if elem.startswith("?") or elem.startswith("I")]
670 + del svnstatus
671 + return self._unadded