chiark / gitweb /
use jarsigner and keytool from same JDK as is being set in JAVA7_HOME
[fdroidserver.git] / fdroidserver / common.py
index 2e1ff2cc4e20151aa35a429d78c4c7acd532cda1..c30d3b4e07ed7d6492a47351f1959d5e83b395be 100644 (file)
@@ -29,12 +29,18 @@ import stat
 import subprocess
 import time
 import operator
-import Queue
 import logging
 import hashlib
 import socket
 import xml.etree.ElementTree as XMLElementTree
 
+try:
+    # Python 2
+    from Queue import Queue
+except ImportError:
+    # Python 3
+    from queue import Queue
+
 from zipfile import ZipFile
 
 import metadata
@@ -56,10 +62,7 @@ default_config = {
         'r10e': "$ANDROID_NDK",
     },
     'build_tools': "23.0.2",
-    'java_paths': {
-        '1.7': "/usr/lib/jvm/java-7-openjdk",
-        '1.8': None,
-    },
+    'java_paths': None,
     'ant': "ant",
     'mvn3': "mvn",
     'gradle': 'gradle',
@@ -125,6 +128,40 @@ def fill_config_defaults(thisconfig):
             thisconfig[k] = exp
             thisconfig[k + '_orig'] = v
 
+    # find all installed JDKs for keytool, jarsigner, and JAVA[6-9]_HOME env vars
+    if thisconfig['java_paths'] is None:
+        thisconfig['java_paths'] = dict()
+        for d in sorted(glob.glob('/usr/lib/jvm/j*[6-9]*')
+                        + glob.glob('/usr/java/jdk1.[6-9]*')
+                        + glob.glob('/System/Library/Java/JavaVirtualMachines/1.[6-9].0.jdk')
+                        + glob.glob('/Library/Java/JavaVirtualMachines/*jdk*[6-9]*')):
+            if os.path.islink(d):
+                continue
+            j = os.path.basename(d)
+            # the last one found will be the canonical one, so order appropriately
+            for regex in (r'1\.([6-9])\.0\.jdk',  # OSX
+                          r'jdk1\.([6-9])\.0_[0-9]+.jdk',  # OSX and Oracle tarball
+                          r'jdk([6-9])-openjdk',  # Arch
+                          r'java-1\.([6-9])\.0-.*',  # RedHat
+                          r'java-([6-9])-oracle',  # Debian WebUpd8
+                          r'jdk-([6-9])-oracle-.*',  # Debian make-jpkg
+                          r'java-([6-9])-openjdk-[^c][^o][^m].*'):  # Debian
+                m = re.match(regex, j)
+                if m:
+                    osxhome = os.path.join(d, 'Contents', 'Home')
+                    if os.path.exists(osxhome):
+                        thisconfig['java_paths'][m.group(1)] = osxhome
+                    else:
+                        thisconfig['java_paths'][m.group(1)] = d
+
+    for java_version in ('7', '8', '9'):
+        java_home = thisconfig['java_paths'][java_version]
+        jarsigner = os.path.join(java_home, 'bin', 'jarsigner')
+        if os.path.exists(jarsigner):
+            thisconfig['jarsigner'] = jarsigner
+            thisconfig['keytool'] = os.path.join(java_home, 'bin', 'keytool')
+            break  # Java7 is preferred, so quit if found
+
     for k in ['ndk_paths', 'java_paths']:
         d = thisconfig[k]
         for k2 in d.copy():
@@ -188,10 +225,8 @@ def read_config(opts, config_file='config.py'):
     for n in ['ANDROID_HOME', 'ANDROID_SDK']:
         env[n] = config['sdk_path']
 
-    for v in ['7', '8']:
-        cpath = config['java_paths']['1.%s' % v]
-        if cpath:
-            env['JAVA%s_HOME' % v] = cpath
+    for k, v in config['java_paths'].items():
+        env['JAVA%s_HOME' % k] = v
 
     for k in ["keystorepass", "keypass"]:
         if k in config:
@@ -295,7 +330,7 @@ def write_password_file(pwtype, password=None):
     command line argments
     '''
     filename = '.fdroid.' + pwtype + '.txt'
-    fd = os.open(filename, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0600)
+    fd = os.open(filename, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600)
     if password is None:
         os.write(fd, config[pwtype])
     else:
@@ -1066,19 +1101,22 @@ def parse_androidmanifests(paths, app):
                     if matches:
                         vercode = matches.group(1)
         else:
-            xml = parse_xml(path)
-            if "package" in xml.attrib:
-                s = xml.attrib["package"].encode('utf-8')
-                if app_matches_packagename(app, s):
-                    package = s
-            if "{http://schemas.android.com/apk/res/android}versionName" in xml.attrib:
-                version = xml.attrib["{http://schemas.android.com/apk/res/android}versionName"].encode('utf-8')
-                base_dir = os.path.dirname(path)
-                version = retrieve_string_singleline(base_dir, version)
-            if "{http://schemas.android.com/apk/res/android}versionCode" in xml.attrib:
-                a = xml.attrib["{http://schemas.android.com/apk/res/android}versionCode"].encode('utf-8')
-                if string_is_integer(a):
-                    vercode = a
+            try:
+                xml = parse_xml(path)
+                if "package" in xml.attrib:
+                    s = xml.attrib["package"].encode('utf-8')
+                    if app_matches_packagename(app, s):
+                        package = s
+                if "{http://schemas.android.com/apk/res/android}versionName" in xml.attrib:
+                    version = xml.attrib["{http://schemas.android.com/apk/res/android}versionName"].encode('utf-8')
+                    base_dir = os.path.dirname(path)
+                    version = retrieve_string_singleline(base_dir, version)
+                if "{http://schemas.android.com/apk/res/android}versionCode" in xml.attrib:
+                    a = xml.attrib["{http://schemas.android.com/apk/res/android}versionCode"].encode('utf-8')
+                    if string_is_integer(a):
+                        vercode = a
+            except Exception:
+                logging.warning("Problem with xml at {0}".format(path))
 
         # Remember package name, may be defined separately from version+vercode
         if package is None:
@@ -1606,7 +1644,7 @@ def FDroidPopen(commands, cwd=None, output=True):
         raise BuildException("OSError while trying to execute " +
                              ' '.join(commands) + ': ' + str(e))
 
-    stdout_queue = Queue.Queue()
+    stdout_queue = Queue()
     stdout_reader = AsynchronousFileReader(p.stdout, stdout_queue)
 
     # Check the queue for output (until there is no more to get)
@@ -1630,8 +1668,6 @@ gradle_signing_configs = re.compile(r'^[\t ]*signingConfigs[ \t]*{[ \t]*$')
 gradle_line_matches = [
     re.compile(r'^[\t ]*signingConfig [^ ]*$'),
     re.compile(r'.*android\.signingConfigs\.[^{]*$'),
-    re.compile(r'.*variant\.outputFile = .*'),
-    re.compile(r'.*output\.outputFile = .*'),
     re.compile(r'.*\.readLine\(.*'),
 ]
 
@@ -1782,7 +1818,7 @@ def verify_apks(signed_apk, unsigned_apk, tmp_dir):
         for meta_inf_file in meta_inf_files:
             unsigned_apk_as_zip.write(os.path.join(tmp_dir, meta_inf_file), arcname=meta_inf_file)
 
-    if subprocess.call(['jarsigner', '-verify', unsigned_apk]) != 0:
+    if subprocess.call([config['jarsigner'], '-verify', unsigned_apk]) != 0:
         logging.info("...NOT verified - {0}".format(signed_apk))
         return compare_apks(signed_apk, unsigned_apk, tmp_dir)
     logging.info("...successfully verified")
@@ -1884,7 +1920,7 @@ def genkeystore(localconfig):
 
     write_password_file("keystorepass", localconfig['keystorepass'])
     write_password_file("keypass", localconfig['keypass'])
-    p = FDroidPopen(['keytool', '-genkey',
+    p = FDroidPopen([config['keytool'], '-genkey',
                      '-keystore', localconfig['keystore'],
                      '-alias', localconfig['repo_keyalias'],
                      '-keyalg', 'RSA', '-keysize', '4096',
@@ -1898,7 +1934,7 @@ def genkeystore(localconfig):
         raise BuildException("Failed to generate key", p.output)
     os.chmod(localconfig['keystore'], 0o0600)
     # now show the lovely key that was just generated
-    p = FDroidPopen(['keytool', '-list', '-v',
+    p = FDroidPopen([config['keytool'], '-list', '-v',
                      '-keystore', localconfig['keystore'],
                      '-alias', localconfig['repo_keyalias'],
                      '-storepass:file', config['keystorepassfile']])