chiark / gitweb /
Merge branch 'master' into logging
authorDaniel Martí <mvdan@mvdan.cc>
Wed, 29 Jan 2014 12:57:57 +0000 (13:57 +0100)
committerDaniel Martí <mvdan@mvdan.cc>
Wed, 29 Jan 2014 12:57:57 +0000 (13:57 +0100)
Conflicts:
fdroidserver/build.py

16 files changed:
fdroid
fdroidserver/build.py
fdroidserver/checkupdates.py
fdroidserver/common.py
fdroidserver/import.py
fdroidserver/init.py
fdroidserver/install.py
fdroidserver/lint.py
fdroidserver/metadata.py
fdroidserver/publish.py
fdroidserver/rewritemeta.py
fdroidserver/scanner.py
fdroidserver/server.py
fdroidserver/stats.py
fdroidserver/update.py
fdroidserver/verify.py

diff --git a/fdroid b/fdroid
index 69cc41e795857ba24502b4ce8596b0d0d7b72eb2..acb8004914485af62b8ef09ac61bf6807f9476f8 100755 (executable)
--- a/fdroid
+++ b/fdroid
@@ -19,6 +19,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import sys
+import logging
 
 commands = [
         "build",
@@ -54,6 +55,11 @@ def main():
         print_help()
         sys.exit(1)
 
+    verbose = any(s in sys.argv for s in ['-v', '--verbose'])
+
+    logging.basicConfig(format='%(levelname)s: %(message)s',
+            level=logging.DEBUG if verbose else logging.INFO)
+
     # Trick optparse into displaying the right usage when --help is used.
     sys.argv[0] += ' ' + command
 
index c60069d5d811adebf44fefb34fa3cd35ebdf1d4e..bdf54ed2db63c4aa96d296539e7114f4cfa01d5e 100644 (file)
@@ -29,6 +29,7 @@ import time
 import json
 from ConfigParser import ConfigParser
 from optparse import OptionParser, OptionError
+import logging
 
 import common, metadata
 from common import BuildException, VCSException, FDroidPopen
@@ -71,12 +72,8 @@ def vagrant(params, cwd=None, printout=False):
     :returns: (ret, out) where ret is the return code, and out
                is the stdout (and stderr) from vagrant
     """
-    p = subprocess.Popen(['vagrant'] + params, cwd=cwd,
-            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    out = p.communicate()[0]
-    if options.verbose:
-        print out
-    return (p.returncode, out)
+    p = FDroidPopen(['vagrant'] + params, cwd=cwd)
+    return (p.returncode, p.stdout)
 
 
 # Note that 'force' here also implies test mode.
@@ -88,52 +85,47 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
     # Reset existing builder machine to a clean state if possible.
     vm_ok = False
     if not options.resetserver:
-        print "Checking for valid existing build server"
+        logging.info("Checking for valid existing build server")
+
         if got_valid_builder_vm():
-            print "...VM is present"
-            p = subprocess.Popen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'list', '--details'],
-                cwd='builder', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            output = p.communicate()[0]
-            if 'fdroidclean' in output:
-                if options.verbose:
-                    print "...snapshot exists - resetting build server to clean state"
+            logging.info("...VM is present")
+            p = FDroidPopen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'list', '--details'], cwd='builder')
+            if 'fdroidclean' in p.stdout:
+                logging.info("...snapshot exists - resetting build server to clean state")
                 retcode, output = vagrant(['status'], cwd='builder')
+
                 if 'running' in output:
-                    if options.verbose:
-                        print "...suspending"
+                    logging.info("...suspending")
                     vagrant(['suspend'], cwd='builder')
-                    print "...waiting a sec..."
+                    logging.info("...waiting a sec...")
                     time.sleep(10)
-                p = subprocess.Popen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'restore', 'fdroidclean'],
-                    cwd='builder', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-                output = p.communicate()[0]
-                if options.verbose:
-                    print output
+                p = FDroidPopen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'restore', 'fdroidclean'],
+                    cwd='builder')
+
                 if p.returncode == 0:
-                    print "...reset to snapshot - server is valid"
+                    logging.info("...reset to snapshot - server is valid")
                     retcode, output = vagrant(['up'], cwd='builder')
                     if retcode != 0:
                         raise BuildException("Failed to start build server")
-                    print "...waiting a sec..."
+                    logging.info("...waiting a sec...")
                     time.sleep(10)
                     vm_ok = True
                 else:
-                    print "...failed to reset to snapshot"
+                    logging.info("...failed to reset to snapshot")
             else:
-                print "...snapshot doesn't exist - VBoxManage snapshot list:\n" + output
+                logging.info("...snapshot doesn't exist - VBoxManage snapshot list:\n" + output)
 
     # If we can't use the existing machine for any reason, make a
     # new one from scratch.
     if not vm_ok:
         if os.path.exists('builder'):
-            print "Removing broken/incomplete/unwanted build server"
+            logging.info("Removing broken/incomplete/unwanted build server")
             vagrant(['destroy', '-f'], cwd='builder')
             shutil.rmtree('builder')
         os.mkdir('builder')
 
-        p = subprocess.Popen('vagrant --version', shell=True, stdout=subprocess.PIPE)
-        vver = p.communicate()[0]
-        if vver.startswith('Vagrant version 1.2'):
+        p = FDroidPopen('vagrant --version', shell=True, stdout=subprocess.PIPE)
+        if p.stdout.startswith('Vagrant version 1.2'):
             with open('builder/Vagrantfile', 'w') as vf:
                 vf.write('Vagrant.configure("2") do |config|\n')
                 vf.write('config.vm.box = "buildserver"\n')
@@ -144,13 +136,13 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
                 vf.write('config.vm.box = "buildserver"\n')
                 vf.write('end\n')
 
-        print "Starting new build server"
+        logging.info("Starting new build server")
         retcode, _ = vagrant(['up'], cwd='builder')
         if retcode != 0:
             raise BuildException("Failed to start build server")
 
         # Open SSH connection to make sure it's working and ready...
-        print "Connecting to virtual machine..."
+        logging.info("Connecting to virtual machine...")
         if subprocess.call('vagrant ssh-config >sshconfig',
                 cwd='builder', shell=True) != 0:
             raise BuildException("Error getting ssh config")
@@ -170,38 +162,34 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
             key_filename=idfile)
         sshs.close()
 
-        print "Saving clean state of new build server"
+        logging.info("Saving clean state of new build server")
         retcode, _ = vagrant(['suspend'], cwd='builder')
         if retcode != 0:
             raise BuildException("Failed to suspend build server")
-        print "...waiting a sec..."
+        logging.info("...waiting a sec...")
         time.sleep(10)
-        p = subprocess.Popen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'take', 'fdroidclean'],
-                cwd='builder', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        output = p.communicate()[0]
+        p = FDroidPopen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'take', 'fdroidclean'],
+                cwd='builder')
         if p.returncode != 0:
-            print output
             raise BuildException("Failed to take snapshot")
-        print "...waiting a sec..."
+        logging.info("...waiting a sec...")
         time.sleep(10)
-        print "Restarting new build server"
+        logging.info("Restarting new build server")
         retcode, _ = vagrant(['up'], cwd='builder')
         if retcode != 0:
             raise BuildException("Failed to start build server")
-        print "...waiting a sec..."
+        logging.info("...waiting a sec...")
         time.sleep(10)
         # Make sure it worked...
-        p = subprocess.Popen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'list', '--details'],
-            cwd='builder', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        output = p.communicate()[0]
-        if 'fdroidclean' not in output:
+        p = FDroidPopen(['VBoxManage', 'snapshot', get_builder_vm_id(), 'list', '--details'],
+            cwd='builder')
+        if 'fdroidclean' not in p.stdout:
             raise BuildException("Failed to take snapshot.")
 
     try:
 
         # Get SSH configuration settings for us to connect...
-        if options.verbose:
-            print "Getting ssh configuration..."
+        logging.info("Getting ssh configuration...")
         subprocess.call('vagrant ssh-config >sshconfig',
                 cwd='builder', shell=True)
         vagranthost = 'default' # Host in ssh config file
@@ -214,8 +202,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
         sshconfig = sshconfig.lookup(vagranthost)
 
         # Open SSH connection...
-        if options.verbose:
-            print "Connecting to virtual machine..."
+        logging.info("Connecting to virtual machine...")
         sshs = ssh.SSHClient()
         sshs.set_missing_host_key_policy(ssh.AutoAddPolicy())
         idfile = sshconfig['identityfile']
@@ -251,7 +238,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
                     ftp.chdir('..')
             ftp.chdir('..')
 
-        print "Preparing server for build..."
+        logging.info("Preparing server for build...")
         serverpath = os.path.abspath(os.path.dirname(__file__))
         ftp.put(os.path.join(serverpath, 'build.py'), 'build.py')
         ftp.put(os.path.join(serverpath, 'common.py'), 'common.py')
@@ -303,8 +290,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
         if basesrclib:
             srclibpaths.append(basesrclib)
         for name, number, lib in srclibpaths:
-            if options.verbose:
-                print "Sending srclib '" + lib + "'"
+            logging.info("Sending srclib '%s'" % lib)
             ftp.chdir('/home/vagrant/build/srclib')
             if not os.path.exists(lib):
                 raise BuildException("Missing srclib directory '" + lib + "'")
@@ -324,7 +310,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
             send_dir(build_dir)
 
         # Execute the build script...
-        print "Starting build..."
+        logging.info("Starting build...")
         chan = sshs.get_transport().open_session()
         chan.get_pty()
         cmdline = 'python build.py --on-server'
@@ -339,7 +325,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
             while chan.recv_ready():
                 output += chan.recv(1024)
             time.sleep(0.1)
-        print "...getting exit status"
+        logging.info("...getting exit status")
         returncode = chan.recv_exit_status()
         while True:
             get = chan.recv(1024)
@@ -350,7 +336,7 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
             raise BuildException("Build.py failed on server for %s:%s" % (app['id'], thisbuild['version']), output)
 
         # Retrieve the built files...
-        print "Retrieving build output..."
+        logging.info("Retrieving build output...")
         if force:
             ftp.chdir('/home/vagrant/tmp')
         else:
@@ -368,15 +354,14 @@ def build_server(app, thisbuild, vcs, build_dir, output_dir, force):
     finally:
 
         # Suspend the build server.
-        print "Suspending build server"
+        logging.info("Suspending build server")
         subprocess.call(['vagrant', 'suspend'], cwd='builder')
 
 def adapt_gradle(build_dir):
     for root, dirs, files in os.walk(build_dir):
         if 'build.gradle' in files:
             path = os.path.join(root, 'build.gradle')
-            if options.verbose:
-                print "Adapting build.gradle at %s" % path
+            logging.info("Adapting build.gradle at %s" % path)
 
             subprocess.call(['sed', '-i',
                     r's@buildToolsVersion\([ =]*\)["\'][0-9\.]*["\']@buildToolsVersion\1"'
@@ -394,7 +379,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
     # different from the default ones
     p = None
     if thisbuild['type'] == 'maven':
-        print "Cleaning Maven project..."
+        logging.info("Cleaning Maven project...")
         cmd = [config['mvn3'], 'clean', '-Dandroid.sdk.path=' + config['sdk_path']]
 
         if '@' in thisbuild['maven']:
@@ -407,7 +392,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
     elif thisbuild['type'] == 'gradle':
 
-        print "Cleaning Gradle project..."
+        logging.info("Cleaning Gradle project...")
         cmd = [config['gradle'], 'clean']
 
         if '@' in thisbuild['gradle']:
@@ -426,7 +411,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         pass
 
     elif thisbuild['type'] == 'ant':
-        print "Cleaning Ant project..."
+        logging.info("Cleaning Ant project...")
         p = FDroidPopen(['ant', 'clean'], cwd=root_dir)
 
     if p is not None and p.returncode != 0:
@@ -434,19 +419,19 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
                 (app['id'], thisbuild['version']), p.stdout)
 
     # Scan before building...
-    print "Scanning source for common problems..."
+    logging.info("Scanning source for common problems...")
     buildprobs = common.scan_source(build_dir, root_dir, thisbuild)
     if len(buildprobs) > 0:
-        print 'Scanner found ' + str(len(buildprobs)) + ' problems:'
+        logging.info('Scanner found %d problems:' % len(buildprobs))
         for problem in buildprobs:
-            print '    %s' % problem
+            logging.info('    %s' % problem)
         if not force:
             raise BuildException("Can't build due to " +
                 str(len(buildprobs)) + " scanned problems")
 
     if not options.notarball:
         # Build the source tarball right before we build the release...
-        print "Creating source tarball..."
+        logging.info("Creating source tarball...")
         tarname = common.getsrcname(app,thisbuild)
         tarball = tarfile.open(os.path.join(tmp_dir, tarname), "w:gz")
         def tarexc(f):
@@ -461,8 +446,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         for name, number, libpath in srclibpaths:
             libpath = os.path.relpath(libpath, root_dir)
             cmd = cmd.replace('$$' + name + '$$', libpath)
-        if options.verbose:
-            print "Running 'build' commands in %s" % root_dir
+        logging.info("Running 'build' commands in %s" % root_dir)
 
         p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=root_dir)
 
@@ -472,7 +456,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
     # Build native stuff if required...
     if thisbuild.get('buildjni') not in (None, 'no'):
-        print "Building native libraries..."
+        logging.info("Building native libraries...")
         jni_components = thisbuild.get('buildjni')
         if jni_components == 'yes':
             jni_components = ['']
@@ -480,8 +464,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
             jni_components = [c.strip() for c in jni_components.split(';')]
         ndkbuild = os.path.join(config['ndk_path'], "ndk-build")
         for d in jni_components:
-            if options.verbose:
-                print "Running ndk-build in " + root_dir + '/' + d
+            logging.info("Building native code in '%s'" % d)
             manifest = root_dir + '/' + d + '/AndroidManifest.xml'
             if os.path.exists(manifest):
                 # Read and write the whole AM.xml to fix newlines and avoid
@@ -500,7 +483,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
     p = None
     # Build the release...
     if thisbuild['type'] == 'maven':
-        print "Building Maven project..."
+        logging.info("Building Maven project...")
 
         if '@' in thisbuild['maven']:
             maven_dir = os.path.join(root_dir, thisbuild['maven'].split('@',1)[1])
@@ -528,7 +511,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         bindir = os.path.join(root_dir, 'target')
 
     elif thisbuild['type'] == 'kivy':
-        print "Building Kivy project..."
+        logging.info("Building Kivy project...")
 
         spec = os.path.join(root_dir, 'buildozer.spec')
         if not os.path.exists(spec):
@@ -588,7 +571,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         p = FDroidPopen(cmd, cwd=distdir)
 
     elif thisbuild['type'] == 'gradle':
-        print "Building Gradle project..."
+        logging.info("Building Gradle project...")
         if '@' in thisbuild['gradle']:
             flavours = thisbuild['gradle'].split('@')[0].split(',')
             gradle_dir = thisbuild['gradle'].split('@')[1]
@@ -608,7 +591,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
         p = FDroidPopen(commands, cwd=gradle_dir)
 
     elif thisbuild['type'] == 'ant':
-        print "Building Ant project..."
+        logging.info("Building Ant project...")
         cmd = ['ant']
         if 'antcommand' in thisbuild:
             cmd += [thisbuild['antcommand']]
@@ -620,7 +603,7 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
     if p is not None and p.returncode != 0:
         raise BuildException("Build failed for %s:%s" % (app['id'], thisbuild['version']), p.stdout)
-    print "Successfully built version " + thisbuild['version'] + ' of ' + app['id']
+    logging.info("Successfully built version " + thisbuild['version'] + ' of ' + app['id'])
 
     if thisbuild['type'] == 'maven':
         stdout_apk = '\n'.join([
@@ -665,20 +648,18 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
 
     # By way of a sanity check, make sure the version and version
     # code in our new apk match what we expect...
-    print "Checking " + src
+    logging.info("Checking " + src)
     if not os.path.exists(src):
         raise BuildException("Unsigned apk is not at expected location of " + src)
 
-    p = subprocess.Popen([os.path.join(config['sdk_path'],
+    p = FDroidPopen([os.path.join(config['sdk_path'],
                         'build-tools', config['build_tools'], 'aapt'),
-                        'dump', 'badging', src],
-                        stdout=subprocess.PIPE)
-    output = p.communicate()[0]
+                        'dump', 'badging', src], output=False)
 
     vercode = None
     version = None
     foundid = None
-    for line in output.splitlines():
+    for line in p.stdout.splitlines():
         if line.startswith("package:"):
             pat = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
             m = pat.match(line)
@@ -766,7 +747,7 @@ def trybuild(app, thisbuild, build_dir, output_dir, also_check_dir, srclib_dir,
     if 'disable' in thisbuild:
         return False
 
-    print "Building version " + thisbuild['version'] + ' of ' + app['id']
+    logging.info("Building version " + thisbuild['version'] + ' of ' + app['id'])
 
     if server:
         # When using server mode, still keep a local cache of the repo, by
@@ -836,12 +817,12 @@ def main():
 
     log_dir = 'logs'
     if not os.path.isdir(log_dir):
-        print "Creating log directory"
+        logging.info("Creating log directory")
         os.makedirs(log_dir)
 
     tmp_dir = 'tmp'
     if not os.path.isdir(tmp_dir):
-        print "Creating temporary directory"
+        logging.info("Creating temporary directory")
         os.makedirs(tmp_dir)
 
     if options.test:
@@ -849,7 +830,7 @@ def main():
     else:
         output_dir = 'unsigned'
         if not os.path.isdir(output_dir):
-            print "Creating output directory"
+            logging.info("Creating output directory")
             os.makedirs(output_dir)
 
     if config['archive_older'] != 0:
@@ -861,7 +842,7 @@ def main():
 
     build_dir = 'build'
     if not os.path.isdir(build_dir):
-        print "Creating build directory"
+        logging.info("Creating build directory")
         os.makedirs(build_dir)
     srclib_dir = os.path.join(build_dir, 'srclib')
     extlib_dir = os.path.join(build_dir, 'extlib')
@@ -911,15 +892,13 @@ def main():
                         build_dir = os.path.join('build', app['id'])
 
                     # Set up vcs interface and make sure we have the latest code...
-                    if options.verbose:
-                        print "Getting {0} vcs interface for {1}".format(
-                                app['Repo Type'], app['Repo'])
+                    logging.info("Getting {0} vcs interface for {1}".format(
+                            app['Repo Type'], app['Repo']))
                     vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir)
 
                     first = False
 
-                if options.verbose:
-                    print "Checking " + thisbuild['version']
+                logging.info("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.force, options.onserver):
@@ -929,19 +908,19 @@ def main():
                 logfile = open(os.path.join(log_dir, app['id'] + '.log'), 'a+')
                 logfile.write(str(be))
                 logfile.close()
-                print "Could not build app %s due to BuildException: %s" % (app['id'], be)
+                logging.info("Could not build app %s due to BuildException: %s" % (app['id'], be))
                 if options.stop:
                     sys.exit(1)
                 failed_apps[app['id']] = be
                 wikilog = be.get_wikitext()
             except VCSException as vcse:
-                print "VCS error while building app %s: %s" % (app['id'], vcse)
+                logging.info("VCS error while building app %s: %s" % (app['id'], vcse))
                 if options.stop:
                     sys.exit(1)
                 failed_apps[app['id']] = vcse
                 wikilog = str(vcse)
             except Exception as e:
-                print "Could not build app %s due to unknown error: %s" % (app['id'], traceback.format_exc())
+                logging.info("Could not build app %s due to unknown error: %s" % (app['id'], traceback.format_exc()))
                 if options.stop:
                     sys.exit(1)
                 failed_apps[app['id']] = e
@@ -956,20 +935,20 @@ def main():
                     txt = "Build completed at " + time.strftime("%Y-%m-%d %H:%M:%SZ", time.gmtime()) + "\n\n" + txt
                     newpage.save(txt, summary='Build log')
                 except:
-                    print "Error while attempting to publish build log"
+                    logging.info("Error while attempting to publish build log")
 
     for app in build_succeeded:
-        print "success: %s" % (app['id'])
+        logging.info("success: %s" % (app['id']))
 
     if not options.verbose:
         for fa in failed_apps:
-            print "Build for app %s failed:\n%s" % (fa, failed_apps[fa])
+            logging.info("Build for app %s failed:\n%s" % (fa, failed_apps[fa]))
 
-    print "Finished."
+    logging.info("Finished.")
     if len(build_succeeded) > 0:
-        print str(len(build_succeeded)) + ' builds succeeded'
+        logging.info(str(len(build_succeeded)) + ' builds succeeded')
     if len(failed_apps) > 0:
-        print str(len(failed_apps)) + ' builds failed'
+        logging.info(str(len(failed_apps)) + ' builds failed')
 
     sys.exit(0)
 
index 232ae2c42dfd2cb8d83e52feaaa60eb3b180fe7e..4984ef2203dc23b9110d40e22464abc2703df8b3 100644 (file)
@@ -28,6 +28,8 @@ from optparse import OptionParser
 import traceback
 import HTMLParser
 from distutils.version import LooseVersion
+import logging
+
 import common, metadata
 from common import BuildException
 from common import VCSException
@@ -48,7 +50,7 @@ def check_http(app):
 
         vercode = "99999999"
         if len(urlcode) > 0:
-            print "...requesting {0}".format(urlcode)
+            logging.info("...requesting {0}".format(urlcode))
             req = urllib2.Request(urlcode, None)
             resp = urllib2.urlopen(req, None, 20)
             page = resp.read()
@@ -61,7 +63,7 @@ def check_http(app):
         version = "??"
         if len(urlver) > 0:
             if urlver != '.':
-                print "...requesting {0}".format(urlver)
+                logging.info("...requesting {0}".format(urlver))
                 req = urllib2.Request(urlver, None)
                 resp = urllib2.urlopen(req, None, 20)
                 page = resp.read()
@@ -114,16 +116,15 @@ def check_tags(app):
         hcode = "0"
 
         for tag in vcs.gettags():
-            if options.verbose:
-                print "Check tag: '{0}'".format(tag)
+            logging.info("Check tag: '{0}'".format(tag))
             vcs.gotorevision(tag)
 
             # Only process tags where the manifest exists...
             paths = common.manifest_paths(build_dir, flavour)
             version, vercode, package = common.parse_androidmanifests(paths)
             if package and package == app['id'] and version and vercode:
-                print "Manifest exists. Found version %s (%s)" % (
-                        version, vercode)
+                logging.info("Manifest exists. Found version %s (%s)" % (
+                        version, vercode))
                 if int(vercode) > int(hcode):
                     htag = tag
                     hcode = str(int(vercode))
@@ -201,7 +202,7 @@ def check_repomanifest(app, branch=None):
 
         vercode = str(int(vercode))
 
-        print "Manifest exists. Found version %s (%s)" % (version, vercode)
+        logging.info("Manifest exists. Found version %s (%s)" % (version, vercode))
 
         return (version, vercode)
 
@@ -307,38 +308,36 @@ def main():
     if options.gplay:
         for app in apps:
             version, reason = check_gplay(app)
-            if version is None and options.verbose:
+            if version is None:
                 if reason == '404':
-                    print "%s is not in the Play Store" % common.getappname(app)
+                    logging.info("%s is not in the Play Store" % common.getappname(app))
                 else:
-                    print "%s encountered a problem: %s" % (common.getappname(app), reason)
+                    logging.info("%s encountered a problem: %s" % (common.getappname(app), reason))
             if version is not None:
                 stored = app['Current Version']
                 if not stored:
-                    if options.verbose:
-                        print "%s has no Current Version but has version %s on the Play Store" % (
-                                common.getappname(app), version)
+                    logging.info("%s has no Current Version but has version %s on the Play Store" % (
+                            common.getappname(app), version))
                 elif LooseVersion(stored) < LooseVersion(version):
-                    print "%s has version %s on the Play Store, which is bigger than %s" % (
-                            common.getappname(app), version, stored)
-                elif options.verbose:
+                    logging.info("%s has version %s on the Play Store, which is bigger than %s" % (
+                            common.getappname(app), version, stored))
+                else:
                     if stored != version:
-                        print "%s has version %s on the Play Store, which differs from %s" % (
-                                common.getappname(app), version, stored)
+                        logging.info("%s has version %s on the Play Store, which differs from %s" % (
+                                common.getappname(app), version, stored))
                     else:
-                        print "%s has the same version %s on the Play Store" % (
-                                common.getappname(app), version)
+                        logging.info("%s has the same version %s on the Play Store" % (
+                                common.getappname(app), version))
         return
 
 
     for app in apps:
 
         if options.autoonly and app['Auto Update Mode'] == 'None':
-            if options.verbose:
-                print "Nothing to do for %s..." % app['id']
+            logging.info("Nothing to do for %s..." % app['id'])
             continue
 
-        print "Processing " + app['id'] + '...'
+        logging.info("Processing " + app['id'] + '...')
 
         writeit = False
         logmsg = None
@@ -374,9 +373,9 @@ def main():
 
         updating = False
         if not version:
-            print "...%s" % msg
+            logging.info("...%s" % msg)
         elif vercode == app['Current Version Code']:
-            print "...up to date"
+            logging.info("...up to date")
         else:
             app['Current Version'] = version
             app['Current Version Code'] = str(int(vercode))
@@ -413,12 +412,12 @@ def main():
                         app['Current Version'] = cv
                         writeit = True
             except Exception:
-                print "ERROR: Auto Name or Current Version failed for %s due to exception: %s" % (app['id'], traceback.format_exc())
+                logging.info("ERROR: Auto Name or Current Version failed for %s due to exception: %s" % (app['id'], traceback.format_exc()))
 
         if updating:
             name = common.getappname(app)
             ver = common.getcvname(app)
-            print '...updating to version %s' % ver
+            logging.info('...updating to version %s' % ver)
             logmsg = 'Update CV of %s to %s' % (name, ver)
 
         if options.auto:
@@ -447,7 +446,7 @@ def main():
                         del newbuild['origlines']
                     newbuild['vercode'] = app['Current Version Code']
                     newbuild['version'] = app['Current Version'] + suffix
-                    print "...auto-generating build for " + newbuild['version']
+                    logging.info("...auto-generating build for " + newbuild['version'])
                     commit = pattern.replace('%v', newbuild['version'])
                     commit = commit.replace('%c', newbuild['vercode'])
                     newbuild['commit'] = commit
@@ -457,23 +456,23 @@ def main():
                     ver = common.getcvname(app)
                     logmsg = "Update %s to %s" % (name, ver)
             else:
-                print 'Invalid auto update mode "' + mode + '"'
+                logging.info('Invalid auto update mode "' + mode + '"')
 
         if writeit:
             metafile = os.path.join('metadata', app['id'] + '.txt')
             metadata.write_metadata(metafile, app)
             if options.commit and logmsg:
-                print "Commiting update for " + metafile
+                logging.info("Commiting update for " + metafile)
                 gitcmd = ["git", "commit", "-m",
                     logmsg]
                 if 'auto_author' in config:
                     gitcmd.extend(['--author', config['auto_author']])
                 gitcmd.extend(["--", metafile])
                 if subprocess.call(gitcmd) != 0:
-                    print "Git commit failed"
+                    logging.info("Git commit failed")
                     sys.exit(1)
 
-    print "Finished."
+    logging.info("Finished.")
 
 if __name__ == "__main__":
     main()
index b348af1f1836077885f7600935a36df97f4976ab..9469f77645934b2dc0b8e1dc498f7ff24c275859 100644 (file)
@@ -26,6 +26,7 @@ import operator
 import Queue
 import threading
 import magic
+import logging
 
 import metadata
 
@@ -43,12 +44,10 @@ def read_config(opts, config_file='config.py'):
     if config is not None:
         return config
     if not os.path.isfile(config_file):
-        print "Missing config file - is this a repo directory?"
+        logging.critical("Missing config file - is this a repo directory?")
         sys.exit(2)
 
     options = opts
-    if not hasattr(options, 'verbose'):
-        options.verbose = False
 
     defconfig = {
         'sdk_path': "$ANDROID_HOME",
@@ -69,14 +68,13 @@ def read_config(opts, config_file='config.py'):
     }
     config = {}
 
-    if options.verbose:
-        print "Reading %s..." % config_file
+    logging.info("Reading %s" % config_file)
     execfile(config_file, config)
 
     if any(k in config for k in ["keystore", "keystorepass", "keypass"]):
         st = os.stat(config_file)
         if st.st_mode & stat.S_IRWXG or st.st_mode & stat.S_IRWXO:
-            print "WARNING: unsafe permissions on {0} (should be 0600)!".format(config_file)
+            logging.warn("unsafe permissions on {0} (should be 0600)!".format(config_file))
 
     for k, v in defconfig.items():
         if k not in config:
@@ -129,7 +127,7 @@ def read_app_args(args, allapps, allow_vercodes=False):
         allids = [app["id"] for app in allapps]
         for p in vercodes:
             if p not in allids:
-                print "No such package: %s" % p
+                logging.critical("No such package: %s" % p)
         raise Exception("Found invalid app ids in arguments")
 
     error = False
@@ -143,7 +141,7 @@ def read_app_args(args, allapps, allow_vercodes=False):
             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'])
+                    logging.critical("No such vercode %s for app %s" % (v, app['id']))
 
     if error:
         raise Exception("Found invalid vercodes for some apps")
@@ -250,10 +248,10 @@ class vcs:
                     writeback = False
                 else:
                     deleterepo = True
-                    print "*** Repository details changed - deleting ***"
+                    logging.info("Repository details changed - deleting")
             else:
                 deleterepo = True
-                print "*** Repository details missing - deleting ***"
+                logging.info("Repository details missing - deleting")
         if deleterepo:
             shutil.rmtree(self.local)
 
@@ -296,29 +294,28 @@ class vcs_git(vcs):
     # fdroidserver) and then we'll proceed to destroy it! This is called as
     # a safety check.
     def checkrepo(self):
-        p = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'],
-                stdout=subprocess.PIPE, cwd=self.local)
-        result = p.communicate()[0].rstrip()
+        p = FDroidPopen(['git', 'rev-parse', '--show-toplevel'], cwd=self.local)
+        result = p.stdout.rstrip()
         if not result.endswith(self.local):
             raise VCSException('Repository mismatch')
 
     def gotorevisionx(self, rev):
         if not os.path.exists(self.local):
-            # Brand new checkout...
+            # Brand new checkout
             if subprocess.call(['git', 'clone', self.remote, self.local]) != 0:
                 raise VCSException("Git clone failed")
             self.checkrepo()
         else:
             self.checkrepo()
-            # Discard any working tree changes...
+            # Discard any working tree changes
             if subprocess.call(['git', 'reset', '--hard'], cwd=self.local) != 0:
                 raise VCSException("Git reset failed")
             # Remove untracked files now, in case they're tracked in the target
-            # revision (it happens!)...
+            # revision (it happens!)
             if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
                 raise VCSException("Git clean failed")
             if not self.refreshed:
-                # Get latest commits and tags from remote...
+                # Get latest commits and tags from remote
                 if subprocess.call(['git', 'fetch', 'origin'],
                         cwd=self.local) != 0:
                     raise VCSException("Git fetch failed")
@@ -326,11 +323,11 @@ class vcs_git(vcs):
                         cwd=self.local) != 0:
                     raise VCSException("Git fetch failed")
                 self.refreshed = True
-        # Check out the appropriate revision...
+        # Check out the appropriate revision
         rev = str(rev if rev else 'origin/master')
         if subprocess.call(['git', 'checkout', '-f', rev], cwd=self.local) != 0:
             raise VCSException("Git checkout failed")
-        # Get rid of any uncontrolled files left behind...
+        # Get rid of any uncontrolled files left behind
         if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
             raise VCSException("Git clean failed")
 
@@ -351,9 +348,8 @@ class vcs_git(vcs):
 
     def gettags(self):
         self.checkrepo()
-        p = subprocess.Popen(['git', 'tag'],
-                stdout=subprocess.PIPE, cwd=self.local)
-        return p.communicate()[0].splitlines()
+        p = FDroidPopen(['git', 'tag'], cwd=self.local)
+        return p.stdout.splitlines()
 
 
 class vcs_gitsvn(vcs):
@@ -373,15 +369,14 @@ class vcs_gitsvn(vcs):
     # fdroidserver) and then we'll proceed to destory it! This is called as
     # a safety check.
     def checkrepo(self):
-        p = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'],
-                stdout=subprocess.PIPE, cwd=self.local)
-        result = p.communicate()[0].rstrip()
+        p = FDroidPopen(['git', 'rev-parse', '--show-toplevel'], cwd=self.local)
+        result = p.stdout.rstrip()
         if not result.endswith(self.local):
             raise VCSException('Repository mismatch')
 
     def gotorevisionx(self, rev):
         if not os.path.exists(self.local):
-            # Brand new checkout...
+            # Brand new checkout
             gitsvn_cmd = '%sgit svn clone %s' % self.userargs()
             if ';' in self.remote:
                 remote_split = self.remote.split(';')
@@ -402,15 +397,15 @@ class vcs_gitsvn(vcs):
             self.checkrepo()
         else:
             self.checkrepo()
-            # Discard any working tree changes...
+            # Discard any working tree changes
             if subprocess.call(['git', 'reset', '--hard'], cwd=self.local) != 0:
                 raise VCSException("Git reset failed")
             # Remove untracked files now, in case they're tracked in the target
-            # revision (it happens!)...
+            # revision (it happens!)
             if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
                 raise VCSException("Git clean failed")
             if not self.refreshed:
-                # Get new commits and tags from repo...
+                # Get new commits and tags from repo
                 if subprocess.call(['%sgit svn rebase %s' % self.userargs()],
                         cwd=self.local, shell=True) != 0:
                     raise VCSException("Git svn rebase failed")
@@ -420,12 +415,8 @@ class vcs_gitsvn(vcs):
         if rev:
             nospaces_rev = rev.replace(' ', '%20')
             # Try finding a svn tag
-            p = subprocess.Popen(['git', 'checkout', 'tags/' + nospaces_rev],
-                    cwd=self.local, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-            out, err = p.communicate()
-            if p.returncode == 0:
-                print out
-            else:
+            p = FDroidPopen(['git', 'checkout', 'tags/' + nospaces_rev], cwd=self.local)
+            if p.returncode != 0:
                 # No tag found, normal svn rev translation
                 # Translate svn rev into git format
                 rev_split = rev.split('/')
@@ -439,30 +430,22 @@ class vcs_gitsvn(vcs):
                     treeish = 'master'
                     svn_rev = rev
 
-                p = subprocess.Popen(['git', 'svn', 'find-rev', 'r' + svn_rev, treeish],
-                    cwd=self.local, stdout=subprocess.PIPE)
-                git_rev = p.communicate()[0].rstrip()
+                p = FDroidPopen(['git', 'svn', 'find-rev', 'r' + svn_rev, treeish],
+                    cwd=self.local)
+                git_rev = p.stdout.rstrip()
 
                 if p.returncode != 0 or not git_rev:
                     # Try a plain git checkout as a last resort
-                    p = subprocess.Popen(['git', 'checkout', rev], cwd=self.local,
-                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-                    out, err = p.communicate()
-                    if p.returncode == 0:
-                        print out
-                    else:
+                    p = FDroidPopen(['git', 'checkout', rev], cwd=self.local)
+                    if p.returncode != 0:
                         raise VCSException("No git treeish found and direct git checkout failed")
                 else:
                     # Check out the git rev equivalent to the svn rev
-                    p = subprocess.Popen(['git', 'checkout', git_rev], cwd=self.local,
-                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-                    out, err = p.communicate()
-                    if p.returncode == 0:
-                        print out
-                    else:
+                    p = FDroidPopen(['git', 'checkout', git_rev], cwd=self.local)
+                    if p.returncode != 0:
                         raise VCSException("Git svn checkout failed")
 
-        # Get rid of any uncontrolled files left behind...
+        # Get rid of any uncontrolled files left behind
         if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
             raise VCSException("Git clean failed")
 
@@ -472,9 +455,10 @@ class vcs_gitsvn(vcs):
 
     def getref(self):
         self.checkrepo()
-        p = subprocess.Popen(['git', 'svn', 'find-rev', 'HEAD'],
-                stdout=subprocess.PIPE, cwd=self.local)
-        return p.communicate()[0].strip()
+        p = FDroidPopen(['git', 'svn', 'find-rev', 'HEAD'], cwd=self.local)
+        if p.returncode != 0:
+            return None
+        return p.stdout.strip()
 
 class vcs_svn(vcs):
 
@@ -511,11 +495,11 @@ class vcs_svn(vcs):
             raise VCSException("Svn update failed")
 
     def getref(self):
-        p = subprocess.Popen(['svn', 'info'],
-                stdout=subprocess.PIPE, cwd=self.local)
+        p = FDroidPopen(['svn', 'info'], cwd=self.local)
         for line in p.communicate()[0].splitlines():
             if line and line.startswith('Last Changed Rev: '):
                 return line[18:]
+        return None
 
 class vcs_hg(vcs):
 
@@ -542,11 +526,9 @@ class vcs_hg(vcs):
         if subprocess.call(['hg', 'update', '-C', rev],
                 cwd=self.local) != 0:
             raise VCSException("Hg checkout failed")
-        p = subprocess.Popen(['hg', 'purge', '--all'], stdout=subprocess.PIPE,
-                             cwd=self.local)
-        result = p.communicate()[0]
+        p = FDroidPopen(['hg', 'purge', '--all'], cwd=self.local)
         # Also delete untracked files, we have to enable purge extension for that:
-        if "'purge' is provided by the following extension" in result:
+        if "'purge' is provided by the following extension" in p.stdout:
             with open(self.local+"/.hg/hgrc", "a") as myfile:
                 myfile.write("\n[extensions]\nhgext.purge=\n")
             if subprocess.call(['hg', 'purge', '--all'], cwd=self.local) != 0:
@@ -555,9 +537,8 @@ class vcs_hg(vcs):
             raise VCSException("HG purge failed")
 
     def gettags(self):
-        p = subprocess.Popen(['hg', 'tags', '-q'],
-                stdout=subprocess.PIPE, cwd=self.local)
-        return p.communicate()[0].splitlines()[1:]
+        p = FDroidPopen(['hg', 'tags', '-q'], cwd=self.local)
+        return p.stdout.splitlines()[1:]
 
 
 class vcs_bzr(vcs):
@@ -585,10 +566,9 @@ class vcs_bzr(vcs):
             raise VCSException("Bzr revert failed")
 
     def gettags(self):
-        p = subprocess.Popen(['bzr', 'tags'],
-                stdout=subprocess.PIPE, cwd=self.local)
+        p = FDroidPopen(['bzr', 'tags'], cwd=self.local)
         return [tag.split('   ')[0].strip() for tag in
-                p.communicate()[0].splitlines()]
+                p.stdout.splitlines()]
 
 def retrieve_string(xml_dir, string):
     if string.startswith('@string/'):
@@ -664,8 +644,7 @@ def ant_subprojects(root_dir):
             relpath = os.path.join(root_dir, path)
             if not os.path.isdir(relpath):
                 continue
-            if options.verbose:
-                print "Found subproject %s..." % path
+            logging.info("Found subproject at %s" % path)
             subprojects.append(path)
     return subprojects
 
@@ -836,7 +815,7 @@ def getsrclib(spec, srclib_dir, srclibpaths=[], subdir=None, target=None,
                         % name, p.stdout)
 
         if srclib["Update Project"] == "Yes" and not (autoupdate and number):
-            print "Updating srclib %s at path %s" % (name, libdir)
+            logging.info("Updating srclib %s at path %s" % (name, libdir))
             cmd = [os.path.join(config['sdk_path'], 'tools', 'android'),
                 'update', 'project', '-p', libdir]
             if target:
@@ -873,32 +852,30 @@ def getsrclib(spec, srclib_dir, srclibpaths=[], subdir=None, target=None,
 #   'srclibpaths' is information on the srclibs being used
 def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=False):
 
-    # Optionally, the actual app source can be in a subdirectory...
+    # Optionally, the actual app source can be in a subdirectory
     if 'subdir' in build:
         root_dir = os.path.join(build_dir, build['subdir'])
     else:
         root_dir = build_dir
 
-    # Get a working copy of the right revision...
-    print "Getting source for revision " + build['commit']
+    # Get a working copy of the right revision
+    logging.info("Getting source for revision " + build['commit'])
     vcs.gotorevision(build['commit'])
 
     # Check that a subdir (if we're using one) exists. This has to happen
-    # after the checkout, since it might not exist elsewhere...
+    # after the checkout, since it might not exist elsewhere
     if not os.path.exists(root_dir):
         raise BuildException('Missing subdir ' + root_dir)
 
-    # Initialise submodules if requred...
+    # Initialise submodules if requred
     if build['submodules']:
-        if options.verbose:
-            print "Initialising submodules..."
+        logging.info("Initialising submodules")
         vcs.initsubmodules()
 
-    # Run an init command if one is required...
+    # Run an init command if one is required
     if 'init' in build:
         cmd = replace_config_vars(build['init'])
-        if options.verbose:
-            print "Running 'init' commands in %s" % root_dir
+        logging.info("Running 'init' commands in %s" % root_dir)
 
         p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=root_dir)
         if p.returncode != 0:
@@ -909,18 +886,18 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
     if 'patch' in build:
         for patch in build['patch'].split(';'):
             patch = patch.strip()
-            print "Applying " + patch
+            logging.info("Applying " + patch)
             patch_path = os.path.join('metadata', app['id'], patch)
             if subprocess.call(['patch', '-p1',
                             '-i', os.path.abspath(patch_path)], cwd=build_dir) != 0:
                 raise BuildException("Failed to apply patch %s" % patch_path)
 
-    # Get required source libraries...
+    # Get required source libraries
     srclibpaths = []
     updatemode = build.get('update', 'auto')
     if 'srclibs' in build:
         target=build['target'] if 'target' in build else None
-        print "Collecting source libraries..."
+        logging.info("Collecting source libraries")
         for lib in build['srclibs'].split(';'):
             srclibpaths.append(getsrclib(lib, srclib_dir, srclibpaths,
                 target=target, preponly=onserver, autoupdate=(updatemode=='auto')))
@@ -945,13 +922,13 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
             update_dirs = ['.'] + ant_subprojects(root_dir)
         else:
             update_dirs = [d.strip() for d in updatemode.split(';')]
-        # Force build.xml update if necessary...
+        # Force build.xml update if necessary
         if updatemode == 'force' or 'target' in build:
             if updatemode == 'force':
                 update_dirs = ['.']
             buildxml = os.path.join(root_dir, 'build.xml')
             if os.path.exists(buildxml):
-                print 'Force-removing old build.xml'
+                logging.info('Force-removing old build.xml')
                 os.remove(buildxml)
 
         for d in update_dirs:
@@ -959,11 +936,10 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
             # Clean update dirs via ant
             p = FDroidPopen(['ant', 'clean'], cwd=subdir)
             dparms = parms + ['-p', d]
-            if options.verbose:
-                if d == '.':
-                    print "Updating main project..."
-                else:
-                    print "Updating subproject %s..." % d
+            if d == '.':
+                logging.info("Updating main project")
+            else:
+                logging.info("Updating subproject %s" % d)
             p = FDroidPopen(dparms, cwd=root_dir)
             # Check to see whether an error was returned without a proper exit
             # code (this is the case for the 'no target set or target invalid'
@@ -972,21 +948,20 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                 raise BuildException("Failed to update project at %s" % d,
                         p.stdout)
 
-    # Update the local.properties file...
+    # Update the local.properties file
     localprops = [ os.path.join(build_dir, 'local.properties') ]
     if 'subdir' in build:
         localprops += [ os.path.join(root_dir, 'local.properties') ]
     for path in localprops:
         if not os.path.isfile(path):
             continue
-        if options.verbose:
-            print "Updating properties file at %s" % path
+        logging.info("Updating properties file at %s" % path)
         f = open(path, 'r')
         props = f.read()
         f.close()
         props += '\n'
         # Fix old-fashioned 'sdk-location' by copying
-        # from sdk.dir, if necessary...
+        # from sdk.dir, if necessary
         if build['oldsdkloc']:
             sdkloc = re.match(r".*^sdk.dir=(\S+)$.*", props,
                 re.S|re.M).group(1)
@@ -995,10 +970,10 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
             props += "sdk.dir=%s\n" % config['sdk_path']
             props += "sdk-location=%s\n" % ['sdk_path']
         if 'ndk_path' in config:
-            # Add ndk location...
+            # Add ndk location
             props += "ndk.dir=%s\n" % config['ndk_path']
             props += "ndk-location=%s\n" % config['ndk_path']
-        # Add java.encoding if necessary...
+        # Add java.encoding if necessary
         if 'encoding' in build:
             props += "java.encoding=%s\n" % build['encoding']
         f = open(path, 'w')
@@ -1024,7 +999,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                     'build.gradle'], cwd=gradle_dir)
 
     # Remove forced debuggable flags
-    print "Removing debuggable flags..."
+    logging.info("Removing debuggable flags")
     for path in manifest_paths(root_dir, flavour):
         if not os.path.isfile(path):
             continue
@@ -1032,9 +1007,9 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
             's/android:debuggable="[^"]*"//g', path]) != 0:
             raise BuildException("Failed to remove debuggable flags")
 
-    # Insert version code and number into the manifest if necessary...
+    # Insert version code and number into the manifest if necessary
     if build['forceversion']:
-        print "Changing the version name..."
+        logging.info("Changing the version name")
         for path in manifest_paths(root_dir, flavour):
             if not os.path.isfile(path):
                 continue
@@ -1049,7 +1024,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                     path]) != 0:
                     raise BuildException("Failed to amend build.gradle")
     if build['forcevercode']:
-        print "Changing the version code..."
+        logging.info("Changing the version code")
         for path in manifest_paths(root_dir, flavour):
             if not os.path.isfile(path):
                 continue
@@ -1064,13 +1039,12 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                     path]) != 0:
                     raise BuildException("Failed to amend build.gradle")
 
-    # Delete unwanted files...
+    # Delete unwanted files
     if 'rm' in build:
         for part in build['rm'].split(';'):
             dest = os.path.join(build_dir, part.strip())
             rdest = os.path.abspath(dest)
-            if options.verbose:
-                print "Removing {0}".format(rdest)
+            logging.info("Removing {0}".format(rdest))
             if not rdest.startswith(os.path.abspath(build_dir)):
                 raise BuildException("rm for {1} is outside build root {0}".format(
                     os.path.abspath(build_dir),os.path.abspath(dest)))
@@ -1082,10 +1056,9 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                 else:
                     subprocess.call('rm -rf ' + rdest, shell=True)
             else:
-                if options.verbose:
-                    print "...but it didn't exist"
+                logging.info("...but it didn't exist")
 
-    # Fix apostrophes translation files if necessary...
+    # Fix apostrophes translation files if necessary
     if build['fixapos']:
         for root, dirs, files in os.walk(os.path.join(root_dir, 'res')):
             for filename in files:
@@ -1096,7 +1069,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                         os.path.join(root, filename)]) != 0:
                         raise BuildException("Failed to amend " + filename)
 
-    # Fix translation files if necessary...
+    # Fix translation files if necessary
     if build['fixtrans']:
         for root, dirs, files in os.walk(os.path.join(root_dir, 'res')):
             for filename in files:
@@ -1122,7 +1095,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
                             else:
                                 index += 1
                         # We only want to insert the positional arguments
-                        # when there is more than one argument...
+                        # when there is more than one argument
                         if oldline != line:
                             if num > 2:
                                 changed = True
@@ -1137,33 +1110,31 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
 
     remove_signing_keys(build_dir)
 
-    # Add required external libraries...
+    # Add required external libraries
     if 'extlibs' in build:
-        print "Collecting prebuilt libraries..."
+        logging.info("Collecting prebuilt libraries")
         libsdir = os.path.join(root_dir, 'libs')
         if not os.path.exists(libsdir):
             os.mkdir(libsdir)
         for lib in build['extlibs'].split(';'):
             lib = lib.strip()
-            if options.verbose:
-                print "...installing extlib {0}".format(lib)
+            logging.info("...installing extlib {0}".format(lib))
             libf = os.path.basename(lib)
             libsrc = os.path.join(extlib_dir, lib)
             if not os.path.exists(libsrc):
                 raise BuildException("Missing extlib file {0}".format(libsrc))
             shutil.copyfile(libsrc, os.path.join(libsdir, libf))
 
-    # Run a pre-build command if one is required...
+    # Run a pre-build command if one is required
     if 'prebuild' in build:
         cmd = replace_config_vars(build['prebuild'])
 
-        # Substitute source library paths into prebuild commands...
+        # Substitute source library paths into prebuild commands
         for name, number, libpath in srclibpaths:
             libpath = os.path.relpath(libpath, root_dir)
             cmd = cmd.replace('$$' + name + '$$', libpath)
 
-        if options.verbose:
-            print "Running 'prebuild' commands in %s" % root_dir
+        logging.info("Running 'prebuild' commands in %s" % root_dir)
 
         p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=root_dir)
         if p.returncode != 0:
@@ -1229,7 +1200,7 @@ def scan_source(build_dir, root_dir, thisbuild):
         return False
 
     def removeproblem(what, fd, fp):
-        print 'Removing %s at %s' % (what, fd)
+        logging.info('Removing %s at %s' % (what, fd))
         os.remove(fp)
 
     def handleproblem(what, fd, fp):
@@ -1239,20 +1210,20 @@ def scan_source(build_dir, root_dir, thisbuild):
             problems.append('Found %s at %s' % (what, fd))
 
     def warnproblem(what, fd, fp):
-        print 'Warning: Found %s at %s' % (what, fd)
+        logging.info('Warning: Found %s at %s' % (what, fd))
 
-    # Iterate through all files in the source code...
+    # Iterate through all files in the source code
     for r,d,f in os.walk(build_dir):
         for curfile in f:
 
             if '/.hg' in r or '/.git' in r or '/.svn' in r:
                 continue
 
-            # Path (relative) to the file...
+            # Path (relative) to the file
             fp = os.path.join(r, curfile)
             fd = fp[len(build_dir):]
 
-            # Check if this file has been explicitly excluded from scanning...
+            # Check if this file has been explicitly excluded from scanning
             if toignore(fd):
                 continue
 
@@ -1280,7 +1251,7 @@ def scan_source(build_dir, root_dir, thisbuild):
     ms.close()
 
     # Presence of a jni directory without buildjni=yes might
-    # indicate a problem... (if it's not a problem, explicitly use
+    # indicate a problem (if it's not a problem, explicitly use
     # buildjni=no to bypass this check)
     if (os.path.exists(os.path.join(root_dir, 'jni')) and
             thisbuild.get('buildjni') is None):
@@ -1358,15 +1329,14 @@ def isApkDebuggable(apkfile, config):
 
     :param apkfile: full path to the apk to check"""
 
-    p = subprocess.Popen([os.path.join(config['sdk_path'],
+    p = FDroidPopen([os.path.join(config['sdk_path'],
         'build-tools', config['build_tools'], 'aapt'),
         'dump', 'xmltree', apkfile, 'AndroidManifest.xml'],
-        stdout=subprocess.PIPE)
-    output = p.communicate()[0]
+        output=False)
     if p.returncode != 0:
-        print "ERROR: Failed to get apk manifest information"
+        logging.critical("Failed to get apk manifest information")
         sys.exit(1)
-    for line in output.splitlines():
+    for line in p.stdout.splitlines():
         if 'android:debuggable' in line and not line.endswith('0x0'):
             return True
     return False
@@ -1398,26 +1368,25 @@ class AsynchronousFileReader(threading.Thread):
 class PopenResult:
     returncode = None
     stdout = ''
-    stderr = ''
-    stdout_apk = ''
 
-def FDroidPopen(commands, cwd=None):
+def FDroidPopen(commands, cwd=None, output=True):
     """
     Run a command and capture the output.
 
     :param commands: command and argument list like in subprocess.Popen
     :param cwd: optionally specifies a working directory
+    :param output: whether to print output as it is fetched
     :returns: A PopenResult.
     """
 
-    if options.verbose:
-        if cwd:
-            print "Directory: %s" % cwd
-        print " > %s" % ' '.join(commands)
+    if cwd:
+        logging.info("Directory: %s" % cwd)
+    logging.info("> %s" % ' '.join(commands))
 
     result = PopenResult()
     p = subprocess.Popen(commands, cwd=cwd,
-            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+            stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+            stdin=subprocess.PIPE)
 
     stdout_queue = Queue.Queue()
     stdout_reader = AsynchronousFileReader(p.stdout, stdout_queue)
@@ -1427,7 +1396,7 @@ def FDroidPopen(commands, cwd=None):
     while not stdout_reader.eof():
         while not stdout_queue.empty():
             line = stdout_queue.get()
-            if options.verbose:
+            if output and options.verbose:
                 # Output directly to console
                 sys.stdout.write(line)
                 sys.stdout.flush()
@@ -1474,8 +1443,8 @@ def remove_signing_keys(build_dir):
                     else:
                         o.write(line)
 
-            if changed and options.verbose:
-                print "Cleaned build.gradle of keysigning configs at %s" % path
+            if changed:
+                logging.info("Cleaned build.gradle of keysigning configs at %s" % path)
 
         for propfile in ('build.properties', 'default.properties', 'ant.properties'):
             if propfile in files:
@@ -1492,8 +1461,8 @@ def remove_signing_keys(build_dir):
                         else:
                             o.write(line)
 
-                if changed and options.verbose:
-                    print "Cleaned %s of keysigning configs at %s" % (propfile,path)
+                if changed:
+                    logging.info("Cleaned %s of keysigning configs at %s" % (propfile,path))
 
 def replace_config_vars(cmd):
     cmd = cmd.replace('$$SDK$$', config['sdk_path'])
index e157b81d489ae670e578046cb4ea6fc7352b9887..64de7740c6858f03fde52092d7b113a43cceed0f 100644 (file)
@@ -24,6 +24,7 @@ import shutil
 import urllib
 from optparse import OptionParser
 from ConfigParser import ConfigParser
+import logging
 import common, metadata
 
 # Get the repo type and address from the given web page. The page is scanned
@@ -106,13 +107,13 @@ def main():
     config = common.read_config(options)
 
     if not options.url:
-        print "Specify project url."
+        logging.info("Specify project url.")
         sys.exit(1)
     url = options.url
 
     tmp_dir = 'tmp'
     if not os.path.isdir(tmp_dir):
-        print "Creating temporary directory"
+        logging.info("Creating temporary directory")
         os.makedirs(tmp_dir)
 
     # Get all apps...
@@ -133,7 +134,7 @@ def main():
         if url.endswith('/'):
             url = url[:-1]
         if url.endswith('.git'):
-            print "A github URL should point to the project, not the git repo"
+            logging.info("A github URL should point to the project, not the git repo")
             sys.exit(1)
         projecttype = 'github'
         repo = url + '.git'
@@ -154,7 +155,7 @@ def main():
         # Figure out the repo type and adddress...
         repotype, repo = getrepofrompage(sourcecode)
         if not repotype:
-            print "Unable to determine vcs type. " + repo
+            logging.info("Unable to determine vcs type. " + repo)
             sys.exit(1)
     elif url.startswith('http://code.google.com/p/'):
         if not url.endswith('/'):
@@ -168,29 +169,29 @@ def main():
         # Figure out the repo type and adddress...
         repotype, repo = getrepofrompage(sourcecode)
         if not repotype:
-            print "Unable to determine vcs type. " + repo
+            logging.info("Unable to determine vcs type. " + repo)
             sys.exit(1)
 
         # Figure out the license...
         req = urllib.urlopen(url)
         if req.getcode() != 200:
-            print 'Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode())
+            logging.info('Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode()))
             sys.exit(1)
         page = req.read()
         index = page.find('Code license')
         if index == -1:
-            print "Couldn't find license data"
+            logging.info("Couldn't find license data")
             sys.exit(1)
         ltext = page[index:]
         lprefix = 'rel="nofollow">'
         index = ltext.find(lprefix)
         if index == -1:
-            print "Couldn't find license text"
+            logging.info("Couldn't find license text")
             sys.exit(1)
         ltext = ltext[index + len(lprefix):]
         index = ltext.find('<')
         if index == -1:
-            print "License text not formatted as expected"
+            logging.info("License text not formatted as expected")
             sys.exit(1)
         ltext = ltext[:index]
         if ltext == 'GNU GPL v3':
@@ -208,17 +209,17 @@ def main():
         elif ltext == 'New BSD License':
             license = 'NewBSD'
         else:
-            print "License " + ltext + " is not recognised"
+            logging.info("License " + ltext + " is not recognised")
             sys.exit(1)
 
     if not projecttype:
-        print "Unable to determine the project type."
-        print "The URL you supplied was not in one of the supported formats. Please consult"
-        print "the manual for a list of supported formats, and supply one of those."
+        logging.info("Unable to determine the project type.")
+        logging.info("The URL you supplied was not in one of the supported formats. Please consult")
+        logging.info("the manual for a list of supported formats, and supply one of those.")
         sys.exit(1)
 
     # Get a copy of the source so we can extract some info...
-    print 'Getting source from ' + repotype + ' repo at ' + repo
+    logging.info('Getting source from ' + repotype + ' repo at ' + repo)
     src_dir = os.path.join(tmp_dir, 'importer')
     if os.path.exists(src_dir):
         shutil.rmtree(src_dir)
@@ -235,12 +236,12 @@ def main():
 
         version, vercode, package = common.parse_androidmanifests(paths)
         if not package:
-            print "Couldn't find package ID"
+            logging.info("Couldn't find package ID")
             sys.exit(1)
         if not version:
-            print "WARNING: Couldn't find latest version name"
+            logging.info("WARNING: Couldn't find latest version name")
         if not vercode:
-            print "WARNING: Couldn't find latest version code"
+            logging.info("WARNING: Couldn't find latest version code")
     else:
         spec = os.path.join(root_dir, 'buildozer.spec')
         if os.path.exists(spec):
@@ -252,13 +253,13 @@ def main():
             version = bconfig.get('app', 'version')
             vercode = None
         else:
-            print "No android or kivy project could be found. Specify --subdir?"
+            logging.info("No android or kivy project could be found. Specify --subdir?")
             sys.exit(1)
 
     # Make sure it's actually new...
     for app in apps:
         if app['id'] == package:
-            print "Package " + package + " already exists"
+            logging.info("Package " + package + " already exists")
             sys.exit(1)
 
     # Construct the metadata...
@@ -295,7 +296,7 @@ def main():
 
     metafile = os.path.join('metadata', package + '.txt')
     metadata.write_metadata(metafile, app)
-    print "Wrote " + metafile
+    logging.info("Wrote " + metafile)
 
 
 if __name__ == "__main__":
index bfa1804654864889419223dc2ddec2b963b1a6dc..db11465e543199860a87e9fff847e587b1b9a660 100644 (file)
@@ -24,14 +24,13 @@ import os
 import re
 import shutil
 import socket
-import subprocess
 import sys
 from optparse import OptionParser
+import logging
 
 import common
 from common import FDroidPopen, BuildException
 
-
 config = {}
 options = None
 
@@ -56,7 +55,7 @@ def genpassword():
 
 def genkey(keystore, repo_keyalias, password, keydname):
     '''generate a new keystore with a new key in it for signing repos'''
-    print('Generating a new key in "' + keystore + '"...')
+    logging.info('Generating a new key in "' + keystore + '"...')
     p = FDroidPopen(['keytool', '-genkey',
                 '-keystore', keystore, '-alias', repo_keyalias,
                 '-keyalg', 'RSA', '-keysize', '4096',
@@ -67,13 +66,10 @@ def genkey(keystore, repo_keyalias, password, keydname):
     if p.returncode != 0:
         raise BuildException("Failed to generate key", p.stdout)
     # now show the lovely key that was just generated
-    p = subprocess.Popen(['keytool', '-list', '-v',
-                '-keystore', keystore, '-alias', repo_keyalias],
-                stdin=subprocess.PIPE,
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE)
+    p = FDroidPopen(['keytool', '-list', '-v',
+                '-keystore', keystore, '-alias', repo_keyalias])
     output = p.communicate(password)[0]
-    print(output.lstrip().strip() + '\n\n')
+    logging.info(output.lstrip().strip() + '\n\n')
 
 
 def main():
@@ -111,7 +107,7 @@ def main():
         shutil.copyfile(os.path.join(examplesdir, 'config.sample.py'), 'config.py')
         os.chmod('config.py', 0o0600)
     else:
-        print('Looks like this is already an F-Droid repo, cowardly refusing to overwrite it...')
+        logging.info('Looks like this is already an F-Droid repo, cowardly refusing to overwrite it...')
         sys.exit()
 
     # now that we have a local config.py, read configuration...
@@ -119,7 +115,7 @@ def main():
 
     # track down where the Android SDK is
     if os.path.isdir(config['sdk_path']):
-        print('Using "' + config['sdk_path'] + '" for the Android SDK')
+        logging.info('Using "' + config['sdk_path'] + '" for the Android SDK')
         sdk_path = config['sdk_path']
     elif 'ANDROID_HOME' in os.environ.keys():
         sdk_path = os.environ['ANDROID_HOME']
@@ -134,7 +130,7 @@ def main():
             if os.path.isdir(os.path.join(sdk_path, 'build-tools')):
                 break
             else:
-                print('"' + s + '" does not contain the Android SDK! Try again...')
+                logging.info('"' + s + '" does not contain the Android SDK! Try again...')
     if os.path.isdir(sdk_path):
         write_to_config('sdk_path', sdk_path)
 
@@ -163,7 +159,7 @@ def main():
     if os.path.isdir(config['ndk_path']):
         ndk_path = config['ndk_path']
     elif 'ANDROID_NDK' in os.environ.keys():
-        print('using ANDROID_NDK')
+        logging.info('using ANDROID_NDK')
         ndk_path = os.environ['ANDROID_NDK']
     if os.path.isdir(ndk_path):
         write_to_config('ndk_path', ndk_path)
@@ -179,7 +175,7 @@ def main():
             keystore = options.keystore
             write_to_config('keystore', keystore)
         else:
-            print('"' + options.keystore + '" does not exist or is not a file!')
+            logging.info('"' + options.keystore + '" does not exist or is not a file!')
             sys.exit(1)
     if options.repo_keyalias:
         repo_keyalias = options.repo_keyalias
@@ -206,13 +202,13 @@ def main():
             write_to_config('keydname', keydname)
         genkey(keystore, repo_keyalias, password, keydname)
 
-    print('Built repo based in "' + fdroiddir + '"')
-    print('with this config:')
-    print('  Android SDK:\t\t\t' + sdk_path)
-    print('  Android SDK Build Tools:\t' + os.path.dirname(aapt))
-    print('  Android NDK (optional):\t' + ndk_path)
-    print('  Keystore for signing key:\t' + keystore)
-    print('\nTo complete the setup, add your APKs to "' +
+    logging.info('Built repo based in "' + fdroiddir + '"')
+    logging.info('with this config:')
+    logging.info('  Android SDK:\t\t\t' + sdk_path)
+    logging.info('  Android SDK Build Tools:\t' + os.path.dirname(aapt))
+    logging.info('  Android NDK (optional):\t' + ndk_path)
+    logging.info('  Keystore for signing key:\t' + keystore)
+    logging.info('\nTo complete the setup, add your APKs to "' +
           os.path.join(fdroiddir, 'repo') + '"' +
 '''
 then run "fdroid update -c; fdroid update".  You might also want to edit
index 0cef99fa16dec413e48ff425bda6f7c5797db6ea..632a4f91cb777493e2a5af1d0925db15ff701a61 100644 (file)
@@ -22,6 +22,7 @@ import sys
 import os
 import glob
 from optparse import OptionParser, OptionError
+import logging
 
 import common
 from common import FDroidPopen
@@ -61,7 +62,7 @@ def main():
 
     output_dir = 'repo'
     if not os.path.isdir(output_dir):
-        print "No signed output directory - nothing to do"
+        logging.info("No signed output directory - nothing to do")
         sys.exit(0)
 
     if args:
@@ -93,22 +94,24 @@ def main():
         devs = devices()
         if not devs:
             raise Exception("No attached devices found")
-        print "Installing %s..." % apk
+        logging.info("Installing %s..." % apk)
         for dev in devs:
-            print "Installing %s on %s..." % (apk, dev)
+            logging.info("Installing %s on %s..." % (apk, dev))
             p = FDroidPopen(["adb", "-s", dev, "install", apk ])
             fail= ""
             for line in p.stdout.splitlines():
                 if line.startswith("Failure"):
                     fail = line[9:-1]
-            if fail:
-                if fail == "INSTALL_FAILED_ALREADY_EXISTS":
-                    print "%s is already installed on %s." % (apk, dev)
-                else:
-                    raise Exception("Failed to install %s on %s: %s" % (
-                        apk, dev, fail))
-
-    print "\nFinished"
+            if not fail:
+                continue
+
+            if fail == "INSTALL_FAILED_ALREADY_EXISTS":
+                logging.warn("%s is already installed on %s." % (apk, dev))
+            else:
+                raise Exception("Failed to install %s on %s: %s" % (
+                    apk, dev, fail))
+
+    logging.info("\nFinished")
 
 if __name__ == "__main__":
     main()
index 782c6f074238eadf553f70f849753449c304e40d..2468da9d6daf29e65c71562961723224b4e85f3c 100644 (file)
@@ -19,6 +19,7 @@
 
 from optparse import OptionParser
 import re
+import logging
 import common, metadata
 
 config = None
@@ -31,7 +32,7 @@ def warn(message):
     if appid:
         print "%s:" % appid
         appid = None
-    print('    %s' % message)
+    print '    %s' % message
 
 def main():
 
@@ -136,7 +137,7 @@ def main():
         if not appid:
             print
 
-    print "Finished."
+    logging.info("Finished.")
 
 if __name__ == "__main__":
     main()
index 4f1a60b05719c130248f7dcac6023b99992dd3d4..3bc55c9b9546a3642e16e3151f015abe0aba0a03 100644 (file)
@@ -19,6 +19,7 @@
 
 import os, re, glob
 import cgi
+import logging
 
 class MetaDataException(Exception):
     def __init__(self, value):
@@ -644,8 +645,8 @@ def write_metadata(dest, app):
             if pf == key:
                 mf.write("%s\n" % comment)
                 written += 1
-        #if options.verbose and written > 0:
-            #print "...writing comments for " + (key if key else 'EOF')
+        if written > 0:
+            logging.debug("...writing comments for " + (key if key else 'EOF'))
 
     def writefield(field, value=None):
         writecomments(field)
@@ -713,8 +714,7 @@ def write_metadata(dest, app):
                 if not value:
                     return
                 value = 'yes'
-            #if options.verbose:
-                #print "...writing {0} : {1}".format(key, value)
+            logging.debug("...writing {0} : {1}".format(key, value))
             outline = '    %s=' % key
             outline += '&& \\\n        '.join([s.lstrip() for s in value.split('&& ')])
             outline += '\n'
index a8adb951498fc21af6070ea511388a76a2e1eaee..c6dadea59a8a78b03e92a9cc1eaefbfb20468a4c 100644 (file)
 import sys
 import os
 import shutil
-import subprocess
 import md5
 import glob
 from optparse import OptionParser
+import logging
 
 import common, metadata
-from common import BuildException
+from common import FDroidPopen, BuildException
 
 config = None
 options = None
@@ -46,22 +46,22 @@ def main():
 
     log_dir = 'logs'
     if not os.path.isdir(log_dir):
-        print "Creating log directory"
+        logging.info("Creating log directory")
         os.makedirs(log_dir)
 
     tmp_dir = 'tmp'
     if not os.path.isdir(tmp_dir):
-        print "Creating temporary directory"
+        logging.info("Creating temporary directory")
         os.makedirs(tmp_dir)
 
     output_dir = 'repo'
     if not os.path.isdir(output_dir):
-        print "Creating output directory"
+        logging.info("Creating output directory")
         os.makedirs(output_dir)
 
     unsigned_dir = 'unsigned'
     if not os.path.isdir(unsigned_dir):
-        print "No unsigned directory - nothing to do"
+        logging.info("No unsigned directory - nothing to do")
         sys.exit(0)
 
     # It was suggested at https://dev.guardianproject.info/projects/bazaar/wiki/FDroid_Audit
@@ -80,11 +80,10 @@ def main():
         m.update(app['id'])
         keyalias = m.hexdigest()[:8]
         if keyalias in allaliases:
-            print "There is a keyalias collision - publishing halted"
+            logging.info("There is a keyalias collision - publishing halted")
             sys.exit(1)
         allaliases.append(keyalias)
-    if options.verbose:
-        print "{0} apps, {0} key aliases".format(len(allapps), len(allaliases))
+    logging.info("{0} apps, {0} key aliases".format(len(allapps), len(allaliases)))
 
     # Process any apks that are waiting to be signed...
     for apkfile in sorted(glob.glob(os.path.join(unsigned_dir, '*.apk'))):
@@ -96,7 +95,7 @@ def main():
         if appid in vercodes and vercodes[appid]:
             if vercode not in vercodes[appid]:
                 continue
-        print "Processing " + apkfile
+        logging.info("Processing " + apkfile)
 
         # Figure out the key alias name we'll use. Only the first 8
         # characters are significant, so we'll use the first 8 from
@@ -115,46 +114,38 @@ def main():
             m = md5.new()
             m.update(appid)
             keyalias = m.hexdigest()[:8]
-        print "Key alias: " + keyalias
+        logging.info("Key alias: " + keyalias)
 
         # See if we already have a key for this application, and
         # if not generate one...
-        p = subprocess.Popen(['keytool', '-list',
+        p = FDroidPopen(['keytool', '-list',
             '-alias', keyalias, '-keystore', config['keystore'],
-            '-storepass', config['keystorepass']], stdout=subprocess.PIPE)
-        output = p.communicate()[0]
+            '-storepass', config['keystorepass']])
         if p.returncode !=0:
-            print "Key does not exist - generating..."
-            p = subprocess.Popen(['keytool', '-genkey',
+            logging.info("Key does not exist - generating...")
+            p = FDroidPopen(['keytool', '-genkey',
                 '-keystore', config['keystore'], '-alias', keyalias,
                 '-keyalg', 'RSA', '-keysize', '2048',
                 '-validity', '10000',
                 '-storepass', config['keystorepass'],
                 '-keypass', config['keypass'],
-                '-dname', config['keydname']], stdout=subprocess.PIPE)
-            output = p.communicate()[0]
-            print output
+                '-dname', config['keydname']])
             if p.returncode != 0:
                 raise BuildException("Failed to generate key")
 
         # Sign the application...
-        p = subprocess.Popen(['jarsigner', '-keystore', config['keystore'],
+        p = FDroidPopen(['jarsigner', '-keystore', config['keystore'],
             '-storepass', config['keystorepass'],
             '-keypass', config['keypass'], '-sigalg',
             'MD5withRSA', '-digestalg', 'SHA1',
-                apkfile, keyalias], stdout=subprocess.PIPE)
-        output = p.communicate()[0]
-        print output
+                apkfile, keyalias])
         if p.returncode != 0:
             raise BuildException("Failed to sign application")
 
         # Zipalign it...
-        p = subprocess.Popen([os.path.join(config['sdk_path'],'tools','zipalign'),
+        p = FDroidPopen([os.path.join(config['sdk_path'],'tools','zipalign'),
                             '-v', '4', apkfile,
-                            os.path.join(output_dir, apkfilename)],
-                            stdout=subprocess.PIPE)
-        output = p.communicate()[0]
-        print output
+                            os.path.join(output_dir, apkfilename)])
         if p.returncode != 0:
             raise BuildException("Failed to align application")
         os.remove(apkfile)
@@ -164,7 +155,7 @@ def main():
         shutil.move(os.path.join(unsigned_dir, tarfilename),
                 os.path.join(output_dir, tarfilename))
 
-        print 'Published ' + apkfilename
+        logging.info('Published ' + apkfilename)
 
 
 if __name__ == "__main__":
index e463cf14d59a2bd938a20964a8aac85145342e72..6ed54fa2ae03b1085660e035e088fc8d35d3dac1 100644 (file)
@@ -19,6 +19,7 @@
 
 import os
 from optparse import OptionParser
+import logging
 import common, metadata
 
 config = None
@@ -41,10 +42,10 @@ def main():
     apps = common.read_app_args(args, allapps, False)
 
     for app in apps:
-        print "Writing " + app['id']
+        logging.info("Writing " + app['id'])
         metadata.write_metadata(os.path.join('metadata', app['id'])+'.txt', app)
 
-    print "Finished."
+    logging.info("Finished.")
 
 if __name__ == "__main__":
     main()
index 64cebfb256c2f0ad89cc8f41bf3f7042b93926e0..8c326c294afe5684def9d5b729b328695485290a 100644 (file)
@@ -20,6 +20,8 @@
 import os
 import traceback
 from optparse import OptionParser
+import logging
+
 import common, metadata
 from common import BuildException
 from common import VCSException
@@ -49,7 +51,7 @@ def main():
 
     build_dir = 'build'
     if not os.path.isdir(build_dir):
-        print "Creating build directory"
+        logging.info("Creating build directory")
         os.makedirs(build_dir)
     srclib_dir = os.path.join(build_dir, 'srclib')
     extlib_dir = os.path.join(build_dir, 'extlib')
@@ -57,15 +59,15 @@ def main():
     for app in apps:
 
         if app['Disabled']:
-            print "Skipping %s: disabled" % app['id']
+            logging.info("Skipping %s: disabled" % app['id'])
             continue
         if not app['builds']:
-            print "Skipping %s: no builds specified" % app['id']
+            logging.info("Skipping %s: no builds specified" % app['id'])
             continue
         elif options.nosvn and app['Repo Type'] == 'svn':
             continue
 
-        print "Processing " + app['id']
+        logging.info("Processing " + app['id'])
 
         try:
 
@@ -77,10 +79,10 @@ def main():
             for thisbuild in app['builds']:
 
                 if 'disable' in thisbuild:
-                    print ("..skipping version " + thisbuild['version'] + " - " +
-                            thisbuild.get('disable', thisbuild['commit'][1:]))
+                    logging.info("...skipping version %s - %s" % (
+                        thisbuild['version'], thisbuild.get('disable', thisbuild['commit'][1:])))
                 else:
-                    print "..scanning version " + thisbuild['version']
+                    logging.info("...scanning version " + thisbuild['version'])
 
                     # Prepare the source code...
                     root_dir, _ = common.prepare_source(vcs, app, thisbuild,
@@ -102,7 +104,7 @@ def main():
             msg = "Could not scan app %s due to unknown error: %s" % (app['id'], traceback.format_exc())
             problems.append(msg)
 
-    print "Finished:"
+    logging.info("Finished:")
     for problem in problems:
         print problem
     print str(len(problems)) + ' problems.'
index 43ea05fd4e7117288773778d53a7a7415a07ddc8..f04dc264d182229ea7e7fad30f66eca9c6ffef7d 100644 (file)
@@ -21,6 +21,7 @@ import sys
 import os
 import subprocess
 from optparse import OptionParser
+import logging
 import common
 
 config = None
@@ -40,11 +41,11 @@ def main():
     config = common.read_config(options)
 
     if len(args) != 1:
-        print "Specify a single command"
+        logging.critical("Specify a single command")
         sys.exit(1)
 
     if args[0] != 'init' and args[0] != 'update':
-        print "The only commands currently supported are 'init' and 'update'"
+        logging.critical("The only commands currently supported are 'init' and 'update'")
         sys.exit(1)
 
     serverwebroot = config['serverwebroot'].rstrip('/').replace('//', '/')
index 3b69082d547bee889a6f2e8a0eb634f9035e33f1..6aeb61297b760a37ac01f5f1284334aa29ecf0cb 100644 (file)
@@ -25,9 +25,11 @@ import traceback
 import glob
 from optparse import OptionParser
 import paramiko
-import common, metadata
 import socket
-import subprocess
+import logging
+
+import common, metadata
+from common import FDroidPopen
 
 def carbon_send(key, value):
     s = socket.socket()
@@ -56,7 +58,7 @@ def main():
     config = common.read_config(options)
 
     if not config['update_stats']:
-        print "Stats are disabled - check your configuration"
+        logging.info("Stats are disabled - check your configuration")
         sys.exit(1)
 
     # Get all metadata-defined apps...
@@ -77,14 +79,14 @@ def main():
         ssh = None
         ftp = None
         try:
-            print 'Retrieving logs'
+            logging.info('Retrieving logs')
             ssh = paramiko.SSHClient()
             ssh.load_system_host_keys()
             ssh.connect('f-droid.org', username='fdroid', timeout=10,
                     key_filename=config['webserver_keyfile'])
             ftp = ssh.open_sftp()
             ftp.get_channel().settimeout(60)
-            print "...connected"
+            logging.info("...connected")
 
             ftp.chdir('logs')
             files = ftp.listdir()
@@ -95,7 +97,7 @@ def main():
                     destsize = ftp.stat(f).st_size
                     if (not os.path.exists(destpath) or
                             os.path.getsize(destpath) != destsize):
-                        print "...retrieving " + f
+                        logging.info("...retrieving " + f)
                         ftp.get(f, destpath)
         except Exception:
             traceback.print_exc()
@@ -112,38 +114,37 @@ def main():
 
     if not options.nologs:
         # Process logs
-        if options.verbose:
-            print 'Processing logs...'
+        logging.info('Processing logs...')
         apps = {}
         appsVer = {}
         logexpr = '(?P<ip>[.:0-9a-fA-F]+) - - \[(?P<time>.*?)\] "GET (?P<uri>.*?) HTTP/1.\d" (?P<statuscode>\d+) \d+ "(?P<referral>.*?)" "(?P<useragent>.*?)"'
         logsearch = re.compile(logexpr).search
         for logfile in glob.glob(os.path.join(logsdir,'access-*.log.gz')):
-            if options.verbose:
-                print '...' + logfile
-            p = subprocess.Popen(["zcat", logfile], stdout = subprocess.PIPE)
+            logging.info('...' + logfile)
+            p = FDroidPopen(["zcat", logfile])
             matches = (logsearch(line) for line in p.stdout)
             for match in matches:
                 if match and match.group('statuscode') == '200':
                     uri = match.group('uri')
-                    if uri.endswith('.apk'):
-                        _, apkname = os.path.split(uri)
-                        app = knownapks.getapp(apkname)
-                        if app:
-                            appid, _ = app
-                            if appid in apps:
-                                apps[appid] += 1
-                            else:
-                                apps[appid] = 1
-                            # Strip the '.apk' from apkname
-                            appVer = apkname[:-4]
-                            if appVer in appsVer:
-                                appsVer[appVer] += 1
-                            else:
-                                appsVer[appVer] = 1
+                    if not uri.endswith('.apk'):
+                        continue
+                    _, apkname = os.path.split(uri)
+                    app = knownapks.getapp(apkname)
+                    if app:
+                        appid, _ = app
+                        if appid in apps:
+                            apps[appid] += 1
+                        else:
+                            apps[appid] = 1
+                        # Strip the '.apk' from apkname
+                        appVer = apkname[:-4]
+                        if appVer in appsVer:
+                            appsVer[appVer] += 1
                         else:
-                            if not apkname in unknownapks:
-                                unknownapks.append(apkname)
+                            appsVer[appVer] = 1
+                    else:
+                        if not apkname in unknownapks:
+                            unknownapks.append(apkname)
 
         # Calculate and write stats for total downloads...
         lst = []
@@ -170,8 +171,7 @@ def main():
         f.close()
 
     # Calculate and write stats for repo types...
-    if options.verbose:
-        print "Processing repo types..."
+    logging.info("Processing repo types...")
     repotypes = {}
     for app in metaapps:
         if len(app['Repo Type']) == 0:
@@ -191,8 +191,7 @@ def main():
     f.close()
 
     # Calculate and write stats for update check modes...
-    if options.verbose:
-        print "Processing update check modes..."
+    logging.info("Processing update check modes...")
     ucms = {}
     for app in metaapps:
         checkmode = app['Update Check Mode'].split('/')[0]
@@ -205,8 +204,7 @@ def main():
         f.write(checkmode + ' ' + str(count) + '\n')
     f.close()
 
-    if options.verbose:
-        print "Processing categories..."
+    logging.info("Processing categories...")
     ctgs = {}
     for app in metaapps:
         if app['Categories'] is None:
@@ -222,8 +220,7 @@ def main():
         f.write(category + ' ' + str(count) + '\n')
     f.close()
 
-    if options.verbose:
-        print "Processing antifeatures..."
+    logging.info("Processing antifeatures...")
     afs = {}
     for app in metaapps:
         if app['AntiFeatures'] is None:
@@ -240,8 +237,7 @@ def main():
     f.close()
 
     # Calculate and write stats for licenses...
-    if options.verbose:
-        print "Processing licenses..."
+    logging.info("Processing licenses...")
     licenses = {}
     for app in metaapps:
         license = app['License']
@@ -255,8 +251,7 @@ def main():
     f.close()
 
     # Write list of latest apps added to the repo...
-    if options.verbose:
-        print "Processing latest apps..."
+    logging.info("Processing latest apps...")
     latest = knownapks.getlatest(10)
     f = open('stats/latestapps.txt', 'w')
     for app in latest:
@@ -264,11 +259,11 @@ def main():
     f.close()
 
     if unknownapks:
-        print '\nUnknown apks:'
+        logging.info('\nUnknown apks:')
         for apk in unknownapks:
-            print apk
+            logging.info(apk)
 
-    print "Finished."
+    logging.info("Finished.")
 
 if __name__ == "__main__":
     main()
index 765e63322061df6df8a8ca8482e50d7b1a46f245..d72f67f106a05a9eadf61e5241b4db308b32d91b 100644 (file)
@@ -22,7 +22,6 @@ import sys
 import os
 import shutil
 import glob
-import subprocess
 import re
 import zipfile
 import hashlib
@@ -30,10 +29,12 @@ import pickle
 from xml.dom.minidom import Document
 from optparse import OptionParser
 import time
-import common, metadata
-from metadata import MetaDataException
 from PIL import Image
+import logging
 
+import common, metadata
+from common import FDroidPopen
+from metadata import MetaDataException
 
 def get_densities():
     return ['640', '480', '320', '240', '160', '120']
@@ -60,7 +61,7 @@ def update_wiki(apps, apks):
     :param apps: fully populated list of all applications
     :param apks: all apks, except...
     """
-    print "Updating wiki"
+    logging.info("Updating wiki")
     wikicat = 'Apps'
     wikiredircat = 'App Redirects'
     import mwclient
@@ -233,24 +234,22 @@ def update_wiki(apps, apks):
             if page.name in genp:
                 pagetxt = page.edit()
                 if pagetxt != genp[page.name]:
-                    print "Updating modified page " + page.name
+                    logging.info("Updating modified page " + page.name)
                     page.save(genp[page.name], summary='Auto-updated')
                 else:
-                    if options.verbose:
-                        print "Page " + page.name + " is unchanged"
+                    logging.info("Page " + page.name + " is unchanged")
             else:
-                print "Deleting page " + page.name
+                logging.info("Deleting page " + page.name)
                 page.delete('No longer published')
         for pagename, text in genp.items():
-            if options.verbose:
-                print "Checking " + pagename
+            logging.info("Checking " + pagename)
             if not pagename in existingpages:
-                print "Creating page " + pagename
+                logging.info("Creating page " + pagename)
                 try:
                     newpage = site.Pages[pagename]
                     newpage.save(text, summary='Auto-created')
                 except:
-                    print "...FAILED to create page"
+                    logging.warn("...FAILED to create page")
 
     # Purge server cache to ensure counts are up to date
     site.pages['Repository Maintenance'].purge()
@@ -271,7 +270,7 @@ def delete_disabled_builds(apps, apkcache, repodirs):
                     srcpath = os.path.join(repodir, apkfilename[:-4] + "_src.tar.gz")
                     for name in [apkpath, srcpath]:
                         if os.path.exists(name):
-                            print "Deleting disabled build output " + apkfilename
+                            logging.info("Deleting disabled build output " + apkfilename)
                             os.remove(name)
                 if apkfilename in apkcache:
                     del apkcache[apkfilename]
@@ -288,15 +287,14 @@ def resize_icon(iconpath, density):
         if any(length > size for length in im.size):
             oldsize = im.size
             im.thumbnail((size, size), Image.ANTIALIAS)
-            print iconpath, "was too large at", oldsize, "- new size is", im.size
+            logging.info(iconpath, "was too large at", oldsize, "- new size is", im.size)
             im.save(iconpath, "PNG")
 
         else:
-            if options.verbose:
-                print iconpath, "is small enough:", im.size
+            logging.info(iconpath, "is small enough:", im.size)
 
     except Exception,e:
-        print "WARNING: Failed resizing {0} - {1}".format(iconpath, e)
+        logging.info("WARNING: Failed resizing {0} - {1}".format(iconpath, e))
 
 def resize_all_icons(repodirs):
     """Resize all icons that exceed the max size
@@ -347,18 +345,17 @@ def scan_apks(apps, apkcache, repodir, knownapks):
 
         apkfilename = apkfile[len(repodir) + 1:]
         if ' ' in apkfilename:
-            print "No spaces in APK filenames!"
+            logging.info("No spaces in APK filenames!")
             sys.exit(1)
 
         if apkfilename in apkcache:
-            if options.verbose:
-                print "Reading " + apkfilename + " from cache"
+            logging.info("Reading " + apkfilename + " from cache")
             thisinfo = apkcache[apkfilename]
 
         else:
 
             if not options.quiet:
-                print "Processing " + apkfilename
+                logging.info("Processing " + apkfilename)
             thisinfo = {}
             thisinfo['apkname'] = apkfilename
             srcfilename = apkfilename[:-4] + "_src.tar.gz"
@@ -369,22 +366,21 @@ def scan_apks(apps, apkcache, repodir, knownapks):
             thisinfo['features'] = []
             thisinfo['icons_src'] = {}
             thisinfo['icons'] = {}
-            p = subprocess.Popen([os.path.join(config['sdk_path'], 'build-tools', config['build_tools'], 'aapt'),
-                                  'dump', 'badging', apkfile],
-                                 stdout=subprocess.PIPE)
-            output = p.communicate()[0]
+            p = FDroidPopen([os.path.join(config['sdk_path'],
+                        'build-tools', config['build_tools'], 'aapt'),
+                    'dump', 'badging', apkfile])
             if p.returncode != 0:
-                print "ERROR: Failed to get apk information"
+                logging.critical("Failed to get apk information")
                 sys.exit(1)
-            for line in output.splitlines():
+            for line in p.stdout.splitlines():
                 if line.startswith("package:"):
                     try:
                         thisinfo['id'] = re.match(name_pat, line).group(1)
                         thisinfo['versioncode'] = int(re.match(vercode_pat, line).group(1))
                         thisinfo['version'] = re.match(vername_pat, line).group(1)
                     except Exception, e:
-                        print "Package matching failed: " + str(e)
-                        print "Line was: " + line
+                        logging.info("Package matching failed: " + str(e))
+                        logging.info("Line was: " + line)
                         sys.exit(1)
                 elif line.startswith("application:"):
                     thisinfo['name'] = re.match(label_pat, line).group(1)
@@ -426,12 +422,12 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                         thisinfo['features'].append(perm)
 
             if not 'sdkversion' in thisinfo:
-                print "  WARNING: no SDK version information found"
+                logging.info("  WARNING: no SDK version information found")
                 thisinfo['sdkversion'] = 0
 
             # Check for debuggable apks...
             if common.isApkDebuggable(apkfile, config):
-                print "WARNING: {0} is debuggable... {1}".format(apkfile, line)
+                logging.info("WARNING: {0} is debuggable... {1}".format(apkfile, line))
 
             # Calculate the sha256...
             sha = hashlib.sha256()
@@ -446,19 +442,14 @@ def scan_apks(apps, apkcache, repodir, knownapks):
             # Get the signature (or md5 of, to be precise)...
             getsig_dir = os.path.join(os.path.dirname(__file__), 'getsig')
             if not os.path.exists(getsig_dir + "/getsig.class"):
-                print "ERROR: getsig.class not found. To fix:"
-                print "\tcd " + getsig_dir
-                print "\t./make.sh"
+                logging.critical("getsig.class not found. To fix: cd '%s' && ./make.sh" % getsig_dir)
                 sys.exit(1)
-            p = subprocess.Popen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'),
-                        'getsig', os.path.join(os.getcwd(), apkfile)], stdout=subprocess.PIPE)
-            output = p.communicate()[0]
-            if options.verbose:
-                print output
-            if p.returncode != 0 or not output.startswith('Result:'):
-                print "ERROR: Failed to get apk signature"
+            p = FDroidPopen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'),
+                        'getsig', os.path.join(os.getcwd(), apkfile)])
+            if p.returncode != 0 or not p.stdout.startswith('Result:'):
+                logging.critical("Failed to get apk signature")
                 sys.exit(1)
-            thisinfo['sig'] = output[7:].strip()
+            thisinfo['sig'] = p.stdout[7:].strip()
 
             apk = zipfile.ZipFile(apkfile, 'r')
 
@@ -484,7 +475,7 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                     thisinfo['icons'][density] = iconfilename 
 
                 except:
-                    print "WARNING: Error retrieving icon file"
+                    logging.info("WARNING: Error retrieving icon file")
                     del thisinfo['icons'][density]
                     del thisinfo['icons_src'][density]
                     empty_densities.append(density)
@@ -509,7 +500,7 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                             empty_densities.remove(density)
                             break
                 except Exception,e:
-                    print "WARNING: Failed reading {0} - {1}".format(iconpath, e)
+                    logging.info("WARNING: Failed reading {0} - {1}".format(iconpath, e))
 
             if thisinfo['icons']:
                 thisinfo['icon'] = iconfilename
@@ -524,9 +515,8 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                     continue
                 if last_density is None:
                     continue
-                if options.verbose:
-                    print "Density %s not available, resizing down from %s" % (
-                            density, last_density)
+                logging.info("Density %s not available, resizing down from %s" % (
+                        density, last_density))
 
                 last_iconpath = os.path.join(
                         get_icon_dir(repodir, last_density), iconfilename)
@@ -535,7 +525,7 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                 try:
                     im = Image.open(last_iconpath)
                 except:
-                    print "WARNING: Invalid image file at %s" % last_iconpath
+                    logging.info("WARNING: Invalid image file at %s" % last_iconpath)
                     continue
 
                 size = dpi_to_px(density)
@@ -552,9 +542,8 @@ def scan_apks(apps, apkcache, repodir, knownapks):
                     continue
                 if last_density is None:
                     continue
-                if options.verbose:
-                    print "Density %s not available, copying from lower density %s" % (
-                            density, last_density)
+                logging.info("Density %s not available, copying from lower density %s" % (
+                        density, last_density))
 
                 shutil.copyfile(
                         os.path.join(get_icon_dir(repodir, last_density), iconfilename),
@@ -646,18 +635,16 @@ def make_index(apps, apks, repodir, archive, categories):
             return " ".join(ret)
 
         def extract_pubkey():
-            p = subprocess.Popen(['keytool', '-exportcert',
+            p = FDroidPopen(['keytool', '-exportcert',
                                   '-alias', config['repo_keyalias'],
                                   '-keystore', config['keystore'],
-                                  '-storepass', config['keystorepass']],
-                                 stdout=subprocess.PIPE)
-            cert = p.communicate()[0]
+                                  '-storepass', config['keystorepass']])
             if p.returncode != 0:
-                print "ERROR: Failed to get repo pubkey"
+                logging.critical("Failed to get repo pubkey")
                 sys.exit(1)
             global repo_pubkey_fingerprint
-            repo_pubkey_fingerprint = cert_fingerprint(cert)
-            return "".join("%02x" % ord(b) for b in cert)
+            repo_pubkey_fingerprint = cert_fingerprint(p.stdout)
+            return "".join("%02x" % ord(b) for b in p.stdout)
 
         repoel.setAttribute("pubkey", extract_pubkey())
 
@@ -748,9 +735,8 @@ def make_index(apps, apks, repodir, archive, categories):
         # Check for duplicates - they will make the client unhappy...
         for i in range(len(apklist) - 1):
             if apklist[i]['versioncode'] == apklist[i+1]['versioncode']:
-                print "ERROR - duplicate versions"
-                print apklist[i]['apkname']
-                print apklist[i+1]['apkname']
+                logging.critical("duplicate versions: '%s' - '%s'" % (
+                    apklist[i]['apkname'], apklist[i+1]['apkname']))
                 sys.exit(1)
 
         for apk in apklist:
@@ -795,31 +781,23 @@ def make_index(apps, apks, repodir, archive, categories):
     if config['repo_keyalias'] is not None:
 
         if not options.quiet:
-            print "Creating signed index."
-            print "Key fingerprint:", repo_pubkey_fingerprint
+            logging.info("Creating signed index.")
+            logging.info("Key fingerprint:", repo_pubkey_fingerprint)
 
         #Create a jar of the index...
-        p = subprocess.Popen(['jar', 'cf', 'index.jar', 'index.xml'],
-            cwd=repodir, stdout=subprocess.PIPE)
-        output = p.communicate()[0]
-        if options.verbose:
-            print output
+        p = FDroidPopen(['jar', 'cf', 'index.jar', 'index.xml'], cwd=repodir)
         if p.returncode != 0:
-            print "ERROR: Failed to create jar file"
+            logging.critical("Failed to create jar file")
             sys.exit(1)
 
         # Sign the index...
-        p = subprocess.Popen(['jarsigner', '-keystore', config['keystore'],
+        p = FDroidPopen(['jarsigner', '-keystore', config['keystore'],
             '-storepass', config['keystorepass'], '-keypass', config['keypass'],
             '-digestalg', 'SHA1', '-sigalg', 'MD5withRSA',
-            os.path.join(repodir, 'index.jar') , config['repo_keyalias']], stdout=subprocess.PIPE)
-        output = p.communicate()[0]
+            os.path.join(repodir, 'index.jar') , config['repo_keyalias']])
         if p.returncode != 0:
-            print "Failed to sign index"
-            print output
+            logging.info("Failed to sign index")
             sys.exit(1)
-        if options.verbose:
-            print output
 
     # Copy the repo icon into the repo directory...
     icon_dir = os.path.join(repodir ,'icons')
@@ -856,7 +834,7 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
 
         if len(apklist) > keepversions:
             for apk in apklist[keepversions:]:
-                print "Moving " + apk['apkname'] + " to archive"
+                logging.info("Moving " + apk['apkname'] + " to archive")
                 shutil.move(os.path.join(repodir, apk['apkname']),
                     os.path.join(archivedir, apk['apkname']))
                 if 'srcname' in apk:
@@ -972,20 +950,17 @@ def main():
         if added:
             app['added'] = added
         else:
-            if options.verbose:
-                print "WARNING: Don't know when " + app['id'] + " was added"
+            logging.info("WARNING: Don't know when " + app['id'] + " was added")
         if lastupdated:
             app['lastupdated'] = lastupdated
         else:
-            if options.verbose:
-                print "WARNING: Don't know when " + app['id'] + " was last updated"
+            logging.info("WARNING: Don't know when " + app['id'] + " was last updated")
 
         if bestver == 0:
             if app['Name'] is None:
                 app['Name'] = app['id']
             app['icon'] = None
-            if options.verbose and app['Disabled'] is None:
-                print "WARNING: Application " + app['id'] + " has no packages"
+            logging.info("WARNING: Application " + app['id'] + " has no packages")
         else:
             if app['Name'] is None:
                 app['Name'] = bestapk['name']
@@ -1016,10 +991,10 @@ def main():
                 f.write(apk['name'] + "\n")
                 f.write(".\n")
                 f.close()
-                print "Generated skeleton metadata for " + apk['id']
+                logging.info("Generated skeleton metadata for " + apk['id'])
             else:
-                print "WARNING: " + apk['apkname'] + " (" + apk['id'] + ") has no metadata"
-                print "       " + apk['name'] + " - " + apk['version']
+                logging.info("WARNING: " + apk['apkname'] + " (" + apk['id'] + ") has no metadata")
+                logging.info("       " + apk['name'] + " - " + apk['version'])
 
     if len(repodirs) > 1:
         archive_old_apks(apps, apks, archapks, repodirs[0], repodirs[1], config['archive_older'])
@@ -1062,7 +1037,7 @@ def main():
     if options.wiki:
         update_wiki(apps, apks + archapks)
 
-    print "Finished."
+    logging.info("Finished.")
 
 if __name__ == "__main__":
     main()
index a9f18392e4227695376b6f409f6ec31ad21c8911..4c99f4ad8149188e17f426d24de99cca256b186c 100644 (file)
@@ -23,8 +23,10 @@ import shutil
 import subprocess
 import glob
 from optparse import OptionParser
+import logging
 
 import common
+from common import FDroidPopen
 
 options = None
 config = None
@@ -43,12 +45,12 @@ def main():
 
     tmp_dir = 'tmp'
     if not os.path.isdir(tmp_dir):
-        print "Creating temporary directory"
+        logging.info("Creating temporary directory")
         os.makedirs(tmp_dir)
 
     unsigned_dir = 'unsigned'
     if not os.path.isdir(unsigned_dir):
-        print "No unsigned directory - nothing to do"
+        logging.error("No unsigned directory - nothing to do")
         sys.exit(0)
 
     verified = 0
@@ -68,17 +70,14 @@ def main():
 
         try:
 
-            print "Processing " + apkfilename
+            logging.info("Processing " + apkfilename)
 
             remoteapk = os.path.join(tmp_dir, apkfilename)
             if os.path.exists(remoteapk):
                 os.remove(remoteapk)
             url = 'https://f-droid.org/repo/' + apkfilename
-            print "...retrieving " + url
-            p = subprocess.Popen(['wget', url],
-                cwd=tmp_dir,
-                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            out = p.communicate()[0]
+            logging.info("...retrieving " + url)
+            p = FDroidPopen(['wget', url], cwd=tmp_dir)
             if p.returncode != 0:
                 raise Exception("Failed to get " + apkfilename)
 
@@ -97,23 +96,21 @@ def main():
                 cwd=thatdir) != 0:
                 raise Exception("Failed to unpack remote build of " + apkfilename)
 
-            p = subprocess.Popen(['diff', '-r', 'this_apk', 'that_apk'],
-                cwd=tmp_dir, stdout=subprocess.PIPE)
-            out = p.communicate()[0]
-            lines = out.splitlines()
+            p = FDroidPopen(['diff', '-r', 'this_apk', 'that_apk'], cwd=tmp_dir)
+            lines = p.stdout.splitlines()
             if len(lines) != 1 or 'META-INF' not in lines[0]:
-                raise Exception("Unexpected diff output - " + out)
+                raise Exception("Unexpected diff output - " + p.stdout)
 
-            print "...successfully verified"
+            logging.info("...successfully verified")
             verified += 1
 
         except Exception, e:
-            print "...NOT verified - {0}".format(e)
+            logging.info("...NOT verified - {0}".format(e))
             notverified += 1
 
-    print "\nFinished"
-    print "{0} successfully verified".format(verified)
-    print "{0} NOT verified".format(notverified)
+    logging.info("Finished")
+    logging.info("{0} successfully verified".format(verified))
+    logging.info("{0} NOT verified".format(notverified))
 
 if __name__ == "__main__":
     main()