From bfe587979de7881592c84f8141ef4678539e4591 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 31 Jan 2020 23:49:50 +0100 Subject: [PATCH 1/5] import: make it work most of the time with git repos This includes real tests too. --- fdroidserver/import.py | 89 +++---- tests/common.TestCase | 24 ++ tests/import.TestCase | 70 +++++- tests/import_proxy.py | 2 + tests/scanner.TestCase | 1 + .../avenginekit/build.gradle | 2 + .../cn.wildfirechat.chat/build.gradle | 41 ++++ .../cn.wildfirechat.chat/chat/build.gradle | 115 +++++++++ .../cn.wildfirechat.chat/client/build.gradle | 57 +++++ .../client/src/main/AndroidManifest.xml | 26 ++ .../emojilibrary/build.gradle | 34 +++ .../gradle/build_libraries.gradle | 42 ++++ .../imagepicker/build.gradle | 30 +++ .../mars-core-release/build.gradle | 2 + .../cn.wildfirechat.chat/push/build.gradle | 55 +++++ .../cn.wildfirechat.chat/settings.gradle | 7 + .../com.anpmech.launcher/app/build.gradle | 76 ++++++ .../app/src/main/AndroidManifest.xml | 66 +++++ .../com.anpmech.launcher/build.gradle | 45 ++++ .../com.anpmech.launcher/settings.gradle | 16 ++ .../org.tasks/app/build.gradle.kts | 225 ++++++++++++++++++ tests/source-files/org.tasks/build.gradle | 13 + tests/source-files/org.tasks/build.gradle.kts | 26 ++ .../org.tasks/buildSrc/build.gradle.kts | 7 + .../org.tasks/settings.gradle.kts | 1 + .../app/src/main/AndroidManifest.xml | 124 ++++++++++ .../ut.ewh.audiometrytest/build.gradle | 29 +++ .../ut.ewh.audiometrytest/settings.gradle | 1 + 28 files changed, 1184 insertions(+), 42 deletions(-) create mode 100644 tests/source-files/cn.wildfirechat.chat/avenginekit/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/chat/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/client/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/client/src/main/AndroidManifest.xml create mode 100755 tests/source-files/cn.wildfirechat.chat/emojilibrary/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/gradle/build_libraries.gradle create mode 100755 tests/source-files/cn.wildfirechat.chat/imagepicker/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/mars-core-release/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/push/build.gradle create mode 100644 tests/source-files/cn.wildfirechat.chat/settings.gradle create mode 100644 tests/source-files/com.anpmech.launcher/app/build.gradle create mode 100644 tests/source-files/com.anpmech.launcher/app/src/main/AndroidManifest.xml create mode 100644 tests/source-files/com.anpmech.launcher/build.gradle create mode 100644 tests/source-files/com.anpmech.launcher/settings.gradle create mode 100644 tests/source-files/org.tasks/app/build.gradle.kts create mode 100644 tests/source-files/org.tasks/build.gradle create mode 100644 tests/source-files/org.tasks/build.gradle.kts create mode 100644 tests/source-files/org.tasks/buildSrc/build.gradle.kts create mode 100644 tests/source-files/org.tasks/settings.gradle.kts create mode 100644 tests/source-files/ut.ewh.audiometrytest/app/src/main/AndroidManifest.xml create mode 100644 tests/source-files/ut.ewh.audiometrytest/build.gradle create mode 100644 tests/source-files/ut.ewh.audiometrytest/settings.gradle diff --git a/fdroidserver/import.py b/fdroidserver/import.py index b463824c..5d0ebfcd 100644 --- a/fdroidserver/import.py +++ b/fdroidserver/import.py @@ -18,12 +18,12 @@ # along with this program. If not, see . import binascii +import glob import os import re import shutil import urllib.request from argparse import ArgumentParser -from configparser import ConfigParser import logging from . import _ @@ -31,8 +31,9 @@ from . import common from . import metadata from .exception import FDroidException - -SETTINGS_GRADLE = re.compile(r'''include\s+['"]:([^'"]*)['"]''') +SETTINGS_GRADLE = re.compile(r'settings\.gradle(?:\.kts)?') +GRADLE_SUBPROJECT = re.compile(r'''['"]:([^'"]+)['"]''') +ANDROID_PLUGIN = re.compile(r'''\s*(:?apply plugin:|id)\(?\s*['"](android|com\.android\.application)['"]\s*\)?''') # Get the repo type and address from the given web page. The page is scanned @@ -168,32 +169,47 @@ def get_metadata_from_url(app, url): shutil.rmtree(build_dir) vcs = common.getvcs(repotype, repo, build_dir) vcs.gotorevision(options.rev) - root_dir = get_subdir(build_dir) app.RepoType = repotype app.Repo = repo - return root_dir, build_dir - - -config = None -options = None - - -def get_subdir(build_dir): - if options.subdir: - return os.path.join(build_dir, options.subdir) - - settings_gradle = os.path.join(build_dir, 'settings.gradle') - if os.path.exists(settings_gradle): - with open(settings_gradle) as fp: - m = SETTINGS_GRADLE.search(fp.read()) - if m: - return os.path.join(build_dir, m.group(1)) - return build_dir +def get_all_gradle_and_manifests(build_dir): + paths = [] + for root, dirs, files in os.walk(build_dir): + for f in sorted(files): + if f == 'AndroidManifest.xml' \ + or f.endswith('.gradle') or f.endswith('.gradle.kts'): + full = os.path.join(root, f) + paths.append(full) + return paths + + +def get_gradle_subdir(build_dir, paths): + """get the subdir where the gradle build is based""" + first_gradle_dir = None + for path in paths: + if not first_gradle_dir: + first_gradle_dir = os.path.relpath(os.path.dirname(path), build_dir) + if os.path.exists(path) and SETTINGS_GRADLE.match(os.path.basename(path)): + with open(path) as fp: + for m in GRADLE_SUBPROJECT.finditer(fp.read()): + for f in glob.glob(os.path.join(os.path.dirname(path), m.group(1), 'build.gradle*')): + with open(f) as fp: + while True: + line = fp.readline() + if not line: + break + if ANDROID_PLUGIN.match(line): + return os.path.relpath(os.path.dirname(f), build_dir) + if first_gradle_dir and first_gradle_dir != '.': + return first_gradle_dir + + return '' + + def main(): global config, options @@ -221,7 +237,6 @@ def main(): app = metadata.App() app.UpdateCheckMode = "Tags" - root_dir = None build_dir = None local_metadata_files = common.get_local_metadata_files() @@ -233,12 +248,11 @@ def main(): app.AutoName = os.path.basename(os.getcwd()) app.RepoType = 'git' - root_dir = get_subdir(os.getcwd()) if os.path.exists('build.gradle'): build.gradle = ['yes'] import git - repo = git.repo.Repo(root_dir) # git repo + repo = git.repo.Repo(os.getcwd()) # git repo for remote in git.Remote.iter_items(repo): if remote.name == 'origin': url = repo.remotes.origin.url @@ -250,7 +264,7 @@ def main(): build.commit = binascii.hexlify(bytearray(repo.head.commit.binsha)) write_local_file = True elif options.url: - root_dir, build_dir = get_metadata_from_url(app, options.url) + build_dir = get_metadata_from_url(app, options.url) build.commit = '?' build.disable = 'Generated by import.py - check/set version fields and commit id' write_local_file = False @@ -258,9 +272,9 @@ def main(): raise FDroidException("Specify project url.") # Extract some information... - paths = common.manifest_paths(root_dir, []) + paths = get_all_gradle_and_manifests(build_dir) + subdir = get_gradle_subdir(build_dir, paths) if paths: - versionName, versionCode, package = common.parse_androidmanifests(paths, app) if not package: raise FDroidException(_("Couldn't find package ID")) @@ -269,17 +283,7 @@ def main(): if not versionCode: logging.warn(_("Couldn't find latest version code")) else: - spec = os.path.join(root_dir, 'buildozer.spec') - if os.path.exists(spec): - defaults = {'orientation': 'landscape', 'icon': '', - 'permissions': '', 'android.api': "18"} - bconfig = ConfigParser(defaults, allow_no_value=True) - bconfig.read(spec) - package = bconfig.get('app', 'package.domain') + '.' + bconfig.get('app', 'package.name') - versionName = bconfig.get('app', 'version') - versionCode = None - else: - raise FDroidException(_("No android or kivy project could be found. Specify --subdir?")) + raise FDroidException(_("No gradle project could be found. Specify --subdir?")) # Make sure it's actually new... if package in apps: @@ -290,13 +294,16 @@ def main(): build.versionCode = versionCode or '0' # TODO heinous but this is still a str if options.subdir: build.subdir = options.subdir + elif subdir: + build.subdir = subdir + if options.license: app.License = options.license if options.categories: app.Categories = options.categories.split(',') - if os.path.exists(os.path.join(root_dir, 'jni')): + if os.path.exists(os.path.join(subdir, 'jni')): build.buildjni = ['yes'] - if os.path.exists(os.path.join(root_dir, 'build.gradle')): + if os.path.exists(os.path.join(subdir, 'build.gradle')): build.gradle = ['yes'] metadata.post_metadata_parse(app) diff --git a/tests/common.TestCase b/tests/common.TestCase index 3d90707a..bb4d78a6 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -816,6 +816,30 @@ class CommonTest(unittest.TestCase): self.assertEqual(('0.94-test', '940', 'org.fdroid.fdroid'), fdroidserver.common.parse_androidmanifests(paths, app)) + app = fdroidserver.metadata.App() + app.AutoName = 'android-chat' + app.RepoType = 'git' + url = 'https://github.com/wildfirechat/android-chat.git' + app.SourceCode = url.rstrip('.git') + app.Repo = url + paths = [ + os.path.join('source-files', 'cn.wildfirechat.chat', 'avenginekit', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'client', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'client', 'src', 'main', 'AndroidManifest.xml'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'emojilibrary', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'gradle', 'build_libraries.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'imagepicker', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'mars-core-release', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'push', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'settings.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'chat', 'build.gradle'), + ] + for path in paths: + self.assertTrue(os.path.isfile(path)) + self.assertEqual(('0.6.9', '23', 'cn.wildfirechat.chat'), + fdroidserver.common.parse_androidmanifests(paths, app)) + def test_parse_androidmanifests_ignore(self): app = fdroidserver.metadata.App() app.id = 'org.fdroid.fdroid' diff --git a/tests/import.TestCase b/tests/import.TestCase index 18852628..4a8936ac 100755 --- a/tests/import.TestCase +++ b/tests/import.TestCase @@ -7,8 +7,11 @@ import logging import optparse import os import requests +import shutil import sys +import tempfile import unittest +from unittest import mock localmodule = os.path.realpath( os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')) @@ -48,11 +51,76 @@ class ImportTest(unittest.TestCase): app = fdroidserver.metadata.App() app.UpdateCheckMode = "Tags" - root_dir, src_dir = import_proxy.get_metadata_from_url(app, url) + build_dir = import_proxy.get_metadata_from_url(app, url) self.assertEqual(app.RepoType, 'git') self.assertEqual(app.WebSite, 'https://gitlab.com/fdroid/ci-test-app') self.assertEqual(app.Repo, 'https://gitlab.com/fdroid/ci-test-app.git') + def test_get_all_gradle_and_manifests(self): + a = import_proxy.get_all_gradle_and_manifests(os.path.join('source-files', 'cn.wildfirechat.chat')) + paths = [ + os.path.join('source-files', 'cn.wildfirechat.chat', 'avenginekit', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'chat', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'client', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'client', 'src', 'main', 'AndroidManifest.xml'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'emojilibrary', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'gradle', 'build_libraries.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'imagepicker', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'mars-core-release', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'push', 'build.gradle'), + os.path.join('source-files', 'cn.wildfirechat.chat', 'settings.gradle'), + ] + self.assertEqual(sorted(paths), sorted(a)) + + def test_get_gradle_subdir(self): + subdirs = { + 'cn.wildfirechat.chat': 'chat', + 'com.anpmech.launcher': 'app', + 'org.tasks': 'app', + 'ut.ewh.audiometrytest': 'app', + } + for f in ('cn.wildfirechat.chat', 'com.anpmech.launcher', 'org.tasks', 'ut.ewh.audiometrytest'): + build_dir = os.path.join('source-files', f) + paths = import_proxy.get_all_gradle_and_manifests(build_dir) + logging.info(paths) + subdir = import_proxy.get_gradle_subdir(build_dir, paths) + self.assertEqual(subdirs[f], subdir) + + def test_get_metadata_from_url(self): + testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir) + os.chdir(testdir) + os.mkdir(os.path.join(testdir, 'tmp')) + tmp_importer = os.path.join(testdir, 'tmp', 'importer') + data = ( + ('cn.wildfirechat.chat', 'https://github.com/wildfirechat/android-chat', '0.6.9', '23'), + ('com.anpmech.launcher', 'https://github.com/KeikaiLauncher/KeikaiLauncher', 'Unknown', None), + ('ut.ewh.audiometrytest', 'https://github.com/ReeceStevens/ut_ewh_audiometer_2014', '1.65', '14'), + ) + for appid, url, vn, vc in data: + shutil.rmtree(tmp_importer, ignore_errors=True) + shutil.copytree(os.path.join(self.basedir, 'source-files', appid), + tmp_importer) + + app = fdroidserver.metadata.App() + app.UpdateCheckMode = "Tags" + with mock.patch('fdroidserver.common.getvcs', + lambda a, b, c: fdroidserver.common.vcs(url, testdir)): + with mock.patch('fdroidserver.common.vcs.gotorevision', + lambda s, rev: None): + with mock.patch('shutil.rmtree', lambda a: None): + build_dir = import_proxy.get_metadata_from_url(app, url) + self.assertEqual('git', app.RepoType) + self.assertEqual(url, app.Repo) + self.assertEqual(url, app.SourceCode) + logging.info(build_dir) + paths = import_proxy.get_all_gradle_and_manifests(build_dir) + self.assertNotEqual(paths, []) + versionName, versionCode, package = fdroidserver.common.parse_androidmanifests(paths, app) + self.assertEqual(vn, versionName) + self.assertEqual(vc, versionCode) + self.assertEqual(appid, package) + if __name__ == "__main__": os.chdir(os.path.dirname(__file__)) diff --git a/tests/import_proxy.py b/tests/import_proxy.py index ce24a50f..f3c4fef8 100644 --- a/tests/import_proxy.py +++ b/tests/import_proxy.py @@ -18,7 +18,9 @@ class Options: module = __import__('fdroidserver.import') for name, obj in inspect.getmembers(module): if name == 'import': + get_all_gradle_and_manifests = obj.get_all_gradle_and_manifests get_metadata_from_url = obj.get_metadata_from_url + get_gradle_subdir = obj.get_gradle_subdir obj.options = Options() options = obj.options break diff --git a/tests/scanner.TestCase b/tests/scanner.TestCase index 6e94d5fb..b8f46af9 100755 --- a/tests/scanner.TestCase +++ b/tests/scanner.TestCase @@ -28,6 +28,7 @@ class ScannerTest(unittest.TestCase): def test_scan_source_files(self): source_files = os.path.join(self.basedir, 'source-files') projects = { + 'cn.wildfirechat.chat': 4, 'Zillode': 1, 'firebase-suspect': 1, 'org.mozilla.rocket': 3, diff --git a/tests/source-files/cn.wildfirechat.chat/avenginekit/build.gradle b/tests/source-files/cn.wildfirechat.chat/avenginekit/build.gradle new file mode 100644 index 00000000..02955512 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/avenginekit/build.gradle @@ -0,0 +1,2 @@ +configurations.maybeCreate("default") +artifacts.add("default", file('avenginekit.aar')) \ No newline at end of file diff --git a/tests/source-files/cn.wildfirechat.chat/build.gradle b/tests/source-files/cn.wildfirechat.chat/build.gradle new file mode 100644 index 00000000..acc41375 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/build.gradle @@ -0,0 +1,41 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + maven { + url "http://developer.huawei.com/repo/" + } + + maven { url 'https://jitpack.io' } + maven { url 'https://dl.bintray.com/jenly/maven' } + } + configurations { + all { + resolutionStrategy { + //force "android.arch.lifecycle:runtime:1.1.1" + } + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/tests/source-files/cn.wildfirechat.chat/chat/build.gradle b/tests/source-files/cn.wildfirechat.chat/chat/build.gradle new file mode 100644 index 00000000..f2503356 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/chat/build.gradle @@ -0,0 +1,115 @@ +apply plugin: 'com.android.application' + +android { + signingConfigs { + wfc { + keyAlias 'wfc' + keyPassword 'wildfirechat' + storeFile file('../wfc.keystore') + storePassword 'wildfirechat' + } + } + compileSdkVersion 28 + aaptOptions.cruncherEnabled = false + aaptOptions.useNewCruncher = false + defaultConfig { + applicationId "cn.wildfirechat.chat" + minSdkVersion 16 + targetSdkVersion 28 //当targetversion大于23时,需要使用fileprovider + versionCode 23 + versionName "0.6.9" + multiDexEnabled true + javaCompileOptions { + annotationProcessorOptions { + includeCompileClasspath true + } + } + signingConfig signingConfigs.wfc + +// buildConfigField("String", "BuglyId", '"34490ba79f"') + + ndk { + abiFilters "armeabi-v7a", 'x86', 'x86_64' // ,'armeabi', 'arm64-v8a', 'x86', 'x86_64' + } + } + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.wfc + } + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.wfc + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + lintOptions { + abortOnError false + } + sourceSets { + main { + // wfc kit start + jniLibs.srcDirs += ['libs', 'kit/libs'] + res.srcDirs += ['kit/src/main/res', 'kit/src/main/res-av'] + assets.srcDirs += ['kit/src/main/assets'] + java.srcDirs += ['kit/src/main/java'] + // wfc kit end + } + } + productFlavors { + } + + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation files('libs/TencentLocationSDK_v4.9.7.12_r247861_161205_1104.jar') + implementation files('libs/TencentMapSDK_Raster_v_1.2.7_51ae0e7.jar') + implementation files('libs/TencentSearch1.1.3.jar') + + implementation 'com.tencent.bugly:crashreport:2.8.6.0' + implementation 'com.tencent.bugly:nativecrashreport:3.6.0.1' + implementation 'com.lqr.adapter:library:1.0.2' + implementation 'com.jaeger.statusbaruitl:library:1.3.5' + implementation project(':push') + + // wfc kit start + implementation fileTree(include: ['*.jar'], dir: 'kit/libs') + implementation 'androidx.appcompat:appcompat:1.1.0-beta01' + implementation 'com.google.android.material:material:1.1.0-alpha10' + implementation 'cjt.library.wheel:camera:1.1.9' + implementation 'com.kyleduo.switchbutton:library:1.4.4' + implementation 'com.squareup.okhttp3:okhttp:3.11.0' + implementation 'com.squareup.okio:okio:1.14.0' + implementation 'com.jakewharton:butterknife:10.2.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0' + implementation 'com.github.bumptech.glide:glide:4.8.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' + implementation 'com.github.chrisbanes:PhotoView:2.3.0' + implementation 'org.webrtc:google-webrtc:1.0.21929' + implementation 'com.afollestad.material-dialogs:core:0.9.6.0' + implementation 'q.rorbin:badgeview:1.1.3' + implementation 'com.google.code.gson:gson:2.8.5' + + // ViewModel and LiveData + def lifecycle_version = '2.2.0-alpha05' + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" + + implementation project(':client') + implementation project(':avenginekit') + implementation project(':emojilibrary') + implementation project(':imagepicker') + + implementation 'com.king.zxing:zxing-lite:1.1.1' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + // kit wfc end +} diff --git a/tests/source-files/cn.wildfirechat.chat/client/build.gradle b/tests/source-files/cn.wildfirechat.chat/client/build.gradle new file mode 100644 index 00000000..ce41d062 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/client/build.gradle @@ -0,0 +1,57 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.github.dcendents.android-maven' + +group = 'com.github.wildfirechat' + +android { + compileSdkVersion 28 + + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + // testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + ndk { + // TODO: changes this for your application if needed + moduleName = "mmnet" + //abiFilter "armeabi" //去掉armeabi架构,armeabi-v7a可以兼容armeabi架构。 + abiFilter "armeabi-v7a" + abiFilter "arm64-v8a" + abiFilter "x86" + abiFilter "x86_64" + } + } + + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + + lintOptions { + abortOnError false + } + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } +} + + +dependencies { + api project(':mars-core-release') + def lifecycle_version = '2.0.0-beta01' + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" +} diff --git a/tests/source-files/cn.wildfirechat.chat/client/src/main/AndroidManifest.xml b/tests/source-files/cn.wildfirechat.chat/client/src/main/AndroidManifest.xml new file mode 100644 index 00000000..0c056938 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/client/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/source-files/cn.wildfirechat.chat/emojilibrary/build.gradle b/tests/source-files/cn.wildfirechat.chat/emojilibrary/build.gradle new file mode 100755 index 00000000..50ea5f5a --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/emojilibrary/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + android { + lintOptions { + abortOnError false + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.0-beta01' +} \ No newline at end of file diff --git a/tests/source-files/cn.wildfirechat.chat/gradle/build_libraries.gradle b/tests/source-files/cn.wildfirechat.chat/gradle/build_libraries.gradle new file mode 100644 index 00000000..42020666 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/gradle/build_libraries.gradle @@ -0,0 +1,42 @@ +def checkExecResult(execResult) { + if (execResult) { + if (execResult.getExitValue() != 0) { + throw new GradleException('Non-zero exit value: ' + execResult.getExitValue()) + } + + } else { + throw new GradleException('Returned a null execResult object') + } +} + +task buildLibrariesForAndroid(type: Exec) { + workingDir '../' + + def sdkDir = System.env.ANDROID_HOME + def ndkDir = System.env.ANDROID_NDK_HOME + + if (rootProject.file("local.properties").exists()) { + Properties properties = new Properties() + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + sdkDir = properties.getProperty('sdk.dir') + ndkDir = properties.getProperty('ndk.dir') + } + + def path = System.env.PATH + + def envMap = [ + 'ANDROID_HOME' : sdkDir, + 'ANDROID_NDK_HOME': ndkDir, + '_ARCH_' : 'armeabi', + 'PATH' : ndkDir, + ] + environment envMap + + print envMap + + commandLine 'python', 'build_android.py', '2', 'armeabi' + + doLast { + checkExecResult(execResult) + } +} diff --git a/tests/source-files/cn.wildfirechat.chat/imagepicker/build.gradle b/tests/source-files/cn.wildfirechat.chat/imagepicker/build.gradle new file mode 100755 index 00000000..66b153a1 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/imagepicker/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.0.0-beta01' + implementation 'com.github.chrisbanes.photoview:library:1.2.4' + implementation 'com.github.bumptech.glide:glide:4.8.0' +} diff --git a/tests/source-files/cn.wildfirechat.chat/mars-core-release/build.gradle b/tests/source-files/cn.wildfirechat.chat/mars-core-release/build.gradle new file mode 100644 index 00000000..65e8c7fe --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/mars-core-release/build.gradle @@ -0,0 +1,2 @@ +configurations.maybeCreate("default") +artifacts.add("default", file('mars-core-release.aar')) \ No newline at end of file diff --git a/tests/source-files/cn.wildfirechat.chat/push/build.gradle b/tests/source-files/cn.wildfirechat.chat/push/build.gradle new file mode 100644 index 00000000..26f5cbe2 --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/push/build.gradle @@ -0,0 +1,55 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + manifestPlaceholders = [ + + MI_APP_ID : "2882303761517722456", + MI_APP_KEY : "5731772292456", + + HMS_APP_ID : "100221325", + + MEIZU_APP_ID : "113616", + MEIZU_APP_KEY: "fcd886f51c144b45b87a67a28e2934d1", + + VIVO_APP_ID : "12918", + VIVO_APP_KEY : "c42feb05-de6c-427d-af55-4f902d9e0a75" + ] + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'com.huawei.android.hms:push:2.5.3.305' + implementation 'com.huawei.android.hms:base:2.5.3.305' + + implementation 'androidx.appcompat:appcompat:1.0.0-beta01' + implementation project(':client') + implementation 'com.meizu.flyme.internet:push-internal:3.4.2@aar' + + def lifecycle_version = '2.2.0-alpha05' + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" +} diff --git a/tests/source-files/cn.wildfirechat.chat/settings.gradle b/tests/source-files/cn.wildfirechat.chat/settings.gradle new file mode 100644 index 00000000..e98e916c --- /dev/null +++ b/tests/source-files/cn.wildfirechat.chat/settings.gradle @@ -0,0 +1,7 @@ +include ':client', + ':push', + ':chat', + ':mars-core-release', + ':emojilibrary', + ':imagepicker', + ':avenginekit' diff --git a/tests/source-files/com.anpmech.launcher/app/build.gradle b/tests/source-files/com.anpmech.launcher/app/build.gradle new file mode 100644 index 00000000..97d2e4fc --- /dev/null +++ b/tests/source-files/com.anpmech.launcher/app/build.gradle @@ -0,0 +1,76 @@ +/* + * Copyright 2015-2017 Hayai Software + * Copyright 2018 The KeikaiLauncher Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id 'com.android.application' + id 'pl.allegro.tech.build.axion-release' version '1.8.1' +} + +scmVersion { + tag { + prefix = '' + } +} + +/** + * Takes version {@code major.minor.patch[-suffix]} and returns numeric versionCode based on it + * Example: {@code 1.2.3-SNAPSHOT} will return {@code 1002003} + */ +static int versionCode(String versionName) { + def matcher = (versionName =~ /(\d+)\.(\d+)\.(\d+).*/) + return matcher.matches() ? + matcher.collect { version, major, minor, patch -> + major.toInteger() * 10000 + minor.toInteger() * 100 + patch.toInteger() + }.head() : + -1 +} + +def androidVersion = [ + name: scmVersion.version, + code: versionCode(scmVersion.version), +] + +android { + compileSdkVersion 28 + defaultConfig { + applicationId 'com.anpmech.launcher' + minSdkVersion 15 + targetSdkVersion 28 + versionName androidVersion.name + versionCode androidVersion.code + } + lintOptions { + abortOnError false + } + buildTypes { + all { + buildConfigField("String", "GITHUB_USER", "\"KeikaiLauncher\"") + buildConfigField("String", "GITHUB_PROJECT", "\"KeikaiLauncher\"") + } + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt' + } + debug { + versionNameSuffix "-debug" + } + } + dependencies { + implementation 'com.android.support:support-annotations:28.0.0' + } +} + +dependencies { +} diff --git a/tests/source-files/com.anpmech.launcher/app/src/main/AndroidManifest.xml b/tests/source-files/com.anpmech.launcher/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..77c4e22f --- /dev/null +++ b/tests/source-files/com.anpmech.launcher/app/src/main/AndroidManifest.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/source-files/com.anpmech.launcher/build.gradle b/tests/source-files/com.anpmech.launcher/build.gradle new file mode 100644 index 00000000..a92bf663 --- /dev/null +++ b/tests/source-files/com.anpmech.launcher/build.gradle @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2017 Hayai Software + * Copyright 2018 The KeikaiLauncher Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + } +} + +allprojects { + repositories { + jcenter() + google() + } +} + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.owasp:dependency-check-gradle:5.2.4' + } +} +apply plugin: 'org.owasp.dependencycheck' +dependencyCheck { + format='JSON' +} diff --git a/tests/source-files/com.anpmech.launcher/settings.gradle b/tests/source-files/com.anpmech.launcher/settings.gradle new file mode 100644 index 00000000..4d775aa7 --- /dev/null +++ b/tests/source-files/com.anpmech.launcher/settings.gradle @@ -0,0 +1,16 @@ +/* + * Copyright 2015-2017 Hayai Software + * Copyright 2018 The KeikaiLauncher Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ + +include ':app' diff --git a/tests/source-files/org.tasks/app/build.gradle.kts b/tests/source-files/org.tasks/app/build.gradle.kts new file mode 100644 index 00000000..23b0524d --- /dev/null +++ b/tests/source-files/org.tasks/app/build.gradle.kts @@ -0,0 +1,225 @@ +import com.android.build.gradle.api.ApplicationVariant + +plugins { + id("com.android.application") + id("checkstyle") + id("io.fabric") + id("com.cookpad.android.licensetools") + kotlin("android") +} + +repositories { + jcenter() + google() + maven(url = "https://jitpack.io") +} + +android { + bundle { + language { + enableSplit = false + } + } + + dexOptions { + javaMaxHeapSize = "2g" + } + + lintOptions { + setLintConfig(file("lint.xml")) + textOutput("stdout") + textReport = true + } + + compileSdkVersion(Versions.targetSdk) + + defaultConfig { + testApplicationId = "org.tasks.test" + applicationId = "org.tasks" + versionCode = 651 + versionName = "7.6.1" + targetSdkVersion(Versions.targetSdk) + minSdkVersion(Versions.minSdk) + multiDexEnabled = true + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + javaCompileOptions { + annotationProcessorOptions { + arguments["room.schemaLocation"] = "$projectDir/schemas" + } + } + } + + signingConfigs { + create("release") { + val tasksKeyAlias: String? by project + val tasksStoreFile: String? by project + val tasksStorePassword: String? by project + val tasksKeyPassword: String? by project + + keyAlias = tasksKeyAlias + storeFile = file(tasksStoreFile?: "none") + storePassword = tasksStorePassword + keyPassword = tasksKeyPassword + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + @Suppress("LocalVariableName") + buildTypes { + getByName("debug") { + val tasks_mapbox_key_debug: String? by project + val tasks_google_key_debug: String? by project + + applicationIdSuffix = ".debug" + resValue("string", "mapbox_key", tasks_mapbox_key_debug ?: "") + resValue("string", "google_key", tasks_google_key_debug ?: "") + isTestCoverageEnabled = true + } + getByName("release") { + val tasks_mapbox_key: String? by project + val tasks_google_key: String? by project + + resValue("string", "mapbox_key", tasks_mapbox_key ?: "") + resValue("string", "google_key", tasks_google_key ?: "") + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard.pro") + signingConfig = signingConfigs.getByName("release") + } + } + + applicationVariants.all(object : Action { + override fun execute(variant: ApplicationVariant) { + variant.resValue("string", "app_package", variant.applicationId) + } + }) + + flavorDimensions("store") + + productFlavors { + create("generic") { + setDimension("store") + proguardFile("generic.pro") + } + create("googleplay") { + setDimension("store") + } + create("amazon") { + setDimension("store") + } + } + + viewBinding { + isEnabled = true + } + + dataBinding { + isEnabled = true + } + + packagingOptions { + exclude("META-INF/*.kotlin_module") + } +} + +configure { + configFile = project.file("google_checks.xml") + toolVersion = "8.16" +} + +configurations.all { + exclude(group = "com.google.guava", module = "guava-jdk5") + exclude(group = "org.apache.httpcomponents", module = "httpclient") + exclude(group = "com.google.http-client", module = "google-http-client-apache") + resolutionStrategy { + force("com.squareup.okhttp3:okhttp:" + Versions.okhttp) + } +} + +val googleplayImplementation by configurations +val amazonImplementation by configurations + +dependencies { + implementation("com.gitlab.bitfireAT:dav4jvm:1.0") + implementation("com.gitlab.bitfireAT:ical4android:be6d515db8") { + exclude(group = "org.threeten", module = "threetenbp") + } + implementation("com.gitlab.bitfireAT:cert4android:1488e39a66") + + annotationProcessor("com.google.dagger:dagger-compiler:${Versions.dagger}") + implementation("com.google.dagger:dagger:${Versions.dagger}") + + implementation("androidx.room:room-rxjava2:${Versions.room}") + annotationProcessor("androidx.room:room-compiler:${Versions.room}") + implementation("androidx.lifecycle:lifecycle-extensions:2.1.0") + implementation("io.reactivex.rxjava2:rxandroid:2.1.1") + implementation("androidx.paging:paging-runtime:2.1.1") + + annotationProcessor("com.jakewharton:butterknife-compiler:${Versions.butterknife}") + implementation("com.jakewharton:butterknife:${Versions.butterknife}") + + debugImplementation("com.facebook.flipper:flipper:${Versions.flipper}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${Versions.flipper}") + debugImplementation("com.facebook.soloader:soloader:0.8.0") + + debugImplementation("com.squareup.leakcanary:leakcanary-android:${Versions.leakcanary}") + + implementation("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}") + implementation("io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:2.0.0") + implementation("androidx.multidex:multidex:2.0.1") + implementation("me.saket:better-link-movement-method:2.2.0") + implementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}") + implementation("com.google.code.gson:gson:2.8.5") + implementation("com.github.rey5137:material:1.2.5") + implementation("com.nononsenseapps:filepicker:4.2.1") + implementation("com.google.android.material:material:1.1.0-rc01") + implementation("androidx.annotation:annotation:1.1.0") + implementation("androidx.constraintlayout:constraintlayout:2.0.0-beta4") + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") + implementation("com.jakewharton.timber:timber:4.7.1") + implementation("com.jakewharton.threetenabp:threetenabp:1.2.1") + implementation("com.google.guava:guava:27.1-android") + implementation("com.jakewharton:process-phoenix:2.0.0") + implementation("com.google.android.apps.dashclock:dashclock-api:2.0.0") + implementation("com.twofortyfouram:android-plugin-api-for-locale:1.0.2") + implementation("com.rubiconproject.oss:jchronic:0.2.6") { + isTransitive = false + } + implementation("org.scala-saddle:google-rfc-2445:20110304") { + isTransitive = false + } + implementation("com.wdullaer:materialdatetimepicker:4.0.1") + implementation("me.leolin:ShortcutBadger:1.1.22@aar") + implementation("com.google.apis:google-api-services-tasks:v1-rev59-1.25.0") + implementation("com.google.apis:google-api-services-drive:v3-rev188-1.25.0") + implementation("com.google.api-client:google-api-client-android:1.30.7") + implementation("androidx.work:work-runtime:${Versions.work}") + implementation("com.mapbox.mapboxsdk:mapbox-android-sdk:7.3.0") + implementation("com.mapbox.mapboxsdk:mapbox-sdk-services:4.6.0") + + googleplayImplementation("com.crashlytics.sdk.android:crashlytics:${Versions.crashlytics}") + googleplayImplementation("com.google.firebase:firebase-analytics:${Versions.firebase}") + googleplayImplementation("com.google.android.gms:play-services-location:17.0.0") + googleplayImplementation("com.google.android.gms:play-services-maps:17.0.0") + googleplayImplementation("com.google.android.libraries.places:places:2.1.0") + googleplayImplementation("com.android.billingclient:billing:1.2.2") + + amazonImplementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + amazonImplementation("com.crashlytics.sdk.android:crashlytics:${Versions.crashlytics}") + amazonImplementation("com.google.firebase:firebase-core:${Versions.firebase}") + + androidTestAnnotationProcessor("com.google.dagger:dagger-compiler:${Versions.dagger}") + androidTestAnnotationProcessor("com.jakewharton:butterknife-compiler:${Versions.butterknife}") + androidTestImplementation("com.google.dexmaker:dexmaker-mockito:1.2") + androidTestImplementation("com.natpryce:make-it-easy:4.0.1") + androidTestImplementation("androidx.test:runner:1.2.0") + androidTestImplementation("androidx.test:rules:1.2.0") + androidTestImplementation("androidx.test.ext:junit:1.1.1") + androidTestImplementation("androidx.annotation:annotation:1.1.0") +} + +apply(mapOf("plugin" to "com.google.gms.google-services")) diff --git a/tests/source-files/org.tasks/build.gradle b/tests/source-files/org.tasks/build.gradle new file mode 100644 index 00000000..2edd2b70 --- /dev/null +++ b/tests/source-files/org.tasks/build.gradle @@ -0,0 +1,13 @@ + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.owasp:dependency-check-gradle:1.3.2.1' + } +} +apply plugin: 'org.owasp.dependencycheck' +dependencyCheck { + format='JSON' +} diff --git a/tests/source-files/org.tasks/build.gradle.kts b/tests/source-files/org.tasks/build.gradle.kts new file mode 100644 index 00000000..f766cea2 --- /dev/null +++ b/tests/source-files/org.tasks/build.gradle.kts @@ -0,0 +1,26 @@ +buildscript { + repositories { + jcenter() + google() + maven("https://maven.fabric.io/public") + } + + dependencies { + classpath("com.android.tools.build:gradle:3.6.0-rc01") + classpath("com.google.gms:google-services:4.3.3") + // https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin + classpath("io.fabric.tools:gradle:1.31.2") + classpath("com.github.ben-manes:gradle-versions-plugin:0.27.0") + classpath("com.cookpad.android.licensetools:license-tools-plugin:1.7.0") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}") + } +} + +plugins { + id("com.github.ben-manes.versions") version "0.21.0" +} + +tasks.getByName("wrapper") { + gradleVersion = "5.6.4" + distributionType = Wrapper.DistributionType.ALL +} diff --git a/tests/source-files/org.tasks/buildSrc/build.gradle.kts b/tests/source-files/org.tasks/buildSrc/build.gradle.kts new file mode 100644 index 00000000..c39a297b --- /dev/null +++ b/tests/source-files/org.tasks/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + jcenter() +} \ No newline at end of file diff --git a/tests/source-files/org.tasks/settings.gradle.kts b/tests/source-files/org.tasks/settings.gradle.kts new file mode 100644 index 00000000..15a801b1 --- /dev/null +++ b/tests/source-files/org.tasks/settings.gradle.kts @@ -0,0 +1 @@ +include(":app") diff --git a/tests/source-files/ut.ewh.audiometrytest/app/src/main/AndroidManifest.xml b/tests/source-files/ut.ewh.audiometrytest/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..1ef6bb12 --- /dev/null +++ b/tests/source-files/ut.ewh.audiometrytest/app/src/main/AndroidManifest.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/source-files/ut.ewh.audiometrytest/build.gradle b/tests/source-files/ut.ewh.audiometrytest/build.gradle new file mode 100644 index 00000000..a90b6488 --- /dev/null +++ b/tests/source-files/ut.ewh.audiometrytest/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0-rc4' + } +} + +allprojects { + repositories { + mavenCentral() + } +} + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.owasp:dependency-check-gradle:1.3.2.1' + } +} +apply plugin: 'org.owasp.dependencycheck' +dependencyCheck { + format='JSON' +} diff --git a/tests/source-files/ut.ewh.audiometrytest/settings.gradle b/tests/source-files/ut.ewh.audiometrytest/settings.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/tests/source-files/ut.ewh.audiometrytest/settings.gradle @@ -0,0 +1 @@ +include ':app' From e9a6c84efd7acfb6c1b53bbf3439d2f569e420ad Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 3 Feb 2020 12:39:41 +0100 Subject: [PATCH 2/5] import: split URL parsing from code cloning This makes things testable and easier to follow. --- fdroidserver/import.py | 38 ++++++++++++++++++++++---------------- tests/import.TestCase | 12 +++++------- tests/import_proxy.py | 3 ++- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/fdroidserver/import.py b/fdroidserver/import.py index 5d0ebfcd..99f4c214 100644 --- a/fdroidserver/import.py +++ b/fdroidserver/import.py @@ -89,12 +89,9 @@ config = None options = None -def get_metadata_from_url(app, url): +def get_app_from_url(url): - tmp_dir = 'tmp' - if not os.path.isdir(tmp_dir): - logging.info(_("Creating temporary directory")) - os.makedirs(tmp_dir) + app = metadata.App() # Figure out what kind of project it is... projecttype = None @@ -162,18 +159,25 @@ def get_metadata_from_url(app, url): or ' ' in repo): raise FDroidException("Repo address '{0}' does not seem to be valid".format(repo)) - # Get a copy of the source so we can extract some info... - logging.info('Getting source from ' + repotype + ' repo at ' + repo) - build_dir = os.path.join(tmp_dir, 'importer') - if os.path.exists(build_dir): - shutil.rmtree(build_dir) - vcs = common.getvcs(repotype, repo, build_dir) - vcs.gotorevision(options.rev) app.RepoType = repotype app.Repo = repo - return build_dir + return app + +def clone_to_tmp_dir(app): + tmp_dir = 'tmp' + if not os.path.isdir(tmp_dir): + logging.info(_("Creating temporary directory")) + os.makedirs(tmp_dir) + + tmp_dir = os.path.join(tmp_dir, 'importer') + if os.path.exists(tmp_dir): + shutil.rmtree(tmp_dir) + vcs = common.getvcs(app.RepoType, app.Repo, tmp_dir) + vcs.gotorevision(options.rev) + + return tmp_dir def get_all_gradle_and_manifests(build_dir): @@ -234,8 +238,7 @@ def main(): config = common.read_config(options) apps = metadata.read_metadata() - app = metadata.App() - app.UpdateCheckMode = "Tags" + app = None build_dir = None @@ -245,8 +248,10 @@ def main(): build = metadata.Build() if options.url is None and os.path.isdir('.git'): + app = metadata.App() app.AutoName = os.path.basename(os.getcwd()) app.RepoType = 'git' + app.UpdateCheckMode = "Tags" if os.path.exists('build.gradle'): build.gradle = ['yes'] @@ -264,7 +269,8 @@ def main(): build.commit = binascii.hexlify(bytearray(repo.head.commit.binsha)) write_local_file = True elif options.url: - build_dir = get_metadata_from_url(app, options.url) + app = get_app_from_url(options.url) + build_dir = clone_to_tmp_dir(app) build.commit = '?' build.disable = 'Generated by import.py - check/set version fields and commit id' write_local_file = False diff --git a/tests/import.TestCase b/tests/import.TestCase index 4a8936ac..097befcf 100755 --- a/tests/import.TestCase +++ b/tests/import.TestCase @@ -49,9 +49,8 @@ class ImportTest(unittest.TestCase): print('Skipping ImportTest!') return - app = fdroidserver.metadata.App() - app.UpdateCheckMode = "Tags" - build_dir = import_proxy.get_metadata_from_url(app, url) + app = import_proxy.get_app_from_url(url) + import_proxy.clone_to_tmp_dir(app) self.assertEqual(app.RepoType, 'git') self.assertEqual(app.WebSite, 'https://gitlab.com/fdroid/ci-test-app') self.assertEqual(app.Repo, 'https://gitlab.com/fdroid/ci-test-app.git') @@ -87,7 +86,7 @@ class ImportTest(unittest.TestCase): subdir = import_proxy.get_gradle_subdir(build_dir, paths) self.assertEqual(subdirs[f], subdir) - def test_get_metadata_from_url(self): + def test_get_app_from_url(self): testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir) os.chdir(testdir) os.mkdir(os.path.join(testdir, 'tmp')) @@ -102,14 +101,13 @@ class ImportTest(unittest.TestCase): shutil.copytree(os.path.join(self.basedir, 'source-files', appid), tmp_importer) - app = fdroidserver.metadata.App() - app.UpdateCheckMode = "Tags" + app = import_proxy.get_app_from_url(url) with mock.patch('fdroidserver.common.getvcs', lambda a, b, c: fdroidserver.common.vcs(url, testdir)): with mock.patch('fdroidserver.common.vcs.gotorevision', lambda s, rev: None): with mock.patch('shutil.rmtree', lambda a: None): - build_dir = import_proxy.get_metadata_from_url(app, url) + build_dir = import_proxy.clone_to_tmp_dir(app) self.assertEqual('git', app.RepoType) self.assertEqual(url, app.Repo) self.assertEqual(url, app.SourceCode) diff --git a/tests/import_proxy.py b/tests/import_proxy.py index f3c4fef8..afe9544e 100644 --- a/tests/import_proxy.py +++ b/tests/import_proxy.py @@ -18,8 +18,9 @@ class Options: module = __import__('fdroidserver.import') for name, obj in inspect.getmembers(module): if name == 'import': + clone_to_tmp_dir = obj.clone_to_tmp_dir get_all_gradle_and_manifests = obj.get_all_gradle_and_manifests - get_metadata_from_url = obj.get_metadata_from_url + get_app_from_url = obj.get_app_from_url get_gradle_subdir = obj.get_gradle_subdir obj.options = Options() options = obj.options From 1153ac24fd9ecd6acb6b6a93c6aaf0a3e1655893 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 3 Feb 2020 12:42:12 +0100 Subject: [PATCH 3/5] import: overhaul URL validation to use urllib.parse Python provides us a lovely URL parser with some level of validation built in. The parsed URL is then much easier to validate. --- fdroidserver/import.py | 92 +++++++++++++++++------------------------- tests/import.TestCase | 12 +++++- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/fdroidserver/import.py b/fdroidserver/import.py index 99f4c214..7b42b458 100644 --- a/fdroidserver/import.py +++ b/fdroidserver/import.py @@ -22,6 +22,7 @@ import glob import os import re import shutil +import urllib.parse import urllib.request from argparse import ArgumentParser import logging @@ -90,81 +91,64 @@ options = None def get_app_from_url(url): + """Guess basic app metadata from the URL. + + The URL must include a network hostname, unless it is an lp:, + file:, or git/ssh URL. This throws ValueError on bad URLs to + match urlparse(). + + """ + + parsed = urllib.parse.urlparse(url) + invalid_url = False + if not parsed.scheme or not parsed.path: + invalid_url = True app = metadata.App() - - # Figure out what kind of project it is... - projecttype = None - app.WebSite = url # by default, we might override it - if url.startswith('git://'): - projecttype = 'git' - repo = url - repotype = 'git' - app.SourceCode = "" - app.WebSite = "" - elif url.startswith('https://github.com'): - projecttype = 'github' - repo = url - repotype = 'git' + app.Repo = url + if url.startswith('git://') or url.startswith('git@'): + app.RepoType = 'git' + elif parsed.netloc == 'github.com': + app.RepoType = 'git' app.SourceCode = url app.IssueTracker = url + '/issues' - app.WebSite = "" - elif url.startswith('https://gitlab.com/'): - projecttype = 'gitlab' + elif parsed.netloc == 'gitlab.com': # git can be fussy with gitlab URLs unless they end in .git if url.endswith('.git'): url = url[:-4] - repo = url + '.git' - repotype = 'git' - app.WebSite = url - app.SourceCode = url + '/tree/HEAD' - app.IssueTracker = url + '/issues' - elif url.startswith('https://notabug.org/'): - projecttype = 'notabug' - if url.endswith('.git'): - url = url[:-4] - repo = url + '.git' - repotype = 'git' + app.Repo = url + '.git' + app.RepoType = 'git' app.SourceCode = url app.IssueTracker = url + '/issues' - app.WebSite = "" - elif url.startswith('https://bitbucket.org/'): + elif parsed.netloc == 'notabug.org': + if url.endswith('.git'): + url = url[:-4] + app.Repo = url + '.git' + app.RepoType = 'git' + app.SourceCode = url + app.IssueTracker = url + '/issues' + elif parsed.netloc == 'bitbucket.org': if url.endswith('/'): url = url[:-1] - projecttype = 'bitbucket' app.SourceCode = url + '/src' app.IssueTracker = url + '/issues' # Figure out the repo type and adddress... - repotype, repo = getrepofrompage(url) - if not repotype: - raise FDroidException("Unable to determine vcs type. " + repo) + app.RepoType, app.Repo = getrepofrompage(url) elif url.startswith('https://') and url.endswith('.git'): - projecttype = 'git' - repo = url - repotype = 'git' - app.SourceCode = "" - app.WebSite = "" - if not projecttype: - raise FDroidException("Unable to determine the project type. " - + "The URL you supplied was not in one of the supported formats. " - + "Please consult the manual for a list of supported formats, " - + "and supply one of those.") + app.RepoType = 'git' - # Ensure we have a sensible-looking repo address at this point. If not, we - # might have got a page format we weren't expecting. (Note that we - # specifically don't want git@...) - if ((repotype != 'bzr' and (not repo.startswith('http://') - and not repo.startswith('https://') - and not repo.startswith('git://'))) - or ' ' in repo): - raise FDroidException("Repo address '{0}' does not seem to be valid".format(repo)) + if not parsed.netloc and parsed.scheme in ('git', 'http', 'https', 'ssh'): + invalid_url = True + if invalid_url: + raise ValueError(_('"{url}" is not a valid URL!'.format(url=url))) - app.RepoType = repotype - app.Repo = repo + if not app.RepoType: + raise FDroidException("Unable to determine vcs type. " + app.Repo) return app + def clone_to_tmp_dir(app): tmp_dir = 'tmp' if not os.path.isdir(tmp_dir): diff --git a/tests/import.TestCase b/tests/import.TestCase index 097befcf..30b660aa 100755 --- a/tests/import.TestCase +++ b/tests/import.TestCase @@ -52,7 +52,6 @@ class ImportTest(unittest.TestCase): app = import_proxy.get_app_from_url(url) import_proxy.clone_to_tmp_dir(app) self.assertEqual(app.RepoType, 'git') - self.assertEqual(app.WebSite, 'https://gitlab.com/fdroid/ci-test-app') self.assertEqual(app.Repo, 'https://gitlab.com/fdroid/ci-test-app.git') def test_get_all_gradle_and_manifests(self): @@ -86,6 +85,17 @@ class ImportTest(unittest.TestCase): subdir = import_proxy.get_gradle_subdir(build_dir, paths) self.assertEqual(subdirs[f], subdir) + def test_bad_urls(self): + for url in ('asdf', + 'file://thing.git', + 'https:///github.com/my/project', + 'git:///so/many/slashes', + 'ssh:/notabug.org/missing/a/slash', + 'git:notabug.org/missing/some/slashes', + 'https//github.com/bar/baz'): + with self.assertRaises(ValueError): + import_proxy.get_app_from_url(url) + def test_get_app_from_url(self): testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir) os.chdir(testdir) From e037ee5972f2e5d4c34e1261faf2e91c2dc147e0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 4 Feb 2020 00:22:24 +0100 Subject: [PATCH 4/5] import: generate skeleton build fields for react-native and flutter --- fdroidserver/import.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/fdroidserver/import.py b/fdroidserver/import.py index 7b42b458..a7dfaa49 100644 --- a/fdroidserver/import.py +++ b/fdroidserver/import.py @@ -19,14 +19,21 @@ import binascii import glob +import json import os import re import shutil import urllib.parse import urllib.request +import yaml from argparse import ArgumentParser import logging +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader + from . import _ from . import common from . import metadata @@ -296,6 +303,36 @@ def main(): if os.path.exists(os.path.join(subdir, 'build.gradle')): build.gradle = ['yes'] + package_json = os.path.join(build_dir, 'package.json') # react-native + pubspec_yaml = os.path.join(build_dir, 'pubspec.yaml') # flutter + if os.path.exists(package_json): + build.sudo = ['apt-get install npm', 'npm install -g react-native-cli'] + build.init = ['npm install'] + with open(package_json) as fp: + data = json.load(fp) + app.AutoName = data.get('name', app.AutoName) + app.License = data.get('license', app.License) + app.Description = data.get('description', app.Description) + app.WebSite = data.get('homepage', app.WebSite) + app_json = os.path.join(build_dir, 'app.json') + if os.path.exists(app_json): + with open(app_json) as fp: + data = json.load(fp) + app.AutoName = data.get('name', app.AutoName) + if os.path.exists(pubspec_yaml): + with open(pubspec_yaml) as fp: + data = yaml.load(fp, Loader=SafeLoader) + app.AutoName = data.get('name', app.AutoName) + app.License = data.get('license', app.License) + app.Description = data.get('description', app.Description) + build.srclibs = ['flutter@stable'] + build.output = 'build/app/outputs/apk/release/app-release.apk' + build.build = [ + '$$flutter$$/bin/flutter config --no-analytics', + '$$flutter$$/bin/flutter packages pub get', + '$$flutter$$/bin/flutter build apk', + ] + metadata.post_metadata_parse(app) app.builds.append(build) From ad92b4c67873bf3fa94be1c87351a5f83a46158c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 5 Feb 2020 20:30:16 +0100 Subject: [PATCH 5/5] scanner: add --force option for scanning disabled apps/builds --- fdroidserver/scanner.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fdroidserver/scanner.py b/fdroidserver/scanner.py index ad23912e..db990f97 100644 --- a/fdroidserver/scanner.py +++ b/fdroidserver/scanner.py @@ -286,6 +286,8 @@ def main(): parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]") common.setup_global_opts(parser) parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]")) + parser.add_argument("-f", "--force", action="store_true", default=False, + help=_("Force scan of disabled apps and builds.")) metadata.add_metadata_arguments(parser) options = parser.parse_args() metadata.warnings_action = options.W @@ -307,7 +309,7 @@ def main(): for appid, app in apps.items(): - if app.Disabled: + if app.Disabled and not options.force: logging.info(_("Skipping {appid}: disabled").format(appid=appid)) continue @@ -334,7 +336,7 @@ def main(): for build in app.builds: - if build.disable: + if build.disable and not options.force: logging.info("...skipping version %s - %s" % ( build.versionName, build.get('disable', build.commit[1:]))) continue