diff --git a/LbConfiguration/python/LbConfiguration/SP2/devtools.py b/LbConfiguration/python/LbConfiguration/SP2/devtools.py index 33f65b608756444d749a44a9378ad74d364a37da..91c9cd86546f8d32004e9f9b84b3f0238975b4b1 100644 --- a/LbConfiguration/python/LbConfiguration/SP2/devtools.py +++ b/LbConfiguration/python/LbConfiguration/SP2/devtools.py @@ -31,7 +31,7 @@ def main(): from lookup import findProject, MissingProjectError from subprocess import call - parser = OptionParser(usage='%prog [options] Project [version]') + parser = OptionParser(usage='%prog [options] Project[/version]') addSearchPath(parser) addOutputLevel(parser) @@ -76,6 +76,10 @@ def main(): args[0:1] = args[0].split('/') else: args.append(DEFAULT_VERSION) + elif len(args) == 2: + logging.warning('deprecated version specification: ' + 'use "lb-dev ... %s/%s" instead', + *args) try: project, version = args @@ -97,6 +101,12 @@ def main(): for entry in listVersions(project, opts.platform): print '%s in %s' % entry sys.exit(0) + if opts.list_platforms: + from lookup import listPlatforms + platforms = listPlatforms(project, version) + if platforms: + print '\n'.join(platforms) + sys.exit(0) if not opts.name: opts.name = '{project}Dev_{version}'.format(project=project, version=version) diff --git a/LbConfiguration/python/LbConfiguration/SP2/lookup.py b/LbConfiguration/python/LbConfiguration/SP2/lookup.py index 0ad9bb1ac33c88220ad1c7dd0897fcb0a9dedceb..2044ece31efcca0bb636d36e26149e820ccefc75 100644 --- a/LbConfiguration/python/LbConfiguration/SP2/lookup.py +++ b/LbConfiguration/python/LbConfiguration/SP2/lookup.py @@ -13,6 +13,7 @@ ''' import os +import re import logging # FIXME: when we drop Python 2.4, this should become 'from . import path' @@ -22,6 +23,24 @@ from LbConfiguration.SP2.version import (DEFAULT_VERSION, versionKey as _vkey, log = logging.getLogger(__name__) +_PLATFORM_ID_RE = re.compile( + r'((x86_64|i686)-[a-z]+[0-9]+-[a-z]+[0-9]+-[a-z0-9]+)|' + r'([a-z]+[0-9]+_[a-z]+[0-9]+_[a-z]+[0-9]+(_dbg)?)') + + +def isPlatformId(s): + ''' + Return True if the string looks like a platform id. + + >>> isPlatformId('x86_64-centos7-gcc64-opt') + True + >>> isPlatformId('slc4_ia32_gcc34') + True + >>> isPlatformId('include') + False + ''' + return bool(_PLATFORM_ID_RE.match(s)) + def versionKey(x): return _vkey(x[0]) @@ -184,6 +203,60 @@ def listVersions(name, platform): yield entry +def listPlatforms(name, version, allow_empty_version=False): + ''' + Find a version of a Gaudi-based project in the directories specified in + the 'path' variable and return the list of platforms available. + + @param name: name of the project (case sensitive for local projects) + @param version: version string + + @return list of platform strings + + If name is None, version should be the path to the top directory of the + project. + ''' + from os.path import isdir, join, normpath, exists + # for the special case ROOT we delegate to another function + if name == 'ROOT': + return listROOTPlatforms(version) + log.debug('listPlatforms(name=%r, version=%r, allow_empty_version=%r)', + name, version, allow_empty_version) + + if name: + # standard project suffixes + suffixes = ['{0}_{1}'.format(name, version), + join(name.upper(), '{0}_{1}'.format(name.upper(), version)), + join(name.upper(), version)] + # special case: for the 'latest' version we allow the plain name + if allow_empty_version: + suffixes.insert(0, name) + else: + # path to project used, no need for suffixes + suffixes = [os.curdir] + + platforms = set() + # if project name is None, version is the path to the top level directory + # of the project + for d in [normpath(join(b, s)) + for b in (path if name else [version]) + for s in suffixes]: + log.debug('check %s', d) + inst_area = join(d, 'InstallArea') + if isdir(inst_area): + for platform in os.listdir(inst_area): + p_dir = join(inst_area, platform) + if (isdir(p_dir) and isPlatformId(platform) + or exists(join(p_dir, 'manifest.xml'))): + platforms.add(platform) + elif exists(join(d, 'manifest.xml')): + platforms.add('<no-platform>') + + if not platforms: + log.warning('could not find %s/%s in %r', name, version, path) + return sorted(platforms) + + def findDataPackage(name, version): ''' Find a data package in the directories specified in the 'path' variable, @@ -390,6 +463,33 @@ def listROOTVersions(platform): break # go to next LCG version +def listROOTPlatforms(version): + ''' + @return list of available platforms for a version of ROOT + ''' + import glob + log.debug('listROOTPlatforms(version=%r)', version) + + info_glob = LCGInfoName('*') + # transform the glob in a capturing regexp + platform_exp = re.compile(re.escape(info_glob).replace('\\*', '(.*)')) + + platforms = set() + for p in [os.path.join(b, s, info_glob) + for b in path + for s in ('', 'LCG_*')]: + for f in glob.glob(p): + platform = platform_exp.search(f).group(1) # it must match if + # the glob matched + # to be sure, check if ROOT is in the list with the right version + for l in open(f): + l = l.split(';') + if l[0].strip().upper() == 'ROOT' and l[2].strip() == version: + platforms.add(platform) + break + return sorted(platforms) + + def findLCGForROOT(version, platform): ''' Return the (highest) version of LCG containing the required version of diff --git a/LbConfiguration/python/LbConfiguration/SP2/options.py b/LbConfiguration/python/LbConfiguration/SP2/options.py index 5d315fc627c137074d83034c1ea79647d1499c67..b3599cc302c0ec1b84c8f8f882eb1cea1fc9b654 100644 --- a/LbConfiguration/python/LbConfiguration/SP2/options.py +++ b/LbConfiguration/python/LbConfiguration/SP2/options.py @@ -307,7 +307,10 @@ def addListing(parser): parser.add_option('-l', '--list', action='store_true', help='list the available versions of the requested ' 'project and exit') + parser.add_option('-L', '--list-platforms', action='store_true', + help='list the available platforms for the requested ' + 'project/version and exit') - parser.set_defaults(list=False) + parser.set_defaults(list=False, list_platforms=False) return parser diff --git a/LbConfiguration/python/LbConfiguration/SP2/script.py b/LbConfiguration/python/LbConfiguration/SP2/script.py index 8faeecd8979de461c66ca68f7b1948e87ac8a59b..f50a272bc2090558ca9731e6daf5f38ae0fb2ff7 100644 --- a/LbConfiguration/python/LbConfiguration/SP2/script.py +++ b/LbConfiguration/python/LbConfiguration/SP2/script.py @@ -133,7 +133,7 @@ def projectExtraPath(projroot): class SP2(EnvConfig.Script): __usage__ = ('Usage: %prog [OPTION]... [NAME=VALUE]... ' - 'PROJECT VERSION [COMMAND [ARG]...]') + 'PROJECT[/VERSION] [COMMAND [ARG]...]') def _prepare_parser(self): from options import addSearchPath, addPlatform, addListing @@ -242,6 +242,9 @@ class SP2(EnvConfig.Script): self.project = FixProjectCase(self.cmd.pop(0)) if self.cmd and isValidVersion(self.project, self.cmd[0]): self.version = self.cmd.pop(0) + self.log.warning('deprecated version specification: ' + 'use "lb-run ... %s/%s ..." instead', + self.project, self.version) else: # if no version is specified, we want to allow just the # project name @@ -375,9 +378,22 @@ class SP2(EnvConfig.Script): self.parser.error('options --use-sp and --path-to-project ' 'are incompatible') + # FIXME: we need to handle common options like --list in a single place + if self.opts.list: + from lookup import listVersions + for entry in listVersions(self.project, self.opts.platform): + print '%s in %s' % entry + sys.exit(0) + if self.opts.list_platforms: + from lookup import listPlatforms + platforms = listPlatforms(self.project, self.version) + if platforms: + print '\n'.join(platforms) + sys.exit(0) + # special handling of the virtual project ROOT # (unless we only want to list) - if not self.opts.list and self.project == 'ROOT': + if self.project == 'ROOT': self.opts.ext.append(self.project) self.project = 'LCG' if self.allow_empty_version: # no version specified @@ -386,13 +402,6 @@ class SP2(EnvConfig.Script): else: self.version = findLCGForROOT(self.version, self.opts.platform) - # FIXME: we need to handle common options like --list in a single place - if self.opts.list: - from lookup import listVersions - for entry in listVersions(self.project, self.opts.platform): - print '%s in %s' % entry - sys.exit(0) - self.version = expandVersionAlias(self.project, self.version, self.opts.platform)