[Pkg-mozext-commits] [adblock-plus] 157/464: Generalized command line parsing/help texts, prepared build tool to support non-Gecko extensions

David Prévot taffit at moszumanska.debian.org
Tue Jul 22 20:44:13 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository adblock-plus.

commit 5454e351acacbf055a46f0d888c89d6029a1df32
Author: Wladimir Palant <trev at adblockplus.org>
Date:   Fri May 20 13:30:52 2011 +0200

    Generalized command line parsing/help texts, prepared build tool to support non-Gecko extensions
---
 build.py | 332 ++++++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 200 insertions(+), 132 deletions(-)

diff --git a/build.py b/build.py
index 7d3bd80..4506f9f 100644
--- a/build.py
+++ b/build.py
@@ -10,42 +10,146 @@ from getopt import getopt, GetoptError
 import buildtools.packager as packager
 import buildtools.releaseAutomation as releaseAutomation
 
-def usage_build(scriptName):
-  print '''%(name)s build [options] [output_file]
+class Command(object):
+  name = property(lambda self: self._name)
+  shortDescription = property(lambda self: self._shortDescription,
+      lambda self, value: self.__dict__.update({'_shortDescription': value}))
+  description = property(lambda self: self._description,
+      lambda self, value: self.__dict__.update({'_description': value}))
+  params = property(lambda self: self._params,
+      lambda self, value: self.__dict__.update({'_params': value}))
+  supportedTypes = property(lambda self: self._supportedTypes,
+      lambda self, value: self.__dict__.update({'_supportedTypes': value}))
+  options = property(lambda self: self._options)
+
+  def __init__(self, handler, name):
+    self._handler = handler
+    self._name = name
+    self._shortDescription = ''
+    self._description = ''
+    self._params = ''
+    self._supportedTypes = None
+    self._options = []
+    self.addOption('Show this message and exit', short='h', long='help')
+
+  def __enter__(self):
+    return self
+
+  def __exit__(self, exc_type, exc_value, traceback):
+    pass
+
+  def __call__(self, baseDir, scriptName, opts, args, type):
+    return self._handler(baseDir, scriptName, opts, args, type)
+
+  def isSupported(self, type):
+    return self._supportedTypes == None or type in self._supportedTypes
+
+  def addOption(self, description, short=None, long=None, value=None):
+    self._options.append((description, short, long, value))
+
+  def parseArgs(self, args):
+    shortOptions = map(lambda o: o[1]+':' if o[3] != None else o[1], filter(lambda o: o[1] != None, self._options))
+    longOptions = map(lambda o: o[2]+'=' if o[3] != None else o[2], filter(lambda o: o[2] != None, self._options))
+    return getopt(args, ''.join(shortOptions), longOptions)
+
+
+commandsList = []
+commands = {}
+def addCommand(handler, name):
+  if isinstance(name, basestring):
+    aliases = ()
+  else:
+    name, aliases = (name[0], name[1:])
+
+  global commandsList, commands
+  command = Command(handler, name)
+  commandsList.append(command)
+  commands[name] = command
+  for alias in aliases:
+    commands[alias] = command
+  return command
+
+def splitByLength(string, maxLen):
+  parts = []
+  currentPart = ''
+  for match in re.finditer(r'\s*(\S+)', string):
+    if len(match.group(0)) + len(currentPart) < maxLen:
+      currentPart += match.group(0)
+    else:
+      parts.append(currentPart)
+      currentPart = match.group(1)
+  if len(currentPart):
+    parts.append(currentPart)
+  return parts
+
+def usage(scriptName, type, commandName=None):
+  if commandName == None:
+    global commandsList
+    descriptions = []
+    for command in commandsList:
+      if not command.isSupported(type):
+        continue
+      commandText = ('%s %s' % (command.name, command.params)).ljust(39)
+      descriptionParts = splitByLength(command.shortDescription, 29)
+      descriptions.append('  %s %s %s' % (scriptName, commandText, descriptionParts[0]))
+      for part in descriptionParts[1:]:
+        descriptions.append('  %s %s %s' % (' ' * len(scriptName), ' ' * len(commandText), part))
+    print '''Usage:
+
+%(descriptions)s
+
+For details on a command run:
 
-Creates an extension build with given file name. If output_file is missing a
-default name will be chosen.
+  %(scriptName)s <command> --help
+''' % {
+    'scriptName': scriptName,
+    'descriptions': '\n'.join(descriptions)
+  }
+  else:
+    global commands
+    command = commands[commandName]
+    description = '\n'.join(map(lambda s: '\n'.join(splitByLength(s, 80)), command.description.split('\n')))
+    options = []
+    for descr, short, long, value in command.options:
+      if short == None:
+        shortText = ''
+      elif value == None:
+        shortText = '-%s' % short
+      else:
+        shortText = '-%s %s' % (short, value)
+      if long == None:
+        longText = ''
+      elif value == None:
+        longText = '--%s' % long
+      else:
+        longText = '--%s=%s' % (long, value)
+      descrParts = splitByLength(descr, 46)
+      options.append('  %s %s %s' % (shortText.ljust(11), longText.ljust(19), descrParts[0]))
+      for part in descrParts[1:]:
+        options.append('  %s %s %s' % (' ' * 11, ' ' * 19, part))
+    print '''%(scriptName)s %(name)s %(params)s
+
+%(description)s
 
 Options:
-  -h          --help              Show this message and exit
-  -l l1,l2,l3 --locales=l1,l2,l3  Only include the given locales (if omitted:
-                                  all locales not marked as incomplete)
-  -b num      --build=num         Use given build number (if omitted the build
-                                  number will be retrieved from Mercurial)
-  -k file     --key=file          File containing private key and certificates
-                                  required to sign the package
-  -r          --release           Create a release build
-              --babelzilla        Create a build for Babelzilla
-''' % {"name": scriptName}
-
-def runBuild(baseDir, scriptName, args):
-  try:
-    opts, args = getopt(args, 'hl:b:k:r:', ['help', 'locales', 'build=', 'key=', 'release', 'babelzilla'])
-  except GetoptError, e:
-    print str(e)
-    usage_build(scriptName)
-    sys.exit(2)
+%(options)s
+''' % {
+      'scriptName': scriptName,
+      'name': command.name,
+      'params': command.params,
+      'description': description,
+      'options': '\n'.join(options)
+    }
+
 
+def runBuild(baseDir, scriptName, opts, args, type):
   locales = None
   buildNum = None
   releaseBuild = False
   keyFile = None
   limitMetadata = False
   for option, value in opts:
-    if option in ('-h', '--help'):
-      usage_build(scriptName)
-      return
-    elif option in ('-l', '--locales'):
+    if option in ('-l', '--locales'):
       locales = value.split(',')
     elif option in ('-b', '--build'):
       buildNum = int(value)
@@ -63,35 +167,10 @@ def runBuild(baseDir, scriptName, args):
                        limitMetadata=limitMetadata)
 
 
-def usage_testenv(scriptName):
-  print '''%(name)s testenv [options] [profile_dir] ...
-
-Sets up the extension in given profiles in such a way that most files are read
-from the current directory. Changes in the files here will be available to these
-profiles immediately after a restart without having to reinstall the extension.
-If no directories are given the list of directories is read from a file.
-
-Options
-  -h          --help              Show this message and exit
-  -d file     --dirs=file         File listing profile directories to set up if
-                                  none are given on command line (default is
-                                  .profileDirs)
-''' % {"name": scriptName}
-
-def setupTestEnvironment(baseDir, scriptName, args):
-  try:
-    opts, args = getopt(args, 'hd:', ['help', 'dirs='])
-  except GetoptError, e:
-    print str(e)
-    usage_testenv(scriptName)
-    sys.exit(2)
-
+def setupTestEnvironment(baseDir, scriptName, opts, args, type):
   dirsFile = '.profileDirs'
   for option, value in opts:
-    if option in ('-h', '--help'):
-      usage_testenv(scriptName)
-      return
-    elif option in ('-d', '--dirs'):
+    if option in ('-d', '--dirs'):
       dirsFile = value
 
   profileDirs = args
@@ -102,31 +181,10 @@ def setupTestEnvironment(baseDir, scriptName, args):
   packager.setupTestEnvironment(baseDir, profileDirs)
 
 
-def usage_showdesc(scriptName):
-  print '''%(name)s showdesc [options]
-
-Display description strings for all locales as specified in the corresponding
-meta.properties files.
-
-Options
-  -h          --help              Show this message and exit
-  -l l1,l2,l3 --locales=l1,l2,l3  Only include the given locales
-''' % {"name": scriptName}
-
-def showDescriptions(baseDir, scriptName, args):
-  try:
-    opts, args = getopt(args, 'hl:', ['help', 'locales='])
-  except GetoptError, e:
-    print str(e)
-    usage_showdesc(scriptName)
-    sys.exit(2)
-
+def showDescriptions(baseDir, scriptName, opts, args, type):
   locales = None
   for option, value in opts:
-    if option in ('-h', '--help'):
-      usage_showdesc(scriptName)
-      return
-    elif option in ('-l', '--locales'):
+    if option in ('-l', '--locales'):
       locales = value.split(',')
 
   if locales == None:
@@ -151,50 +209,25 @@ def showDescriptions(baseDir, scriptName, args):
        locale['description.long'] if 'description.long' in locale else 'None',
       )).encode('utf-8')
 
-def usage_release(scriptName):
-  print '''%(name)s release [options] <version>
-
-Note: If you are not the project owner then you probably don't want to run this!
-
-Runs release automation: creates downloads for the new version, tags source code
-repository as well as downloads and buildtools repository.
-
-Options
-  -h          --help              Show this message and exit
-  -k file     --key=file          File containing private key and certificates
-                                  required to sign the release
-  -d dir      --downloads=dir     Directory containing downloads repository
-                                  (if omitted ../downloads is assumed)
-''' % {"name": scriptName}
-
-def runReleaseAutomation(baseDir, scriptName, args):
-  try:
-    opts, args = getopt(args, 'hk:d:', ['help', 'key=', 'downloads='])
-  except GetoptError, e:
-    print str(e)
-    usage_release(scriptName)
-    sys.exit(2)
 
+def runReleaseAutomation(baseDir, scriptName, opts, args, type):
   buildtoolsRepo = buildtools.__path__[0]
   keyFile = None
   downloadsRepo = os.path.join(baseDir, '..', 'downloads')
   for option, value in opts:
-    if option in ('-h', '--help'):
-      usage_release(scriptName)
-      return
-    elif option in ('-k', '--key'):
+    if option in ('-k', '--key'):
       keyFile = value
     elif option in ('-d', '--downloads'):
       downloadsRepo = value
 
   if len(args) == 0:
     print 'No version number specified for the release'
-    usage_release(scriptName)
+    usage(scriptName, type, 'release')
     return
   version = args[0]
   if re.search(r'[^\w\.]', version):
     print 'Wrong version number format'
-    usage_release(scriptName)
+    usage(scriptName, type, 'release')
     return
 
   if keyFile == None:
@@ -202,23 +235,52 @@ def runReleaseAutomation(baseDir, scriptName, args):
 
   releaseAutomation.run(baseDir, version, keyFile, downloadsRepo, buildtoolsRepo)
 
+with addCommand(lambda baseDir, scriptName, opts, args, type: usage(scriptName, type), ('help', '-h', '--help')) as command:
+  command.shortDescription = 'Show this message'
+
+with addCommand(runBuild, 'build') as command:
+  command.shortDescription = 'Create a build'
+  command.description = 'Creates an extension build with given file name. If output_file is missing a default name will be chosen.'
+  command.params = '[options] [output_file]'
+  command.addOption('Only include the given locales (if omitted: all locales not marked as incomplete)', short='l', long='locales', value='l1,l2,l3')
+  command.addOption('Use given build number (if omitted the build number will be retrieved from Mercurial)', short='b', long='build', value='num')
+  command.addOption('File containing private key and certificates required to sign the package', short='k', long='key', value='file')
+  command.addOption('Create a release build', short='r', long='release')
+  command.addOption('Create a build for Babelzilla', long='babelzilla')
+  command.supportedTypes = ('gecko')
+
+with addCommand(setupTestEnvironment, 'testenv') as command:
+  command.shortDescription = 'Set up test environment'
+  command.description = 'Sets up the extension in given profiles in such a way '\
+    'that most files are read from the current directory. Changes in the files '\
+    'here will be available to these profiles immediately after a restart '\
+    'without having to reinstall the extension. If no directories are given the '\
+    'list of directories is read from a file.'
+  command.addOption('File listing profile directories to set up if none are given on command line (default is .profileDirs)', short='d', long='dirs', value='file')
+  command.params = '[options] [profile_dir] ...'
+  command.supportedTypes = ('gecko')
+
+with addCommand(showDescriptions, 'showdesc') as command:
+  command.shortDescription = 'Print description strings for all locales'
+  command.description = 'Display description strings for all locales as specified in the corresponding meta.properties files.'
+  command.addOption('Only include the given locales', short='l', long='locales', value='l1,l2,l3')
+  command.params = '[options]'
+  command.supportedTypes = ('gecko')
+
+with addCommand(runReleaseAutomation, 'release') as command:
+  command.shortDescription = 'Run release automation'
+  command.description = 'Note: If you are not the project owner then you '\
+    'probably don\'t want to run this!\n\n'\
+    'Runs release automation: creates downloads for the new version, tags '\
+    'source code repository as well as downloads and buildtools repository.'
+  command.addOption('File containing private key and certificates required to sign the release', short='k', long='key', value='file')
+  command.addOption('Directory containing downloads repository (if omitted ../downloads is assumed)', short='d', long='downloads', value='dir')
+  command.params = '[options] <version>'
+  command.supportedTypes = ('gecko')
+
+def processArgs(baseDir, args, type='gecko'):
+  global commands
 
-def usage(scriptName):
-  print '''Usage:
-
-  %(name)s help                                   Show this message
-  %(name)s build [options] [output_file]          Create a build
-  %(name)s testenv [options] [profile_dir] ...    Set up test environment
-  %(name)s showdesc [options]                     Print description strings for
-                                                  all locales
-  %(name)s release [options] <version>            Run release automation
-
-For details on a command run:
-
-  %(name)s <command> --help
-''' % {"name": scriptName}
-
-def processArgs(baseDir, args):
   scriptName = os.path.basename(args[0])
   args = args[1:]
   if len(args) == 0:
@@ -230,16 +292,22 @@ No command given, assuming "build". For a list of commands run:
 ''' % scriptName
 
   command = args[0]
-  if command == 'help' or command == '--help' or command == '-h':
-    usage(scriptName)
-  elif command == 'build':
-    runBuild(baseDir, scriptName, args[1:])
-  elif command == 'testenv':
-    setupTestEnvironment(baseDir, scriptName, args[1:])
-  elif command == 'showdesc':
-    showDescriptions(baseDir, scriptName, args[1:])
-  elif command == 'release':
-    runReleaseAutomation(baseDir, scriptName, args[1:])
+  if command in commands:
+    if commands[command].isSupported(type):
+      try:
+        opts, args = commands[command].parseArgs(args[1:])
+      except GetoptError, e:
+        print str(e)
+        usage(scriptName, type, command)
+        sys.exit(2)
+      for option, value in opts:
+        if option in ('-h', '--help'):
+          usage(scriptName, type, command)
+        sys.exit()
+      commands[command](baseDir, scriptName, opts, args, type)
+    else:
+      print 'Command %s is not supported for this application type' % command
+      usage(scriptName, type)
   else:
     print 'Command %s is unrecognized' % command
-    usage(scriptName)
+    usage(scriptName, type)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git



More information about the Pkg-mozext-commits mailing list