Buildroot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas De Schampheleire <patrickdepinguin@gmail.com>
To: buildroot@busybox.net
Subject: [Buildroot] [PATCHv2 buildroot-test 05/11] autobuild-run: use docopt for argument parsing
Date: Sun, 19 Oct 2014 21:30:01 +0200	[thread overview]
Message-ID: <1413747007-24990-6-git-send-email-patrickdepinguin@gmail.com> (raw)
In-Reply-To: <1413747007-24990-1-git-send-email-patrickdepinguin@gmail.com>

From: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>

Using docopt, argument parsing becomes trivial. Adding a new argument is
a matter of updating the usage text.
This commit removes the original cumbersome argument handling and uses
docopt instead. A method is added to import the settings from the
configuration file in a similar dictionary as the one created by docopt,
so that both can be merged (giving priority to the configuration file,
as before).

With these changes, each option can be passed as argument and in the
configuration file. This means that http-user and http-password can now
also be added as argument (even though passing the password on the
command-line is not recommended).

Signed-off-by: Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
---
v2: rebase after reordering

 scripts/autobuild-run | 132 +++++++++++++++++++++++++++-----------------------
 1 file changed, 71 insertions(+), 61 deletions(-)

diff --git a/scripts/autobuild-run b/scripts/autobuild-run
index 589b1d1..061ae31 100755
--- a/scripts/autobuild-run
+++ b/scripts/autobuild-run
@@ -57,6 +57,37 @@
 #   BR2_PACKAGE_CLASSPATH=y, improve the script to detect whether the
 #   necessary host machine requirements are there to build classpath.
 
+"""autobuild-run - run Buildroot autobuilder
+
+Usage: autobuild-run [options]
+
+Options:
+  -h, --help                     show this help message and exit
+  -V, --version                  show version
+  -n, --ninstances NINSTANCES    number of parallel instances [default: 1]
+  -j, --njobs NJOBS              number of parallel jobs [default: 1]
+  -s, --submitter SUBMITTER      name/machine of submitter [default: N/A]
+  --http-login LOGIN             username to send results with
+  --http-password PASSWORD       password to send results with (for security
+                                 reasons it is recommended to define this in the
+                                 config file instead, with user-read permissions
+                                 only)
+  -c, --config CONFIG            path to configuration file
+
+Format of the configuration file:
+
+  All arguments can also be specified in the configuration file specified with
+  --config, using 'key = value' format (not including the leading --
+  characters). For example:
+
+   [main]
+   ninstances = <value>
+   njobs = <value>
+   http-login = <value>
+   http-password = <value>
+   submitter = <value>
+"""
+
 import urllib2
 import csv
 from random import randint
@@ -70,6 +101,7 @@ import sys
 import hashlib
 import argparse
 import ConfigParser
+import docopt
 
 MAX_DURATION = 60 * 60 * 4
 VERSION = 1
@@ -508,75 +540,51 @@ def run_instance(instance, njobs, http_login, http_password, submitter, sysinfo)
         ret = do_build(instance, njobs, instance_log)
         send_results(instance, http_login, http_password, submitter, instance_log, ret)
 
-def config_get():
-    """Get configuration parameters, either from the command line or the config file"""
+# args / config file merging inspired by:
+# https://github.com/docopt/docopt/blob/master/examples/config_file_example.py
 
-    epilog_text = """
-Format of the configuration file:
+def load_ini_config(configfile):
+    """Load configuration from file, returning a docopt-like dictionary"""
 
-   [main]
-   ninstances = <value>
-   njobs = <value>
-   http-login = <value>
-   http-password = <value>
-   submitter = <value>
-"""
+    if not os.path.exists(configfile):
+        print "ERROR: configuration file %s does not exist" % configfile
+        sys.exit(1)
+
+    config = ConfigParser.RawConfigParser()
+    if not config.read(configfile):
+        print "ERROR: cannot parse configuration file %s" % configfile
+        sys.exit(1)
 
-    parser = argparse.ArgumentParser(description='Run Buildroot autobuilder',
-                                     formatter_class=argparse.RawDescriptionHelpFormatter,
-                                     epilog=epilog_text)
-    parser.add_argument("--ninstances", '-n', metavar="NINSTANCES",
-                        help="Number of parallel instances", default=None)
-    parser.add_argument("--njobs", '-j', metavar="NJOBS",
-                        help="Number of parallel jobs", default=None)
-    parser.add_argument("--submitter", '-s', metavar="SUBMITTER",
-                        help="Name/machine of submitter")
-    parser.add_argument("--config", '-c', metavar="CONFIG",
-                        help="Path to configuration file")
-    args = parser.parse_args()
-
-    ninstances = 1
-    njobs = 1
-    http_login = None
-    http_password = None
-    submitter = "N/A"
-
-    if args.config:
-        if not os.path.exists(args.config):
-            print "ERROR: configuration file %s does not exist" % args.config
-            sys.exit(1)
-        parser = ConfigParser.RawConfigParser()
-        if not parser.read([args.config]):
-            print "ERROR: cannot parse configuration file %s" % args.config
-            sys.exit(1)
-        if parser.has_option('main', 'ninstances'):
-            ninstances = parser.getint('main', 'ninstances')
-        if parser.has_option('main', 'njobs'):
-            njobs = parser.getint('main', 'njobs')
-        if parser.has_option('main', 'http-login'):
-            http_login = parser.get('main', 'http-login')
-        if parser.has_option('main', 'http-password'):
-            http_password = parser.get('main', 'http-password')
-        if parser.has_option('main', 'submitter'):
-            submitter = parser.get('main', 'submitter')
-
-    if args.njobs:
-        njobs = int(args.njobs)
-    if args.ninstances:
-        ninstances = int(args.ninstances)
-    if args.submitter:
-        submitter = args.submitter
-
-    return (ninstances, njobs, http_login, http_password, submitter)
+    # Prepend '--' to options specified in the config file, so they can be
+    # merged with those given on the command-line
+    return dict(('--%s' % key, value) for key, value in config.items('main'))
+
+
+def merge(dict_1, dict_2):
+    """Merge two dictionaries.
+
+    Values that evaluate to true take priority over falsy values.
+    `dict_1` takes priority over `dict_2`.
+
+    """
+    return dict((str(key), dict_1.get(key) or dict_2.get(key))
+                for key in set(dict_2) | set(dict_1))
 
 def main():
     check_version()
     sysinfo = SystemInfo()
-    (ninstances, njobs, http_login, http_password, submitter) = config_get()
+
+    args = docopt.docopt(__doc__, version=VERSION)
+
+    if args['--config']:
+        ini_config = load_ini_config(args['--config'])
+        # merge config/args, priority given to config
+        args = merge(ini_config, args)
 
     # http_login/password could theoretically be allowed as empty, so check
     # explicitly on None.
-    do_send_results = (http_login is not None) and (http_password is not None)
+    do_send_results = (args['--http-login'] is not None) \
+                        and (args['--http-password'] is not None)
     check_requirements(do_send_results)
     if not do_send_results:
         print "WARN: due to the lack of http login/password details, results will not be submitted"
@@ -586,8 +594,10 @@ def main():
         os.killpg(os.getpgid(os.getpid()), signal.SIGTERM)
         sys.exit(1)
     processes = []
-    for i in range(0, ninstances):
-        p = Process(target=run_instance, args=(i, njobs, http_login, http_password, submitter, sysinfo))
+    for i in range(0, int(args['--ninstances'])):
+        p = Process(target=run_instance, args=(i, int(args['--njobs']),
+                args['--http-login'], args['--http-password'],
+                args['--submitter'], sysinfo))
         p.start()
         processes.append(p)
     signal.signal(signal.SIGTERM, sigterm_handler)
-- 
1.8.5.1

  parent reply	other threads:[~2014-10-19 19:30 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-19 19:29 [Buildroot] [PATCHv2 buildroot-test 00/11] autobuild-run improvements Thomas De Schampheleire
2014-10-19 19:29 ` [Buildroot] [PATCHv2 buildroot-test 01/11] autobuild-run: check-requirements does not need to know the login details Thomas De Schampheleire
2014-10-19 20:59   ` Thomas Petazzoni
2014-10-20  9:47     ` Thomas De Schampheleire
2014-10-27 17:56       ` Peter Korsgaard
2014-10-28 11:10         ` Thomas De Schampheleire
2014-10-28 11:14           ` Thomas Petazzoni
2014-10-19 19:29 ` [Buildroot] [PATCHv2 buildroot-test 02/11] autobuild-run: convert regular function comments into docstrings Thomas De Schampheleire
2014-10-19 21:01   ` Thomas Petazzoni
2014-10-19 19:29 ` [Buildroot] [PATCHv2 buildroot-test 03/11] autobuild-run: create main method to locally-scope all variables Thomas De Schampheleire
2014-10-19 21:01   ` Thomas Petazzoni
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 04/11] scripts: add python module docopt Thomas De Schampheleire
2014-10-19 19:30 ` Thomas De Schampheleire [this message]
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 06/11] autobuild-run: add option --make-opts for custom Buildroot options Thomas De Schampheleire
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 07/11] autobuild-run: use **kwargs to avoid explicit parameter passthroughs Thomas De Schampheleire
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 08/11] autobuild-run: set LC_ALL=C to not use locale settings of host machine Thomas De Schampheleire
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 09/11] autobuild-run: improve the logic to generate build-end.log Thomas De Schampheleire
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 10/11] autobuild-run: save config.log files for failed package Thomas De Schampheleire
2014-10-19 19:44   ` Samuel Martin
2014-10-20  9:45     ` Thomas De Schampheleire
2014-10-19 19:30 ` [Buildroot] [PATCHv2 buildroot-test 11/11] autobuild-run: extend TODO list Thomas De Schampheleire

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1413747007-24990-6-git-send-email-patrickdepinguin@gmail.com \
    --to=patrickdepinguin@gmail.com \
    --cc=buildroot@busybox.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox