1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-09-11 15:13:27 +02:00

Merge branch 'bsd-osx-porting-and-tests' into 'master'

BSD/OSX porting and tests

This makes `fdroid init` and `fdroid update` work on BSD/OSX and maybe Cygwin also (I didn't test Cygwin).  It also makes the install process more tolerant, like not requiring `python-magic` to run, while using it if its available.

Some fixes and additional tests are also included.  The commit messages have more info.

See merge request !56
This commit is contained in:
Ciaran Gultnieks 2015-08-03 12:43:15 +00:00
commit 581bc3c541
14 changed files with 963 additions and 85 deletions

4
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.pyc
*.class
*.box
# files generated by build
build/
dist/
@ -11,3 +12,6 @@ env/
fdroidserver.egg-info/
pylint.parseable
/.testfiles/
# files generated by tests
tests/local.properties

View File

@ -4,7 +4,6 @@ include fd-commit
include fdroid
include jenkins-build
include makebuildserver
include updateplugin
include buildserver/config.buildserver.py
include buildserver/fixpaths.sh
include buildserver/cookbooks/android-ndk/recipes/default.rb
@ -27,7 +26,6 @@ include examples/opensc-fdroid.cfg
include tests/getsig/run.sh
include tests/getsig/make.sh
include tests/getsig/getsig.java
include tests/getsig/getsig.class
include tests/run-tests
include tests/update.TestCase
include tests/urzip.apk

30
README
View File

@ -18,16 +18,36 @@ Installing
The easiest way to install the `fdroidserver` tools is on Debian, Ubuntu, Mint
or other Debian based distributions, you can install using:
sudo apt-get install fdroidserver
For older Ubuntu releases or to get the latest version, you can get
`fdroidserver` from the Guardian Project PPA (the signing key
fingerprint is `6B80 A842 07B3 0AC9 DEE2 35FE F50E ADDD 2234 F563`)
sudo add-apt-repository ppa:guardianproject/ppa
sudo apt-get update
sudo apt-get install fdroidserver
But you can also use `virtualenv` and `pip` python tools that also work on other
distributions.
On OSX, `fdroidserver` is available from third party package managers,
like Homebrew, MacPorts, and Fink:
First, make sure you have installed the python header files, virtualenv and pip.
They should be included in your OS's default package manager or you can install
them via other mechanisms like Brew/dnf/pacman/emerge/Fink/MacPorts.
sudo brew install fdroidserver
For any platform where Python's `easy_install` is an option (e.g. OSX
or Cygwin, you can use it:
sudo easy_install fdroidserver
Python's `pip` also works:
sudo pip install fdroidserver
The combination of `virtualenv` and `pip` is great for testing out the
latest versions of `fdroidserver`. Using `pip`, `fdroidserver` can
even be installed straight from git. First, make sure you have
installed the python header files, virtualenv and pip. They should be
included in your OS's default package manager or you can install them
via other mechanisms like Brew/dnf/pacman/emerge/Fink/MacPorts.
For Debian based distributions:

View File

@ -3,16 +3,17 @@
# Copy this file to config.py, then amend the settings below according to
# your system configuration.
# Path to the Android SDK
sdk_path = "$ANDROID_HOME"
# Custom path to the Android SDK, defaults to $ANDROID_HOME
# sdk_path = "/opt/android-sdk"
# Path to various versions of the Android NDK
# Most users will have the latest at $ANDROID_NDK, which is used by default
# If a version is missing or assigned to None, it is assumed not installed
ndk_paths = {
'r9b': None,
'r10e': "$ANDROID_NDK"
}
# Custom paths to various versions of the Android NDK, defaults to 'r10e' set
# to $ANDROID_NDK. Most users will have the latest at $ANDROID_NDK, which is
# used by default. If a version is missing or assigned to None, it is assumed
# not installed.
# ndk_paths = {
# 'r9b': "/opt/android-ndk-r9b",
# 'r10e': "/opt/android-ndk"
# }
# Build tools version to be used
build_tools = "22.0.1"

View File

@ -436,10 +436,9 @@ def adapt_gradle(build_dir):
if not os.path.isfile(path):
continue
logging.debug("Adapting %s at %s" % (filename, path))
FDroidPopen(['sed', '-i',
r's@buildToolsVersion\([ =]\+\).*@buildToolsVersion\1"'
+ config['build_tools'] + '"@g', path])
common.regsub_file(r"""(\s*)buildToolsVersion[\s'"=]+.*""",
r"""\1buildToolsVersion '%s'""" % config['build_tools'],
path)
def capitalize_intact(string):
@ -631,17 +630,13 @@ def build_local(app, thisbuild, vcs, build_dir, output_dir, srclib_dir, extlib_d
'package']
if thisbuild['target']:
target = thisbuild["target"].split('-')[1]
FDroidPopen(['sed', '-i',
's@<platform>[0-9]*</platform>@<platform>'
+ target + '</platform>@g',
'pom.xml'],
cwd=root_dir)
common.regsub_file(r'<platform>[0-9]*</platform>',
r'<platform>%s</platform>' % target,
os.path.join(root_dir, 'pom.xml'))
if '@' in thisbuild['maven']:
FDroidPopen(['sed', '-i',
's@<platform>[0-9]*</platform>@<platform>'
+ target + '</platform>@g',
'pom.xml'],
cwd=maven_dir)
common.regsub_file(r'<platform>[0-9]*</platform>',
r'<platform>%s</platform>' % target,
os.path.join(maven_dir, 'pom.xml'))
p = FDroidPopen(mvncmd, cwd=maven_dir)

View File

@ -29,7 +29,6 @@ import time
import operator
import Queue
import threading
import magic
import logging
import hashlib
import socket
@ -121,6 +120,14 @@ def fill_config_defaults(thisconfig):
thisconfig[k][k2 + '_orig'] = v
def regsub_file(pattern, repl, path):
with open(path, 'r') as f:
text = f.read()
text = re.sub(pattern, repl, text)
with open(path, 'w') as f:
f.write(text)
def read_config(opts, config_file='config.py'):
"""Read the repository config
@ -965,10 +972,9 @@ def remove_debuggable_flags(root_dir):
logging.debug("Removing debuggable flags from %s" % root_dir)
for root, dirs, files in os.walk(root_dir):
if 'AndroidManifest.xml' in files:
path = os.path.join(root, 'AndroidManifest.xml')
p = FDroidPopen(['sed', '-i', 's/android:debuggable="[^"]*"//g', path], output=False)
if p.returncode != 0:
raise BuildException("Failed to remove debuggable flags of %s" % path)
regsub_file(r'android:debuggable="[^"]*"',
'',
os.path.join(root, 'AndroidManifest.xml'))
# Extract some information from the AndroidManifest.xml at the given path.
@ -1305,9 +1311,9 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
if build['target']:
n = build["target"].split('-')[1]
FDroidPopen(['sed', '-i',
's@compileSdkVersion *[0-9]*@compileSdkVersion ' + n + '@g',
'build.gradle'], cwd=root_dir, output=False)
regsub_file(r'compileSdkVersion[ =]+[0-9]+',
r'compileSdkVersion %s' % n,
os.path.join(root_dir, 'build.gradle'))
# Remove forced debuggable flags
remove_debuggable_flags(root_dir)
@ -1319,34 +1325,27 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver=
if not os.path.isfile(path):
continue
if has_extension(path, 'xml'):
p = FDroidPopen(['sed', '-i',
's/android:versionName="[^"]*"/android:versionName="' + build['version'] + '"/g',
path], output=False)
if p.returncode != 0:
raise BuildException("Failed to amend manifest")
regsub_file(r'android:versionName="[^"]*"',
r'android:versionName="%s"' % build['version'],
path)
elif has_extension(path, 'gradle'):
p = FDroidPopen(['sed', '-i',
's/versionName *=* *.*/versionName = "' + build['version'] + '"/g',
path], output=False)
if p.returncode != 0:
raise BuildException("Failed to amend build.gradle")
regsub_file(r"""(\s*)versionName[\s'"=]+.*""",
r"""\1versionName '%s'""" % build['version'],
path)
if build['forcevercode']:
logging.info("Changing the version code")
for path in manifest_paths(root_dir, flavours):
if not os.path.isfile(path):
continue
if has_extension(path, 'xml'):
p = FDroidPopen(['sed', '-i',
's/android:versionCode="[^"]*"/android:versionCode="' + build['vercode'] + '"/g',
path], output=False)
if p.returncode != 0:
raise BuildException("Failed to amend manifest")
regsub_file(r'android:versionCode="[^"]*"',
r'android:versionCode="%s"' % build['vercode'],
path)
elif has_extension(path, 'gradle'):
p = FDroidPopen(['sed', '-i',
's/versionCode *=* *[0-9]*/versionCode = ' + build['vercode'] + '/g',
path], output=False)
if p.returncode != 0:
raise BuildException("Failed to amend build.gradle")
regsub_file(r'versionCode[ =]+[0-9]+',
r'versionCode %s' % build['vercode'],
path)
# Delete unwanted files
if build['rm']:
@ -1441,6 +1440,37 @@ def getpaths(build_dir, build, field):
return paths
def get_mime_type(path):
'''
There are two incompatible versions of the 'magic' module, one
that comes as part of libmagic, which is what Debian includes as
python-magic, then another called python-magic that is a separate
project that wraps libmagic. The second is 'magic' on pypi, so
both need to be supported. Then on platforms where libmagic is
not easily included, e.g. OSX and Windows, fallback to the
built-in 'mimetypes' module so this will work without
libmagic. Hence this function with the following hacks:
'''
try:
import magic
ms = None
try:
ms = magic.open(magic.MIME_TYPE)
ms.load()
return magic.from_file(path, mime=True)
except AttributeError:
return ms.file(path)
if ms is not None:
ms.close()
except UnicodeError:
logging.warn('Found malformed magic number at %s' % path)
except ImportError:
import mimetypes
mimetypes.init()
return mimetypes.guess_type(path, strict=False)
# 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):
@ -1472,12 +1502,6 @@ def scan_source(build_dir, root_dir, thisbuild):
scanignore_worked = set()
scandelete_worked = set()
try:
ms = magic.open(magic.MIME_TYPE)
ms.load()
except AttributeError:
ms = None
def toignore(fd):
for p in scanignore:
if fd.startswith(p):
@ -1526,10 +1550,7 @@ def scan_source(build_dir, root_dir, thisbuild):
fp = os.path.join(r, curfile)
fd = fp[len(build_dir) + 1:]
try:
mime = magic.from_file(fp, mime=True) if ms is None else ms.file(fp)
except UnicodeError:
warnproblem('malformed magic number', fd)
mime = get_mime_type(fp)
if mime == 'application/x-sharedlib':
count += handleproblem('shared library', fd, fp)
@ -1537,7 +1558,7 @@ def scan_source(build_dir, root_dir, thisbuild):
elif mime == 'application/x-archive':
count += handleproblem('static library', fd, fp)
elif mime == 'application/x-executable':
elif mime == 'application/x-executable' or mime == 'application/x-mach-binary':
count += handleproblem('binary executable', fd, fp)
elif mime == 'application/x-java-applet':
@ -1581,8 +1602,6 @@ def scan_source(build_dir, root_dir, thisbuild):
if any(suspect.match(line) for suspect in usual_suspects):
count += handleproblem('usual suspect at line %d' % i, fd, fp)
break
if ms is not None:
ms.close()
for p in scanignore:
if p not in scanignore_worked:
@ -2032,9 +2051,9 @@ def genkeystore(localconfig):
'-keypass:file', config['keypassfile'],
'-dname', localconfig['keydname']])
# TODO keypass should be sent via stdin
os.chmod(localconfig['keystore'], 0o0600)
if p.returncode != 0:
raise BuildException("Failed to generate key", p.output)
os.chmod(localconfig['keystore'], 0o0600)
# now show the lovely key that was just generated
p = FDroidPopen(['keytool', '-list', '-v',
'-keystore', localconfig['keystore'],

View File

@ -70,8 +70,16 @@ def main():
# find root install prefix
tmp = os.path.dirname(sys.argv[0])
if os.path.basename(tmp) == 'bin':
prefix = os.path.dirname(tmp)
examplesdir = prefix + '/share/doc/fdroidserver/examples'
prefix = None
egg_link = os.path.join(tmp, '..', 'local/lib/python2.7/site-packages/fdroidserver.egg-link')
if os.path.exists(egg_link):
# installed from local git repo
examplesdir = os.path.join(open(egg_link).readline().rstrip(), 'examples')
else:
prefix = os.path.dirname(os.path.dirname(__file__)) # use .egg layout
if not prefix.endswith('.egg'): # use UNIX layout
prefix = os.path.dirname(tmp)
examplesdir = prefix + '/share/doc/fdroidserver/examples'
else:
# we're running straight out of the git repo
prefix = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))

View File

@ -50,13 +50,21 @@ cd $WORKSPACE/tests
#------------------------------------------------------------------------------#
# test building the source tarball
# test building the source tarball, then installing it
cd $WORKSPACE
python2 setup.py sdist
rm -rf $WORKSPACE/env
virtualenv --python=python2 $WORKSPACE/env
. $WORKSPACE/env/bin/activate
pip install dist/fdroidserver-*.tar.gz
# run tests in new pip+virtualenv install
fdroid=$WORKSPACE/env/bin/fdroid $WORKSPACE/tests/run-tests $apksource
#------------------------------------------------------------------------------#
# test install using site packages
# test install using install direct from git repo
cd $WORKSPACE
rm -rf $WORKSPACE/env
virtualenv --python=python2 --system-site-packages $WORKSPACE/env
@ -65,7 +73,6 @@ pip install -e $WORKSPACE
python2 setup.py install
# run tests in new pip+virtualenv install
. $WORKSPACE/env/bin/activate
fdroid=$WORKSPACE/env/bin/fdroid $WORKSPACE/tests/run-tests $apksource

View File

@ -3,6 +3,12 @@
from setuptools import setup
import sys
# workaround issue with easy_install on OSX, where sys.prefix is not an installable location
if sys.platform == 'darwin' and sys.prefix.startswith('/System'):
data_prefix = '/Library/Python/2.7/site-packages'
else:
data_prefix = sys.prefix
setup(name='fdroidserver',
version='0.3.0',
description='F-Droid Server Tools',
@ -13,18 +19,17 @@ setup(name='fdroidserver',
packages=['fdroidserver'],
scripts=['fdroid', 'fd-commit'],
data_files=[
(sys.prefix + '/share/doc/fdroidserver/examples',
(data_prefix + '/share/doc/fdroidserver/examples',
['buildserver/config.buildserver.py',
'examples/config.py',
'examples/makebs.config.py',
'examples/opensc-fdroid.cfg',
'examples/fdroid-icon.png']),
],
install_requires=[
install_requires=[ # should include 'python-magic' but its not strictly required
'mwclient',
'paramiko',
'Pillow',
'python-magic',
'apache-libcloud >= 0.14.1',
'pyasn1',
'pyasn1-modules',

484
tests/AndroidManifest.xml Normal file
View File

@ -0,0 +1,484 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.fdroid.fdroid"
android:installLocation="auto"
android:versionCode="940"
android:versionName="0.94-test"
>
<uses-sdk
tools:overrideLibrary="org.thoughtcrime.ssl.pinning"
android:minSdkVersion="8"
android:targetSdkVersion="21"
/>
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true"
/>
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature
android:name="android.hardware.nfc"
android:required="false" />
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
<uses-permission android:name="android.permission.NFC" />
<!-- These permissions are only granted when F-Droid is installed as a system-app! -->
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.DELETE_PACKAGES"
tools:ignore="ProtectedPermissions"/>
<application
android:debuggable="true"
android:name="FDroidApp"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:description="@string/app_description"
android:allowBackup="true"
android:theme="@style/AppThemeDark"
android:supportsRtl="true"
>
<provider
android:authorities="org.fdroid.fdroid.data.AppProvider"
android:name="org.fdroid.fdroid.data.AppProvider"
android:exported="false"/>
<provider
android:authorities="org.fdroid.fdroid.data.RepoProvider"
android:name="org.fdroid.fdroid.data.RepoProvider"
android:exported="false"/>
<provider
android:authorities="org.fdroid.fdroid.data.ApkProvider"
android:name="org.fdroid.fdroid.data.ApkProvider"
android:exported="false"/>
<provider
android:authorities="org.fdroid.fdroid.data.InstalledAppProvider"
android:name="org.fdroid.fdroid.data.InstalledAppProvider"
android:exported="false"/>
<activity
android:name=".FDroid"
android:launchMode="singleTop"
android:configChanges="keyboardHidden|orientation|screenSize" >
<!-- App URLs -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="fdroid.app" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="f-droid.org" />
<data android:host="www.f-droid.org" />
<data android:pathPrefix="/app/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="f-droid.org" />
<data android:host="www.f-droid.org" />
<data android:pathPrefix="/repository/browse" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="market" android:host="details" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="play.google.com" /> <!-- they don't do www. -->
<data android:path="/store/apps/details" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="amzn" android:host="apps" android:path="/android" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="amazon.com" />
<data android:host="www.amazon.com" />
<data android:path="/gp/mas/dl/android" />
</intent-filter>
<!-- Search URLs -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="fdroid.search" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="market" android:host="search" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="play.google.com" /> <!-- they don't do www. -->
<data android:path="/store/search" />
</intent-filter>
<!-- Handle NFC tags detected from outside our application -->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<!--
URIs that come in via NFC have scheme/host normalized to all lower case
https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED
-->
<data android:scheme="fdroidrepo" />
<data android:scheme="fdroidrepos" />
</intent-filter>
<!-- Repo URLs -->
<!--
This intent serves two purposes: Swapping apps between devices and adding a
repo from a website (e.g. https://guardianproject.info/fdroid/repo).
We intercept both of these situations in the FDroid activity, and then redirect
to the appropriate handler (swap handling, manage repos respectively) from there.
The reason for this is that the only differentiating factor is the presence
of a "swap=1" in the query string, and intent-filter is unable to deal with
query parameters. An alternative would be to do something like fdroidswap:// as
a scheme, but then we. Need to copy/paste all of this intent-filter stuff and
keep it up to date when it changes or a bug is found.
-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<!--
Android's scheme matcher is case-sensitive, so include
ALL CAPS versions to support ALL CAPS URLs in QR Codes.
QR Codes have a special ALL CAPS mode that uses a reduced
character set, making for more compact QR Codes.
-->
<data android:scheme="http" />
<data android:scheme="HTTP" />
<data android:scheme="https" />
<data android:scheme="HTTPS" />
<data android:scheme="fdroidrepo" />
<data android:scheme="FDROIDREPO" />
<data android:scheme="fdroidrepos" />
<data android:scheme="FDROIDREPOS" />
<data android:host="*" />
<!--
The pattern matcher here is poorly implemented, in particular the * is
non-greedy, so you have to do stupid tricks to match patterns that have
repeat characters in them. http://stackoverflow.com/a/8599921/306864
-->
<data android:path="/fdroid/repo" />
<data android:pathPattern="/fdroid/repo/*" />
<data android:pathPattern="/.*/fdroid/repo" />
<data android:pathPattern="/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/fdroid/repo/*" />
<data android:pathPattern="/.*/.*/.*/fdroid/repo" />
<data android:pathPattern="/.*/.*/.*/fdroid/repo/*" />
<data android:path="/fdroid/archive" />
<data android:pathPattern="/fdroid/archive/*" />
<data android:pathPattern="/.*/fdroid/archive" />
<data android:pathPattern="/.*/fdroid/archive/*" />
<data android:pathPattern="/.*/.*/fdroid/archive" />
<data android:pathPattern="/.*/.*/fdroid/archive/*" />
<data android:pathPattern="/.*/.*/.*/fdroid/archive" />
<data android:pathPattern="/.*/.*/.*/fdroid/archive/*" />
<!--
Some QR Code scanners don't respect custom schemes like fdroidrepo://,
so this is a workaround, since the local repo URL is all uppercase in
the QR Code for sending the local repo to another device.
-->
<data android:path="/FDROID/REPO" />
<data android:pathPattern="/.*/FDROID/REPO" />
<data android:pathPattern="/.*/.*/FDROID/REPO" />
<data android:pathPattern="/.*/.*/.*/FDROID/REPO" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchResults" />
</activity>
<activity
android:name=".views.swap.ConnectSwapActivity"
android:theme="@style/SwapTheme.Wizard.ReceiveSwap"
android:label=""
android:noHistory="true"
android:parentActivityName=".FDroid"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:name=".installer.InstallConfirmActivity"
android:label="@string/menu_install"
android:parentActivityName=".FDroid">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:name=".views.ManageReposActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:parentActivityName=".FDroid" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.org.fdroid.fdroid.repo" />
</intent-filter>
</activity>
<activity
android:name=".NfcNotEnabledActivity"
android:noHistory="true" />
<!--<activity android:name=".views.QrWizardDownloadActivity" />
<activity android:name=".views.QrWizardWifiNetworkActivity" />
<activity
android:name=".views.LocalRepoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/local_repo"
android:launchMode="singleTop"
android:parentActivityName=".FDroid"
android:screenOrientation="portrait" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:name=".views.SelectLocalAppsActivity"
android:label="@string/setup_repo"
android:parentActivityName=".views.LocalRepoActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.LocalRepoActivity" />
</activity>-->
<activity
android:name=".views.RepoDetailsActivity"
android:label="@string/menu_manage"
android:parentActivityName=".views.ManageReposActivity"
android:windowSoftInputMode="stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.ManageReposActivity" />
</activity>
<activity
android:name=".AppDetails"
android:label="@string/app_details"
android:exported="true"
android:parentActivityName=".FDroid" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:name=".views.swap.SwapAppListActivity$SwapAppDetails"
android:label="@string/app_details"
android:parentActivityName=".views.swap.SwapAppListActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".views.swap.SwapAppListActivity" />
</activity>
<activity
android:label="@string/menu_preferences"
android:name=".PreferencesActivity"
android:parentActivityName=".FDroid" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:label="@string/menu_swap"
android:name=".views.swap.SwapActivity"
android:parentActivityName=".FDroid"
android:theme="@style/SwapTheme.Wizard"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<activity
android:label="@string/swap"
android:name=".views.swap.SwapAppListActivity"
android:parentActivityName=".FDroid"
android:theme="@style/SwapTheme.AppList"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
</activity>
<!-- Note: Theme.NoDisplay, this activity shows dialogs only -->
<activity
android:name=".installer.InstallIntoSystemDialogActivity"
android:theme="@android:style/Theme.NoDisplay" />
<receiver
android:name=".installer.InstallIntoSystemBootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".SearchResults"
android:label="@string/search_results"
android:exported="true"
android:launchMode="singleTop"
android:parentActivityName=".FDroid" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".FDroid" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<receiver android:name=".receiver.StartupReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.PackageAddedReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.PackageUpgradedReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.PackageRemovedReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.WifiStateChangeReceiver" >
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".UpdateService" />
<service android:name=".net.WifiStateChangeService" />
<service android:name=".localrepo.LocalRepoService" />
</application>
</manifest>

65
tests/build.TestCase Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
import inspect
import optparse
import os
import re
import sys
import unittest
localmodule = os.path.realpath(
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
print('localmodule: ' + localmodule)
if localmodule not in sys.path:
sys.path.insert(0, localmodule)
import fdroidserver.build
import fdroidserver.common
class BuildTest(unittest.TestCase):
'''fdroidserver/build.py'''
def _set_build_tools(self):
build_tools = os.path.join(fdroidserver.common.config['sdk_path'], 'build-tools')
if os.path.exists(build_tools):
fdroidserver.common.config['build_tools'] = ''
for f in sorted(os.listdir(build_tools), reverse=True):
versioned = os.path.join(build_tools, f)
if os.path.isdir(versioned) \
and os.path.isfile(os.path.join(versioned, 'aapt')):
fdroidserver.common.config['build_tools'] = versioned
break
return True
else:
print 'no build-tools found: ' + build_tools
return False
def _find_all(self):
for cmd in ('aapt', 'adb', 'android', 'zipalign'):
path = fdroidserver.common.find_sdk_tools_cmd(cmd)
if path is not None:
self.assertTrue(os.path.exists(path))
self.assertTrue(os.path.isfile(path))
def test_adapt_gradle(self):
teststring = 'FAKE_VERSION_FOR_TESTING'
fdroidserver.build.config = {}
fdroidserver.build.config['build_tools'] = teststring
fdroidserver.build.adapt_gradle(os.path.dirname(__file__))
filedata = open(os.path.join(os.path.dirname(__file__), 'build.gradle')).read()
self.assertIsNotNone(re.search("\s+buildToolsVersion '%s'\s+" % teststring, filedata))
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="Spew out even more information than normal")
(fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
newSuite = unittest.TestSuite()
newSuite.addTest(unittest.makeSuite(BuildTest))
unittest.main()

218
tests/build.gradle Normal file
View File

@ -0,0 +1,218 @@
apply plugin: 'com.android.application'
if ( !hasProperty( 'sourceDeps' ) ) {
logger.info "Setting up *binary* dependencies for F-Droid (if you'd prefer to build from source, pass the -PsourceDeps argument to gradle while building)."
repositories {
jcenter()
// This is here until we sort out all dependencies from mavenCentral/jcenter. Once all of
// the dependencies below have been sorted out, this can be removed.
flatDir {
dirs 'libs/binaryDeps'
}
}
dependencies {
compile 'com.android.support:support-v4:22.1.0',
'com.android.support:appcompat-v7:22.1.0',
'com.android.support:support-annotations:22.1.0',
'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0',
'com.nostra13.universalimageloader:universal-image-loader:1.9.4',
'com.google.zxing:core:3.2.0',
'eu.chainfire:libsuperuser:1.0.0.201504231659',
// We use a slightly modified spongycastle, see
// openkeychain/spongycastle with some changes on top of 1.51.0.0
'com.madgag.spongycastle:pkix:1.51.0.0',
'com.madgag.spongycastle:prov:1.51.0.0',
'com.madgag.spongycastle:core:1.51.0.0'
// Upstream doesn't have a binary on mavenCentral/jcenter yet:
// https://github.com/kolavar/android-support-v4-preferencefragment/issues/13
compile(name: 'support-v4-preferencefragment-release', ext: 'aar')
// Fork for F-Droid, including support for https. Not merged into upstream
// yet (seems to be a little unsupported as of late), so not using mavenCentral/jcenter.
compile(name: 'nanohttpd-2.1.0')
// Upstream doesn't have a binary on mavenCentral.
compile(name: 'zipsigner')
// Project semi-abandoned, 3.4.1 is from 2011 and we use trunk from 2013
compile(name: 'jmdns')
androidTestCompile 'commons-io:commons-io:2.2'
}
} else {
logger.info "Setting up *source* dependencies for F-Droid (because you passed in the -PsourceDeps argument to gradle while building)."
repositories {
jcenter()
}
dependencies {
compile project(':extern:AndroidPinning')
compile project(':extern:UniversalImageLoader:library')
compile project(':extern:libsuperuser:libsuperuser')
compile project(':extern:nanohttpd:core')
compile project(':extern:jmdns')
compile project(':extern:zipsigner')
compile project(':extern:zxing-core')
compile( project(':extern:support-v4-preferencefragment') ) {
exclude module: 'support-v4'
}
// Until the android team updates the gradle plugin version from 0.10.0 to
// a newer version, we can't build this from source with our gradle version
// of 1.0.0. They use API's which have been moved in the newer plugin.
// So yes, this is a little annoying that our "source dependencies" include
// a bunch of binaries from jcenter - but the ant build file (which is the
// one used to build F-Droid which is distributed on https://f-droid.org
// builds these from source - well - not support-v4).
//
// If the android team gets the build script working with the newer plugin,
// then you can find the relevant portions of the ../build.gradle file that
// include magic required to make it work at around about the v0.78 git tag.
// They have since been removed to clean up the build file.
compile 'com.android.support:support-v4:22.1.0',
'com.android.support:appcompat-v7:22.1.0',
'com.android.support:support-annotations:22.1.0'
androidTestCompile 'commons-io:commons-io:2.2'
}
}
task cleanBinaryDeps(type: Delete) {
enabled = project.hasProperty('sourceDeps')
description = "Removes all .jar and .aar files from F-Droid/libs/. Requires the sourceDeps property to be set (\"gradle -PsourceDeps cleanBinaryDeps\")"
delete fileTree('libs/binaryDeps') {
include '*.aar'
include '*.jar'
}
}
task binaryDeps(type: Copy, dependsOn: ':F-Droid:prepareReleaseDependencies') {
enabled = project.hasProperty('sourceDeps')
description = "Copies .jar and .aar files from subproject dependencies in extern/ to F-Droid/libs. Requires the sourceDeps property to be set (\"gradle -PsourceDeps binaryDeps\")"
from ('../extern/' ) {
include 'support-v4-preferencefragment/build/outputs/aar/support-v4-preferencefragment-release.aar',
'nanohttpd/core/build/libs/nanohttpd-2.1.0.jar',
'zipsigner/build/libs/zipsigner.jar',
'jmdns/build/libs/jmdns.jar',
'Support/v4/build/libs/support-v4.jar'
}
into 'libs/binaryDeps'
includeEmptyDirs false
eachFile { FileCopyDetails details ->
// Don't copy to a sub folder such as libs/binaryDeps/Project/build/outputs/aar/project.aar, but
// rather libs/binaryDeps/project.aar.
details.path = details.name
}
}
android {
compileSdkVersion 21
buildToolsVersion '22.0.1'
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
androidTest.setRoot('test')
androidTest {
manifest.srcFile 'test/AndroidManifest.xml'
java.srcDirs = ['test/src']
resources.srcDirs = ['test/src']
aidl.srcDirs = ['test/src']
renderscript.srcDirs = ['test/src']
res.srcDirs = ['test/res']
assets.srcDirs = ['test/assets']
}
}
buildTypes {
release {
minifyEnabled false
}
buildTypes {
debug {
debuggable true
}
}
}
compileOptions {
compileOptions.encoding = "UTF-8"
// Use Java 1.7, requires minSdk 8
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
// Enable all Android lint warnings
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:all"
}
}
}
// This person took the example code below from another blogpost online, however
// I lost the reference to it:
// http://stackoverflow.com/questions/23297562/gradle-javadoc-and-android-documentation
android.applicationVariants.all { variant ->
task("generate${variant.name}Javadoc", type: Javadoc) {
title = "$name $version API"
description "Generates Javadoc for F-Droid."
source = variant.javaCompile.source
def sdkDir
Properties properties = new Properties()
File localProps = project.rootProject.file('local.properties')
if (localProps.exists()) {
properties.load(localProps.newDataInputStream())
sdkDir = properties.getProperty('sdk.dir')
} else {
sdkDir = System.getenv('ANDROID_HOME')
}
if (!sdkDir) {
throw new ProjectConfigurationException("Cannot find android sdk. Make sure sdk.dir is defined in local.properties or the environment variable ANDROID_HOME is set.", null)
}
ext.androidJar = "${sdkDir}/platforms/${android.compileSdkVersion}/android.jar"
classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
options.links("http://docs.oracle.com/javase/7/docs/api/");
options.links("http://d.android.com/reference/");
exclude '**/BuildConfig.java'
exclude '**/R.java'
}
}

View File

@ -6,6 +6,7 @@
import inspect
import optparse
import os
import re
import sys
import unittest
@ -17,6 +18,7 @@ if localmodule not in sys.path:
sys.path.insert(0,localmodule)
import fdroidserver.common
import fdroidserver.metadata
class CommonTest(unittest.TestCase):
'''fdroidserver/common.py'''
@ -95,6 +97,48 @@ class CommonTest(unittest.TestCase):
self.assertFalse(fdroidserver.common.is_valid_package_name(name),
"{0} should not be a valid package name".format(name))
def test_prepare_sources(self):
testint = 99999999
teststr = 'FAKE_STR_FOR_TESTING'
testdir = os.path.dirname(__file__)
config = dict()
config['sdk_path'] = os.getenv('ANDROID_HOME')
config['build_tools'] = 'FAKE_BUILD_TOOLS_VERSION'
fdroidserver.common.config = config
app = dict()
app['id'] = 'org.fdroid.froid'
build = dict(fdroidserver.metadata.flag_defaults)
build['commit'] = 'master'
build['forceversion'] = True
build['forcevercode'] = True
build['gradle'] = ['yes']
build['ndk_path'] = os.getenv('ANDROID_NDK_HOME')
build['target'] = 'android-' + str(testint)
build['type'] = 'gradle'
build['version'] = teststr
build['vercode'] = testint
class FakeVcs():
# no need to change to the correct commit here
def gotorevision(self, rev, refresh=True):
pass
# no srclib info needed, but it could be added...
def getsrclib(self):
return None
fdroidserver.common.prepare_source(FakeVcs(), app, build, testdir, testdir, testdir)
filedata = open(os.path.join(testdir, 'build.gradle')).read()
self.assertIsNotNone(re.search("\s+compileSdkVersion %s\s+" % testint, filedata))
filedata = open(os.path.join(testdir, 'AndroidManifest.xml')).read()
self.assertIsNone(re.search('android:debuggable', filedata))
self.assertIsNotNone(re.search('android:versionName="%s"' % build['version'], filedata))
self.assertIsNotNone(re.search('android:versionCode="%s"' % build['vercode'], filedata))
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("-v", "--verbose", action="store_true", default=False,

View File

@ -35,12 +35,12 @@ create_fake_android_home() {
create_test_dir() {
test -e $WORKSPACE/.testfiles || mkdir $WORKSPACE/.testfiles
mktemp --directory --tmpdir=$WORKSPACE/.testfiles
TMPDIR=$WORKSPACE/.testfiles mktemp -d
}
create_test_file() {
test -e $WORKSPACE/.testfiles || mkdir $WORKSPACE/.testfiles
mktemp --tmpdir=$WORKSPACE/.testfiles
TMPDIR=$WORKSPACE/.testfiles mktemp
}
#------------------------------------------------------------------------------#
@ -124,6 +124,7 @@ REPOROOT=`create_test_dir`
cd $REPOROOT
$fdroid init
$fdroid update --create-metadata
$fdroid readmeta
$fdroid server update --local-copy-dir=/tmp/fdroid
# now test the errors work
@ -160,6 +161,7 @@ cd $REPOROOT
$fdroid init
copy_apks_into_repo $REPOROOT
$fdroid update --create-metadata
$fdroid readmeta
grep -F '<application id=' repo/index.xml > /dev/null
LOCALCOPYDIR=`create_test_dir`/fdroid
@ -263,6 +265,7 @@ $fdroid init --keystore $KEYSTORE --android-home $STORED_ANDROID_HOME --no-promp
test -e $KEYSTORE
copy_apks_into_repo $REPOROOT
$fdroid update --create-metadata
$fdroid readmeta
grep -F '<application id=' repo/index.xml > /dev/null
test -e repo/index.xml
test -e repo/index.jar
@ -278,6 +281,7 @@ mkdir repo
copy_apks_into_repo $REPOROOT
$fdroid init
$fdroid update --create-metadata
$fdroid readmeta
grep -F '<application id=' repo/index.xml > /dev/null
@ -291,6 +295,7 @@ $fdroid init --keystore $KEYSTORE
test -e $KEYSTORE
copy_apks_into_repo $REPOROOT
$fdroid update --create-metadata
$fdroid readmeta
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml > /dev/null
@ -318,6 +323,7 @@ $fdroid update --create-key
test -e $KEYSTORE
copy_apks_into_repo $REPOROOT
$fdroid update --create-metadata
$fdroid readmeta
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml > /dev/null
@ -333,11 +339,14 @@ $fdroid init --keystore $KEYSTORE
test -e $KEYSTORE
copy_apks_into_repo $REPOROOT
$fdroid update --create-metadata
$fdroid readmeta
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml > /dev/null
cp $WORKSPACE/tests/urzip.apk $REPOROOT/
test -e $REPOROOT/repo/info.guardianproject.urzip_100.apk || \
cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
$fdroid update --create-metadata
$fdroid readmeta
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml > /dev/null
@ -361,8 +370,8 @@ KEYSTORE=$REPOROOT/keystore.jks
cd $REPOROOT
touch config.py
touch fdroid-icon.png
mkdir repo/
cp $WORKSPACE/tests/urzip.apk $REPOROOT/
mkdir repo
cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
set +e
$fdroid update --create-metadata
if [ $? -eq 0 ]; then
@ -400,6 +409,7 @@ $fdroid init --keystore $KEYSTORE
test -e $KEYSTORE
cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
$fdroid update --create-metadata
$fdroid readmeta
test -e repo/index.xml
test -e repo/index.jar
grep -F '<application id=' repo/index.xml > /dev/null