# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
+import logging
commands = [
"build",
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
import json
from ConfigParser import ConfigParser
from optparse import OptionParser, OptionError
+import logging
import common, metadata
from common import BuildException, VCSException, FDroidPopen
: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.
# 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')
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")
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
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']
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')
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 + "'")
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'
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)
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:
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"'
# 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']:
elif thisbuild['type'] == 'gradle':
- print "Cleaning Gradle project..."
+ logging.info("Cleaning Gradle project...")
cmd = [config['gradle'], 'clean']
if '@' in thisbuild['gradle']:
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:
(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):
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)
# 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 = ['']
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
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])
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):
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]
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']]
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([
# 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)
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
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:
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:
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')
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):
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
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)
import traceback
import HTMLParser
from distutils.version import LooseVersion
+import logging
+
import common, metadata
from common import BuildException
from common import VCSException
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()
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()
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))
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)
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
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))
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:
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
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()
import Queue
import threading
import magic
+import logging
import metadata
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",
}
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:
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
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")
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)
# 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")
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")
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):
# 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(';')
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")
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('/')
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")
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):
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):
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:
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):
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/'):
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
% 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:
# '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:
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')))
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:
# 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'
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)
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')
'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
'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
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
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)))
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:
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:
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
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:
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):
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
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):
: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
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)
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()
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:
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'])
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
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...
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'
# 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('/'):
# 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':
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)
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):
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...
metafile = os.path.join('metadata', package + '.txt')
metadata.write_metadata(metafile, app)
- print "Wrote " + metafile
+ logging.info("Wrote " + metafile)
if __name__ == "__main__":
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
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',
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():
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...
# 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']
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)
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)
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
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
import os
import glob
from optparse import OptionParser, OptionError
+import logging
import common
from common import FDroidPopen
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:
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()
from optparse import OptionParser
import re
+import logging
import common, metadata
config = None
if appid:
print "%s:" % appid
appid = None
- print(' %s' % message)
+ print ' %s' % message
def main():
if not appid:
print
- print "Finished."
+ logging.info("Finished.")
if __name__ == "__main__":
main()
import os, re, glob
import cgi
+import logging
class MetaDataException(Exception):
def __init__(self, value):
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)
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'
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
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
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'))):
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
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)
shutil.move(os.path.join(unsigned_dir, tarfilename),
os.path.join(output_dir, tarfilename))
- print 'Published ' + apkfilename
+ logging.info('Published ' + apkfilename)
if __name__ == "__main__":
import os
from optparse import OptionParser
+import logging
import common, metadata
config = None
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()
import os
import traceback
from optparse import OptionParser
+import logging
+
import common, metadata
from common import BuildException
from common import VCSException
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')
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:
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,
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.'
import os
import subprocess
from optparse import OptionParser
+import logging
import common
config = None
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('//', '/')
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()
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...
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()
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()
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 = []
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:
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]
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:
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:
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']
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:
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()
import os
import shutil
import glob
-import subprocess
import re
import zipfile
import hashlib
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']
: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
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()
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]
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
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"
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)
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()
# 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')
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)
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
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)
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)
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),
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())
# 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:
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')
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:
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']
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'])
if options.wiki:
update_wiki(apps, apks + archapks)
- print "Finished."
+ logging.info("Finished.")
if __name__ == "__main__":
main()
import subprocess
import glob
from optparse import OptionParser
+import logging
import common
+from common import FDroidPopen
options = None
config = None
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
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)
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()