config = None
options = None
+
def get_default_config():
return {
'sdk_path': os.getenv("ANDROID_HOME"),
'keyaliases': {},
}
+
def read_config(opts, config_file='config.py'):
"""Read the repository config
return config
+
def test_sdk_exists(c):
if c['sdk_path'] is None:
# c['sdk_path'] is set to the value of ANDROID_HOME by default
return False
return True
+
def write_password_file(pwtype, password=None):
'''
writes out passwords to a protected file instead of passing passwords as
os.close(fd)
config[pwtype + 'file'] = filename
+
# Given the arguments in the form of multiple appid:[vc] strings, this returns
# a dictionary with the set of vercodes specified for each package.
def read_pkg_args(args, allow_vercodes=False):
return vercodes
+
# On top of what read_pkg_args does, this returns the whole app metadata, but
# limiting the builds list to the builds matching the vercodes specified.
def read_app_args(args, allapps, allow_vercodes=False):
return apps
+
def has_extension(filename, extension):
name, ext = os.path.splitext(filename)
ext = ext.lower()[1:]
apk_regex = None
+
def apknameinfo(filename):
global apk_regex
filename = os.path.basename(filename)
raise Exception("Invalid apk name: %s" % filename)
return result
+
def getapkname(app, build):
return "%s_%s.apk" % (app['id'], build['vercode'])
+
def getsrcname(app, build):
return "%s_%s_src.tar.gz" % (app['id'], build['vercode'])
+
def getappname(app):
if app['Name']:
return app['Name']
return app['Auto Name']
return app['id']
+
def getcvname(app):
return '%s (%s)' % (app['Current Version'], app['Current Version Code'])
+
def getvcs(vcstype, remote, local):
if vcstype == 'git':
return vcs_git(remote, local)
return getsrclib(remote, 'build/srclib', raw=True)
raise VCSException("Invalid vcs type " + vcstype)
+
def getsrclibvcs(name):
srclib_path = os.path.join('srclibs', name + ".txt")
if not os.path.exists(srclib_path):
raise VCSException("Missing srclib " + name)
return metadata.parse_srclib(srclib_path)['Repo Type']
+
class vcs:
def __init__(self, remote, local):
def getsrclib(self):
return self.srclib
+
class vcs_git(vcs):
def repotype(self):
return None
return p.stdout.strip()
+
class vcs_svn(vcs):
def repotype(self):
return line[18:]
return None
+
class vcs_hg(vcs):
def repotype(self):
return [tag.split(' ')[0].strip() for tag in
p.stdout.splitlines()]
+
def retrieve_string(app_dir, string, xmlfiles=None):
res_dirs = [
return string.replace("\\'", "'")
+
# Return list of existing files that will be used to find the highest vercode
def manifest_paths(app_dir, flavour):
return [path for path in possible_manifests if os.path.isfile(path)]
+
# Retrieve the package name. Returns the name, or None if not found.
def fetch_real_name(app_dir, flavour):
app_search = re.compile(r'.*<application.*').search
return result
return None
+
# Retrieve the version name
def version_name(original, app_dir, flavour):
for f in manifest_paths(app_dir, flavour):
return string
return original
+
def get_library_references(root_dir):
libraries = []
proppath = os.path.join(root_dir, 'project.properties')
libraries.append(path)
return libraries
+
def ant_subprojects(root_dir):
subprojects = get_library_references(root_dir)
for subpath in subprojects:
subprojects.insert(0, relp)
return subprojects
+
def remove_debuggable_flags(root_dir):
# Remove forced debuggable flags
logging.info("Removing debuggable flags")
if p.returncode != 0:
raise BuildException("Failed to remove debuggable flags of %s" % path)
+
# Extract some information from the AndroidManifest.xml at the given path.
# Returns (version, vercode, package), any or all of which might be None.
# All values returned are strings.
return (max_version, max_vercode, max_package)
+
class BuildException(Exception):
def __init__(self, value, detail=None):
self.value = value
ret += "\n==== detail begin ====\n%s\n==== detail end ====" % self.detail.strip()
return ret
+
class VCSException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
+
# Get the specified source library.
# Returns the path to it. Normally this is the path to be used when referencing
# it, which may be a subdirectory of the actual project. If you want the base
return (root_dir, srclibpaths)
+
# Split and extend via globbing the paths from a field
def getpaths(build_dir, build, field):
paths = []
paths += [r[len(build_dir)+1:] for r in glob.glob(full_path)]
return paths
+
# Scan the source code in the given directory (and all subdirectories)
# and return the number of fatal problems encountered
def scan_source(build_dir, root_dir, thisbuild):
lst.reverse()
return lst
+
def isApkDebuggable(apkfile, config):
"""Returns True if the given apk file is debuggable
'''Check whether there is no more content to expect.'''
return not self.is_alive() and self._queue.empty()
+
class PopenResult:
returncode = None
stdout = ''
+
def SilentPopen(commands, cwd=None, shell=False):
return FDroidPopen(commands, cwd=cwd, shell=shell, output=False)
+
def FDroidPopen(commands, cwd=None, shell=False, output=True):
"""
Run a command and capture the possibly huge output.
result.returncode = p.returncode
return result
+
def remove_signing_keys(build_dir):
comment = re.compile(r'[ ]*//')
signing_configs = re.compile(r'^[\t ]*signingConfigs[ \t]*{[ \t]*$')
logging.info("Cleaned %s of keysigning configs at %s" % (propfile, path))
+
def replace_config_vars(cmd):
cmd = cmd.replace('$$SDK$$', config['sdk_path'])
cmd = cmd.replace('$$NDK$$', config['ndk_path'])
cmd = cmd.replace('$$MVN3$$', config['mvn3'])
return cmd
+
def place_srclib(root_dir, number, libpath):
if not number:
return
import cgi
import logging
+
class MetaDataException(Exception):
def __init__(self, value):
self.value = value
[])
}
+
# Check an app's metadata information for integrity errors
def check_metadata(info):
for k, t in valuetypes.iteritems():
elif k == 'bool':
build[attr] = False
+
# Formatter for descriptions. Create an instance, and call parseline() with
# each line of the description source from the metadata. At the end, call
# end() and then text_plain, text_wiki and text_html will contain the result.
def end(self):
self.endcur()
+
# Parse multiple lines of description as written in a metadata file, returning
# a single string in plain text format.
def description_plain(lines, linkres):
ps.end()
return ps.text_plain
+
# Parse multiple lines of description as written in a metadata file, returning
# a single string in wiki format. Used for the Maintainer Notes field as well,
# because it's the same format.
ps.end()
return ps.text_wiki
+
# Parse multiple lines of description as written in a metadata file, returning
# a single string in HTML format.
def description_html(lines, linkres):
ps.end()
return ps.text_html
+
def parse_srclib(metafile, **kw):
thisinfo = {}
return thisinfo
+
# Read all metadata. Returns a list of 'app' objects (which are dictionaries as
# returned by the parse_metadata function.
def read_metadata(xref=True, package=None, store=True):
return apps
+
# Get the type expected for a given metadata field.
def metafieldtype(name):
if name in ['Description', 'Maintainer Notes']:
return 'unknown'
return 'string'
+
def flagtype(name):
if name in ['extlibs', 'srclibs', 'patch', 'rm', 'buildjni',
'update', 'scanignore', 'scandelete']:
return 'script'
return 'string'
+
# Parse metadata for a single application.
#
# 'metafile' - the filename to read. The package id for the application comes
return thisinfo
+
# Write a metadata file.
#
# 'dest' - The path to the output file
from common import FDroidPopen
from metadata import MetaDataException
+
def get_densities():
return ['640', '480', '320', '240', '160', '120']
+
def dpi_to_px(density):
return (int(density) * 48) / 160
+
def px_to_dpi(px):
return (int(px) * 160) / 48
+
def get_icon_dir(repodir, density):
if density is None:
return os.path.join(repodir, "icons")
return os.path.join(repodir, "icons-%s" % density)
+
def get_icon_dirs(repodir):
for density in get_densities():
yield get_icon_dir(repodir, density)
yield os.path.join(repodir, "icons")
+
def update_wiki(apps, apks):
"""Update the wiki
# Purge server cache to ensure counts are up to date
site.pages['Repository Maintenance'].purge()
+
def delete_disabled_builds(apps, apkcache, repodirs):
"""Delete disabled build outputs.
if apkfilename in apkcache:
del apkcache[apkfilename]
+
def resize_icon(iconpath, density):
if not os.path.isfile(iconpath):
except Exception, e:
logging.error("Failed resizing {0} - {1}".format(iconpath, e))
+
def resize_all_icons(repodirs):
"""Resize all icons that exceed the max size
for iconpath in glob.glob(icon_glob):
resize_icon(iconpath, density)
+
def scan_apks(apps, apkcache, repodir, knownapks):
"""Scan the apks in the given repo directory.
repo_pubkey_fingerprint = None
+
def make_index(apps, apks, repodir, archive, categories):
"""Make a repo index.
config = None
options = None
+
def main():
global config, options