summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--command.py13
-rw-r--r--docs/manifest-format.txt5
-rw-r--r--error.py12
-rw-r--r--manifest_xml.py22
-rw-r--r--project.py46
-rwxr-xr-xrepo6
-rw-r--r--subcmds/init.py6
-rw-r--r--subcmds/sync.py5
8 files changed, 108 insertions, 7 deletions
diff --git a/command.py b/command.py
index 8e93787e..724e4c5d 100644
--- a/command.py
+++ b/command.py
@@ -15,9 +15,11 @@
15 15
16import os 16import os
17import optparse 17import optparse
18import re
18import sys 19import sys
19 20
20from error import NoSuchProjectError 21from error import NoSuchProjectError
22from error import InvalidProjectGroupsError
21 23
22class Command(object): 24class Command(object):
23 """Base class for any command line action in repo. 25 """Base class for any command line action in repo.
@@ -63,9 +65,16 @@ class Command(object):
63 all = self.manifest.projects 65 all = self.manifest.projects
64 result = [] 66 result = []
65 67
68 mp = self.manifest.manifestProject
69
70 groups = mp.config.GetString('manifest.groups')
71 if groups:
72 groups = re.split('[,\s]+', groups)
73
66 if not args: 74 if not args:
67 for project in all.values(): 75 for project in all.values():
68 if missing_ok or project.Exists: 76 if ((missing_ok or project.Exists) and
77 project.MatchesGroups(groups)):
69 result.append(project) 78 result.append(project)
70 else: 79 else:
71 by_path = None 80 by_path = None
@@ -102,6 +111,8 @@ class Command(object):
102 raise NoSuchProjectError(arg) 111 raise NoSuchProjectError(arg)
103 if not missing_ok and not project.Exists: 112 if not missing_ok and not project.Exists:
104 raise NoSuchProjectError(arg) 113 raise NoSuchProjectError(arg)
114 if not project.MatchesGroups(groups):
115 raise InvalidProjectGroupsError(arg)
105 116
106 result.append(project) 117 result.append(project)
107 118
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 21f19db6..a7bb1561 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -48,6 +48,7 @@ following DTD:
48 <!ATTLIST project path CDATA #IMPLIED> 48 <!ATTLIST project path CDATA #IMPLIED>
49 <!ATTLIST project remote IDREF #IMPLIED> 49 <!ATTLIST project remote IDREF #IMPLIED>
50 <!ATTLIST project revision CDATA #IMPLIED> 50 <!ATTLIST project revision CDATA #IMPLIED>
51 <!ATTLIST project groups CDATA #IMPLIED>
51 52
52 <!ELEMENT remove-project (EMPTY)> 53 <!ELEMENT remove-project (EMPTY)>
53 <!ATTLIST remove-project name CDATA #REQUIRED> 54 <!ATTLIST remove-project name CDATA #REQUIRED>
@@ -158,6 +159,10 @@ Tags and/or explicit SHA-1s should work in theory, but have not
158been extensively tested. If not supplied the revision given by 159been extensively tested. If not supplied the revision given by
159the default element is used. 160the default element is used.
160 161
162Attribute `groups`: List of groups to which this project belongs,
163whitespace or comma separated. All projects are part of the group
164"default" unless "-default" is specified in the list of groups.
165
161Element remove-project 166Element remove-project
162---------------------- 167----------------------
163 168
diff --git a/error.py b/error.py
index 812585cd..78c5c0e0 100644
--- a/error.py
+++ b/error.py
@@ -77,6 +77,18 @@ class NoSuchProjectError(Exception):
77 return 'in current directory' 77 return 'in current directory'
78 return self.name 78 return self.name
79 79
80
81class InvalidProjectGroupsError(Exception):
82 """A specified project is not suitable for the specified groups
83 """
84 def __init__(self, name=None):
85 self.name = name
86
87 def __str__(self):
88 if self.Name is None:
89 return 'in current directory'
90 return self.name
91
80class RepoChangedException(Exception): 92class RepoChangedException(Exception):
81 """Thrown if 'repo sync' results in repo updating its internal 93 """Thrown if 'repo sync' results in repo updating its internal
82 repo or manifest repositories. In this special case we must 94 repo or manifest repositories. In this special case we must
diff --git a/manifest_xml.py b/manifest_xml.py
index 44538690..a250382f 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -119,6 +119,12 @@ class XmlManifest(object):
119 def Save(self, fd, peg_rev=False): 119 def Save(self, fd, peg_rev=False):
120 """Write the current manifest out to the given file descriptor. 120 """Write the current manifest out to the given file descriptor.
121 """ 121 """
122 mp = self.manifestProject
123
124 groups = mp.config.GetString('manifest.groups')
125 if groups:
126 groups = re.split('[,\s]+', groups)
127
122 doc = xml.dom.minidom.Document() 128 doc = xml.dom.minidom.Document()
123 root = doc.createElement('manifest') 129 root = doc.createElement('manifest')
124 doc.appendChild(root) 130 doc.appendChild(root)
@@ -167,6 +173,10 @@ class XmlManifest(object):
167 173
168 for p in sort_projects: 174 for p in sort_projects:
169 p = self.projects[p] 175 p = self.projects[p]
176
177 if not p.MatchesGroups(groups):
178 continue
179
170 e = doc.createElement('project') 180 e = doc.createElement('project')
171 root.appendChild(e) 181 root.appendChild(e)
172 e.setAttribute('name', p.name) 182 e.setAttribute('name', p.name)
@@ -190,6 +200,9 @@ class XmlManifest(object):
190 ce.setAttribute('dest', c.dest) 200 ce.setAttribute('dest', c.dest)
191 e.appendChild(ce) 201 e.appendChild(ce)
192 202
203 if p.groups:
204 e.setAttribute('groups', ','.join(p.groups))
205
193 if self._repo_hooks_project: 206 if self._repo_hooks_project:
194 root.appendChild(doc.createTextNode('')) 207 root.appendChild(doc.createTextNode(''))
195 e = doc.createElement('repo-hooks') 208 e = doc.createElement('repo-hooks')
@@ -504,6 +517,12 @@ class XmlManifest(object):
504 else: 517 else:
505 rebase = rebase.lower() in ("yes", "true", "1") 518 rebase = rebase.lower() in ("yes", "true", "1")
506 519
520 groups = node.getAttribute('groups')
521 if groups:
522 groups = re.split('[,\s]+', groups)
523 else:
524 groups = None
525
507 if self.IsMirror: 526 if self.IsMirror:
508 relpath = None 527 relpath = None
509 worktree = None 528 worktree = None
@@ -520,7 +539,8 @@ class XmlManifest(object):
520 relpath = path, 539 relpath = path,
521 revisionExpr = revisionExpr, 540 revisionExpr = revisionExpr,
522 revisionId = None, 541 revisionId = None,
523 rebase = rebase) 542 rebase = rebase,
543 groups = groups)
524 544
525 for n in node.childNodes: 545 for n in node.childNodes:
526 if n.nodeName == 'copyfile': 546 if n.nodeName == 'copyfile':
diff --git a/project.py b/project.py
index 303abe33..b2eaa878 100644
--- a/project.py
+++ b/project.py
@@ -504,7 +504,8 @@ class Project(object):
504 relpath, 504 relpath,
505 revisionExpr, 505 revisionExpr,
506 revisionId, 506 revisionId,
507 rebase = True): 507 rebase = True,
508 groups = None):
508 self.manifest = manifest 509 self.manifest = manifest
509 self.name = name 510 self.name = name
510 self.remote = remote 511 self.remote = remote
@@ -524,6 +525,7 @@ class Project(object):
524 self.revisionId = revisionId 525 self.revisionId = revisionId
525 526
526 self.rebase = rebase 527 self.rebase = rebase
528 self.groups = groups
527 529
528 self.snapshots = {} 530 self.snapshots = {}
529 self.copyfiles = [] 531 self.copyfiles = []
@@ -645,6 +647,45 @@ class Project(object):
645 647
646 return heads 648 return heads
647 649
650 def MatchesGroups(self, manifest_groups):
651 """Returns true if the manifest groups specified at init should cause
652 this project to be synced.
653 Prefixing a manifest group with "-" inverts the meaning of a group.
654 All projects are implicitly labelled with "default" unless they are
655 explicitly labelled "-default".
656 If any non-inverted manifest groups are specified, the default label
657 is ignored.
658 Specifying only inverted groups implies "default".
659 """
660 project_groups = self.groups
661 if not manifest_groups:
662 return not project_groups or not "-default" in project_groups
663
664 if not project_groups:
665 project_groups = ["default"]
666 elif not ("default" in project_groups or "-default" in project_groups):
667 project_groups.append("default")
668
669 plus_groups = [x for x in manifest_groups if not x.startswith("-")]
670 minus_groups = [x[1:] for x in manifest_groups if x.startswith("-")]
671
672 if not plus_groups:
673 plus_groups.append("default")
674
675 for group in minus_groups:
676 if group in project_groups:
677 # project was excluded by -group
678 return False
679
680 for group in plus_groups:
681 if group in project_groups:
682 # project was included by group
683 return True
684
685 # groups were specified that did not include this project
686 if plus_groups:
687 return False
688 return True
648 689
649## Status Display ## 690## Status Display ##
650 691
@@ -2091,7 +2132,8 @@ class MetaProject(Project):
2091 remote = RemoteSpec('origin'), 2132 remote = RemoteSpec('origin'),
2092 relpath = '.repo/%s' % name, 2133 relpath = '.repo/%s' % name,
2093 revisionExpr = 'refs/heads/master', 2134 revisionExpr = 'refs/heads/master',
2094 revisionId = None) 2135 revisionId = None,
2136 groups = None)
2095 2137
2096 def PreSync(self): 2138 def PreSync(self):
2097 if self.Exists: 2139 if self.Exists:
diff --git a/repo b/repo
index 1977d635..75fe9ec2 100755
--- a/repo
+++ b/repo
@@ -28,7 +28,7 @@ if __name__ == '__main__':
28del magic 28del magic
29 29
30# increment this whenever we make important changes to this script 30# increment this whenever we make important changes to this script
31VERSION = (1, 14) 31VERSION = (1, 15)
32 32
33# increment this if the MAINTAINER_KEYS block is modified 33# increment this if the MAINTAINER_KEYS block is modified
34KEYRING_VERSION = (1,0) 34KEYRING_VERSION = (1,0)
@@ -125,6 +125,10 @@ group.add_option('--reference',
125group.add_option('--depth', type='int', default=None, 125group.add_option('--depth', type='int', default=None,
126 dest='depth', 126 dest='depth',
127 help='create a shallow clone with given depth; see git clone') 127 help='create a shallow clone with given depth; see git clone')
128group.add_option('-g', '--groups',
129 dest='groups', default="",
130 help='restrict manifest projects to ones with a specified group',
131 metavar='GROUP')
128 132
129 133
130# Tool 134# Tool
diff --git a/subcmds/init.py b/subcmds/init.py
index 1cba3665..6cf39d14 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -86,6 +86,10 @@ to update the working directory files.
86 g.add_option('--depth', type='int', default=None, 86 g.add_option('--depth', type='int', default=None,
87 dest='depth', 87 dest='depth',
88 help='create a shallow clone with given depth; see git clone') 88 help='create a shallow clone with given depth; see git clone')
89 g.add_option('-g', '--groups',
90 dest='groups', default="",
91 help='restrict manifest projects to ones with a specified group',
92 metavar='GROUP')
89 93
90 # Tool 94 # Tool
91 g = p.add_option_group('repo Version options') 95 g = p.add_option_group('repo Version options')
@@ -135,6 +139,8 @@ to update the working directory files.
135 r.ResetFetch() 139 r.ResetFetch()
136 r.Save() 140 r.Save()
137 141
142 m.config.SetString('manifest.groups', opt.groups)
143
138 if opt.reference: 144 if opt.reference:
139 m.config.SetString('repo.reference', opt.reference) 145 m.config.SetString('repo.reference', opt.reference)
140 146
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 74b3f183..63227afd 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -277,7 +277,7 @@ later is required to fix a server side protocol bug.
277 277
278 def UpdateProjectList(self): 278 def UpdateProjectList(self):
279 new_project_paths = [] 279 new_project_paths = []
280 for project in self.manifest.projects.values(): 280 for project in self.GetProjects(None, missing_ok=True):
281 if project.relpath: 281 if project.relpath:
282 new_project_paths.append(project.relpath) 282 new_project_paths.append(project.relpath)
283 file_name = 'project.list' 283 file_name = 'project.list'
@@ -306,7 +306,8 @@ later is required to fix a server side protocol bug.
306 worktree = os.path.join(self.manifest.topdir, path), 306 worktree = os.path.join(self.manifest.topdir, path),
307 relpath = path, 307 relpath = path,
308 revisionExpr = 'HEAD', 308 revisionExpr = 'HEAD',
309 revisionId = None) 309 revisionId = None,
310 groups = None)
310 311
311 if project.IsDirty(): 312 if project.IsDirty():
312 print >>sys.stderr, 'error: Cannot remove project "%s": \ 313 print >>sys.stderr, 'error: Cannot remove project "%s": \