EOH
mkdir -p $ANDROID_HOME/licenses/
+
cat << EOF > $ANDROID_HOME/licenses/android-sdk-license
8933bad161af4178b1185d1a37fbf41ea5269c55
+
d56f5187479451eabf01fb78af6dfcb131a6481e
EOF
-echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > $ANDROID_HOME/licenses/android-sdk-preview-license
+
+cat <<EOF > $ANDROID_HOME/licenses/android-sdk-preview-license
+
+84831b9409646a918e30573bab4c9c91346d8abd
+EOF
+
+cat <<EOF > $ANDROID_HOME/licenses/android-sdk-preview-license-old
+79120722343a6f314e0719f863036c702b0e6b2a
+
+84831b9409646a918e30573bab4c9c91346d8abd
+EOF
+
echo y | $ANDROID_HOME/tools/bin/sdkmanager "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.1"
echo y | $ANDROID_HOME/tools/bin/sdkmanager "extras;m2repository;com;android;support;constraint;constraint-layout-solver;1.0.1"
echo y | $ANDROID_HOME/tools/bin/sdkmanager "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2"
__complete_options
}
+__complete_mirror() {
+ opts="-v"
+ lopts="--archive --output-dir"
+ __complete_options
+}
+
__complete_nightly() {
opts="-v -q"
lopts="--show-secret-var"
init \
install \
lint \
+mirror \
nightly \
publish \
readmeta \
# sync_from_local_copy_dir = True
-# To upload the repo to an Amazon S3 bucket using `fdroid server update`.
-# Warning, this deletes and recreates the whole fdroid/ directory each
-# time. This is based on apache-libcloud, which supports basically all cloud
-# storage services, so it should be easy to port the fdroid server tools to
-# any of them.
+# To upload the repo to an Amazon S3 bucket using `fdroid server
+# update`. Warning, this deletes and recreates the whole fdroid/
+# directory each time. This prefers s3cmd, but can also use
+# apache-libcloud. To customize how s3cmd interacts with the cloud
+# provider, create a 's3cfg' file next to this file (config.py), and
+# those settings will be used instead of any 'aws' variable below.
#
# awsbucket = 'myawsfdroid'
# awsaccesskeyid = 'SEE0CHAITHEIMAUR2USA'
("btlog", _("Update the binary transparency log for a URL")),
("signatures", _("Extract signatures from APKs")),
("nightly", _("Set up an app build for a nightly build repo")),
+ ("mirror", _("Download complete mirrors of small repos")),
])
import glob
import subprocess
import re
+import resource
import tarfile
import traceback
import time
# Read all app and srclib metadata
pkgs = common.read_pkg_args(options.appid, True)
- allapps = metadata.read_metadata(not options.onserver, pkgs)
+ allapps = metadata.read_metadata(not options.onserver, pkgs, sort_by_time=True)
apps = common.read_app_args(options.appid, allapps, True)
for appid, app in list(apps.items()):
if not apps:
raise FDroidException("No apps to process.")
+ # make sure enough open files are allowed to process everything
+ soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
+ if len(apps) > soft:
+ try:
+ soft = len(apps) * 2
+ if soft > hard:
+ soft = hard
+ resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard))
+ logging.debug(_('Set open file limit to {integer}')
+ .format(integer=soft))
+ except (OSError, ValueError) as e:
+ logging.warning(_('Setting open file limit failed: ') + str(e))
+
if options.latest:
for app in apps.values():
for build in reversed(app.builds):
logging.info(ngettext("{} build failed",
"{} builds failed", len(failed_apps)).format(len(failed_apps)))
- sys.exit(0)
+ # hack to ensure this exits, even is some threads are still running
+ sys.stdout.flush()
+ sys.stderr.flush()
+ os._exit(0)
if __name__ == "__main__":
import xml.etree.ElementTree as XMLElementTree
from binascii import hexlify
-from datetime import datetime
+from datetime import datetime, timedelta
from distutils.version import LooseVersion
from queue import Queue
from zipfile import ZipFile
return glob.glob('.fdroid.[a-jl-z]*[a-rt-z]')
-def read_pkg_args(args, allow_vercodes=False):
+def read_pkg_args(appid_versionCode_pairs, allow_vercodes=False):
"""
- :param args: arguments in the form of multiple appid:[vc] strings
+ :param appids: arguments in the form of multiple appid:[vc] strings
:returns: a dictionary with the set of vercodes specified for each package
"""
-
vercodes = {}
- if not args:
+ if not appid_versionCode_pairs:
return vercodes
- for p in args:
+ for p in appid_versionCode_pairs:
if allow_vercodes and ':' in p:
package, vercode = p.split(':')
else:
return vercodes
-def read_app_args(args, allapps, allow_vercodes=False):
- """
- 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(appid_versionCode_pairs, allapps, allow_vercodes=False):
+ """Build a list of App instances for processing
+
+ On top of what read_pkg_args does, this returns the whole app
+ metadata, but limiting the builds list to the builds matching the
+ appid_versionCode_pairs and vercodes specified. If no appid_versionCode_pairs are specified, then
+ all App and Build instances are returned.
+
"""
- vercodes = read_pkg_args(args, allow_vercodes)
+ vercodes = read_pkg_args(appid_versionCode_pairs, allow_vercodes)
if not vercodes:
return allapps
vercode = None
package = None
+ flavour = ""
+ if app.builds and 'gradle' in app.builds[-1] and app.builds[-1].gradle:
+ flavour = app.builds[-1].gradle[-1]
+
if has_extension(path, 'gradle'):
+ # first try to get version name and code from correct flavour
with open(path, 'r') as f:
- for line in f:
- if gradle_comment.match(line):
- continue
- # Grab first occurence of each to avoid running into
- # alternative flavours and builds.
- if not package:
- matches = psearch_g(line)
- if matches:
- s = matches.group(2)
- if app_matches_packagename(app, s):
- package = s
- if not version:
- matches = vnsearch_g(line)
- if matches:
- version = matches.group(2)
- if not vercode:
- matches = vcsearch_g(line)
- if matches:
- vercode = matches.group(1)
+ buildfile = f.read()
+
+ regex_string = r"" + flavour + ".*?}"
+ search = re.compile(regex_string, re.DOTALL)
+ result = search.search(buildfile)
+
+ if result is not None:
+ resultgroup = result.group()
+
+ if not package:
+ matches = psearch_g(resultgroup)
+ if matches:
+ s = matches.group(2)
+ if app_matches_packagename(app, s):
+ package = s
+ if not version:
+ matches = vnsearch_g(resultgroup)
+ if matches:
+ version = matches.group(2)
+ if not vercode:
+ matches = vcsearch_g(resultgroup)
+ if matches:
+ vercode = matches.group(1)
+ else:
+ # fall back to parse file line by line
+ with open(path, 'r') as f:
+ for line in f:
+ if gradle_comment.match(line):
+ continue
+ # Grab first occurence of each to avoid running into
+ # alternative flavours and builds.
+ if not package:
+ matches = psearch_g(line)
+ if matches:
+ s = matches.group(2)
+ if app_matches_packagename(app, s):
+ package = s
+ if not version:
+ matches = vnsearch_g(line)
+ if matches:
+ version = matches.group(2)
+ if not vercode:
+ matches = vcsearch_g(line)
+ if matches:
+ vercode = matches.group(1)
else:
try:
xml = parse_xml(path)
return [int(sp) if sp.isdigit() else sp for sp in re.split(r'(\d+)', s)]
+def check_system_clock(dt_obj, path):
+ """Check if system clock is updated based on provided date
+
+ If an APK has files newer than the system time, suggest updating
+ the system clock. This is useful for offline systems, used for
+ signing, which do not have another source of clock sync info. It
+ has to be more than 24 hours newer because ZIP/APK files do not
+ store timezone info
+
+ """
+ checkdt = dt_obj - timedelta(1)
+ if datetime.today() < checkdt:
+ logging.warning(_('System clock is older than date in {path}!').format(path=path)
+ + '\n' + _('Set clock to that time using:') + '\n'
+ + 'sudo date -s "' + str(dt_obj) + '"')
+
+
class KnownApks:
"""permanent store of existing APKs with the date they were added
date = datetime.strptime(t[-1], '%Y-%m-%d')
filename = line[0:line.rfind(appid) - 1]
self.apks[filename] = (appid, date)
+ check_system_clock(date, self.path)
self.changed = False
def writeifchanged(self):
raise BuildException("OSError while trying to execute " +
' '.join(commands) + ': ' + str(e))
+ # TODO are these AsynchronousFileReader threads always exiting?
if not stderr_to_stdout and options.verbose:
stderr_queue = Queue()
stderr_reader = AsynchronousFileReader(p.stderr, stderr_queue)
+ '" does not exist, creating a new keystore there.')
common.write_to_config(test_config, 'keystore', keystore)
repo_keyalias = None
+ keydname = None
if options.repo_keyalias:
repo_keyalias = options.repo_keyalias
common.write_to_config(test_config, 'repo_keyalias', repo_keyalias)
flags=re.MULTILINE)
with open('opensc-fdroid.cfg', 'w') as f:
f.write(opensc_fdroid)
- elif not os.path.exists(keystore):
+ elif os.path.exists(keystore):
+ to_set = ['keystorepass', 'keypass', 'repo_keyalias', 'keydname']
+ if repo_keyalias:
+ to_set.remove('repo_keyalias')
+ if keydname:
+ to_set.remove('keydname')
+ logging.warning('\n' + _('Using existing keystore "{path}"').format(path=keystore)
+ + '\n' + _('Now set these in config.py:') + ' '
+ + ', '.join(to_set) + '\n')
+ else:
password = common.genpassword()
c = dict(test_config)
c['keystorepass'] = password
import textwrap
import io
import yaml
+from collections import OrderedDict
# use libyaml if it is available
try:
from yaml import CLoader
srclibs[srclibname] = parse_srclib(metadatapath)
-def read_metadata(xref=True, check_vcs=[]):
- """
- Read all metadata. Returns a list of 'app' objects (which are dictionaries as
- returned by the parse_txt_metadata function.
+def read_metadata(xref=True, check_vcs=[], sort_by_time=False):
+ """Return a list of App instances sorted newest first
+
+ This reads all of the metadata files in a 'data' repository, then
+ builds a list of App instances from those files. The list is
+ sorted based on creation time, newest first. Most of the time,
+ the newer files are the most interesting.
+
+ If there are multiple metadata files for a single appid, then the first
+ file that is parsed wins over all the others, and the rest throw an
+ exception. So the original .txt format is parsed first, at least until
+ newer formats stabilize.
check_vcs is the list of packageNames to check for .fdroid.yml in source
+
"""
# Always read the srclibs before the apps, since they can use a srlib as
# their source repository.
read_srclibs()
- apps = {}
+ apps = OrderedDict()
for basedir in ('metadata', 'tmp'):
if not os.path.exists(basedir):
os.makedirs(basedir)
- # If there are multiple metadata files for a single appid, then the first
- # file that is parsed wins over all the others, and the rest throw an
- # exception. So the original .txt format is parsed first, at least until
- # newer formats stabilize.
-
- for metadatapath in sorted(glob.glob(os.path.join('metadata', '*.txt'))
- + glob.glob(os.path.join('metadata', '*.json'))
- + glob.glob(os.path.join('metadata', '*.yml'))
- + glob.glob('.fdroid.txt')
- + glob.glob('.fdroid.json')
- + glob.glob('.fdroid.yml')):
+ metadatafiles = (glob.glob(os.path.join('metadata', '*.txt'))
+ + glob.glob(os.path.join('metadata', '*.json'))
+ + glob.glob(os.path.join('metadata', '*.yml'))
+ + glob.glob('.fdroid.txt')
+ + glob.glob('.fdroid.json')
+ + glob.glob('.fdroid.yml'))
+
+ if sort_by_time:
+ entries = ((os.stat(path).st_mtime, path) for path in metadatafiles)
+ metadatafiles = []
+ for _ignored, path in sorted(entries, reverse=True):
+ metadatafiles.append(path)
+ else:
+ # most things want the index alpha sorted for stability
+ metadatafiles = sorted(metadatafiles)
+
+ for metadatapath in metadatafiles:
packageName, _ignored = fdroidserver.common.get_extension(os.path.basename(metadatapath))
if packageName in apps:
warn_or_exception(_("Found multiple metadata files for {appid}")
--- /dev/null
+#!/usr/bin/env python3
+
+import ipaddress
+import logging
+import os
+import posixpath
+import socket
+import subprocess
+import sys
+from argparse import ArgumentParser
+import urllib.parse
+
+from . import _
+from . import common
+from . import index
+from . import update
+
+options = None
+
+
+def _run_wget(path, urls):
+ if options.verbose:
+ verbose = '--verbose'
+ else:
+ verbose = '--no-verbose'
+
+ if not urls:
+ return
+ logging.debug(_('Running wget in {path}').format(path=path))
+ os.makedirs(path, exist_ok=True)
+ os.chdir(path)
+ urls_file = '.fdroid-mirror-wget-input-file'
+ with open(urls_file, 'w') as fp:
+ for url in urls:
+ fp.write(url.split('?')[0] + '\n') # wget puts query string in the filename
+ subprocess.call(['wget', verbose, '--continue', '--user-agent="fdroid mirror"',
+ '--input-file=' + urls_file])
+ os.remove(urls_file)
+
+
+def main():
+ global options
+
+ parser = ArgumentParser(usage=_("%(prog)s [options] url"))
+ common.setup_global_opts(parser)
+ parser.add_argument("url", nargs='?',
+ help=_('Base URL to mirror, can include the index signing key '
+ + 'using the query string: ?fingerprint='))
+ parser.add_argument("--archive", action='store_true', default=False,
+ help=_("Also mirror the full archive section"))
+ parser.add_argument("--output-dir", default=None,
+ help=_("The directory to write the mirror to"))
+ options = parser.parse_args()
+
+ if options.url is None:
+ logging.error(_('A URL is required as an argument!') + '\n')
+ parser.print_help()
+ sys.exit(1)
+
+ scheme, hostname, path, params, query, fragment = urllib.parse.urlparse(options.url)
+ fingerprint = urllib.parse.parse_qs(query).get('fingerprint')
+
+ def _append_to_url_path(*args):
+ '''Append the list of path components to URL, keeping the rest the same'''
+ newpath = posixpath.join(path, *args)
+ return urllib.parse.urlunparse((scheme, hostname, newpath, params, query, fragment))
+
+ if fingerprint:
+ config = common.read_config(options)
+ if not ('jarsigner' in config or 'apksigner' in config):
+ logging.error(_('Java JDK not found! Install in standard location or set java_paths!'))
+ sys.exit(1)
+
+ def _get_index(section, etag=None):
+ url = _append_to_url_path(section)
+ return index.download_repo_index(url, etag=etag)
+ else:
+ def _get_index(section, etag=None):
+ import io
+ import json
+ import zipfile
+ from . import net
+ url = _append_to_url_path(section, 'index-v1.jar')
+ content, etag = net.http_get(url)
+ with zipfile.ZipFile(io.BytesIO(content)) as zip:
+ jsoncontents = zip.open('index-v1.json').read()
+ data = json.loads(jsoncontents.decode('utf-8'))
+ return data, etag
+
+ ip = None
+ try:
+ ip = ipaddress.ip_address(hostname)
+ except ValueError:
+ pass
+ if hostname == 'f-droid.org' \
+ or (ip is not None and hostname in socket.gethostbyname_ex('f-droid.org')[2]):
+ print(_('ERROR: this command should never be used to mirror f-droid.org!\n'
+ 'A full mirror of f-droid.org requires more than 200GB.'))
+ sys.exit(1)
+
+ path = path.rstrip('/')
+ if path.endswith('repo') or path.endswith('archive'):
+ logging.warning(_('Do not include "{path}" in URL!')
+ .format(path=path.split('/')[-1]))
+ elif not path.endswith('fdroid'):
+ logging.warning(_('{url} does not end with "fdroid", check the URL path!')
+ .format(url=options.url))
+
+ icondirs = ['icons', ]
+ for density in update.screen_densities:
+ icondirs.append('icons-' + density)
+
+ if options.output_dir:
+ basedir = options.output_dir
+ else:
+ basedir = os.path.join(os.getcwd(), hostname, path.strip('/'))
+ os.makedirs(basedir, exist_ok=True)
+
+ if options.archive:
+ sections = ('repo', 'archive')
+ else:
+ sections = ('repo', )
+
+ for section in sections:
+ sectiondir = os.path.join(basedir, section)
+
+ data, etag = _get_index(section)
+
+ os.makedirs(sectiondir, exist_ok=True)
+ os.chdir(sectiondir)
+ for icondir in icondirs:
+ os.makedirs(os.path.join(sectiondir, icondir), exist_ok=True)
+
+ urls = []
+ for packageName, packageList in data['packages'].items():
+ for package in packageList:
+ to_fetch = []
+ for k in ('apkName', 'srcname'):
+ if k in package:
+ to_fetch.append(package[k])
+ elif k == 'apkName':
+ logging.error(_('{appid} is missing {name}')
+ .format(appid=package['packageName'], name=k))
+ for f in to_fetch:
+ if not os.path.exists(f) \
+ or (f.endswith('.apk') and os.path.getsize(f) != package['size']):
+ urls.append(_append_to_url_path(section, f))
+ urls.append(_append_to_url_path(section, f + '.asc'))
+ _run_wget(sectiondir, urls)
+
+ for app in data['apps']:
+ localized = app.get('localized')
+ if localized:
+ for locale, d in localized.items():
+ urls = []
+ components = (section, app['packageName'], locale)
+ for k in update.GRAPHIC_NAMES:
+ f = d.get(k)
+ if f:
+ filepath_tuple = components + (f, )
+ urls.append(_append_to_url_path(*filepath_tuple))
+ _run_wget(os.path.join(basedir, *components), urls)
+ for k in update.SCREENSHOT_DIRS:
+ urls = []
+ filelist = d.get(k)
+ if filelist:
+ components = (section, app['packageName'], locale, k)
+ for f in filelist:
+ filepath_tuple = components + (f, )
+ urls.append(_append_to_url_path(*filepath_tuple))
+ _run_wget(os.path.join(basedir, *components), urls)
+
+ urls = dict()
+ for app in data['apps']:
+ if 'icon' not in app:
+ logging.error(_('no "icon" in {appid}').format(appid=app['packageName']))
+ continue
+ icon = app['icon']
+ for icondir in icondirs:
+ url = _append_to_url_path(section, icondir, icon)
+ if icondir not in urls:
+ urls[icondir] = []
+ urls[icondir].append(url)
+
+ for icondir in icondirs:
+ _run_wget(os.path.join(basedir, section, icondir), urls[icondir])
+
+
+if __name__ == "__main__":
+ main()
repo_url = repo_base + '/repo'
git_mirror_path = os.path.join(repo_basedir, 'git-mirror')
git_mirror_repodir = os.path.join(git_mirror_path, 'fdroid', 'repo')
+ git_mirror_metadatadir = os.path.join(git_mirror_path, 'fdroid', 'metadata')
if not os.path.isdir(git_mirror_repodir):
logging.debug(_('cloning {url}').format(url=clone_url))
try:
mirror_git_repo.git.add(all=True)
mirror_git_repo.index.commit("update README")
- icon_path = os.path.join(repo_basedir, 'icon.png')
+ icon_path = os.path.join(git_mirror_path, 'icon.png')
try:
import qrcode
- img = qrcode.make('Some data here')
+ img = qrcode.make(repo_url)
with open(icon_path, 'wb') as fp:
fp.write(img)
except Exception:
shutil.copy(exampleicon, icon_path)
mirror_git_repo.git.add(all=True)
mirror_git_repo.index.commit("update repo/website icon")
+ shutil.copy(icon_path, repo_basedir)
os.chdir(repo_basedir)
- common.local_rsync(options, git_mirror_repodir + '/', 'repo/')
+ if os.path.isdir(git_mirror_repodir):
+ common.local_rsync(options, git_mirror_repodir + '/', 'repo/')
+ if os.path.isdir(git_mirror_metadatadir):
+ common.local_rsync(options, git_mirror_metadatadir + '/', 'metadata/')
ssh_private_key_file = _ssh_key_from_debug_keystore()
# this is needed for GitPython to find the SSH key
except subprocess.CalledProcessError:
pass
- subprocess.check_call(['fdroid', 'update', '--rename-apks', '--verbose'], cwd=repo_basedir)
+ subprocess.check_call(['fdroid', 'update', '--rename-apks', '--create-metadata', '--verbose'],
+ cwd=repo_basedir)
+ common.local_rsync(options, repo_basedir + '/metadata/', git_mirror_metadatadir + '/')
+ mirror_git_repo.git.add(all=True)
+ mirror_git_repo.index.commit("update app metadata")
try:
subprocess.check_call(['fdroid', 'server', 'update', '--verbose'], cwd=repo_basedir)
except subprocess.CalledProcessError:
BINARY_TRANSPARENCY_DIR = 'binary_transparency'
+AUTO_S3CFG = '.fdroid-server-update-s3cfg'
+USER_S3CFG = 's3cfg'
+
def update_awsbucket(repo_section):
'''
logging.debug(_('Using s3cmd to sync with: {url}')
.format(url=config['awsbucket']))
- configfilename = '.s3cfg'
- fd = os.open(configfilename, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600)
- os.write(fd, '[default]\n'.encode('utf-8'))
- os.write(fd, ('access_key = ' + config['awsaccesskeyid'] + '\n').encode('utf-8'))
- os.write(fd, ('secret_key = ' + config['awssecretkey'] + '\n').encode('utf-8'))
- os.close(fd)
+ if os.path.exists(USER_S3CFG):
+ logging.info(_('Using "{path}" for configuring s3cmd.').format(path=USER_S3CFG))
+ configfilename = USER_S3CFG
+ else:
+ fd = os.open(AUTO_S3CFG, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600)
+ logging.debug(_('Creating "{path}" for configuring s3cmd.').format(path=AUTO_S3CFG))
+ os.write(fd, '[default]\n'.encode('utf-8'))
+ os.write(fd, ('access_key = ' + config['awsaccesskeyid'] + '\n').encode('utf-8'))
+ os.write(fd, ('secret_key = ' + config['awssecretkey'] + '\n').encode('utf-8'))
+ os.close(fd)
+ configfilename = AUTO_S3CFG
s3bucketurl = 's3://' + config['awsbucket']
s3cmd = [config['s3cmd'], '--config=' + configfilename]
_('To use awsbucket, awssecretkey and awsaccesskeyid must also be set in config.py!'))
awsbucket = config['awsbucket']
+ if os.path.exists(USER_S3CFG):
+ raise FDroidException(_('"{path}" exists but s3cmd is not installed!')
+ .format(path=USER_S3CFG))
+
cls = get_driver(Provider.S3)
driver = cls(config['awsaccesskeyid'], config['awssecretkey'])
try:
with open(outputfilename, 'w') as fp:
json.dump(response, fp, indent=2, sort_keys=True)
- if response.get('positives') > 0:
+ if response.get('positives', 0) > 0:
logging.warning(repofilename + ' has been flagged by virustotal '
+ str(response['positives']) + ' times:'
+ '\n\t' + response['permalink'])
import hashlib
import pickle
import time
-from datetime import datetime, timedelta
+from datetime import datetime
from argparse import ArgumentParser
import collections
"""
- sourcedirs = glob.glob(os.path.join('build', '[A-Za-z]*', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'))
+ sourcedirs = glob.glob(os.path.join('build', '[A-Za-z]*', 'src', '[A-Za-z]*', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'))
+ sourcedirs += glob.glob(os.path.join('build', '[A-Za-z]*', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'))
sourcedirs += glob.glob(os.path.join('build', '[A-Za-z]*', 'metadata', '[a-z][a-z]*'))
sourcedirs += glob.glob(os.path.join('metadata', '[A-Za-z]*', '[a-z][a-z]*'))
continue
locale = segments[-1]
destdir = os.path.join('repo', packageName, locale)
+
+ # flavours specified in build receipt
+ build_flavours = ""
+ if apps[packageName] and 'builds' in apps[packageName] and len(apps[packageName].builds) > 0\
+ and 'gradle' in apps[packageName].builds[-1]:
+ build_flavours = apps[packageName].builds[-1].gradle
+
+ if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavours:
+ logging.debug("ignoring due to wrong flavour")
+ continue
+
for f in files:
if f in ('description.txt', 'full_description.txt'):
_set_localized_text_entry(apps[packageName], locale, 'description',
apkzip = zipfile.ZipFile(apkfile, 'r')
- # if an APK has files newer than the system time, suggest updating
- # the system clock. This is useful for offline systems, used for
- # signing, which do not have another source of clock sync info. It
- # has to be more than 24 hours newer because ZIP/APK files do not
- # store timezone info
manifest = apkzip.getinfo('AndroidManifest.xml')
if manifest.date_time[1] == 0: # month can't be zero
logging.debug(_('AndroidManifest.xml has no date'))
else:
- dt_obj = datetime(*manifest.date_time)
- checkdt = dt_obj - timedelta(1)
- if datetime.today() < checkdt:
- logging.warning('System clock is older than manifest in: '
- + apkfilename
- + '\nSet clock to that time using:\n'
- + 'sudo date -s "' + str(dt_obj) + '"')
+ common.check_system_clock(datetime(*manifest.date_time), apkfilename)
# extract icons from APK zip file
iconfilename = "%s.%s.png" % (apk['packageName'], apk['versionCode'])
import math
import json
import tarfile
-import time
import shutil
import subprocess
import textwrap
from .common import FDroidException
from logging import getLogger
+from fdroidserver import _
+
logger = getLogger('fdroidserver-vmtools')
def up(self, provision=True):
try:
self.vgrnt.up(provision=provision)
- logger.info('...waiting a sec...')
- time.sleep(10)
self.srvuuid = self._vagrant_fetch_uuid()
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not bring up vm '%s'" % self.srvname) from e
logger.info('suspending buildserver')
try:
self.vgrnt.suspend()
- logger.info('...waiting a sec...')
- time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not suspend vm '%s'" % self.srvname) from e
# (eg. lookupByName only works on running VMs)
try:
_check_call(('virsh', '-c', 'qemu:///system', 'destroy', self.srvname))
- logger.info("...waiting a sec...")
- time.sleep(10)
except subprocess.CalledProcessError as e:
logger.info("could not force libvirt domain '%s' off: %s", self.srvname, e)
try:
# libvirt python bindings do not support all flags required
# for undefining domains correctly.
_check_call(('virsh', '-c', 'qemu:///system', 'undefine', self.srvname, '--nvram', '--managed-save', '--remove-all-storage', '--snapshots-metadata'))
- logger.info("...waiting a sec...")
- time.sleep(10)
except subprocess.CalledProcessError as e:
logger.info("could not undefine libvirt domain '%s': %s", self.srvname, e)
vol = storagePool.storageVolLookupByName(self.srvname + '.img')
imagepath = vol.path()
# TODO use a libvirt storage pool to ensure the img file is readable
- _check_call(['sudo', '/bin/chmod', '-R', 'a+rX', '/var/lib/libvirt/images'])
+ if not os.access(imagepath, os.R_OK):
+ logger.warning(_('Cannot read "{path}"!').format(path=imagepath))
+ _check_call(['sudo', '/bin/chmod', '-R', 'a+rX', '/var/lib/libvirt/images'])
shutil.copy2(imagepath, 'box.img')
_check_call(['qemu-img', 'rebase', '-p', '-b', '', 'box.img'])
img_info_raw = _check_output(['qemu-img', 'info', '--output=json', 'box.img'])
logger.info("creating snapshot '%s' for vm '%s'", snapshot_name, self.srvname)
try:
_check_call(['virsh', '-c', 'qemu:///system', 'snapshot-create-as', self.srvname, snapshot_name])
- logger.info('...waiting a sec...')
- time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not cerate snapshot '%s' "
"of libvirt vm '%s'"
dom = self.conn.lookupByName(self.srvname)
snap = dom.snapshotLookupByName(snapshot_name)
dom.revertToSnapshot(snap)
- logger.info('...waiting a sec...')
- time.sleep(10)
except libvirt.libvirtError as e:
raise FDroidBuildVmException('could not revert domain \'%s\' to snapshot \'%s\''
% (self.srvname, snapshot_name)) from e
logger.info("creating snapshot '%s' for vm '%s'", snapshot_name, self.srvname)
try:
_check_call(['VBoxManage', 'snapshot', self.srvuuid, 'take', 'fdroidclean'], cwd=self.srvdir)
- logger.info('...waiting a sec...')
- time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException('could not cerate snapshot '
'of virtualbox vm %s'
echo "No virtualization is used."
fi
sudo /bin/chmod -R a+rX /var/lib/libvirt/images
-ulimit -n 2048
echo 'maximum allowed number of open file descriptors: ' `ulimit -n`
ls -ld /var/lib/libvirt/images
ls -l /var/lib/libvirt/images || echo no access
'pyasn1-modules',
'python-vagrant',
'PyYAML',
+ 'qrcode',
'ruamel.yaml >= 0.13',
'requests >= 2.5.2, != 2.11.0, != 2.12.2, != 2.18.0',
'docker-py >= 1.9, < 2.0',
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
import inspect
+import logging
import optparse
import os
import re
self.assertTrue(os.path.exists(path))
self.assertTrue(os.path.isfile(path))
+ def setUp(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self.basedir = os.path.join(localmodule, 'tests')
+ self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ os.chdir(self.basedir)
+
def test_force_gradle_build_tools(self):
- testsbase = os.path.join(os.path.dirname(__file__), '..', '.testfiles')
- if not os.path.exists(testsbase):
- os.makedirs(testsbase)
- testsdir = tempfile.mkdtemp(prefix='test_adapt_gradle', dir=testsbase)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
shutil.copytree(os.path.join(os.path.dirname(__file__), 'source-files'),
- os.path.join(testsdir, 'source-files'))
+ os.path.join(testdir, 'source-files'))
teststring = 'FAKE_VERSION_FOR_TESTING'
- fdroidserver.build.force_gradle_build_tools(testsdir, teststring)
+ fdroidserver.build.force_gradle_build_tools(testdir, teststring)
pattern = re.compile(bytes("buildToolsVersion[\s=]+'%s'\s+" % teststring, 'utf8'))
for p in ('source-files/fdroid/fdroidclient/build.gradle',
'source-files/Zillode/syncthing-silk/build.gradle',
'source-files/open-keychain/open-keychain/build.gradle',
'source-files/osmandapp/osmand/build.gradle',
'source-files/open-keychain/open-keychain/OpenKeychain/build.gradle'):
- with open(os.path.join(testsdir, p), 'rb') as f:
+ with open(os.path.join(testdir, p), 'rb') as f:
filedata = f.read()
self.assertIsNotNone(pattern.search(filedata))
print('no build-tools found: ' + build_tools)
def test_find_java_root_path(self):
- tmptestsdir = tempfile.mkdtemp(prefix='test_find_java_root_path', dir=self.tmpdir)
- os.chdir(tmptestsdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
+ os.chdir(testdir)
all_pathlists = [
([ # Debian
testint = 99999999
teststr = 'FAKE_STR_FOR_TESTING'
- tmptestsdir = tempfile.mkdtemp(prefix='test_prepare_sources', dir=self.tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
shutil.copytree(os.path.join(self.basedir, 'source-files'),
- os.path.join(tmptestsdir, 'source-files'))
+ os.path.join(testdir, 'source-files'))
- testdir = os.path.join(tmptestsdir, 'source-files', 'fdroid', 'fdroidclient')
+ fdroidclient_testdir = os.path.join(testdir, 'source-files', 'fdroid', 'fdroidclient')
config = dict()
config['sdk_path'] = os.getenv('ANDROID_HOME')
def getsrclib(self):
return None
- fdroidserver.common.prepare_source(FakeVcs(), app, build, testdir, testdir, testdir)
+ fdroidserver.common.prepare_source(FakeVcs(), app, build,
+ fdroidclient_testdir, fdroidclient_testdir, fdroidclient_testdir)
- with open(os.path.join(testdir, 'build.gradle'), 'r') as f:
+ with open(os.path.join(fdroidclient_testdir, 'build.gradle'), 'r') as f:
filedata = f.read()
self.assertIsNotNone(re.search("\s+compileSdkVersion %s\s+" % testint, filedata))
- with open(os.path.join(testdir, 'AndroidManifest.xml')) as f:
+ with open(os.path.join(fdroidclient_testdir, 'AndroidManifest.xml')) as f:
filedata = f.read()
self.assertIsNone(re.search('android:debuggable', filedata))
self.assertIsNotNone(re.search('android:versionName="%s"' % build.versionName, filedata))
def test_prepare_sources_refresh(self):
packageName = 'org.fdroid.ci.test.app'
- testdir = tempfile.mkdtemp(prefix='test_prepare_sources_refresh', dir=self.tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
print('testdir', testdir)
os.chdir(testdir)
os.mkdir('build')
fdroidserver.signindex.config = config
sourcedir = os.path.join(self.basedir, 'signindex')
- testsdir = tempfile.mkdtemp(prefix='test_signjar', dir=self.tmpdir)
+ testsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
for f in ('testy.jar', 'guardianproject.jar',):
sourcefile = os.path.join(sourcedir, f)
testfile = os.path.join(testsdir, f)
sourceapk = os.path.join(self.basedir, 'urzip.apk')
- testdir = tempfile.mkdtemp(prefix='test_verify_apks', dir=self.tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
print('testdir', testdir)
copyapk = os.path.join(testdir, 'urzip-copy.apk')
sig = fdroidserver.common.metadata_find_developer_signature('org.smssecure.smssecure')
self.assertEqual('b30bb971af0d134866e158ec748fcd553df97c150f58b0a963190bbafbeb0868', sig)
+ def test_parse_androidmanifests(self):
+ source_files_dir = os.path.join(os.path.dirname(__file__), 'source-files')
+ app = fdroidserver.metadata.App()
+ app.id = 'org.fdroid.fdroid'
+ paths = [
+ os.path.join(source_files_dir, 'fdroid', 'fdroidclient', 'AndroidManifest.xml'),
+ os.path.join(source_files_dir, 'fdroid', 'fdroidclient', 'build.gradle'),
+ ]
+ for path in paths:
+ self.assertTrue(os.path.isfile(path))
+ self.assertEqual(('0.94-test', '940', 'org.fdroid.fdroid'),
+ fdroidserver.common.parse_androidmanifests(paths, app))
+
+ def test_parse_androidmanifests_with_flavor(self):
+ source_files_dir = os.path.join(os.path.dirname(__file__), 'source-files')
+ app = fdroidserver.metadata.App()
+ build = fdroidserver.metadata.Build()
+ build.gradle = ['devVersion']
+ app.builds = [build]
+ app.id = 'org.fdroid.fdroid.dev'
+ paths = [
+ os.path.join(source_files_dir, 'fdroid', 'fdroidclient', 'AndroidManifest.xml'),
+ os.path.join(source_files_dir, 'fdroid', 'fdroidclient', 'build.gradle'),
+ ]
+ for path in paths:
+ self.assertTrue(os.path.isfile(path))
+ self.assertEqual(('0.95-dev', '949', 'org.fdroid.fdroid.dev'),
+ fdroidserver.common.parse_androidmanifests(paths, app))
+
if __name__ == "__main__":
parser = optparse.OptionParser()
newSuite = unittest.TestSuite()
newSuite.addTest(unittest.makeSuite(CommonTest))
- unittest.main(failfast=True)
+ unittest.main(failfast=False)
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
import inspect
+import logging
import optparse
import os
import requests
class ImportTest(unittest.TestCase):
'''fdroid import'''
+ def setUp(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self.basedir = os.path.join(localmodule, 'tests')
+ self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ os.chdir(self.basedir)
+
def test_import_gitlab(self):
- os.chdir(os.path.dirname(__file__))
# FDroidPopen needs some config to work
config = dict()
fdroidserver.common.fill_config_defaults(config)
#!/usr/bin/env python3
import inspect
+import logging
import optparse
import os
import sys
class IndexTest(unittest.TestCase):
def setUp(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self.basedir = os.path.join(localmodule, 'tests')
+ self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ os.chdir(self.basedir)
+
fdroidserver.common.config = None
config = fdroidserver.common.read_config(fdroidserver.common.options)
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
fdroidserver.common.config = config
fdroidserver.signindex.config = config
- @staticmethod
- def test_verify_jar_signature_succeeds():
- basedir = os.path.dirname(__file__)
- source_dir = os.path.join(basedir, 'signindex')
+ def test_verify_jar_signature_succeeds(self):
+ source_dir = os.path.join(self.basedir, 'signindex')
for f in ('testy.jar', 'guardianproject.jar'):
testfile = os.path.join(source_dir, f)
fdroidserver.common.verify_jar_signature(testfile)
def test_verify_jar_signature_fails(self):
- basedir = os.path.dirname(__file__)
- source_dir = os.path.join(basedir, 'signindex')
+ source_dir = os.path.join(self.basedir, 'signindex')
testfile = os.path.join(source_dir, 'unsigned.jar')
with self.assertRaises(fdroidserver.index.VerificationException):
fdroidserver.common.verify_jar_signature(testfile)
def test_get_public_key_from_jar_succeeds(self):
- basedir = os.path.dirname(__file__)
- source_dir = os.path.join(basedir, 'signindex')
+ source_dir = os.path.join(self.basedir, 'signindex')
for f in ('testy.jar', 'guardianproject.jar'):
testfile = os.path.join(source_dir, f)
jar = zipfile.ZipFile(testfile)
self.assertTrue(fingerprint == GP_FINGERPRINT)
def test_get_public_key_from_jar_fails(self):
- basedir = os.path.dirname(__file__)
- source_dir = os.path.join(basedir, 'signindex')
+ source_dir = os.path.join(self.basedir, 'signindex')
testfile = os.path.join(source_dir, 'unsigned.jar')
jar = zipfile.ZipFile(testfile)
with self.assertRaises(fdroidserver.index.VerificationException):
if __name__ == "__main__":
- if os.path.basename(os.getcwd()) != 'tests' and os.path.isdir('tests'):
- os.chdir('tests')
-
parser = optparse.OptionParser()
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="Spew out even more information than normal")
self.assertTrue(fdroidserver.lint.check_for_unsupported_metadata_files())
tmpdir = os.path.join(localmodule, '.testfiles')
- tmptestsdir = tempfile.mkdtemp(prefix='test_check_for_unsupported_metadata_files-',
- dir=tmpdir)
+ tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=tmpdir)
self.assertFalse(fdroidserver.lint.check_for_unsupported_metadata_files(tmptestsdir + '/'))
shutil.copytree(os.path.join(localmodule, 'tests', 'metadata'),
os.path.join(tmptestsdir, 'metadata'),
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
+import glob
import inspect
+import logging
import optparse
import os
+import random
+import shutil
import sys
import unittest
import yaml
class MetadataTest(unittest.TestCase):
'''fdroidserver/metadata.py'''
+ def setUp(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self.basedir = os.path.join(localmodule, 'tests')
+ self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ os.chdir(self.basedir)
+
def test_read_metadata(self):
def _build_yaml_representer(dumper, data):
'''Creates a YAML representation of a Build instance'''
return dumper.represent_dict(data)
- testsdir = os.path.dirname(__file__)
- os.chdir(testsdir)
-
self.maxDiff = None
# these need to be set to prevent code running on None, only
# yaml.dump(frommeta, f, default_flow_style=False)
def test_rewrite_yaml_fakeotaupdate(self):
-
- # setup/reset test dir if necessary and setup params
- tmpdir = os.path.join(os.path.dirname(__file__), '..', '.testfiles')
- if not os.path.exists(tmpdir):
- os.makedirs(tmpdir)
- testdir = tempfile.mkdtemp(prefix='test_rewrite_metadata_', dir=tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
# rewrite metadata
self.assertEqual(result.read(), orig.read())
def test_rewrite_yaml_fdroidclient(self):
-
- # setup/reset test dir if necessary and setup params
- tmpdir = os.path.join(os.path.dirname(__file__), '..', '.testfiles')
- if not os.path.exists(tmpdir):
- os.makedirs(tmpdir)
- testdir = tempfile.mkdtemp(prefix='test_rewrite_metadata_', dir=tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
# rewrite metadata
self.assertEqual(result.read(), orig.read())
def test_rewrite_yaml_special_build_params(self):
-
- # setup/reset test dir if necessary and setup params
- tmpdir = os.path.join(os.path.dirname(__file__), '..', '.testfiles')
- if not os.path.exists(tmpdir):
- os.makedirs(tmpdir)
- testdir = tempfile.mkdtemp(prefix='test_rewrite_metadata_', dir=tmpdir)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
# rewrite metadata
self.maxDiff = None
self.assertEqual(result.read(), orig.read())
+ def test_read_metadata_sort_by_time(self):
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
+ metadatadir = os.path.join(testdir, 'metadata')
+ os.makedirs(metadatadir)
+ fdroidserver.common.config = {'accepted_formats': ['txt']}
+
+ randomlist = []
+ randomapps = glob.glob(os.path.join(self.basedir, 'metadata', '*.txt'))
+ random.shuffle(randomapps)
+ i = 1
+ for f in randomapps:
+ shutil.copy(f, metadatadir)
+ new = os.path.join(metadatadir, os.path.basename(f))
+ stat = os.stat(new)
+ os.utime(new, (stat.st_ctime, stat.st_mtime + i))
+ # prepend new item so newest is always first
+ randomlist = [os.path.basename(f)[:-4]] + randomlist
+ i += 1
+ os.chdir(testdir)
+ allapps = fdroidserver.metadata.read_metadata(xref=True, sort_by_time=True)
+ allappids = []
+ for appid, app in allapps.items():
+ allappids.append(appid)
+ self.assertEqual(randomlist, allappids)
+
if __name__ == "__main__":
parser = optparse.OptionParser()
#
import inspect
+import logging
import optparse
import os
import sys
class PublishTest(unittest.TestCase):
'''fdroidserver/publish.py'''
+ def setUp(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self.basedir = os.path.join(localmodule, 'tests')
+ self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ os.chdir(self.basedir)
+
def test_key_alias(self):
publish.config = {}
self.assertEqual('a163ec9b', publish.key_alias('com.example.app'))
'com.example.anotherapp',
'org.org.org']
- with tempfile.TemporaryDirectory() as tmpdir:
- orig_cwd = os.getcwd()
- try:
- os.chdir(tmpdir)
- with open('config.py', 'w') as f:
- pass
-
- publish.store_stats_fdroid_signing_key_fingerprints(appids, indent=2)
-
- self.maxDiff = None
- expected = {
- "com.example.anotherapp": {
- "signer": "fa3f6a017541ee7fe797be084b1bcfbf92418a7589ef1f7fdeb46741b6d2e9c3"
- },
- "com.example.app": {
- "signer": "d34f678afbaa8f2fa6cc0edd6f0c2d1d2e2e9eb08bea521b24c740806016bff4"
- },
- "org.org.org": {
- "signer": "277655a6235bc6b0ef2d824396c51ba947f5ebc738c293d887e7083ff338af82"
- },
- "org.test.testy": {
- "signer": "6ae5355157a47ddcc3834a71f57f6fb5a8c2621c8e0dc739e9ddf59f865e497c"
- }
- }
- self.assertEqual(expected, common.load_stats_fdroid_signing_key_fingerprints())
-
- with open('config.py', 'r') as f:
- self.assertEqual(textwrap.dedent('''\
-
- repo_key_sha256 = "c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41"
- '''), f.read())
- finally:
- os.chdir(orig_cwd)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
+ os.chdir(testdir)
+ with open('config.py', 'w') as f:
+ pass
+
+ publish.store_stats_fdroid_signing_key_fingerprints(appids, indent=2)
+
+ self.maxDiff = None
+ expected = {
+ "com.example.anotherapp": {
+ "signer": "fa3f6a017541ee7fe797be084b1bcfbf92418a7589ef1f7fdeb46741b6d2e9c3"
+ },
+ "com.example.app": {
+ "signer": "d34f678afbaa8f2fa6cc0edd6f0c2d1d2e2e9eb08bea521b24c740806016bff4"
+ },
+ "org.org.org": {
+ "signer": "277655a6235bc6b0ef2d824396c51ba947f5ebc738c293d887e7083ff338af82"
+ },
+ "org.test.testy": {
+ "signer": "6ae5355157a47ddcc3834a71f57f6fb5a8c2621c8e0dc739e9ddf59f865e497c"
+ }
+ }
+ self.assertEqual(expected, common.load_stats_fdroid_signing_key_fingerprints())
+
+ with open('config.py', 'r') as f:
+ self.assertEqual(textwrap.dedent('''\
+
+ repo_key_sha256 = "c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41"
+ '''), f.read())
def test_store_and_load_fdroid_signing_key_fingerprints_with_missmatch(self):
common.config = {}
publish.config['repo_keyalias'] = 'repokey'
publish.config['repo_key_sha256'] = 'bad bad bad bad bad bad bad bad bad bad bad bad'
- with tempfile.TemporaryDirectory() as tmpdir:
- orig_cwd = os.getcwd()
- try:
- os.chdir(tmpdir)
- publish.store_stats_fdroid_signing_key_fingerprints({}, indent=2)
- with self.assertRaises(FDroidException):
- common.load_stats_fdroid_signing_key_fingerprints()
- finally:
- os.chdir(orig_cwd)
+ testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
+ os.chdir(testdir)
+ publish.store_stats_fdroid_signing_key_fingerprints({}, indent=2)
+ with self.assertRaises(FDroidException):
+ common.load_stats_fdroid_signing_key_fingerprints()
if __name__ == "__main__":
- if os.path.basename(os.getcwd()) != 'tests' and os.path.isdir('tests'):
- os.chdir('tests')
-
parser = optparse.OptionParser()
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="Spew out even more information than normal")
--- /dev/null
+The copyleft libre software Nextcloud Android app, gives you access to all the files in your Nextcloud.\n\nFeatures:\n* Easy, modern interface, suited to the theme of your server\n* Upload files to your Nextcloud server\n* Share them with others\n* Keep your favorite files and folders synced\n* Search across all folders on your server\n* Auto Upload for photos and videos taken by your device\n* Keep up to date with notifications\n* Multi-account support\n* Secure access to your data with fingerprint or PIN\n* Integration with DAVdroid for easy setup of calendar & Contacts synchronization\n\nPlease report all issues at https://github.com/nextcloud/android/issues and discuss this app at https://help.nextcloud.com/c/clients/android\n\nNew to Nextcloud? Nextcloud is a private file sync & share and communication server. It is libre software, and you can host it yourself or pay a company to do it for you. That way, you are in control of your photos, your calendar and contact data, your documents and everything else.\n\nCheck out Nextcloud at https://nextcloud.com
\ No newline at end of file
--- /dev/null
+The Nextcloud Android app gives you access to all your files in your Nextcloud
\ No newline at end of file
--- /dev/null
+Nextcloud
\ No newline at end of file
--- /dev/null
+The Open Source Nextcloud Android app allows you to access all your files on your Nextcloud.\nThis is a dev version of the official Nextcloud app and includes brand-new, untested features which might lead to instabilities and data loss. The app is designed for users willing to test the new features and to report bugs if they occur. Do not use it for your productive work!\n\nThe dev version can be installed alongside the official Nextcloud app which is available at F-Droid, too. Once a day it is checked if the source code was updated, so there can be longer pauses between builds.
--- /dev/null
+The Nextcloud Dev app is a development snapshot and can be installed parallel.
--- /dev/null
+Nextcloud Dev
\ No newline at end of file
--- /dev/null
+The copyleft libre software Nextcloud Android app, gives you access to all the files in your Nextcloud.\n\nFeatures:\n* Easy, modern interface, suited to the theme of your server\n* Upload files to your Nextcloud server\n* Share them with others\n* Keep your favorite files and folders synced\n* Search across all folders on your server\n* Auto Upload for photos and videos taken by your device\n* Keep up to date with notifications\n* Multi-account support\n* Secure access to your data with fingerprint or PIN\n* Integration with DAVdroid for easy setup of calendar & Contacts synchronization\n\nPlease report all issues at https://github.com/nextcloud/android/issues and discuss this app at https://help.nextcloud.com/c/clients/android\n\nNew to Nextcloud? Nextcloud is a private file sync & share and communication server. It is libre software, and you can host it yourself or pay a company to do it for you. That way, you are in control of your photos, your calendar and contact data, your documents and everything else.\n\nCheck out Nextcloud at https://nextcloud.com
\ No newline at end of file
--- /dev/null
+The Nextcloud Android app gives you access to all your files in your Nextcloud
\ No newline at end of file
--- /dev/null
+Nextcloud
\ No newline at end of file
--- /dev/null
+The Open Source Nextcloud Android app allows you to access all your files on your Nextcloud.\nThis is a dev version of the official Nextcloud app and includes brand-new, untested features which might lead to instabilities and data loss. The app is designed for users willing to test the new features and to report bugs if they occur. Do not use it for your productive work!\n\nThe dev version can be installed alongside the official Nextcloud app which is available at F-Droid, too. Once a day it is checked if the source code was updated, so there can be longer pauses between builds.
--- /dev/null
+The Nextcloud Dev app is a development snapshot and can be installed parallel.
--- /dev/null
+Nextcloud Dev
\ No newline at end of file
android {
compileSdkVersion 21
buildToolsVersion '22.0.1'
+
+ defaultConfig {
+
+ flavorDimensions "default"
+
+ productFlavors {
+ devVersion {
+ applicationId "org.fdroid.fdroid.dev"
+ dimension "default"
+ versionCode 949
+ versionName "0.95-dev"
+ }
+ }
+
+ }
sourceSets {
main {
shutil.rmtree(os.path.join('repo', 'info.guardianproject.urzip'), ignore_errors=True)
+ shutil.rmtree(os.path.join('build', 'com.nextcloud.client'), ignore_errors=True)
+ shutil.copytree(os.path.join('source-files', 'com.nextcloud.client'), os.path.join('build', 'com.nextcloud.client'))
+
+ shutil.rmtree(os.path.join('build', 'com.nextcloud.client.dev'), ignore_errors=True)
+ shutil.copytree(os.path.join('source-files', 'com.nextcloud.client.dev'),
+ os.path.join('build', 'com.nextcloud.client.dev'))
+
apps = dict()
- for packageName in ('info.guardianproject.urzip', 'org.videolan.vlc', 'obb.mainpatch.current'):
- apps[packageName] = dict()
+ for packageName in ('info.guardianproject.urzip', 'org.videolan.vlc', 'obb.mainpatch.current',
+ 'com.nextcloud.client', 'com.nextcloud.client.dev'):
+ apps[packageName] = fdroidserver.metadata.App()
apps[packageName]['id'] = packageName
apps[packageName]['CurrentVersionCode'] = 0xcafebeef
+
apps['info.guardianproject.urzip']['CurrentVersionCode'] = 100
+
+ buildnextcloudclient = fdroidserver.metadata.Build()
+ buildnextcloudclient.gradle = ['generic']
+ apps['com.nextcloud.client']['builds'] = [buildnextcloudclient]
+
+ buildnextclouddevclient = fdroidserver.metadata.Build()
+ buildnextclouddevclient.gradle = ['versionDev']
+ apps['com.nextcloud.client.dev']['builds'] = [buildnextclouddevclient]
+
fdroidserver.update.insert_localized_app_metadata(apps)
appdir = os.path.join('repo', 'info.guardianproject.urzip', 'en-US')
self.assertTrue(os.path.isfile(os.path.join(appdir, 'icon.png')))
self.assertTrue(os.path.isfile(os.path.join(appdir, 'featureGraphic.png')))
- self.assertEqual(3, len(apps))
+ self.assertEqual(5, len(apps))
for packageName, app in apps.items():
self.assertTrue('localized' in app)
self.assertTrue('en-US' in app['localized'])
self.assertEqual('featureGraphic.png', app['localized']['en-US']['featureGraphic'])
self.assertEqual(1, len(app['localized']['en-US']['phoneScreenshots']))
self.assertEqual(1, len(app['localized']['en-US']['sevenInchScreenshots']))
+ elif packageName == 'com.nextcloud.client':
+ self.assertEqual('Nextcloud', app['localized']['en-US']['name'])
+ self.assertEqual(1073, len(app['localized']['en-US']['description']))
+ self.assertEqual(78, len(app['localized']['en-US']['summary']))
+ elif packageName == 'com.nextcloud.client.dev':
+ self.assertEqual('Nextcloud Dev', app['localized']['en-US']['name'])
+ self.assertEqual(586, len(app['localized']['en-US']['description']))
+ self.assertEqual(79, len(app['localized']['en-US']['summary']))
def test_insert_triple_t_metadata(self):
importer = os.path.join(localmodule, 'tests', 'tmp', 'importer')
tmpdir = os.path.join(localmodule, '.testfiles')
if not os.path.exists(tmpdir):
os.makedirs(tmpdir)
- tmptestsdir = tempfile.mkdtemp(prefix='test_insert_triple_t_metadata-', dir=tmpdir)
+ tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=tmpdir)
packageDir = os.path.join(tmptestsdir, 'build', packageName)
shutil.copytree(importer, packageDir)
tmpdir = os.path.join(localmodule, '.testfiles')
if not os.path.exists(tmpdir):
os.makedirs(tmpdir)
- tmptestsdir = tempfile.mkdtemp(prefix='test_process_apk_signed_by_disabled_algorithms-',
+ tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
dir=tmpdir)
print('tmptestsdir', tmptestsdir)
os.chdir(tmptestsdir)
tmpdir = os.path.join(localmodule, '.testfiles')
if not os.path.exists(tmpdir):
os.makedirs(tmpdir)
- tmptestsdir = tempfile.mkdtemp(prefix='test_create_metadata_from_template-',
+ tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
dir=tmpdir)
print('tmptestsdir', tmptestsdir)
os.chdir(tmptestsdir)