3 # This is a replacement for the formerly bash-written function pl_parsePkgs ()
5 # Usage: $0 [-a arch] default_arch keyword fcdistro pldistro pkgs-file[..s]
6 # default_arch is $pl_DISTRO_ARCH, but can be overridden
9 #################### original language was (in this example, keyword=package)
10 ## to add to all distros
12 ## to add in one distro
14 ## to remove in one distro
16 #################### replacement language
21 ## add in fedora distros starting with f10
22 # +package>=f10: p1 p2
25 ## ditto but remove instead
26 # -package=centos5: p1 p2
27 # -package<=centos5: p1 p2
29 from __future__ import print_function
32 from sys import stderr
33 from optparse import OptionParser
37 known_arch = ['i386', 'i686', 'x86_64']
38 default_fcdistro = 'f23'
41 # oldies but we have references to that in the pkgs files
42 'f8', 'f10', 'f12', 'f16',
43 # these ones are still relevant
44 'f14', 'f18', 'f20', 'f21', 'f22', 'f23',
49 'precise', # 12.04 LTS
55 default_pldistro='onelab'
58 'group', 'groupname', 'groupdesc',
59 'package', 'pip', 'gem',
60 'nodeyumexclude', 'plcyumexclude', 'yumexclude',
61 'precious', 'junk', 'mirror',
65 m_fcdistro_cutter = re.compile('([a-z]+)([0-9]+)')
70 def __init__(self, arch, fcdistro, pldistro, keyword, inputs, options):
72 self.fcdistro = fcdistro
73 self.pldistro = pldistro
74 self.keyword = keyword
76 # for verbose, new_line, and the like
77 self.options = options
79 for known in known_fcdistros:
82 (distro, version) = m_fcdistro_cutter.match(fcdistro).groups()
83 # debian-like names can't use numbering
90 self.version = int(version)
92 print('unrecognized fcdistro', fcdistro, file=stderr)
95 # qualifier is either '>=','<=', or '='
96 def match (self, qualifier, version):
98 return self.version == version
99 elif qualifier == '>=':
100 return self.version >= version
101 elif qualifier == '<=':
102 return self.version <= version
104 raise Exception('Internal error - unexpected qualifier {qualifier}'.format(**locals()))
106 m_comment = re.compile('\A\s*#')
107 m_blank = re.compile('\A\s*\Z')
109 m_ident = re.compile('\A'+re_ident+'\Z')
111 re_qualified += '(?P<plus_minus>[+-]?)'
112 re_qualified += '\s*'
113 re_qualified += '(?P<keyword>{re_ident})'.format(re_ident=re_ident)
114 re_qualified += '\s*'
115 re_qualified += '(?P<qualifier>>=|<=|=)'
116 re_qualified += '\s*'
117 re_qualified += '(?P<fcdistro>{re_ident}[0-9]+)'.format(re_ident=re_ident)
118 re_qualified += '\s*'
119 m_qualified = re.compile('\A{re_qualified}\Z'.format(**locals()))
121 re_old = '[a-z]+[+-][a-z]+[0-9]+'
122 m_old = re.compile('\A{re_old}\Z'.format(**locals()))
124 # returns a tuple (included, excluded)
125 def parse(self, filename):
131 for line in file(filename).readlines():
134 if self.m_comment.match(line) or self.m_blank.match(line):
137 lefts, rights = line.split(':', 1)
138 for left in lefts.split():
139 ########## single ident
140 if self.m_ident.match(left):
141 if left not in known_keywords:
142 raise Exception("Unknown keyword {left}".format(**locals()))
143 elif left == self.keyword:
144 included += rights.split()
146 m = self.m_qualified.match(left)
148 (plus_minus, kw, qual, fcdistro) = m.groups()
149 if kw not in known_keywords:
150 raise Exception("Unknown keyword in {left}".format(**locals()))
151 if fcdistro not in known_fcdistros:
152 raise Exception('Unknown fcdistro {fcdistro}'.format(**locals()))
153 # skip if another keyword
154 if kw != self.keyword: continue
155 # does this fcdistro match ?
156 (distro, version) = m_fcdistro_cutter.match(fcdistro).groups()
157 version = int (version)
158 # skip if another distro family
159 if distro != self.distro: continue
160 # skip if the qualifier does not fit
161 if not self.match (qual, version):
162 if self.options.verbose:
163 print('{filename}:{lineno}:qualifer {left} does not apply'
164 .format(**locals()), file=stderr)
166 # we're in, let's add (default) or remove (if plus_minus is minus)
167 if plus_minus == '-':
168 if self.options.verbose:
169 print('{filename}:{lineno}: from {left}, excluding {rights}'
170 .format(**locals()), file=stderr)
171 excluded += rights.split()
173 if self.options.verbose:
174 print('{filename}:{lineno}: from {left}, including {rights}'\
175 .format(**locals()), file=stderr)
176 included += rights.split()
177 elif self.m_old.match(left):
178 raise Exception('Old-fashioned syntax not supported anymore {left}'.\
181 raise Exception('error in left expression {left}'.format(**locals()))
183 except Exception as e:
185 print("{filename}:{lineno}:syntax error: {e}".format(**locals()), file=stderr)
186 except Exception as e:
188 print('Could not parse file', filename, e, file=stderr)
189 return (ok, included, excluded)
195 for input in self.inputs:
196 (o, i, e) = self.parse (input)
200 # avoid set operations that would not preserve order
201 results = [ x for x in included if x not in excluded ]
203 results = [ x.replace('@arch@', self.arch).\
204 replace('@fcdistro@', self.fcdistro).\
205 replace('@pldistro@', self.pldistro) for x in results]
206 if self.options.sort_results:
208 # default is space-separated
209 if not self.options.new_line:
210 print(" ".join(results))
211 # but for tests results are printed each on a line
213 for result in results:
218 usage = "Usage: %prog [options] keyword input[...]"
219 parser = OptionParser (usage=usage)
220 parser.add_option ('-a', '--arch', dest='arch', action='store', default=default_arch,
221 help='target arch, e.g. i386 or x86_64, default={}'.format(default_arch))
222 parser.add_option ('-f', '--fcdistro', dest='fcdistro', action='store', default=default_fcdistro,
223 help='fcdistro, e.g. f12 or centos5')
224 parser.add_option ('-d', '--pldistro', dest='pldistro', action='store', default=default_pldistro,
225 help='pldistro, e.g. onelab or planetlab')
226 parser.add_option ('-v', '--verbose', dest='verbose', action='store_true', default=False,
227 help='verbose when using qualifiers')
228 parser.add_option ('-n', '--new-line', dest='new_line', action='store_true', default=False,
229 help='print outputs separated with newlines rather than with a space')
230 parser.add_option ('-u', '--no-sort', dest='sort_results', default=True, action='store_false',
231 help='keep results in the same order as in the inputs')
232 (options, args) = parser.parse_args()
235 parser.print_help(file=stderr)
239 if not options.arch in known_arch:
240 print('Unsupported arch', options.arch, file=stderr)
241 parser.print_help(file=stderr)
243 if options.arch == 'i686':
245 if not options.fcdistro in known_fcdistros:
246 print('Unsupported fcdistro', options.fcdistro, file=stderr)
247 parser.print_help(file=stderr)
250 pkgs = PkgsParser(options.arch, options.fcdistro, options.pldistro, keyword, inputs, options)
257 if __name__ == '__main__':