import logging
commands = {
- "build": "Build a package from source",
- "init": "Quickly start a new repository",
- "publish": "Sign and place packages in the repo",
- "update": "Update repo information for new packages",
- "verify": "Verify the integrity of downloaded packages",
- "checkupdates": "Check for updates to applications",
- "import": "Add a new application from its source code",
- "install": "Install built packages on devices",
- "readmeta": "Read all the metadata files and exit",
- "rewritemeta": "Rewrite all the metadata files",
- "lint": "Warn about possible metadata errors",
- "scanner": "Scan the source code of a package",
- "stats": "Update the stats of the repo",
- "server": "Interact with the repo HTTP server",
- }
+ "build": "Build a package from source",
+ "init": "Quickly start a new repository",
+ "publish": "Sign and place packages in the repo",
+ "update": "Update repo information for new packages",
+ "verify": "Verify the integrity of downloaded packages",
+ "checkupdates": "Check for updates to applications",
+ "import": "Add a new application from its source code",
+ "install": "Install built packages on devices",
+ "readmeta": "Read all the metadata files and exit",
+ "rewritemeta": "Rewrite all the metadata files",
+ "lint": "Warn about possible metadata errors",
+ "scanner": "Scan the source code of a package",
+ "stats": "Update the stats of the repo",
+ "server": "Interact with the repo HTTP server",
+ }
def print_help():
logging.info("Adapting build.gradle at %s" % path)
FDroidPopen(['sed', '-i',
- r's@buildToolsVersion\([ =]*\)["\'][0-9\.]*["\']@buildToolsVersion\1"'
- + config['build_tools'] + '"@g', path])
+ r's@buildToolsVersion\([ =]*\)["\'][0-9\.]*["\']@buildToolsVersion\1"'
+ + config['build_tools'] + '"@g', path])
def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver):
# Prepare the source code...
root_dir, srclibpaths = common.prepare_source(vcs, app, thisbuild,
- build_dir, srclib_dir, extlib_dir, onserver)
+ build_dir, srclib_dir,
+ extlib_dir, onserver)
# We need to clean via the build tool in case the binary dirs are
# different from the default ones
if p is not None and p.returncode != 0:
raise BuildException("Error cleaning %s:%s" %
- (app['id'], thisbuild['version']), p.stdout)
+ (app['id'], thisbuild['version']), p.stdout)
logging.info("Getting rid of Gradle wrapper binaries...")
for root, dirs, files in os.walk(build_dir):
with open(manifest, 'r') as f:
manifestcontent = f.read()
manifestcontent = manifestcontent.replace('</manifest>',
- '<fdroid buildserverid="' + buildserverid + '"' +
- ' fdroidserverid="' + fdroidserverid + '"' +
- '/></manifest>')
+ '<fdroid buildserverid="'
+ + buildserverid + '"'
+ + ' fdroidserverid="'
+ + fdroidserverid + '"'
+ + '/></manifest>')
with open(manifest, 'w') as f:
f.write(manifestcontent)
if p.returncode != 0:
raise BuildException("Error running build command for %s:%s" %
- (app['id'], thisbuild['version']), p.stdout)
+ (app['id'], thisbuild['version']), p.stdout)
# Build native stuff if required...
if thisbuild.get('buildjni') not in (None, ['no']):
maven_dir = root_dir
mvncmd = [config['mvn3'], '-Dandroid.sdk.path=' + config['sdk_path'],
- '-Dmaven.jar.sign.skip=true', '-Dmaven.test.skip=true',
- '-Dandroid.sign.debug=false', '-Dandroid.release=true',
- 'package']
+ '-Dmaven.jar.sign.skip=true', '-Dmaven.test.skip=true',
+ '-Dandroid.sign.debug=false', '-Dandroid.release=true',
+ 'package']
if 'target' in thisbuild:
target = thisbuild["target"].split('-')[1]
FDroidPopen(['sed', '-i',
- 's@<platform>[0-9]*</platform>@<platform>'+target+'</platform>@g',
- 'pom.xml'], cwd=root_dir)
+ 's@<platform>[0-9]*</platform>@<platform>'+target+'</platform>@g',
+ 'pom.xml'],
+ cwd=root_dir)
if '@' in thisbuild['maven']:
FDroidPopen(['sed', '-i',
- 's@<platform>[0-9]*</platform>@<platform>'+target+'</platform>@g',
- 'pom.xml'], cwd=maven_dir)
+ 's@<platform>[0-9]*</platform>@<platform>'+target+'</platform>@g',
+ 'pom.xml'],
+ cwd=maven_dir)
if 'mvnflags' in thisbuild:
mvncmd += thisbuild['mvnflags']
spec = os.path.join(root_dir, 'buildozer.spec')
if not os.path.exists(spec):
raise BuildException("Expected to find buildozer-compatible spec at {0}"
- .format(spec))
+ .format(spec))
defaults = {'orientation': 'landscape', 'icon': '',
'permissions': '', 'android.api': "18"}
'--package', app['id'],
'--version', bconfig.get('app', 'version'),
'--orientation', orientation
- ]
+ ]
perms = bconfig.get('app', 'permissions')
for perm in perms.split(','):
stdout_apk = '\n'.join([
line for line in p.stdout.splitlines() if any(a in line for a in ('.apk', '.ap_'))])
m = re.match(r".*^\[INFO\] .*apkbuilder.*/([^/]*)\.apk",
- stdout_apk, re.S | re.M)
+ stdout_apk, re.S | re.M)
if not m:
m = re.match(r".*^\[INFO\] Creating additional unsigned apk file .*/([^/]+)\.apk[^l]",
- stdout_apk, re.S | re.M)
+ stdout_apk, re.S | re.M)
if not m:
m = re.match(r'.*^\[INFO\] [^$]*aapt \[package,[^$]*' + bindir + r'/([^/]+)\.ap[_k][,\]]',
- stdout_apk, re.S | re.M)
+ stdout_apk, re.S | re.M)
if not m:
raise BuildException('Failed to find output')
src = m.group(1)
src = os.path.join(bindir, src) + '.apk'
elif thisbuild['type'] == 'kivy':
src = 'python-for-android/dist/default/bin/{0}-{1}-release.apk'.format(
- bconfig.get('app', 'title'), bconfig.get('app', 'version'))
+ bconfig.get('app', 'title'), bconfig.get('app', 'version'))
elif thisbuild['type'] == 'gradle':
basename = app['id']
dd = build_dir
stdout_apk = '\n'.join([
line for line in p.stdout.splitlines() if '.apk' in line])
src = re.match(r".*^.*Creating (.+) for release.*$.*", stdout_apk,
- re.S | re.M).group(1)
+ re.S | re.M).group(1)
src = os.path.join(bindir, src)
elif thisbuild['type'] == 'raw':
src = os.path.join(root_dir, thisbuild['output'])
if not os.path.exists(src):
raise BuildException("Unsigned apk is not at expected location of " + src)
- p = SilentPopen([os.path.join(config['sdk_path'],
- 'build-tools', config['build_tools'], 'aapt'),
- 'dump', 'badging', src])
+ p = SilentPopen([os.path.join(config['sdk_path'], 'build-tools',
+ config['build_tools'], 'aapt'),
+ 'dump', 'badging', src])
vercode = None
version = None
if (version != thisbuild['version'] or
vercode != thisbuild['vercode']):
raise BuildException(("Unexpected version/version code in output;"
- " APK: '%s' / '%s', "
- " Expected: '%s' / '%s'")
- % (version, str(vercode), thisbuild['version'], str(thisbuild['vercode']))
- )
+ " APK: '%s' / '%s', "
+ " Expected: '%s' / '%s'")
+ % (version, str(vercode), thisbuild['version'],
+ str(thisbuild['vercode']))
+ )
# Copy the unsigned apk to our destination directory for further
# processing (by publish.py)...
def trybuild(app, thisbuild, build_dir, output_dir, also_check_dir, srclib_dir, extlib_dir,
- tmp_dir, repo_dir, vcs, test, server, force, onserver):
+ tmp_dir, repo_dir, vcs, test, server, force, onserver):
"""
Build a particular version of an application, if it needs building.
if options.wiki:
import mwclient
site = mwclient.Site((config['wiki_protocol'], config['wiki_server']),
- path=config['wiki_path'])
+ path=config['wiki_path'])
site.login(config['wiki_user'], config['wiki_password'])
# Build applications...
build_dir = os.path.join('build', app['id'])
# Set up vcs interface and make sure we have the latest code...
- logging.debug("Getting {0} vcs interface for {1}".format(
- app['Repo Type'], app['Repo']))
+ logging.debug("Getting {0} vcs interface for {1}"
+ .format(app['Repo Type'], app['Repo']))
vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir)
first = False
logging.debug("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):
+ 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):
build_succeeded.append(app)
wikilog = "Build succeeded"
except BuildException as be:
if not package or package != appid or not version or not vercode:
continue
- logging.debug("Manifest exists. Found version {0} ({1})".format(
- version, vercode))
+ logging.debug("Manifest exists. Found version {0} ({1})"
+ .format(version, vercode))
if int(vercode) > int(hcode):
htag = tag
hcode = str(int(vercode))
if version is not None:
stored = app['Current Version']
if not stored:
- logging.info("{0} has no Current Version but has version {1} on the Play Store".format(
- common.getappname(app), version))
+ logging.info("{0} has no Current Version but has version {1} on the Play Store"
+ .format(common.getappname(app), version))
elif LooseVersion(stored) < LooseVersion(version):
- logging.info("{0} has version {1} on the Play Store, which is bigger than {2}".format(
- common.getappname(app), version, stored))
+ logging.info("{0} has version {1} on the Play Store, which is bigger than {2}"
+ .format(common.getappname(app), version, stored))
else:
if stored != version:
- logging.info("{0} has version {1} on the Play Store, which differs from {2}".format(
- common.getappname(app), version, stored))
+ logging.info("{0} has version {1} on the Play Store, which differs from {2}"
+ .format(common.getappname(app), version, stored))
else:
- logging.info("{0} has the same version {1} on the Play Store".format(
- common.getappname(app), version))
+ logging.info("{0} has the same version {1} on the Play Store"
+ .format(common.getappname(app), version))
return
for app in apps:
flavour = None
logging.debug("...fetch auto name from " + app_dir +
- ((" (flavour: %s)" % flavour) if flavour else ""))
+ ((" (flavour: %s)" % flavour) if flavour else ""))
new_name = common.fetch_real_name(app_dir, flavour)
if new_name:
logging.debug("...got autoname '" + new_name + "'")
metadata.write_metadata(metafile, app)
if options.commit:
logging.info("Commiting update for " + metafile)
- gitcmd = ["git", "commit", "-m",
- commitmsg]
+ gitcmd = ["git", "commit", "-m", commitmsg]
if 'auto_author' in config:
gitcmd.extend(['--author', config['auto_author']])
gitcmd.extend(["--", metafile])
# and remote that directory was created from, allowing us to drop it
# automatically if either of those things changes.
fdpath = os.path.join(self.local, '..',
- '.fdroidvcs-' + os.path.basename(self.local))
+ '.fdroidvcs-' + os.path.basename(self.local))
cdata = self.repotype() + ' ' + self.remote
writeback = True
deleterepo = False
p = SilentPopen(['echo "'+'\n'.join(alltags)+'" | \
xargs -I@ git log --format=format:"%at @%n" -1 @ | \
sort -n | awk \'{print $2}\''],
- cwd=self.local, shell=True)
+ cwd=self.local, shell=True)
return p.stdout.splitlines()[-number:]
def retrieve_string(app_dir, string, xmlfiles=None):
res_dirs = [
- os.path.join(app_dir, 'res'),
- os.path.join(app_dir, 'src/main'),
- ]
+ os.path.join(app_dir, 'res'),
+ os.path.join(app_dir, 'src/main'),
+ ]
if xmlfiles is None:
xmlfiles = []
# Return list of existing files that will be used to find the highest vercode
def manifest_paths(app_dir, flavour):
- possible_manifests = [os.path.join(app_dir, 'AndroidManifest.xml'),
- os.path.join(app_dir, 'src', 'main', 'AndroidManifest.xml'),
- os.path.join(app_dir, 'src', 'AndroidManifest.xml'),
- os.path.join(app_dir, 'build.gradle')]
+ possible_manifests = \
+ [os.path.join(app_dir, 'AndroidManifest.xml'),
+ os.path.join(app_dir, 'src', 'main', 'AndroidManifest.xml'),
+ os.path.join(app_dir, 'src', 'AndroidManifest.xml'),
+ os.path.join(app_dir, 'build.gradle')]
if flavour:
possible_manifests.append(
- os.path.join(app_dir, 'src', flavour, 'AndroidManifest.xml'))
+ os.path.join(app_dir, 'src', flavour, 'AndroidManifest.xml'))
return [path for path in possible_manifests if os.path.isfile(path)]
# it, which may be a subdirectory of the actual project. If you want the base
# directory of the project, pass 'basepath=True'.
def getsrclib(spec, srclib_dir, srclibpaths=[], subdir=None,
- basepath=False, raw=False, prepare=True, preponly=False):
+ basepath=False, raw=False, prepare=True, preponly=False):
number = None
subdir = None
p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=libdir)
if p.returncode != 0:
raise BuildException("Error running prepare command for srclib %s"
- % name, p.stdout)
+ % name, p.stdout)
if basepath:
libdir = sdir
p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=root_dir)
if p.returncode != 0:
raise BuildException("Error running init command for %s:%s" %
- (app['id'], build['version']), p.stdout)
+ (app['id'], build['version']), p.stdout)
# Apply patches if any
if 'patch' in build:
logging.info("Collecting source libraries")
for lib in build['srclibs']:
srclibpaths.append(getsrclib(lib, srclib_dir, srclibpaths,
- preponly=onserver))
+ preponly=onserver))
for name, number, libpath in srclibpaths:
place_srclib(root_dir, int(number) if number else None, libpath)
# from sdk.dir, if necessary
if build['oldsdkloc']:
sdkloc = re.match(r".*^sdk.dir=(\S+)$.*", props,
- re.S | re.M).group(1)
+ re.S | re.M).group(1)
props += "sdk-location=%s\n" % sdkloc
else:
props += "sdk.dir=%s\n" % config['sdk_path']
if 'target' in build:
n = build["target"].split('-')[1]
FDroidPopen(['sed', '-i',
- 's@compileSdkVersion *[0-9]*@compileSdkVersion '+n+'@g',
- 'build.gradle'], cwd=root_dir)
+ 's@compileSdkVersion *[0-9]*@compileSdkVersion '+n+'@g',
+ 'build.gradle'],
+ cwd=root_dir)
if '@' in build['gradle']:
gradle_dir = os.path.join(root_dir, build['gradle'].split('@', 1)[1])
gradle_dir = os.path.normpath(gradle_dir)
FDroidPopen(['sed', '-i',
- 's@compileSdkVersion *[0-9]*@compileSdkVersion '+n+'@g',
- 'build.gradle'], cwd=gradle_dir)
+ 's@compileSdkVersion *[0-9]*@compileSdkVersion '+n+'@g',
+ 'build.gradle'],
+ cwd=gradle_dir)
# Remove forced debuggable flags
remove_debuggable_flags(root_dir)
continue
if has_extension(path, 'xml'):
p = SilentPopen(['sed', '-i',
- 's/android:versionName="[^"]*"/android:versionName="' + build['version'] + '"/g',
- path])
+ 's/android:versionName="[^"]*"/android:versionName="'
+ + build['version'] + '"/g',
+ path])
if p.returncode != 0:
raise BuildException("Failed to amend manifest")
elif has_extension(path, 'gradle'):
p = SilentPopen(['sed', '-i',
- 's/versionName *=* *"[^"]*"/versionName = "' + build['version'] + '"/g',
- path])
+ 's/versionName *=* *"[^"]*"/versionName = "'
+ + build['version'] + '"/g',
+ path])
if p.returncode != 0:
raise BuildException("Failed to amend build.gradle")
if build['forcevercode']:
continue
if has_extension(path, 'xml'):
p = SilentPopen(['sed', '-i',
- 's/android:versionCode="[^"]*"/android:versionCode="' + build['vercode'] + '"/g',
- path])
+ 's/android:versionCode="[^"]*"/android:versionCode="'
+ + build['vercode'] + '"/g',
+ path])
if p.returncode != 0:
raise BuildException("Failed to amend manifest")
elif has_extension(path, 'gradle'):
p = SilentPopen(['sed', '-i',
- 's/versionCode *=* *[0-9]*/versionCode = ' + build['vercode'] + '/g',
- path])
+ 's/versionCode *=* *[0-9]*/versionCode = '
+ + build['vercode'] + '/g',
+ path])
if p.returncode != 0:
raise BuildException("Failed to amend build.gradle")
p = FDroidPopen(['bash', '-x', '-c', cmd], cwd=root_dir)
if p.returncode != 0:
raise BuildException("Error running prebuild command for %s:%s" %
- (app['id'], build['version']), p.stdout)
+ (app['id'], build['version']), p.stdout)
updatemode = build.get('update', ['auto'])
# Generate (or update) the ant build file, build.xml...
# Common known non-free blobs (always lower case):
usual_suspects = [
- re.compile(r'flurryagent', re.IGNORECASE),
- re.compile(r'paypal.*mpl', re.IGNORECASE),
- re.compile(r'libgoogleanalytics', re.IGNORECASE),
- re.compile(r'admob.*sdk.*android', re.IGNORECASE),
- re.compile(r'googleadview', re.IGNORECASE),
- re.compile(r'googleadmobadssdk', re.IGNORECASE),
- re.compile(r'google.*play.*services', re.IGNORECASE),
- re.compile(r'crittercism', re.IGNORECASE),
- re.compile(r'heyzap', re.IGNORECASE),
- re.compile(r'jpct.*ae', re.IGNORECASE),
- re.compile(r'youtubeandroidplayerapi', re.IGNORECASE),
- re.compile(r'bugsense', re.IGNORECASE),
- re.compile(r'crashlytics', re.IGNORECASE),
- re.compile(r'ouya.*sdk', re.IGNORECASE),
- ]
+ re.compile(r'flurryagent', re.IGNORECASE),
+ re.compile(r'paypal.*mpl', re.IGNORECASE),
+ re.compile(r'libgoogleanalytics', re.IGNORECASE),
+ re.compile(r'admob.*sdk.*android', re.IGNORECASE),
+ re.compile(r'googleadview', re.IGNORECASE),
+ re.compile(r'googleadmobadssdk', re.IGNORECASE),
+ re.compile(r'google.*play.*services', re.IGNORECASE),
+ re.compile(r'crittercism', re.IGNORECASE),
+ re.compile(r'heyzap', re.IGNORECASE),
+ re.compile(r'jpct.*ae', re.IGNORECASE),
+ re.compile(r'youtubeandroidplayerapi', re.IGNORECASE),
+ re.compile(r'bugsense', re.IGNORECASE),
+ re.compile(r'crashlytics', re.IGNORECASE),
+ re.compile(r'ouya.*sdk', re.IGNORECASE),
+ ]
scanignore = getpaths(build_dir, thisbuild, 'scanignore')
scandelete = getpaths(build_dir, thisbuild, 'scandelete')
:param apkfile: full path to the apk to check"""
- p = SilentPopen([os.path.join(config['sdk_path'],
- 'build-tools', config['build_tools'], 'aapt'),
- 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'])
+ p = SilentPopen([os.path.join(config['sdk_path'], 'build-tools',
+ config['build_tools'], 'aapt'),
+ 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'])
if p.returncode != 0:
logging.critical("Failed to get apk manifest information")
sys.exit(1)
result = PopenResult()
p = subprocess.Popen(commands, cwd=cwd, shell=shell,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout_queue = Queue.Queue()
stdout_reader = AsynchronousFileReader(p.stdout, stdout_queue)
comment = re.compile(r'[ ]*//')
signing_configs = re.compile(r'^[\t ]*signingConfigs[ \t]*{[ \t]*$')
line_matches = [
- re.compile(r'^[\t ]*signingConfig [^ ]*$'),
- re.compile(r'.*android\.signingConfigs\..*'),
- re.compile(r'.*variant\.outputFile = .*'),
- re.compile(r'.*\.readLine\(.*'),
- ]
+ re.compile(r'^[\t ]*signingConfig [^ ]*$'),
+ re.compile(r'.*android\.signingConfigs\..*'),
+ re.compile(r'.*variant\.outputFile = .*'),
+ re.compile(r'.*\.readLine\(.*'),
+ ]
for root, dirs, files in os.walk(build_dir):
if 'build.gradle' in files:
path = os.path.join(root, 'build.gradle')
spec = os.path.join(root_dir, 'buildozer.spec')
if os.path.exists(spec):
defaults = {'orientation': 'landscape', 'icon': '',
- 'permissions': '', 'android.api': "18"}
+ 'permissions': '', 'android.api': "18"}
bconfig = ConfigParser(defaults, allow_no_value=True)
bconfig.read(spec)
package = bconfig.get('app', 'package.domain') + '.' + bconfig.get('app', 'package.name')
common.write_password_file("keystorepass", password)
common.write_password_file("keypass", password)
p = FDroidPopen(['keytool', '-genkey',
- '-keystore', keystore, '-alias', repo_keyalias,
- '-keyalg', 'RSA', '-keysize', '4096',
- '-sigalg', 'SHA256withRSA',
- '-validity', '10000',
- '-storepass:file', config['keystorepassfile'],
- '-keypass:file', config['keypassfile'],
- '-dname', keydname])
+ '-keystore', keystore, '-alias', repo_keyalias,
+ '-keyalg', 'RSA', '-keysize', '4096',
+ '-sigalg', 'SHA256withRSA',
+ '-validity', '10000',
+ '-storepass:file', config['keystorepassfile'],
+ '-keypass:file', config['keypassfile'],
+ '-dname', keydname])
# TODO keypass should be sent via stdin
if p.returncode != 0:
raise BuildException("Failed to generate key", p.stdout)
if repo_keyalias is not None:
logging.info(' Alias for key in store:\t' + repo_keyalias)
logging.info('\nTo complete the setup, add your APKs to "' +
- os.path.join(fdroiddir, 'repo') + '"' +
-'''
+ os.path.join(fdroiddir, 'repo') + '"' + '''
then run "fdroid update -c; fdroid update". You might also want to edit
"config.py" to set the URL, repo name, and more. You should also set up
a signing key (a temporary one might have been automatically generated).
options = None
regex_warnings = {
- 'Web Site': [
- (re.compile(r'.*[^sS]://github\.com/.*'),
- "github URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://code\.google\.com/.*'),
- "code.google.com URLs should always use https:// not http://"),
+ 'Web Site': [
+ (re.compile(r'.*[^sS]://github\.com/.*'),
+ "github URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://code\.google\.com/.*'),
+ "code.google.com URLs should always use https:// not http://"),
],
- 'Source Code': [
- (re.compile(r'.*[^sS]://github\.com/.*'),
- "github URLs should always use https:// (not http://, git://, or git@)"),
- (re.compile(r'.*code\.google\.com/p/[^/]+[/]*$'),
- "/source is missing"),
- (re.compile(r'.*[^sS]://code\.google\.com/.*'),
- "code.google.com URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://dl\.google\.com/.*'),
- "dl.google.com URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://gitorious\.org/.*'),
- "gitorious URLs should always use https:// (not http://, git://, or git@)"),
+ 'Source Code': [
+ (re.compile(r'.*[^sS]://github\.com/.*'),
+ "github URLs should always use https:// (not http://, git://, or git@)"),
+ (re.compile(r'.*code\.google\.com/p/[^/]+[/]*$'),
+ "/source is missing"),
+ (re.compile(r'.*[^sS]://code\.google\.com/.*'),
+ "code.google.com URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://dl\.google\.com/.*'),
+ "dl.google.com URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://gitorious\.org/.*'),
+ "gitorious URLs should always use https:// (not http://, git://, or git@)"),
],
- 'Repo': [
- (re.compile(r'.*[^sS]://code\.google\.com/.*'),
- "code.google.com URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://dl\.google\.com/.*'),
- "dl.google.com URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://github\.com/.*'),
- "github URLs should always use https:// (not http://, git://, or git@)"),
- (re.compile(r'.*[^sS]://gitorious\.org/.*'),
- "gitorious URLs should always use https:// (not http://, git://, or git@)"),
- (re.compile(r'.*[^sS]://[^.]*\.googlecode\.com/svn/?.*'),
- "Google Code SVN URLs should always use https:// (not http:// or svn://)"),
- (re.compile(r'.*[^sS]://svn\.apache\.org/repos/?.*'),
- "Apache SVN URLs should always use https:// (not http:// or svn://)"),
- (re.compile(r'.*[^sS]://svn\.code\.sf\.net/.*'),
- "Sourceforge SVN URLs should always use https:// (not http:// or svn://)"),
+ 'Repo': [
+ (re.compile(r'.*[^sS]://code\.google\.com/.*'),
+ "code.google.com URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://dl\.google\.com/.*'),
+ "dl.google.com URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://github\.com/.*'),
+ "github URLs should always use https:// (not http://, git://, or git@)"),
+ (re.compile(r'.*[^sS]://gitorious\.org/.*'),
+ "gitorious URLs should always use https:// (not http://, git://, or git@)"),
+ (re.compile(r'.*[^sS]://[^.]*\.googlecode\.com/svn/?.*'),
+ "Google Code SVN URLs should always use https:// (not http:// or svn://)"),
+ (re.compile(r'.*[^sS]://svn\.apache\.org/repos/?.*'),
+ "Apache SVN URLs should always use https:// (not http:// or svn://)"),
+ (re.compile(r'.*[^sS]://svn\.code\.sf\.net/.*'),
+ "Sourceforge SVN URLs should always use https:// (not http:// or svn://)"),
],
- 'Issue Tracker': [
- (re.compile(r'.*code\.google\.com/p/[^/]+[/]*$'),
- "/issues is missing"),
- (re.compile(r'.*[^sS]://code\.google\.com/.*'),
- "code.google.com URLs should always use https:// not http://"),
- (re.compile(r'.*github\.com/[^/]+/[^/]+[/]*$'),
- "/issues is missing"),
- (re.compile(r'.*[^sS]://github\.com/.*'),
- "github URLs should always use https:// not http://"),
- (re.compile(r'.*[^sS]://gitorious\.org/.*'),
- "gitorious URLs should always use https:// not http://"),
+ 'Issue Tracker': [
+ (re.compile(r'.*code\.google\.com/p/[^/]+[/]*$'),
+ "/issues is missing"),
+ (re.compile(r'.*[^sS]://code\.google\.com/.*'),
+ "code.google.com URLs should always use https:// not http://"),
+ (re.compile(r'.*github\.com/[^/]+/[^/]+[/]*$'),
+ "/issues is missing"),
+ (re.compile(r'.*[^sS]://github\.com/.*'),
+ "github URLs should always use https:// not http://"),
+ (re.compile(r'.*[^sS]://gitorious\.org/.*'),
+ "gitorious URLs should always use https:// not http://"),
],
- 'Description': [
- (re.compile(r'[ ]*[*#][^ .]'),
- "Invalid bulleted list"),
- (re.compile(r'^ '),
- "Unnecessary leading space"),
+ 'Description': [
+ (re.compile(r'[ ]*[*#][^ .]'),
+ "Invalid bulleted list"),
+ (re.compile(r'^ '),
+ "Unnecessary leading space"),
],
-
}
regex_pedantic = {
- 'Web Site': [
- (re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
- "Appending .git is not necessary"),
- (re.compile(r'.*code\.google\.com/p/[^/]+/[^w]'),
- "Possible incorrect path appended to google code project site"),
+ 'Web Site': [
+ (re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
+ "Appending .git is not necessary"),
+ (re.compile(r'.*code\.google\.com/p/[^/]+/[^w]'),
+ "Possible incorrect path appended to google code project site"),
],
- 'Source Code': [
- (re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
- "Appending .git is not necessary"),
- (re.compile(r'.*code\.google\.com/p/[^/]+/source/.*'),
- "/source is often enough on its own"),
+ 'Source Code': [
+ (re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
+ "Appending .git is not necessary"),
+ (re.compile(r'.*code\.google\.com/p/[^/]+/source/.*'),
+ "/source is often enough on its own"),
],
- 'Repo': [
- (re.compile(r'^http://.*'),
- "if https:// is available, use it instead of http://"),
- (re.compile(r'^svn://.*'),
- "if https:// is available, use it instead of svn://"),
+ 'Repo': [
+ (re.compile(r'^http://.*'),
+ "if https:// is available, use it instead of http://"),
+ (re.compile(r'^svn://.*'),
+ "if https:// is available, use it instead of svn://"),
],
- 'Issue Tracker': [
- (re.compile(r'.*code\.google\.com/p/[^/]+/issues/.*'),
- "/issues is often enough on its own"),
- (re.compile(r'.*github\.com/[^/]+/[^/]+/issues/.*'),
- "/issues is often enough on its own"),
+ 'Issue Tracker': [
+ (re.compile(r'.*code\.google\.com/p/[^/]+/issues/.*'),
+ "/issues is often enough on its own"),
+ (re.compile(r'.*github\.com/[^/]+/[^/]+/issues/.*'),
+ "/issues is often enough on its own"),
],
- 'Summary': [
- (re.compile(r'.*\bandroid\b.*', re.IGNORECASE),
- "No need to specify that the app is for Android"),
- (re.compile(r'.*\b(app|application)\b.*', re.IGNORECASE),
- "No need to specify that the app is... an app"),
- (re.compile(r'.*\b(free software|open source)\b.*', re.IGNORECASE),
- "No need to specify that the app is Free Software"),
- (re.compile(r'.*[a-z0-9][.,!?][ $]'),
- "Punctuation should be avoided"),
+ 'Summary': [
+ (re.compile(r'.*\bandroid\b.*', re.IGNORECASE),
+ "No need to specify that the app is for Android"),
+ (re.compile(r'.*\b(app|application)\b.*', re.IGNORECASE),
+ "No need to specify that the app is... an app"),
+ (re.compile(r'.*\b(free software|open source)\b.*', re.IGNORECASE),
+ "No need to specify that the app is Free Software"),
+ (re.compile(r'.*[a-z0-9][.,!?][ $]'),
+ "Punctuation should be avoided"),
],
-}
+ }
def main():
pwarn("Summary '%s' probably contains redundant info already in app name '%s'" % (
summary, name))
-
# Description size limit
desc_chars = sum(len(l) for l in app['Description'])
if desc_chars > config['char_limits']['Description']:
if m.match(l):
warn("%s at line '%s': %s" % (f, l, r))
-
# Regex pedantic checks in all kinds of fields
if options.pedantic:
for f in regex_pedantic:
'Repo': '',
'Requires Root': False,
'No Source Since': ''
-}
+ }
# This defines the preferred order for the build items - as in the
'extlibs', 'srclibs', 'patch', 'prebuild', 'scanignore',
'scandelete', 'build', 'buildjni', 'preassemble', 'bindir',
'antcommand', 'novcheck'
-]
+ ]
# Designates a metadata field type and checks that it matches
for v in values:
if not self.compiled.match(v):
raise MetaDataException("'%s' is not a valid %s in %s. "
- % (v, self.name, appid) +
- "Regex pattern: %s" % (self.matching))
+ % (v, self.name, appid) +
+ "Regex pattern: %s" % (self.matching))
def _assert_list(self, values, appid):
for v in values:
if v not in self.matching:
raise MetaDataException("'%s' is not a valid %s in %s. "
- % (v, self.name, appid) +
- "Possible values: %s" % (", ".join(self.matching)))
+ % (v, self.name, appid) +
+ "Possible values: %s" % (", ".join(self.matching)))
def check(self, value, appid):
if type(value) is not str or not value:
# Generic value types
valuetypes = {
'int': FieldType("Integer",
- r'^[1-9][0-9]*$', None,
- ['FlattrID'],
- ['vercode']),
+ r'^[1-9][0-9]*$', None,
+ ['FlattrID'],
+ ['vercode']),
'http': FieldType("HTTP link",
- r'^http[s]?://', None,
- ["Web Site", "Source Code", "Issue Tracker", "Donate"], []),
+ r'^http[s]?://', None,
+ ["Web Site", "Source Code", "Issue Tracker", "Donate"], []),
'bitcoin': FieldType("Bitcoin address",
- r'^[a-zA-Z0-9]{27,34}$', None,
- ["Bitcoin"],
- []),
+ r'^[a-zA-Z0-9]{27,34}$', None,
+ ["Bitcoin"],
+ []),
'litecoin': FieldType("Litecoin address",
- r'^L[a-zA-Z0-9]{33}$', None,
- ["Litecoin"],
- []),
+ r'^L[a-zA-Z0-9]{33}$', None,
+ ["Litecoin"],
+ []),
'dogecoin': FieldType("Dogecoin address",
- r'^D[a-zA-Z0-9]{33}$', None,
- ["Dogecoin"],
- []),
+ r'^D[a-zA-Z0-9]{33}$', None,
+ ["Dogecoin"],
+ []),
'Bool': FieldType("Boolean",
- ['Yes', 'No'], None,
- ["Requires Root"],
- []),
+ ['Yes', 'No'], None,
+ ["Requires Root"],
+ []),
'bool': FieldType("Boolean",
- ['yes', 'no'], None,
- [],
- ['submodules', 'oldsdkloc', 'forceversion', 'forcevercode',
- 'novcheck']),
+ ['yes', 'no'], None,
+ [],
+ ['submodules', 'oldsdkloc', 'forceversion', 'forcevercode',
+ 'novcheck']),
'Repo Type': FieldType("Repo Type",
- ['git', 'git-svn', 'svn', 'hg', 'bzr', 'srclib'], None,
- ["Repo Type"],
- []),
+ ['git', 'git-svn', 'svn', 'hg', 'bzr', 'srclib'], None,
+ ["Repo Type"],
+ []),
'archive': FieldType("Archive Policy",
- r'^[0-9]+ versions$', None,
- ["Archive Policy"],
- []),
+ r'^[0-9]+ versions$', None,
+ ["Archive Policy"],
+ []),
'antifeatures': FieldType("Anti-Feature",
- ["Ads", "Tracking", "NonFreeNet", "NonFreeDep", "NonFreeAdd", "UpstreamNonFree"], ',',
- ["AntiFeatures"],
- []),
+ ["Ads", "Tracking", "NonFreeNet", "NonFreeDep", "NonFreeAdd", "UpstreamNonFree"], ',',
+ ["AntiFeatures"],
+ []),
'autoupdatemodes': FieldType("Auto Update Mode",
- r"^(Version .+|None)$", None,
- ["Auto Update Mode"],
- []),
+ r"^(Version .+|None)$", None,
+ ["Auto Update Mode"],
+ []),
'updatecheckmodes': FieldType("Update Check Mode",
- r"^(Tags|Tags .+|RepoManifest|RepoManifest/.+|RepoTrunk|HTTP|Static|None)$", None,
- ["Update Check Mode"],
- [])
-}
+ r"^(Tags|Tags .+|RepoManifest|RepoManifest/.+|RepoTrunk|HTTP|Static|None)$", None,
+ ["Update Check Mode"],
+ [])
+ }
# Check an app's metadata information for integrity errors
description_html(app['Description'], linkres)
except Exception, e:
raise MetaDataException("Problem with description of " + app['id'] +
- " - " + str(e))
+ " - " + str(e))
return apps
def flagtype(name):
if name in ['extlibs', 'srclibs', 'patch', 'rm', 'buildjni',
- 'update', 'scanignore', 'scandelete']:
+ 'update', 'scanignore', 'scandelete']:
return 'list'
if name in ['init', 'prebuild', 'build']:
return 'script'
def add_buildflag(p, thisbuild):
bv = p.split('=', 1)
if len(bv) != 2:
- raise MetaDataException("Invalid build flag at {0} in {1}".
- format(buildlines[0], linedesc))
+ raise MetaDataException("Invalid build flag at {0} in {1}"
+ .format(buildlines[0], linedesc))
pk, pv = bv
if pk in thisbuild:
- raise MetaDataException("Duplicate definition on {0} in version {1} of {2}".
- format(pk, thisbuild['version'], linedesc))
+ raise MetaDataException("Duplicate definition on {0} in version {1} of {2}"
+ .format(pk, thisbuild['version'], linedesc))
pk = pk.lstrip()
if pk not in ordered_flags:
- raise MetaDataException("Unrecognised build flag at {0} in {1}".
- format(p, linedesc))
+ raise MetaDataException("Unrecognised build flag at {0} in {1}"
+ .format(p, linedesc))
t = flagtype(pk)
if t == 'list':
# Port legacy ';' separators
elif t == 'script':
thisbuild[pk] = pv
else:
- raise MetaDataException("Unrecognised build flag type '%s' at %s in %s" % (
- t, p, linedesc))
+ raise MetaDataException("Unrecognised build flag type '%s' at %s in %s"
+ % (t, p, linedesc))
def parse_buildline(lines):
value = "".join(lines)
if mode == 3:
if not any(line.startswith(s) for s in (' ', '\t')):
if 'commit' not in curbuild and 'disable' not in curbuild:
- raise MetaDataException("No commit specified for {0} in {1}".format(
- curbuild['version'], linedesc))
+ raise MetaDataException("No commit specified for {0} in {1}"
+ .format(curbuild['version'], linedesc))
thisinfo['builds'].append(curbuild)
add_comments('build:' + curbuild['version'])
mode = 0
curbuild = {}
vv = value.split(',')
if len(vv) != 2:
- raise MetaDataException('Build should have comma-separated version and vercode, not "{0}", in {1}'.
- format(value, linedesc))
+ raise MetaDataException('Build should have comma-separated version and vercode, not "{0}", in {1}'
+ .format(value, linedesc))
curbuild['version'] = vv[0]
curbuild['vercode'] = vv[1]
buildlines = []
# See if we already have a key for this application, and
# if not generate one...
p = FDroidPopen(['keytool', '-list',
- '-alias', keyalias, '-keystore', config['keystore'],
- '-storepass:file', config['keystorepassfile']])
+ '-alias', keyalias, '-keystore', config['keystore'],
+ '-storepass:file', config['keystorepassfile']])
if p.returncode != 0:
logging.info("Key does not exist - generating...")
p = FDroidPopen(['keytool', '-genkey',
- '-keystore', config['keystore'], '-alias', keyalias,
- '-keyalg', 'RSA', '-keysize', '2048',
- '-validity', '10000',
- '-storepass:file', config['keystorepassfile'],
- '-keypass:file', config['keypassfile'],
- '-dname', config['keydname']])
+ '-keystore', config['keystore'],
+ '-alias', keyalias,
+ '-keyalg', 'RSA', '-keysize', '2048',
+ '-validity', '10000',
+ '-storepass:file', config['keystorepassfile'],
+ '-keypass:file', config['keypassfile'],
+ '-dname', config['keydname']])
# TODO keypass should be sent via stdin
if p.returncode != 0:
raise BuildException("Failed to generate key")
# Sign the application...
p = FDroidPopen(['jarsigner', '-keystore', config['keystore'],
- '-storepass:file', config['keystorepassfile'],
- '-keypass:file', config['keypassfile'], '-sigalg',
- 'MD5withRSA', '-digestalg', 'SHA1',
- apkfile, keyalias])
+ '-storepass:file', config['keystorepassfile'],
+ '-keypass:file', config['keypassfile'], '-sigalg',
+ 'MD5withRSA', '-digestalg', 'SHA1',
+ apkfile, keyalias])
# TODO keypass should be sent via stdin
if p.returncode != 0:
raise BuildException("Failed to sign application")
# Zipalign it...
p = FDroidPopen([os.path.join(config['sdk_path'], 'tools', 'zipalign'),
- '-v', '4', apkfile,
- os.path.join(output_dir, apkfilename)])
+ '-v', '4', apkfile,
+ os.path.join(output_dir, apkfilename)])
if p.returncode != 0:
raise BuildException("Failed to align application")
os.remove(apkfile)
# Prepare the source code...
root_dir, _ = common.prepare_source(vcs, app, thisbuild,
- build_dir, srclib_dir, extlib_dir, False)
+ build_dir, srclib_dir,
+ extlib_dir, False)
# Do the scan...
buildprobs = common.scan_source(build_dir, root_dir, thisbuild)
for problem in buildprobs:
- problems.append(problem +
- ' in ' + app['id'] + ' ' + thisbuild['version'])
+ problems.append(problem + ' in ' + app['id']
+ + ' ' + thisbuild['version'])
except BuildException as be:
msg = "Could not scan app %s due to BuildException: %s" % (app['id'], be)
appscount = Counter()
appsvercount = Counter()
logexpr = '(?P<ip>[.:0-9a-fA-F]+) - - \[(?P<time>.*?)\] ' + \
- '"GET (?P<uri>.*?) HTTP/1.\d" (?P<statuscode>\d+) ' + \
- '\d+ "(?P<referral>.*?)" "(?P<useragent>.*?)"'
+ '"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')):
logging.debug('...' + logfile)
wikiredircat = 'App Redirects'
import mwclient
site = mwclient.Site((config['wiki_protocol'], config['wiki_server']),
- path=config['wiki_path'])
+ path=config['wiki_path'])
site.login(config['wiki_user'], config['wiki_password'])
generated_pages = {}
generated_redirects = {}
for af in app['AntiFeatures'].split(','):
wikidata += '{{AntiFeature|' + af + '}}\n'
wikidata += '{{App|id=%s|name=%s|added=%s|lastupdated=%s|source=%s|tracker=%s|web=%s|donate=%s|flattr=%s|bitcoin=%s|litecoin=%s|dogecoin=%s|license=%s|root=%s}}\n' % (
- app['id'],
- app['Name'],
- time.strftime('%Y-%m-%d', app['added']) if 'added' in app else '',
- time.strftime('%Y-%m-%d', app['lastupdated']) if 'lastupdated' in app else '',
- app['Source Code'],
- app['Issue Tracker'],
- app['Web Site'],
- app['Donate'],
- app['FlattrID'],
- app['Bitcoin'],
- app['Litecoin'],
- app['Dogecoin'],
- app['License'],
- app.get('Requires Root', 'No'))
+ app['id'],
+ app['Name'],
+ time.strftime('%Y-%m-%d', app['added']) if 'added' in app else '',
+ time.strftime('%Y-%m-%d', app['lastupdated']) if 'lastupdated' in app else '',
+ app['Source Code'],
+ app['Issue Tracker'],
+ app['Web Site'],
+ app['Donate'],
+ app['FlattrID'],
+ app['Bitcoin'],
+ app['Litecoin'],
+ app['Dogecoin'],
+ app['License'],
+ app.get('Requires Root', 'No'))
if app['Provides']:
wikidata += "This app provides: %s" % ', '.join(app['Summary'].split(','))
if 'disable' in thisbuild:
if thisbuild['vercode'] == app['Current Version Code']:
cantupdate = True
- apklist.append({
- #TODO: Nasty: vercode is a string in the build, and an int elsewhere
- 'versioncode': int(thisbuild['vercode']),
- 'version': thisbuild['version'],
- 'buildproblem': thisbuild['disable']
- })
+ #TODO: Nasty: vercode is a string in the build, and an int elsewhere
+ apklist.append({'versioncode': int(thisbuild['vercode']),
+ 'version': thisbuild['version'],
+ 'buildproblem': thisbuild['disable']
+ })
else:
builtit = False
for apk in apklist:
break
if not builtit:
buildfails = True
- apklist.append({
- 'versioncode': int(thisbuild['vercode']),
- 'version': thisbuild['version'],
- 'buildproblem': "The build for this version appears to have failed. Check the [[{0}/lastbuild|build log]].".format(app['id'])
- })
+ apklist.append({'versioncode': int(thisbuild['vercode']),
+ 'version': thisbuild['version'],
+ 'buildproblem': "The build for this version appears to have failed. Check the [[{0}/lastbuild|build log]].".format(app['id'])
+ })
if app['Current Version Code'] == '0':
cantupdate = True
# Sort with most recent first...
# Drop double spaces caused mostly by replacing ':' above
apppagename = apppagename.replace(' ', ' ')
for expagename in site.allpages(prefix=apppagename,
- filterredir='nonredirects', generator=False):
+ filterredir='nonredirects',
+ generator=False):
if expagename == apppagename:
noclobber = True
# Another reason not to make the redirect page is if the app name
generated_redirects[apppagename] = "#REDIRECT [[" + pagename + "]]\n[[Category:" + wikiredircat + "]]"
for tcat, genp in [(wikicat, generated_pages),
- (wikiredircat, generated_redirects)]:
+ (wikiredircat, generated_redirects)]:
catpages = site.Pages['Category:' + tcat]
existingpages = []
for page in catpages:
thisinfo['features'] = []
thisinfo['icons_src'] = {}
thisinfo['icons'] = {}
- p = FDroidPopen([os.path.join(config['sdk_path'],
- 'build-tools', config['build_tools'], 'aapt'),
- 'dump', 'badging', apkfile])
+ p = FDroidPopen([os.path.join(config['sdk_path'], 'build-tools',
+ config['build_tools'], 'aapt'),
+ 'dump', 'badging', apkfile])
if p.returncode != 0:
logging.critical("Failed to get apk information")
sys.exit(1)
perm = re.match(string_pat, line).group(1)
#Filter out this, it's only added with the latest SDK tools and
#causes problems for lots of apps.
- if (perm != "android.hardware.screen.portrait" and
- perm != "android.hardware.screen.landscape"):
+ if perm != "android.hardware.screen.portrait" \
+ and perm != "android.hardware.screen.landscape":
if perm.startswith("android.feature."):
perm = perm[16:]
thisinfo['features'].append(perm)
logging.critical("getsig.class not found. To fix: cd '%s' && ./make.sh" % getsig_dir)
sys.exit(1)
p = FDroidPopen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'),
- 'getsig', os.path.join(os.getcwd(), apkfile)])
+ '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)
apk = zipfile.ZipFile(apkfile, 'r')
iconfilename = "%s.%s.png" % (
- thisinfo['id'],
- thisinfo['versioncode'])
+ thisinfo['id'],
+ thisinfo['versioncode'])
# Extract the icon file...
densities = get_densities()
if '-1' in thisinfo['icons_src']:
iconsrc = thisinfo['icons_src']['-1']
iconpath = os.path.join(
- get_icon_dir(repodir, None), iconfilename)
+ get_icon_dir(repodir, None), iconfilename)
iconfile = open(iconpath, 'wb')
iconfile.write(apk.read(iconsrc))
iconfile.close()
if density == densities[-1] or dpi >= int(density):
thisinfo['icons'][density] = iconfilename
shutil.move(iconpath,
- os.path.join(get_icon_dir(repodir, density), iconfilename))
+ os.path.join(get_icon_dir(repodir, density), iconfilename))
empty_densities.remove(density)
break
except Exception, e:
continue
if last_density is None:
continue
- logging.info("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)
+ get_icon_dir(repodir, last_density), iconfilename)
iconpath = os.path.join(
- get_icon_dir(repodir, density), iconfilename)
+ get_icon_dir(repodir, density), iconfilename)
try:
im = Image.open(last_iconpath)
except:
continue
if last_density is None:
continue
- logging.info("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),
- os.path.join(get_icon_dir(repodir, density), iconfilename))
+ os.path.join(get_icon_dir(repodir, last_density), iconfilename),
+ os.path.join(get_icon_dir(repodir, density), iconfilename))
empty_densities.remove(density)
baseline = os.path.join(get_icon_dir(repodir, '160'), iconfilename)
if os.path.isfile(baseline):
shutil.copyfile(baseline,
- os.path.join(get_icon_dir(repodir, None), iconfilename))
+ os.path.join(get_icon_dir(repodir, None), iconfilename))
# Record in known apks, getting the added date at the same time..
added = knownapks.recordapk(thisinfo['apkname'], thisinfo['id'])
def extract_pubkey():
p = FDroidPopen(['keytool', '-exportcert',
- '-alias', config['repo_keyalias'],
- '-keystore', config['keystore'],
- '-storepass:file', config['keystorepassfile']]
+ '-alias', config['repo_keyalias'],
+ '-keystore', config['keystore'],
+ '-storepass:file', config['keystorepassfile']]
+ config['smartcardoptions'])
if p.returncode != 0:
msg = "Failed to get repo pubkey!"
return ("fdroid.app:" + link, app['Name'])
raise MetaDataException("Cannot resolve app id " + link)
addElement('desc',
- metadata.description_html(app['Description'], linkres), doc, apel)
+ metadata.description_html(app['Description'], linkres),
+ doc, apel)
addElement('license', app['License'], doc, apel)
if 'Categories' in app:
addElement('categories', ','.join(app["Categories"]), doc, apel)
for apk in apklist[keepversions:]:
logging.info("Moving " + apk['apkname'] + " to archive")
shutil.move(os.path.join(repodir, apk['apkname']),
- os.path.join(archivedir, apk['apkname']))
+ os.path.join(archivedir, apk['apkname']))
if 'srcname' in apk:
shutil.move(os.path.join(repodir, apk['srcname']),
- os.path.join(archivedir, apk['srcname']))
+ os.path.join(archivedir, apk['srcname']))
archapks.append(apk)
apks.remove(apk)
help="Resize all the icons exceeding the max pixel size and exit")
parser.add_option("-e", "--editor", default="/etc/alternatives/editor",
help="Specify editor to use in interactive mode. Default " +
- "is /etc/alternatives/editor")
+ "is /etc/alternatives/editor")
parser.add_option("-w", "--wiki", default=False, action="store_true",
help="Update the wiki")
parser.add_option("", "--pretty", action="store_true", default=False,
os.mkdir(d)
if subprocess.call(['jar', 'xf',
- os.path.join("..", "..", unsigned_dir, apkfilename)],
- cwd=thisdir) != 0:
+ os.path.join("..", "..", unsigned_dir, apkfilename)],
+ cwd=thisdir) != 0:
raise Exception("Failed to unpack local build of " + apkfilename)
- if subprocess.call(['jar', 'xf', os.path.join("..", "..", remoteapk)],
- cwd=thatdir) != 0:
+ if subprocess.call(['jar', 'xf',
+ os.path.join("..", "..", remoteapk)],
+ cwd=thatdir) != 0:
raise Exception("Failed to unpack remote build of " + apkfilename)
p = FDroidPopen(['diff', '-r', 'this_apk', 'that_apk'], cwd=tmp_dir)