Separated build (compile) from publish (sign)

This commit is contained in:
Ciaran Gultnieks 2012-02-02 14:27:49 +00:00
parent f49df5a586
commit 9ba5c8cea8
2 changed files with 148 additions and 64 deletions

View file

@ -24,8 +24,6 @@ import subprocess
import re import re
import zipfile import zipfile
import tarfile import tarfile
import md5
import shlex
from xml.dom.minidom import Document from xml.dom.minidom import Document
from optparse import OptionParser from optparse import OptionParser
@ -67,11 +65,13 @@ if not os.path.isdir(tmp_dir):
if options.test: if options.test:
output_dir = tmp_dir output_dir = tmp_dir
else: else:
output_dir = 'repo' output_dir = 'unsigned'
if not os.path.isdir(output_dir): if not os.path.isdir(output_dir):
print "Creating output directory" print "Creating output directory"
os.makedirs(output_dir) os.makedirs(output_dir)
repo_dir = 'repo'
build_dir = 'build' build_dir = 'build'
if not os.path.isdir(build_dir): if not os.path.isdir(build_dir):
print "Creating build directory" print "Creating build directory"
@ -104,10 +104,10 @@ for app in apps:
try: try:
dest = os.path.join(output_dir, app['id'] + '_' + dest = os.path.join(output_dir, app['id'] + '_' +
thisbuild['vercode'] + '.apk') thisbuild['vercode'] + '.apk')
dest_unsigned = os.path.join(tmp_dir, app['id'] + '_' + dest_repo = os.path.join(repo_dir, app['id'] + '_' +
thisbuild['vercode'] + '_unsigned.apk') thisbuild['vercode'] + '.apk')
if os.path.exists(dest): if os.path.exists(dest) or os.path.exists(dest_repo):
if options.verbose: if options.verbose:
print "..version " + thisbuild['version'] + " already exists" print "..version " + thisbuild['version'] + " already exists"
elif thisbuild['commit'].startswith('!'): elif thisbuild['commit'].startswith('!'):
@ -228,67 +228,15 @@ for app in apps:
% (version, str(vercode), thisbuild['version'], str(thisbuild['vercode'])) % (version, str(vercode), thisbuild['version'], str(thisbuild['vercode']))
) )
# Copy the unsigned apk to our temp directory for further # Copy the unsigned apk to our destination directory for further
# processing... # processing (by publish.py)...
shutil.copyfile(src, dest_unsigned) shutil.copyfile(src, dest)
# Figure out the key alias name we'll use. Only the first 8
# characters are significant, so we'll use the first 8 from
# the MD5 of the app's ID and hope there are no collisions.
# If a collision does occur later, we're going to have to
# come up with a new alogrithm, AND rename all existing keys
# in the keystore!
if keyaliases.has_key(app['id']):
# For this particular app, the key alias is overridden...
keyalias = keyaliases[app['id']]
else:
m = md5.new()
m.update(app['id'])
keyalias = m.hexdigest()[:8]
print "Key alias: " + keyalias
# See if we already have a key for this application, and
# if not generate one...
p = subprocess.Popen(['keytool', '-list',
'-alias', keyalias, '-keystore', keystore,
'-storepass', keystorepass], stdout=subprocess.PIPE)
output = p.communicate()[0]
if p.returncode !=0:
print "Key does not exist - generating..."
p = subprocess.Popen(['keytool', '-genkey',
'-keystore', keystore, '-alias', keyalias,
'-keyalg', 'RSA', '-keysize', '2048',
'-validity', '10000',
'-storepass', keystorepass, '-keypass', keypass,
'-dname', keydname], stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to generate key")
# Sign the application...
p = subprocess.Popen(['jarsigner', '-keystore', keystore,
'-storepass', keystorepass, '-keypass', keypass,
dest_unsigned, keyalias], stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to sign application")
# Zipalign it...
p = subprocess.Popen([os.path.join(sdk_path,'tools','zipalign'),
'-v', '4', dest_unsigned, dest],
stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to align application")
os.remove(dest_unsigned)
# Move the source tarball into the output directory... # Move the source tarball into the output directory...
if output_dir != tmp_dir: if output_dir != tmp_dir:
shutil.move(os.path.join(tmp_dir, tarname + '.tar.gz'), tarfilename = tarname + '.tar.gz'
os.path.join(output_dir, tarname + '.tar.gz')) shutil.move(os.path.join(tmp_dir, tarfilename),
os.path.join(output_dir, tarfilename))
build_succeeded.append(app) build_succeeded.append(app)
except BuildException as be: except BuildException as be:

136
publish.py Executable file
View file

@ -0,0 +1,136 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# publish.py - part of the FDroid server tools
# Copyright (C) 2010-12, Ciaran Gultnieks, ciaran@ciarang.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import shutil
import subprocess
import re
import zipfile
import tarfile
import md5
import glob
from optparse import OptionParser
import common
from common import BuildException
#Read configuration...
execfile('config.py')
# Parse command line...
parser = OptionParser()
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="Spew out even more information than normal")
parser.add_option("-p", "--package", default=None,
help="Publish only the specified package")
(options, args) = parser.parse_args()
log_dir = 'logs'
if not os.path.isdir(log_dir):
print "Creating log directory"
os.makedirs(log_dir)
tmp_dir = 'tmp'
if not os.path.isdir(tmp_dir):
print "Creating temporary directory"
os.makedirs(tmp_dir)
output_dir = 'repo'
if not os.path.isdir(output_dir):
print "Creating output directory"
os.makedirs(output_dir)
unsigned_dir = 'unsigned'
if not os.path.isdir(unsigned_dir):
print "No unsigned directory - nothing to do"
sys.exit(0)
for apkfile in sorted(glob.glob(os.path.join(unsigned_dir, '*.apk'))):
apkfilename = os.path.basename(apkfile)
i = apkfilename.rfind('_')
if i == -1:
raise BuildException("Invalid apk name")
appid = apkfilename[:i]
print "Processing " + appid
if not options.package or options.package == appid:
# Figure out the key alias name we'll use. Only the first 8
# characters are significant, so we'll use the first 8 from
# the MD5 of the app's ID and hope there are no collisions.
# If a collision does occur later, we're going to have to
# come up with a new alogrithm, AND rename all existing keys
# in the keystore!
if keyaliases.has_key(appid):
# For this particular app, the key alias is overridden...
keyalias = keyaliases[appid]
else:
m = md5.new()
m.update(appid)
keyalias = m.hexdigest()[:8]
print "Key alias: " + keyalias
# See if we already have a key for this application, and
# if not generate one...
p = subprocess.Popen(['keytool', '-list',
'-alias', keyalias, '-keystore', keystore,
'-storepass', keystorepass], stdout=subprocess.PIPE)
output = p.communicate()[0]
if p.returncode !=0:
print "Key does not exist - generating..."
p = subprocess.Popen(['keytool', '-genkey',
'-keystore', keystore, '-alias', keyalias,
'-keyalg', 'RSA', '-keysize', '2048',
'-validity', '10000',
'-storepass', keystorepass, '-keypass', keypass,
'-dname', keydname], stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to generate key")
# Sign the application...
p = subprocess.Popen(['jarsigner', '-keystore', keystore,
'-storepass', keystorepass, '-keypass', keypass,
apkfile, keyalias], stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to sign application")
# Zipalign it...
p = subprocess.Popen([os.path.join(sdk_path,'tools','zipalign'),
'-v', '4', apkfile,
os.path.join(output_dir, apkfilename)],
stdout=subprocess.PIPE)
output = p.communicate()[0]
print output
if p.returncode != 0:
raise BuildException("Failed to align application")
os.remove(apkfile)
# Move the source tarball into the output directory...
tarfilename = apkfilename[:-4] + '_src.tar.gz'
shutil.move(os.path.join(unsigned_dir, tarfilename),
os.path.join(output_dir, tarfilename))
print 'Published ' + apkfilename