chiark / gitweb /
Start rewrite: Remove --package and --install from 'build'
authorDaniel Martí <mvdan@mvdan.cc>
Wed, 11 Dec 2013 16:29:38 +0000 (17:29 +0100)
committerDaniel Martí <mvdan@mvdan.cc>
Thu, 19 Dec 2013 16:05:40 +0000 (17:05 +0100)
completion/bash-completion
fdroidserver/build.py
fdroidserver/common.py
fdroidserver/metadata.py

index 41ba5d748a0c8c1637d78cd8b18b9d47c1e62cf0..b05ee2a2ee3e568a2f01980d020ffe1d5571bbf5 100644 (file)
 #
 # This way, one can simply do 'fbld com.some.app' or 'fcheckup com.some.app'
 
-__fdroid_cwd() {
-       if [[ "${PWD##*/}" == metadata ]]; then
-               subdir=.
-       else
-               [ -d metadata ] && subdir=metadata || return 1
-       fi
-}
-
 __fdroid_init() {
        COMPREPLY=()
        cur="${COMP_WORDS[COMP_CWORD]}"
@@ -40,29 +32,24 @@ __fdroid_init() {
 }
 
 __package() {
-       [ -n "$subdir" ] || __fdroid_cwd
-       files=( ${subdir}/*.txt )
-       files=( ${files[@]#${subdir}/} )
+       files=( metadata/*.txt )
+       files=( ${files[@]#metadata/} )
        files=${files[@]%.txt}
        COMPREPLY=( $( compgen -W "$files" -- $cur ) )
 }
 
+__signed_package() {
+       files=( repo/*.apk )
+       files=( ${files[@]#repo/} )
+       files=${files[@]%_*}
+       COMPREPLY=( $( compgen -W "$files" -- $cur ) )
+}
+
 __vercode() {
-       local s p_found p
-       s=${#COMP_WORDS[*]}
-       p_found=false
-
-       $aliased && p=${COMP_WORDS[1]} || {
-               for (( i=1; i <= s; i++ )); do
-                       $p_found && { p=${COMP_WORDS[$i]}; break;}
-                       [[ ${COMP_WORDS[$i]} == -p ]] || [[ ${COMP_WORDS[$i]} == --package ]] &&\
-                               p_found=true
-               done
-               $p_found || return 0
-       }
-       [ -n "$subdir" ] || __fdroid_cwd
+       local p
+       p=${cur:0:-1}
 
-       COMPREPLY=( $( compgen -W "$( while read line; do
+       COMPREPLY=( $( compgen -P "${p}:" -W "$( while read line; do
                if [[ "$line" == "Build Version:"* ]]
                then
                        line="${line#*,}"
@@ -72,7 +59,7 @@ __vercode() {
                        line="${line#*,}"
                        printf "${line%%,*} "
                fi
-               done < "${subdir}/${p}.txt" )" -- $cur ) )
+               done < "metadata/${p}.txt" )" -- $cur ) )
 }
 
 __complete_options() {
@@ -88,15 +75,15 @@ __complete_options() {
 
 __complete_build() {
        opts="-h -v -p -c -l -s -t -f"
-       lopts="--help --verbose --package --vercode --latest --server --resetserver
- --on-server --force --install --all"
-       case "${prev}" in
-               -p|--package)
-                       __package
-                       return 0;;
-               -c|--vercode)
+       lopts="--help --verbose --latest --server --resetserver --on-server
+ --force --all"
+       case "${cur}" in
+               *:)
                        __vercode
                        return 0;;
+               *)
+                       __package
+                       return 0;;
        esac
        __complete_options
 }
@@ -203,7 +190,6 @@ _fdroid() {
        cmd=${COMP_WORDS[1]}
        cmds=" build init update publish checkupdates import rewritemeta scanner verify stats server "
        aliased=false
-       __fdroid_cwd || return 0
 
        for c in $cmds; do eval "_fdroid_${c} () {
                local cur prev cmds opts lopts
@@ -234,7 +220,6 @@ _fdroid_checkupdates_project() {
 }
 
 _fd-commit() {
-       __fdroid_cwd || return 0
        __package
 }
 
index 2dada68c390ba0ee3693e4a3ba266f3a9383b72c..a5d9dba8cf78f40c9f7c915aa983186e10db6cb3 100644 (file)
@@ -379,7 +379,7 @@ def adapt_gradle(path):
             's@com.android.tools.build:gradle:[0-9\.\+]*@com.android.tools.build:gradle:'+ config['gradle_plugin'] +'@g', path])
 
 
-def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_dir, tmp_dir, install, force, onserver):
+def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver):
     """Do a build locally."""
 
     # Prepare the source code...
@@ -506,11 +506,8 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         else:
             maven_dir = root_dir
 
-        mvncmd = [config['mvn3'], '-Dandroid.sdk.path=' + config['sdk_path']]
-        if install:
-            mvncmd += ['-Dandroid.sign.debug=true', 'package', 'android:deploy']
-        else:
-            mvncmd += ['-Dandroid.sign.debug=false', '-Dandroid.release=true', 'package']
+        mvncmd = [config['mvn3'], '-Dandroid.sdk.path=' + config['sdk_path'],
+                '-Dandroid.sign.debug=false', '-Dandroid.release=true', 'package']
         if 'target' in thisbuild:
             target = thisbuild["target"].split('-')[1]
             subprocess.call(['sed', '-i',
@@ -622,19 +619,14 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         if 'preassemble' in thisbuild:
             for task in thisbuild['preassemble'].split():
                 commands.append(task)
-        if install:
-            commands += ['assemble'+flavour+'Debug', 'install'+flavour+'Debug']
-        else:
-            commands += ['assemble'+flavour+'Release']
+        commands += ['assemble'+flavour+'Release']
 
         p = FDroidPopen(commands, cwd=gradle_dir)
 
     else:
         print "Building Ant project..."
         cmd = ['ant']
-        if install:
-            cmd += ['debug','install']
-        elif 'antcommand' in thisbuild:
+        if 'antcommand' in thisbuild:
             cmd += [thisbuild['antcommand']]
         else:
             cmd += ['release']
@@ -646,9 +638,6 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         raise BuildException("Build failed for %s:%s" % (app['id'], thisbuild['version']), p.stdout, p.stderr)
     print "Successfully built version " + thisbuild['version'] + ' of ' + app['id']
 
-    if install:
-        return
-
     # Find the apk name in the output...
     if 'bindir' in thisbuild:
         bindir = os.path.join(build_dir, thisbuild['bindir'])
@@ -752,7 +741,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
 
 def trybuild(app, thisbuild, build_dir, output_dir, also_check_dir, srclib_dir, extlib_dir,
-        tmp_dir, repo_dir, vcs, test, server, install, force, onserver):
+        tmp_dir, repo_dir, vcs, test, server, force, onserver):
     """
     Build a particular version of an application, if it needs building.
 
@@ -796,22 +785,18 @@ def trybuild(app, thisbuild, build_dir, output_dir, also_check_dir, srclib_dir,
 
         build_server(app, thisbuild, vcs, build_dir, output_dir, force)
     else:
-        build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_dir, tmp_dir, install, force, onserver)
+        build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver)
     return True
 
 
 def parse_commandline():
     """Parse the command line. Returns options, args."""
 
-    parser = OptionParser()
+    parser = OptionParser(usage="Usage: %prog [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
     parser.add_option("-v", "--verbose", action="store_true", default=False,
                       help="Spew out even more information than normal")
-    parser.add_option("-p", "--package", default=None,
-                      help="Build only the specified package")
-    parser.add_option("-c", "--vercode", default=None,
-                      help="Build only the specified version code")
     parser.add_option("-l", "--latest", action="store_true", default=False,
-                      help="Build only the latest version code available")
+                      help="Build only the latest version of each package")
     parser.add_option("-s", "--stop", action="store_true", default=False,
                       help="Make the build stop on exceptions")
     parser.add_option("-t", "--test", action="store_true", default=False,
@@ -824,13 +809,8 @@ def parse_commandline():
                       help="Specify that we're running on the build server")
     parser.add_option("-f", "--force", action="store_true", default=False,
                       help="Force build of disabled apps, and carries on regardless of scan problems. Only allowed in test mode.")
-    parser.add_option("--install", action="store_true", default=False,
-                      help="Use 'ant debug install' to build and install a " +
-                      "debug version on your device or emulator. " +
-                      "Implies --force and --test")
-    parser.add_option("--all", action="store_true", default=False,
-                      help="Use with --install, when not using --package"
-                      " to confirm you really want to build and install everything.")
+    parser.add_option("-a", "--all", action="store_true", default=False,
+                      help="Build all applications available")
     parser.add_option("-w", "--wiki", default=False, action="store_true",
                       help="Update the wiki")
     options, args = parser.parse_args()
@@ -839,19 +819,6 @@ def parse_commandline():
     if options.onserver:
         options.stop = True
 
-    # The --install option implies --test and --force...
-    if options.install:
-        if options.server:
-            print "Can't install when building on a build server."
-            sys.exit(1)
-        if not options.package and not options.all:
-            print "This would build and install everything in the repo to the device."
-            print "You probably want to use --package and maybe also --vercode."
-            print "If you really want to install everything, use --all."
-            sys.exit(1)
-        options.force = True
-        options.test = True
-
     if options.force and not options.test:
         print "Force is only allowed in test mode"
         sys.exit(1)
@@ -874,9 +841,6 @@ def main():
         print "Using --resetserver without --server makes no sense"
         sys.exit(1)
 
-    # Get all apps...
-    apps = metadata.read_metadata(xref=not options.onserver)
-
     log_dir = 'logs'
     if not os.path.isdir(log_dir):
         print "Creating log directory"
@@ -909,25 +873,10 @@ def main():
     srclib_dir = os.path.join(build_dir, 'srclib')
     extlib_dir = os.path.join(build_dir, 'extlib')
 
-    # Filter apps and build versions according to command-line options, etc...
-    if options.package:
-        apps = [app for app in apps if app['id'] == options.package]
-        if len(apps) == 0:
-            print "No such package"
-            sys.exit(1)
-    apps = [app for app in apps if (options.force or not app['Disabled']) and
-            app['builds'] and len(app['Repo Type']) > 0 and len(app['builds']) > 0]
-    if len(apps) == 0:
-        print "Nothing to do - all apps are disabled or have no builds defined."
-        sys.exit(1)
-    if options.vercode:
-        for app in apps:
-            app['builds'] = [b for b in app['builds']
-                    if str(b['vercode']) == options.vercode]
-    elif options.latest:
-        for app in apps:
-            m = max([i['vercode'] for i in app['builds']], key=int)
-            app['builds'] = [b for b in app['builds'] if b['vercode'] == m]
+    # Get all apps...
+    allapps = metadata.read_metadata(xref=not options.onserver)
+
+    apps = common.read_app_args(args, options, allapps)
 
     if options.wiki:
         import mwclient
@@ -967,7 +916,7 @@ def main():
                     print "Checking " + thisbuild['version']
                 if trybuild(app, thisbuild, build_dir, output_dir, also_check_dir,
                         srclib_dir, extlib_dir, tmp_dir, repo_dir, vcs, options.test,
-                        options.server, options.install, options.force, options.onserver):
+                        options.server, options.force, options.onserver):
                     build_succeeded.append(app)
                     wikilog = "Build succeeded"
             except BuildException as be:
index 5b3d7c620234d897f3bf0787583122b36c612a18..fc23074901de98598419c93e6f258c071c11466b 100644 (file)
@@ -110,6 +110,53 @@ def read_config(opts, config_file='config.py'):
 
     return config
 
+def read_app_args(args, options, allapps):
+    if args:
+        vercodes = {}
+        for p in args:
+            if ':' in p:
+                package, vercode = p.split(':')
+            else:
+                package, vercode = p, None
+            if package not in vercodes:
+                vercodes[package] = [vercode] if vercode else []
+                continue
+            elif vercode not in vercodes[package]:
+                vercodes[package] += [vercode] if vercode else []
+        packages = vercodes.keys()
+        apps = [app for app in allapps if app['id'] in packages]
+        if len(apps) != len(packages):
+            allids = [app["id"] for app in allapps]
+            for p in packages:
+                if p not in allids:
+                    print "No such package: %s" % p
+            raise Exception("Found invalid app ids in arguments")
+
+    apps = [app for app in apps if (options.force or not app['Disabled']) and
+            app['builds'] and len(app['Repo Type']) > 0 and len(app['builds']) > 0]
+    if len(apps) == 0:
+        raise Exception("No apps to process.")
+
+    error = False
+    for app in apps:
+        vc = vercodes[app['id']]
+        if vc:
+            app['builds'] = [b for b in app['builds'] if b['vercode'] in vc]
+            if len(app['builds']) != len(vercodes[app['id']]):
+                error = True
+                allvcs = [b['vercode'] for b in app['builds']]
+                for v in vercodes[app['id']]:
+                    if v not in allvcs:
+                        print "No such vercode %s for app %s" % (v, app['id'])
+        elif options.latest:
+            app['builds'] = app['builds'][-1:]
+
+    if error:
+        raise Exception("Found invalid vercodes for some apps")
+
+    return apps
+
+
 def getapkname(app, build):
     return "%s_%s.apk" % (app['id'], build['vercode'])
 
@@ -117,14 +164,14 @@ def getsrcname(app, build):
     return "%s_%s_src.tar.gz" % (app['id'], build['vercode'])
 
 def getappname(app):
-       if app['Name']:
-               return '%s (%s)' % (app['Name'], app['id'])
-       if app['Auto Name']:
-               return '%s (%s)' % (app['Auto Name'], app['id'])
-       return app['id']
+    if app['Name']:
+        return '%s (%s)' % (app['Name'], app['id'])
+    if app['Auto Name']:
+        return '%s (%s)' % (app['Auto Name'], app['id'])
+    return app['id']
 
 def getcvname(app):
-       return '%s (%s)' % (app['Current Version'], app['Current Version Code'])
+    return '%s (%s)' % (app['Current Version'], app['Current Version Code'])
 
 def getvcs(vcstype, remote, local):
     if vcstype == 'git':
index 889fae0d18907a4684398c8824ba7e2de314ee9c..f52fc878cdcbb5296af5e9abecd2ee0dd72ef5e1 100644 (file)
@@ -38,25 +38,26 @@ class MetaDataException(Exception):
 class FieldType():
     def __init__(self, name, matching, sep, fields, attrs):
         self.name = name
+        self.matching = matching
         if type(matching) is str:
-            self.matching = re.compile(matching)
-        elif type(matching) is list:
-            self.matching = matching
+            self.compiled = re.compile(matching)
         self.sep = sep
         self.fields = fields
         self.attrs = attrs
 
     def _assert_regex(self, values, appid):
         for v in values:
-            if not self.matching.match(v):
-                raise MetaDataException("'%s' is not a valid %s in %s"
-                        % (v, self.name, appid))
+            if not self.compiled.match(v):
+                raise MetaDataException("'%s' is not a valid %s in %s. "
+                        % (v, self.name, appid) +
+                        "Regex pattern: %s" % (self.matching))
 
     def _assert_list(self, values, appid):
         for v in values:
             if v not in self.matching:
-                raise MetaDataException("'%s' is not a valid %s in %s"
-                        % (v, self.name, appid))
+                raise MetaDataException("'%s' is not a valid %s in %s. "
+                        % (v, self.name, appid) +
+                        "Possible values: %s" % (", ".join(self.matching)))
 
     def check(self, value, appid):
         if type(value) is not str or not value: