The repository of older versions of applications from the main demo repository.
"""
+# Normally, all apps are collected into a single app repository, like on
+# https://f-droid.org. For certain situations, it is better to make a repo
+# that is made up of APKs only from a single app. For example, an automated
+# build server that publishes nightly builds.
+# per_app_repos = True
+
# `fdroid update` will create a link to the current version of a given app.
# This provides a static path to the current APK. To disable the creation of
# this link, uncomment this:
'mvn3': "mvn",
'gradle': 'gradle',
'sync_from_local_copy_dir': False,
+ 'per_app_repos': False,
'make_current_version_link': True,
'current_version_name_source': 'Name',
'update_stats': False,
f.write(chunk)
f.flush()
return local_filename
+
+
+def get_per_app_repos():
+ '''per-app repos are dirs named with the packageName of a single app'''
+
+ # Android packageNames are Java packages, they may contain uppercase or
+ # lowercase letters ('A' through 'Z'), numbers, and underscores
+ # ('_'). However, individual package name parts may only start with
+ # letters. https://developer.android.com/guide/topics/manifest/manifest-element.html#package
+ p = re.compile('^([a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)*)?$')
+
+ repos = []
+ for root, dirs, files in os.walk(os.getcwd()):
+ for d in dirs:
+ print 'checking', root, 'for', d
+ if d in ('archive', 'metadata', 'repo', 'srclibs', 'tmp'):
+ # standard parts of an fdroid repo, so never packageNames
+ continue
+ elif p.match(d) \
+ and os.path.exists(os.path.join(d, 'fdroid', 'repo', 'index.jar')):
+ repos.append(d)
+ break
+ return repos
repo_sections.append('archive')
if not os.path.exists('archive'):
os.mkdir('archive')
+ if config['per_app_repos']:
+ repo_sections += common.get_per_app_repos()
if args[0] == 'init':
ssh = paramiko.SSHClient()
apks.remove(apk)
+def add_apks_to_per_app_repos(repodir, apks):
+ apks_per_app = dict()
+ for apk in apks:
+ apk['per_app_dir'] = os.path.join(apk['id'], 'fdroid')
+ apk['per_app_repo'] = os.path.join(apk['per_app_dir'], 'repo')
+ apk['per_app_icons'] = os.path.join(apk['per_app_repo'], 'icons')
+ apks_per_app[apk['id']] = apk
+
+ if not os.path.exists(apk['per_app_icons']):
+ logging.info('Adding new repo for only ' + apk['id'])
+ os.makedirs(apk['per_app_icons'])
+
+ apkpath = os.path.join(repodir, apk['apkname'])
+ shutil.copy(apkpath, apk['per_app_repo'])
+ apksigpath = apkpath + '.sig'
+ if os.path.exists(apksigpath):
+ shutil.copy(apksigpath, apk['per_app_repo'])
+ apkascpath = apkpath + '.asc'
+ if os.path.exists(apkascpath):
+ shutil.copy(apkascpath, apk['per_app_repo'])
+
+
config = None
options = None
# name comes from there!)
sortedids = sorted(apps.iterkeys(), key=lambda appid: apps[appid]['Name'].upper())
+ # APKs are placed into multiple repos based on the app package, providing
+ # per-app subscription feeds for nightly builds and things like it
+ if config['per_app_repos']:
+ add_apks_to_per_app_repos(repodirs[0], apks)
+ for appid, app in apps.iteritems():
+ repodir = os.path.join(appid, 'fdroid', 'repo')
+ appdict = dict()
+ appdict[appid] = app
+ if os.path.isdir(repodir):
+ make_index(appdict, [appid], apks, repodir, False, categories)
+ else:
+ logging.info('Skipping index generation for ' + appid)
+ return
+
if len(repodirs) > 1:
archive_old_apks(apps, apks, archapks, repodirs[0], repodirs[1], config['archive_older'])