Compare commits

...

623 commits

Author SHA1 Message Date
Hans-Christoph Steiner
40fbbd2e48 Merge branch 'wire--checksum-to-rclone' into 'master'
deploy: wire up --no-checksum option to rclone functionality

See merge request fdroid/fdroidserver!1705
2025-09-25 14:32:51 +00:00
Hans-Christoph Steiner
4fabdf9290 deploy: wire up --checksum option to rclone functionality
By default `fdroid deploy` uses the checksum to check for changed files.
The rclone code should do the same.
2025-09-25 16:21:50 +02:00
Hans-Christoph Steiner
7c2a0aa6c2 Merge branch 'fix-tests-for-replacing-s3cmd-and-libcloud' into 'master'
Fix tests for replacing s3cmd and libcloud

See merge request fdroid/fdroidserver!1703
2025-09-25 14:21:02 +00:00
paul mayero
ffc0a6cec0 Fix tests for replacing s3cmd and libcloud 2025-09-25 14:21:02 +00:00
Michael Pöhn
bf33fc5d9b Merge branch 'scanner' into 'master'
scanner: fix catalog match

See merge request fdroid/fdroidserver!1692
2025-09-18 11:31:13 +00:00
linsui
5ded08048b scanner: remove asLibraryDependency from catalog accessor 2025-09-18 11:19:32 +00:00
linsui
5f6e59c76d scanner: fix catalog match 2025-09-18 11:19:32 +00:00
linsui
9b8a334dcf Merge branch 'checkupdates-fix-get_upstream_main_branch' into 'master'
checkupdates: fix get_upstream_main_branch() for Debian/forky

See merge request fdroid/fdroidserver!1702
2025-09-18 10:57:09 +00:00
Hans-Christoph Steiner
8b11e098db checkupdates: fix get_upstream_main_branch() for Debian/forky
```
FAIL: test_get_upstream_main_branch (tests.test_checkupdates.CheckupdatesTest.test_get_upstream_main_branch)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builds/fdroid/fdroidserver/tests/test_checkupdates.py", line 509, in test_get_upstream_main_branch
    self.assertEqual(
    ~~~~~~~~~~~~~~~~^
        f'upstream/{testvalue}',
        ^^^^^^^^^^^^^^^^^^^^^^^^
        branch,
        ^^^^^^^
        f'The default branch should be called {testvalue}!',
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
AssertionError: 'upstream/foo' != 'upstream/main'
- upstream/foo
+ upstream/main
 : The default branch should be called foo!
```
2025-09-18 10:52:15 +00:00
Hans-Christoph Steiner
c9c5147cac Merge branch 'user-rclone.conf' into 'master'
deploy: find rclone.conf in the root of the repo

See merge request fdroid/fdroidserver!1701
2025-09-18 10:01:04 +00:00
thefuture
b6d6d46aeb error if repo rclone.conf is not referenced in config.yml 2025-09-18 11:06:04 +02:00
Hans-Christoph Steiner
1f9fb16844 deploy: find rclone.conf in the root of the repo
This enables the same way of managing the config as existed with s3cmd's
s3cfg file.
2025-09-18 11:05:18 +02:00
Hans-Christoph Steiner
0a87deff1c Merge branch 'remove-libcloud-and-s3cmd' into 'master'
Remove libcloud and s3cmd from fdroidserver

Closes #1289 and #1288

See merge request fdroid/fdroidserver!1650
2025-09-17 11:36:13 +00:00
paul mayero
dbd769db9f Remove libcloud and s3cmd from fdroidserver 2025-09-17 11:36:12 +00:00
Hans-Christoph Steiner
a9856cfb92 Merge branch 'spelling-versionCode-versionName' into 'master'
standardize on versionCode/versionName as spelling

See merge request fdroid/fdroidserver!1699
2025-09-17 07:08:00 +00:00
Hans-Christoph Steiner
bbe29abaa3 standardize on versionName as spelling 2025-09-17 06:55:46 +00:00
Hans-Christoph Steiner
1068057524 standardize on versionCode as spelling 2025-09-17 06:55:46 +00:00
linsui
e8d4d8fc6a Merge branch 'maven' into 'master'
scanner: remove tailing / from maven repo address

See merge request fdroid/fdroidserver!1700
2025-09-17 06:50:54 +00:00
linsui
f578684be8 scanner: remove tailing / from maven repo address 2025-09-17 14:37:30 +08:00
Hans-Christoph Steiner
57244dec63 Merge branch 'noversioncode' into 'master'
update: Handle APKs without a version code in their manifest

Closes #1240

See merge request fdroid/fdroidserver!1695
2025-08-26 10:10:51 +00:00
Tobias Mueller
2eb3986ecf update: Handle APKs without a version code in their manifest 2025-08-26 10:10:51 +00:00
Hans-Christoph Steiner
d4ad523dd2 Merge branch '__init__.py-black-format' into 'master'
convert fdroidserver/__init__.py to black format

See merge request fdroid/fdroidserver!1690
2025-08-18 15:48:23 +00:00
Hans-Christoph Steiner
6fff73b678 convert fdroidserver/__init__.py to black format 2025-08-18 15:38:08 +00:00
linsui
fbf8fc54db Merge branch 'patch-1' into 'master'
Sonatype is now Maven Central

See merge request fdroid/fdroidserver!1693
2025-08-18 13:32:29 +00:00
Licaon_Kter
f5f79ac1ea Sonatype is now Maven Central 2025-08-18 13:32:29 +00:00
Michael Pöhn
97e9784d5d Merge branch 'fix-srcname-cache-crash' into 'master'
update: don't crash if src tarball is not present

See merge request fdroid/fdroidserver!1691
2025-07-31 15:31:38 +00:00
Hans-Christoph Steiner
d20a6a5dcf update: don't crash if src tarball is not present 2025-07-29 17:20:11 +02:00
Michael Pöhn
058f0b7f6a Merge branch 'cache-srcname-sha256' into 'master'
update: cache the SHA-256 of the src tarball

Closes #1290

See merge request fdroid/fdroidserver!1686
2025-07-28 21:10:40 +00:00
Hans-Christoph Steiner
e07cdf5f0c update: cache the SHA-256 of the src tarball
closes #1290
2025-07-28 14:11:07 +00:00
Hans-Christoph Steiner
f9d111c8c1 Merge branch 'removeunf' into 'master'
Remove UpstreamNonFree

Closes fdroiddata#2481

See merge request fdroid/fdroidserver!1680
2025-07-28 14:10:18 +00:00
Licaon_Kter
8b54e2b4cf Remove UpstreamNonFree 2025-07-28 15:59:35 +02:00
Hans-Christoph Steiner
d594a683ab Merge branch 'isort' into 'master'
Sort import

See merge request fdroid/fdroidserver!1689
2025-07-26 15:47:48 +00:00
linsui
7a98650ed3 Sort import
ruff check --fix --select I
2025-07-26 15:35:19 +00:00
linsui
b19b8050db Merge branch 'fix-schildichat-fastlane' into 'master'
update: more accurate fastlane subdir/flavor matching

See merge request fdroid/fdroidserver!1687
2025-07-26 12:52:31 +00:00
Hans-Christoph Steiner
6a3758d3c4 update: more accurate fastlane subdir/flavor matching
This should fix Schildichat showing Element X's metadata.
2025-07-26 12:36:32 +00:00
Hans-Christoph Steiner
546821fc3d Merge branch 'scanpath' into 'master'
scanner: report all errors

See merge request fdroid/fdroidserver!1688
2025-07-26 10:44:26 +00:00
linsui
120a1655b4 scanner: report all errors 2025-07-26 18:33:57 +08:00
linsui
19d709edcd Merge branch 'standalone-gradlew-fdroid' into 'master'
make gradlew-fdroid a standalone project

See merge request fdroid/fdroidserver!1684
2025-07-25 17:46:59 +00:00
Hans-Christoph Steiner
5049645003 make gradlew-fdroid a standalone project
https://gitlab.com/fdroid/gradlew-fdroid
2025-07-25 17:46:31 +00:00
Hans-Christoph Steiner
e4b54c9768 Merge branch 'docker-buildserver-always-apt-https' into 'master'
buildserver: always use HTTPS for apt connections in Docker image

See merge request fdroid/fdroidserver!1603
2025-07-23 16:24:56 +00:00
Hans-Christoph Steiner
7988c54d00 buildserver: always use HTTPS for apt connections in Docker image
This configuration has been in use in .gitlab-ci.yml scripts for a while
now and has proven reliable.  This is a "low hanging fruit" improvement.
It provides an extra layer of protection for when their are apt vulns.  And
it makes it much harder to profile what a server/laptop is doing based on
the internet traffic.  The network observer will no longer be able to see
which packages are being downloaded since apt uses HTTP pipelining so size
attacks are not really possible. And HTTPS hides the URLs, filenames,
download contents, etc.
2025-07-23 16:09:20 +00:00
Hans-Christoph Steiner
05c4bf2483 Merge branch 'ci-PUBLISH-to-bookworm' into 'master'
gitlab-ci: update PUBLISH to bookworm since prod has already

See merge request fdroid/fdroidserver!1685
2025-07-23 16:08:48 +00:00
Hans-Christoph Steiner
7e219561b7 gitlab-ci: update PUBLISH to bookworm since prod has already 2025-07-22 21:52:28 +02:00
Hans-Christoph Steiner
6ad3c74bb4 Merge branch 'subdir-fastlane-support' into 'master'
update: support fastlane/ dir in subdir:

See merge request fdroid/fdroidserver!1679
2025-07-17 08:46:27 +00:00
Hans-Christoph Steiner
96c0d928da update: support fastlane/ dir in subdir:
GNU Taler apps use this.
* https://git.taler.net/taler-android.git/tree/merchant-terminal/fastlane/metadata/android/en-US?h=pos-1.0.2
2025-07-16 17:32:49 +02:00
Hans-Christoph Steiner
ba5c78d45f update: fetch Builds one time and reuse 2025-07-16 16:35:58 +02:00
linsui
8f1411607a Merge branch 'update-gradle-job' into 'master'
gitlab-ci: update "gradle" job to only check files when changed

See merge request fdroid/fdroidserver!1682
2025-07-16 12:23:02 +00:00
Hans-Christoph Steiner
97b0b0eaf8
gitlab-ci: update gradle: job to only check files in
While we are at it, also upgrade to Debian/trixie and rules:

this now handles making the merge requests:
https://gitlab.com/fdroid/gradle-transparency-log/-/merge_requests/2
2025-07-16 14:08:54 +02:00
Hans-Christoph Steiner
c6c4764b33 Merge branch 'gradle-release-checksums.py' into 'master'
bot: update to gradle v7.6.6

See merge request fdroid/fdroidserver!1681
2025-07-16 12:06:44 +00:00
fdroid-bot
7946acd52a gradle v8.14.3 2025-07-16 11:52:37 +00:00
linsui
0a91b98aee Merge branch 'gradle' into 'master'
AGP 8.11 requires Gradle 8.13

See merge request fdroid/fdroidserver!1678
2025-07-06 07:30:11 +00:00
linsui
09a51a429b AGP 8.11 requires Gradle 8.13 2025-07-06 07:29:46 +00:00
linsui
47b5ecdc8c Merge branch 'gradle' into 'master'
gradle 8.14.3

See merge request fdroid/fdroidserver!1677
2025-07-05 07:15:55 +00:00
linsui
909864a8c7 gradle 8.14.3 2025-07-05 15:03:27 +08:00
Hans-Christoph Steiner
47b9b24aef Merge branch 'gitlab-ci-pages-needs' into 'master'
gitlab-ci: 'pages' needs 'Build documentation' but it has `changes:`

See merge request fdroid/fdroidserver!1670
2025-06-26 06:55:43 +00:00
Hans-Christoph Steiner
f4f1c003a6 gitlab-ci: 'pages' needs 'Build documentation' but it has changes:
Fixes this error:

> Unable to create pipeline
>
> 'pages' job needs 'Build documentation' job, but 'Build documentation'
> does not exist in the pipeline. This might be because of the only,
> except, or rules keywords. To need a job that sometimes does not exist
> in the pipeline, use needs:optional.
2025-06-26 06:44:56 +00:00
Michael Pöhn
51b55963a5 Merge branch 'only-copy-icons-if-they-changed' into 'master'
only copy icons into repo/ if they changed

See merge request fdroid/fdroidserver!1664
2025-06-25 10:32:06 +00:00
Hans-Christoph Steiner
52c1bcca70 only copy icons into repo/ if they changed
This should make things more efficient and reduce the size of the diffs in
the transparency log.  Using shutil.copy2() preserves metadata.
2025-06-25 09:46:20 +00:00
Hans-Christoph Steiner
8a36e264b4 Merge branch 'merge_weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1676
2025-06-25 08:05:47 +00:00
Hans-Christoph Steiner
d5d65cfabd
make -C locale update 2025-06-25 09:54:03 +02:00
Hans-Christoph Steiner
dcb804f70d enable Bashkir (ba) as supported locale, its at 100% 2025-06-25 09:50:54 +02:00
Zulfar
a0cae97155 Translated using Weblate: Bashkir (ba) by Zulfar <mzulfar20@gmail.com>
Currently translated at 100.0% (579 of 579 strings)

Added translation using Weblate: Bashkir (ba) by Zulfar <mzulfar20@gmail.com>

Co-authored-by: Zulfar <mzulfar20@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ba/
Translation: F-Droid/F-Droid Server
2025-06-25 09:49:50 +02:00
Hans-Christoph Steiner
956cb11f91
gitlab-ci: rm dash from macOS tests, it reliably segfaults
dash rarely changes and is reliably run on Debian in the hooks/pre-commit
job.  So remove it from the macOS job, where it is flaky and hard to
troubleshoot (who has macOS? ;-)

https://gitlab.com/fdroid/fdroidserver/-/jobs/10454622138

```
==============================================================================
run commit hooks
+ echo_header 'run commit hooks'
+ test -x ./hooks/pre-commit
+ ./hooks/pre-commit
WARNING: pydocstyle is not installed, using dummy placeholder!
WARNING: pyflakes is not installed, using dummy placeholder!
WARNING: pycodestyle is not installed, using dummy placeholder!
./hooks/pre-commit: line 111: 20320 Segmentation fault: 11  $DASH -n $f
ERROR: dash tests failed!
```
2025-06-25 09:42:46 +02:00
Hans-Christoph Steiner
193ca5842c
version 2.4.2 2025-06-24 21:52:38 +02:00
Hans-Christoph Steiner
a44364d661
update CHANGELOG.md 2025-06-24 21:52:21 +02:00
Hans-Christoph Steiner
9fffe0aea4 Merge branch 'merge_weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1675
2025-06-24 15:24:31 +00:00
Artyom Rybakov
76eb0611a0 Translated using Weblate: Russian (ru) by Artyom Rybakov <rib.artem@gmail.com>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Artyom Rybakov <rib.artem@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-06-24 17:12:59 +02:00
WaldiS
e21fd0d167 Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>
Currently translated at 100.0% (579 of 579 strings)

Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>

Currently translated at 98.4% (570 of 579 strings)

Co-authored-by: WaldiS <sto@tutanota.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translation: F-Droid/F-Droid Server
2025-06-24 17:12:59 +02:00
Swyter
d5e554dcd6 Translated using Weblate: Spanish (es) by Swyter <swyterzone@gmail.com>
Currently translated at 98.2% (569 of 579 strings)

Translated using Weblate: Spanish (es) by Swyter <swyterzone@gmail.com>

Currently translated at 98.2% (569 of 579 strings)

Co-authored-by: Swyter <swyterzone@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/es/
Translation: F-Droid/F-Droid Server
2025-06-24 17:12:59 +02:00
Hans-Christoph Steiner
e3ee7ed42e Merge branch 'gradle-release-checksums.py' into 'master'
update to gradle v7.6.5

See merge request fdroid/fdroidserver!1674
2025-06-24 15:08:15 +00:00
fdroid-bot
417ec9fe96 gradle v8.14.2 2025-06-24 14:58:15 +00:00
Torsten Grote
a3cd45c3fb Merge branch 'nightly-deploy-fixes' into 'master'
fixes for nightly and deploy, while debugging fdroidclient-nightly

See merge request fdroid/fdroidserver!1672
2025-06-24 12:05:14 +00:00
Hans-Christoph Steiner
d71fba164c nightly: fix bug that clones nightly repo to wrong location
bug introduced in ce018158ee from !1563
2025-06-24 13:08:48 +02:00
Hans-Christoph Steiner
e177520379 nightly: include project's LICENSE in the nightly repo 2025-06-24 13:08:48 +02:00
Hans-Christoph Steiner
10f2a4c592 Merge branch 'gitlab-ci-docker-depends-on-fdroid-build' into 'master'
gitlab-ci: "fdroid build" changes: for "docker" job

Closes docker-executable-fdroidserver#28

See merge request fdroid/fdroidserver!1673
2025-06-24 11:02:38 +00:00
Hans-Christoph Steiner
6b6cc2379c gitlab-ci: "fdroid build" changes: for "docker" job
"docker" depends on "fdroid build", so "fdroid build"'s changes: needs to
include "docker"'s.
2025-06-24 12:56:24 +02:00
Hans-Christoph Steiner
dcd5336138 scanner: fix tests after !1526 2025-06-23 23:10:15 +02:00
Hans-Christoph Steiner
f953146505
version 2.4.1 2025-06-23 22:37:29 +02:00
Hans-Christoph Steiner
e110390b99
update CHANGELOG.md 2025-06-23 22:37:26 +02:00
Hans-Christoph Steiner
fd3f71ad3c
run tests/refresh-SUSS_DEFAULT.py 2025-06-23 22:37:23 +02:00
Hans-Christoph Steiner
336d5381ae Merge branch 'fix-flaky-test' into 'master'
update: change assert to fix flaky tests

See merge request fdroid/fdroidserver!1671
2025-06-23 19:03:27 +00:00
Hans-Christoph Steiner
63298ad2ad update: change assert to fix flaky tests
This was happening often:

```
======================================================================
FAIL: test_strip_and_copy_image_in_file_ctime_changed (tests.test_update.UpdateTest.test_strip_and_copy_image_in_file_ctime_changed)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builds/fdroid/fdroidserver/tests/test_update.py", line 1409, in test_strip_and_copy_image_in_file_ctime_changed
    self.assertNotAlmostEqual(
AssertionError: 1750683024.4857466 == 1750683024.4957466 within 0.01 delta (0.009999990463256836 difference)
```
2025-06-23 15:16:21 +02:00
Torsten Grote
61777e273c Merge branch 'deploy-fix-for-nightly' into 'master'
deploy: use master branch when working complete git-mirror repo

See merge request fdroid/fdroidserver!1666
2025-06-23 13:09:57 +00:00
Hans-Christoph Steiner
53bf6c7ce1 deploy: use master branch when working complete git-mirror repo
The *-nightly git repo always uses the _master_ branch.  The `index_only:`
support maintains a separate local branch since its git repo should be as
small as possible.  The full repo should be maintained for mirrors not
using `index_only:` so that when it force-pushes, it does not need to always
push all the files, only the updated ones.  So the full repo should be
maintained in the _master_ branch, and only the `index_only` mirrors should
have their own branch.

This adds a test case to reproduce this error:
https://gitlab.com/fdroid/fdroidclient/-/jobs/10347168516

This case also applies to any setup that used `servergitmirrors:` before the
`index_only:` feature was added.  This also applies to cases if the repo
maintainer manually clones the *-nightly repo into _fdroid/git-mirror/_
2025-06-23 12:39:15 +00:00
linsui
51c973f15e Merge branch 'buildserver-androguard-from-backports' into 'master'
buildserver: androguard res0/res1 fixes from bookworm-backports

See merge request fdroid/fdroidserver!1667
2025-06-20 10:34:59 +00:00
Hans-Christoph Steiner
894fdb641e buildserver: androguard res0/res1 fixes from bookworm-backports 2025-06-20 10:34:27 +00:00
Hans-Christoph Steiner
d029095641 Merge branch 'merge_weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1669
2025-06-18 21:01:20 +00:00
Bora Atıcı
85dba17d48 Translated using Weblate: Turkish (tr) by Bora Atıcı <boratici.acc@gmail.com>
Currently translated at 99.8% (578 of 579 strings)

Co-authored-by: Bora Atıcı <boratici.acc@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/tr/
Translation: F-Droid/F-Droid Server
2025-06-18 22:49:22 +02:00
Nuri KÜÇÜKLER
57541eb52e Translated using Weblate: Turkish (tr) by Nuri KÜÇÜKLER <enatsek@gmail.com>
Currently translated at 98.6% (571 of 579 strings)

Co-authored-by: Nuri KÜÇÜKLER <enatsek@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/tr/
Translation: F-Droid/F-Droid Server
2025-06-18 22:49:22 +02:00
ssantos
7e8976d9b0 Translated using Weblate: Portuguese (Portugal) (pt_PT) by ssantos <ssantos@web.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translation: F-Droid/F-Droid Server
2025-06-18 22:49:22 +02:00
WaldiS
b6d7e8732b Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>
Currently translated at 98.2% (569 of 579 strings)

Co-authored-by: WaldiS <sto@tutanota.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translation: F-Droid/F-Droid Server
2025-06-18 22:49:22 +02:00
Ecron
2590f00ff0 Translated using Weblate: Catalan (ca) by Ecron <ecron_89@hotmail.com>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Ecron <ecron_89@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
Translation: F-Droid/F-Droid Server
2025-06-18 22:49:22 +02:00
Hans-Christoph Steiner
1135cee8b7 Merge branch 'nightly-GitPython' into 'master'
nightly: switch dep from vcs_git to GitPython

See merge request fdroid/fdroidserver!1563
2025-06-18 16:47:06 +00:00
Hans-Christoph Steiner
76d711ba3c nightly: convert to black format 2025-06-18 18:34:53 +02:00
Hans-Christoph Steiner
b2057a1ce0 nightly: switch dep from vcs_git to GitPython
This code already depends on GitPython, and hopefully the common.vcs* stuff
can eventually go away entirely.  GitPython should provide those bits
already, and they are maintained by someone else.

https://github.com/gitpython-developers/GitPython/pull/2029
2025-06-18 18:34:49 +02:00
Hans-Christoph Steiner
ce018158ee nightly: set up test for git clone function 2025-06-18 18:03:59 +02:00
Hans-Christoph Steiner
d398994ad3 Merge branch 'fix-categories-yml-only-icon' into 'master'
update: If categories.yml only has icon:, then add name:

See merge request fdroid/fdroidserver!1659
2025-06-16 17:25:09 +00:00
Hans-Christoph Steiner
494d811846 update: If cateogories.yml only has icon:, then add name:
E.g. if _categories.yml_ is like:

```yaml
Time:
  icon: time.png
```
2025-06-16 17:13:48 +00:00
Hans-Christoph Steiner
964861eb68 Merge branch 'polish-pylint' into 'master'
polish pylint

See merge request fdroid/fdroidserver!1637
2025-06-16 17:13:27 +00:00
linsui
8c14e44f63 gitlab-ci: show pylint output in log when it fails 2025-06-16 17:08:38 +00:00
Hans-Christoph Steiner
e1a8e1a08a pylint: use default good-names list 2025-06-16 17:08:38 +00:00
Hans-Christoph Steiner
d5bc7a6942 let pylint choose how many CPUs to use 2025-06-16 17:08:38 +00:00
Jochen Sprickerhof
78e6b8f04c Merge branch 'strip-and-copy-check-by-time' into 'master'
update: use ctime/mtime to control _strip_and_copy_image runs

See merge request fdroid/fdroidserver!1665
2025-06-11 19:26:03 +00:00
Hans-Christoph Steiner
59102fb07f update: use ctime/mtime to control _strip_and_copy_image runs
Oftentimes, the file that is copied is stripped, in which case, the file
size is different.  Using a file size check here means it will rerun the
strip and copy every time `fdroid update` is run for any image that needs
to be stripped.  If the source's ctime is newer than the destination, then
the process should run since it is a newly created file.  Even more so with
mtime, since the destination's mtime is reset based on the source's.
2025-06-11 17:33:34 +02:00
Hans-Christoph Steiner
3cb6078059 Merge branch 'lazyconfig' into 'master'
Lazyload environment variables in config.yml

See merge request fdroid/fdroidserver!1645
2025-06-11 13:02:09 +00:00
linsui
cd1630d2f5 Lazyload environment variables in config.yml 2025-06-11 13:02:09 +00:00
linsui
e44fd22199 Merge branch 'gradle' into 'master'
gradlew-fdroid: update AGP required gradle version

See merge request fdroid/fdroidserver!1661
2025-06-10 17:33:49 +00:00
linsui
69003ae65b gradlew-fdroid: update AGP required gradle version 2025-06-10 17:18:35 +00:00
Hans-Christoph Steiner
d4a71cd572 Merge branch 'two-fixes-for-tests' into 'master'
two fixes for the tests

See merge request fdroid/fdroidserver!1657
2025-06-10 17:14:21 +00:00
Hans-Christoph Steiner
721de49104 make_website: only parse repo_pubkey if its needed
This makes writing tests a lot easier, since the test cases no longer need
to provide a value for `repo_pubkey:`.
2025-06-08 20:12:04 +00:00
Hans-Christoph Steiner
677301bc8a gitlab-ci: make gradle job show files with trigger it
For some reason, this logic thinks that this merge request has changed
makebuildserver and/or gradlew-fdroid, though it clearly has not. This
should shed some light on it.

https://gitlab.com/fdroid/fdroidserver/-/jobs/9835383262
2025-06-08 20:12:04 +00:00
linsui
f281068cbf Merge branch 'gradle8142' into 'master'
gradle 8.14.2

See merge request fdroid/fdroidserver!1663
2025-06-08 07:14:18 +00:00
Licaon_Kter
e98f0966e0 gradle 8.14.2 2025-06-08 09:31:16 +03:00
linsui
0885cf3b49 Merge branch 'gradle8141' into 'master'
gradle - 8.14.1

See merge request fdroid/fdroidserver!1660
2025-05-24 07:32:06 +00:00
Licaon_Kter
c70af2503c gradle - 8.14.1 2025-05-24 09:36:38 +03:00
Hans-Christoph Steiner
bd10ee73c1 Merge branch 'deprecate_bzr_svn' into 'master'
Deprecate bzr, hg and git-svn support (attack surface)

See merge request fdroid/fdroidserver!1656
2025-05-23 07:15:12 +00:00
Jochen Sprickerhof
cfc848771d Deprecate bzr, hg and git-svn support (attack surface) 2025-05-23 07:14:42 +00:00
Michael Pöhn
ac90d11906 Merge branch 'funding-manifest-urls' into 'master'
💸 add .well-known/funding-manifest-urls

See merge request fdroid/fdroidserver!1658
2025-05-22 15:31:33 +00:00
Michael Pöhn
7cf1cd1f4c
💸 add .well-known/funding-manifest-urls
This is used by floss.fund to automatically verify that a repository is
indeed owned by the author of the corresponding funding.json file.
2025-05-22 17:29:50 +02:00
Hans-Christoph Steiner
2a939bf87f Merge branch 'flavor' into 'master'
update: match fastlane flavor with all combinations

See merge request fdroid/fdroidserver!1647
2025-05-22 12:59:26 +00:00
linsui
a5d966bf0f calculate all combinations of gradle flavors 2025-05-22 12:24:33 +02:00
linsui
e957583337 common: add calculate_gradle_flavor_combination 2025-05-22 12:24:32 +02:00
linsui
6c054f62ca flavour -> flavor 2025-05-22 12:16:43 +02:00
Hans-Christoph Steiner
0ac750463f Merge branch 'checkupdate' into 'master'
checkupdates: set push ref to HEAD:refs/heads/branch_name

See merge request fdroid/fdroidserver!1638
2025-05-22 10:13:23 +00:00
Hans-Christoph Steiner
8c9b0b3a2a add test case 2025-05-22 12:12:24 +02:00
linsui
243a0475f9 checkupdates: don't create branch with .lock end 2025-05-22 12:12:24 +02:00
linsui
e538c34c32 checkupdates: set push ref to HEAD:refs/heads/branch_name 2025-05-22 12:12:24 +02:00
Hans-Christoph Steiner
e7060011aa Merge branch 'triple-t' into 'master'
Fix handling of Triple-T 1.0.0 graphics

Closes #1260

See merge request fdroid/fdroidserver!1652
2025-05-22 10:11:25 +00:00
Leo Heitmann Ruiz
5f534ea2cb Add test case for Triple-T 1.0.0 graphics 2025-05-22 11:57:57 +02:00
Leo Heitmann Ruiz
ffd4274503 Fix handling of Triple-T 1.0.0 graphics
Unlike screenshots, the featureGraphic, icon, promoGraphic, and tvBanner
should be placed directly in the locale directory instead of in a
dedicated subdirectory (in the F-Droid metadata structure). For version
1.0.0 of the Triple-T structure this currently isn't done. Instead, the
graphics are treated as screenshots are.

To illustrate:

en-US/listing/icon/icon.png
en-US/listing/featureGraphic/play_store_feature_graphic.png

Should end up as:

en-US/icon.png
en-US/featureGraphic.png

But instead they currently end up as:

en-US/icon/icon.png
en-US/featureGraphic/play_store_feature_graphic.png

This patch should fix it.

It seems the erroneous behavior was introduced in
a4169484fd

Closes #1260
2025-05-21 16:57:35 +00:00
Hans-Christoph Steiner
0a8f9ec5fc Merge branch 'SOURCE_DATE_EPOCH' into 'master'
set SOURCE_DATE_EPOCH from app's git otherwise fdroiddata metadata file

See merge request fdroid/fdroidserver!1653
2025-05-20 20:03:48 +00:00
Hans-Christoph Steiner
20b36f1970 SOURCE_DATE_EPOCH from app's git otherwise fdroiddata metadata file
https://reproducible-builds.org/docs/source-date-epoch
2025-05-19 16:31:40 +02:00
linsui
0b6e304922 Merge branch 'gradlew-fdroid-one-more-level' into 'master'
gradlew-fdroid: also search ../../gradle/ for wrapper files

See merge request fdroid/fdroidserver!1655
2025-05-19 08:44:11 +00:00
Hans-Christoph Steiner
9384c5ab70 gradlew-fdroid: also search ../../gradle/ for wrapper files
https://github.com/geteduroam/android-app/pull/139
2025-05-17 00:15:44 +02:00
linsui
7b6767eb50 Merge branch 'no-git-exec-in-update' into 'master'
update: never execute VCS e.g. git

See merge request fdroid/fdroidserver!1630
2025-05-16 07:00:36 +00:00
Hans-Christoph Steiner
4e7bda736c update: never execute VCS e.g. git
Package repos come from untrusted sources, in terms of the buildserver. They
should be handled in VMs and containers as much as possible to avoid
vulnerabilities.  As far as I could tell, `fdroid update` only has a single
place where it executes any VCS system: if there is .fdroid.yml present in
a package repo, then it will fetch the commit ID using git.

For better security properties, this implements a simple function to just
read the files to get that commit ID.  The function that executes git to do
the same thing is relabeled "unsafe".  That is used for status JSON
everywhere, but that runs on fdroiddata.git and fdroidserver.git, which are
trusted repos.

The unsafe version is also used in places where git.Repo() is needed for
other things.
2025-05-12 18:30:03 +02:00
Hans-Christoph Steiner
2a9c8e9644 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1654
2025-05-12 14:44:41 +00:00
M. Fatih Uluçam
da58061c80 Translated using Weblate: Turkish (tr) by "M. Fatih Uluçam" <mulucam@gmail.com>
Currently translated at 94.6% (548 of 579 strings)

Co-authored-by: M. Fatih Uluçam <mulucam@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/tr/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
VfBFan
696df82999 Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Laurent FAVOLE
cc61a3e9e3 Translated using Weblate: French (fr) by Laurent FAVOLE <laurentfavole03@gmail.com>
Currently translated at 99.1% (574 of 579 strings)

Co-authored-by: Laurent FAVOLE <laurentfavole03@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
ssantos
3b78b3cf06 Translated using Weblate: Portuguese (pt) by ssantos <ssantos@web.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Aindriú Mac Giolla Eoin
0e086f5e61 Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Andrey
61943c3f06 Translated using Weblate: Russian (ru) by Andrey <andrey@mailbox.org>
Currently translated at 98.4% (570 of 579 strings)

Co-authored-by: Andrey <andrey@mailbox.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Ihor Hordiichuk
eebbfedee5 Translated using Weblate: Ukrainian (uk) by Ihor Hordiichuk <igor_ck@outlook.com>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Besnik Bleta
1a9ba8e956 Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 97.7% (566 of 579 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2025-05-12 16:29:00 +02:00
Fjuro
dd64d557f2
Translated using Weblate: Czech (cs) by Fjuro <fjuro@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:13 +02:00
Liner Seven
cd0b961e3c
Translated using Weblate: Japanese (ja) by Liner Seven <linour7gmekiblo@gmail.com>
Currently translated at 100.0% (579 of 579 strings)

Translated using Weblate: Japanese (ja) by Liner Seven <linour7gmekiblo@gmail.com>

Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Liner Seven <linour7gmekiblo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:13 +02:00
C. Rüdinger
57ec6a93ed
Translated using Weblate: German (de) by "C. Rüdinger" <Mail-an-CR@web.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: C. Rüdinger <Mail-an-CR@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:13 +02:00
Ceeee
0e752f1ef0
Translated using Weblate: German (de) by Ceeee <marius.romanus@gmx.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Ceeee <marius.romanus@gmx.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:12 +02:00
VfBFan
13166fce05
Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:12 +02:00
Igor Rückert
22af55fb6d
Translated using Weblate: Portuguese (Brazil) (pt_BR) by Igor Rückert <igorruckert@yahoo.com.br>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Igor Rückert <igorruckert@yahoo.com.br>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:12 +02:00
大王叫我来巡山
858edaaa4d
Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:12 +02:00
Максим Горпиніч
f2faeca949
Translated using Weblate: Ukrainian (uk) by Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Currently translated at 100.0% (579 of 579 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-05-11 16:14:11 +02:00
linsui
9e51fa36e5 Merge branch 'upgradedebianvm' into 'master'
Use latest Bookworm images for makebuildserver

See merge request fdroid/fdroidserver!1651
2025-05-08 12:13:25 +00:00
Licaon_Kter
7924888e5a Use latest Bookworm images for makebuildserver 2025-05-08 12:13:25 +00:00
Michael Pöhn
b581d08b6f Merge branch 'optional_config' into 'master'
Make v2 localized config optional

See merge request fdroid/fdroidserver!1649
2025-04-28 11:14:40 +00:00
Jochen Sprickerhof
b83c1aace3
Make v2 localized config optional
Fixes:

Traceback (most recent call last):
  File "/home/fdroid/fdroidserver/fdroid", line 22, in <module>
    fdroidserver.__main__.main()
  File "/home/fdroid/fdroidserver/fdroidserver/__main__.py", line 222, in main
    raise e
  File "/home/fdroid/fdroidserver/fdroidserver/__main__.py", line 203, in main
    mod.main()
  File "/home/fdroid/fdroidserver/fdroidserver/update.py", line 2774, in main
    fdroidserver.index.make(archived_apps, archapks, repodirs[1], True)
  File "/home/fdroid/fdroidserver/fdroidserver/index.py", line 132, in make
    make_v2(
  File "/home/fdroid/fdroidserver/fdroidserver/index.py", line 728, in make_v2
    output["repo"] = v2_repo(repodict, repodir, archive)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/fdroid/fdroidserver/fdroidserver/index.py", line 686, in v2_repo
    repo["icon"] = config["archive" if archive else "repo"]["icon"]
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
KeyError: 'icon'
2025-04-28 08:38:54 +02:00
linsui
561da8f7d1 Merge branch 'gradle' into 'master'
gradle v8.14

See merge request fdroid/fdroidserver!1648
2025-04-26 07:11:12 +00:00
linsui
b93fc6f9da gradle v8.14 2025-04-26 14:41:27 +08:00
Michael Pöhn
265adadaba Merge branch 'include-stages-in-update.json' into 'master'
update: include stages timing info in update.json

See merge request fdroid/fdroidserver!1644
2025-04-23 17:38:27 +00:00
Hans-Christoph Steiner
2a33857fd0
update: include stages timing info in update.json
!1627 missed this, so stages only get included in running.json.  That means
the stages info is only visible while update is running, making it hard to
use.
2025-04-23 19:26:50 +02:00
Hans-Christoph Steiner
3b360f6b80 Merge branch 'repo_key_sha256-valid' into 'master'
lint: repo_key_sha256 to list of valid config keys

See merge request fdroid/fdroidserver!1643
2025-04-16 12:00:33 +00:00
Hans-Christoph Steiner
004103357b gitlab-ci: metadata_v0 test expects no config 2025-04-16 11:11:57 +00:00
Hans-Christoph Steiner
56338cd7d0 repo_key_sha256 to list of valid config keys
fdroidserver!287
2025-04-16 11:11:57 +00:00
Hans-Christoph Steiner
a03cfa3fc2 Merge branch 'patch-1' into 'master'
Clarify libmagic needs to be installed separately

See merge request fdroid/fdroidserver!1640
2025-04-15 16:22:22 +00:00
Benson Muite
c4d46a187f Clarify libmagic needs to be installed separately
See installation instructions at https://pypi.org/project/python-magic/
2025-04-12 14:54:36 +03:00
Hans-Christoph Steiner
692f79ec7d Merge branch 'verify-json-output' into 'master'
`fdroid verify` JSON output

See merge request fdroid/fdroidserver!1632
2025-04-10 15:52:41 +00:00
Hans-Christoph Steiner
17e5a59704 verify: generate <appid>.json files that list all reports 2025-04-10 15:41:46 +00:00
Hans-Christoph Steiner
029636ed61 verify: write verified.json in function to ease testing 2025-04-10 15:41:46 +00:00
Hans-Christoph Steiner
d34d051329 Merge branch 'checkupdate' into 'master'
checkupdates: always print remote message of git push

See merge request fdroid/fdroidserver!1636
2025-04-09 09:58:53 +00:00
linsui
2aba6fd324 checkupdates: always print remote message of git push 2025-04-09 17:48:11 +08:00
Hans-Christoph Steiner
f7cc4812a2 Merge branch 'gitlab-ci-refactor-to-rules' into 'master'
gitlab-ci: migrate to rules: syntax and split up linters into standalone jobs

See merge request fdroid/fdroidserver!1614
2025-04-09 07:31:18 +00:00
Hans-Christoph Steiner
9bcd13bfdd gitlab-ci: add "lint" pre-stage before default "test" stage 2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
7f67a882e7 gitlab-ci: only run Python-only jobs when .py files change 2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
6ad79e3c06 gitlab-ci: move bandit to its own job 2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
3e67bee037 gitlab-ci: move pylint to its own job 2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
3b9d39ac61 gitlab-ci: move shellcheck to own job fenced by changes: 2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
aa9cc14991 gitlab-ci: refactor to rules: and ditch old only: syntax
Adding workflow: is required, otherwise there would be duplicate
pipelines for all users in the @fdroid group.  There would be "branch
pipelines" and "merge request pipelines".  Confusingly, only jobs with
rules: get duplicated.
2025-04-09 07:19:50 +00:00
Hans-Christoph Steiner
07d499ce1f Merge branch 'checkupdate' into 'master'
checkupdates: adjust log level

See merge request fdroid/fdroidserver!1635
2025-04-09 07:01:34 +00:00
linsui
a13dd109d3 checkupdates: adjust log level 2025-04-09 14:51:27 +08:00
Hans-Christoph Steiner
3582a12f18 Merge branch 'clearer-srclibs' into 'master'
vcs_git: clearer error messages for checkrepo()

See merge request fdroid/fdroidserver!1634
2025-04-03 10:25:11 +00:00
Michael Pöhn
69f9f52ba2 drop error prefix when raising VCSException in case retrieving git revision failed 2025-04-03 10:24:46 +00:00
Michael Pöhn
046c527ee8 vcs_git: clearer error messages for checkrepo()
This updates error messages the help identify issues when loading srclibs
and fixes pushing srclibs into build vms/containers.
2025-04-03 10:24:46 +00:00
Michael Pöhn
0d88a94192 metadata: rename srcdir -> srclibs_dir for clarity 2025-04-03 10:24:46 +00:00
Hans-Christoph Steiner
e6cff099f2
delete file I mistakenly included 2025-04-01 11:41:46 +02:00
Hans-Christoph Steiner
bb7394ab3c Merge branch 'start-integrating' into 'master'
start integrating

See merge request fdroid/fdroidserver!1631
2025-03-31 15:34:14 +00:00
Hans-Christoph Steiner
a011b34b97 black format and use returncode directly without != 0 2025-03-31 11:27:13 +02:00
Hans-Christoph Steiner
9a8d80ee6b purge dead code: apk_signer_fingerprint_short 2025-03-31 11:09:07 +02:00
Hans-Christoph Steiner
ef4bbe4612 Merge branch 'use-codeclimate-for-linting-tests' into 'master'
ci: use GitLab Code Quality for linting tests

See merge request fdroid/fdroidserver!1443
2025-03-26 21:33:31 +00:00
proletarius101
90b82ea7e6 ci: use GitLab Code Quality for linting tests 2025-03-26 21:33:31 +00:00
Hans-Christoph Steiner
c98028136a
version 2.4.0 2025-03-25 12:13:57 +01:00
Hans-Christoph Steiner
9fb909b648
update CHANGELOG.md 2025-03-25 12:13:54 +01:00
Hans-Christoph Steiner
0cce48dc04
use black code format for locale/pick-complete-translations.py 2025-03-25 12:13:51 +01:00
Hans-Christoph Steiner
eef237de85
locale/pick-complete-translations.py: use stable sort order for MANIFEST.in 2025-03-25 12:13:47 +01:00
Hans-Christoph Steiner
0c867f908f
make -C locale update 2025-03-25 12:13:43 +01:00
Hans-Christoph Steiner
4cefec9333
fix missing comma in error message 2025-03-25 12:13:22 +01:00
Ihor Hordiichuk
d9046727e5
Translated using Weblate: Ukrainian (uk) by Ihor Hordiichuk <igor_ck@outlook.com>
Currently translated at 100.0% (578 of 578 strings)

Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-03-25 11:23:22 +01:00
Hans-Christoph Steiner
01b948cae7 Merge branch 'publish-and-signatures-cleanup' into 'master'
run test_signatures.py in PUBLISH CI job; clean up signatures/publish tests

See merge request fdroid/fdroidserver!1624
2025-03-25 10:23:16 +00:00
Hans-Christoph Steiner
59474437b3 delete cruft test script 2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
a69340a1ea MANIFEST.in: case-insensitive ASCII byte value for stable sort
```
LC_ALL=C sort --ignore-case --stable --output=MANIFEST.in MANIFEST.in
```
2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
40be283c4a APK for testing maxSdkVersion handling
APK is org.bitbucket.tickytacky.mirrormirror_4.apk disassembled with
`apktool decode`, maxSdkVersion added, then reassembled with `apktool build`
2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
eef3188600 test_signatures: remove unneeded config from tests 2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
d024c8964f convert test_signatures.py to black code format 2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
8f351d8406 publish: convert to black code format 2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
68fad5c7f7 gitlab-ci: delete extraneous keystore key from PUBLISH job
repo_keyalias is set in tests/config.yml, so this does not need to fake the
fdroiddata value.
2025-03-25 10:23:00 +00:00
Hans-Christoph Steiner
5150c721f4 verify_apk_signature: work when options is not set
Then test_signatures.py can run on the PUBLISH CI job.
2025-03-25 10:23:00 +00:00
Michael Pöhn
8d17b67642 Merge branch 'update-stages-in-status-json' into 'master'
update: add execution stages to status JSON

See merge request fdroid/fdroidserver!1627
2025-03-25 09:07:22 +00:00
Hans-Christoph Steiner
acbab69722 update: add execution stages to status JSON
This should help us profile what takes so long in `fdroid update`.  It also
gives feedback so that people can see how close to done it is, or where it
failed.

This is based on how incremental status JSON works for `fdroid build`.
2025-03-24 11:14:40 +01:00
Hans-Christoph Steiner
51487192b9 Merge branch 'fix-found-dexdump' into 'master'
fix _dexdump_found() in test_scanner.py !1621

See merge request fdroid/fdroidserver!1625
2025-03-24 08:24:46 +00:00
Hans-Christoph Steiner
58609aa9f0 fix _dexdump_found() in test_scanner.py !1621
find_sdk_tools_cmd() will throw an exception if it can't find the tool, not
return None.
2025-03-24 08:24:01 +00:00
Hans-Christoph Steiner
0b192a7694 Merge branch 'weblate' into 'master'
update source strings

See merge request fdroid/fdroidserver!1626
2025-03-23 21:00:40 +00:00
Hans-Christoph Steiner
b29ee09fda
locale: full update of source strings 2025-03-23 21:49:34 +01:00
Aindriú Mac Giolla Eoin
7cf7f4b14e
Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:05 +01:00
LucasMZ
050aec31e2
Translated using Weblate: Portuguese (Brazil) (pt_BR) by LucasMZ <git@lucasmz.dev>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: LucasMZ <git@lucasmz.dev>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:04 +01:00
Edgars Andersons
f0cd68a9fb
Translated using Weblate: Latvian (lv) by Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Currently translated at 11.0% (69 of 623 strings)

Co-authored-by: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/lv/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:04 +01:00
Besnik Bleta
868eb64de6
Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 97.7% (609 of 623 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:04 +01:00
VfBFan
51457a6f8e
Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:04 +01:00
大王叫我来巡山
b95d60f24b
Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:04 +01:00
Fjuro
3c9fa6761e
Translated using Weblate: Czech (cs) by Fjuro <fjuro@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:03 +01:00
Champ0999
4e18b38d8f
Translated using Weblate: Italian (it) by Champ0999 <champ0999@users.noreply.hosted.weblate.org>
Currently translated at 89.7% (559 of 623 strings)

Co-authored-by: Champ0999 <champ0999@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/it/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:03 +01:00
Максим Горпиніч
cb69c4fea3
Translated using Weblate: Ukrainian (uk) by Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Currently translated at 100.0% (623 of 623 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-03-23 11:56:03 +01:00
Hans-Christoph Steiner
2b8640b95a Merge branch 'scanner-suppress-verbose' into 'master'
scanner: only output "X problems found" if errors or --verbose

See merge request fdroid/fdroidserver!1622
2025-03-21 08:45:52 +00:00
Hans-Christoph Steiner
35d205a9b9 scanner: only output "X problems found" if errors or --verbose
UNIX/POSIX standard behavior is to output nothing at all if a command
succeeds.  This suppresses "0 problems found", unless the user requests it.
2025-03-21 08:45:23 +00:00
Hans-Christoph Steiner
78efc16fc2 scanner: suppress verbose/confusing log output on success
This additionally asserts that the right log output happened.
2025-03-21 08:45:23 +00:00
Hans-Christoph Steiner
88f4a36f38 Merge branch 'no-more-stats-dir' into 'master'
remove last uses of stats/ dir

See merge request fdroid/fdroidserver!1620
2025-03-20 14:42:09 +00:00
Hans-Christoph Steiner
4b9100ae80 publish: remove last use of stats/ dir
This file can be treated like the other index files in repo/. This also has
the advantage that it will automatically get synced by @CiaranG's existing
sync scripts.
2025-03-20 15:08:32 +01:00
Hans-Christoph Steiner
38378ddfb7 rename v1_sort_packages to sort_package_versions 2025-03-20 15:08:32 +01:00
Hans-Christoph Steiner
8565a97465 rename functions and variables to reflect stats/ going away 2025-03-20 15:08:32 +01:00
Hans-Christoph Steiner
b911fb9ed9
make -C locale/ update 2025-03-20 15:06:59 +01:00
Hans-Christoph Steiner
c17a9253ff
version 2.4 alpha 2 2025-03-20 15:04:20 +01:00
Hans-Christoph Steiner
88108c8381
update CHANGELOG.md 2025-03-20 15:04:17 +01:00
Hans-Christoph Steiner
80edad8947 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1623
2025-03-20 13:43:15 +00:00
Edgars Andersons
46939ec4ba
Translated using Weblate: Latvian (lv) by Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Currently translated at 10.7% (67 of 621 strings)

Co-authored-by: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/lv/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:20 +00:00
Максим Горпиніч
efd79866a7
Translated using Weblate: Ukrainian (uk) by Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Currently translated at 100.0% (621 of 621 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:20 +00:00
VfBFan
f6011ae304
Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (621 of 621 strings)

Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>

Currently translated at 99.5% (618 of 621 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:19 +00:00
大王叫我来巡山
d67a7c1b04
Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (621 of 621 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:19 +00:00
Igor Rückert
af147855f6
Translated using Weblate: Portuguese (Brazil) (pt_BR) by Igor Rückert <igorruckert@yahoo.com.br>
Currently translated at 100.0% (621 of 621 strings)

Co-authored-by: Igor Rückert <igorruckert@yahoo.com.br>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:18 +00:00
Hosted Weblate
dad3299810
Update translation files
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/
Translation: F-Droid/F-Droid Server
2025-03-20 12:48:17 +00:00
Hans-Christoph Steiner
ada4631f15 Merge branch 'dexdump-arch-skip' into 'master'
handle arches that are missing dexdump in tests

See merge request fdroid/fdroidserver!1621
2025-03-20 12:48:05 +00:00
Hans-Christoph Steiner
ec2b847e03 handle arches that are missing dexdump in tests
dexdump is only available for certain CPU architectures.  Google binaries
are for amd64 and arm64.  Debian binaries are for amd64, arm64, armhf,
i386, and riscv64.  That leaves out armel, ppc64el, s390x, loong64, etc.
where pure Python code runs perfectly fine.
2025-03-20 12:42:59 +00:00
Hans-Christoph Steiner
f09d859281 Merge branch 'fix-1125' into 'master'
index: fail if user sets mirrors:isPrimary wrong

Closes #1125

See merge request fdroid/fdroidserver!1617
2025-03-20 11:13:36 +00:00
Hans-Christoph Steiner
20569217d9 index: fail if user sets mirrors:isPrimary wrong
Really, this is not meant to be set by the user in the config.  But if they
add something harmless that'll be ignored anyway, it seems that throwing an
error is too much.  So only throw the error if it is set wrongly.
2025-03-20 11:13:09 +00:00
Hans-Christoph Steiner
8e39f82eb9 Merge branch 'bun' into 'master'
scanner: add bun.lock as lock file of package.json

See merge request fdroid/fdroidserver!1615
2025-03-20 07:30:02 +00:00
linsui
5e28cd367f scanner: add bun.lock as lock file of package.json 2025-03-20 07:29:09 +00:00
Hans-Christoph Steiner
0af61d8fe1 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1618
2025-03-19 20:20:38 +00:00
Hans-Christoph Steiner
6fbb2fec9c
make -C locale update 2025-03-19 17:57:41 +01:00
Kristoffer Grundström
4448aeb550
Translated using Weblate: Swedish (sv) by Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Currently translated at 19.2% (118 of 613 strings)

Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sv/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Ricky Tigg
65b015302d
Translated using Weblate: Finnish (fi) by Ricky Tigg <ricky.tigg@gmail.com>
Currently translated at 5.0% (31 of 613 strings)

Co-authored-by: Ricky Tigg <ricky.tigg@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fi/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Hosted Weblate
273b763aed
Update translation files
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Hans-Christoph Steiner
c62094274c
Translated using Weblate: Tamil (ta) by Hans-Christoph Steiner <hans@guardianproject.info>
Currently translated at 98.6% (604 of 612 strings)

Co-authored-by: Hans-Christoph Steiner <hans@eds.org>
Co-authored-by: Hans-Christoph Steiner <hans@guardianproject.info>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ta/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Kristoffer Grundström
29487d8c3a
Translated using Weblate: Swedish (sv) by Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Currently translated at 12.5% (77 of 612 strings)

Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sv/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Marcus skoding
560d7fd200
Translated using Weblate: Swedish (sv) by Marcus skoding <ggd7cnc9m@mozmail.com>
Currently translated at 12.5% (77 of 612 strings)

Translated using Weblate: Swedish (sv) by Marcus skoding <ggd7cnc9m@mozmail.com>

Currently translated at 12.2% (75 of 612 strings)

Co-authored-by: Marcus skoding <ggd7cnc9m@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sv/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Kristoffer Grundström
f76114ba5c
Translated using Weblate: Swedish (sv) by Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Currently translated at 12.2% (75 of 612 strings)

Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sv/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Kuldeep Singh
40daf5e153
Added translation using Weblate: Punjabi (pa) by Kuldeep Singh <kuldeepburjbhalaike@gmail.com>
Co-authored-by: Kuldeep Singh <kuldeepburjbhalaike@gmail.com>
2025-03-19 17:53:54 +01:00
தமிழ்நேரம்
72ca7ebc4f
Translated using Weblate: Tamil (ta) by தமிழ்நேரம் <anishprabu.t@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ta/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Hosted Weblate
db7afbedf5
Update translation files
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Bård Sigurd Møller
e50ce950a3
Translated using Weblate: Norwegian Nynorsk (nn) by Bård Sigurd Møller <git@bsmoller.no>
Currently translated at 0.6% (4 of 611 strings)

Added translation using Weblate: Norwegian Nynorsk (nn) by Bård Sigurd Møller <git@bsmoller.no>

Co-authored-by: Bård Sigurd Møller <git@bsmoller.no>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/nn/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Edgars Andersons
7f207496bb
Translated using Weblate: Latvian (lv) by Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Currently translated at 7.0% (43 of 612 strings)

Translated using Weblate: Latvian (lv) by Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>

Currently translated at 6.8% (42 of 611 strings)

Co-authored-by: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/lv/
Translation: F-Droid/F-Droid Server
2025-03-19 17:53:54 +01:00
Hans-Christoph Steiner
edd88cc701
version 2.4 alpha 1 2025-03-19 17:45:15 +01:00
Hans-Christoph Steiner
a01e91da6c
update CHANGELOG.md 2025-03-19 17:45:12 +01:00
Hans-Christoph Steiner
e23b196a0f
run tests/refresh-SUSS_DEFAULT.py 2025-03-19 17:45:08 +01:00
Hans-Christoph Steiner
52045f9819 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1616
2025-03-19 16:24:40 +00:00
Golubev Alexander
ca082daaea Translated using Weblate: Russian (ru) by Golubev Alexander <fatzer2@gmail.com>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Golubev Alexander <fatzer2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
大王叫我来巡山
9429f0917b Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Максим Горпиніч
c5d5ab3a79 Translated using Weblate: Ukrainian (uk) by Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
LucasMZ
26860dbf2f Translated using Weblate: Portuguese (Brazil) (pt_BR) by LucasMZ <git@lucasmz.dev>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: LucasMZ <git@lucasmz.dev>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
ssantos
0907755efe Translated using Weblate: Portuguese (pt) by ssantos <ssantos@web.de>
Currently translated at 100.0% (613 of 613 strings)

Translated using Weblate: Portuguese (Portugal) (pt_PT) by ssantos <ssantos@web.de>

Currently translated at 100.0% (613 of 613 strings)

Translated using Weblate: Portuguese (pt) by ssantos <ssantos@web.de>

Currently translated at 99.8% (612 of 613 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
WaldiS
2a36726798 Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>
Currently translated at 100.0% (613 of 613 strings)

Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>

Currently translated at 99.8% (612 of 613 strings)

Co-authored-by: WaldiS <sto@tutanota.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Liner Seven
c0da9df12f Translated using Weblate: Japanese (ja) by Liner Seven <linour7gmekiblo@gmail.com>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Liner Seven <linour7gmekiblo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Aindriú Mac Giolla Eoin
bb5d7a0e91 Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Lula Bye
dedc92b467 Translated using Weblate: French (fr) by Lula Bye <translate.cylinder716@passinbox.com>
Currently translated at 97.3% (597 of 613 strings)

Co-authored-by: Lula Bye <translate.cylinder716@passinbox.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Nicolás Pérez
99b8f76487 Translated using Weblate: Spanish (es) by Nicolás Pérez <ccnicolasperez@gmail.com>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Nicolás Pérez <ccnicolasperez@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/es/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
VfBFan
d3eff85c51 Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Fjuro
fcbbf3bea3 Translated using Weblate: Czech (cs) by Fjuro <fjuro@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
pitroig
2b8c957d12 Translated using Weblate: Catalan (ca) by pitroig <ona@riseup.net>
Currently translated at 100.0% (613 of 613 strings)

Co-authored-by: pitroig <ona@riseup.net>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
Translation: F-Droid/F-Droid Server
2025-03-19 17:13:35 +01:00
Hans-Christoph Steiner
a95f4f11b0
pick-complete-translations.py: use new Weblate API 2025-03-19 17:13:29 +01:00
Hans-Christoph Steiner
b416d9b604 Merge branch 'skip-test-for-unsupported-arch' into 'master'
skip tests that won't run on a given CPU architecture

See merge request fdroid/fdroidserver!1330
2025-03-19 14:56:18 +00:00
Hans-Christoph Steiner
0b3fe26524
skip tests that won't run on a given CPU architecture 2025-03-19 15:47:06 +01:00
Hans-Christoph Steiner
025828932d purge test exceptions for Python < 3.9, that's the min version 2025-03-19 11:11:36 +01:00
Michael Pöhn
17a4912e83 Merge branch 'gitlab-ci-signing-server' into 'master'
gitlab-ci: "PUBLISH" job to test in the signing server's setup

See merge request fdroid/fdroidserver!1613
2025-03-12 16:48:36 +00:00
Hans-Christoph Steiner
c5f442616e gitlab-ci: "PUBLISH" job to test in the signing server's setup 2025-03-12 17:27:26 +01:00
Hans-Christoph Steiner
2f4e0f47a1 signatures: make from . import net optional
This eliminates the need to have python3-requests installed on the signing
server.  This was missed in 031ae1103e
2025-03-12 17:27:26 +01:00
Hans-Christoph Steiner
3e6cb67e69 Merge branch 'signing-server' into 'master'
complete workflow for porting the signing server for config.yml

See merge request fdroid/fdroidserver!1610
2025-03-12 13:11:21 +00:00
Hans-Christoph Steiner
d06e33697a lint: missing valid config key: apk_signing_key_block_list 2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
9d147c6b6b test_common: remove self.tmpdir and use standard self.testdir pat 2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
858068c64b only show "unsafe perms on config.yml" when secrets are present
This should make for fewer false positives.
2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
36007d50e5 AbstractBaseTest class for sharing setUp and tearDown in tests 2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
f269232b96 hide error messages in tests that are meant to fail 2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
8cf1297e2c clarify config data types and structures 2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
081e02c109 expand {env: foo} in any place a string can be
`keypass: {env: keypass}` has been in use in production repos for
years.  That is not anything new. It makes it possible to maintain
_config.yml_ publicly even when it needs secrets.  This change makes
sure it is possible to use {env: foo} syntax anywhere where a string
value is valid. The "list of dicts" values can be str, list of str or
list of dicts with str.

Before the {env: keypass} syntax, the actual password was just inline
in the config file.  Before this commit, it was only possible to use
{env: key} syntax in simple, string-only configs, e.g. from
examples/config.yml:
2025-03-12 13:37:17 +01:00
Hans-Christoph Steiner
031ae1103e function-local imports to limit deps for publish/signindex/gpgsign
This eliminates the need to have these installed on the signing server:

* python3-qrcode
* python3-requests

The signing server currently uses a git clone to run _fdroidserver_ and
`apt-get install` for dependencies.  This leaves "qrcode" in
"install_requires" since moving it to "extras_require" would break
`fdroid update` and `fdroid nightly` for anything that does
`pip install fdroidserver`:

https://gitlab.com/eighthave/fdroidserver/-/jobs/9386520037
2025-03-12 13:37:13 +01:00
Hans-Christoph Steiner
864ccb560b Merge branch 'pydocfix' into 'master'
🪐 fix pydoc link in hooks/pre-commit

See merge request fdroid/fdroidserver!1612
2025-03-12 09:17:58 +00:00
Michael Pöhn
14e13b4f4a
🪐 fix pydoc link in hooks/pre-commit
updated pydoc linter flags based on how it's used in .gitlab-ci.yml
2025-03-12 10:04:46 +01:00
Michael Pöhn
1521d5c659 Merge branch 'YAML-1.2' into 'master'
standardize config on ruamel.yaml with a YAML 1.2 config

See merge request fdroid/fdroidserver!1611
2025-03-10 08:34:06 +00:00
Hans-Christoph Steiner
3ab2baf542 _yaml.config_dump() for writing out config
This outputs YAML in a string that is suitable for use in regexps
and string replacements, as well as complete files.  It is therefore
explicitly set up to avoid writing out headers and footers.
2025-03-10 08:49:18 +01:00
Hans-Christoph Steiner
2f47938dbf standardize config on ruamel.yaml with a YAML 1.2 config
This is a key piece of the ongoing `PUBLISH` _config.yml_ migration. There was uneven implementation of which YAML parser to use, and that could lead to bugs where one parser might read a value one way, and a different parser will read the value a different way. I wanted to be sure that YAML 1.2 would always work.

This makes all code that handles config files use the same `ruamel.yaml` parsers.  This only touches other usages of YAML parsers when there is overlap.  This does not port all of _fdroidserver_ to `ruamel.yaml` and YAML 1.2.  The metadata files should already be YAML 1.2 anyway.

# Conflicts:
#	fdroidserver/lint.py
2025-03-10 08:48:58 +01:00
Hans-Christoph Steiner
53b62415d3 load lint_licenses where it is needed to avoid circular imports
This is the only thing that common.py imports from lint.py.
2025-03-07 14:52:23 +01:00
Jochen Sprickerhof
16fb0fbe91 Merge branch 'purge-config.py' into 'master'
purge config.py

See merge request fdroid/fdroidserver!1607
2025-03-05 14:42:01 +00:00
Hans-Christoph Steiner
3cc6c09ffc use common var for 'config.yml', standarize on UTF-8
This makes it easy to track all the places that use config.yml, and
hopefully makes things feel cleaner.  This also standardizes all places
where config.yml is written out to use UTF-8 as the file encoding.

This also includes a lot of black code format fixes.
2025-03-05 12:20:32 +01:00
Hans-Christoph Steiner
1f96a84f9a
gitlab-ci: add yamllint job 2025-02-26 17:28:01 +01:00
Hans-Christoph Steiner
642499ec94
purge config.py handling, it is no longer supported 2025-02-26 17:27:58 +01:00
Hans-Christoph Steiner
cb9533bd74 Merge branch 'gradle-release-checksums.py' into 'master'
update to gradle v8.13

See merge request fdroid/fdroidserver!1609
2025-02-26 12:39:57 +00:00
fdroid-bot
a37c409c74 gradle v8.13 2025-02-26 10:19:22 +00:00
Michael Pöhn
0f5a1a0bfb Merge branch 'lint-config.yml' into 'master'
Lint config.yml

See merge request fdroid/fdroidserver!1606
2025-02-26 10:18:47 +00:00
Hans-Christoph Steiner
1ee9ea8cf9 lint: implement for config.yml 2025-02-24 19:07:27 +01:00
Hans-Christoph Steiner
695d97e103
fix: "no new line character at the end of file"
If yamllint is installed `fdroid lint` will run it, and what will output
the  (new-line-at-end-of-file) warning message.
2025-02-24 18:13:13 +01:00
Hans-Christoph Steiner
56865f9ba6
checkupdates: remove auto_author: config, it is no longer used
checkupdates-runner sets the required values anyway.
fe3cb890db/.gitlab-ci.yml (L35)
2025-02-24 11:58:56 +01:00
Hans-Christoph Steiner
ecdf47d893 update: do not crash on {env: } in paths in config.yml 2025-02-22 23:32:29 +01:00
Hans-Christoph Steiner
4d66f30faf Merge branch 'skip-test-on-macOS' into 'master'
skip test with mystery failure only on macOS

See merge request fdroid/fdroidserver!1605
2025-02-14 10:15:17 +00:00
Hans-Christoph Steiner
f92542c7ea skip test with mystery failure only on macOS
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1587#note_2273747610

This happened when this test was a shell script as well:
https://gitlab.com/fdroid/fdroidserver/-/blob/2.3.5/tests/run-tests#L1244
2025-02-14 11:12:22 +01:00
Hans-Christoph Steiner
dde1942520 Merge branch 'migrate-integration-tests-to-python' into 'master'
Migrate integration tests from Bash to Python

See merge request fdroid/fdroidserver!1587
2025-02-13 20:40:35 +00:00
Hans-Christoph Steiner
1694966455 gpg requires a short path to the socket to talk to gpg-agent 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
efda0f5d6c skip gpgsign test if gpg is not availabe on the PATH 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
b7c5233668 test_integration: stop trying to handle proxy errors
I don't think it is possible to automatically handle those cases, because
proxy setups can be so widely varied and can have privacy ramifications.
The person running the test who hits proxy errors will need to handle them
manually.
2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
efce0ce0e4 use shared test function to replicate .testfiles setup
* It should include a subdir named after the test case.
* self.testdir is the common var name for this.
* tmp_repo is not a repo/ subdir, but instead the root of the whole repo
2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
820abbc876 'archive/' dir might have been locally created 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
7a21c24e45 test_integration: add docstring comments 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
b933043ca1 new helpers: get_output_extension() & get_release_apk_filename()
This also moves to the standard var names: appid & versionCode
2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
8b52740636 use for f in files var name; avoid using keyword as var name 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
1720a51e9e replace := walrus operator usages 2025-02-13 17:56:30 +01:00
mindston
1cbd68af84 Ignore bandit insecure usage of tmp dir warnings 2025-02-13 17:56:30 +01:00
mindston
565ae02678 Remove macOS exceptions 2025-02-13 17:56:30 +01:00
mindston
fa4ff197aa Force C.UTF-8 locale for messages instead of en_US.UTF-8 2025-02-13 17:56:30 +01:00
mindston
aeb6c612e9 Set configuration variables for tests that run Git 2025-02-13 17:56:30 +01:00
mindston
96f9d7fdf8 Fix androguard import for versions <4 2025-02-13 17:56:30 +01:00
mindston
385832c1fd Fix usage of removed $WORKSPACE variable in run-tests 2025-02-13 17:56:30 +01:00
mindston
62b4af4f19 Fix UTC timezone import to work on Python <3.11 2025-02-13 17:56:30 +01:00
mindston
9201b3ca94 Migrate integration tests from Bash to Python 2025-02-13 17:56:30 +01:00
Hans-Christoph Steiner
49697d1479 Merge branch 'error-on-duplicate-files' into 'master'
index: error if duplicate package files are in repo

See merge request fdroid/fdroidserver!1602
2025-02-13 16:56:08 +00:00
Hans-Christoph Steiner
f7dc89e9ba index: error if duplicate package files are in repo
Looks like the ~index-v2 work removed this error case, and the old bash
integration test case failed to catch it.  This reestablishes this error.

@mindston's refactoring of the old bash test suite caught this issue, e.g.
!1587
2025-02-12 18:38:05 +01:00
Jochen Sprickerhof
6df9d0ecba Merge branch 'autoname' into 'master'
checkupdates: sort the order of dirs when finding autoname

See merge request fdroid/fdroidserver!1601
2025-02-07 17:26:17 +00:00
linsui
a7e56598d6 checkupdates: sort the order of dirs when finding autoname 2025-02-07 22:16:18 +08:00
Hans-Christoph Steiner
9215f5e4b1 Merge branch 'triple-t' into 'master'
update.py: fix triple-t metadata extract when there is no subdir

See merge request fdroid/fdroidserver!1599
2025-01-27 13:49:11 +00:00
linsui
2b725a5966 update.py: fix triple-t metadata extract when there is no subdir 2025-01-27 13:47:36 +00:00
Hans-Christoph Steiner
7c376209e0 Merge branch 'testcommon-rename-to-shared_test_code' into 'master'
tests: rename testcommon module to shared_test_code

See merge request fdroid/fdroidserver!1583
2025-01-27 10:21:58 +00:00
Hans-Christoph Steiner
66d220bd9f tests: rename testcommon module to shared_test_code
This name always confuses me, since there is also test_common.py. And this
module is not actually a test suite, even though it starts with "test".
This also makes for better tab completion, e.g.

python3 -m unittest tests/te[Tab] -> tests/test_
2025-01-27 10:11:19 +00:00
linsui
f9431aaf0f Merge branch 'gradle' into 'master'
gradle v8.12.1

See merge request fdroid/fdroidserver!1598
2025-01-26 04:20:00 +00:00
linsui
0c6e976a01 gradle v8.12.1 2025-01-26 12:09:54 +08:00
Hans-Christoph Steiner
6e1c1f4cc0
make -C locale update 2025-01-21 17:03:56 +01:00
Hans-Christoph Steiner
f719efcba0
version 2.3.5 2025-01-21 16:43:22 +01:00
Hans-Christoph Steiner
e45709beef
update CHANGELOG.md 2025-01-21 16:43:16 +01:00
Hans-Christoph Steiner
0930937939 Merge branch 'ban-apksigner-v33' into 'master'
ban apksigner v33, it has bugs verifying APKs with v3/v3.1 sigs

See merge request fdroid/fdroidserver!1593
2025-01-21 15:00:24 +00:00
Hans-Christoph Steiner
2ac925a249 ban apksigner v33, it has bugs verifying APKs with v3/v3.1 sigs 2025-01-21 15:00:23 +00:00
Hans-Christoph Steiner
afd1a89ca5 Merge branch 'updatedebianimagetrick' into 'master'
Fix vagrant image download issue

See merge request fdroid/fdroidserver!1595
2025-01-21 14:08:09 +00:00
Licaon_Kter
f3102d81b1 Fix vagrant image download issue 2025-01-21 15:57:12 +02:00
Hans-Christoph Steiner
c8c2b1be78 Merge branch 'updatedebianimage' into 'master'
Use latest Bookworm images for makebuildserver

See merge request fdroid/fdroidserver!1594
2025-01-21 13:49:50 +00:00
Licaon_Kter
9e03dba11e Use latest Bookworm images for makebuildserver 2025-01-21 13:36:56 +02:00
Hans-Christoph Steiner
1fc8053936 Merge branch 'fix-ci' into 'master'
two CI fixes: remove broken arch job and ignore one checkupdates test on macOS

See merge request fdroid/fdroidserver!1592
2025-01-21 09:34:12 +00:00
Hans-Christoph Steiner
9b5a67340e checkupdates: skip test_get_upstream_main_branch on macOS
This test checks the detection of the default initial branch. It is a hard
thing to test since different platform configurations have different
defaults.  checkupdates is basically only used on GNU/Linux anyway.

Here's the failure:
https://gitlab.com/fdroid/fdroidserver/-/jobs/8896420261
2025-01-20 15:37:54 +01:00
Hans-Christoph Steiner
594099a10c gitlab-ci: remove arch_pip_install job
https://gitlab.com/fdroid/fdroidserver/-/jobs/8898887965

It broke and no one seems to want to maintain it.
2025-01-20 15:28:25 +01:00
Hans-Christoph Steiner
f14c3e38c8 Merge branch 'merge_weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1591
2025-01-20 14:04:35 +00:00
大王叫我来巡山
d588afd3f9 Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Максим Горпиніч
eecfcbe547 Translated using Weblate: Ukrainian (uk) by Максим Горпиніч <mgorpinic2005@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Максим Горпиніч <mgorpinic2005@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Reno Tx
06eb722b13 Translated using Weblate: Serbian (sr) by Reno Tx <renotx@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Reno Tx <renotx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sr/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Besnik Bleta
d969181b55 Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 97.7% (598 of 612 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Andrey
49d18e494b Translated using Weblate: Russian (ru) by Andrey <andrey@mailbox.org>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Andrey <andrey@mailbox.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Golubev Alexander
a9404dbb42 Translated using Weblate: Russian (ru) by Golubev Alexander <fatzer2@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Golubev Alexander <fatzer2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Dmitry
89f44e0fed Translated using Weblate: Russian (ru) by Dmitry <dmitrydmitry761@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Dmitry <dmitrydmitry761@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
ssantos
a3f9b244d9 Translated using Weblate: Portuguese (Portugal) (pt_PT) by ssantos <ssantos@web.de>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
LucasMZ
787612b93f Translated using Weblate: Portuguese (Brazil) (pt_BR) by LucasMZ <git@lucasmz.dev>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: LucasMZ <git@lucasmz.dev>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Liner Seven
d742fc4f65 Translated using Weblate: Japanese (ja) by Liner Seven <linour7gmekiblo@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Liner Seven <linour7gmekiblo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Aindriú Mac Giolla Eoin
f78492e8ad Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Armand Camponovo
7720402d72 Translated using Weblate: French (fr) by Armand Camponovo <contact@camarm.dev>
Currently translated at 96.7% (592 of 612 strings)

Co-authored-by: Armand Camponovo <contact@camarm.dev>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Sylvain Pichon
eb616643c4 Translated using Weblate: French (fr) by Sylvain Pichon <Sp_@users.noreply.hosted.weblate.org>
Currently translated at 96.5% (591 of 612 strings)

Translated using Weblate: French (fr) by Sylvain Pichon <Sp_@users.noreply.hosted.weblate.org>

Currently translated at 95.7% (586 of 612 strings)

Co-authored-by: Sylvain Pichon <Sp_@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
gallegonovato
11574b717e Translated using Weblate: Spanish (es) by gallegonovato <fran-carro@hotmail.es>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/es/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
VfBFan
6e0b9c94b2 Translated using Weblate: German (de) by VfBFan <drop0815@posteo.de>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: VfBFan <drop0815@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Fjuro
c1f0914476 Translated using Weblate: Czech (cs) by Fjuro <fjuro@alius.cz>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: Fjuro <fjuro@alius.cz>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
pitroig
8831217ca1 Translated using Weblate: Catalan (ca) by pitroig <ona@riseup.net>
Currently translated at 100.0% (612 of 612 strings)

Co-authored-by: pitroig <ona@riseup.net>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
Translation: F-Droid/F-Droid Server
2025-01-20 14:53:42 +01:00
Hans-Christoph Steiner
3000cfcd04
pick-complete-translations.py: auto cherry-pick complete langs 2025-01-20 14:53:08 +01:00
Hans-Christoph Steiner
d4b348bd93 Merge branch 'nettests_localhost' into 'master'
test_net: figure out the proper IP protocol for localhost

See merge request fdroid/fdroidserver!1589
2025-01-20 10:34:01 +00:00
Simon Chopin
89a282c12e test_net: figure out the proper IP protocol for localhost
On some systems, localhost is only defined for 127.0.0.1 (e.g. Ubuntu
and Debian containers). However, there is code that hardcodes possible
values for localhost, making it possible to open an IPv6 socket for
localhost.

On those systems, the socket will be open but urllib3 will resolve
localhost *only* to 127.0.0.1, thus failing miserably to connect.

To resolve the situation, rather than defaulting to IPv6 we actually
resolve localhost and use the socket family of the first result. On my
current system (upcoming Ubuntu Plucky) if localhost=::1 is defined in
/etc/hosts it will come up as the first result, if not 127.0.0.1 will.

V2: Use self.port rather than a forgotten hardcoded port.

Fixes: f01628ca6b "fix localhost network tests on systems with IPv6"
2025-01-20 10:33:49 +00:00
Hans-Christoph Steiner
2716f93e79 Merge branch 'verify-handle-corrupt-json' into 'master'
verify: handle corrupt verified.json

See merge request fdroid/fdroidserver!1580
2025-01-20 09:48:32 +00:00
Hans-Christoph Steiner
5b1b1d12a1 verify: handle corrupt verified.json
verified.json can get quite large on verification.f-droid.org, and for some
unknown reason, it sometimes corrupts it when writing it out.  All the data
is already available in all the other JSON files, so this just automatically
reconstructs it.  Its a hack, but it took me much less time than I've
already spent trying to troubleshoot why it writes out corrupt verified.json.
2025-01-20 09:48:20 +00:00
Jochen Sprickerhof
4c88b19bae Merge branch 'apk-v1-signature-regex-fix' into 'master'
match the full file name when looking for the v1 signature block

See merge request fdroid/fdroidserver!1588
2025-01-15 15:24:37 +00:00
Hans-Christoph Steiner
f5a6aa2cbf bandit no longer includes B410 lxml check
https://github.com/PyCQA/bandit/pull/1212
2025-01-15 15:07:24 +01:00
Hans-Christoph Steiner
20caa6fa1c match the full file name when looking for the v1 signature block
ZipFile.namelist() produces a string per file.  The filename could contain
newline chars, including at the beginning and end.  ^$ in regex matches
around newline chars.  \A\Z matches the beginning/end of the full string.

This is exactly the same as obfusk's r'\AMETA-INF/(?s:.)*\.(DSA|EC|RSA)\Z'
but in a readable format that is also easily searchable, and standard for
this code base.

https://github.com/obfusk/fdroid-fakesigner-poc/blob/master/fdroidserver-regex.patch

#1251
2025-01-15 14:45:35 +01:00
linsui
0bb240fac6 Merge branch 'gradle' into 'master'
update to gradle v8.12

See merge request fdroid/fdroidserver!1584
2024-12-22 07:11:51 +00:00
linsui
c70684ea25 update to gradle v8.12 2024-12-22 15:00:47 +08:00
Hans-Christoph Steiner
3b64dcee7a
version 2.3.4 2024-12-12 17:43:43 +01:00
Hans-Christoph Steiner
eb49351b81
update CHANGELOG.md 2024-12-12 17:43:19 +01:00
Hans-Christoph Steiner
dfbf79ef2b Merge branch 'fix-net-tests-on-ipv6' into 'master'
fix localhost network tests on systems with IPv6

See merge request fdroid/fdroidserver!1581
2024-12-12 15:20:24 +00:00
Hans-Christoph Steiner
f01628ca6b fix localhost network tests on systems with IPv6
Thanks to themill from Debian for this suggestion:

> https://docs.python.org/3/library/socket.html#socket.socket makes me
> think socket.socket has done an ipv4 only but urilib3 will do
> whatever localhost resolves to.  I suspect the test code should be
> using socket.create_server - there's an example at
> https://docs.python.org/3/library/socket.html#socket.create_server
2024-12-12 15:19:58 +00:00
Jochen Sprickerhof
99c3ea9966 Merge branch 'extlib' into 'master'
lint: only error out on missing extlib on versions not archived

See merge request fdroid/fdroidserver!1579
2024-12-12 14:43:42 +00:00
linsui
f93e30f1e9 lint: only error out on missing extlib on versions not archived 2024-12-12 22:33:36 +08:00
linsui
9b59d5cf48 update: extract archive policy calculation to common 2024-12-12 22:20:38 +08:00
Hans-Christoph Steiner
173e45f248
make -C locale update 2024-12-11 14:39:27 +01:00
Hans-Christoph Steiner
c631ca7142
version 2.3.3 2024-12-11 12:51:34 +01:00
Hans-Christoph Steiner
b408d56c2b
update CHANGELOG.md for 2.3.3 2024-12-11 12:51:03 +01:00
Hans-Christoph Steiner
d826178892 Merge branch 'verify--clean-up-verified' into 'master'
verify: --clean-up-verified to rm all files except the JSON report

See merge request fdroid/fdroidserver!1574
2024-12-11 11:48:39 +00:00
Hans-Christoph Steiner
5deb936e86 verify: --clean-up-verified to rm all files except the JSON report 2024-12-11 11:39:02 +00:00
Hans-Christoph Steiner
56814824ee new function get_src_tarball_name; deprecates getsrcname
Some places in the code that need this, like verify.py, do not have
app and build instances, but do have appid and versionCode.  And
fdroidserver/build.py is going away.
2024-12-11 11:39:02 +00:00
Hans-Christoph Steiner
78865a7b2b Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1578
2024-12-11 11:35:28 +00:00
VfBFan
ba0069aaa2 Translated using Weblate: German (de) by VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Licaon Kter
66704e1a4c Translated using Weblate: Romanian (ro) by Licaon Kter <licaon.kter@protonmail.com>
Currently translated at 95.4% (583 of 611 strings)

Co-authored-by: Licaon Kter <licaon.kter@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ro/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Golubev Alexander
2d12f8c731 Translated using Weblate: Russian (ru) by Golubev Alexander <fatzer2@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Golubev Alexander <fatzer2@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
WaldiS
25daaea989 Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>
Currently translated at 99.3% (607 of 611 strings)

Co-authored-by: WaldiS <sto@tutanota.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Reno Tx
cd25bd6ce7 Translated using Weblate: Serbian (sr) by Reno Tx <renotx@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Reno Tx <renotx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sr/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Eryk Michalak
4a5d2c4422 Translated using Weblate: Polish (pl) by Eryk Michalak <gnu.ewm@protonmail.com>
Currently translated at 97.3% (595 of 611 strings)

Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Shuuji TAKAHASHI (shuuji3)
07b83ed101 Translated using Weblate: Japanese (ja) by "Shuuji TAKAHASHI (shuuji3)" <shuuji3@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Shuuji TAKAHASHI (shuuji3) <shuuji3@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Ecron
8658f21282 Translated using Weblate: Catalan (ca) by Ecron <ecron_89@hotmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Ecron <ecron_89@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
தமிழ்நேரம்
067a216f00 Translated using Weblate: Tamil (ta) by தமிழ்நேரம் <anishprabu.t@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Translated using Weblate: Tamil (ta) by தமிழ்நேரம் <anishprabu.t@gmail.com>

Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ta/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Ldm Public
6671720d68 Translated using Weblate: French (fr) by Ldm Public <ldmpub@gmail.com>
Currently translated at 95.9% (586 of 611 strings)

Translated using Weblate: French (fr) by Ldm Public <ldmpub@gmail.com>

Currently translated at 95.9% (586 of 611 strings)

Translated using Weblate: French (fr) by Ldm Public <ldmpub@gmail.com>

Currently translated at 95.4% (583 of 611 strings)

Translated using Weblate: French (fr) by Ldm Public <ldmpub@gmail.com>

Currently translated at 95.0% (581 of 611 strings)

Co-authored-by: Ldm Public <ldmpub@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Lzebulon
e8aff6a755 Translated using Weblate: French (fr) by Lzebulon <lzebulon@crans.org>
Currently translated at 95.9% (586 of 611 strings)

Translated using Weblate: French (fr) by Lzebulon <lzebulon@crans.org>

Currently translated at 95.4% (583 of 611 strings)

Translated using Weblate: French (fr) by Lzebulon <lzebulon@crans.org>

Currently translated at 95.0% (581 of 611 strings)

Translated using Weblate: French (fr) by Lzebulon <lzebulon@crans.org>

Currently translated at 94.9% (580 of 611 strings)

Co-authored-by: Lzebulon <lzebulon@crans.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-12-11 12:25:21 +01:00
Michael Pöhn
36fafaf2cc Merge branch 'replace-deprecated-pkg_resources' into 'master'
support Python 3.13

See merge request fdroid/fdroidserver!1576
2024-12-11 10:28:02 +00:00
Hans-Christoph Steiner
bc118484e4 index.xml: XML escaping from Python < 3.13 which stopped converting "
index.xml is for old clients that are stuck in the past forever.  So the
format should not change at all.  Python 3.13 changed minidom so it no
longer converts " to an XML entity.
154477be72
2024-12-06 16:15:48 +01:00
Hans-Christoph Steiner
6d40e8fa27
extras_require: python-magic is preferred when libmagic is available 2024-12-06 12:26:45 +01:00
Hans-Christoph Steiner
46dba20ba3
setup.py: update classifiers 2024-12-06 12:26:42 +01:00
Hans-Christoph Steiner
5fde2f4d03
replace deprecated pkg_resources.get_distribution() from setuptools
This should fix the CI error for macOS and reduce technical debt.
https://gitlab.com/fdroid/fdroidserver/-/jobs/8542884186
2024-12-06 12:26:37 +01:00
Jochen Sprickerhof
30e308ac8a Merge branch 'stop-overwriting-index-png' into 'master'
update: only gen index.png when making index.html

See merge request fdroid/fdroidserver!1575
2024-12-04 12:25:06 +00:00
Hans-Christoph Steiner
ad9b0c3294 update: only gen index.png when making index.html
* https://f-droid.org/repo does not use the index.png at all
* Some repos want to set their own index.png rather than the QR code
2024-12-04 13:13:30 +01:00
Hans-Christoph Steiner
11aee5b325
version 2.3.2 2024-11-26 22:17:08 +01:00
Hans-Christoph Steiner
620e9f9331
update CHANGELOG.md for 2.3.2 2024-11-26 22:17:05 +01:00
Hans-Christoph Steiner
194d4b63d0 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1573
2024-11-26 21:13:32 +00:00
தமிழ்நேரம்
a45893addf Translated using Weblate: Tamil (ta) by தமிழ்நேரம் <anishprabu.t@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ta/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Joan Pujolar
dbd6034738 Translated using Weblate: Catalan (ca) by Joan Pujolar <joan.pujolar@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Ldm Public
222f19d167 Translated using Weblate: French (fr) by Ldm Public <ldmpub@gmail.com>
Currently translated at 93.7% (573 of 611 strings)

Co-authored-by: Ldm Public <ldmpub@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Peter Dave Hello
a8c354a2d0 Translated using Weblate: Chinese (Traditional Han script) (zh_Hant) by Peter Dave Hello <hsu@peterdavehello.org>
Currently translated at 81.9% (501 of 611 strings)

Co-authored-by: Peter Dave Hello <hsu@peterdavehello.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hant/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Danial Behzadi
19bb2bf1aa Translated using Weblate: Persian (fa) by Danial Behzadi <dani.behzi@ubuntu.com>
Currently translated at 18.1% (111 of 611 strings)

Translated using Weblate: Persian (fa) by Danial Behzadi <dani.behzi@ubuntu.com>

Currently translated at 9.9% (61 of 611 strings)

Translated using Weblate: Persian (fa) by Danial Behzadi <dani.behzi@ubuntu.com>

Currently translated at 9.9% (61 of 611 strings)

Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fa/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Hugo Carvalho
9ce877acdb Translated using Weblate: Portuguese (pt) by Hugo Carvalho <hugokarvalho@hotmail.com>
Currently translated at 100.0% (611 of 611 strings)

Translated using Weblate: Portuguese (pt) by Hugo Carvalho <hugokarvalho@hotmail.com>

Currently translated at 97.3% (595 of 611 strings)

Translated using Weblate: Portuguese (Portugal) (pt_PT) by Hugo Carvalho <hugokarvalho@hotmail.com>

Currently translated at 100.0% (611 of 611 strings)

Translated using Weblate: Portuguese (Portugal) (pt_PT) by Hugo Carvalho <hugokarvalho@hotmail.com>

Currently translated at 97.3% (595 of 611 strings)

Co-authored-by: Hugo Carvalho <hugokarvalho@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
gfbdrgng
0b40c04422 Translated using Weblate: Russian (ru) by gfbdrgng <hnaofegnp@hldrive.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: gfbdrgng <hnaofegnp@hldrive.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2024-11-26 22:03:01 +01:00
Reno Tx
4ea9cdfa93
Translated using Weblate: Serbian (sr) by Reno Tx <renotx@users.noreply.hosted.weblate.org>
Currently translated at 96.8% (592 of 611 strings)

Co-authored-by: Reno Tx <renotx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sr/
Translation: F-Droid/F-Droid Server
2024-11-26 19:01:59 +01:00
Michael Pöhn
e52a07d63a Merge branch 'install-fixes' into 'master'
install: fix breakage in downloading from Maven Central, GitHub Releases

See merge request fdroid/fdroidserver!1572
2024-11-26 15:15:59 +00:00
Hans-Christoph Steiner
8fc340aaca install: fix download dir when fetching from GitHub Releases 2024-11-26 15:31:47 +01:00
Hans-Christoph Steiner
8c81033ea3 FDroidPopenBytes: do not crash if options are not set
This makes writing test cases a lot easier. For example:

======================================================================
ERROR: test_devices (tests.test_install.InstallTest.test_devices)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/hans/code/fdroid/server/tests/test_install.py", line 31, in test_devices
    devices = fdroidserver.install.devices()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hans/code/fdroid/server/fdroidserver/install.py", line 225, in devices
    p = common.SdkToolsPopen(['adb', "devices"])
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hans/code/fdroid/server/fdroidserver/common.py", line 2921, in SdkToolsPopen
    return FDroidPopen([abscmd] + commands[1:],
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hans/code/fdroid/server/fdroidserver/common.py", line 3024, in FDroidPopen
    result = FDroidPopenBytes(commands, cwd, envs, output, stderr_to_stdout)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hans/code/fdroid/server/fdroidserver/common.py", line 2987, in FDroidPopenBytes
    if output and options.verbose:
                  ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'verbose'
2024-11-26 15:20:06 +01:00
Hans-Christoph Steiner
d2cc020336 install: fix broken URL building logic for Maven Central
The append logic was wrong, so it was trying to download URLs like:
https://repo.maven.apache.org/maven2/org/fdroid/fdroid/F-Droid/maven-metadata.xml/org/fdroid/fdroid/F-Droid/1.20.0/F-Droid-1.20.0.apk

Which should be:
https://repo.maven.apache.org/maven2/org/fdroid/fdroid/F-Droid/1.20.0/F-Droid-1.20.0.apk

Can be manually tested using:
`test_download_fdroid_apk=1 python -m unittest -k test_download_fdroid_apk_from_maven`
2024-11-26 15:14:18 +01:00
Hans-Christoph Steiner
a2d27ba15e
install: remove forgotten print() 2024-11-26 11:17:46 +01:00
Michael Pöhn
a9c6eeb753 Merge branch 'fix-1543' into 'master'
buildserver/provision-apt-get-install: install python3-magic for scanner

See merge request fdroid/fdroidserver!1571
2024-11-25 18:43:01 +00:00
Hans-Christoph Steiner
9b2a4a90a7 buildserver/provision-apt-get-install:
This was forgotten in !1543

ansible-role-install-fdroidserver-dependencies!11
2024-11-25 19:21:07 +01:00
Hans-Christoph Steiner
fe29f56238
version 2.3.1 2024-11-25 17:38:02 +01:00
Hans-Christoph Steiner
a26995e534
update CHANGELOG.md for 2.3.0 and 2.3.1 2024-11-25 17:35:39 +01:00
Hans-Christoph Steiner
25bd35a166 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1570
2024-11-25 15:42:28 +00:00
大王叫我来巡山
865c7a33bb Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Besnik Bleta
e61ee39ee4 Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 97.5% (596 of 611 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
gfbdrgng
e162278143 Translated using Weblate: Russian (ru) by gfbdrgng <hnaofegnp@hldrive.com>
Currently translated at 98.3% (601 of 611 strings)

Co-authored-by: gfbdrgng <hnaofegnp@hldrive.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
dedakir923
4b53f4b1d3 Translated using Weblate: Portuguese (Brazil) (pt_BR) by dedakir923 <dedakir923@exoular.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: dedakir923 <dedakir923@exoular.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
LucasMZ
04f8058dfc Translated using Weblate: Portuguese (Brazil) (pt_BR) by LucasMZ <git@lucasmz.dev>
Currently translated at 97.7% (597 of 611 strings)

Co-authored-by: LucasMZ <git@lucasmz.dev>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Aindriú Mac Giolla Eoin
46dd2227e9 Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Sylvain Pichon
8ee15b9cac Translated using Weblate: French (fr) by Sylvain Pichon <Sp_@users.noreply.hosted.weblate.org>
Currently translated at 92.7% (567 of 611 strings)

Co-authored-by: Sylvain Pichon <Sp_@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Sylvain Pichon
13db3f7018 Translated using Weblate: French (fr) by Sylvain Pichon <service@spichon.fr>
Currently translated at 92.6% (566 of 611 strings)

Translated using Weblate: French (fr) by Sylvain Pichon <service@spichon.fr>

Currently translated at 92.1% (563 of 611 strings)

Co-authored-by: Sylvain Pichon <service@spichon.fr>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
gallegonovato
a9c9825727 Translated using Weblate: Spanish (es) by gallegonovato <fran-carro@hotmail.es>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/es/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
VfBFan
696f68a99d Translated using Weblate: German (de) by VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Fjuro
bb911bf4f3 Translated using Weblate: Czech (cs) by Fjuro <fjuro@alius.cz>
Currently translated at 100.0% (611 of 611 strings)

Co-authored-by: Fjuro <fjuro@alius.cz>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2024-11-25 16:30:51 +01:00
Jochen Sprickerhof
67e27cc706 Merge branch 'optional-deps-for-macOS' into 'master'
install biplist and pycountry by default on macOS

See merge request fdroid/fdroidserver!1569
2024-11-25 14:39:34 +00:00
Hans-Christoph Steiner
1b0fabe8f5 install biplist and pycountry by default on macOS
* biplist is only used for Apple iOS IPA files.
* pycountry is only used for linting countryCodes in mirror configs.

Both of these are included via the Debian packaging, where those packages
and updates are more vetted.  Homebrew for macOS makes it very difficult to
include optional dependencies, so this includes the optional dependencies
via distutils' method.
2024-11-25 15:28:43 +01:00
Jochen Sprickerhof
cd29dd84d2 Merge branch 'drop_imghdr' into 'master'
scanner: replace deprecated imghdr with libmagic/puremagic

See merge request fdroid/fdroidserver!1543
2024-11-25 13:57:06 +00:00
Jochen Sprickerhof
8a5359ab3f scanner: replace deprecated imghdr with libmagic/puremagic
libmagic's Python bindings detect more types, puremagic is pure Python.

imghdr was dropped in Python 3.13.

This reverts commit 3bc246ccad.
2024-11-25 13:26:38 +01:00
Hans-Christoph Steiner
432618eb03 Merge branch 'master' into 'master'
post release translation updates

See merge request fdroid/fdroidserver!1568
2024-11-21 20:45:45 +00:00
Hans-Christoph Steiner
4d3feb93e3
make -C locale update 2024-11-21 21:35:26 +01:00
Doctorredits_here
732a945fa3
Translated using Weblate: Indonesian (id) by Doctorredits_here <alkaf.alkaf2018@tutamail.com>
Currently translated at 16.8% (100 of 592 strings)

Co-authored-by: Doctorredits_here <alkaf.alkaf2018@tutamail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/id/
Translation: F-Droid/F-Droid Server
2024-11-21 21:35:23 +01:00
Cool Man
069f75b3d5
Translated using Weblate: Arabic (ar) by Cool Man <mcool3273@gmail.com>
Currently translated at 5.5% (33 of 592 strings)

Co-authored-by: Cool Man <mcool3273@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ar/
Translation: F-Droid/F-Droid Server
2024-11-21 21:35:19 +01:00
Hans-Christoph Steiner
6ff1c9733c
include tests/__init__.py in dist tarball 2024-11-21 21:35:16 +01:00
Hans-Christoph Steiner
d69028e1b1 Merge branch 'master' into 'master'
release 2.3.0

See merge request fdroid/fdroidserver!1567
2024-11-21 16:01:50 +00:00
Hans-Christoph Steiner
eae5ae3ae8
version 2.3.0 2024-11-21 16:49:01 +01:00
Hans-Christoph Steiner
37dc6c121d run tests/refresh-SUSS_DEFAULT.py 2024-11-21 15:23:29 +01:00
Hans-Christoph Steiner
2a6d584713 Merge branch 'gradle-release-checksums.py' into 'master'
update to gradle v8.11.1

See merge request fdroid/fdroidserver!1566
2024-11-21 12:48:17 +00:00
fdroid-bot
50b686b33b gradle v8.11.1 2024-11-21 12:26:23 +00:00
linsui
9203941b78 Merge branch 'fix-checkupdates-one-MR-per-app' into 'master'
checkupdates: reuse per-app branches when making merge requests; plus bug fixes

See merge request fdroid/fdroidserver!1551
2024-11-21 12:25:47 +00:00
Hans-Christoph Steiner
0ec9cd6921 checkupdates: only update app branches if metadata file changed 2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
e3f724681a checkupdates: parse default branch from upstream remote 2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
fd15ac9276 checkupdates: mark as Draft when only changing Current Version
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1551#note_2190155816
2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
c97503b5f3 checkupdates: get default branch from git config 2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
fbe9152ee5 checkupdates: commit summary is merge request title 2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
cd8d4ef88b checkupdates: reuse per-app branches when making merge requests
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1551#note_2206085258
2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
20ff302e89 checkupdates: remove duplicate push in push_commits() 2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
17c480d299 checkupdates: make iter_commits only include commits in appid branch
iter_commits() follows `git rev-list` (which selects different commits
than `git diff`).  With ... notation, `git rev-list` will return all
the commits that are not shared by the two branches.  This needs only
the commits in the right side of the comparison (like how `git diff`
does it).
2024-11-21 12:15:14 +00:00
Hans-Christoph Steiner
f34a132132 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1564
2024-11-20 16:42:27 +00:00
Phantomwise
fb880ad14f Translated using Weblate: French (fr) by Phantomwise <phantomwise67@protonmail.com>
Currently translated at 94.4% (559 of 592 strings)

Co-authored-by: Phantomwise <phantomwise67@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translation: F-Droid/F-Droid Server
2024-11-20 17:31:53 +01:00
Hugo Carvalho
82e47bd392 Translated using Weblate: Portuguese (Portugal) (pt_PT) by Hugo Carvalho <hugokarvalho@hotmail.com>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Hugo Carvalho <hugokarvalho@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translation: F-Droid/F-Droid Server
2024-11-20 17:31:53 +01:00
linsui
a72be3e415 Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by linsui <linsui@inbox.lv>
Currently translated at 100.0% (592 of 592 strings)

Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by linsui <linsui@inbox.lv>

Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: linsui <linsui@inbox.lv>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2024-11-20 17:31:53 +01:00
ygsk10
fcf4875c76 Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by ygsk10 <yogaskung@protonmail.ch>
Currently translated at 100.0% (592 of 592 strings)

Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by ygsk10 <yogaskung@protonmail.ch>

Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: ygsk10 <yogaskung@protonmail.ch>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2024-11-20 17:31:53 +01:00
Hans-Christoph Steiner
a8e31796d8 Merge branch 'wasm' into 'master'
scanner: disallow wasm file

See merge request fdroid/fdroidserver!1562
2024-11-20 12:49:15 +00:00
linsui
56d5f360ed scanner: disallow wasm file 2024-11-20 19:10:30 +08:00
Jochen Sprickerhof
e137aa9c44 Merge branch 'refactor-tests' into 'master'
Refactor TestCase files into python modules

See merge request fdroid/fdroidserver!1561
2024-11-20 09:58:58 +00:00
Hans-Christoph Steiner
487269c667 tests: standardize on VerboseFalseOptions as mock 2024-11-20 10:46:21 +01:00
SilentGhost
7ff32bc4b0 Refactor TestCase files into python modules
Convert all TestCase files into standard python modules to be run and
discovered by unittest.
2024-11-20 10:37:52 +01:00
Hans-Christoph Steiner
4d6682bc70 update: fix _strip_and_copy_image to work with pathlib 2024-11-19 20:27:29 +01:00
Hans-Christoph Steiner
65119b3193 rename to test_gradlew-fdroid to match Python unittest naming 2024-11-19 20:27:29 +01:00
Hans-Christoph Steiner
00e9b7dcd7 Merge branch 'color-output' into 'master'
add --color arg for optional colorized log output

See merge request fdroid/fdroidserver!1552
2024-11-19 13:04:38 +00:00
Hans-Christoph Steiner
290587f449 add ColorFormatter class for optional colorized log output 2024-11-19 13:04:23 +00:00
Hans-Christoph Steiner
7e8e2403cd black formatting 2024-11-19 13:04:23 +00:00
Hans-Christoph Steiner
801d6f9566 Merge branch 'hg-gotorevisionx' into 'master'
Fix local build scenario with Mercurial repositories

See merge request fdroid/fdroidserver!1560
2024-11-18 21:12:23 +00:00
relan
118c7fc783 Remove "hg purge" after "hg update"
1. "hg purge" works only on interactive shell (see #1015).
2. No need to clean anything because we did this before "hg update".
2024-11-18 21:12:04 +00:00
relan
87909fae74 Remove ignored files on gotorevisionx for hg
Other revisions can change the list of ignored files and if we don't
remove them, switching to another revision can fail.
2024-11-18 21:12:04 +00:00
Hans-Christoph Steiner
3bd2bc69d3 Merge branch 'fix-file-exists' into 'master'
Vagrantfile: fix undefined method `exists?' error

See merge request fdroid/fdroidserver!1558
2024-11-18 21:09:22 +00:00
relan
7661518775 Vagrantfile: fix undefined method `exists?' error
This method has been deprecated for a long time, now it's gone.
2024-11-18 21:09:12 +00:00
Hans-Christoph Steiner
d7813b2abc Merge branch 'fix-chown-dot' into 'master'
Fix warning from "chown" about the syntax

See merge request fdroid/fdroidserver!1559
2024-11-18 21:08:35 +00:00
relan
5b57ced0a6 Fix warning from "chown" about the syntax
The warning:

    chown: warning: '.' should be ':': ‘vagrant.vagrant’
2024-11-14 21:45:46 +03:00
Hans-Christoph Steiner
069f088b38 Merge branch 'gradle-release-checksums.py' into 'master'
update to gradle v8.11

See merge request fdroid/fdroidserver!1556
2024-11-13 07:24:20 +00:00
fdroid-bot
dde2947ad2 gradle v8.11 2024-11-13 06:40:37 +00:00
Hans-Christoph Steiner
c42edd4163 Merge branch 'fdroid-install-updates' into 'master'
`fdroid install` updates

See merge request fdroid/fdroidserver!1554
2024-11-13 06:40:00 +00:00
Hans-Christoph Steiner
1be808c728 include net.TestCase in dist tarball
Now that `fdroid install` is something that is expected to work as part of
any package, the test suite should also include the net tests, which
`fdroid install` relies on.
2024-11-08 17:59:06 +02:00
Hans-Christoph Steiner
ad66baa266 net: skip test in CI that mysteriously fails there
I couldn't figure out why it is failing there.
2024-11-08 17:49:15 +02:00
Hans-Christoph Steiner
85e585161f net: use localhost instead of IP for both sides of test setup 2024-11-08 17:49:15 +02:00
Hans-Christoph Steiner
90eeb63809 net: ignore proxy env vars, tests only use localhost
Proxy settings via environment variables can interfere with this
test. The requests library will automatically pick up proxy
settings from environment variables. Proxy settings can force the
local connection over the proxy, which might not support that,
then this fails with an error like 405 or others.
2024-11-08 17:49:14 +02:00
Hans-Christoph Steiner
05e091804d install: verify sig for all downloaded APKs if apksigner is installed 2024-11-08 17:12:42 +02:00
Hans-Christoph Steiner
addb7b9acc install: echo characters that the user inputs at the prompt 2024-11-08 17:12:42 +02:00
Hans-Christoph Steiner
b9b4ca9778 install: download any app from f-droid.org 2024-11-08 17:12:42 +02:00
Hans-Christoph Steiner
dfbf54bbba Merge branch 'rewordfrosting' into 'master'
Reword extra blocks

See merge request fdroid/fdroidserver!1555
2024-11-08 15:09:05 +00:00
Licaon_Kter
96ed60fda3 Reword extra blocks 2024-11-08 15:09:05 +00:00
Hans-Christoph Steiner
d666c030f7 Merge branch 'weblate' into 'master'
weblate

See merge request fdroid/fdroidserver!1553
2024-11-05 14:31:18 +00:00
Hans-Christoph Steiner
69d2c874b6
enable new languages: Irish (ga) and Japanese (ja) 2024-11-05 15:20:56 +01:00
Peter Dave Hello
46df7d87aa Translated using Weblate: Chinese (Traditional Han script) (zh_Hant) by Peter Dave Hello <hsu@peterdavehello.org>
Currently translated at 82.0% (486 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hant/
2024-11-05 15:18:40 +01:00
WaldiS
7ee9882be5 Translated using Weblate: Polish (pl) by WaldiS <sto@tutanota.de>
Currently translated at 99.6% (590 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
2024-11-05 15:18:40 +01:00
Golubev Alexander
7da3357d47 Translated using Weblate: Russian (ru) by Golubev Alexander <fatzer2@gmail.com>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ru/
2024-11-05 15:18:40 +01:00
Fat Potato
eec7addc16 Translated using Weblate: Portuguese (Portugal) (pt_PT) by Fat Potato <mjwany48@gmail.com>
Currently translated at 98.3% (582 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
2024-11-05 15:18:40 +01:00
ssantos
d6a004da56 Translated using Weblate: Portuguese (pt) by ssantos <ssantos@web.de>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt/
2024-11-05 15:18:40 +01:00
Eryk Michalak
f37381e0ff Translated using Weblate: Polish (pl) by Eryk Michalak <gnu.ewm@protonmail.com>
Currently translated at 99.3% (588 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
2024-11-05 15:18:40 +01:00
Lily Chou
cc2088d7bf Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by Lily Chou <lily-develop@outlook.com>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
2024-11-05 15:18:40 +01:00
pitroig
4a6bb9e064 Translated using Weblate: Catalan (ca) by pitroig <ona@riseup.net>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ca/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
5771cfe9f4 Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 99.6% (590 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
770d31ce3e Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 48.3% (286 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
aae4d7f08a Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 25.8% (153 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
dd98d45698 Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 25.6% (152 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
f3151bfb3e Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 25.3% (150 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
14df3c3ec5 Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 25.1% (149 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
12b816421f Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 25.0% (148 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
97bdfcbe7c Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 20.4% (121 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
ba5ed94494 Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 18.2% (108 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
f9ddddf1c6 Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 11.3% (67 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
Fjuro
f3303f88cc Translated using Weblate: Czech (cs) by Fjuro <fjuro@alius.cz>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
2024-11-05 15:18:39 +01:00
Fjuro
df496419d4 Translated using Weblate: Czech (cs) by Fjuro <fjuro@alius.cz>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
2024-11-05 15:18:39 +01:00
Reno Tx
75995b3915 Translated using Weblate: Serbian (sr) by Reno Tx <renotx@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sr/
2024-11-05 15:18:39 +01:00
Suguru Hirahara
c5b8d2823d Translated using Weblate: Japanese (ja) by Suguru Hirahara <shirahara@users.noreply.hosted.weblate.org>
Currently translated at 10.4% (62 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ja/
2024-11-05 15:18:39 +01:00
VfBFan
18d0fad4d1 Translated using Weblate: German (de) by VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (592 of 592 strings)

Translation: F-Droid/F-Droid Server
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
2024-11-05 15:18:39 +01:00
Wang
97eab1ada9 Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by Wang <wang@plasma.ac.cn>
Currently translated at 97.9% (580 of 592 strings)

Co-authored-by: Wang <wang@plasma.ac.cn>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Fjuro
e2ad739628 Translated using Weblate: Czech (cs) by Fjuro <fjuro@alius.cz>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Fjuro <fjuro@alius.cz>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Ihor Hordiichuk
11a7c8d1ce Translated using Weblate: Ukrainian (uk) by Ihor Hordiichuk <igor_ck@outlook.com>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
ssantos
0babd55762 Translated using Weblate: German (de) by ssantos <ssantos@web.de>
Currently translated at 99.6% (590 of 592 strings)

Co-authored-by: ssantos <ssantos@web.de>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Aindriú Mac Giolla Eoin
9e092582c2 Translated using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Currently translated at 100.0% (592 of 592 strings)

Added translation using Weblate: Irish (ga) by Aindriú Mac Giolla Eoin <aindriu80@gmail.com>

Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ga/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Jakub Boukal
3e7bce38f8 Translated using Weblate: Czech (cs) by Jakub Boukal <www.bagr@gmail.com>
Currently translated at 99.1% (587 of 592 strings)

Co-authored-by: Jakub Boukal <www.bagr@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/cs/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Nazar
8676ab800f Translated using Weblate: Ukrainian (uk) by Nazar <balaraz@tuta.io>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/uk/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
VfBFan
8e0722d490 Translated using Weblate: German (de) by VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Currently translated at 98.4% (583 of 592 strings)

Co-authored-by: VfBFan <VfBFan@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/de/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Besnik Bleta
3d923a07c1 Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 97.1% (575 of 592 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
大王叫我来巡山
3f71f87900 Translated using Weblate: Chinese (Simplified Han script) (zh_Hans) by 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Currently translated at 94.7% (561 of 592 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/zh_Hans/
Translation: F-Droid/F-Droid Server
2024-11-05 15:18:39 +01:00
Oğuz Ersen
6e70263dcb Translated using Weblate: Turkish (tr) by Oğuz Ersen <oguz@ersen.moe>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/tr/
Translation: F-Droid/F-Droid Server
2024-11-05 15:17:21 +01:00
Hans-Christoph Steiner
643d8da709 Merge branch 'fdroid-install' into 'master'
install: expand subcommand to be able to fetch F-Droid.apk and install it

See merge request fdroid/fdroidserver!1546
2024-11-05 13:13:01 +00:00
Hans-Christoph Steiner
acae5f1ac9 tests/run-tests: stop skipping install.TestCase 2024-11-01 00:57:45 +01:00
Hans-Christoph Steiner
27e3b5066a install: add --no-privacy-mode as an argument 2024-11-01 00:34:03 +01:00
Hans-Christoph Steiner
4d22a7f67f install: Y/n prompt, --yes, --no controls downloading F-Droid.apk 2024-11-01 00:34:03 +01:00
Hans-Christoph Steiner
560472e4e5 install: download from GitHub Releases 2024-11-01 00:16:13 +01:00
Hans-Christoph Steiner
1eb6516f16 install: add IPNS download method 2024-11-01 00:09:58 +01:00
Hans-Christoph Steiner
3da48e64bc install: use Maven Central as additional source 2024-11-01 00:09:58 +01:00
Hans-Christoph Steiner
b77eba824b install: convert to common.get_config() 2024-11-01 00:09:54 +01:00
Hans-Christoph Steiner
3a3417f6f8 install: add --privacy-mode flag 2024-10-31 23:49:34 +01:00
Hans-Christoph Steiner
c7bc8d0fea install: function to fetch, verify and install the F-Droid.apk 2024-10-31 23:49:30 +01:00
Hans-Christoph Steiner
681d705da0 install: reliable algorithm for picking devices from adb output
Versions of this algorithm are used elsewhere:
* https://github.com/openatx/adbutils/blob/master/adbutils/_adb.py
2024-10-31 21:55:20 +01:00
Hans-Christoph Steiner
f1b110942a net: let localhost RetryServer tests run with an HTTP proxy active 2024-10-31 21:55:20 +01:00
Hans-Christoph Steiner
59fcfa5dec index: download_repo_index_v2() uses mirrors
test_download_repo_index_v2_url_parsing is no longer needed, since all the
things it tested are now handled in test_download_repo_index_v2
2024-10-31 21:55:18 +01:00
Hans-Christoph Steiner
2e3f6d273a net: download_using_mirrors() to download like fdroidclient does 2024-10-31 21:54:47 +01:00
Hans-Christoph Steiner
49dcc53076 install: download_fdroid_apk() to fetch the recommended initial APK 2024-10-31 21:54:47 +01:00
Hans-Christoph Steiner
56bed02a29 install: download_apk() fetchs APKs by appid based on the index 2024-10-31 21:54:45 +01:00
Jochen Sprickerhof
97b156a963 Merge branch 'drop_known_apks' into 'master'
Drop stats/known_apks.txt

See merge request fdroid/fdroidserver!1547
2024-10-31 11:02:09 +00:00
Hans-Christoph Steiner
ab28c442e2 KnownApks: remove dead code 2024-10-31 09:20:26 +00:00
Hans-Christoph Steiner
173c1d67f4 KnownApks: appid is no longer needed at all, remove it. 2024-10-31 09:20:26 +00:00
Hans-Christoph Steiner
5032207da0 add basic tests of KnownApks mechanism
The tests in tests/run-tests do provide coverage for these cases, but it is
not explicit, but just comes from testing that the index file has not
changed.  These tests make it explicit what is being tested.
2024-10-31 09:20:26 +00:00
Jochen Sprickerhof
81c0c9d4aa Drop stats/known_apks.txt
Use repo/index-v2.json instead.
Also fix deprecated datetime.utcnow().
2024-10-31 09:20:26 +00:00
Hans-Christoph Steiner
83a3227235 Merge branch 'fix-checkupdates-one-MR-per-app' into 'master'
checkupdates: --merge_request commits to branch named after appid

See merge request fdroid/fdroidserver!1550
2024-10-30 19:03:14 +00:00
Hans-Christoph Steiner
25779e8b32 checkupdates: --merge_request commits to branch named after appid 2024-10-30 18:35:34 +01:00
Hans-Christoph Steiner
21cb8ac5e0 Merge branch 'frosting' into 'master'
scanner: scan frosting blocks in binary scanner

See merge request fdroid/fdroidserver!1548
2024-10-30 15:26:23 +00:00
linsui
e3eb597331 scanner: scan frosting blocks in binary scanner 2024-10-30 15:16:32 +00:00
linsui
5c32d5bb38 Merge branch 'checkupdates-merge-request' into 'master'
checkupdates: --merge-request flag for single app runs then a MR

See merge request fdroid/fdroidserver!1149
2024-10-30 14:44:28 +00:00
Hans-Christoph Steiner
9a34590e95 checkupdates: make merge-request per appid on push 2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
66a340fe89 checkupdates: add --verbose progress to push_commits() 2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
206f07364b checkupdates: remove appid branches that have been merged
To avoid having thousands of branches on checkupdatess-bot's remote, this
cleans up any remote branches that are pointing to commit that has been
fully merged.
2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
78b368f88b enforce black code format for tests/checkupdates.TestCase 2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
e03915e391 deploy: ensure progress is instantiated before trying to use it 2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
4c225f02d2 checkupdates: push_commits() to push auto-branch when new commits 2024-10-30 14:43:45 +00:00
Hans-Christoph Steiner
a9db97d214 Merge branch 'catalog2' into 'master'
scanner: catalog: get catalog from parent dirs

See merge request fdroid/fdroidserver!1540
2024-10-30 13:51:12 +00:00
linsui
24dc3baadf scanner: catalog: relax VERSION_CATALOG_REGEX
There may be other blocks in dependencyResolutionManagement
2024-10-20 21:21:28 +08:00
linsui
4c3dd9c76c scanner: catalog: get catalog from parent dirs
When walking through the repo, there may be another settings.gradle in a
sub project with a different catalog. In the subdir the catalog of the
sub project shuold be used and in other subdir the catalog of the root
project should be used.
2024-10-20 21:21:28 +08:00
Hans-Christoph Steiner
399ac608c7 Merge branch 'apkcache_no_checksum' into 'master'
Use mtime and file size for apkcache

See merge request fdroid/fdroidserver!1542
2024-10-18 10:50:57 +00:00
Jochen Sprickerhof
3544d5195d Use mtime and file size for apkcache
This reduces the update time significantly as we no longer compute the
sha256 for every apk.
2024-10-18 10:41:15 +00:00
Hans-Christoph Steiner
1e919a6e19 Merge branch 'doc_repo_web_base_url' into 'master'
Document repo_web_base_url

See merge request fdroid/fdroidserver!1178
2024-10-15 16:36:02 +00:00
Jochen Sprickerhof
de2f05e4da
Document repo_web_base_url 2024-10-15 18:31:56 +02:00
Hans-Christoph Steiner
5fbd5ed2d1 Merge branch 'move-mirror-script' into 'master'
mv mirror push script to fdroid-bootstrap-buildserver

See merge request fdroid/fdroidserver!1545
2024-10-11 09:44:11 +00:00
Hans-Christoph Steiner
40c6b7d9cf mv mirror push script to fdroid-bootstrap-buildserver
This script is only part of the production _buildserver_, so it should
be managed by the Ansible setup for the production _buildserver_.

fdroid-bootstrap-buildserver!26
2024-10-11 09:44:03 +00:00
Jochen Sprickerhof
ae42710d33 Merge branch 'flutter-triple-t' into 'master'
Consider subdir for Flutter app triple-t metadata discover

See merge request fdroid/fdroidserver!1541
2024-10-10 12:51:16 +00:00
linsui
deabd7bdc0 Consider subdir for Flutter app triple-t metadata discover 2024-10-10 12:50:59 +00:00
Hans-Christoph Steiner
f446be6c0c Merge branch 'gradlew_plugin' into 'master'
gradlew: fix plugin version

See merge request fdroid/fdroidserver!1544
2024-10-09 10:03:38 +00:00
linsui
eadfe415b0 gradlew: fix plugin version 2024-10-09 00:48:47 +08:00
Jochen Sprickerhof
b9ff024775 Merge branch 'read_metadata' into 'master'
Read only metadata of apps given on the command line

See merge request fdroid/fdroidserver!1037
2024-10-06 08:35:05 +00:00
Jochen Sprickerhof
15d3a3612d
Drop duplicated code (already done in get_metadata_files) 2024-10-06 10:25:19 +02:00
Jochen Sprickerhof
4d0a21f336
Use vercodes in read_metadata interface
read_metadata is only called in read_app_args with an argument. As
vercodes is already there, drop the duplicate call.
2024-10-06 10:25:19 +02:00
Jochen Sprickerhof
8ab1d53318
Read only metadata of apps given on the command line 2024-10-06 10:25:19 +02:00
linsui
66018d3f09 Merge branch 'catalog' into 'master'
scanner: catalog: dependency declaration can be declared as a simple string

See merge request fdroid/fdroidserver!1536
2024-09-27 16:33:58 +00:00
linsui
2ceec6b9d6 scanner: catalog: dependency declaration can be declared as a simple string 2024-09-27 14:28:55 +00:00
Hans-Christoph Steiner
1323751835 Merge branch 'gradle-release-checksums.py' into 'master'
update to gradle v8.10.2

See merge request fdroid/fdroidserver!1538
2024-09-25 11:08:17 +00:00
fdroid-bot
2a13d6d400 gradle v8.10.2 2024-09-25 10:58:29 +00:00
Hans-Christoph Steiner
ba91b71d60 Merge branch 'ipfs-cid' into 'master'
Only check for ipfs_cid when doing fdroid update

See merge request fdroid/fdroidserver!1503
2024-09-25 10:57:55 +00:00
g0t mi1k
5f7203ddf2 Only check for ipfs_cid when doing fdroid update 2024-09-25 11:44:05 +01:00
Hans-Christoph Steiner
680554c1c6 Merge branch 'licaon-kter-master-patch-50256' into 'master'
Use latest Bookworm images for makebuildserver

See merge request fdroid/fdroidserver!1534
2024-09-23 19:04:58 +00:00
Licaon_Kter
17a051329e Use latest Bookworm images for makebuildserver 2024-09-23 19:04:42 +00:00
Hans-Christoph Steiner
8c4583b04e Merge branch 'catalog' into 'master'
scanner: support libs.versions.toml

Closes #1168

See merge request fdroid/fdroidserver!1526
2024-09-23 15:03:25 +00:00
linsui
eff0ef48f4 scanner: support libs.versions.toml 2024-09-23 16:35:27 +08:00
linsui
528760acc8 scanner.TestCase: format 2024-09-23 16:28:50 +08:00
Hans-Christoph Steiner
0d148d58e1 Merge branch 'appid-args-should-not-end-with-colon' into 'master'
throw error when CLI appid args end with a : but no Version Code

See merge request fdroid/fdroidserver!1522
2024-09-23 08:21:31 +00:00
Hans-Christoph Steiner
0d5c7516f2 throw error when CLI appid args end with a : but no Version Code
This is already the behavior in read_app_args(), but wasn't implemented in
read_pkg_args() yet.
2024-09-23 08:21:21 +00:00
Hans-Christoph Steiner
21e91564a0 Merge branch 'ci-debian-testing-libcloud' into 'master'
gitlab-ci: include libcloud for tests

See merge request fdroid/fdroidserver!1533
2024-09-23 08:16:31 +00:00
Hans-Christoph Steiner
2b9cb9cf3e gitlab-ci: include libcloud for tests 2024-09-23 10:13:07 +02:00
Hans-Christoph Steiner
a57a612982 Merge branch 'remove-flattr' into 'master'
Remove all mentions of Flattr

See merge request fdroid/fdroidserver!1530
2024-09-23 07:59:08 +00:00
Leo Heitmann Ruiz
0cee694c43 Remove all mentions of Flattr 2024-09-23 07:59:08 +00:00
Hans-Christoph Steiner
96ec2da0e7 Merge branch 'fix-scanner-tests-failing-with-refresh' into 'master'
scanner: always use built-in ruleset when running tests

See merge request fdroid/fdroidserver!1532
2024-09-23 07:57:57 +00:00
Hans-Christoph Steiner
043492277e
scanner: always use built-in ruleset when running tests
The SUSS rule sets are changing all the time, but the test cases are not.
So this makes the test cases just use the built-in ruleset so the test
cases don't randomly break.
2024-09-21 17:20:11 +02:00
Hans-Christoph Steiner
9a65e24930 Merge branch 'diff' into 'master'
Show \r when diffing reproducible apk

See merge request fdroid/fdroidserver!1529
2024-09-19 13:25:55 +00:00
linsui
afc31e115e Show \r when diffing reproducible apk 2024-09-19 20:19:44 +08:00
Hans-Christoph Steiner
143639b8df Merge branch 'fix-scanner-tests' into 'master'
add test files missing from MANIFEST.in

See merge request fdroid/fdroidserver!1527
2024-09-17 15:58:52 +00:00
Hans-Christoph Steiner
feb0fdfad6 add test files missing from MANIFEST.in 2024-09-17 15:58:30 +00:00
Hans-Christoph Steiner
2bf2777f5e Merge branch 'licaon-kter-master-patch-66765' into 'master'
scanner - jcenter is gone

See merge request fdroid/fdroidserver!1528
2024-09-17 15:58:12 +00:00
Licaon_Kter
02f0052806 scanner - jcenter is gone 2024-09-17 15:58:02 +00:00
Hans-Christoph Steiner
19beb0378d Merge branch 'deploy-standardization' into 'master'
standardize deploy.py code to follow fdroidserver patterns

See merge request fdroid/fdroidserver!1521
2024-09-17 11:57:33 +00:00
Hans-Christoph Steiner
fe3d929f67 deploy: lists for command lines to handle escaping
fdroidserver uses lists of strings to handle the escaping command line
arguments, this converts the rclone code to that pattern.
2024-09-17 10:16:57 +00:00
Hans-Christoph Steiner
5126a58af8 deploy: rclone_config always as list to avoid code duplication 2024-09-17 10:16:57 +00:00
linsui
567e3dbaba Merge branch 'import' into 'master'
import_subcommand.py: misc fixes and updates

See merge request fdroid/fdroidserver!1525
2024-09-16 13:16:49 +00:00
linsui
8648954f19 import_subcommand.py: misc fixes and updates 2024-09-16 19:48:02 +08:00
linsui
faac9b38c8 import_subcommand.py: move functions from common.py
These functions are only used in this file
2024-09-12 22:14:28 +08:00
linsui
5da4e670dd import_subcommand.py: format 2024-09-12 22:12:06 +08:00
Hans-Christoph Steiner
b7749ece8d Merge branch 'weblate' into 'master'
fix typo in translatable string: s,itmes,items,g

See merge request fdroid/fdroidserver!1524
2024-09-10 16:05:35 +00:00
Hans-Christoph Steiner
492d4a5619
fix typo in translatable string: s,itmes,items,g 2024-09-10 17:00:54 +02:00
Jose Delvani
41b9419740
Translated using Weblate: Portuguese (Brazil) (pt_BR) by Jose Delvani <jsdelvani@users.noreply.hosted.weblate.org>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: Jose Delvani <jsdelvani@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translation: F-Droid/F-Droid Server
2024-09-10 15:17:38 +02:00
gallegonovato
c326fc961d
Translated using Weblate: Spanish (es) by gallegonovato <fran-carro@hotmail.es>
Currently translated at 100.0% (592 of 592 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/es/
Translation: F-Droid/F-Droid Server
2024-09-10 15:17:38 +02:00
Besnik Bleta
eb68ae3d8c
Translated using Weblate: Albanian (sq) by Besnik Bleta <besnik@programeshqip.org>
Currently translated at 93.2% (552 of 592 strings)

Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translation: F-Droid/F-Droid Server
2024-09-10 15:17:38 +02:00
Hans-Christoph Steiner
f6f962aaf4
Translated using Weblate: Serbian (sr) by Hans-Christoph Steiner <hans@guardianproject.info>
Currently translated at 97.9% (580 of 592 strings)

Translated using Weblate: Romanian (ro) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 97.9% (580 of 592 strings)

Translated using Weblate: Albanian (sq) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 90.5% (536 of 592 strings)

Translated using Weblate: Polish (pl) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 96.4% (571 of 592 strings)

Translated using Weblate: French (fr) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 93.2% (552 of 592 strings)

Translated using Weblate: Italian (it) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 93.5% (554 of 592 strings)

Translated using Weblate: Portuguese (Portugal) (pt_PT) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 97.9% (580 of 592 strings)

Translated using Weblate: Portuguese (Brazil) (pt_BR) by Hans-Christoph Steiner <hans@guardianproject.info>

Currently translated at 97.9% (580 of 592 strings)

Co-authored-by: Hans-Christoph Steiner <hans@eds.org>
Co-authored-by: Hans-Christoph Steiner <hans@guardianproject.info>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/fr/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/it/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pl/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/pt_PT/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/ro/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sq/
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/sr/
Translation: F-Droid/F-Droid Server
2024-09-10 15:17:38 +02:00
Hosted Weblate
d6f5a1760a
Update translation files
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/f-droid/fdroidserver/
Translation: F-Droid/F-Droid Server
2024-09-10 15:17:38 +02:00
218 changed files with 32351 additions and 24339 deletions

View file

@ -1,3 +1,3 @@
[bandit]
skips: B110,B404,B408,B410,B603,B607
skips: B110,B404,B408,B603,B607,B322
targets: .

1
.gitignore vendored
View file

@ -27,7 +27,6 @@ tmp/
/tests/repo/status
# files used in manual testing
/config.py
/config.yml
/tmp/
/logs/

View file

@ -1,5 +1,22 @@
---
# Use merge request pipelines when a merge request is open for the branch.
# Use branch pipelines when a merge request is not open for the branch.
# https://docs.gitlab.com/ci/yaml/workflow/#switch-between-branch-pipelines-and-merge-request-pipelines
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
stages:
- lint
- test # default for jobs that do not specify stage:
- deploy
variables:
pip: pip3 --timeout 100 --retries 10
# speed up git checkout phase
@ -50,6 +67,7 @@ metadata_v0:
- git checkout $RELEASE_COMMIT_ID
- cd ..
- git clone --depth 1 https://gitlab.com/fdroid/fdroiddata.git
- rm -f fdroiddata/config.yml # ignore config for this test
- cd fdroiddata
- ../tests/dump_internal_metadata_format.py
- cd ..
@ -59,6 +77,7 @@ metadata_v0:
- ../tests/dump_internal_metadata_format.py
- sed -i
-e '/ArchivePolicy:/d'
-e '/FlattrID:/d'
-e '/RequiresRoot:/d'
metadata/dump_*/*.yaml
- diff -uw metadata/dump_*
@ -79,12 +98,31 @@ metadata_v0:
# Ubuntu and other distros often lack https:// support
- grep Debian /etc/issue.net
&& { find /etc/apt/sources.list* -type f | xargs sed -i s,http:,https:, ; }
# The official Debian docker images ship without ca-certificates,
# TLS certificates cannot be verified until that is installed. The
# following code turns off TLS verification, and enables HTTPS, so
# at least unverified TLS is used for apt-get instead of plain
# HTTP. Once ca-certificates is installed, the CA verification is
# enabled by removing this config. This set up makes the initial
# `apt-get update` and `apt-get install` look the same as verified
# TLS to the network observer and hides the metadata.
- echo 'Acquire::https::Verify-Peer "false";' > /etc/apt/apt.conf.d/99nocacertificates
- apt-get update
- apt-get install ca-certificates
- rm /etc/apt/apt.conf.d/99nocacertificates
- apt-get dist-upgrade
# For jobs that only need to run when there are changes to Python files.
.python-rules-changes: &python-rules-changes
rules:
- changes:
- .gitlab-ci.yml
- fdroid
- makebuildserver
- setup.py
- fdroidserver/*.py
- tests/*.py
# Since F-Droid uses Debian as its default platform, from production
# servers to CI to contributor machines, it is important to know when
@ -93,8 +131,8 @@ metadata_v0:
debian_testing:
image: debian:testing
<<: *apt-template
only:
- master@fdroid/fdroidserver
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PROJECT_PATH == "fdroid/fdroidserver"
script:
- apt-get install
aapt
@ -107,6 +145,7 @@ debian_testing:
ipfs-cid
python3-biplist
python3-defusedxml
python3-libcloud
python3-pycountry
python3-setuptools
sdkmanager
@ -121,8 +160,8 @@ debian_testing:
ubuntu_lts_ppa:
image: ubuntu:latest
<<: *apt-template
only:
- master@fdroid/fdroidserver
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PROJECT_PATH == "fdroid/fdroidserver"
script:
- export ANDROID_HOME=/usr/lib/android-sdk
- apt-get install gnupg
@ -147,6 +186,46 @@ ubuntu_lts_ppa:
- ./run-tests
# Test to see how rclone works with S3
test_deploy_to_s3_with_rclone:
image: debian:bookworm-slim
<<: *apt-template
tags:
- saas-linux-small-amd64 # the shared runners are known to support Docker.
services:
- name: docker:dind
command: ["--tls=false"]
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
before_script:
# ensure minio is up before executing tests
- apt-get update
- apt-get install -y
androguard
apksigner
curl
docker.io
git
python3-venv
rclone
# This job requires working docker but will silently fail if docker is not available
- docker info
- python3 -m venv --system-site-packages test-venv
- . test-venv/bin/activate
- pip install testcontainers[minio]
- pip install .
script:
- python3 -m unittest -k test_update_remote_storage_with_rclone --verbose
rules:
- changes:
- .gitlab-ci.yml
- fdroidserver/deploy.py
- tests/test_deploy.py
- tests/test_integration.py
# Test using Ubuntu/jammy LTS (supported til April, 2027) with depends
# from pypi and sdkmanager. The venv is used to isolate the dist
# tarball generation environment from the clean install environment.
@ -166,7 +245,7 @@ ubuntu_jammy_pip:
# back to bare machine to act as user's install machine
- export ANDROID_HOME=/opt/android-sdk
- $pip install sdkmanager
- sdkmanager 'build-tools;33.0.0'
- sdkmanager 'build-tools;35.0.0'
# Install extras_require.optional from setup.py
- $pip install biplist pycountry
@ -174,46 +253,16 @@ ubuntu_jammy_pip:
- $pip install dist/fdroidserver-*.tar.gz
- tar xzf dist/fdroidserver-*.tar.gz
- cd fdroidserver-*
- export PATH=$PATH:$ANDROID_HOME/build-tools/33.0.0
- export PATH=$PATH:$ANDROID_HOME/build-tools/35.0.0
- fdroid=`which fdroid` ./tests/run-tests
# check localization was properly installed
- LANGUAGE='de' fdroid --help | grep 'Gültige Befehle sind'
# test installation process on a bleeding edge distro with pip
arch_pip_install:
image: archlinux
only:
- master@fdroid/fdroidserver
script:
- pacman --sync --sysupgrade --refresh --noconfirm gcc git grep python-pip python-virtualenv python-wheel tar
- python -m venv venv
- source venv/bin/activate
- pip install -e .[test]
- fdroid
- fdroid readmeta
- fdroid update --help
# The gradlew-fdroid tests are isolated from the rest of the test
# suite, so they run as their own job.
gradlew-fdroid:
image: debian:bookworm-slim
<<: *apt-template
only:
changes:
- .gitlab-ci.yml
- gradlew-fdroid
- tests/test-gradlew-fdroid
script:
- apt-get install ca-certificates curl default-jdk-headless shellcheck unzip
- shellcheck --severity=error --color gradlew-fdroid tests/test-gradlew-fdroid
- ./tests/test-gradlew-fdroid
# Run all the various linters and static analysis tools.
lint_format_bandit_checks:
hooks/pre-commit:
stage: lint
image: debian:bookworm-slim
variables:
LANG: C.UTF-8
@ -228,35 +277,60 @@ lint_format_bandit_checks:
make
pycodestyle
pyflakes3
pylint
python3-dev
python3-git
python3-nose
python3-pip
python3-yaml
shellcheck
- ./hooks/pre-commit
bandit:
image: debian:bookworm-slim
<<: *python-rules-changes
<<: *apt-template
script:
- apt-get install python3-pip
- $pip install --break-system-packages bandit
- export EXITVALUE=0
- function set_error() { export EXITVALUE=1; printf "\x1b[31mERROR `history|tail -2|head -1|cut -b 6-500`\x1b[0m\n"; }
- ./hooks/pre-commit || set_error
- bandit
-r
-ii
--ini .bandit
|| set_error
- pylint --output-format=colorized --reports=n
- bandit -r -ii --ini .bandit
pylint:
stage: lint
image: debian:bookworm-slim
<<: *python-rules-changes
<<: *apt-template
script:
- apt-get install pylint python3-pip
- $pip install --break-system-packages pylint-gitlab
- pylint --output-format=colorized,pylint_gitlab.GitlabCodeClimateReporter:pylint-report.json
fdroid
makebuildserver
setup.py
fdroidserver/*.py
tests/*.py
tests/*.TestCase
|| set_error
- shellcheck --exclude SC2046,SC2090 --severity=warning --color tests/run-tests
|| set_error
- exit $EXITVALUE
artifacts:
reports:
codequality: pylint-report.json
when: always
shellcheck:
stage: lint
image: debian:bookworm-slim
rules:
- changes:
- .gitlab-ci.yml
- hooks/install-hooks.sh
- hooks/pre-commit
- tests/run-tests
<<: *apt-template
script:
- apt-get install shellcheck
# TODO GitLab Code Quality report https://github.com/koalaman/shellcheck/issues/3155
- shellcheck --exclude SC2046,SC2090 --severity=warning --color
hooks/install-hooks.sh
hooks/pre-commit
tests/run-tests
# Check all the dependencies in Debian to mirror production. CVEs are
# generally fixed in the latest versions in pip/pypi.org, so it isn't
# so important to scan that kind of install in CI.
@ -264,10 +338,7 @@ lint_format_bandit_checks:
safety:
image: debian:bookworm-slim
rules:
# once only:/changes: are ported to rules:, this could be removed:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: never
- if: $CI_PIPELINE_SOURCE == "push" && $SAFETY_API_KEY
- if: $SAFETY_API_KEY
changes:
- .gitlab-ci.yml
- .safety-policy.yml
@ -288,8 +359,34 @@ safety:
- python3 -m safety --key "$SAFETY_API_KEY" --stage cicd scan
# Run all the various linters and static analysis tools.
# TODO tests/*/*/*.yaml are not covered
yamllint:
stage: lint
image: debian:bookworm-slim
rules:
- changes:
- .gitlab-ci.yml
- .safety-policy.yml
- .yamllint
- tests/*.yml
- tests/*/*.yml
- tests/*/*/.*.yml
<<: *apt-template
variables:
LANG: C.UTF-8
script:
- apt-get install yamllint
- yamllint
.gitlab-ci.yml
.safety-policy.yml
.yamllint
tests/*.yml
tests/*/*.yml
tests/*/*/.*.yml
locales:
stage: lint
image: debian:bookworm-slim
variables:
LANG: C.UTF-8
@ -308,6 +405,7 @@ locales:
black:
stage: lint
image: debian:bookworm-slim
<<: *apt-template
script:
@ -354,14 +452,14 @@ fedora_latest:
- chown -R testuser .
- cd tests
- su testuser --login --command
"cd `pwd`; export ANDROID_HOME=$ANDROID_HOME; fdroid=~testuser/.local/bin/fdroid ./run-tests"
"cd `pwd`; export CI=$CI ANDROID_HOME=$ANDROID_HOME; fdroid=~testuser/.local/bin/fdroid ./run-tests"
macOS:
tags:
- saas-macos-medium-m1
only:
- master@fdroid/fdroidserver
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PROJECT_PATH == "fdroid/fdroidserver"
script:
- export HOMEBREW_CURL_RETRIES=10
- brew update > /dev/null
@ -372,7 +470,7 @@ macOS:
- brew install --cask android-commandlinetools temurin # temurin is a JDK
# test suite dependencies
- brew install dash bash coreutils gnu-sed
- brew install bash coreutils gnu-sed
# TODO port tests/run-tests to POSIX and gsed, it has a couple GNU-isms like du --bytes
- export PATH="$(brew --prefix fdroidserver)/libexec/bin:$(brew --prefix coreutils)/libexec/gnubin:$PATH"
@ -389,56 +487,45 @@ macOS:
- echo "macOS sticks with bash 3.x because of licenses, so avoid new bash syntax"
- /bin/bash --version
- /bin/bash -n gradlew-fdroid tests/run-tests
# TODO remove the packages below once they are included in the Homebrew package
- $(brew --prefix fdroidserver)/libexec/bin/python3 -m pip install biplist oscrypto pycountry
- /bin/bash -n tests/run-tests
# test fdroidserver from git with current package's dependencies
- fdroid="$(brew --prefix fdroidserver)/libexec/bin/python3 $PWD/fdroid" ./tests/run-tests
gradle:
image: debian:bookworm-slim
image: debian:trixie-slim
<<: *apt-template
variables:
GIT_DEPTH: 1000
rules:
- changes:
- .gitlab-ci.yml
- makebuildserver
script:
- apt-get install
ca-certificates
git
openssh-client
python3-bs4
python3-colorama
python3-git
python3-gitlab
python3-packaging
python3-requests
# if this is a merge request fork, then only check if relevant files changed
- if [ "$CI_PROJECT_NAMESPACE" != "fdroid" ]; then
git fetch https://gitlab.com/fdroid/fdroidserver.git;
for f in `git diff --name-only --diff-filter=d FETCH_HEAD...HEAD`; do
test "$f" == "makebuildserver" && export CHANGED="yes";
test "$f" == "gradlew-fdroid" && export CHANGED="yes";
done;
test -z "$CHANGED" && exit;
fi
- ./tests/gradle-release-checksums.py
# Run an actual build in a simple, faked version of the buildserver guest VM.
fdroid build:
image: registry.gitlab.com/fdroid/fdroidserver:buildserver
only:
changes:
- .gitlab-ci.yml
- fdroidserver/build.py
- fdroidserver/common.py
- fdroidserver/exception.py
- fdroidserver/metadata.py
- fdroidserver/net.py
- fdroidserver/scanner.py
- fdroidserver/vmtools.py
rules:
- changes:
- .gitlab-ci.yml
- fdroidserver/build.py
- fdroidserver/common.py
- fdroidserver/exception.py
- fdroidserver/metadata.py
- fdroidserver/net.py
- fdroidserver/scanner.py
- fdroidserver/vmtools.py
# for the docker: job which depends on this one
- makebuildserver
- buildserver/*
cache:
key: "$CI_JOB_NAME"
paths:
@ -474,6 +561,8 @@ fdroid build:
env HOME=$home_vagrant
fdroid"
- git -C $home_vagrant/gradlew-fdroid pull
- chown -R vagrant $home_vagrant
- chown -R vagrant $fdroidserver/.git
- chown vagrant $fdroidserver/
@ -499,11 +588,11 @@ fdroid build:
plugin_fetchsrclibs:
image: debian:bookworm-slim
<<: *apt-template
only:
changes:
- .gitlab-ci.yml
- examples/fdroid_fetchsrclibs.py
- fdroidserver/__main__.py
rules:
- changes:
- .gitlab-ci.yml
- examples/fdroid_fetchsrclibs.py
- fdroidserver/__main__.py
script:
- apt-get install
curl
@ -543,8 +632,8 @@ plugin_fetchsrclibs:
servergitmirrors:
image: debian:bookworm-slim
<<: *apt-template
only:
- master@fdroid/fdroidserver
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PROJECT_PATH == "fdroid/fdroidserver"
script:
- apt-get install
default-jdk-headless
@ -572,11 +661,11 @@ servergitmirrors:
- ./tests/key-tricks.py
- ssh-keyscan gitlab.com >> /root/.ssh/known_hosts
- test -d /tmp/fdroid/repo || mkdir -p /tmp/fdroid/repo
- cp tests/config.py tests/keystore.jks /tmp/fdroid/
- cp tests/config.yml tests/keystore.jks /tmp/fdroid/
- cp tests/repo/com.politedroid_6.apk /tmp/fdroid/repo/
- cd /tmp/fdroid
- touch fdroid-icon.png
- printf "\nservergitmirrors = 'git@gitlab.com:fdroid/ci-test-servergitmirrors-repo.git'\n" >> config.py
- printf "\nservergitmirrors\x3a 'git@gitlab.com:fdroid/ci-test-servergitmirrors-repo.git'\n" >> config.yml
- $PYTHONPATH/fdroid update --verbose --create-metadata
- $PYTHONPATH/fdroid deploy --verbose
- export DLURL=`grep -Eo 'https://gitlab.com/fdroid/ci-test-servergitmirrors-repo[^"]+' repo/index-v1.json`
@ -586,6 +675,7 @@ servergitmirrors:
Build documentation:
image: debian:bookworm-slim
<<: *python-rules-changes
<<: *apt-template
script:
- apt-get install make python3-sphinx python3-numpydoc python3-pydata-sphinx-theme pydocstyle fdroidserver
@ -605,8 +695,8 @@ Build documentation:
Windows:
tags:
- windows
only:
- windows
rules:
- if: $CI_COMMIT_BRANCH == "windows"
script:
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
- choco install --no-progress -y git --force --params "/GitAndUnixToolsOnPath"
@ -617,10 +707,10 @@ Windows:
- python -m pip install --upgrade babel pip setuptools
- python -m pip install -e .
- $files = @(Get-ChildItem tests\*.TestCase)
- $files = @(Get-ChildItem tests\test_*.py)
- foreach ($f in $files) {
write-output $f;
python $f;
python -m unittest $f;
if( $LASTEXITCODE -eq 0 ) {
write-output "SUCCESS $f";
} else {
@ -629,15 +719,16 @@ Windows:
}
# these are the tests that must pass
- python tests\checkupdates.TestCase
- python tests\exception.TestCase
- python tests\import_subcommand.TestCase
- python tests\init.TestCase
- python tests\lint.TestCase
- python tests\main.TestCase
- python tests\metadata.TestCase
- python tests\rewritemeta.TestCase
- python tests\vcs.TestCase
- python -m unittest -k
checkupdates
exception
import_subcommand
test_lint
test_metadata
test_rewritemeta
test_vcs
tests.test_init
tests.test_main
after_script:
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
artifacts:
@ -656,7 +747,9 @@ pages:
artifacts:
paths:
- public
needs: ["Build documentation"]
needs:
- job: "Build documentation"
optional: true
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' # only publish pages on default (master) branch
@ -668,13 +761,12 @@ pages:
docker:
dependencies:
- fdroid build
only:
changes:
- .gitlab-ci.yml
- makebuildserver
- buildserver/*
variables:
- $CI_COMMIT_BRANCH == "master" || $CI_PROJECT_NAMESPACE != "fdroid"
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PROJECT_PATH == "fdroid/fdroidserver"
changes:
- .gitlab-ci.yml
- makebuildserver
- buildserver/*
image: docker:dind
services:
- docker:dind
@ -697,3 +789,66 @@ docker:
fi
- docker push $RELEASE_IMAGE
- docker push $RELEASE_IMAGE-bookworm
# PUBLISH is the signing server. It has a very minimal manual setup.
PUBLISH:
image: debian:bookworm-backports
<<: *python-rules-changes
script:
- apt-get update
- apt-get -qy upgrade
- apt-get -qy install --no-install-recommends -t bookworm-backports
androguard
apksigner
curl
default-jdk-headless
git
gpg
gpg-agent
python3-asn1crypto
python3-defusedxml
python3-git
python3-ruamel.yaml
python3-yaml
rsync
# Run only relevant parts of the test suite, other parts will fail
# because of this minimal base setup.
- python3 -m unittest
tests/test_gpgsign.py
tests/test_metadata.py
tests/test_publish.py
tests/test_signatures.py
tests/test_signindex.py
- cd tests
- mkdir archive
- mkdir unsigned
- cp urzip-release-unsigned.apk unsigned/info.guardianproject.urzip_100.apk
- grep '^key.*pass' config.yml | sed 's,\x3a ,=,' > $CI_PROJECT_DIR/variables
- sed -Ei 's,^(key.*pass|keystore)\x3a.*,\1\x3a {env\x3a \1},' config.yml
- printf '\ngpghome\x3a {env\x3a gpghome}\n' >> config.yml
- |
tee --append $CI_PROJECT_DIR/variables <<EOF
gpghome=$CI_PROJECT_DIR/tests/gnupghome
keystore=$CI_PROJECT_DIR/tests/keystore.jks
serverwebroot=/tmp
export gpghome keypass keystorepass keystore serverwebroot
EOF
- source $CI_PROJECT_DIR/variables
# silence warnings
- chmod 0600 config.yml config/*.yml config/*/*.yml
- chmod 0700 $gpghome
- export PATH=$CI_PROJECT_DIR:$PATH
# run signpkg.sh
- fdroid publish --verbose
- fdroid gpgsign --verbose
- rsync --progress repo/* $serverwebroot/
# run signindex.sh
- fdroid gpgsign --verbose
- fdroid signindex --verbose
- rsync --stats repo/* $serverwebroot/

View file

@ -0,0 +1 @@
https://f-droid.org/funding.json

View file

@ -4,16 +4,203 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## unreleased
### Added
### Fixed
## [2.5.0] - NEXT
### Removed
* deploy: `awsaccesskeyid:` and `awssecretkey:` config items removed, use the
standard env vars: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
## [2.4.2] - 2025-06-24
### Fixed
* nightly: fix bug that clones nightly repo to wrong location
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1672
* Sync translations for all supported languages: es pl ru
## [2.4.1] - 2025-06-23
### Added
* build: Clearer error messages when working with Git.
* verify: generate <appid>.json files that list all reports
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1632
### Fixed
* deploy: use master branch when working complete git-mirror repo
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1666
* update: use ctime/mtime to control _strip_and_copy_image runs
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1665
* update: If categories.yml only has icon:, then add name:
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1659
* update: fix handling of Triple-T 1.0.0 graphics
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1652
* update: never execute any VCS e.g. git
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1630
* config: lazyload environment variables in config.yml
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1645
* config: make localized name/description/icon optional
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1649
* lint: add repo_key_sha256 to list of valid config keys
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1643
* build: calculate all combinations of gradle flavors
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1638
* build: set SOURCE_DATE_EPOCH from app's git otherwise fdroiddata metadata file
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1653
* Sync translations for all supported languages: ca cs de fr ga ja pl pt pt_BR
pt_PT ru sq tr uk zh_Hans
### Removed
## [2.4.0] - 2025-03-25
### Added
* lint: support the base _config.yml_.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1606
### Fixed
* Expand {env: foo} config syntax to be allowed any place a string is.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1610
* Only show "unsafe permissions on config.yml" when secrets are present.
* Standardized config files on ruamel.yaml with a YAML 1.2 data format.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1611
* Brought back error when a package has multiple package types (e.g. xapk and
apk). https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1602
* Reworked test suite to be entirely based on Python unittest (thanks @mindston).
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1587
* publish/signindex/gpgsign no longer load the _qrcode_ and _requests_ modules,
and can operate without them installed.
* scanner: add bun.lock as lock file of package.json
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1615
* index: fail if user sets mirrors:isPrimary wrong
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1617
https://gitlab.com/fdroid/fdroidserver/-/issues/1125
* Sync translations for all supported languages: bo ca cs de es fr ga hu it ja
ko nb_NO pl pt pt_BR pt_PT ro ru sq sr sw tr uk zh_Hans zh_Hant
### Removed
* checkupdates: remove auto_author: config, it is no longer used.
* Purge support for the long-deprecated _config.py_ config file.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1607
## [2.3.5] - 2025-01-20
### Fixed
* Fix issue where APKs with v1-only signatures and targetSdkVersion < 30 could
be maliciously crafted to bypass AllowedAPKSigningKeys
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1588
* Ignore apksigner v33.x, it has bugs verifying APKs with v3/v3.1 sigs.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1593
* Sync translations for: ca cs de es fr ga ja pt_BR pt_PT ru sq sr uk zh_Hans
## [2.3.4] - 2024-12-12
### Fixed
* Fix localhost network tests on systems with IPv6.
* lint: only error out on missing extlib on versions not archived.
## [2.3.3] - 2024-12-11
### Added
* verify: `--clean-up-verified` to delete files used when verifying an APK if
the verification was successful.
### Fixed
* Support Python 3.13 in the full test suite.
* Sync translations for: ca de fr ja pl ro ru sr ta
* update: only generate _index.png_ when making _index.html_, allowing the repo
operator to set a different repo icon, e.g. not the QR Code.
## [2.3.2] - 2024-11-26
### Fixed
* install: fix downloading from GitHub Releases and Maven Central.
* Sync translations for: ca fa fr pt ru sr ta zh_Hant
## [2.3.1] - 2024-11-25
### Fixed
* Sync all translations for: cs de es fr ga pt_BR ru sq zh_Hans.
* Drop use of deprecated imghdr library to support Python 3.13.
* Install biplist and pycountry by default on macOS.
* Fixed running test suite out of dist tarball.
## [2.3.0] - 2024-11-21
### Added
* YAML 1.2 as native format for all _.yml_ files, including metadata and config.
* install: will now fetch _F-Droid.apk_ and install it via `adb`.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1546
* scanner: scan APK Signing Block for known block types like Google Play
Signature aka "Frosting".
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1555
* Support Rclone for deploying to many different cloud services.
* deploy: support deploying to GitHub Releases.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1471
* scanner: support libs.versions.toml
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1526
* Consider subdir for triple-t metadata discovery in Flutter apps.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1541
* deploy: added `index_only:` mode for mirroring the index to small hosting
locations. https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1420
* Support publishing repos in AltStore format.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1465
* Support indexing iOS IPA app files.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1413
* deploy: _config/mirrors.yml_ file with support for adding per-mirror metadata,
like `countryCode:`.
* Repo's categories are now set in the config files.
* lint: check syntax of config files.
* publish: `--error-on-failed` to exit when signing/verifying fails.
* scanner: `--refresh` and `refresh_config:` to control triggering a refresh of
the rule sets.
* Terminal output colorization and `--color` argument to control it.
* New languages: Catalan (ca), Irish (ga), Japanese (ja), Serbian (sr), and
Swahili (sw).
* Support donation links from `community_bridge`, `buy_me_a_coffee`.
### Fixed
* Use last modified time and file size for caching data about scanned APKs
instead of SHA-256 checksum.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1542
* `repo_web_base_url:` config for generating per-app URLs for viewing in
browsers. https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1178
* `fdroid scanner` flags WebAssembly binary _.wasm_ files.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1562
* Test suite as standard Python `unittest` setup (thanks @ghost.adh).
* scanner: error on dependency files without lock file.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1504
* nightly: finding APKs in the wrong directory. (thanks @WrenIX)
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1512
* `AllowedAPKSigningKeys` works with all single-signer APK signatures.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1466
* Sync all translations for: cs de it ko pl pt pt_BR pt_PT ro ru sq tr uk
zh_Hans zh_Hant.
* Support Androguard 4.x.
* Support Python 3.12.
### Removed
* Drop all uses of _stats/known_apks.txt_ and the `update_stats:` config key.
https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1547
* The `maven:` field is now always a string, with `yes` as a legacy special
value. It is no longer treated like a boolean in any case.
* scanner: jcenter is no longer an allowed Maven repo.
* build: `--reset-server` removed (thanks @gotmi1k).
## [2.2.2] - 2024-04-24

View file

@ -20,14 +20,17 @@ include examples/template.yml
include examples/Vagrantfile.yaml
include gradlew-fdroid
include LICENSE
include locale/ba/LC_MESSAGES/fdroidserver.po
include locale/bo/LC_MESSAGES/fdroidserver.po
include locale/ca/LC_MESSAGES/fdroidserver.po
include locale/cs/LC_MESSAGES/fdroidserver.po
include locale/de/LC_MESSAGES/fdroidserver.po
include locale/es/LC_MESSAGES/fdroidserver.po
include locale/fr/LC_MESSAGES/fdroidserver.po
include locale/ga/LC_MESSAGES/fdroidserver.po
include locale/hu/LC_MESSAGES/fdroidserver.po
include locale/it/LC_MESSAGES/fdroidserver.po
include locale/ja/LC_MESSAGES/fdroidserver.po
include locale/ko/LC_MESSAGES/fdroidserver.po
include locale/nb_NO/LC_MESSAGES/fdroidserver.po
include locale/pl/LC_MESSAGES/fdroidserver.po
@ -48,7 +51,6 @@ include README.md
include tests/aosp_testkey_debug.keystore
include tests/apk.embedded_1.apk
include tests/bad-unicode-*.apk
include tests/build.TestCase
include tests/build-tools/17.0.0/aapt-output-com.moez.QKSMS_182.txt
include tests/build-tools/17.0.0/aapt-output-com.politedroid_3.txt
include tests/build-tools/17.0.0/aapt-output-com.politedroid_4.txt
@ -58,10 +60,10 @@ include tests/build-tools/17.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/17.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/17.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/17.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/17.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/17.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/17.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/17.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/17.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/17.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/17.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/18.1.1/aapt-output-com.moez.QKSMS_182.txt
@ -73,10 +75,10 @@ include tests/build-tools/18.1.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/18.1.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/18.1.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/18.1.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/18.1.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/18.1.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/18.1.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/18.1.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/18.1.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/18.1.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/18.1.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/19.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -88,10 +90,10 @@ include tests/build-tools/19.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/19.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/19.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/19.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/19.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/19.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/19.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/19.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/19.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/19.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/19.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/19.1.0/aapt-output-com.moez.QKSMS_182.txt
@ -103,10 +105,10 @@ include tests/build-tools/19.1.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/19.1.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/19.1.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/19.1.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/19.1.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/19.1.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/19.1.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/19.1.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/19.1.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/19.1.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/19.1.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/20.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -118,10 +120,10 @@ include tests/build-tools/20.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/20.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/20.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/20.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/20.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/20.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/20.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/20.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/20.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/20.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/20.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/21.1.1/aapt-output-com.moez.QKSMS_182.txt
@ -133,10 +135,10 @@ include tests/build-tools/21.1.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/21.1.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/21.1.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/21.1.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/21.1.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/21.1.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/21.1.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/21.1.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/21.1.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/21.1.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/21.1.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/21.1.2/aapt-output-com.moez.QKSMS_182.txt
@ -148,10 +150,10 @@ include tests/build-tools/21.1.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/21.1.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/21.1.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/21.1.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/21.1.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/21.1.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/21.1.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/21.1.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/21.1.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/21.1.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/21.1.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/22.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -163,10 +165,10 @@ include tests/build-tools/22.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/22.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/22.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/22.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/22.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/22.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/22.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/22.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/22.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/22.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/22.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/22.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -178,10 +180,10 @@ include tests/build-tools/22.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/22.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/22.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/22.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/22.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/22.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/22.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/22.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/22.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/22.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/22.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/23.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -193,10 +195,10 @@ include tests/build-tools/23.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/23.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/23.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/23.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/23.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/23.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/23.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/23.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/23.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/23.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -208,10 +210,10 @@ include tests/build-tools/23.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/23.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/23.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/23.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/23.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/23.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/23.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/23.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/23.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/23.0.2/aapt-output-com.moez.QKSMS_182.txt
@ -223,10 +225,10 @@ include tests/build-tools/23.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/23.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/23.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/23.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/23.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/23.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/23.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/23.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/23.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/23.0.3/aapt-output-com.moez.QKSMS_182.txt
@ -238,10 +240,10 @@ include tests/build-tools/23.0.3/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/23.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/23.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/23.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/23.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/23.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/23.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/23.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/23.0.3/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/23.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/24.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -253,10 +255,10 @@ include tests/build-tools/24.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/24.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/24.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/24.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/24.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/24.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/24.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/24.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/24.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/24.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -268,10 +270,10 @@ include tests/build-tools/24.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/24.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/24.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/24.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/24.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/24.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/24.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/24.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/24.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/24.0.2/aapt-output-com.moez.QKSMS_182.txt
@ -283,10 +285,10 @@ include tests/build-tools/24.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/24.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/24.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/24.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/24.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/24.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/24.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/24.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/24.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/24.0.3/aapt-output-com.moez.QKSMS_182.txt
@ -298,10 +300,10 @@ include tests/build-tools/24.0.3/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/24.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/24.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/24.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/24.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/24.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/24.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/24.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/24.0.3/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/24.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/25.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -313,10 +315,10 @@ include tests/build-tools/25.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/25.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/25.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/25.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/25.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/25.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/25.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/25.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/25.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/25.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -328,10 +330,10 @@ include tests/build-tools/25.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/25.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/25.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/25.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/25.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/25.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/25.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/25.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/25.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/25.0.2/aapt-output-com.moez.QKSMS_182.txt
@ -343,10 +345,10 @@ include tests/build-tools/25.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/25.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/25.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/25.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/25.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/25.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/25.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/25.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/25.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/25.0.3/aapt-output-com.moez.QKSMS_182.txt
@ -358,10 +360,10 @@ include tests/build-tools/25.0.3/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/25.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/25.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/25.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/25.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/25.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/25.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/25.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/25.0.3/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/25.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/26.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -373,10 +375,10 @@ include tests/build-tools/26.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/26.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/26.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/26.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/26.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/26.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/26.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/26.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/26.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/26.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -388,10 +390,10 @@ include tests/build-tools/26.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/26.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/26.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/26.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/26.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/26.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/26.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/26.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/26.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/26.0.2/aapt-output-com.moez.QKSMS_182.txt
@ -403,10 +405,10 @@ include tests/build-tools/26.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/26.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/26.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/26.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/26.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/26.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/26.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/26.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/26.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/26.0.3/aapt-output-com.moez.QKSMS_182.txt
@ -418,10 +420,10 @@ include tests/build-tools/26.0.3/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/26.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/26.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/26.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/26.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/26.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/26.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/26.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/26.0.3/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/26.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/27.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -433,10 +435,10 @@ include tests/build-tools/27.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/27.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/27.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/27.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/27.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/27.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/27.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/27.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/27.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/27.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -448,10 +450,10 @@ include tests/build-tools/27.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/27.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/27.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/27.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/27.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/27.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/27.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/27.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/27.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/27.0.2/aapt-output-com.moez.QKSMS_182.txt
@ -463,10 +465,10 @@ include tests/build-tools/27.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/27.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/27.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/27.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/27.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/27.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/27.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/27.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/27.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/27.0.3/aapt-output-com.moez.QKSMS_182.txt
@ -478,10 +480,10 @@ include tests/build-tools/27.0.3/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/27.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/27.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/27.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/27.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/27.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/27.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/27.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/27.0.3/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/27.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/28.0.0/aapt-output-com.moez.QKSMS_182.txt
@ -493,10 +495,10 @@ include tests/build-tools/28.0.0/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/28.0.0/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/28.0.0/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/28.0.0/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/28.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.0/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/28.0.0/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/28.0.0/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/28.0.0/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.0/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/28.0.0/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/28.0.1/aapt-output-com.moez.QKSMS_182.txt
@ -508,10 +510,10 @@ include tests/build-tools/28.0.1/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/28.0.1/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/28.0.1/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/28.0.1/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/28.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.1/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/28.0.1/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/28.0.1/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/28.0.1/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.1/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/28.0.1/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/28.0.2/aapt-output-com.politedroid_3.txt
@ -522,10 +524,10 @@ include tests/build-tools/28.0.2/aapt-output-duplicate.permisssions_9999999.txt
include tests/build-tools/28.0.2/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/28.0.2/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/28.0.2/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/28.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.2/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/28.0.2/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/28.0.2/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/28.0.2/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.2/aapt-output-org.droidtr.keyboard_34.txt
include tests/build-tools/28.0.2/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/28.0.3/aapt-output-com.example.test.helloworld_1.txt
@ -538,17 +540,15 @@ include tests/build-tools/28.0.3/aapt-output-info.guardianproject.urzip_100.txt
include tests/build-tools/28.0.3/aapt-output-info.zwanenburg.caffeinetile_4.txt
include tests/build-tools/28.0.3/aapt-output-no.min.target.sdk_987.txt
include tests/build-tools/28.0.3/aapt-output-obb.main.oldversion_1444412523.txt
include tests/build-tools/28.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.3/aapt-output-obb.main.twoversions_1101613.txt
include tests/build-tools/28.0.3/aapt-output-obb.main.twoversions_1101615.txt
include tests/build-tools/28.0.3/aapt-output-obb.main.twoversions_1101617.txt
include tests/build-tools/28.0.3/aapt-output-obb.mainpatch.current_1619.txt
include tests/build-tools/28.0.3/aapt-output-souch.smsbypass_9.txt
include tests/build-tools/generate.sh
include tests/check-fdroid-apk
include tests/checkupdates.TestCase
include tests/com.fake.IpaApp_1000000000001.ipa
include tests/common.TestCase
include tests/config.py
include tests/config.yml
include tests/config/antiFeatures.yml
include tests/config/categories.yml
include tests/config/de/antiFeatures.yml
@ -567,18 +567,16 @@ include tests/config/ic_antifeature_upstreamnonfree.xml
include tests/config/ro/antiFeatures.yml
include tests/config/zh-rCN/antiFeatures.yml
include tests/corrupt-featureGraphic.png
include tests/deploy.TestCase
include tests/dummy-keystore.jks
include tests/dump_internal_metadata_format.py
include tests/exception.TestCase
include tests/extra/manual-vmtools-test.py
include tests/funding-usernames.yaml
include tests/get_android_tools_versions/android-ndk-r10e/RELEASE.TXT
include tests/get_android_tools_versions/android-sdk/ndk-bundle/package.xml
include tests/get_android_tools_versions/android-sdk/ndk-bundle/source.properties
include tests/get_android_tools_versions/android-sdk/ndk/11.2.2725575/source.properties
include tests/get_android_tools_versions/android-sdk/ndk/17.2.4988734/source.properties
include tests/get_android_tools_versions/android-sdk/ndk/21.3.6528147/source.properties
include tests/get_android_tools_versions/android-sdk/ndk-bundle/package.xml
include tests/get_android_tools_versions/android-sdk/ndk-bundle/source.properties
include tests/get_android_tools_versions/android-sdk/patcher/v4/source.properties
include tests/get_android_tools_versions/android-sdk/platforms/android-30/source.properties
include tests/get_android_tools_versions/android-sdk/skiaparser/1/source.properties
@ -589,10 +587,6 @@ include tests/gnupghome/secring.gpg
include tests/gnupghome/trustdb.gpg
include tests/gradle-maven-blocks.yaml
include tests/gradle-release-checksums.py
include tests/import_subcommand.TestCase
include tests/index.TestCase
include tests/init.TestCase
include tests/install.TestCase
include tests/IsMD5Disabled.java
include tests/issue-1128-min-sdk-30-poc.apk
include tests/issue-1128-poc1.apk
@ -600,10 +594,11 @@ include tests/issue-1128-poc2.apk
include tests/issue-1128-poc3a.apk
include tests/issue-1128-poc3b.apk
include tests/janus.apk
include tests/keystore.jks
include tests/key-tricks.py
include tests/lint.TestCase
include tests/main.TestCase
include tests/keystore.jks
include tests/metadata-rewrite-yml/app.with.special.build.params.yml
include tests/metadata-rewrite-yml/fake.ota.update.yml
include tests/metadata-rewrite-yml/org.fdroid.fdroid.yml
include tests/metadata/apk/info.guardianproject.urzip.yaml
include tests/metadata/apk/org.dyndns.fules.ck.yaml
include tests/metadata/app.with.special.build.params.yml
@ -621,13 +616,14 @@ include tests/metadata/dump/org.smssecure.smssecure.yaml
include tests/metadata/dump/org.videolan.vlc.yaml
include tests/metadata/duplicate.permisssions.yml
include tests/metadata/fake.ota.update.yml
include tests/metadata/info.guardianproject.checkey.yml
include tests/metadata/info.guardianproject.checkey/en-US/description.txt
include tests/metadata/info.guardianproject.checkey/en-US/name.txt
include tests/metadata/info.guardianproject.checkey/en-US/phoneScreenshots/checkey-phone.png
include tests/metadata/info.guardianproject.checkey/en-US/phoneScreenshots/checkey.png
include tests/metadata/info.guardianproject.checkey/en-US/summary.txt
include tests/metadata/info.guardianproject.checkey/ja-JP/name.txt
include tests/metadata/info.guardianproject.checkey.yml
include tests/metadata/info.guardianproject.urzip.yml
include tests/metadata/info.guardianproject.urzip/en-US/changelogs/100.txt
include tests/metadata/info.guardianproject.urzip/en-US/changelogs/default.txt
include tests/metadata/info.guardianproject.urzip/en-US/full_description.txt
@ -636,31 +632,26 @@ include tests/metadata/info.guardianproject.urzip/en-US/images/icon.png
include tests/metadata/info.guardianproject.urzip/en-US/short_description.txt
include tests/metadata/info.guardianproject.urzip/en-US/title.txt
include tests/metadata/info.guardianproject.urzip/en-US/video.txt
include tests/metadata/info.guardianproject.urzip.yml
include tests/metadata/info.zwanenburg.caffeinetile.yml
include tests/metadata/no.min.target.sdk.yml
include tests/metadata/obb.main.oldversion.yml
include tests/metadata/obb.mainpatch.current.yml
include tests/metadata/obb.main.twoversions.yml
include tests/metadata/obb.mainpatch.current.yml
include tests/metadata/org.adaway.yml
include tests/metadata/org.fdroid.ci.test.app.yml
include tests/metadata/org.fdroid.fdroid.yml
include tests/metadata/org.maxsdkversion.yml
include tests/metadata/org.smssecure.smssecure.yml
include tests/metadata/org.smssecure.smssecure/signatures/134/28969C09.RSA
include tests/metadata/org.smssecure.smssecure/signatures/134/28969C09.SF
include tests/metadata/org.smssecure.smssecure/signatures/134/MANIFEST.MF
include tests/metadata/org.smssecure.smssecure/signatures/135/28969C09.RSA
include tests/metadata/org.smssecure.smssecure/signatures/135/28969C09.SF
include tests/metadata/org.smssecure.smssecure/signatures/135/MANIFEST.MF
include tests/metadata/org.smssecure.smssecure.yml
include tests/metadata/org.videolan.vlc.yml
include tests/metadata/raw.template.yml
include tests/metadata-rewrite-yml/app.with.special.build.params.yml
include tests/metadata-rewrite-yml/fake.ota.update.yml
include tests/metadata-rewrite-yml/org.fdroid.fdroid.yml
include tests/metadata/souch.smsbypass.yml
include tests/metadata.TestCase
include tests/minimal_targetsdk_30_unsigned.apk
include tests/nightly.TestCase
include tests/Norway_bouvet_europe_2.obf.zip
include tests/no_targetsdk_minsdk1_unsigned.apk
include tests/no_targetsdk_minsdk30_unsigned.apk
@ -671,7 +662,6 @@ include tests/org.bitbucket.tickytacky.mirrormirror_3.apk
include tests/org.bitbucket.tickytacky.mirrormirror_4.apk
include tests/org.dyndns.fules.ck_20.apk
include tests/org.sajeg.fallingblocks_3.apk
include tests/publish.TestCase
include tests/repo/com.example.test.helloworld_1.apk
include tests/repo/com.politedroid_3.apk
include tests/repo/com.politedroid_4.apk
@ -690,16 +680,17 @@ include tests/repo/main.1434483388.obb.main.oldversion.obb
include tests/repo/main.1619.obb.mainpatch.current.obb
include tests/repo/no.min.target.sdk_987.apk
include tests/repo/obb.main.oldversion_1444412523.apk
include tests/repo/obb.mainpatch.current_1619_another-release-key.apk
include tests/repo/obb.mainpatch.current_1619.apk
include tests/repo/obb.mainpatch.current/en-US/featureGraphic.png
include tests/repo/obb.mainpatch.current/en-US/icon.png
include tests/repo/obb.mainpatch.current/en-US/phoneScreenshots/screenshot-main.png
include tests/repo/obb.mainpatch.current/en-US/sevenInchScreenshots/screenshot-tablet-main.png
include tests/repo/obb.main.twoversions_1101613.apk
include tests/repo/obb.main.twoversions_1101615.apk
include tests/repo/obb.main.twoversions_1101617.apk
include tests/repo/obb.main.twoversions_1101617_src.tar.gz
include tests/repo/obb.mainpatch.current/en-US/featureGraphic.png
include tests/repo/obb.mainpatch.current/en-US/icon.png
include tests/repo/obb.mainpatch.current/en-US/phoneScreenshots/screenshot-main.png
include tests/repo/obb.mainpatch.current/en-US/sevenInchScreenshots/screenshot-tablet-main.png
include tests/repo/obb.mainpatch.current_1619.apk
include tests/repo/obb.mainpatch.current_1619_another-release-key.apk
include tests/repo/org.maxsdkversion_4.apk
include tests/repo/org.videolan.vlc/en-US/icon.png
include tests/repo/org.videolan.vlc/en-US/phoneScreenshots/screenshot10.png
include tests/repo/org.videolan.vlc/en-US/phoneScreenshots/screenshot12.png
@ -711,16 +702,16 @@ include tests/repo/org.videolan.vlc/en-US/phoneScreenshots/screenshot4.png
include tests/repo/org.videolan.vlc/en-US/phoneScreenshots/screenshot7.png
include tests/repo/org.videolan.vlc/en-US/phoneScreenshots/screenshot9.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot0.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot1.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot11.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot13.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot14.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot16.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot17.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot19.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot1.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot2.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot21.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot23.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot2.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot3.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot5.png
include tests/repo/org.videolan.vlc/en-US/sevenInchScreenshots/screenshot6.png
@ -729,18 +720,25 @@ include tests/repo/patch.1619.obb.mainpatch.current.obb
include tests/repo/souch.smsbypass_9.apk
include tests/repo/urzip-*.apk
include tests/repo/v1.v2.sig_1020.apk
include tests/rewritemeta.TestCase
include tests/run-tests
include tests/SANAPPSI.RSA
include tests/SANAPPSI.SF
include tests/scanner.TestCase
include tests/signatures.TestCase
include tests/signindex.TestCase
include tests/signindex/guardianproject.jar
include tests/shared_test_code.py
include tests/signindex/guardianproject-v1.jar
include tests/signindex/guardianproject.jar
include tests/signindex/testy.jar
include tests/signindex/unsigned.jar
include tests/source-files/at.bitfire.davdroid/build.gradle
include tests/source-files/catalog.test/app/build.gradle
include tests/source-files/catalog.test/build.gradle.kts
include tests/source-files/catalog.test/buildSrc/build.gradle.kts
include tests/source-files/catalog.test/buildSrc/settings.gradle.kts
include tests/source-files/catalog.test/buildSrc2/build.gradle.kts
include tests/source-files/catalog.test/buildSrc2/settings.gradle.kts
include tests/source-files/catalog.test/core/build.gradle
include tests/source-files/catalog.test/gradle/libs.versions.toml
include tests/source-files/catalog.test/libs.versions.toml
include tests/source-files/catalog.test/settings.gradle.kts
include tests/source-files/cn.wildfirechat.chat/avenginekit/build.gradle
include tests/source-files/cn.wildfirechat.chat/build.gradle
include tests/source-files/cn.wildfirechat.chat/chat/build.gradle
@ -757,6 +755,11 @@ include tests/source-files/com.anpmech.launcher/app/src/main/AndroidManifest.xml
include tests/source-files/com.anpmech.launcher/build.gradle
include tests/source-files/com.anpmech.launcher/settings.gradle
include tests/source-files/com.github.jameshnsears.quoteunquote/build.gradle
include tests/source-files/com.github.shadowsocks/core/build.gradle.kts
include tests/source-files/com.github.shadowsocks/mobile/build.gradle.kts
include tests/source-files/com.infomaniak.mail/Core/gradle/core.versions.toml
include tests/source-files/com.infomaniak.mail/gradle/libs.versions.toml
include tests/source-files/com.infomaniak.mail/settings.gradle
include tests/source-files/com.integreight.onesheeld/build.gradle
include tests/source-files/com.integreight.onesheeld/gradle/wrapper/gradle-wrapper.properties
include tests/source-files/com.integreight.onesheeld/localeapi/build.gradle
@ -770,16 +773,21 @@ include tests/source-files/com.integreight.onesheeld/pullToRefreshlibrary/src/ma
include tests/source-files/com.integreight.onesheeld/quickReturnHeader/build.gradle
include tests/source-files/com.integreight.onesheeld/quickReturnHeader/src/main/AndroidManifest.xml
include tests/source-files/com.integreight.onesheeld/settings.gradle
include tests/source-files/com.jens.automation2/build.gradle
include tests/source-files/com.jens.automation2/app/build.gradle
include tests/source-files/com.jens.automation2/build.gradle
include tests/source-files/com.kunzisoft.testcase/build.gradle
include tests/source-files/com.nextcloud.client/build.gradle
include tests/source-files/com.lolo.io.onelist/app/build.gradle.kts
include tests/source-files/com.lolo.io.onelist/build.gradle.kts
include tests/source-files/com.lolo.io.onelist/gradle/libs.versions.toml
include tests/source-files/com.lolo.io.onelist/gradle/wrapper/gradle-wrapper.properties
include tests/source-files/com.lolo.io.onelist/settings.gradle
include tests/source-files/com.nextcloud.client.dev/src/generic/fastlane/metadata/android/en-US/full_description.txt
include tests/source-files/com.nextcloud.client.dev/src/generic/fastlane/metadata/android/en-US/short_description.txt
include tests/source-files/com.nextcloud.client.dev/src/generic/fastlane/metadata/android/en-US/title.txt
include tests/source-files/com.nextcloud.client.dev/src/versionDev/fastlane/metadata/android/en-US/full_description.txt
include tests/source-files/com.nextcloud.client.dev/src/versionDev/fastlane/metadata/android/en-US/short_description.txt
include tests/source-files/com.nextcloud.client.dev/src/versionDev/fastlane/metadata/android/en-US/title.txt
include tests/source-files/com.nextcloud.client/build.gradle
include tests/source-files/com.nextcloud.client/src/generic/fastlane/metadata/android/en-US/full_description.txt
include tests/source-files/com.nextcloud.client/src/generic/fastlane/metadata/android/en-US/short_description.txt
include tests/source-files/com.nextcloud.client/src/generic/fastlane/metadata/android/en-US/title.txt
@ -799,21 +807,26 @@ include tests/source-files/firebase-allowlisted/app/build.gradle
include tests/source-files/firebase-allowlisted/build.gradle
include tests/source-files/firebase-suspect/app/build.gradle
include tests/source-files/firebase-suspect/build.gradle
include tests/source-files/flavor.test/build.gradle
include tests/source-files/info.guardianproject.ripple/build.gradle
include tests/source-files/lockfile.test/flutter/.dart_tool/flutter_gen/pubspec.yaml
include tests/source-files/lockfile.test/flutter/pubspec.lock
include tests/source-files/lockfile.test/flutter/pubspec.yaml
include tests/source-files/lockfile.test/javascript/package.json
include tests/source-files/lockfile.test/javascript/yarn.lock
include tests/source-files/lockfile.test/rust/subdir2/Cargo.toml
include tests/source-files/lockfile.test/rust/subdir/Cargo.lock
include tests/source-files/lockfile.test/rust/subdir/Cargo.toml
include tests/source-files/lockfile.test/rust/subdir/subdir/subdir/Cargo.toml
include tests/source-files/lockfile.test/rust/subdir2/Cargo.toml
include tests/source-files/open-keychain/open-keychain/build.gradle
include tests/source-files/open-keychain/open-keychain/OpenKeychain/build.gradle
include tests/source-files/org.mozilla.rocket/app/build.gradle
include tests/source-files/org.noise_planet.noisecapture/app/build.gradle
include tests/source-files/org.noise_planet.noisecapture/settings.gradle
include tests/source-files/org.noise_planet.noisecapture/sosfilter/build.gradle
include tests/source-files/org.piepmeyer.gauguin/build.gradle.kts
include tests/source-files/org.piepmeyer.gauguin/libs.versions.toml
include tests/source-files/org.piepmeyer.gauguin/settings.gradle.kts
include tests/source-files/org.tasks/app/build.gradle.kts
include tests/source-files/org.tasks/build.gradle
include tests/source-files/org.tasks/build.gradle.kts
@ -821,6 +834,7 @@ include tests/source-files/org.tasks/buildSrc/build.gradle.kts
include tests/source-files/org.tasks/settings.gradle.kts
include tests/source-files/osmandapp/osmand/build.gradle
include tests/source-files/osmandapp/osmand/gradle/wrapper/gradle-wrapper.properties
include tests/source-files/OtakuWorld/build.gradle
include tests/source-files/realm/react-native/android/build.gradle
include tests/source-files/se.manyver/android/app/build.gradle
include tests/source-files/se.manyver/android/build.gradle
@ -838,11 +852,33 @@ include tests/source-files/ut.ewh.audiometrytest/settings.gradle
include tests/source-files/yuriykulikov/AlarmClock/gradle/wrapper/gradle-wrapper.properties
include tests/source-files/Zillode/syncthing-silk/build.gradle
include tests/SpeedoMeterApp.main_1.apk
include tests/stats/known_apks.txt
include tests/testcommon.py
include tests/test-gradlew-fdroid
include tests/triple-t-2/build/org.piwigo.android/app/build.gradle
include tests/test_build.py
include tests/test_checkupdates.py
include tests/test_common.py
include tests/test_deploy.py
include tests/test_exception.py
include tests/test_gradlew-fdroid
include tests/test_import_subcommand.py
include tests/test_index.py
include tests/test_init.py
include tests/test_install.py
include tests/test_lint.py
include tests/test_main.py
include tests/test_metadata.py
include tests/test_nightly.py
include tests/test_publish.py
include tests/test_rewritemeta.py
include tests/test_scanner.py
include tests/test_signatures.py
include tests/test_signindex.py
include tests/test_update.py
include tests/test_vcs.py
include tests/triple-t-1-graphics/build/de.wivewa.dialer/app/src/main/play/en-US/listing/featureGraphic/play_store_feature_graphic.png
include tests/triple-t-1-graphics/build/de.wivewa.dialer/app/src/main/play/en-US/listing/icon/icon.png
include tests/triple-t-1-graphics/build/de.wivewa.dialer/app/src/main/play/en-US/listing/phoneScreenshots/1.png
include tests/triple-t-1-graphics/metadata/de.wivewa.dialer.yml
include tests/triple-t-2/build/org.piwigo.android/app/.gitignore
include tests/triple-t-2/build/org.piwigo.android/app/build.gradle
include tests/triple-t-2/build/org.piwigo.android/app/src/debug/res/values/constants.xml
include tests/triple-t-2/build/org.piwigo.android/app/src/debug/res/values/strings.xml
include tests/triple-t-2/build/org.piwigo.android/app/src/main/java/org/piwigo/PiwigoApplication.java
@ -897,14 +933,13 @@ include tests/triple-t-multiple/build/ch.admin.bag.covidcertificate.wallet/verif
include tests/triple-t-multiple/build/ch.admin.bag.covidcertificate.wallet/wallet/src/main/play/listings/en-US/title.txt
include tests/triple-t-multiple/metadata/ch.admin.bag.covidcertificate.verifier.yml
include tests/triple-t-multiple/metadata/ch.admin.bag.covidcertificate.wallet.yml
include tests/update.TestCase
include tests/urzip.apk
include tests/urzip-badcert.apk
include tests/urzip-badsig.apk
include tests/urzip-release.apk
include tests/urzip-release-unsigned.apk
include tests/urzip-release.apk
include tests/urzip.apk
include tests/v2.only.sig_2.apk
include tests/valid-package-names/random-package-names
include tests/valid-package-names/RandomPackageNames.java
include tests/valid-package-names/test.py
include tests/vcs.TestCase
include tests/__init__.py

View file

@ -53,13 +53,13 @@ To run the full test suite:
tests/run-tests
To run the tests for individual Python modules, see the _.TestCase_ files, e.g.:
To run the tests for individual Python modules, see the `tests/test_*.py` files, e.g.:
tests/metadata.TestCase
python -m unittest tests/test_metadata.py
It is also possible to run individual tests:
tests/metadata.TestCase MetadataTest.test_rewrite_yaml_special_build_params
python -m unittest tests.test_metadata.MetadataTest.test_rewrite_yaml_special_build_params
There is a growing test suite that has good coverage on a number of key parts of
this code base. It does not yet cover all the code, and there are some parts

View file

@ -37,11 +37,22 @@ RUN useradd --create-home -s /bin/bash vagrant && echo -n 'vagrant:vagrant' | ch
#
# Ensure fdroidserver's dependencies are marked manual before purging
# unneeded packages, otherwise, all its dependencies get purged.
#
# The official Debian docker images ship without ca-certificates, so
# TLS certificates cannot be verified until that is installed. The
# following code temporarily turns off TLS verification, and enables
# HTTPS, so at least unverified TLS is used for apt-get instead of
# plain HTTP. Once ca-certificates is installed, the CA verification
# is enabled by removing the newly created config file. This set up
# makes the initial `apt-get update` and `apt-get install` look the
# same as verified TLS to the network observer and hides the metadata.
RUN printf "path-exclude=/usr/share/locale/*\npath-exclude=/usr/share/man/*\npath-exclude=/usr/share/doc/*\npath-include=/usr/share/doc/*/copyright\n" >/etc/dpkg/dpkg.cfg.d/01_nodoc \
&& mkdir -p /usr/share/man/man1 \
&& echo 'Acquire::https::Verify-Peer "false";' > /etc/apt/apt.conf.d/99nocacertificates \
&& find /etc/apt/sources.list* -type f -exec sed -i s,http:,https:, {} \; \
&& apt-get update \
&& apt-get install ca-certificates \
&& sed -i 's,http:,https:,' /etc/apt/sources.list.d/debian.sources \
&& rm /etc/apt/apt.conf.d/99nocacertificates \
&& apt-get upgrade \
&& apt-get dist-upgrade \
&& apt-get install openssh-client iproute2 python3 openssh-server sudo \

View file

@ -14,7 +14,7 @@ configfile = {
srvpath = Pathname.new(File.dirname(__FILE__)).realpath
configpath = File.join(srvpath, "/Vagrantfile.yaml")
if File.exists? configpath
if File.exist? configpath
c = YAML.load_file(configpath)
if c and not c.empty?
c.each do |k,v|
@ -86,7 +86,7 @@ Vagrant.configure("2") do |config|
# Make sure dir exists to mount to, since buildserver/ is
# automatically mounted as /vagrant in the guest VM. This is more
# necessary with 9p synced folders
Dir.mkdir('cache') unless File.exists?('cache')
Dir.mkdir('cache') unless File.exist?('cache')
# Root partition needs to be resized to the new allocated space
config.vm.provision "shell", inline: <<-SHELL

View file

@ -104,6 +104,7 @@ apt-get upgrade
apt-get update || apt-get update
packages="
androguard/bookworm-backports
apksigner
default-jdk-headless
default-jre-headless
@ -114,6 +115,7 @@ packages="
gnupg
mercurial
patch
python3-magic
python3-packaging
rsync
sdkmanager/bookworm-backports

View file

@ -10,6 +10,6 @@ cat <<EOF > $flutter_conf
"enabled": false
}
EOF
chown -R vagrant.vagrant $flutter_conf
chown -R vagrant:vagrant $flutter_conf
chmod -R 0644 $flutter_conf

View file

@ -25,9 +25,14 @@ fi
chmod -R a+rX /opt/gradle
test -e /opt/gradle/bin || mkdir -p /opt/gradle/bin
ln -fs /home/vagrant/fdroidserver/gradlew-fdroid /opt/gradle/bin/gradle
chown -h vagrant.vagrant /opt/gradle/bin/gradle
chown vagrant.vagrant /opt/gradle/versions
git clone --depth 1 https://gitlab.com/fdroid/gradlew-fdroid.git /home/vagrant/gradlew-fdroid/
chmod 0755 /home/vagrant/gradlew-fdroid/gradlew-fdroid
chmod -R u+rwX,a+rX,go-w /home/vagrant/gradlew-fdroid/
ln -fs /home/vagrant/gradlew-fdroid/gradlew-fdroid /opt/gradle/bin/gradle
ln -fs /home/vagrant/gradlew-fdroid/gradlew-fdroid /usr/local/bin/
chown -h vagrant:vagrant /opt/gradle/bin/gradle
chown vagrant:vagrant /opt/gradle/versions
chmod 0755 /opt/gradle/versions
GRADLE_HOME=/home/vagrant/.gradle
@ -44,5 +49,5 @@ systemProp.org.gradle.internal.http.connectionTimeout=600000
systemProp.org.gradle.internal.http.socketTimeout=600000
EOF
chown -R vagrant.vagrant $GRADLE_HOME/
chown -R vagrant:vagrant $GRADLE_HOME/
chmod -R a+rX $GRADLE_HOME/

View file

@ -109,8 +109,8 @@ __complete_gpgsign() {
}
__complete_install() {
opts="-v -q"
lopts="--verbose --quiet --all"
opts="-v -q -a -p -n -y"
lopts="--verbose --quiet --all --color --no-color --privacy-mode --no-privacy-mode --no --yes"
case "${cur}" in
-*)
__complete_options
@ -251,7 +251,7 @@ __complete_btlog() {
__complete_mirror() {
opts="-v"
lopts="--all --archive --build-logs --pgp-signatures --src-tarballs --output-dir"
lopts="--all --archive --build-logs --color --no-color --pgp-signatures --src-tarballs --output-dir"
__complete_options
}
@ -270,7 +270,7 @@ __complete_deploy() {
__complete_signatures() {
opts="-v -q"
lopts="--verbose --no-check-https"
lopts="--verbose --color --no-color --no-check-https"
case "${cur}" in
-*)
__complete_options
@ -289,7 +289,7 @@ __complete_signindex() {
__complete_init() {
opts="-v -q -d"
lopts="--verbose --quiet --distinguished-name --keystore
--repo-keyalias --android-home --no-prompt"
--repo-keyalias --android-home --no-prompt --color --no-color"
__complete_options
}

View file

@ -12,6 +12,7 @@
#
import os
import sys
sys.path.insert(0, os.path.abspath('../../fdroidserver'))
# -- Project information -----------------------------------------------------

View file

@ -51,6 +51,13 @@
# Canonical URL of the repositoy, needs to end in /repo. Is is used to identity
# the repo in the client, as well.
# repo_url: https://MyFirstFDroidRepo.org/fdroid/repo
#
# Base URL for per-package pages on the website of this repo,
# i.e. https://f-droid.org/packages/<appid>/ This should be accessible
# with a browser. Setting it to null or not setting this disables the
# feature.
# repo_web_base_url: https://MyFirstFDroidRepo.org/packages/
#
# repo_name: My First F-Droid Repo Demo
# repo_description: >-
# This is a repository of apps to be used with F-Droid. Applications
@ -62,6 +69,7 @@
# As above, but for the archive repo.
#
# archive_url: https://f-droid.org/archive
# archive_web_base_url:
# archive_name: My First F-Droid Archive Demo
# archive_description: >-
# The repository of older versions of packages from the main demo repository.
@ -297,70 +305,33 @@
#
# sync_from_local_copy_dir: true
# To deploy to an AWS S3 "bucket" in the US East region, set the
# bucket name in the config, then set the environment variables
# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY using the values from
# the AWS Management Console. See
# https://rclone.org/s3/#authentication
#
# awsbucket: myawsfdroidbucket
# To upload the repo to an Amazon S3 bucket using `fdroid deploy'
# . rclone, s3cmd and apache libcloud are the available options.
# If rclone and s3cmd are not installed, apache libcloud is used.
# To use apache libcloud, add the following options to this file
# (config.yml)
# For extended options for syncing to cloud drive and object store
# services, `fdroid deploy' wraps Rclone. Rclone is a full featured
# sync tool for a huge variety of cloud services. Set up your services
# using `rclone config`, then specify each config name to deploy the
# awsbucket: to. Using rclone_config: overrides the default AWS S3 US
# East setup, and will only sync to the services actually specified.
#
# awsbucket: myawsfdroid
# awsaccesskeyid: SEE0CHAITHEIMAUR2USA
# awssecretkey: {env: awssecretkey}
#
# In case s3cmd is installed and rclone is not installed,
# s3cmd will be the preferred sync option.
# It will delete and recreate the whole fdroid directory each time.
# To customize how s3cmd interacts with the cloud
# provider, create a 's3cfg' file next to this file (config.yml), and
# those settings will be used instead of any 'aws' variable below.
# Secrets can be fetched from environment variables to ensure that
# they are not leaked as part of this file.
#
# awsbucket: myawsfdroid
# awsaccesskeyid: SEE0CHAITHEIMAUR2USA
# awssecretkey: {env: awssecretkey}
#
# In case rclone is installed and s3cmd is not installed,
# rclone will be the preferred sync option.
# It will sync the local folders with remote folders without
# deleting anything in one go.
# To ensure success, install rclone as per
# the instructions at https://rclone.org/install/ and also configure for
# object storage services as detailed at https://rclone.org/s3/#configuration
# By default rclone uses the configuration file at ~/.config/rclone/rclone.conf
# To specify a custom configuration file, please add the full path to the
# configuration file as below
# awsbucket: myawsfdroidbucket
# rclone_config:
# - aws-sample-config
# - rclone-supported-service-config
# By default Rclone uses the user's default configuration file at
# ~/.config/rclone/rclone.conf To specify a custom configuration file,
# please add the full path to the configuration file as below.
#
# path_to_custom_rclone_config: /home/mycomputer/somedir/example.conf
#
# This setting will ignore the default rclone config found at
# ~/.config/rclone/rclone.conf
#
# Please note that rclone_config can be assigned a string or list
#
# awsbucket: myawsfdroid
# rclone_config: aws-sample-config
#
# or
#
# awsbucket: myawsfdroid
# rclone_config: [aws-sample-config, rclone-supported-service-config]
#
# In case both rclone and s3cmd are installed, the preferred sync
# tool can be specified in this file (config.yml)
# if s3cmd is preferred, set it as below
#
# s3cmd: true
#
# if rclone is preferred, set it as below
#
# rclone: true
#
# Please note that only one can be set to true at any time
# Also, in the event that both s3cmd and rclone are installed
# and both are missing from the config.yml file, the preferred
# tool will be s3cmd.
# If you want to force 'fdroid server' to use a non-standard serverwebroot.
@ -393,11 +364,6 @@
# configured to allow push access (e.g. ssh key, username/password, etc)
# binary_transparency_remote: git@gitlab.com:fdroid/binary-transparency-log.git
# If you want to keep the "added" and "last updated" dates for each
# app and APK in your repo, enable this. The name comes from an old
# system for tracking statistics that is no longer included.
# update_stats: true
# Set this to true to always use a build server. This saves specifying the
# --server option on dedicated secure build server hosts.
# build_server_always: true

View file

@ -6,7 +6,6 @@ import argparse
import logging
from fdroidserver import _, common, metadata
from fdroidserver.exception import VCSException
fdroid_summary = 'reset app VCSs to the latest version'
@ -24,9 +23,9 @@ def main():
)
metadata.add_metadata_arguments(parser)
options = common.parse_args(parser)
pkgs = common.read_pkg_args(options.appid, True)
allapps = metadata.read_metadata(pkgs)
apps = common.read_app_args(options.appid, allapps, True)
apps = common.read_app_args(
options.appid, allow_version_codes=True, sort_by_time=True
)
common.read_config()
for appid, app in apps.items():

View file

@ -4,6 +4,7 @@
import os
from argparse import ArgumentParser
from fdroidserver import common
from fdroidserver.common import FDroidPopen
from fdroidserver.exception import BuildException

View file

@ -4,6 +4,7 @@
import os
from argparse import ArgumentParser
from fdroidserver import common
from fdroidserver.common import FDroidPopen
from fdroidserver.exception import BuildException

View file

@ -4,6 +4,7 @@
#
from argparse import ArgumentParser
from fdroidserver import common, index
fdroid_summary = 'export the keystore in standard PEM format'

View file

@ -8,6 +8,7 @@
import argparse
import os
import pprint
from fdroidserver import _, common, metadata
fdroid_summary = 'prepare the srclibs for `fdroid build --on-server`'
@ -19,9 +20,7 @@ def main():
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
metadata.add_metadata_arguments(parser)
options = common.parse_args(parser)
pkgs = common.read_pkg_args(options.appid, True)
allapps = metadata.read_metadata(pkgs)
apps = common.read_app_args(options.appid, allapps, True)
apps = common.read_app_args(options.appid, allow_version_codes=True, sort_by_time=True)
common.read_config()
srclib_dir = os.path.join('build', 'srclib')
os.makedirs(srclib_dir, exist_ok=True)

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from fdroidserver import common
from fdroidserver.common import FDroidPopen
from fdroidserver.exception import BuildException

View file

@ -1,29 +0,0 @@
#!/bin/bash
#
# This script syncs the entire repo to the primary mirrors. It is
# meant to run in a cronjob quite frequently, as often as there are
# files to send.
#
# This script expects the receiving side to have the following
# preceeding the ssh key entry in ~/.ssh/authorized_keys:
# command="rsync --server -logDtpre.iLsfx --log-format=X --delete --delay-updates . /path/to/htdocs/fdroid/",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
#
set -e
(
flock -n 200
set -e
cd /home/fdroid
for section in repo archive; do
echo "Started $section at `date`:"
for host in fdroid@ftp-push.lysator.liu.se fdroid@plug-mirror.rcac.purdue.edu fdroid@ftp.agdsn.de; do
set -x
# be super careful with the trailing slashes here! if one is wrong, it'll delete the entire section!
rsync --archive --delay-updates --progress --delete \
--timeout=3600 \
/home/fdroid/public_html/${section} \
${host}:/srv/fdroid-mirror.at.or.at/htdocs/fdroid/ &
set +x
done
wait
done
) 200>/var/lock/root_fdroidmirrortomirror

View file

@ -3,7 +3,6 @@ import glob
import os
import sys
# support running straight from git and standard installs
rootpaths = [
os.path.realpath(os.path.join(os.path.dirname(__file__), '..')),
@ -15,7 +14,10 @@ rootpaths = [
localedir = None
for rootpath in rootpaths:
if len(glob.glob(os.path.join(rootpath, 'locale', '*', 'LC_MESSAGES', 'fdroidserver.mo'))) > 0:
found_mo = glob.glob(
os.path.join(rootpath, 'locale', '*', 'LC_MESSAGES', 'fdroidserver.mo')
)
if len(found_mo) > 0:
localedir = os.path.join(rootpath, 'locale')
break
@ -24,39 +26,52 @@ gettext.textdomain('fdroidserver')
_ = gettext.gettext
from fdroidserver.exception import (FDroidException,
MetaDataException,
VerificationException) # NOQA: E402
from fdroidserver.exception import (
FDroidException,
MetaDataException,
VerificationException, # NOQA: E402
)
FDroidException # NOQA: B101
MetaDataException # NOQA: B101
VerificationException # NOQA: B101
from fdroidserver.common import (verify_apk_signature,
genkeystore as generate_keystore) # NOQA: E402
from fdroidserver.common import genkeystore as generate_keystore # NOQA: E402
from fdroidserver.common import verify_apk_signature
verify_apk_signature # NOQA: B101
generate_keystore # NOQA: B101
from fdroidserver.index import (download_repo_index,
download_repo_index_v1,
download_repo_index_v2,
get_mirror_service_urls,
make as make_index) # NOQA: E402
from fdroidserver.index import (
download_repo_index,
download_repo_index_v1,
download_repo_index_v2,
get_mirror_service_urls,
)
from fdroidserver.index import make as make_index # NOQA: E402
download_repo_index # NOQA: B101
download_repo_index_v1 # NOQA: B101
download_repo_index_v2 # NOQA: B101
get_mirror_service_urls # NOQA: B101
make_index # NOQA: B101
from fdroidserver.update import (process_apk,
process_apks,
scan_apk,
scan_repo_files) # NOQA: E402
from fdroidserver.update import (
process_apk,
process_apks,
scan_apk,
scan_repo_files, # NOQA: E402
)
process_apk # NOQA: B101
process_apks # NOQA: B101
scan_apk # NOQA: B101
scan_repo_files # NOQA: B101
from fdroidserver.deploy import (update_awsbucket,
update_servergitmirrors,
update_serverwebroots,
update_serverwebroot) # NOQA: E402
from fdroidserver.deploy import (
update_awsbucket,
update_servergitmirrors,
update_serverwebroot, # NOQA: E402
update_serverwebroots,
)
update_awsbucket # NOQA: B101
update_servergitmirrors # NOQA: B101
update_serverwebroots # NOQA: B101

View file

@ -18,20 +18,20 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
import importlib.metadata
import logging
import os
import pkgutil
import logging
import importlib.metadata
import git
import fdroidserver.common
import fdroidserver.metadata
from fdroidserver import _
import re
import sys
from argparse import ArgumentError
from collections import OrderedDict
import git
import fdroidserver.common
import fdroidserver.metadata
from fdroidserver import _
COMMANDS = OrderedDict([
("build", _("Build a package from source")),

64
fdroidserver/_yaml.py Normal file
View file

@ -0,0 +1,64 @@
# Copyright (C) 2025, Hans-Christoph Steiner <hans@eds.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Standard YAML parsing and dumping.
YAML 1.2 is the preferred format for all data files. When loading
F-Droid formats like config.yml and <Application ID>.yml, YAML 1.2 is
forced, and older YAML constructs should be considered an error.
It is OK to load and dump files in other YAML versions if they are
externally defined formats, like FUNDING.yml. In those cases, these
common instances might not be appropriate to use.
There is a separate instance for dumping based on the "round trip" aka
"rt" mode. The "rt" mode maintains order while the "safe" mode sorts
the output. Also, yaml.version is not forced in the dumper because that
makes it write out a "%YAML 1.2" header. F-Droid's formats are
explicitly defined as YAML 1.2 and meant to be human-editable. So that
header gets in the way.
"""
import ruamel.yaml
yaml = ruamel.yaml.YAML(typ='safe')
yaml.version = (1, 2)
yaml_dumper = ruamel.yaml.YAML(typ='rt')
def config_dump(config, fp=None):
"""Dump config data in YAML 1.2 format without headers.
This outputs YAML in a string that is suitable for use in regexps
and string replacements, as well as complete files. It is therefore
explicitly set up to avoid writing out headers and footers.
This is modeled after PyYAML's yaml.dump(), which can dump to a file
or return a string.
https://yaml.dev/doc/ruamel.yaml/example/#Output_of_%60dump()%60_as_a_string
"""
dumper = ruamel.yaml.YAML(typ='rt')
dumper.default_flow_style = False
dumper.explicit_start = False
dumper.explicit_end = False
if fp is None:
with ruamel.yaml.compat.StringIO() as fp:
dumper.dump(config, fp)
return fp.getvalue()
dumper.dump(config, fp)

View file

@ -68,9 +68,18 @@ import struct
import sys
import zipfile
import zlib
from collections import namedtuple
from typing import Any, BinaryIO, Callable, Dict, Iterable, Iterator, Optional, Tuple, Union
from typing import (
Any,
BinaryIO,
Callable,
Dict,
Iterable,
Iterator,
Optional,
Tuple,
Union,
)
__version__ = "1.1.1"
NAME = "apksigcopier"

View file

@ -28,22 +28,21 @@
# the F-Droid client.
import collections
import defusedxml.minidom
import git
import glob
import os
import json
import logging
import requests
import os
import shutil
import tempfile
import zipfile
from argparse import ArgumentParser
from typing import Optional
from . import _
from . import common
from . import deploy
import defusedxml.minidom
import git
import requests
from . import _, common, deploy
from .exception import FDroidException

View file

@ -18,31 +18,27 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import shutil
import argparse
import glob
import subprocess
import logging
import os
import posixpath
import re
import shutil
import subprocess
import tarfile
import threading
import traceback
import time
import requests
import tempfile
import argparse
import logging
import threading
import time
import traceback
from gettext import ngettext
from pathlib import Path
from . import _
from . import common
from . import net
from . import metadata
from . import scanner
from . import vmtools
import requests
from . import _, common, metadata, net, scanner, vmtools
from .common import FDroidPopen
from .exception import FDroidException, BuildException, VCSException
from .exception import BuildException, FDroidException, VCSException
try:
import paramiko
@ -155,9 +151,7 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
ftp.mkdir('fdroidserver')
ftp.chdir('fdroidserver')
ftp.put(os.path.join(serverpath, '..', 'fdroid'), 'fdroid')
ftp.put(os.path.join(serverpath, '..', 'gradlew-fdroid'), 'gradlew-fdroid')
ftp.chmod('fdroid', 0o755) # nosec B103 permissions are appropriate
ftp.chmod('gradlew-fdroid', 0o755) # nosec B103 permissions are appropriate
send_dir(os.path.join(serverpath))
ftp.chdir(homedir)
@ -306,7 +300,7 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
else:
ftp.chdir(posixpath.join(homedir, 'unsigned'))
apkfile = common.get_release_filename(app, build)
tarball = common.getsrcname(app, build)
tarball = common.get_src_tarball_name(app.id, build.versionCode)
try:
ftp.get(apkfile, os.path.join(output_dir, apkfile))
if not options.notarball:
@ -479,7 +473,7 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
logging.critical("Android NDK '%s' is not a directory!" % ndk_path)
raise FDroidException()
common.set_FDroidPopen_env(build)
common.set_FDroidPopen_env(app, build)
# create ..._toolsversion.log when running in builder vm
if onserver:
@ -541,13 +535,13 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
if build.preassemble:
gradletasks += build.preassemble
flavours = build.gradle
if flavours == ['yes']:
flavours = []
flavors = build.gradle
if flavors == ['yes']:
flavors = []
flavours_cmd = ''.join([transform_first_char(flav, str.upper) for flav in flavours])
flavors_cmd = ''.join([transform_first_char(flav, str.upper) for flav in flavors])
gradletasks += ['assemble' + flavours_cmd + 'Release']
gradletasks += ['assemble' + flavors_cmd + 'Release']
cmd = [config['gradle']]
if build.gradleprops:
@ -619,7 +613,7 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
if not options.notarball:
# Build the source tarball right before we build the release...
logging.info("Creating source tarball...")
tarname = common.getsrcname(app, build)
tarname = common.get_src_tarball_name(app.id, build.versionCode)
tarball = tarfile.open(os.path.join(tmp_dir, tarname), "w:gz")
def tarexc(t):
@ -721,8 +715,7 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
bindir = os.path.join(root_dir, 'bin')
if os.path.isdir(os.path.join(build_dir, '.git')):
import git
commit_id = common.get_head_commit_id(git.repo.Repo(build_dir))
commit_id = str(common.get_head_commit_id(build_dir))
else:
commit_id = build.commit
@ -764,11 +757,11 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
# really old path
os.path.join(root_dir, 'build', 'apk'),
]
# If we build with gradle flavours with gradle plugin >= 3.0 the APK will be in
# a subdirectory corresponding to the flavour command used, but with different
# If we build with gradle flavors with gradle plugin >= 3.0 the APK will be in
# a subdirectory corresponding to the flavor command used, but with different
# capitalization.
if flavours_cmd:
apk_dirs.append(os.path.join(root_dir, 'build', 'outputs', 'apk', transform_first_char(flavours_cmd, str.lower), 'release'))
if flavors_cmd:
apk_dirs.append(os.path.join(root_dir, 'build', 'outputs', 'apk', transform_first_char(flavors_cmd, str.lower), 'release'))
for apks_dir in apk_dirs:
for apkglob in ['*-release-unsigned.apk', '*-unsigned.apk', '*.apk']:
apks = glob.glob(os.path.join(apks_dir, apkglob))
@ -1117,10 +1110,7 @@ def main():
srclib_dir = os.path.join(build_dir, 'srclib')
extlib_dir = os.path.join(build_dir, 'extlib')
# Read all app and srclib metadata
pkgs = common.read_pkg_args(options.appid, True)
allapps = metadata.read_metadata(pkgs, sort_by_time=True)
apps = common.read_app_args(options.appid, allapps, True)
apps = common.read_app_args(options.appid, allow_version_codes=True, sort_by_time=True)
for appid, app in list(apps.items()):
if (app.get('Disabled') and not options.force) or not app.get('RepoType') or not app.get('Builds', []):

View file

@ -18,26 +18,34 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import configparser
import copy
import logging
import os
import re
import urllib.request
import urllib.error
import time
import subprocess
import sys
from argparse import ArgumentParser
import time
import traceback
import logging
import copy
import urllib.error
import urllib.parse
import urllib.request
from argparse import ArgumentParser
from pathlib import Path
from typing import Optional
from . import _
from . import common
from . import metadata
from . import net
from .exception import VCSException, NoSubmodulesException, FDroidException, MetaDataException
import git
from . import _, common, metadata, net
from .exception import (
FDroidException,
MetaDataException,
NoSubmodulesException,
VCSException,
)
# https://gitlab.com/fdroid/checkupdates-runner/-/blob/1861899262a62a4ed08fa24e5449c0368dfb7617/.gitlab-ci.yml#L36
BOT_EMAIL = 'fdroidci@bubu1.eu'
def check_http(app: metadata.App) -> tuple[Optional[str], Optional[int]]:
@ -85,7 +93,7 @@ def check_http(app: metadata.App) -> tuple[Optional[str], Optional[int]]:
m = re.search(codeex, page)
if not m:
raise FDroidException("No RE match for version code")
raise FDroidException("No RE match for versionCode")
vercode = common.version_code_string_to_int(m.group(1).strip())
if urlver != '.':
@ -205,7 +213,7 @@ def check_tags(app: metadata.App, pattern: str) -> tuple[str, int, str]:
if codeex:
m = re.search(codeex, filecontent)
if not m:
logging.debug(f"UpdateCheckData regex {codeex} for version code"
logging.debug(f"UpdateCheckData regex {codeex} for versionCode"
f" has no match in tag {tag}")
continue
@ -225,7 +233,7 @@ def check_tags(app: metadata.App, pattern: str) -> tuple[str, int, str]:
if verex:
m = re.search(verex, filecontent)
if not m:
logging.debug(f"UpdateCheckData regex {verex} for version name"
logging.debug(f"UpdateCheckData regex {verex} for versionName"
f" has no match in tag {tag}")
continue
@ -375,7 +383,8 @@ def dirs_with_manifest(startdir: str):
A directory that contains a manifest file of an Android project, None if
no directory could be found
"""
for root, _dirs, files in os.walk(startdir):
for root, dirs, files in os.walk(startdir):
dirs.sort()
if any(m in files for m in [
'AndroidManifest.xml', 'pom.xml', 'build.gradle', 'build.gradle.kts']):
yield Path(root)
@ -668,8 +677,6 @@ def checkupdates_app(app: metadata.App, auto: bool, commit: bool = False) -> Non
if commit:
logging.info("Commiting update for " + app.metadatapath)
gitcmd = ["git", "commit", "-m", commitmsg]
if 'auto_author' in config:
gitcmd.extend(['--author', config['auto_author']])
gitcmd.extend(["--", app.metadatapath])
if subprocess.call(gitcmd) != 0:
raise FDroidException("Git commit failed")
@ -683,6 +690,184 @@ def get_last_build_from_app(app: metadata.App) -> metadata.Build:
return metadata.Build()
def get_upstream_main_branch(git_repo):
refs = list()
for ref in git_repo.remotes.upstream.refs:
if ref.name != 'upstream/HEAD':
refs.append(ref.name)
if len(refs) == 1:
return refs[0]
for name in ('upstream/main', 'upstream/master'):
if name in refs:
return name
try:
with git_repo.config_reader() as reader:
return 'upstream/%s' % reader.get_value('init', 'defaultBranch')
except configparser.NoSectionError:
return 'upstream/main'
def checkout_appid_branch(appid):
"""Prepare the working branch named after the appid.
This sets up everything for checkupdates_app() to run and add
commits. If there is an existing branch named after the appid,
and it has commits from users other than the checkupdates-bot,
then this will return False. Otherwise, it returns True.
The checkupdates-runner must set the committer email address in
the git config. Then any commit with a committer or author that
does not match that will be considered to have human edits. That
email address is currently set in:
https://gitlab.com/fdroid/checkupdates-runner/-/blob/1861899262a62a4ed08fa24e5449c0368dfb7617/.gitlab-ci.yml#L36
"""
logging.debug(f'Creating merge request branch for {appid}')
git_repo = git.Repo.init('.')
upstream_main = get_upstream_main_branch(git_repo)
for remote in git_repo.remotes:
remote.fetch()
try:
git_repo.remotes.origin.fetch(f'{appid}:refs/remotes/origin/{appid}')
except Exception as e:
logging.debug('"%s" branch not found on origin remote:\n\t%s', appid, e)
if appid in git_repo.remotes.origin.refs:
start_point = f"origin/{appid}"
for commit in git_repo.iter_commits(
f'{upstream_main}...{start_point}', right_only=True
):
if commit.committer.email != BOT_EMAIL or commit.author.email != BOT_EMAIL:
return False
else:
start_point = upstream_main
git_repo.git.checkout('-B', appid, start_point)
git_repo.git.rebase(upstream_main, strategy_option='ours', kill_after_timeout=120)
return True
def get_changes_versus_ref(git_repo, ref, f):
changes = []
for m in re.findall(
r"^[+-].*", git_repo.git.diff(f"{ref}", '--', f), flags=re.MULTILINE
):
if not re.match(r"^(\+\+\+|---) ", m):
changes.append(m)
return changes
def push_commits(branch_name='checkupdates'):
"""Make git branch then push commits as merge request.
The appid is parsed from the actual file that was changed so that
only the right branch is ever updated.
This uses the appid as the standard branch name so that there is
only ever one open merge request per-app. If multiple apps are
included in the branch, then 'checkupdates' is used as branch
name. This is to support the old way operating, e.g. in batches.
This uses GitLab "Push Options" to create a merge request. Git
Push Options are config data that can be sent via `git push
--push-option=... origin foo`.
References
----------
* https://docs.gitlab.com/ee/user/project/push_options.html
"""
if branch_name != "checkupdates":
if callable(getattr(git.SymbolicReference, "_check_ref_name_valid", None)):
git.SymbolicReference._check_ref_name_valid(branch_name)
git_repo = git.Repo.init('.')
upstream_main = get_upstream_main_branch(git_repo)
files = set()
for commit in git_repo.iter_commits(f'{upstream_main}...HEAD', right_only=True):
files.update(commit.stats.files.keys())
files = list(files)
if len(files) == 1:
m = re.match(r'metadata/(\S+)\.yml', files[0])
if m:
branch_name = m.group(1) # appid
if not files:
return
# https://git-scm.com/docs/git-check-ref-format Git refname can't end with .lock
if branch_name.endswith(".lock"):
branch_name = f"{branch_name}_"
remote = git_repo.remotes.origin
if branch_name in remote.refs:
if not get_changes_versus_ref(git_repo, f'origin/{branch_name}', files[0]):
return
git_repo.create_head(branch_name, force=True)
push_options = [
'merge_request.create',
'merge_request.remove_source_branch',
'merge_request.title=bot: ' + git_repo.branches[branch_name].commit.summary,
'merge_request.description='
+ '~%s checkupdates-bot run %s' % (branch_name, os.getenv('CI_JOB_URL')),
]
# mark as draft if there are only changes to CurrentVersion:
current_version_only = True
for m in get_changes_versus_ref(git_repo, upstream_main, files[0]):
if not re.match(r"^[-+]CurrentVersion", m):
current_version_only = False
break
if current_version_only:
push_options.append('merge_request.draft')
progress = git.RemoteProgress()
pushinfos = remote.push(
f"HEAD:refs/heads/{branch_name}",
progress=progress,
force=True,
set_upstream=True,
push_option=push_options,
)
for pushinfo in pushinfos:
logging.info(pushinfo.summary)
# Show potentially useful messages from git remote
if progress:
for line in progress.other_lines:
logging.info(line)
if pushinfo.flags & (
git.remote.PushInfo.ERROR
| git.remote.PushInfo.REJECTED
| git.remote.PushInfo.REMOTE_FAILURE
| git.remote.PushInfo.REMOTE_REJECTED
):
raise FDroidException(
f'{remote.url} push failed: {pushinfo.flags} {pushinfo.summary}'
)
else:
logging.info(remote.url + ': ' + pushinfo.summary)
def prune_empty_appid_branches(git_repo=None, main_branch='main'):
"""Remove empty branches from checkupdates-bot git remote."""
if git_repo is None:
git_repo = git.Repo.init('.')
upstream_main = get_upstream_main_branch(git_repo)
main_branch = upstream_main.split('/')[1]
remote = git_repo.remotes.origin
remote.update(prune=True)
merged_branches = git_repo.git().branch(remotes=True, merged=upstream_main).split()
for remote_branch in merged_branches:
if not remote_branch or '/' not in remote_branch:
continue
if remote_branch.split('/')[1] not in (main_branch, 'HEAD'):
for ref in git_repo.remotes.origin.refs:
if remote_branch == ref.name:
remote.push(':%s' % ref.remote_head, force=True) # rm remote branch
def status_update_json(processed: list, failed: dict) -> None:
"""Output a JSON file with metadata about this run."""
logging.debug(_('Outputting JSON'))
@ -716,6 +901,8 @@ def main():
help=_("Only process apps with auto-updates"))
parser.add_argument("--commit", action="store_true", default=False,
help=_("Commit changes"))
parser.add_argument("--merge-request", action="store_true", default=False,
help=_("Commit changes, push, then make a merge request"))
parser.add_argument("--allow-dirty", action="store_true", default=False,
help=_("Run on git repo that has uncommitted changes"))
metadata.add_metadata_arguments(parser)
@ -730,10 +917,11 @@ def main():
logging.error(_('Build metadata git repo has uncommited changes!'))
sys.exit(1)
# Get all apps...
allapps = metadata.read_metadata()
if options.merge_request and not (options.appid and len(options.appid) == 1):
logging.error(_('--merge-request only runs on a single appid!'))
sys.exit(1)
apps = common.read_app_args(options.appid, allapps, False)
apps = common.read_app_args(options.appid)
processed = []
failed = dict()
@ -748,7 +936,17 @@ def main():
logging.info(msg)
try:
checkupdates_app(app, options.auto, options.commit)
if options.merge_request:
if not checkout_appid_branch(appid):
msg = _("...checkupdate failed for {appid} : {error}").format(
appid=appid,
error='Open merge request with human edits, skipped.',
)
logging.warning(msg)
failed[appid] = msg
continue
checkupdates_app(app, options.auto, options.commit or options.merge_request)
processed.append(appid)
except Exception as e:
msg = _("...checkupdate failed for {appid} : {error}").format(appid=appid, error=e)
@ -757,6 +955,10 @@ def main():
failed[appid] = str(e)
exit_code = 1
if options.appid and options.merge_request:
push_commits()
prune_empty_appid_branches()
status_update_json(processed, failed)
sys.exit(exit_code)

File diff suppressed because it is too large Load diff

View file

@ -16,29 +16,28 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import configparser
import glob
import hashlib
import json
import logging
import os
import pathlib
import re
import shutil
import subprocess
import sys
import time
import urllib
from typing import Dict, List
from git import Repo
import yaml
from argparse import ArgumentParser
import logging
from shlex import split
import pathlib
import shutil
from typing import Dict, List
import git
import yaml
from git import Repo
import fdroidserver.github
from . import _
from . import common
from . import index
from . import _, common, index
from .exception import FDroidException
config = None
@ -48,11 +47,10 @@ GIT_BRANCH = 'master'
BINARY_TRANSPARENCY_DIR = 'binary_transparency'
AUTO_S3CFG = '.fdroid-deploy-s3cfg'
USER_S3CFG = 's3cfg'
USER_RCLONE_CONF = None
REMOTE_HOSTNAME_REGEX = re.compile(r'\W*\w+\W+(\w+).*')
EMBEDDED_RCLONE_CONF = 'rclone.conf'
def _get_index_file_paths(base_dir):
"""Return the list of files to be synced last, since they finalize the deploy.
@ -61,8 +59,15 @@ def _get_index_file_paths(base_dir):
services can take a while. So the index files should be updated
last. That ensures that the package files are available when the
client learns about them from the new index files.
signer-index.* are only published in the repo/ section.
"""
return [os.path.join(base_dir, filename) for filename in common.INDEX_FILES]
return [
os.path.join(base_dir, filename)
for filename in common.INDEX_FILES
if not (filename.startswith('signer-index.') and base_dir.endswith('archive'))
]
def _get_index_excludes(base_dir):
@ -92,399 +97,161 @@ def _remove_missing_files(files: List[str]) -> List[str]:
return existing
def _generate_rclone_include_pattern(files):
"""Generate a pattern for rclone's --include flag (https://rclone.org/filtering/)."""
return "{" + ",".join(sorted(set(files))) + "}"
def update_awsbucket(repo_section, is_index_only=False, verbose=False, quiet=False):
"""Upload the contents of the directory `repo_section` (including subdirectories) to the AWS S3 "bucket".
"""Sync the directory `repo_section` (including subdirectories) to AWS S3 US East.
The contents of that subdir of the
bucket will first be deleted.
This is a shim function for public API compatibility.
Requires AWS credentials set as environment variables:
https://rclone.org/s3/#authentication
Requires AWS credentials set in config.yml: awsaccesskeyid, awssecretkey
"""
logging.debug(
f'''Syncing "{repo_section}" to Amazon S3 bucket "{config['awsbucket']}"'''
)
if common.set_command_in_config('s3cmd') and common.set_command_in_config('rclone'):
logging.info(
'Both rclone and s3cmd are installed. Checking config.yml for preference.'
)
if config['s3cmd'] is not True and config['rclone'] is not True:
logging.warning(
'No syncing tool set in config.yml!. Defaulting to using s3cmd'
)
update_awsbucket_s3cmd(repo_section, is_index_only)
if config['s3cmd'] is True and config['rclone'] is True:
logging.warning(
'Both syncing tools set in config.yml!. Defaulting to using s3cmd'
)
update_awsbucket_s3cmd(repo_section, is_index_only)
if config['s3cmd'] is True and config['rclone'] is not True:
update_awsbucket_s3cmd(repo_section, is_index_only)
if config['rclone'] is True and config['s3cmd'] is not True:
update_remote_storage_with_rclone(
repo_section, is_index_only, verbose, quiet
)
elif common.set_command_in_config('s3cmd'):
update_awsbucket_s3cmd(repo_section, is_index_only)
elif common.set_command_in_config('rclone'):
update_remote_storage_with_rclone(repo_section, is_index_only, verbose, quiet)
else:
update_awsbucket_libcloud(repo_section, is_index_only)
def update_awsbucket_s3cmd(repo_section, is_index_only=False):
"""Upload using the CLI tool s3cmd, which provides rsync-like sync.
The upload is done in multiple passes to reduce the chance of
interfering with an existing client-server interaction. In the
first pass, only new files are uploaded. In the second pass,
changed files are uploaded, overwriting what is on the server. On
the third/last pass, the indexes are uploaded, and any removed
files are deleted from the server. The last pass is the only pass
to use a full MD5 checksum of all files to detect changes.
"""
logging.debug(_('Using s3cmd to sync with: {url}').format(url=config['awsbucket']))
if os.path.exists(USER_S3CFG):
logging.info(_('Using "{path}" for configuring s3cmd.').format(path=USER_S3CFG))
configfilename = USER_S3CFG
else:
fd = os.open(AUTO_S3CFG, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600)
logging.debug(
_('Creating "{path}" for configuring s3cmd.').format(path=AUTO_S3CFG)
)
os.write(fd, '[default]\n'.encode('utf-8'))
os.write(
fd, ('access_key = ' + config['awsaccesskeyid'] + '\n').encode('utf-8')
)
os.write(fd, ('secret_key = ' + config['awssecretkey'] + '\n').encode('utf-8'))
os.close(fd)
configfilename = AUTO_S3CFG
s3bucketurl = 's3://' + config['awsbucket']
s3cmd = [config['s3cmd'], '--config=' + configfilename]
if subprocess.call(s3cmd + ['info', s3bucketurl]) != 0:
logging.warning(_('Creating new S3 bucket: {url}').format(url=s3bucketurl))
if subprocess.call(s3cmd + ['mb', s3bucketurl]) != 0:
logging.error(
_('Failed to create S3 bucket: {url}').format(url=s3bucketurl)
)
raise FDroidException()
s3cmd_sync = s3cmd + ['sync', '--acl-public']
options = common.get_options()
if options and options.verbose:
s3cmd_sync += ['--verbose']
if options and options.quiet:
s3cmd_sync += ['--quiet']
s3url = s3bucketurl + '/fdroid/'
logging.debug(
_('s3cmd sync indexes {path} to {url} and delete').format(
path=repo_section, url=s3url
)
)
if is_index_only:
logging.debug(
_('s3cmd syncs indexes from {path} to {url} and deletes removed').format(
path=repo_section, url=s3url
)
)
sync_indexes_flags = []
sync_indexes_flags.extend(_get_index_includes(repo_section))
sync_indexes_flags.append('--delete-removed')
sync_indexes_flags.append('--delete-after')
if options.no_checksum:
sync_indexes_flags.append('--no-check-md5')
else:
sync_indexes_flags.append('--check-md5')
returncode = subprocess.call(
s3cmd_sync + sync_indexes_flags + [repo_section, s3url]
)
if returncode != 0:
raise FDroidException()
else:
logging.debug('s3cmd sync new files in ' + repo_section + ' to ' + s3url)
logging.debug(_('Running first pass with MD5 checking disabled'))
excludes = _get_index_excludes(repo_section)
returncode = subprocess.call(
s3cmd_sync
+ excludes
+ ['--no-check-md5', '--skip-existing', repo_section, s3url]
)
if returncode != 0:
raise FDroidException()
logging.debug('s3cmd sync all files in ' + repo_section + ' to ' + s3url)
returncode = subprocess.call(
s3cmd_sync + excludes + ['--no-check-md5', repo_section, s3url]
)
if returncode != 0:
raise FDroidException()
logging.debug(
_('s3cmd sync indexes {path} to {url} and delete').format(
path=repo_section, url=s3url
)
)
s3cmd_sync.append('--delete-removed')
s3cmd_sync.append('--delete-after')
if options.no_checksum:
s3cmd_sync.append('--no-check-md5')
else:
s3cmd_sync.append('--check-md5')
if subprocess.call(s3cmd_sync + [repo_section, s3url]) != 0:
raise FDroidException()
update_remote_storage_with_rclone(repo_section, is_index_only, verbose, quiet)
def update_remote_storage_with_rclone(
repo_section, is_index_only=False, verbose=False, quiet=False
repo_section,
awsbucket,
is_index_only=False,
verbose=False,
quiet=False,
checksum=False,
):
"""
Upload fdroid repo folder to remote storage using rclone sync.
"""Sync the directory `repo_section` (including subdirectories) to configed cloud services.
Rclone sync can send the files to any supported remote storage
service once without numerous polling.
If remote storage is s3 e.g aws s3, wasabi, filebase then path will be
bucket_name/fdroid/repo where bucket_name will be an s3 bucket
If remote storage is storage drive/sftp e.g google drive, rsync.net
the new path will be bucket_name/fdroid/repo where bucket_name
will be a folder
service once without numerous polling. If remote storage is S3 e.g
AWS S3, Wasabi, Filebase, etc, then path will be
bucket_name/fdroid/repo where bucket_name will be an S3 bucket. If
remote storage is storage drive/sftp e.g google drive, rsync.net the
new path will be bucket_name/fdroid/repo where bucket_name will be a
folder
See https://rclone.org/docs/#config-config-file
rclone filtering works differently than rsync. For example,
"--include" implies "--exclude **" at the end of an rclone internal
filter list.
If rclone.conf is in the root of the repo, then it will be preferred
over the rclone default config paths.
Better than the s3cmd command as it does the syncing in one command
Check https://rclone.org/docs/#config-config-file (optional config file)
"""
logging.debug(_('Using rclone to sync with: {url}').format(url=config['awsbucket']))
logging.debug(_('Using rclone to sync to "{name}"').format(name=awsbucket))
if config.get('path_to_custom_rclone_config') is not None:
USER_RCLONE_CONF = config['path_to_custom_rclone_config']
if os.path.exists(USER_RCLONE_CONF):
logging.info("'path_to_custom_rclone_config' found in config.yml")
logging.info(
_('Using "{path}" for syncing with remote storage.').format(
path=USER_RCLONE_CONF
rclone_config = config.get('rclone_config', [])
if rclone_config and isinstance(rclone_config, str):
rclone_config = [rclone_config]
path = config.get('path_to_custom_rclone_config')
if path:
if not os.path.exists(path):
logging.error(
_('path_to_custom_rclone_config: "{path}" does not exist!').format(
path=path
)
)
configfilename = USER_RCLONE_CONF
else:
logging.info('Custom configuration not found.')
logging.info(
'Using default configuration at {}'.format(
subprocess.check_output(split("rclone config file")).decode("utf-8")
)
)
configfilename = None
sys.exit(1)
configfilename = path
elif os.path.exists(EMBEDDED_RCLONE_CONF):
path = EMBEDDED_RCLONE_CONF # in this case, only for display
configfilename = EMBEDDED_RCLONE_CONF
if not rclone_config:
raise FDroidException(_("'rclone_config' must be set in config.yml!"))
else:
logging.warning("'path_to_custom_rclone_config' not found in config.yml")
logging.info('Custom configuration not found.')
logging.info(
'Using default configuration at {}'.format(
subprocess.check_output(split("rclone config file")).decode("utf-8")
)
)
configfilename = None
output = subprocess.check_output(['rclone', 'config', 'file'], text=True)
default_config_path = output.split('\n')[-2]
if os.path.exists(default_config_path):
path = default_config_path
if path:
logging.info(_('Using "{path}" for rclone config.').format(path=path))
upload_dir = 'fdroid/' + repo_section
if not config.get('rclone_config') or not config.get('awsbucket'):
raise FDroidException(
_('To use rclone, rclone_config and awsbucket must be set in config.yml!')
if not rclone_config:
env = os.environ
# Check both canonical and backup names, but only tell user about canonical.
if not env.get("AWS_SECRET_ACCESS_KEY") and not env.get("AWS_SECRET_KEY"):
raise FDroidException(
_(
""""AWS_SECRET_ACCESS_KEY" must be set as an environmental variable!"""
)
)
if not env.get("AWS_ACCESS_KEY_ID") and not env.get('AWS_ACCESS_KEY'):
raise FDroidException(
_(""""AWS_ACCESS_KEY_ID" must be set as an environmental variable!""")
)
default_remote = "AWS-S3-US-East-1"
env_rclone_config = configparser.ConfigParser()
env_rclone_config.add_section(default_remote)
env_rclone_config.set(
default_remote,
'; = This file is auto-generated by fdroid deploy, do not edit!',
'',
)
env_rclone_config.set(default_remote, "type", "s3")
env_rclone_config.set(default_remote, "provider", "AWS")
env_rclone_config.set(default_remote, "region", "us-east-1")
env_rclone_config.set(default_remote, "env_auth", "true")
if is_index_only:
sources = _get_index_file_paths(repo_section)
sources = _remove_missing_files(sources)
else:
sources = [repo_section]
configfilename = ".fdroid-deploy-rclone.conf"
with open(configfilename, "w", encoding="utf-8") as autoconfigfile:
env_rclone_config.write(autoconfigfile)
rclone_config = [default_remote]
for source in sources:
if isinstance(config['rclone_config'], str):
rclone_sync_command = (
'rclone sync '
+ source
+ ' '
+ config['rclone_config']
+ ':'
+ config['awsbucket']
+ '/'
+ upload_dir
)
rclone_sync_command = ['rclone', 'sync', '--delete-after']
if configfilename:
rclone_sync_command += ['--config', configfilename]
rclone_sync_command = split(rclone_sync_command)
if checksum:
rclone_sync_command.append('--checksum')
if verbose:
rclone_sync_command += ['--verbose']
elif quiet:
rclone_sync_command += ['--quiet']
if verbose:
rclone_sync_command += ['--verbose']
elif quiet:
rclone_sync_command += ['--quiet']
if configfilename:
rclone_sync_command += split('--config=' + configfilename)
complete_remote_path = (
config['rclone_config'] + ':' + config['awsbucket'] + '/' + upload_dir
)
logging.debug(
"rclone sync all files in " + source + ' to ' + complete_remote_path
)
if subprocess.call(rclone_sync_command) != 0:
# TODO copying update_serverwebroot rsync algo
for remote_config in rclone_config:
complete_remote_path = f'{remote_config}:{awsbucket}/{upload_dir}'
logging.info(f'rclone sync to {complete_remote_path}')
if is_index_only:
index_only_files = common.INDEX_FILES + ['diff/*.*']
include_pattern = _generate_rclone_include_pattern(index_only_files)
cmd = rclone_sync_command + [
'--include',
include_pattern,
'--delete-excluded',
repo_section,
complete_remote_path,
]
logging.info(cmd)
if subprocess.call(cmd) != 0:
raise FDroidException()
if isinstance(config['rclone_config'], list):
for remote_config in config['rclone_config']:
rclone_sync_command = (
'rclone sync '
+ source
+ ' '
+ remote_config
+ ':'
+ config['awsbucket']
+ '/'
+ upload_dir
)
rclone_sync_command = split(rclone_sync_command)
if verbose:
rclone_sync_command += ['--verbose']
elif quiet:
rclone_sync_command += ['--quiet']
if configfilename:
rclone_sync_command += split('--config=' + configfilename)
complete_remote_path = (
remote_config + ':' + config['awsbucket'] + '/' + upload_dir
)
logging.debug(
"rclone sync all files in " + source + ' to ' + complete_remote_path
)
if subprocess.call(rclone_sync_command) != 0:
raise FDroidException()
def update_awsbucket_libcloud(repo_section, is_index_only=False):
"""No summary.
Upload the contents of the directory `repo_section` (including
subdirectories) to the AWS S3 "bucket".
The contents of that subdir of the
bucket will first be deleted.
Requires AWS credentials set in config.yml: awsaccesskeyid, awssecretkey
"""
logging.debug(
_('using Apache libcloud to sync with {url}').format(url=config['awsbucket'])
)
import libcloud.security
libcloud.security.VERIFY_SSL_CERT = True
from libcloud.storage.types import Provider, ContainerDoesNotExistError
from libcloud.storage.providers import get_driver
if not config.get('awsaccesskeyid') or not config.get('awssecretkey'):
raise FDroidException(
_(
'To use awsbucket, awssecretkey and awsaccesskeyid must also be set in config.yml!'
else:
cmd = (
rclone_sync_command
+ _get_index_excludes(repo_section)
+ [
repo_section,
complete_remote_path,
]
)
)
awsbucket = config['awsbucket']
if os.path.exists(USER_S3CFG):
raise FDroidException(
_('"{path}" exists but s3cmd is not installed!').format(path=USER_S3CFG)
)
cls = get_driver(Provider.S3)
driver = cls(config['awsaccesskeyid'], config['awssecretkey'])
try:
container = driver.get_container(container_name=awsbucket)
except ContainerDoesNotExistError:
container = driver.create_container(container_name=awsbucket)
logging.info(_('Created new container "{name}"').format(name=container.name))
upload_dir = 'fdroid/' + repo_section
objs = dict()
for obj in container.list_objects():
if obj.name.startswith(upload_dir + '/'):
objs[obj.name] = obj
if is_index_only:
index_files = [
f"{os.getcwd()}/{name}" for name in _get_index_file_paths(repo_section)
]
files_to_upload = [
os.path.join(root, name)
for root, dirs, files in os.walk(os.path.join(os.getcwd(), repo_section))
for name in files
]
files_to_upload = list(set(files_to_upload) & set(index_files))
files_to_upload = _remove_missing_files(files_to_upload)
else:
files_to_upload = [
os.path.join(root, name)
for root, dirs, files in os.walk(os.path.join(os.getcwd(), repo_section))
for name in files
]
for file_to_upload in files_to_upload:
upload = False
object_name = 'fdroid/' + os.path.relpath(file_to_upload, os.getcwd())
if object_name not in objs:
upload = True
else:
obj = objs.pop(object_name)
if obj.size != os.path.getsize(file_to_upload):
upload = True
else:
# if the sizes match, then compare by MD5
md5 = hashlib.md5() # nosec AWS uses MD5
with open(file_to_upload, 'rb') as f:
while True:
data = f.read(8192)
if not data:
break
md5.update(data)
if obj.hash != md5.hexdigest():
s3url = 's3://' + awsbucket + '/' + obj.name
logging.info(' deleting ' + s3url)
if not driver.delete_object(obj):
logging.warning('Could not delete ' + s3url)
upload = True
if upload:
logging.debug(' uploading "' + file_to_upload + '"...')
extra = {'acl': 'public-read'}
if file_to_upload.endswith('.sig'):
extra['content_type'] = 'application/pgp-signature'
elif file_to_upload.endswith('.asc'):
extra['content_type'] = 'application/pgp-signature'
path = os.path.relpath(file_to_upload)
logging.info(f' uploading {path} to s3://{awsbucket}/{object_name}')
with open(file_to_upload, 'rb') as iterator:
obj = driver.upload_object_via_stream(
iterator=iterator,
container=container,
object_name=object_name,
extra=extra,
)
# delete the remnants in the bucket, they do not exist locally
while objs:
object_name, obj = objs.popitem()
s3url = 's3://' + awsbucket + '/' + object_name
if object_name.startswith(upload_dir):
logging.warning(' deleting ' + s3url)
driver.delete_object(obj)
else:
logging.info(' skipping ' + s3url)
if subprocess.call(cmd) != 0:
raise FDroidException()
cmd = rclone_sync_command + [
repo_section,
complete_remote_path,
]
if subprocess.call(cmd) != 0:
raise FDroidException()
def update_serverwebroot(serverwebroot, repo_section):
@ -654,6 +421,13 @@ def update_servergitmirrors(servergitmirrors, repo_section):
For history, there is the archive section, and there is the binary
transparency log.
This will attempt to use the existing remote branch so that it does
not have to push all of the files in the repo each time. Old setups
or runs of `fdroid nightly` might use the "master" branch. For the
"index only" mode, it will recreate the branch from scratch each
time since usually all the files are changed. In any case, the
index files are small compared to the full repo.
"""
from clint.textui import progress
@ -724,7 +498,7 @@ def update_servergitmirrors(servergitmirrors, repo_section):
if is_index_only:
local_branch_name = 'index_only'
else:
local_branch_name = 'full'
local_branch_name = GIT_BRANCH
if local_branch_name in repo.heads:
repo.git.switch(local_branch_name)
else:
@ -849,9 +623,10 @@ def upload_to_servergitmirror(
| git.remote.PushInfo.REMOTE_REJECTED
):
# Show potentially useful messages from git remote
for line in progress.other_lines:
if line.startswith('remote:'):
logging.debug(line)
if progress:
for line in progress.other_lines:
if line.startswith('remote:'):
logging.debug(line)
raise FDroidException(
remote.url
+ ' push failed: '
@ -883,9 +658,10 @@ def upload_to_android_observatory(repo_section):
def upload_apk_to_android_observatory(path):
# depend on requests and lxml only if users enable AO
import requests
from . import net
from lxml.html import fromstring
from . import net
apkfilename = os.path.basename(path)
r = requests.post(
'https://androidobservatory.org/',
@ -1195,7 +971,7 @@ def upload_to_github_releases_repo(repo_conf, release_infos, global_gh_token):
if not token:
logging.warning(
_(
"One of the 'github_releases' config itmes is missing the "
"One of the 'github_releases' config items is missing the "
"'token' value. skipping ..."
)
)
@ -1206,7 +982,7 @@ def upload_to_github_releases_repo(repo_conf, release_infos, global_gh_token):
if not conf_package_names:
logging.warning(
_(
"One of the 'github_releases' config itmes is missing the "
"One of the 'github_releases' config items is missing the "
"'packageNames' value. skipping ..."
)
)
@ -1370,8 +1146,16 @@ def main():
# update_servergitmirrors will take care of multiple mirrors so don't need a foreach
update_servergitmirrors(config['servergitmirrors'], repo_section)
if config.get('awsbucket'):
awsbucket = config['awsbucket']
index_only = config.get('awsbucket_index_only')
update_awsbucket(repo_section, index_only, options.verbose, options.quiet)
update_remote_storage_with_rclone(
repo_section,
awsbucket,
index_only,
options.verbose,
options.quiet,
not options.no_checksum,
)
if config.get('androidobservatory'):
upload_to_android_observatory(repo_section)
if config.get('virustotal_apikey'):

View file

@ -35,6 +35,10 @@ class VCSException(FDroidException):
pass
class NoVersionCodeException(FDroidException):
pass
class NoSubmodulesException(VCSException):
pass

View file

@ -18,17 +18,20 @@
import json
import pathlib
import urllib.request
import urllib.parse
import urllib.request
class GithubApi:
"""
Warpper for some select calls to GitHub Json/REST API.
"""Wrapper for some select calls to GitHub Json/REST API.
This class wraps some calls to api.github.com. This is not intended to be a
general API wrapper. Instead it's purpose is to return pre-filtered and
transformed data that's playing well with other fdroidserver functions.
With the GitHub API, the token is optional, but it has pretty
severe rate limiting.
"""
def __init__(self, api_token, repo_path):
@ -41,9 +44,10 @@ class GithubApi:
def _req(self, url, data=None):
h = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {self._api_token}",
"X-GitHub-Api-Version": "2022-11-28",
}
if self._api_token:
h["Authorization"] = f"Bearer {self._api_token}"
return urllib.request.Request(
url,
headers=h,
@ -65,6 +69,17 @@ class GithubApi:
released_tags = self.list_released_tags()
return [x for x in all_tags if x not in released_tags]
def get_latest_apk(self):
req = self._req(
f"https://api.github.com/repos/{self._repo_path}/releases/latest"
)
with urllib.request.urlopen(req) as resp: # nosec CWE-22 disable bandit warning
assets = json.load(resp)['assets']
for asset in assets:
url = asset.get('browser_download_url')
if url and url.endswith('.apk'):
return url
def tag_exists(self, tag):
"""
Check if git tag is present on github.

View file

@ -16,14 +16,13 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import glob
from argparse import ArgumentParser
import logging
import os
import time
from argparse import ArgumentParser
from . import _
from . import common
from . import _, common
from .common import FDroidPopen
from .exception import FDroidException

View file

@ -18,34 +18,64 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import logging
import os
import re
import stat
import urllib
import git
import json
import shutil
import stat
import sys
import yaml
import urllib
from argparse import ArgumentParser
import logging
from pathlib import Path
from typing import Optional
import git
import yaml
try:
from yaml import CSafeLoader as SafeLoader
except ImportError:
from yaml import SafeLoader
from . import _
from . import common
from . import metadata
from . import _, common, metadata
from .exception import FDroidException
config = None
SETTINGS_GRADLE_REGEX = re.compile(r'settings\.gradle(?:\.kts)?')
GRADLE_SUBPROJECT_REGEX = re.compile(r'''['"]:?([^'"]+)['"]''')
APPLICATION_ID_REGEX = re.compile(r'''\s*applicationId\s=?\s?['"].*['"]''')
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', '.gradle.kts')):
full = Path(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 = path.parent.relative_to(build_dir)
if path.exists() and SETTINGS_GRADLE_REGEX.match(path.name):
for m in GRADLE_SUBPROJECT_REGEX.finditer(path.read_text(encoding='utf-8')):
for f in (path.parent / m.group(1)).glob('build.gradle*'):
with f.open(encoding='utf-8') as fp:
for line in fp:
if common.ANDROID_PLUGIN_REGEX.match(
line
) or APPLICATION_ID_REGEX.match(line):
return f.parent.relative_to(build_dir)
if first_gradle_dir and first_gradle_dir != Path('.'):
return first_gradle_dir
def handle_retree_error_on_windows(function, path, excinfo):
"""Python can't remove a readonly file on Windows so chmod first."""
@ -100,6 +130,7 @@ def getrepofrompage(url: str) -> tuple[Optional[str], str]:
The found repository type or None if an error occured.
address_or_reason
The address to the found repository or the reason if an error occured.
"""
if not url.startswith('http'):
return (None, _('{url} does not start with "http"!'.format(url=url)))
@ -122,7 +153,7 @@ def getrepofrompage(url: str) -> tuple[Optional[str], str]:
index = page.find('hg clone')
if index != -1:
repotype = 'hg'
repo = page[index + 9:]
repo = page[index + 9 :]
index = repo.find('<')
if index == -1:
return (None, _("Error while getting repo address"))
@ -134,7 +165,7 @@ def getrepofrompage(url: str) -> tuple[Optional[str], str]:
index = page.find('git clone')
if index != -1:
repotype = 'git'
repo = page[index + 10:]
repo = page[index + 10 :]
index = repo.find('<')
if index == -1:
return (None, _("Error while getting repo address"))
@ -168,6 +199,7 @@ def get_app_from_url(url: str) -> metadata.App:
If the VCS type could not be determined.
:exc:`ValueError`
If the URL is invalid.
"""
parsed = urllib.parse.urlparse(url)
invalid_url = False
@ -243,18 +275,29 @@ def main():
# Parse command line...
parser = ArgumentParser()
common.setup_global_opts(parser)
parser.add_argument("-u", "--url", default=None,
help=_("Project URL to import from."))
parser.add_argument("-s", "--subdir", default=None,
help=_("Path to main Android project subdirectory, if not in root."))
parser.add_argument("-c", "--categories", default=None,
help=_("Comma separated list of categories."))
parser.add_argument("-l", "--license", default=None,
help=_("Overall license of the project."))
parser.add_argument("--omit-disable", action="store_true", default=False,
help=_("Do not add 'disable:' to the generated build entries"))
parser.add_argument("--rev", default=None,
help=_("Allows a different revision (or git branch) to be specified for the initial import"))
parser.add_argument("-u", "--url", help=_("Project URL to import from."))
parser.add_argument(
"-s",
"--subdir",
help=_("Path to main Android project subdirectory, if not in root."),
)
parser.add_argument(
"-c",
"--categories",
help=_("Comma separated list of categories."),
)
parser.add_argument("-l", "--license", help=_("Overall license of the project."))
parser.add_argument(
"--omit-disable",
action="store_true",
help=_("Do not add 'disable:' to the generated build entries"),
)
parser.add_argument(
"--rev",
help=_(
"Allows a different revision (or git branch) to be specified for the initial import"
),
)
metadata.add_metadata_arguments(parser)
options = common.parse_args(parser)
metadata.warnings_action = options.W
@ -268,24 +311,20 @@ def main():
local_metadata_files = common.get_local_metadata_files()
if local_metadata_files:
raise FDroidException(_("This repo already has local metadata: %s") % local_metadata_files[0])
raise FDroidException(
_("This repo already has local metadata: %s") % local_metadata_files[0]
)
build = metadata.Build()
app = metadata.App()
if options.url is None and Path('.git').is_dir():
app = metadata.App()
app.AutoName = Path.cwd().name
app.RepoType = 'git'
if Path('build.gradle').exists() or Path('build.gradle.kts').exists():
build.gradle = ['yes']
git_repo = git.Repo(Path.cwd())
tmp_importer_dir = Path.cwd()
git_repo = git.Repo(tmp_importer_dir)
for remote in git.Remote.iter_items(git_repo):
if remote.name == 'origin':
url = git_repo.remotes.origin.url
if url.startswith('https://git'): # github, gitlab
app.SourceCode = url.rstrip('.git')
app.Repo = url
app = get_app_from_url(url)
break
write_local_file = True
elif options.url:
@ -294,25 +333,28 @@ def main():
git_repo = git.Repo(tmp_importer_dir)
if not options.omit_disable:
build.disable = 'Generated by `fdroid import` - check version fields and commitid'
build.disable = (
'Generated by `fdroid import` - check version fields and commitid'
)
write_local_file = False
else:
raise FDroidException("Specify project url.")
app.AutoUpdateMode = 'Version'
app.UpdateCheckMode = 'Tags'
build.commit = common.get_head_commit_id(git_repo)
build.commit = common.get_head_commit_id(tmp_importer_dir)
# Extract some information...
paths = common.get_all_gradle_and_manifests(tmp_importer_dir)
subdir = common.get_gradle_subdir(tmp_importer_dir, paths)
paths = get_all_gradle_and_manifests(tmp_importer_dir)
gradle_subdir = get_gradle_subdir(tmp_importer_dir, paths)
if paths:
versionName, versionCode, appid = common.parse_androidmanifests(paths, app)
if not appid:
raise FDroidException(_("Couldn't find Application ID"))
if not versionName:
logging.warning(_('Could not find latest version name'))
logging.warning(_('Could not find latest versionName'))
if not versionCode:
logging.warning(_('Could not find latest version code'))
logging.warning(_('Could not find latest versionCode'))
else:
raise FDroidException(_("No gradle project could be found. Specify --subdir?"))
@ -322,16 +364,15 @@ def main():
# Create a build line...
build.versionName = versionName or 'Unknown'
app.CurrentVersion = build.versionName
build.versionCode = versionCode or 0
app.CurrentVersionCode = build.versionCode
if options.subdir:
build.subdir = options.subdir
build.gradle = ['yes']
elif subdir:
build.subdir = subdir.as_posix()
build.gradle = ['yes']
else:
# subdir might be None
subdir = Path()
elif gradle_subdir:
build.subdir = gradle_subdir.as_posix()
# subdir might be None
subdir = Path(tmp_importer_dir / build.subdir) if build.subdir else tmp_importer_dir
if options.license:
app.License = options.license
@ -339,23 +380,23 @@ def main():
app.Categories = options.categories.split(',')
if (subdir / 'jni').exists():
build.buildjni = ['yes']
if (subdir / 'build.gradle').exists() or (subdir / 'build.gradle').exists():
if (subdir / 'build.gradle').exists() or (subdir / 'build.gradle.kts').exists():
build.gradle = ['yes']
app.AutoName = common.fetch_real_name(subdir, build.gradle)
package_json = tmp_importer_dir / 'package.json' # react-native
pubspec_yaml = tmp_importer_dir / 'pubspec.yaml' # flutter
if package_json.exists():
build.sudo = [
'sysctl fs.inotify.max_user_watches=524288 || true',
'curl -Lo node.tar.gz https://nodejs.org/download/release/v19.3.0/node-v19.3.0-linux-x64.tar.gz',
'echo "b525028ae5bb71b5b32cb7fce903ccce261dbfef4c7dd0f3e0ffc27cd6fc0b3f node.tar.gz" | sha256sum -c -',
'tar xzf node.tar.gz --strip-components=1 -C /usr/local/',
'npm -g install yarn',
'apt-get update',
'apt-get install -y npm',
]
build.init = ['npm install --build-from-source']
with package_json.open() as fp:
data = json.load(fp)
app.AutoName = data.get('name', app.AutoName)
app.AutoName = app.AutoName or data.get('name')
app.License = data.get('license', app.License)
app.Description = data.get('description', app.Description)
app.WebSite = data.get('homepage', app.WebSite)
@ -365,11 +406,11 @@ def main():
if app_json.exists():
with app_json.open() as fp:
data = json.load(fp)
app.AutoName = data.get('name', app.AutoName)
app.AutoName = app.AutoName or data.get('name')
if pubspec_yaml.exists():
with pubspec_yaml.open() as fp:
data = yaml.load(fp, Loader=SafeLoader)
app.AutoName = data.get('name', app.AutoName)
app.AutoName = app.AutoName or data.get('name')
app.License = data.get('license', app.License)
app.Description = data.get('description', app.Description)
app.UpdateCheckData = 'pubspec.yaml|version:\\s.+\\+(\\d+)|.|version:\\s(.+)\\+'
@ -405,8 +446,11 @@ def main():
Path('build').mkdir(exist_ok=True)
build_dir = Path('build') / appid
if build_dir.exists():
logging.warning(_('{path} already exists, ignoring import results!')
.format(path=build_dir))
logging.warning(
_('{path} already exists, ignoring import results!').format(
path=build_dir
)
)
sys.exit(1)
elif tmp_importer_dir:
# For Windows: Close the repo or a git.exe instance holds handles to repo

View file

@ -20,32 +20,49 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Process the index files.
This module is loaded by all fdroid subcommands since it is loaded in
fdroidserver/__init__.py. Any narrowly used dependencies should be
imported where they are used to limit dependencies for subcommands
like publish/signindex/gpgsign. This eliminates the need to have
these installed on the signing server.
"""
import calendar
import collections
import hashlib
import json
import logging
import os
import re
import ruamel.yaml
import shutil
import sys
import tempfile
import urllib.parse
import zipfile
import calendar
import qrcode
from binascii import hexlify, unhexlify
from datetime import datetime, timezone
from pathlib import Path
from xml.dom.minidom import Document
from . import _
from . import common
from . import metadata
from . import net
from . import signindex
from fdroidserver.common import ANTIFEATURES_CONFIG_NAME, CATEGORIES_CONFIG_NAME, CONFIG_CONFIG_NAME, MIRRORS_CONFIG_NAME, RELEASECHANNELS_CONFIG_NAME, DEFAULT_LOCALE, FDroidPopen, FDroidPopenBytes, load_stats_fdroid_signing_key_fingerprints
from fdroidserver._yaml import yaml
from fdroidserver.common import (
ANTIFEATURES_CONFIG_NAME,
CATEGORIES_CONFIG_NAME,
CONFIG_CONFIG_NAME,
DEFAULT_LOCALE,
MIRRORS_CONFIG_NAME,
RELEASECHANNELS_CONFIG_NAME,
FDroidPopen,
FDroidPopenBytes,
load_publish_signer_fingerprints,
)
from fdroidserver.exception import FDroidException, VerificationException
from . import _, common, metadata, signindex
def make(apps, apks, repodir, archive):
"""Generate the repo index files.
@ -77,7 +94,7 @@ def make(apps, apks, repodir, archive):
sortedapps[appid] = apps[appid]
repodict = collections.OrderedDict()
repodict['timestamp'] = datetime.utcnow().replace(tzinfo=timezone.utc)
repodict['timestamp'] = datetime.now(timezone.utc)
repodict['version'] = METADATA_VERSION
if common.config['repo_maxage'] != 0:
@ -116,14 +133,13 @@ def make(apps, apks, repodir, archive):
raise TypeError(_('only accepts strings, lists, and tuples'))
requestsdict[command] = packageNames
fdroid_signing_key_fingerprints = load_stats_fdroid_signing_key_fingerprints()
signer_fingerprints = load_publish_signer_fingerprints()
make_v0(sortedapps, apks, repodir, repodict, requestsdict,
fdroid_signing_key_fingerprints)
make_v1(sortedapps, apks, repodir, repodict, requestsdict,
fdroid_signing_key_fingerprints)
make_v2(sortedapps, apks, repodir, repodict, requestsdict,
fdroid_signing_key_fingerprints, archive)
make_v0(sortedapps, apks, repodir, repodict, requestsdict, signer_fingerprints)
make_v1(sortedapps, apks, repodir, repodict, requestsdict, signer_fingerprints)
make_v2(
sortedapps, apks, repodir, repodict, requestsdict, signer_fingerprints, archive
)
make_website(sortedapps, repodir, repodict)
make_altstore(
sortedapps,
@ -144,23 +160,25 @@ def _should_file_be_generated(path, magic_string):
def make_website(apps, repodir, repodict):
_ignored, repo_pubkey_fingerprint = extract_pubkey()
repo_pubkey_fingerprint_stripped = repo_pubkey_fingerprint.replace(" ", "")
link = repodict["address"]
link_fingerprinted = ('{link}?fingerprint={fingerprint}'
.format(link=link, fingerprint=repo_pubkey_fingerprint_stripped))
# do not change this string, as it will break updates for files with older versions of this string
autogenerate_comment = "auto-generated - fdroid index updates will overwrite this file"
if not os.path.exists(repodir):
os.makedirs(repodir)
qrcode.make(link_fingerprinted).save(os.path.join(repodir, "index.png"))
html_name = 'index.html'
html_file = os.path.join(repodir, html_name)
if _should_file_be_generated(html_file, autogenerate_comment):
import qrcode
_ignored, repo_pubkey_fingerprint = extract_pubkey()
repo_pubkey_fingerprint_stripped = repo_pubkey_fingerprint.replace(" ", "")
link = repodict["address"]
link_fingerprinted = '{link}?fingerprint={fingerprint}'.format(
link=link, fingerprint=repo_pubkey_fingerprint_stripped
)
qrcode.make(link_fingerprinted).save(os.path.join(repodir, "index.png"))
with open(html_file, 'w') as f:
name = repodict["name"]
description = repodict["description"]
@ -509,7 +527,6 @@ def package_metadata(app, repodir):
"AuthorPhone",
"AuthorWebSite",
"Bitcoin",
"FlattrID",
"Liberapay",
"Litecoin",
"OpenCollective",
@ -578,7 +595,10 @@ def convert_version(version, app, repodir):
ver["file"]["ipfsCIDv1"] = ipfsCIDv1
if "srcname" in version:
ver["src"] = common.file_entry(os.path.join(repodir, version["srcname"]))
ver["src"] = common.file_entry(
os.path.join(repodir, version["srcname"]),
version["srcnameSha256"],
)
if "obbMainFile" in version:
ver["obbMainFile"] = common.file_entry(
@ -674,9 +694,13 @@ def v2_repo(repodict, repodir, archive):
config = common.load_localized_config(CONFIG_CONFIG_NAME, repodir)
if config:
repo["name"] = config["archive" if archive else "repo"]["name"]
repo["description"] = config["archive" if archive else "repo"]["description"]
repo["icon"] = config["archive" if archive else "repo"]["icon"]
localized_config = config["archive" if archive else "repo"]
if "name" in localized_config:
repo["name"] = localized_config["name"]
if "description" in localized_config:
repo["description"] = localized_config["description"]
if "icon" in localized_config:
repo["icon"] = localized_config["icon"]
repo["address"] = repodict["address"]
if "mirrors" in repodict:
@ -701,7 +725,7 @@ def v2_repo(repodict, repodir, archive):
return repo
def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints, archive):
def make_v2(apps, packages, repodir, repodict, requestsdict, signer_fingerprints, archive):
def _index_encoder_default(obj):
if isinstance(obj, set):
@ -723,7 +747,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
output["repo"]["requests"] = requestsdict
# establish sort order of the index
v1_sort_packages(packages, fdroid_signing_key_fingerprints)
sort_package_versions(packages, signer_fingerprints)
output_packages = collections.OrderedDict()
output['packages'] = output_packages
@ -762,7 +786,9 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
# include definitions for "auto-defined" categories, e.g. just used in app metadata
for category in sorted(categories_used_by_apps):
if category not in output['repo'][CATEGORIES_CONFIG_NAME]:
output['repo'][CATEGORIES_CONFIG_NAME][category] = {"name": {DEFAULT_LOCALE: category}}
output['repo'][CATEGORIES_CONFIG_NAME][category] = dict()
if 'name' not in output['repo'][CATEGORIES_CONFIG_NAME][category]:
output['repo'][CATEGORIES_CONFIG_NAME][category]['name'] = {DEFAULT_LOCALE: category}
# do not include defined categories if no apps use them
for category in list(output['repo'].get(CATEGORIES_CONFIG_NAME, list())):
if category not in categories_used_by_apps:
@ -838,7 +864,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
signindex.sign_index(repodir, json_name)
def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints):
def make_v1(apps, packages, repodir, repodict, requestsdict, signer_fingerprints):
def _index_encoder_default(obj):
if isinstance(obj, set):
@ -868,7 +894,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
output['repo']['mirrors'] = mirrors
# establish sort order of the index
v1_sort_packages(packages, fdroid_signing_key_fingerprints)
sort_package_versions(packages, signer_fingerprints)
appslist = []
output['apps'] = appslist
@ -941,7 +967,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
for k, v in sorted(package.items()):
if not v:
continue
if k in ('icon', 'icons', 'icons_src', 'ipfsCIDv1', 'name'):
if k in ('icon', 'icons', 'icons_src', 'ipfsCIDv1', 'name', 'srcnameSha256'):
continue
if k == 'antiFeatures':
d[k] = sorted(v.keys())
@ -976,8 +1002,8 @@ def _copy_to_local_copy_dir(repodir, f):
.format(path=local_copy_dir))
def v1_sort_packages(packages, fdroid_signing_key_fingerprints):
"""Sort the supplied list to ensure a deterministic sort order for package entries in the index file.
def sort_package_versions(packages, signer_fingerprints):
"""Sort to ensure a deterministic order for package versions in the index file.
This sort-order also expresses
installation preference to the clients.
@ -1002,7 +1028,7 @@ def v1_sort_packages(packages, fdroid_signing_key_fingerprints):
if dev_signer and dev_signer == signer:
group = GROUP_DEV_SIGNED
else:
fdroid_signer = fdroid_signing_key_fingerprints.get(packageName, {}).get('signer')
fdroid_signer = signer_fingerprints.get(packageName, {}).get('signer')
if fdroid_signer and fdroid_signer == signer:
group = GROUP_FDROID_SIGNED
@ -1015,7 +1041,7 @@ def v1_sort_packages(packages, fdroid_signing_key_fingerprints):
packages.sort(key=v1_sort_keys)
def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints):
def make_v0(apps, apks, repodir, repodict, requestsdict, signer_fingerprints):
"""Aka index.jar aka index.xml."""
doc = Document()
@ -1114,7 +1140,7 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
if name_from_apk is None:
name_from_apk = apk.get('name')
for versionCode, apksforver in apksbyversion.items():
fdroid_signer = fdroid_signing_key_fingerprints.get(appid, {}).get('signer')
fdroid_signer = signer_fingerprints.get(appid, {}).get('signer')
fdroid_signed_apk = None
name_match_apk = None
for x in apksforver:
@ -1169,7 +1195,6 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
addElementNonEmpty('donate', app.Donate, doc, apel)
addElementNonEmpty('bitcoin', app.Bitcoin, doc, apel)
addElementNonEmpty('litecoin', app.Litecoin, doc, apel)
addElementNonEmpty('flattr', app.FlattrID, doc, apel)
addElementNonEmpty('openCollective', app.OpenCollective, doc, apel)
# These elements actually refer to the current version (i.e. which
@ -1312,6 +1337,29 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
os.remove(siglinkname)
os.symlink(sigfile_path, siglinkname)
if sys.version_info.minor >= 13:
# Python 3.13 changed minidom so it no longer converts " to an XML entity.
# https://github.com/python/cpython/commit/154477be722ae5c4e18d22d0860e284006b09c4f
# This just puts back the previous implementation, with black code format.
import inspect
import xml.dom.minidom
def _write_data(writer, text, attr): # pylint: disable=unused-argument
if text:
text = (
text.replace('&', '&amp;')
.replace('<', '&lt;')
.replace('"', '&quot;')
.replace('>', '&gt;')
)
writer.write(text)
argnames = tuple(inspect.signature(xml.dom.minidom._write_data).parameters)
if argnames == ('writer', 'text', 'attr'):
xml.dom.minidom._write_data = _write_data
else:
logging.warning('Failed to monkey patch minidom for index.xml support!')
if common.options.pretty:
output = doc.toprettyxml(encoding='utf-8')
else:
@ -1357,7 +1405,15 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
% repo_icon)
os.makedirs(os.path.dirname(iconfilename), exist_ok=True)
try:
import qrcode
qrcode.make(common.config['repo_url']).save(iconfilename)
except ModuleNotFoundError as e:
raise ModuleNotFoundError(
_(
'The "qrcode" Python package is not installed (e.g. apt-get install python3-qrcode)!'
)
) from e
except Exception:
exampleicon = os.path.join(common.get_examples_dir(),
common.default_config['repo_icon'])
@ -1424,7 +1480,7 @@ def add_mirrors_to_repodict(repo_section, repodict):
)
)
with mirrors_yml.open() as fp:
mirrors_config = ruamel.yaml.YAML(typ='safe').load(fp)
mirrors_config = yaml.load(fp)
if not isinstance(mirrors_config, list):
msg = _('{path} is not list, but a {datatype}!')
raise TypeError(
@ -1478,6 +1534,7 @@ def add_mirrors_to_repodict(repo_section, repodict):
repodict['mirrors'] = []
canonical_url = repodict['address']
found_primary = False
errors = 0
for mirror in mirrors:
if canonical_url == mirror['url']:
found_primary = True
@ -1486,9 +1543,19 @@ def add_mirrors_to_repodict(repo_section, repodict):
for k in sorted(mirror.keys()):
sortedmirror[k] = mirror[k]
repodict['mirrors'].insert(0, sortedmirror)
elif mirror.get('isPrimary'):
errors += 1
logging.error(
_('Mirror config for {url} contains "isPrimary" key!').format(
url=mirror['url']
)
)
else:
repodict['mirrors'].append(mirror)
if errors:
raise FDroidException(_('"isPrimary" key should not be added to mirrors!'))
if repodict['mirrors'] and not found_primary:
repodict['mirrors'].insert(0, {'isPrimary': True, 'url': repodict['address']})
@ -1603,6 +1670,8 @@ def download_repo_index_v1(url_str, etag=None, verify_fingerprint=True, timeout=
- The new eTag as returned by the HTTP request
"""
from . import net
url = urllib.parse.urlsplit(url_str)
fingerprint = None
@ -1635,7 +1704,7 @@ def download_repo_index_v1(url_str, etag=None, verify_fingerprint=True, timeout=
return index, new_etag
def download_repo_index_v2(url_str, etag=None, verify_fingerprint=True, timeout=600):
def download_repo_index_v2(url_str, etag=None, verify_fingerprint=True, timeout=None):
"""Download and verifies index v2 file, then returns its data.
Downloads the repository index from the given :param url_str and
@ -1654,8 +1723,15 @@ def download_repo_index_v2(url_str, etag=None, verify_fingerprint=True, timeout=
- The new eTag as returned by the HTTP request
"""
from . import net
etag # etag is unused but needs to be there to keep the same API as the earlier functions.
url = urllib.parse.urlsplit(url_str)
if timeout is not None:
logging.warning('"timeout" argument of download_repo_index_v2() is deprecated!')
fingerprint = None
if verify_fingerprint:
query = urllib.parse.parse_qs(url.query)
@ -1667,29 +1743,22 @@ def download_repo_index_v2(url_str, etag=None, verify_fingerprint=True, timeout=
path = url.path.rsplit('/', 1)[0]
else:
path = url.path.rstrip('/')
url = urllib.parse.SplitResult(url.scheme, url.netloc, path, '', '')
url = urllib.parse.SplitResult(url.scheme, url.netloc, path + '/entry.jar', '', '')
download, new_etag = net.http_get(url.geturl(), etag, timeout)
mirrors = common.get_mirrors(url, 'entry.jar')
f = net.download_using_mirrors(mirrors)
entry, public_key, fingerprint = get_index_from_jar(f, fingerprint)
if download is None:
return None, new_etag
# jarsigner is used to verify the JAR, it requires a file for input
with tempfile.TemporaryDirectory() as dirname:
with (Path(dirname) / 'entry.jar').open('wb') as fp:
fp.write(download)
fp.flush()
entry, public_key, fingerprint = get_index_from_jar(fp.name, fingerprint)
name = entry['index']['name']
sha256 = entry['index']['sha256']
url = urllib.parse.SplitResult(url.scheme, url.netloc, path + name, '', '')
index, _ignored = net.http_get(url.geturl(), None, timeout)
mirrors = common.get_mirrors(url, entry['index']['name'][1:])
f = net.download_using_mirrors(mirrors)
with open(f, 'rb') as fp:
index = fp.read()
if sha256 != hashlib.sha256(index).hexdigest():
raise VerificationException(
_("SHA-256 of {url} does not match entry!").format(url=url)
)
return json.loads(index), new_etag
return json.loads(index), None
def get_index_from_jar(jarfile, fingerprint=None, allow_deprecated=False):

View file

@ -19,16 +19,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import glob
import logging
import os
import re
import shutil
import socket
import sys
from argparse import ArgumentParser
import logging
from . import _
from . import common
from . import _, common
from .exception import FDroidException
config = {}
@ -38,13 +37,13 @@ def disable_in_config(key, value):
"""Write a key/value to the local config.yml, then comment it out."""
import yaml
with open('config.yml') as f:
data = f.read()
with open(common.CONFIG_FILE) as fp:
data = fp.read()
pattern = r'\n[\s#]*' + key + r':.*'
repl = '\n#' + yaml.dump({key: value}, default_flow_style=False)
data = re.sub(pattern, repl, data)
with open('config.yml', 'w') as f:
f.writelines(data)
with open(common.CONFIG_FILE, 'w') as fp:
fp.writelines(data)
def main():
@ -82,7 +81,7 @@ def main():
)
options = common.parse_args(parser)
common.set_console_logging(options.verbose)
common.set_console_logging(options.verbose, options.color)
fdroiddir = os.getcwd()
test_config = dict()
@ -138,24 +137,24 @@ def main():
_("Android SDK not found at {path}!").format(path=test_config['sdk_path'])
)
if not os.path.exists('config.yml') and not os.path.exists('config.py'):
if not os.path.exists(common.CONFIG_FILE):
# 'metadata' and 'tmp' are created in fdroid
if not os.path.exists('repo'):
os.mkdir('repo')
example_config_yml = os.path.join(examplesdir, 'config.yml')
example_config_yml = os.path.join(examplesdir, common.CONFIG_FILE)
if os.path.exists(example_config_yml):
shutil.copyfile(example_config_yml, 'config.yml')
shutil.copyfile(example_config_yml, common.CONFIG_FILE)
else:
from pkg_resources import get_distribution
versionstr = get_distribution('fdroidserver').version
if not versionstr:
versionstr = 'master'
with open('config.yml', 'w') as fp:
with open(common.CONFIG_FILE, 'w') as fp:
fp.write('# see https://gitlab.com/fdroid/fdroidserver/blob/')
fp.write(versionstr)
fp.write('/examples/config.yml\n')
os.chmod('config.yml', 0o0600)
fp.write(f'/examples/{common.CONFIG_FILE}\n')
os.chmod(common.CONFIG_FILE, 0o0600)
# If android_home is None, test_config['sdk_path'] will be used and
# "$ANDROID_HOME" may be used if the env var is set up correctly.
# If android_home is not None, the path given from the command line

View file

@ -17,35 +17,298 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import glob
from argparse import ArgumentParser
import locale
import logging
import os
import sys
import termios
import tty
from argparse import ArgumentParser, BooleanOptionalAction
from pathlib import Path
from urllib.parse import urlencode, urlparse, urlunparse
from . import _
from . import common
from .common import SdkToolsPopen
import defusedxml.ElementTree as XMLElementTree
from . import _, common, github, index, net
from .exception import FDroidException
config = None
DEFAULT_IPFS_GATEWAYS = ("https://gateway.ipfs.io/ipfs/",)
MAVEN_CENTRAL_MIRRORS = [
{
"url": "https://repo1.maven.org/maven2/",
"dnsA": ["199.232.16.209"],
"worksWithoutSNI": True,
},
{
"url": "https://repo.maven.apache.org/maven2/",
"dnsA": ["199.232.16.215"],
"worksWithoutSNI": True,
},
{
"url": "https://maven-central-asia.storage-download.googleapis.com/maven2/",
},
{
"url": "https://maven-central-eu.storage-download.googleapis.com/maven2/",
},
{
"url": "https://maven-central.storage-download.googleapis.com/maven2/",
},
]
# pylint: disable=unused-argument
def download_apk(appid='org.fdroid.fdroid', privacy_mode=False):
"""Download an APK from F-Droid via the first mirror that works."""
url = urlunparse(
urlparse(common.FDROIDORG_MIRRORS[0]['url'])._replace(
query=urlencode({'fingerprint': common.FDROIDORG_FINGERPRINT})
)
)
data, _ignored = index.download_repo_index_v2(url)
app = data.get('packages', dict()).get(appid)
preferred_version = None
for version in app['versions'].values():
if not preferred_version:
# if all else fails, use the first one
preferred_version = version
if not version.get('releaseChannels'):
# prefer APK in default release channel
preferred_version = version
break
mirrors = common.append_filename_to_mirrors(
preferred_version['file']['name'][1:], common.FDROIDORG_MIRRORS
)
ipfsCIDv1 = preferred_version['file'].get('ipfsCIDv1')
if ipfsCIDv1:
for gateway in DEFAULT_IPFS_GATEWAYS:
mirrors.append({'url': os.path.join(gateway, ipfsCIDv1)})
f = net.download_using_mirrors(mirrors)
if f and os.path.exists(f):
versionCode = preferred_version['manifest']['versionCode']
f = Path(f)
return str(f.rename(f.with_stem(f'{appid}_{versionCode}')).resolve())
def download_fdroid_apk(privacy_mode=False): # pylint: disable=unused-argument
"""Directly download the current F-Droid APK and verify it.
This downloads the "download button" link, which is the version
that is best tested for new installs.
"""
mirror = common.FDROIDORG_MIRRORS[0]
mirror['url'] = urlunparse(urlparse(mirror['url'])._replace(path='F-Droid.apk'))
return net.download_using_mirrors([mirror])
def download_fdroid_apk_from_github(privacy_mode=False):
"""Download F-Droid.apk from F-Droid's GitHub Releases."""
if common.config and not privacy_mode:
token = common.config.get('github_token')
else:
token = None
gh = github.GithubApi(token, 'https://github.com/f-droid/fdroidclient')
latest_apk = gh.get_latest_apk()
filename = os.path.basename(latest_apk)
return net.download_file(latest_apk, os.path.join(common.get_cachedir(), filename))
def download_fdroid_apk_from_ipns(privacy_mode=False):
"""Download the F-Droid APK from an IPNS repo."""
cid = 'k51qzi5uqu5dl4hbcksbdmplanu9n4hivnqsupqe6vzve1pdbeh418ssptldd3'
mirrors = [
{"url": f"https://ipfs.io/ipns/{cid}/F-Droid.apk"},
]
if not privacy_mode:
mirrors.append({"url": f"https://{cid}.ipns.dweb.link/F-Droid.apk"})
return net.download_using_mirrors(mirrors)
def download_fdroid_apk_from_maven(privacy_mode=False):
"""Download F-Droid.apk from Maven Central and official mirrors."""
path = 'org/fdroid/fdroid/F-Droid'
if privacy_mode:
mirrors = MAVEN_CENTRAL_MIRRORS[:2] # skip the Google servers
else:
mirrors = MAVEN_CENTRAL_MIRRORS
metadata = net.download_using_mirrors(
common.append_filename_to_mirrors(
os.path.join(path, 'maven-metadata.xml'), mirrors
)
)
version = XMLElementTree.parse(metadata).getroot().findall('*.//latest')[0].text
mirrors = common.append_filename_to_mirrors(
os.path.join(path, version, f'F-Droid-{version}.apk'), mirrors
)
return net.download_using_mirrors(mirrors)
def install_fdroid_apk(privacy_mode=False):
"""Download and install F-Droid.apk using all tricks we can muster.
By default, this first tries to fetch the official install APK
which is offered when someone clicks the "download" button on
https://f-droid.org/. Then it will try all the mirrors and
methods until it gets something successful, or runs out of
options.
There is privacy_mode which tries to download from mirrors first,
so that this downloads from a mirror that has many different kinds
of files available, thereby breaking the clear link to F-Droid.
Returns
-------
None for success or the error message.
"""
country_code = locale.getlocale()[0].split('_')[-1]
if privacy_mode is None and country_code in ('CN', 'HK', 'IR', 'TM'):
logging.warning(
_('Privacy mode was enabled based on your locale ({country_code}).').format(
country_code=country_code
)
)
privacy_mode = True
if privacy_mode or not (common.config and common.config.get('jarsigner')):
download_methods = [
download_fdroid_apk_from_maven,
download_fdroid_apk_from_ipns,
download_fdroid_apk_from_github,
]
else:
download_methods = [
download_apk,
download_fdroid_apk_from_maven,
download_fdroid_apk_from_github,
download_fdroid_apk_from_ipns,
download_fdroid_apk,
]
for method in download_methods:
try:
f = method(privacy_mode=privacy_mode)
break
except Exception as e:
logging.info(e)
else:
return _('F-Droid.apk could not be downloaded from any known source!')
fingerprint = common.apk_signer_fingerprint(f)
if fingerprint.upper() != common.FDROIDORG_FINGERPRINT:
return _('{path} has the wrong fingerprint ({fingerprint})!').format(
path=f, fingerprint=fingerprint
)
install_apk(f)
def install_apk(f):
if common.config and common.config.get('apksigner'):
# TODO this should always verify, but that requires APK sig verification in Python #94
logging.info(_('Verifying package {path} with apksigner.').format(path=f))
common.verify_apk_signature(f)
if common.config and common.config.get('adb'):
if devices():
install_apks_to_devices([f])
os.remove(f)
else:
os.remove(f)
return _('No devices found for `adb install`! Please plug one in.')
def devices():
p = SdkToolsPopen(['adb', "devices"])
"""Get the list of device serials for use with adb commands."""
p = common.SdkToolsPopen(['adb', "devices"])
if p.returncode != 0:
raise FDroidException("An error occured when finding devices: %s" % p.output)
lines = [line for line in p.output.splitlines() if not line.startswith('* ')]
if len(lines) < 3:
return []
lines = lines[1:-1]
return [line.split()[0] for line in lines]
serials = list()
for line in p.output.splitlines():
columns = line.strip().split("\t", maxsplit=1)
if len(columns) == 2:
serial, status = columns
if status == 'device':
serials.append(serial)
else:
d = {'serial': serial, 'status': status}
logging.warning(_('adb reports {serial} is "{status}"!'.format(**d)))
return serials
def install_apks_to_devices(apks):
"""Install the list of APKs to all Android devices reported by `adb devices`."""
for apk in apks:
# Get device list each time to avoid device not found errors
devs = devices()
if not devs:
raise FDroidException(_("No attached devices found"))
logging.info(_("Installing %s...") % apk)
for dev in devs:
logging.info(
_("Installing '{apkfilename}' on {dev}...").format(
apkfilename=apk, dev=dev
)
)
p = common.SdkToolsPopen(['adb', "-s", dev, "install", apk])
fail = ""
for line in p.output.splitlines():
if line.startswith("Failure"):
fail = line[9:-1]
if not fail:
continue
if fail == "INSTALL_FAILED_ALREADY_EXISTS":
logging.warning(
_('"{apkfilename}" is already installed on {dev}.').format(
apkfilename=apk, dev=dev
)
)
else:
raise FDroidException(
_("Failed to install '{apkfilename}' on {dev}: {error}").format(
apkfilename=apk, dev=dev, error=fail
)
)
def read_char():
"""Read input from the terminal prompt one char at a time."""
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def strtobool(val):
"""Convert a localized string representation of truth to True or False."""
return val.lower() in ('', 'y', 'yes', _('yes'), _('true')) # '' is pressing Enter
def prompt_user(yes, msg):
"""Prompt user for yes/no, supporting Enter and Esc as accepted answers."""
run_install = yes
if yes is None and sys.stdout.isatty():
print(msg, end=' ', flush=True)
answer = ''
while True:
in_char = read_char()
if in_char == '\r': # Enter key
break
if not in_char.isprintable():
sys.exit(1)
print(in_char, end='', flush=True)
answer += in_char
run_install = strtobool(answer)
print()
return run_install
def main():
global config
# Parse command line...
parser = ArgumentParser(
usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]"
)
@ -62,22 +325,56 @@ def main():
default=False,
help=_("Install all signed applications available"),
)
parser.add_argument(
"-p",
"--privacy-mode",
action=BooleanOptionalAction,
default=None,
help=_("Download F-Droid.apk using mirrors that leak less to the network"),
)
parser.add_argument(
"-y",
"--yes",
action="store_true",
default=None,
help=_("Automatic yes to all prompts."),
)
parser.add_argument(
"-n",
"--no",
action="store_false",
dest='yes',
help=_("Automatic no to all prompts."),
)
options = common.parse_args(parser)
common.set_console_logging(options.verbose)
common.set_console_logging(options.verbose, options.color)
logging.captureWarnings(True) # for SNIMissingWarning
common.get_config()
if not options.appid and not options.all:
parser.error(
_("option %s: If you really want to install all the signed apps, use --all")
% "all"
run_install = prompt_user(
options.yes,
_('Would you like to download and install F-Droid.apk via adb? (YES/no)'),
)
config = common.read_config()
if run_install:
sys.exit(install_fdroid_apk(options.privacy_mode))
sys.exit(1)
output_dir = 'repo'
if not os.path.isdir(output_dir):
logging.info(_("No signed output directory - nothing to do"))
sys.exit(0)
if (options.appid or options.all) and not os.path.isdir(output_dir):
logging.error(_("No signed output directory - nothing to do"))
run_install = prompt_user(
options.yes,
_('Would you like to download the app(s) from f-droid.org? (YES/no)'),
)
if run_install:
for appid in options.appid:
f = download_apk(appid)
install_apk(f)
sys.exit(install_fdroid_apk(options.privacy_mode))
sys.exit(1)
if options.appid:
vercodes = common.read_pkg_args(options.appid, True)
@ -99,45 +396,14 @@ def main():
for appid, apk in apks.items():
if not apk:
raise FDroidException(_("No signed APK available for %s") % appid)
install_apks_to_devices(apks.values())
else:
elif options.all:
apks = {
common.publishednameinfo(apkfile)[0]: apkfile
for apkfile in sorted(glob.glob(os.path.join(output_dir, '*.apk')))
}
for appid, apk in apks.items():
# Get device list each time to avoid device not found errors
devs = devices()
if not devs:
raise FDroidException(_("No attached devices found"))
logging.info(_("Installing %s...") % apk)
for dev in devs:
logging.info(
_("Installing '{apkfilename}' on {dev}...").format(
apkfilename=apk, dev=dev
)
)
p = SdkToolsPopen(['adb', "-s", dev, "install", apk])
fail = ""
for line in p.output.splitlines():
if line.startswith("Failure"):
fail = line[9:-1]
if not fail:
continue
if fail == "INSTALL_FAILED_ALREADY_EXISTS":
logging.warning(
_('"{apkfilename}" is already installed on {dev}.').format(
apkfilename=apk, dev=dev
)
)
else:
raise FDroidException(
_("Failed to install '{apkfilename}' on {dev}: {error}").format(
apkfilename=apk, dev=dev, error=fail
)
)
install_apks_to_devices(apks.values())
logging.info('\n' + _('Finished'))

View file

@ -24,7 +24,7 @@ import urllib.parse
from argparse import ArgumentParser
from pathlib import Path
import ruamel.yaml
from fdroidserver._yaml import yaml
from . import _, common, metadata, rewritemeta
@ -159,10 +159,6 @@ regex_checks = {
],
'Donate': http_checks
+ [
(
re.compile(r'.*flattr\.com'),
_("Flattr donation methods belong in the FlattrID: field"),
),
(
re.compile(r'.*liberapay\.com'),
_("Liberapay donation methods belong in the Liberapay: field"),
@ -217,6 +213,82 @@ regex_checks = {
],
}
# config keys that are currently ignored by lint, but could be supported.
ignore_config_keys = (
'github_releases',
'java_paths',
)
bool_keys = (
'allow_disabled_algorithms',
'androidobservatory',
'build_server_always',
'deploy_process_logs',
'keep_when_not_allowed',
'make_current_version_link',
'nonstandardwebroot',
'per_app_repos',
'refresh_scanner',
'scan_binary',
'sync_from_local_copy_dir',
)
check_config_keys = (
'ant',
'apk_signing_key_block_list',
'archive',
'archive_description',
'archive_icon',
'archive_name',
'archive_older',
'archive_url',
'archive_web_base_url',
'awsbucket',
'awsbucket_index_only',
'binary_transparency_remote',
'cachedir',
'char_limits',
'current_version_name_source',
'git_mirror_size_limit',
'github_token',
'gpghome',
'gpgkey',
'gradle',
'identity_file',
'install_list',
'java_paths',
'keyaliases',
'keydname',
'keypass',
'keystore',
'keystorepass',
'lint_licenses',
'local_copy_dir',
'mirrors',
'mvn3',
'ndk_paths',
'path_to_custom_rclone_config',
'rclone_config',
'repo',
'repo_description',
'repo_icon',
'repo_key_sha256',
'repo_keyalias',
'repo_maxage',
'repo_name',
'repo_pubkey',
'repo_url',
'repo_web_base_url',
'scanner_signature_sources',
'sdk_path',
'servergitmirrors',
'serverwebroot',
'smartcardoptions',
'sync_from_local_copy_dir',
'uninstall_list',
'virustotal_apikey',
)
locale_pattern = re.compile(r"[a-z]{2,3}(-([A-Z][a-zA-Z]+|\d+|[a-z]+))*")
versioncode_check_pattern = re.compile(r"(\\d|\[(0-9|\\d)_?(a-fA-F)?])[+]")
@ -297,7 +369,7 @@ def check_update_check_data_int(app): # noqa: D403
# codeex can be empty as well
if codeex and not versioncode_check_pattern.search(codeex):
yield _(
f'UpdateCheckData must match the version code as integer (\\d or [0-9]): {codeex}'
f'UpdateCheckData must match the versionCode as integer (\\d or [0-9]): {codeex}'
)
@ -505,11 +577,20 @@ def check_format(app):
def check_license_tag(app):
"""Ensure all license tags contain only valid/approved values."""
if config['lint_licenses'] is None:
return
if app.License not in config['lint_licenses']:
if config['lint_licenses'] == APPROVED_LICENSES:
"""Ensure all license tags contain only valid/approved values.
It is possible to disable license checking by setting a null or empty value,
e.g. `lint_licenses: ` or `lint_licenses: []`
"""
if 'lint_licenses' in config:
lint_licenses = config['lint_licenses']
if lint_licenses is None:
return
else:
lint_licenses = APPROVED_LICENSES
if app.License not in lint_licenses:
if lint_licenses == APPROVED_LICENSES:
yield _(
'Unexpected license tag "{}"! Only use FSF or OSI '
'approved tags from https://spdx.org/license-list'
@ -530,13 +611,23 @@ def check_extlib_dir(apps):
used = set()
for app in apps:
for build in app.get('Builds', []):
if app.Disabled:
continue
archive_policy = common.calculate_archive_policy(
app, common.config['archive_older']
)
builds = [build for build in app.Builds if not build.disable]
for i in range(len(builds)):
build = builds[i]
for path in build.extlibs:
path = Path(path)
if path not in extlib_files:
yield _(
"{appid}: Unknown extlib {path} in build '{versionName}'"
).format(appid=app.id, path=path, versionName=build.versionName)
# Don't show error on archived versions
if i >= len(builds) - archive_policy:
yield _(
"{appid}: Unknown extlib {path} in build '{versionName}'"
).format(appid=app.id, path=path, versionName=build.versionName)
else:
used.add(path)
@ -761,7 +852,7 @@ def lint_config(arg):
passed = False
with path.open() as fp:
data = ruamel.yaml.YAML(typ='safe').load(fp)
data = yaml.load(fp)
common.config_type_check(arg, data)
if path.name == mirrors_name:
@ -785,6 +876,41 @@ def lint_config(arg):
msg += ' '
msg += _('Did you mean {code}?').format(code=', '.join(sorted(m)))
print(msg)
elif path.name == config_name and path.parent.name != 'config':
valid_keys = set(tuple(common.default_config) + bool_keys + check_config_keys)
for key in ignore_config_keys:
if key in valid_keys:
valid_keys.remove(key)
for key in data:
if key not in valid_keys:
passed = False
msg = _("ERROR: {key} not a valid key!").format(key=key)
m = difflib.get_close_matches(key.lower(), valid_keys, 2, 0.5)
if m:
msg += ' '
msg += _('Did you mean {code}?').format(code=', '.join(sorted(m)))
print(msg)
continue
if key in bool_keys:
t = bool
else:
t = type(common.default_config.get(key, ""))
show_error = False
if t is str:
if type(data[key]) not in (str, list, dict):
passed = False
show_error = True
elif type(data[key]) != t:
passed = False
show_error = True
if show_error:
print(
_("ERROR: {key}'s value should be of type {t}!").format(
key=key, t=t.__name__
)
)
elif path.name in (config_name, categories_name, antifeatures_name):
for key in data:
if path.name == config_name and key not in ('archive', 'repo'):
@ -858,7 +984,7 @@ def main():
paths = list()
for arg in options.appid:
if (
arg == 'config.yml'
arg == common.CONFIG_FILE
or Path(arg).parent.name == 'config'
or Path(arg).parent.parent.name == 'config' # localized
):
@ -882,9 +1008,7 @@ def main():
def lint_metadata(options):
# Get all apps...
allapps = metadata.read_metadata(options.appid)
apps = common.read_app_args(options.appid, allapps, False)
apps = common.read_app_args(options.appid)
anywarns = check_for_unsupported_metadata_files()

View file

@ -115,7 +115,7 @@ __license__ = "Python License 2.0"
# been done in the StrictVersion class above. This works great as long
# as everyone can go along with bondage and discipline. Hopefully a
# (large) subset of Python module programmers will agree that the
# particular flavour of bondage and discipline provided by StrictVersion
# particular flavor of bondage and discipline provided by StrictVersion
# provides enough benefit to be worth using, and will submit their
# version numbering scheme to its domination. The free-thinking
# anarchists in the lot will never give in, though, and something needs

View file

@ -18,18 +18,18 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import git
from pathlib import Path
import math
import platform
import os
import re
import logging
import ruamel.yaml
import math
import os
import platform
import re
from collections import OrderedDict
from pathlib import Path
from . import common
from . import _
import ruamel.yaml
from . import _, common
from ._yaml import yaml
from .exception import MetaDataException
srclibs = None
@ -67,7 +67,6 @@ yaml_app_field_order = [
'Translation',
'Changelog',
'Donate',
'FlattrID',
'Liberapay',
'OpenCollective',
'Bitcoin',
@ -128,7 +127,6 @@ class App(dict):
self.Translation = ''
self.Changelog = ''
self.Donate = None
self.FlattrID = None
self.Liberapay = None
self.OpenCollective = None
self.Bitcoin = None
@ -408,10 +406,6 @@ class FieldValidator:
# Generic value types
valuetypes = {
FieldValidator("Flattr ID",
r'^[0-9a-z]+$',
['FlattrID']),
FieldValidator("Liberapay",
VALID_USERNAME_REGEX,
['Liberapay']),
@ -478,7 +472,6 @@ def parse_yaml_srclib(metadatapath):
with metadatapath.open("r", encoding="utf-8") as f:
try:
yaml = ruamel.yaml.YAML(typ='safe')
data = yaml.load(f)
if type(data) is not dict:
if platform.system() == 'Windows':
@ -544,14 +537,14 @@ def read_srclibs():
srclibs = {}
srcdir = Path('srclibs')
srcdir.mkdir(exist_ok=True)
srclibs_dir = Path('srclibs')
srclibs_dir.mkdir(exist_ok=True)
for metadatapath in sorted(srcdir.glob('*.yml')):
for metadatapath in sorted(srclibs_dir.glob('*.yml')):
srclibs[metadatapath.stem] = parse_yaml_srclib(metadatapath)
def read_metadata(appids={}, sort_by_time=False):
def read_metadata(appid_to_vercode={}, sort_by_time=False):
"""Return a list of App instances sorted newest first.
This reads all of the metadata files in a 'data' repository, then
@ -559,7 +552,7 @@ def read_metadata(appids={}, sort_by_time=False):
sorted based on creation time, newest first. Most of the time,
the newer files are the most interesting.
appids is a dict with appids a keys and versionCodes as values.
appid_to_vercode is a dict with appids a keys and versionCodes as values.
"""
# Always read the srclibs before the apps, since they can use a srlib as
@ -571,9 +564,8 @@ def read_metadata(appids={}, sort_by_time=False):
for basedir in ('metadata', 'tmp'):
Path(basedir).mkdir(exist_ok=True)
if appids:
vercodes = common.read_pkg_args(appids)
metadatafiles = common.get_metadata_files(vercodes)
if appid_to_vercode:
metadatafiles = common.get_metadata_files(appid_to_vercode)
else:
metadatafiles = list(Path('metadata').glob('*.yml')) + list(
Path('.').glob('.fdroid.yml')
@ -665,14 +657,12 @@ def parse_metadata(metadatapath):
build_dir = common.get_build_dir(app)
metadata_in_repo = build_dir / '.fdroid.yml'
if metadata_in_repo.is_file():
try:
commit_id = common.get_head_commit_id(git.Repo(build_dir))
commit_id = common.get_head_commit_id(build_dir)
if commit_id is not None:
logging.debug(
_('Including metadata from %s@%s') % (metadata_in_repo, commit_id)
)
# See https://github.com/PyCQA/pylint/issues/2856 .
# pylint: disable-next=no-member
except git.exc.InvalidGitRepositoryError:
else:
logging.debug(
_('Including metadata from {path}').format(path=metadata_in_repo)
)
@ -716,8 +706,7 @@ def parse_yaml_metadata(mf):
"""
try:
yaml = ruamel.yaml.YAML(typ='safe')
yamldata = yaml.load(mf)
yamldata = common.yaml.load(mf)
except ruamel.yaml.YAMLError as e:
_warn_or_exception(
_("could not parse '{path}'").format(path=mf.name)
@ -1256,19 +1245,24 @@ def _app_to_yaml(app):
def write_yaml(mf, app):
"""Write metadata in yaml format.
This requires the 'rt' round trip dumper to maintain order and needs
custom indent settings, so it needs to instantiate its own YAML
instance. Therefore, this function deliberately avoids using any of
the common YAML parser setups.
Parameters
----------
mf
active file discriptor for writing
app
app metadata to written to the yaml file
app metadata to written to the YAML file
"""
_del_duplicated_NoSourceSince(app)
yaml_app = _app_to_yaml(app)
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.dump(yaml_app, stream=mf)
yamlmf = ruamel.yaml.YAML(typ='rt')
yamlmf.indent(mapping=2, sequence=4, offset=2)
yamlmf.dump(yaml_app, stream=mf)
def write_metadata(metadatapath, app):

View file

@ -7,13 +7,10 @@ import posixpath
import socket
import subprocess
import sys
from argparse import ArgumentParser
import urllib.parse
from argparse import ArgumentParser
from . import _
from . import common
from . import index
from . import update
from . import _, common, index, update
def _run_wget(path, urls, verbose=False):
@ -91,7 +88,7 @@ def main():
)
options = common.parse_args(parser)
common.set_console_logging(options.verbose)
common.set_console_logging(options.verbose, options.color)
if options.all:
options.archive = True
@ -133,6 +130,7 @@ def main():
import io
import json
import zipfile
from . import net
url = _append_to_url_path(section, 'index-v1.jar')

View file

@ -17,13 +17,21 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
import logging
import os
import requests
import random
import tempfile
import time
import urllib
import requests
import urllib3
from requests.adapters import HTTPAdapter, Retry
from requests.exceptions import ChunkedEncodingError
from . import _, common
logger = logging.getLogger(__name__)
HEADERS = {'User-Agent': 'F-Droid'}
@ -64,14 +72,88 @@ def download_file(url, local_filename=None, dldir='tmp', retries=3, backoff_fact
f.write(chunk)
f.flush()
return local_filename
except ChunkedEncodingError as err:
except requests.exceptions.ChunkedEncodingError as err:
if i == retries:
raise err
logging.warning('Download interrupted, retrying...')
logger.warning('Download interrupted, retrying...')
time.sleep(backoff_factor * 2**i)
raise ValueError("retries must be >= 0")
def download_using_mirrors(mirrors, local_filename=None):
"""Try to download the file from any working mirror.
Download the file that all URLs in the mirrors list point to,
trying all the tricks, starting with the most private methods
first. The list of mirrors is converted into a list of mirror
configurations to try, in order that the should be attempted.
This builds mirror_configs_to_try using all possible combos to
try. If a mirror is marked with worksWithoutSNI: True, then this
logic will try it twice: first without SNI, then again with SNI.
"""
mirrors = common.parse_list_of_dicts(mirrors)
mirror_configs_to_try = []
for mirror in mirrors:
mirror_configs_to_try.append(mirror)
if mirror.get('worksWithoutSNI'):
m = copy.deepcopy(mirror)
del m['worksWithoutSNI']
mirror_configs_to_try.append(m)
if not local_filename:
for mirror in mirrors:
filename = urllib.parse.urlparse(mirror['url']).path.split('/')[-1]
if filename:
break
if filename:
local_filename = os.path.join(common.get_cachedir(), filename)
else:
local_filename = tempfile.mkstemp(prefix='fdroid-')
timeouts = (2, 10, 100)
last_exception = None
for timeout in timeouts:
for mirror in mirror_configs_to_try:
last_exception = None
urllib3.util.ssl_.HAS_SNI = not mirror.get('worksWithoutSNI')
try:
# the stream=True parameter keeps memory usage low
r = requests.get(
mirror['url'],
stream=True,
allow_redirects=False,
headers=HEADERS,
# add jitter to the timeout to be less predictable
timeout=timeout + random.randint(0, timeout), # nosec B311
)
if r.status_code != 200:
raise requests.exceptions.HTTPError(r.status_code, response=r)
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.flush()
return local_filename
except (
ConnectionError,
requests.exceptions.ChunkedEncodingError,
requests.exceptions.ConnectionError,
requests.exceptions.ContentDecodingError,
requests.exceptions.HTTPError,
requests.exceptions.SSLError,
requests.exceptions.StreamConsumedError,
requests.exceptions.Timeout,
requests.exceptions.UnrewindableBodyError,
) as e:
last_exception = e
logger.debug(_('Retrying failed download: %s') % str(e))
# if it hasn't succeeded by now, then give up and raise last exception
if last_exception:
raise last_exception
def http_get(url, etag=None, timeout=600):
"""Download the content from the given URL by making a GET request.

View file

@ -19,24 +19,25 @@
import base64
import datetime
import git
import hashlib
import inspect
import logging
import os
import paramiko
import platform
import shutil
import ssl
import subprocess
import sys
import tempfile
import yaml
from urllib.parse import urlparse
from argparse import ArgumentParser
from typing import Optional
from urllib.parse import urlparse
from . import _
from . import common
import git
import paramiko
import yaml
from . import _, common
from .exception import VCSException
# hard coded defaults for Android ~/.android/debug.keystore files
@ -176,7 +177,9 @@ def _ssh_key_from_debug_keystore(keystore: Optional[str] = None) -> str:
return ssh_private_key_file
def get_repo_base_url(clone_url: str, repo_git_base: str, force_type: Optional[str] = None) -> str:
def get_repo_base_url(
clone_url: str, repo_git_base: str, force_type: Optional[str] = None
) -> str:
"""Generate the base URL for the F-Droid repository.
Parameters
@ -203,6 +206,41 @@ def get_repo_base_url(clone_url: str, repo_git_base: str, force_type: Optional[s
sys.exit(1)
def clone_git_repo(clone_url, git_mirror_path):
"""Clone a git repo into the given path, failing if a password is required.
If GitPython's safe mode is present, this will use that. Otherwise,
this includes a very limited version of the safe mode just to ensure
this won't hang on password prompts.
https://github.com/gitpython-developers/GitPython/pull/2029
"""
logging.debug(_('cloning {url}').format(url=clone_url))
try:
sig = inspect.signature(git.Repo.clone_from)
if 'safe' in sig.parameters:
git.Repo.clone_from(clone_url, git_mirror_path, safe=True)
else:
git.Repo.clone_from(
clone_url,
git_mirror_path,
env={
'GIT_ASKPASS': '/bin/true',
'SSH_ASKPASS': '/bin/true',
'GIT_USERNAME': 'u',
'GIT_PASSWORD': 'p',
'GIT_HTTP_USERNAME': 'u',
'GIT_HTTP_PASSWORD': 'p',
'GIT_SSH': '/bin/false', # for git < 2.3
'GIT_TERMINAL_PROMPT': '0',
},
)
except git.exc.GitCommandError as e:
logging.warning(_('WARNING: only public git repos are supported!'))
raise VCSException(f'git clone {clone_url} failed:', str(e)) from e
def main():
"""Deploy to F-Droid repository or generate SSH private key from keystore.
@ -288,19 +326,27 @@ def main():
# we are in GitLab CI
repo_git_base = os.getenv('CI_PROJECT_PATH') + NIGHTLY
clone_url = os.getenv('CI_PROJECT_URL') + NIGHTLY
repo_base = get_repo_base_url(clone_url, repo_git_base, force_type='gitlab.com')
repo_base = get_repo_base_url(
clone_url, repo_git_base, force_type='gitlab.com'
)
servergitmirror = 'git@' + urlparse(clone_url).netloc + ':' + repo_git_base
deploy_key_url = clone_url + '/-/settings/repository#js-deploy-keys-settings'
deploy_key_url = (
f'{clone_url}/-/settings/repository#js-deploy-keys-settings'
)
git_user_name = os.getenv('GITLAB_USER_NAME')
git_user_email = os.getenv('GITLAB_USER_EMAIL')
elif 'TRAVIS_REPO_SLUG' in os.environ:
# we are in Travis CI
repo_git_base = os.getenv('TRAVIS_REPO_SLUG') + NIGHTLY
clone_url = 'https://github.com/' + repo_git_base
repo_base = get_repo_base_url(clone_url, repo_git_base, force_type='github.com')
repo_base = get_repo_base_url(
clone_url, repo_git_base, force_type='github.com'
)
servergitmirror = 'git@github.com:' + repo_git_base
deploy_key_url = ('https://github.com/' + repo_git_base + '/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys')
deploy_key_url = (
f'https://github.com/{repo_git_base}/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys'
)
git_user_name = repo_git_base
git_user_email = os.getenv('USER') + '@' + platform.node()
elif (
@ -309,23 +355,35 @@ def main():
and 'CIRCLE_PROJECT_REPONAME' in os.environ
):
# we are in Circle CI
repo_git_base = (os.getenv('CIRCLE_PROJECT_USERNAME')
+ '/' + os.getenv('CIRCLE_PROJECT_REPONAME') + NIGHTLY)
repo_git_base = (
os.getenv('CIRCLE_PROJECT_USERNAME')
+ '/'
+ os.getenv('CIRCLE_PROJECT_REPONAME')
+ NIGHTLY
)
clone_url = os.getenv('CIRCLE_REPOSITORY_URL') + NIGHTLY
repo_base = get_repo_base_url(clone_url, repo_git_base, force_type='github.com')
repo_base = get_repo_base_url(
clone_url, repo_git_base, force_type='github.com'
)
servergitmirror = 'git@' + urlparse(clone_url).netloc + ':' + repo_git_base
deploy_key_url = ('https://github.com/' + repo_git_base + '/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys')
deploy_key_url = (
f'https://github.com/{repo_git_base}/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys'
)
git_user_name = os.getenv('CIRCLE_USERNAME')
git_user_email = git_user_name + '@' + platform.node()
elif 'GITHUB_ACTIONS' in os.environ:
# we are in Github actions
repo_git_base = (os.getenv('GITHUB_REPOSITORY') + NIGHTLY)
clone_url = (os.getenv('GITHUB_SERVER_URL') + '/' + repo_git_base)
repo_base = get_repo_base_url(clone_url, repo_git_base, force_type='github.com')
repo_git_base = os.getenv('GITHUB_REPOSITORY') + NIGHTLY
clone_url = os.getenv('GITHUB_SERVER_URL') + '/' + repo_git_base
repo_base = get_repo_base_url(
clone_url, repo_git_base, force_type='github.com'
)
servergitmirror = 'git@' + urlparse(clone_url).netloc + ':' + repo_git_base
deploy_key_url = ('https://github.com/' + repo_git_base + '/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys')
deploy_key_url = (
f'https://github.com/{repo_git_base}/settings/keys'
+ '\nhttps://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys'
)
git_user_name = os.getenv('GITHUB_ACTOR')
git_user_email = git_user_name + '@' + platform.node()
else:
@ -337,16 +395,12 @@ def main():
git_mirror_fdroiddir = os.path.join(git_mirror_path, 'fdroid')
git_mirror_repodir = os.path.join(git_mirror_fdroiddir, 'repo')
git_mirror_metadatadir = os.path.join(git_mirror_fdroiddir, 'metadata')
git_mirror_statsdir = os.path.join(git_mirror_fdroiddir, 'stats')
if not os.path.isdir(git_mirror_repodir):
logging.debug(_('cloning {url}').format(url=clone_url))
vcs = common.getvcs('git', clone_url, git_mirror_path)
p = vcs.git(['clone', '--', vcs.remote, str(vcs.local)])
if p.returncode != 0:
print('WARNING: only public git repos are supported!')
raise VCSException('git clone %s failed:' % clone_url, p.output)
clone_git_repo(clone_url, git_mirror_path)
if not os.path.isdir(git_mirror_repodir):
os.makedirs(git_mirror_repodir, mode=0o755)
if os.path.exists('LICENSE'):
shutil.copy2('LICENSE', git_mirror_path)
mirror_git_repo = git.Repo.init(git_mirror_path)
writer = mirror_git_repo.config_writer()
@ -365,9 +419,13 @@ You can use it with the [F-Droid](https://f-droid.org/) Android app.
[![{repo_url}]({repo_url}/icons/icon.png)](https://fdroid.link/#{repo_url})
Last updated: {date}'''.format(repo_git_base=repo_git_base,
repo_url=repo_url,
date=datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'))
Last updated: {date}'''.format(
repo_git_base=repo_git_base,
repo_url=repo_url,
date=datetime.datetime.now(datetime.timezone.utc).strftime(
'%Y-%m-%d %H:%M:%S UTC'
),
)
with open(readme_path, 'w') as fp:
fp.write(readme)
mirror_git_repo.git.add(all=True)
@ -381,8 +439,6 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base,
common.local_rsync(options, [git_mirror_repodir + '/'], 'repo/')
if os.path.isdir(git_mirror_metadatadir):
common.local_rsync(options, [git_mirror_metadatadir + '/'], 'metadata/')
if os.path.isdir(git_mirror_statsdir):
common.local_rsync(options, [git_mirror_statsdir + '/'], 'stats/')
ssh_private_key_file = _ssh_key_from_debug_keystore()
# this is needed for GitPython to find the SSH key
@ -422,19 +478,17 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base,
'keypass': PASSWORD,
'keydname': DISTINGUISHED_NAME,
'make_current_version_link': False,
'update_stats': True,
}
with open('config.yml', 'w') as fp:
with open(common.CONFIG_FILE, 'w', encoding='utf-8') as fp:
yaml.dump(config, fp, default_flow_style=False)
os.chmod('config.yml', 0o600)
os.chmod(common.CONFIG_FILE, 0o600)
config = common.read_config()
common.assert_config_keystore(config)
logging.debug(
_('Run over {cibase} to find -debug.apk. and skip repo_basedir {repo_basedir}').format(
cibase=cibase,
repo_basedir=repo_basedir
)
_(
'Run over {cibase} to find -debug.apk. and skip repo_basedir {repo_basedir}'
).format(cibase=cibase, repo_basedir=repo_basedir)
)
for root, dirs, files in os.walk(cibase):
@ -496,7 +550,6 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base,
common.local_rsync(
options, [repo_basedir + '/metadata/'], git_mirror_metadatadir + '/'
)
common.local_rsync(options, [repo_basedir + '/stats/'], git_mirror_statsdir + '/')
mirror_git_repo.git.add(all=True)
mirror_git_repo.index.commit("update app metadata")
@ -523,10 +576,16 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base,
if not os.path.exists(androiddir):
os.mkdir(androiddir)
logging.info(_('created {path}').format(path=androiddir))
logging.error(_('{path} does not exist! Create it by running:').format(path=options.keystore)
+ '\n keytool -genkey -v -keystore ' + options.keystore + ' -storepass android \\'
+ '\n -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 \\'
+ '\n -dname "CN=Android Debug,O=Android,C=US"')
logging.error(
_('{path} does not exist! Create it by running:').format(
path=options.keystore
)
+ '\n keytool -genkey -v -keystore '
+ options.keystore
+ ' -storepass android \\'
+ '\n -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 \\'
+ '\n -dname "CN=Android Debug,O=Android,C=US"'
)
sys.exit(1)
ssh_dir = os.path.join(os.getenv('HOME'), '.ssh')
privkey = _ssh_key_from_debug_keystore(options.keystore)

View file

@ -28,23 +28,21 @@ mostly reports success by moving an APK from unsigned/ to repo/
"""
import sys
import glob
import hashlib
import json
import logging
import os
import re
import shutil
import glob
import hashlib
from argparse import ArgumentParser
from collections import OrderedDict
import logging
from gettext import ngettext
import json
import sys
import time
import zipfile
from argparse import ArgumentParser
from collections import OrderedDict
from gettext import ngettext
from . import _
from . import common
from . import metadata
from . import _, common, metadata
from .common import FDroidPopen
from .exception import BuildException, FDroidException
@ -139,13 +137,13 @@ def sign_sig_key_fingerprint_list(jar_file):
raise FDroidException("Failed to sign '{}'!".format(jar_file))
def store_stats_fdroid_signing_key_fingerprints(appids, indent=None):
def store_publish_signer_fingerprints(appids, indent=None):
"""Store list of all signing-key fingerprints for given appids to HD.
This list will later on be needed by fdroid update.
"""
if not os.path.exists('stats'):
os.makedirs('stats')
if not os.path.exists('repo'):
os.makedirs('repo')
data = OrderedDict()
fps = read_fingerprints_from_keystore()
for appid in sorted(appids):
@ -153,9 +151,12 @@ def store_stats_fdroid_signing_key_fingerprints(appids, indent=None):
if alias in fps:
data[appid] = {'signer': fps[key_alias(appid)]}
jar_file = os.path.join('stats', 'publishsigkeys.jar')
jar_file = os.path.join('repo', 'signer-index.jar')
output = json.dumps(data, indent=indent)
with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
jar.writestr('publishsigkeys.json', json.dumps(data, indent=indent))
jar.writestr('signer-index.json', output)
with open(os.path.join('repo', 'signer-index.json'), 'w') as fp:
fp.write(output)
sign_sig_key_fingerprint_list(jar_file)
@ -344,7 +345,6 @@ def main():
glob.glob(os.path.join(unsigned_dir, '*.apk'))
+ glob.glob(os.path.join(unsigned_dir, '*.zip'))
):
appid, vercode = common.publishednameinfo(apkfile)
apkfilename = os.path.basename(apkfile)
if vercodes and appid not in vercodes:
@ -368,7 +368,6 @@ def main():
if b.get("versionCode") == vercode:
build = b
if app.Binaries or (build and build.binary):
# It's an app where we build from source, and verify the apk
# contents against a developer's binary, and then publish their
# version if everything checks out.
@ -379,15 +378,21 @@ def main():
srcapk = srcapk.replace(unsigned_dir, binaries_dir)
if not os.path.isfile(srcapk):
logging.error("...reference binary missing - publish skipped: "
"'{refpath}'".format(refpath=srcapk))
logging.error(
"...reference binary missing - publish skipped: '{refpath}'".format(
refpath=srcapk
)
)
failed += 1
else:
# Compare our unsigned one with the downloaded one...
compare_result = common.verify_apks(srcapk, apkfile, tmp_dir)
if compare_result:
logging.error("...verification failed - publish skipped : "
"{result}".format(result=compare_result))
logging.error(
"...verification failed - publish skipped : {result}".format(
result=compare_result
)
)
failed += 1
else:
# Success! So move the downloaded file to the repo, and remove
@ -399,7 +404,6 @@ def main():
logging.info('Published ' + apkfilename)
elif apkfile.endswith('.zip'):
# OTA ZIPs built by fdroid do not need to be signed by jarsigner,
# just to be moved into place in the repo
shutil.move(apkfile, os.path.join(output_dir, apkfilename))
@ -407,7 +411,6 @@ def main():
logging.info('Published ' + apkfilename)
else:
# It's a 'normal' app, i.e. we sign and publish it...
skipsigning = False
@ -446,10 +449,11 @@ def main():
signed_apk_path = os.path.join(output_dir, apkfilename)
if os.path.exists(signed_apk_path):
raise BuildException("Refusing to sign '{0}' file exists in both "
"{1} and {2} folder.".format(apkfilename,
unsigned_dir,
output_dir))
raise BuildException(
_(
"Refusing to sign '{path}', file exists in both {dir1} and {dir2} folder."
).format(path=apkfilename, dir1=unsigned_dir, dir2=output_dir)
)
# Sign the application...
common.sign_apk(apkfile, signed_apk_path, keyalias)
@ -460,7 +464,7 @@ def main():
publish_source_tarball(apkfilename, unsigned_dir, output_dir)
logging.info('Published ' + apkfilename)
store_stats_fdroid_signing_key_fingerprints(allapps.keys())
store_publish_signer_fingerprints(allapps.keys())
status_update_json(generated_keys, signed_apks)
logging.info('published list signing-key fingerprints')

View file

@ -17,8 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from argparse import ArgumentParser
from . import common
from . import metadata
from . import common, metadata
def main():

View file

@ -17,16 +17,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from argparse import ArgumentParser
import logging
import io
import tempfile
import logging
import shutil
import tempfile
from argparse import ArgumentParser
from pathlib import Path
from . import _
from . import common
from . import metadata
from . import _, common, metadata
config = None
@ -81,9 +79,7 @@ def main():
config = common.read_config()
# Get all apps...
allapps = metadata.read_metadata(options.appid)
apps = common.read_app_args(options.appid, allapps, False)
apps = common.read_app_args(options.appid)
for appid, app in apps.items():
path = Path(app.metadatapath)

View file

@ -16,7 +16,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import imghdr
import itertools
import json
import logging
@ -29,10 +28,21 @@ import urllib.request
import zipfile
from argparse import ArgumentParser
from dataclasses import dataclass, field, fields
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from enum import IntEnum
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Union
try:
import magic
except ImportError:
import puremagic as magic
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib
from . import _, common, metadata, scanner
from .exception import BuildException, ConfigurationException, VCSException
@ -53,18 +63,198 @@ MAVEN_URL_REGEX = re.compile(
DEPFILE = {
"Cargo.toml": ["Cargo.lock"],
"pubspec.yaml": ["pubspec.lock"],
"package.json": ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
"package.json": ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lock"],
}
SCANNER_CACHE_VERSION = 1
DEFAULT_CATALOG_PREFIX_REGEX = re.compile(
r'''defaultLibrariesExtensionName\s*=\s*['"](\w+)['"]'''
)
GRADLE_CATALOG_FILE_REGEX = re.compile(
r'''(?:create\()?['"]?(\w+)['"]?\)?\s*\{[^}]*from\(files\(['"]([^"]+)['"]\)\)'''
)
VERSION_CATALOG_REGEX = re.compile(r'versionCatalogs\s*\{')
APK_SIGNING_BLOCK_IDS = {
# https://source.android.com/docs/security/features/apksigning/v2#apk-signing-block
# 0x7109871a: 'APK signature scheme v2',
# https://source.android.com/docs/security/features/apksigning/v3#apk-signing-block
# 0xf05368c0: 'APK signature scheme v3',
# See "Security metadata in early 2018"
# https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html
0x2146444E: 'Google Play Signature aka "Frosting"',
# 0x42726577: 'Verity padding',
# 0x6DFF800D: 'Source stamp V2 X509 cert',
# JSON with some metadata, used by Chinese company Meituan
0x71777777: 'Meituan payload',
# Dependencies metadata generated by Gradle and encrypted by Google Play.
# '...The data is compressed, encrypted by a Google Play signing key...'
# https://developer.android.com/studio/releases/gradle-plugin#dependency-metadata
0x504B4453: 'Dependency metadata',
}
class ExitCode(IntEnum):
NONFREE_CODE = 1
class GradleVersionCatalog:
"""Parse catalog from libs.versions.toml.
https://docs.gradle.org/current/userguide/platforms.html
"""
def __init__(self, catalog):
self.version = {
alias: self.get_version(version)
for alias, version in catalog.get("versions", {}).items()
}
self.libraries = {
self.alias_to_accessor(alias): self.library_to_coordinate(library)
for alias, library in catalog.get("libraries", {}).items()
}
self.plugins = {
self.alias_to_accessor(alias): self.plugin_to_coordinate(plugin)
for alias, plugin in catalog.get("plugins", {}).items()
}
self.bundles = {
self.alias_to_accessor(alias): self.bundle_to_coordinates(bundle)
for alias, bundle in catalog.get("bundles", {}).items()
}
@staticmethod
def alias_to_accessor(alias: str) -> str:
"""Covert alias to accessor.
https://docs.gradle.org/current/userguide/platforms.html#sub:mapping-aliases-to-accessors
Alias is used to define a lib in catalog. Accessor is used to access it.
"""
return alias.replace("-", ".").replace("_", ".")
def get_version(self, version: Union[dict, str]) -> str:
if isinstance(version, str):
return version
ref = version.get("ref")
if ref:
return self.version.get(ref, "")
return (
version.get("prefer", "")
or version.get("require", "")
or version.get("strictly", "")
)
def library_to_coordinate(self, library: Union[dict, str]) -> str:
"""Generate the Gradle dependency coordinate from catalog."""
if isinstance(library, str):
return library
module = library.get("module")
if not module:
group = library.get("group")
name = library.get("name")
if group and name:
module = f"{group}:{name}"
else:
return ""
version = library.get("version")
if version:
return f"{module}:{self.get_version(version)}"
else:
return module
def plugin_to_coordinate(self, plugin: Union[dict, str]) -> str:
"""Generate the Gradle plugin coordinate from catalog."""
if isinstance(plugin, str):
return plugin
id = plugin.get("id")
if not id:
return ""
version = plugin.get("version")
if version:
return f"{id}:{self.get_version(version)}"
else:
return id
def bundle_to_coordinates(self, bundle: list[str]) -> list[str]:
"""Generate the Gradle dependency bundle coordinate from catalog."""
coordinates = []
for alias in bundle:
library = self.libraries.get(self.alias_to_accessor(alias))
if library:
coordinates.append(library)
return coordinates
def get_coordinate(self, accessor: str) -> list[str]:
"""Get the Gradle coordinate from the catalog with an accessor."""
if accessor.startswith("plugins."):
return [
self.plugins.get(accessor[8:].removesuffix(".asLibraryDependency"), "")
]
if accessor.startswith("bundles."):
return self.bundles.get(accessor[8:], [])
return [self.libraries.get(accessor, "")]
def get_catalogs(root: str) -> dict[str, GradleVersionCatalog]:
"""Get all Gradle dependency catalogs from settings.gradle[.kts].
Returns a dict with the extension and the corresponding catalog.
The extension is used as the prefix of the accessor to access libs in the catalog.
"""
root = Path(root)
catalogs = {}
default_prefix = "libs"
catalog_files_m = []
def find_block_end(s, start):
pat = re.compile("[{}]")
depth = 1
for m in pat.finditer(s, pos=start):
if m.group() == "{":
depth += 1
else:
depth -= 1
if depth == 0:
return m.start()
else:
return -1
groovy_file = root / "settings.gradle"
kotlin_file = root / "settings.gradle.kts"
if groovy_file.is_file():
gradle_file = groovy_file
elif kotlin_file.is_file():
gradle_file = kotlin_file
else:
return {}
s = gradle_file.read_text(encoding="utf-8")
version_catalogs_m = VERSION_CATALOG_REGEX.search(s)
if version_catalogs_m:
start = version_catalogs_m.end()
end = find_block_end(s, start)
catalog_files_m = GRADLE_CATALOG_FILE_REGEX.finditer(s, start, end)
m_default = DEFAULT_CATALOG_PREFIX_REGEX.search(s)
if m_default:
default_prefix = m_default.group(1)
default_catalog_file = Path(root) / "gradle/libs.versions.toml"
if default_catalog_file.is_file():
with default_catalog_file.open("rb") as f:
catalogs[default_prefix] = GradleVersionCatalog(tomllib.load(f))
for m in catalog_files_m:
catalog_file = Path(root) / m.group(2).replace("$rootDir/", "")
if catalog_file.is_file():
with catalog_file.open("rb") as f:
catalogs[m.group(1)] = GradleVersionCatalog(tomllib.load(f))
return catalogs
def get_gradle_compile_commands(build):
compileCommands = [
'alias',
'api',
'apk',
'classpath',
@ -76,19 +266,30 @@ def get_gradle_compile_commands(build):
'runtimeOnly',
]
buildTypes = ['', 'release']
flavors = ['']
if build.gradle and build.gradle != ['yes']:
flavors += build.gradle
flavors = common.calculate_gradle_flavor_combination(build.gradle)
else:
flavors = ['']
commands = [
''.join(c) for c in itertools.product(flavors, buildTypes, compileCommands)
return [''.join(c) for c in itertools.product(flavors, buildTypes, compileCommands)]
def get_gradle_compile_commands_without_catalog(build):
return [
re.compile(rf'''\s*{c}.*\s*\(?['"].*['"]''', re.IGNORECASE)
for c in get_gradle_compile_commands(build)
]
def get_gradle_compile_commands_with_catalog(build, prefix):
return [
re.compile(rf'\s*{c}.*\s*\(?{prefix}\.([a-z0-9.]+)', re.IGNORECASE)
for c in get_gradle_compile_commands(build)
]
return [re.compile(r'\s*' + c, re.IGNORECASE) for c in commands]
def get_embedded_classes(apkfile, depth=0):
"""
Get the list of Java classes embedded into all DEX files.
"""Get the list of Java classes embedded into all DEX files.
:return: set of Java classes names as string
"""
@ -134,7 +335,7 @@ def get_embedded_classes(apkfile, depth=0):
def _datetime_now():
"""Get datetime.now(), using this funciton allows mocking it for testing."""
return datetime.utcnow()
return datetime.now(timezone.utc)
def _scanner_cachedir():
@ -183,8 +384,7 @@ class SignatureDataController:
raise SignatureDataVersionMismatchException()
def check_last_updated(self):
"""
Check if the last_updated value is ok and raise an exception if expired or inaccessible.
"""Check if the last_updated value is ok and raise an exception if expired or inaccessible.
:raises SignatureDataMalformedException: when timestamp value is
inaccessible or not parse-able
@ -194,7 +394,7 @@ class SignatureDataController:
last_updated = self.data.get("last_updated", None)
if last_updated:
try:
last_updated = datetime.fromtimestamp(last_updated)
last_updated = datetime.fromtimestamp(last_updated, timezone.utc)
except ValueError as e:
raise SignatureDataMalformedException() from e
except TypeError as e:
@ -259,8 +459,7 @@ class SignatureDataController:
logging.debug("write '{}' to cache".format(self.filename))
def verify_data(self):
"""
Clean and validate `self.data`.
"""Clean and validate `self.data`.
Right now this function does just a basic key sanitation.
"""
@ -354,6 +553,8 @@ class SUSSDataController(SignatureDataController):
class ScannerTool:
refresh_allowed = True
def __init__(self):
# we could add support for loading additional signature source
# definitions from config.yml here
@ -362,7 +563,9 @@ class ScannerTool:
options = common.get_options()
options_refresh_scanner = (
hasattr(options, "refresh_scanner") and options.refresh_scanner
hasattr(options, "refresh_scanner")
and options.refresh_scanner
and ScannerTool.refresh_allowed
)
if options_refresh_scanner or common.get_config().get('refresh_scanner'):
self.refresh()
@ -447,8 +650,7 @@ _SCANNER_TOOL = None
def _get_tool():
"""
Lazy loading function for getting a ScannerTool instance.
"""Lazy loading function for getting a ScannerTool instance.
ScannerTool initialization need to access `common.config` values. Those are only available after initialization through `common.read_config()`. So this factory assumes config was called at an erlier point in time.
"""
@ -471,6 +673,17 @@ def scan_binary(apkfile):
if regexp.match(classname):
logging.debug("Problem: found class '%s'" % classname)
problems += 1
logging.info(_('Scanning APK for extra signing blocks.'))
a = common.get_androguard_APK(str(apkfile))
a.parse_v2_v3_signature()
for b in a._v2_blocks:
if b in APK_SIGNING_BLOCK_IDS:
logging.debug(
f"Problem: found extra signing block '{APK_SIGNING_BLOCK_IDS[b]}'"
)
problems += 1
if warnings:
logging.warning(
_("Found {count} warnings in {filename}").format(
@ -492,6 +705,7 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
Returns
-------
the number of fatal problems encountered.
"""
count = 0
@ -507,11 +721,11 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
re.compile(r'^https://' + re.escape(repo) + r'/*')
for repo in [
'repo1.maven.org/maven2', # mavenCentral()
'jcenter.bintray.com', # jcenter()
'jitpack.io',
'www.jitpack.io',
'repo.maven.apache.org/maven2',
'oss.jfrog.org/artifactory/oss-snapshot-local',
'central.sonatype.com/repository/maven-snapshots',
'oss.sonatype.org/content/repositories/snapshots',
'oss.sonatype.org/content/repositories/releases',
'oss.sonatype.org/content/groups/public',
@ -533,8 +747,12 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
]
]
scanignore = common.getpaths_map(build_dir, build.scanignore)
scandelete = common.getpaths_map(build_dir, build.scandelete)
scanignore, scanignore_not_found_paths = common.getpaths_map(
build_dir, build.scanignore
)
scandelete, scandelete_not_found_paths = common.getpaths_map(
build_dir, build.scandelete
)
scanignore_worked = set()
scandelete_worked = set()
@ -568,6 +786,7 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
Returns
-------
0 as we explicitly ignore the file, so don't count an error
"""
msg = 'Ignoring %s at %s' % (what, path_in_build_dir)
logging.info(msg)
@ -590,6 +809,7 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
Returns
-------
0 as we deleted the offending file
"""
msg = 'Removing %s at %s' % (what, path_in_build_dir)
logging.info(msg)
@ -617,6 +837,7 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
Returns
-------
0, as warnings don't count as errors
"""
if toignore(path_in_build_dir):
return 0
@ -642,6 +863,7 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
Returns
-------
0 if the problem was ignored/deleted/is only a warning, 1 otherwise
"""
options = common.get_options()
if toignore(path_in_build_dir):
@ -679,8 +901,12 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
]
def is_image_file(path):
if imghdr.what(path) is not None:
return True
try:
mimetype = magic.from_file(path, mime=True)
if mimetype and mimetype.startswith('image/'):
return True
except Exception as e:
logging.info(e)
def safe_path(path_in_build_dir):
for sp in safe_paths:
@ -688,11 +914,21 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
return True
return False
gradle_compile_commands = get_gradle_compile_commands(build)
def is_used_by_gradle_without_catalog(line):
return any(
command.match(line)
for command in get_gradle_compile_commands_without_catalog(build)
)
def is_used_by_gradle(line):
return any(command.match(line) for command in gradle_compile_commands)
def is_used_by_gradle_with_catalog(line, prefix):
for m in (
command.match(line)
for command in get_gradle_compile_commands_with_catalog(build, prefix)
):
if m:
return m
all_catalogs = {}
# Iterate through all files in the source code
for root, dirs, files in os.walk(build_dir, topdown=True):
# It's topdown, so checking the basename is enough
@ -700,6 +936,9 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
if ignoredir in dirs:
dirs.remove(ignoredir)
if "settings.gradle" in files or "settings.gradle.kts" in files:
all_catalogs[str(root)] = get_catalogs(root)
for curfile in files:
if curfile in ['.DS_Store']:
continue
@ -765,6 +1004,13 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
count += handleproblem(
_('Java JAR file'), path_in_build_dir, filepath, json_per_build
)
elif curfile.endswith('.wasm'):
count += handleproblem(
_('WebAssembly binary file'),
path_in_build_dir,
filepath,
json_per_build,
)
elif curfile.endswith('.java'):
if not os.path.isfile(filepath):
@ -781,19 +1027,40 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
break
elif curfile.endswith('.gradle') or curfile.endswith('.gradle.kts'):
catalog_path = str(build_dir)
# Find the longest path of dir that the curfile is in
for p in all_catalogs:
if os.path.commonpath([root, p]) == p:
catalog_path = p
catalogs = all_catalogs.get(catalog_path, {})
if not os.path.isfile(filepath):
continue
with open(filepath, 'r', errors='replace') as f:
lines = f.readlines()
for i, line in enumerate(lines):
if is_used_by_gradle(line):
if is_used_by_gradle_without_catalog(line):
for name in suspects_found(line):
count += handleproblem(
"usual suspect '%s'" % (name),
f"usual suspect '{name}'",
path_in_build_dir,
filepath,
json_per_build,
)
for prefix, catalog in catalogs.items():
m = is_used_by_gradle_with_catalog(line, prefix)
if not m:
continue
accessor = m[1]
coordinates = catalog.get_coordinate(accessor)
for coordinate in coordinates:
for name in suspects_found(coordinate):
count += handleproblem(
f"usual suspect '{prefix}.{accessor}: {name}'",
path_in_build_dir,
filepath,
json_per_build,
)
noncomment_lines = [
line for line in lines if not common.gradle_comment.match(line)
]
@ -843,11 +1110,19 @@ def scan_source(build_dir, build=metadata.Build(), json_per_build=None):
json_per_build,
)
for p in scanignore_not_found_paths:
logging.error(_("Non-exist scanignore path: %s") % p)
count += 1
for p in scanignore:
if p not in scanignore_worked:
logging.error(_('Unused scanignore path: %s') % p)
count += 1
for p in scandelete_not_found_paths:
logging.error(_("Non-exist scandelete path: %s") % p)
count += 1
for p in scandelete:
if p not in scandelete_worked:
logging.error(_('Unused scandelete path: %s') % p)
@ -928,10 +1203,7 @@ def main():
_get_tool()
return
# Read all app and srclib metadata
allapps = metadata.read_metadata()
apps = common.read_app_args(appids, allapps, True)
apps = common.read_app_args(appids, allow_version_codes=True)
build_dir = 'build'
if not os.path.isdir(build_dir):
@ -1032,7 +1304,7 @@ def main():
logging.info(_("Finished"))
if options.json:
print(json.dumps(json_output))
else:
elif probcount or options.verbose:
print(_("%d problems found") % probcount)
@ -1955,13 +2227,13 @@ SUSS_DEFAULT = r'''{
"https://www.android.com/gms/"
],
"gradle_signatures": [
"com.google.android.gms(?!.oss-licenses-plugin)",
"com.google.android.gms(?!.(oss-licenses-plugin|strict-version-matcher-plugin))",
"com.google.android.ump",
"androidx.core:core-google-shortcuts",
"androidx.credentials:credentials",
"androidx.credentials:credentials-play-services-auth",
"androidx.media3:media3-cast",
"androidx.media3:media3-datasource-cronet",
"androidx.wear:wear-remote-interactions",
"androidx.work:work-gcm",
"com.google.android.exoplayer:extension-cast",
"com.google.android.exoplayer:extension-cronet",
@ -1969,9 +2241,21 @@ SUSS_DEFAULT = r'''{
"com.cloudinary:cloudinary-android.*:2\\.[12]\\.",
"com.pierfrancescosoffritti.androidyoutubeplayer:chromecast-sender",
"com.yayandroid:locationmanager",
"play-services",
"(?<!org.microg.gms:)play-services",
"xyz.belvi.mobilevision:barcodescanner",
"com.google.api-client:google-api-client-android"
"com.google.api-client:google-api-client-android",
"com.google.maps.android:android-maps-utils",
"com.github.budowski:android-maps-utils",
"com.microsoft.identity:common",
"com.microsoft.identity.client:msal"
],
"gradle_signatures_negative_examples": [
"com.google.android.gms.oss-licenses-plugin",
"com.google.android.gms.strict-version-matcher-plugin"
],
"gradle_signatures_positive_examples": [
"com.google.android.gms:play-services-base",
"com.google.android.gms:play-services-oss-licenses"
],
"license": "NonFree",
"name": "Google Mobile Services"
@ -1989,7 +2273,10 @@ SUSS_DEFAULT = r'''{
},
"com.google.android.libraries": {
"code_signatures": [
"com/google/android/libraries"
"com/google/android/libraries(?!/accessibility)"
],
"code_signatures_negative_examples": [
"com/google/android/libraries/accessibility"
],
"gradle_signatures": [
"com.google.android.libraries(?!.mapsplatform.secrets-gradle-plugin)"
@ -2110,7 +2397,8 @@ SUSS_DEFAULT = r'''{
"https://developers.google.com/ml-kit"
],
"gradle_signatures": [
"com.google.mlkit"
"com.google.mlkit",
"io.github.g00fy2.quickie"
],
"license": "NonFree",
"name": "ML Kit"
@ -2335,6 +2623,19 @@ SUSS_DEFAULT = r'''{
"description": "processes real-time data at the intersection of commerce and culture, providing useful, actionable insights for brands and publishers. See <a rel='nofollow' href='https://www.crunchbase.com/organization/quantcast'>Crunchbase</a> and <a href='https://reports.exodus-privacy.eu.org/en/trackers/133/'>Exodus Privacy</a>.",
"license": "NonFree"
},
"com.revenuecat.purchases": {
"code_signatures": [
"com/revenuecat/purchases"
],
"documentation": [
"https://www.revenuecat.com/"
],
"gradle_signatures": [
"com.revenuecat.purchases"
],
"license": "NonFree",
"name": "RevenueCat Purchases"
},
"com.samsung.accessory": {
"anti_features": [
"NonFreeComp"
@ -2468,6 +2769,9 @@ SUSS_DEFAULT = r'''{
"com.wei.android.lib:fingerprintidentify",
"com.github.uccmawei:FingerprintIdentify"
],
"gradle_signatures_positive_examples": [
"implementation \"com.github.uccmawei:fingerprintidentify:${safeExtGet(\"fingerprintidentify\", \"1.2.6\")}\""
],
"license": "NonFree",
"name": "FingerprintIdentify"
},
@ -2651,6 +2955,16 @@ SUSS_DEFAULT = r'''{
"license": "NonFree",
"name": "Pushy"
},
"org.gradle.toolchains.foojay-resolver-convention": {
"documentation": [
"https://github.com/gradle/foojay-toolchains"
],
"gradle_signatures": [
"org.gradle.toolchains.foojay-resolver"
],
"license": "Apache-2.0",
"name": "Foojay Toolchains Plugin"
},
"org.mariuszgromada.math": {
"code_signatures": [
"org/mariuszgromada/math/mxparser/parsertokens/SyntaxStringBuilder",
@ -2683,7 +2997,7 @@ SUSS_DEFAULT = r'''{
"license": "NonFree"
}
},
"timestamp": 1725205987.66681,
"timestamp": 1747829076.702502,
"version": 1,
"last_updated": 1725950235.569432
"last_updated": 1750710966.431471
}'''

View file

@ -15,16 +15,13 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
import os
import re
import sys
from argparse import ArgumentParser
import re
import os
import sys
import logging
from . import _
from . import common
from . import net
from . import _, common
from .exception import FDroidException
@ -68,6 +65,8 @@ def extract(options):
elif httpre.match(apk):
if apk.startswith('https') or options.no_check_https:
try:
from . import net
tmp_apk = os.path.join(tmp_dir, 'signed.apk')
net.download_file(apk, tmp_apk)
sigdir = extract_signature(tmp_apk)
@ -104,7 +103,7 @@ def main():
)
parser.add_argument("--no-check-https", action="store_true", default=False)
options = common.parse_args(parser)
common.set_console_logging(options.verbose)
common.set_console_logging(options.verbose, options.color)
common.read_config()
extract(options)

View file

@ -17,15 +17,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import logging
import os
import time
import zipfile
from argparse import ArgumentParser
import logging
from . import _
from . import common
from . import metadata
from . import _, common, metadata
from .exception import FDroidException
config = None

View file

@ -28,8 +28,8 @@ Example
import os
import sys
import time
import threading
import time
class Tail(object):

View file

@ -20,25 +20,27 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
import sys
import os
import shutil
import copy
import filecmp
import glob
import logging
import re
import socket
import warnings
import zipfile
import hashlib
import json
import logging
import os
import re
import shutil
import socket
import sys
import time
import yaml
import copy
import warnings
import zipfile
from argparse import ArgumentParser
from datetime import datetime, timezone
from pathlib import Path
import asn1crypto.cms
import defusedxml.ElementTree as ElementTree
from datetime import datetime, timezone
from argparse import ArgumentParser
from pathlib import Path
import yaml
try:
from yaml import CSafeLoader as SafeLoader
@ -48,14 +50,13 @@ except ImportError:
import collections
from binascii import hexlify
from . import _
from . import common
from . import metadata
from .common import DEFAULT_LOCALE
from .exception import BuildException, FDroidException, VerificationException
from PIL import Image, PngImagePlugin
import fdroidserver.index
from PIL import Image, PngImagePlugin
from . import _, common, metadata
from .common import DEFAULT_LOCALE
from .exception import BuildException, FDroidException, NoVersionCodeException, VerificationException
if hasattr(Image, 'DecompressionBombWarning'):
warnings.simplefilter('error', Image.DecompressionBombWarning)
@ -133,7 +134,7 @@ def disabled_algorithms_allowed():
or common.default_config['allow_disabled_algorithms'])
def status_update_json(apps, apks):
def status_update_json(output, apps, apks):
"""Output a JSON file with metadata about this `fdroid update` run.
Parameters
@ -145,7 +146,6 @@ def status_update_json(apps, apks):
"""
logging.debug(_('Outputting JSON'))
output = common.setup_status_output(start_timestamp)
output['antiFeatures'] = dict()
output['disabled'] = []
output['archivePolicy0'] = []
@ -202,6 +202,13 @@ def status_update_json(apps, apks):
common.write_status_json(output, options.pretty)
def output_status_stage(output, stage):
if 'stages' not in output:
output['stages'] = dict()
output['stages'][stage] = common.epoch_millis_now()
common.write_running_status_json(output)
def delete_disabled_builds(apps, apkcache, repodirs):
"""Delete disabled build outputs.
@ -316,6 +323,13 @@ def get_cache_file():
return os.path.join('tmp', 'apkcache.json')
def get_cache_mtime():
apkcachefile = get_cache_file()
if os.path.exists(apkcachefile):
return os.stat(apkcachefile).st_mtime
return 0
def get_cache():
"""Get the cached dict of the APK index.
@ -355,7 +369,13 @@ def get_cache():
if not isinstance(v['antiFeatures'], dict):
v['antiFeatures'] = {k: {} for k in sorted(v['antiFeatures'])}
if 'added' in v:
v['added'] = datetime.fromtimestamp(v['added'])
v['added'] = datetime.fromtimestamp(v['added'], tz=timezone.utc)
if v.get('srcname') and not v.get('srcnameSha256'):
f = f'archive/{v["srcname"]}'
if not os.path.exists(f):
f = f'repo/{v["srcname"]}'
if os.path.exists(f):
v['srcnameSha256'] = common.sha256sum(f)
return apkcache
@ -491,7 +511,7 @@ def insert_obbs(repodir, apps, apks):
obbWarnDelete(f, _('OBB filename must start with "main." or "patch.":'))
continue
if not re.match(r'^-?[0-9]+$', chunks[1]):
obbWarnDelete(f, _('The OBB version code must come after "{name}.":')
obbWarnDelete(f, _('The OBB versionCode must come after "{name}.":')
.format(name=chunks[0]))
continue
versionCode = int(chunks[1])
@ -530,7 +550,7 @@ VERSION_STRING_RE = re.compile(r'^([0-9]+)\.([0-9]+)\.([0-9]+)$')
def version_string_to_int(version):
"""
Convert sermver version designation to version code.
Convert semantic version designation to versionCode.
Approximately convert a [Major].[Minor].[Patch] version string
consisting of numeric characters (0-9) and periods to a number. The
@ -683,7 +703,7 @@ def scan_repo_for_ipas(apkcache, repodir, knownapks):
apkcache[ipa_name] = ipa
cachechanged = True
added = knownapks.recordapk(ipa_name, ipa['packageName'])
added = knownapks.recordapk(ipa_name)
if added:
ipa['added'] = added
@ -787,16 +807,20 @@ def _strip_and_copy_image(in_file, outpath):
It is not used at all in the F-Droid ecosystem, so its much safer
just to remove it entirely.
This uses size+mtime to check for a new file since this process
actually modifies the resulting file to strip out the EXIF.
This only uses ctime/mtime to check for a new file since this
process actually modifies the resulting file to strip out the EXIF.
Therefore, whenever the file needs to be stripped, it will have a
newer ctime and most likely a different size. The mtime is copied
from the source to the destination, so it can be the same.
outpath can be path to either a file or dir. The dir that outpath
refers to must exist before calling this.
Potential source of Python code to strip JPEGs without dependencies:
http://www.fetidcascade.com/public/minimal_exif_writer.py
"""
logging.debug('copying ' + in_file + ' ' + outpath)
logging.debug('copying %s %s', in_file, outpath)
if not os.path.exists(in_file):
if os.path.islink(in_file):
@ -810,12 +834,11 @@ def _strip_and_copy_image(in_file, outpath):
else:
out_file = outpath
if os.path.exists(out_file):
in_stat = os.stat(in_file)
out_stat = os.stat(out_file)
if in_stat.st_size == out_stat.st_size \
and in_stat.st_mtime == out_stat.st_mtime:
return
if os.path.exists(out_file) and (
os.path.getmtime(in_file) <= os.path.getmtime(out_file)
and os.path.getctime(in_file) <= os.path.getctime(out_file)
):
return
extension = common.get_extension(in_file)[1]
if extension == 'png':
@ -1019,16 +1042,20 @@ def copy_triple_t_store_metadata(apps):
for packageName, app in apps.items():
builds = app.get('Builds', [])
gradle_subdirs = set()
if builds and builds[-1].subdir:
if builds:
subdir = builds[-1].subdir or ''
for flavor in builds[-1].gradle:
if flavor not in ('yes', 'no', True, False):
p = os.path.join('build', packageName, builds[-1].subdir, 'src', flavor, 'play')
p = os.path.join('build', packageName, subdir, 'src', flavor, 'play')
if os.path.exists(p):
gradle_subdirs.add(p)
if not gradle_subdirs:
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, builds[-1].subdir, 'src', '*', 'play')))
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, subdir, 'src', '*', 'play')))
if not gradle_subdirs:
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, builds[-1].subdir, '*', 'src', '*', 'play')))
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, subdir, '*', 'src', '*', 'play')))
if not gradle_subdirs:
# Flutter-style android subdir
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, subdir, 'android', 'app', 'src', '*', 'play')))
if not gradle_subdirs:
sg_list = sorted(glob.glob(os.path.join('build', packageName, 'settings.gradle*')))
if sg_list:
@ -1097,6 +1124,9 @@ def copy_triple_t_store_metadata(apps):
repofilename = os.path.basename(f)
if segments[-2] == 'listing':
locale = segments[-3]
if dirname in GRAPHIC_NAMES:
repofilename = dirname + '.' + extension
dirname = ''
elif segments[-4] == 'listings': # v2.x
locale = segments[-3]
if dirname in tt_graphic_names:
@ -1124,6 +1154,7 @@ def insert_localized_app_metadata(apps):
metadata/<locale>/
fastlane/metadata/android/<locale>/
<subdir>/fastlane/metadata/android/<locale>/
src/<buildFlavor>/fastlane/metadata/android/<locale>/
...as well as the /metadata/<packageName>/<locale> directory.
@ -1143,7 +1174,7 @@ def insert_localized_app_metadata(apps):
https://f-droid.org/en/docs/All_About_Descriptions_Graphics_and_Screenshots/#in-the-apps-build-metadata-in-an-fdroiddata-collection
"""
sourcedirs = glob.glob(os.path.join('build', '[A-Za-z]*', 'src', '[A-Za-z]*', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'))
sourcedirs += glob.glob(os.path.join('build', '[A-Za-z]*', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'))
sourcedirs += glob.glob(os.path.join('build', '[A-Za-z]*', '**', 'fastlane', 'metadata', 'android', '[a-z][a-z]*'), recursive=True)
sourcedirs += glob.glob(os.path.join('build', '[A-Za-z]*', 'metadata', '[a-z][a-z]*'))
sourcedirs += glob.glob(os.path.join('metadata', '[A-Za-z]*', '[a-z][a-z]*'))
@ -1159,17 +1190,40 @@ def insert_localized_app_metadata(apps):
locale = segments[-1]
destdir = os.path.join('repo', packageName, locale)
# flavours specified in build receipt
build_flavours = ""
if (
apps[packageName]
and len(apps[packageName].get('Builds', [])) > 0
and 'gradle' in apps[packageName]['Builds'][-1]
):
build_flavours = apps[packageName]['Builds'][-1]['gradle']
builds = apps.get(packageName, {}).get('Builds', [])
found_in_subdir = (
builds
and len(segments) > 6
and segments[-4] == "fastlane"
and segments[-3] == "metadata"
and segments[-2] == "android"
and '/'.join(segments[2:-4]) == builds[-1].get('subdir')
)
if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavours:
logging.debug("ignoring due to wrong flavour")
# flavors specified in build receipt
build_flavors = []
if builds and 'gradle' in builds[-1] and builds[-1]['gradle'] != ['yes']:
build_flavors = common.calculate_gradle_flavor_combination(
builds[-1]['gradle']
)
found_in_flavor = (
len(segments) > 7
and segments[2] == 'src'
and segments[4] == "fastlane"
and segments[3] in build_flavors
)
if (
not found_in_subdir
and not found_in_flavor
and segments[0] == 'build'
and segments[2] not in ('metadata', 'fastlane')
):
logging.debug(
'Not scanning "{dir}" with unknown subdir or gradle flavor "{value}"'.format(
dir=os.path.relpath(root), value=segments[3]
)
)
continue
for f in files:
@ -1207,9 +1261,7 @@ def insert_localized_app_metadata(apps):
try:
versionCode = int(base)
locale = segments[-2]
if versionCode in [
a["versionCode"] for a in apps[packageName]["Builds"]
]:
if versionCode in [b["versionCode"] for b in builds]:
_set_localized_text_entry(
apps[packageName],
locale,
@ -1434,19 +1486,18 @@ def insert_localized_ios_app_metadata(apps_with_packages):
fdroidserver.update.copy_ios_screenshots_to_repo(screenshots, package_name)
# lookup icons, copy them and put them into app
icon_path = _get_ipa_icon(Path('build') / package_name)
icon_src = _get_ipa_icon(Path('build') / package_name)
icon_dest = Path('repo') / package_name / 'icon.png' # for now just assume png
icon_stat = os.stat(icon_path)
app['iconv2'] = {
DEFAULT_LOCALE: {
'name': str(icon_dest).lstrip('repo'),
'sha256': common.sha256sum(icon_dest),
'size': icon_stat.st_size,
'size': os.path.getsize(icon_src),
}
}
if not icon_dest.exists():
if not icon_dest.exists() or not filecmp.cmp(icon_src, icon_dest):
icon_dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(icon_path, icon_dest)
shutil.copy2(icon_src, icon_dest)
def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False):
@ -1525,8 +1576,10 @@ def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False):
repo_file['packageName'] = m.group(1)
repo_file['versionCode'] = int(m.group(2))
srcfilename = name + b'_src.tar.gz'
if os.path.exists(os.path.join(repodir, srcfilename)):
srcpath = os.path.join(repodir, srcfilename)
if os.path.exists(srcpath):
repo_file['srcname'] = srcfilename.decode()
repo_file['srcnameSha256'] = common.sha256sum(srcpath.decode())
repo_file['size'] = stat.st_size
apkcache[name_utf8] = repo_file
@ -1539,8 +1592,9 @@ def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False):
default_date_param = None
# Record in knownapks, getting the added date at the same time..
added = knownapks.recordapk(repo_file['apkName'], repo_file['packageName'],
default_date=default_date_param)
added = knownapks.recordapk(
repo_file['apkName'], default_date=default_date_param
)
if added:
repo_file['added'] = added
@ -1747,6 +1801,7 @@ def scan_apk_androguard(apk, apkfile):
xml = apkobject.get_android_manifest_xml()
androidmanifest_xml = apkobject.xml['AndroidManifest.xml']
if len(xml.nsmap) > 0:
# one of them surely will be the Android one, or its corrupt
xmlns = common.XMLNS_ANDROID
@ -1756,8 +1811,12 @@ def scan_apk_androguard(apk, apkfile):
xmlns = '{}'
vcstr = androidmanifest_xml.get(xmlns + 'versionCode')
logging.debug("Version Code: %r (%s)" % (vcstr, apkfile))
if vcstr.startswith('0x'):
if not vcstr:
raise NoVersionCodeException(_("APK file {path} does not have a version code "
"in its manifest").format(path=apkfile))
elif vcstr.startswith('0x'):
apk['versionCode'] = int(vcstr, 16)
else:
apk['versionCode'] = int(vcstr)
@ -1850,7 +1909,7 @@ def scan_apk_androguard(apk, apkfile):
def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=False,
allow_disabled_algorithms=False, archive_bad_sig=False, apps=None):
allow_disabled_algorithms=False, archive_bad_sig=False, apps=None, cache_timestamp=0):
"""Process the apk with the given filename in the given repo directory.
This also extracts the icons.
@ -1872,6 +1931,8 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
disabled algorithms in the signature (e.g. MD5)
archive_bad_sig
move APKs with a bad signature to the archive
cache_timestamp
the timestamp of the cache file
Returns
-------
@ -1885,7 +1946,8 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
usecache = False
if apkfilename in apkcache:
apk = apkcache[apkfilename]
if apk.get('hash') == common.sha256sum(apkfile):
stat = os.stat(apkfile)
if apk.get('size') == stat.st_size and stat.st_mtime < cache_timestamp:
logging.debug(_("Reading {apkfilename} from cache")
.format(apkfilename=apkfilename))
usecache = True
@ -1902,6 +1964,10 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
logging.warning(_("Skipping '{apkfilename}' with invalid signature!")
.format(apkfilename=apkfilename))
return True, None, False
except NoVersionCodeException:
logging.warning(_("Skipping '{apkfilename}' without versionCode!")
.format(apkfilename=apkfilename))
return True, None, False
if apps:
if apk['packageName'] in apps:
@ -1940,8 +2006,10 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
apk['apkName'] = apkfilename
srcfilename = apkfilename[:-4] + "_src.tar.gz"
if os.path.exists(os.path.join(repodir, srcfilename)):
srcpath = os.path.join(repodir, srcfilename)
if os.path.exists(srcpath):
apk['srcname'] = srcfilename
apk['srcnameSha256'] = common.sha256sum(srcpath)
# verify the jar signature is correct, allow deprecated
# algorithms only if the APK is in the archive.
@ -1988,13 +2056,12 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
fill_missing_icon_densities(empty_densities, iconfilename, apk, repodir)
if use_date_from_apk:
default_date_param = datetime.fromtimestamp(os.stat(apkfile).st_mtime)
default_date_param = datetime.fromtimestamp(os.stat(apkfile).st_mtime, tz=timezone.utc)
else:
default_date_param = None
# Record in known apks, getting the added date at the same time..
added = knownapks.recordapk(apk['apkName'], apk['packageName'],
default_date=default_date_param)
added = knownapks.recordapk(apk['apkName'], default_date=default_date_param)
if added:
apk['added'] = added
@ -2004,7 +2071,7 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
return False, apk, cachechanged
def process_apks(apkcache, repodir, knownapks, use_date_from_apk=False, apps=None):
def process_apks(apkcache, repodir, knownapks, use_date_from_apk=False, apps=None, cache_timestamp=0):
"""Process the apks in the given repo directory.
This also extracts the icons.
@ -2019,6 +2086,8 @@ def process_apks(apkcache, repodir, knownapks, use_date_from_apk=False, apps=Non
b known apks info
use_date_from_apk
use date from APK (instead of current date) for newly added APKs
cache_timestamp
the timestamp of the cache file
Returns
-------
@ -2040,7 +2109,7 @@ def process_apks(apkcache, repodir, knownapks, use_date_from_apk=False, apps=Non
apkfilename = apkfile[len(repodir) + 1:]
ada = disabled_algorithms_allowed()
(skip, apk, cachethis) = process_apk(apkcache, apkfilename, repodir, knownapks,
use_date_from_apk, ada, True, apps)
use_date_from_apk, ada, True, apps, cache_timestamp)
if skip:
continue
apks.append(apk)
@ -2253,7 +2322,7 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
continue
apkList.append(apk)
# Sort the apk list by version code. First is highest/newest.
# Sort the apk list by versionCode. First is highest/newest.
sorted_list = sorted(apkList, key=lambda apk: apk['versionCode'], reverse=True)
if currentVersionApk:
# Insert apk which corresponds to currentVersion at the front
@ -2261,15 +2330,9 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
return sorted_list
for appid, app in apps.items():
if app.get('ArchivePolicy') is not None:
keepversions = app['ArchivePolicy']
else:
keepversions = defaultkeepversions
if app.get('VercodeOperation'):
keepversions *= len(app['VercodeOperation'])
if common.metadata_find_developer_signing_files(appid, app['CurrentVersionCode']):
keepversions *= 2
keepversions = common.calculate_archive_policy(app, defaultkeepversions)
if common.metadata_find_developer_signing_files(appid, app['CurrentVersionCode']):
keepversions *= 2
logging.debug(_("Checking archiving for {appid} - apks:{integer}, keepversions:{keep}, archapks:{arch}")
.format(appid=appid, integer=len(apks), keep=keepversions, arch=len(archapks)))
@ -2405,12 +2468,12 @@ def create_metadata_from_template(apk):
def read_added_date_from_all_apks(apps, apks):
"""No summary.
Added dates come from the stats/known_apks.txt file but are
Added dates come from the repo/index-v2.json file but are
read when scanning apks and thus need to be applied form apk
level to app level for _all_ apps and not only from non-archived
ones
TODO: read the added dates directly from known_apks.txt instead of
TODO: read the added dates directly from index-v2.json instead of
going through apks that way it also works for for repos that
don't keep an archive of apks.
"""
@ -2578,7 +2641,7 @@ def main():
metadata.warnings_action = options.W
config = common.read_config()
common.setup_status_output(start_timestamp)
status_output = common.setup_status_output(start_timestamp)
if not (('jarsigner' in config or 'apksigner' in config)
and 'keytool' in config):
@ -2638,14 +2701,18 @@ def main():
# Get APK cache
apkcache = get_cache()
cache_timestamp = get_cache_mtime()
# Delete builds for disabled apps
output_status_stage(status_output, 'delete_disabled_builds')
delete_disabled_builds(apps, apkcache, repodirs)
# Scan all apks in the main repo
output_status_stage(status_output, 'process_apks')
apks, cachechanged = process_apks(apkcache, repodirs[0], knownapks,
options.use_date_from_apk, apps)
options.use_date_from_apk, apps, cache_timestamp)
output_status_stage(status_output, 'scan_repo_files')
files, fcachechanged = scan_repo_files(apkcache, repodirs[0], knownapks,
options.use_date_from_apk)
cachechanged = cachechanged or fcachechanged
@ -2655,10 +2722,23 @@ def main():
cachechanged = cachechanged or icachechanged
apks += ipas
output_status_stage(status_output, 'remove_apks')
appid_has_apks = set()
appid_has_repo_files = set()
sha256_has_files = collections.defaultdict(list)
errors = 0
remove_apks = []
for apk in apks:
sha256 = apk['hash']
if sha256 in sha256_has_files:
errors += 1
for path2 in sha256_has_files[sha256]:
logging.error(
_('{path1} is a duplicate of {path2}, remove one!').format(
path1=apk["apkName"], path2=path2
)
)
sha256_has_files[sha256].append(apk['apkName'])
to_remove = get_apks_without_allowed_signatures(apps.get(apk['packageName']), apk)
if to_remove:
remove_apks.append(apk)
@ -2701,19 +2781,22 @@ def main():
for apk in remove_apks:
apks.remove(apk)
mismatch_errors = ''
for appid in appid_has_apks:
if appid in appid_has_repo_files:
appid_files = ', '.join(glob.glob(os.path.join('repo', appid + '_[0-9]*.*')))
mismatch_errors += (_('{appid} has both APKs and files: {files}')
.format(appid=appid, files=appid_files)) + '\n'
if mismatch_errors:
raise FDroidException(mismatch_errors)
errors += 1
logging.error(
_('{appid} has both APKs and files: {files}').format(
appid=appid, files=appid_files
)
)
if errors:
sys.exit(errors)
# Scan the archive repo for apks as well
if len(repodirs) > 1:
archapks, cc = process_apks(apkcache, repodirs[1], knownapks,
options.use_date_from_apk, apps)
options.use_date_from_apk, apps, cache_timestamp)
if cc:
cachechanged = True
else:
@ -2722,18 +2805,25 @@ def main():
if cachechanged:
write_cache(apkcache)
output_status_stage(status_output, 'read_added_date_from_all_apks')
# The added date currently comes from the oldest apk which might be in the archive.
# So we need this populated at app level before continuing with only processing /repo
# or /archive
read_added_date_from_all_apks(apps, apks + archapks)
if len(repodirs) > 1:
output_status_stage(status_output, 'archive_old_apks archive')
archive_old_apks(apps, apks, archapks, repodirs[0], repodirs[1], config['archive_older'])
output_status_stage(status_output, 'prepare_apps archive')
archived_apps = prepare_apps(apps, archapks, repodirs[1])
output_status_stage(status_output, 'index.make archive')
fdroidserver.index.make(archived_apps, archapks, repodirs[1], True)
output_status_stage(status_output, 'prepare_apps repo')
repoapps = prepare_apps(apps, apks, repodirs[0])
output_status_stage(status_output, 'index.make repo')
# APKs are placed into multiple repos based on the app package, providing
# per-app subscription feeds for nightly builds and things like it
if config['per_app_repos']:
@ -2754,13 +2844,10 @@ def main():
git_remote = config.get('binary_transparency_remote')
if git_remote or os.path.isdir(os.path.join('binary_transparency', '.git')):
from . import btlog
output_status_stage(status_output, 'make_binary_transparency_log')
btlog.make_binary_transparency_log(repodirs)
if config['update_stats']:
# Update known apks info...
knownapks.writeifchanged()
status_update_json(apps, apks + archapks)
status_update_json(status_output, apps, apks + archapks)
logging.info(_("Finished"))

View file

@ -16,18 +16,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import glob
import json
import logging
import requests
import os
import sys
from argparse import ArgumentParser
from collections import OrderedDict
from . import _
from . import common
from . import net
import requests
from . import _, common, net
from .exception import FDroidException
config = None
@ -58,8 +57,8 @@ def _add_diffoscope_info(d):
]
d['diffoscope']['External-Tools-Required'] = external_tools
from diffoscope.tools import OS_NAMES, get_current_os
from diffoscope.external_tools import EXTERNAL_TOOLS
from diffoscope.tools import OS_NAMES, get_current_os
current_os = get_current_os()
os_list = [current_os] if (current_os in OS_NAMES) else iter(OS_NAMES)
@ -80,6 +79,30 @@ def _add_diffoscope_info(d):
pass
def get_verified_json(path):
"""Get the full collection of reports that is written out to verified.json."""
if os.path.exists(path):
try:
with open(path) as fp:
return json.load(fp)
except Exception as e:
logging.info(f'{path}: {e}')
data = OrderedDict()
data['packages'] = OrderedDict()
for f in glob.glob(os.path.join(os.path.dirname(path), '*.apk.json')):
with open(f) as fp:
reports = json.load(fp)
for report in reports.values():
packageName = report['local']['packageName']
if packageName not in data['packages']:
data['packages'][packageName] = []
data['packages'][packageName].append(report)
return data
def write_json_report(url, remote_apk, unsigned_apk, compare_result):
"""Write out the results of the verify run to JSON.
@ -120,28 +143,44 @@ def write_json_report(url, remote_apk, unsigned_apk, compare_result):
with open(jsonfile, 'w') as fp:
json.dump(data, fp, sort_keys=True)
if output['verified']:
jsonfile = 'unsigned/verified.json'
if os.path.exists(jsonfile):
with open(jsonfile) as fp:
data = json.load(fp)
else:
data = OrderedDict()
data['packages'] = OrderedDict()
packageName = output['local']['packageName']
appid, version_code = os.path.basename(unsigned_apk[:-4]).rsplit('_', 1)
appid_base = unsigned_apk.rsplit('_', 1)[0]
apkReports = sorted(
glob.glob(f'{appid_base}_[0-9]*.json'), # don't include <appid>.json
key=lambda s: int(s[:-9].rsplit('_', 1)[1]), # numeric sort by versionCode
)
with open(apkReports[-1]) as fp:
reports = json.load(fp)
appid_output = {'apkReports': apkReports}
most_recent = 0
for report_time, run in reports.items():
if float(report_time) > most_recent:
most_recent = float(report_time)
appid_output['lastRunVerified'] = run['verified']
with open(f'{appid_base}.json', 'w') as fp:
json.dump(appid_output, fp, cls=common.Encoder, sort_keys=True)
if packageName not in data['packages']:
data['packages'][packageName] = []
found = False
output_dump = json.dumps(output, sort_keys=True)
for p in data['packages'][packageName]:
if output_dump == json.dumps(p, sort_keys=True):
found = True
break
if not found:
data['packages'][packageName].insert(0, json.loads(output_dump))
with open(jsonfile, 'w') as fp:
json.dump(data, fp, cls=common.Encoder, sort_keys=True)
if output['verified']:
write_verified_json(output)
def write_verified_json(output):
jsonfile = 'unsigned/verified.json'
data = get_verified_json(jsonfile)
packageName = output['local']['packageName']
if packageName not in data['packages']:
data['packages'][packageName] = []
found = False
output_dump = json.dumps(output, sort_keys=True)
for p in data['packages'][packageName]:
if output_dump == json.dumps(p, sort_keys=True):
found = True
break
if not found:
data['packages'][packageName].insert(0, json.loads(output_dump))
with open(jsonfile, 'w') as fp:
json.dump(data, fp, cls=common.Encoder, sort_keys=True)
def main():
@ -157,6 +196,12 @@ def main():
nargs='*',
help=_("application ID with optional versionCode in the form APPID[:VERCODE]"),
)
parser.add_argument(
"--clean-up-verified",
action="store_true",
default=False,
help=_("Remove source tarball and any APKs if successfully verified."),
)
parser.add_argument(
"--reuse-remote-apk",
action="store_true",
@ -224,12 +269,26 @@ def main():
) from e
unsigned_apk = os.path.join(unsigned_dir, apkfilename)
compare_result = common.verify_apks(remote_apk, unsigned_apk, tmp_dir)
compare_result = common.verify_apks(
remote_apk,
unsigned_apk,
tmp_dir,
clean_up_verified=options.clean_up_verified,
)
if options.output_json:
write_json_report(url, remote_apk, unsigned_apk, compare_result)
if compare_result:
raise FDroidException(compare_result)
if options.clean_up_verified:
src_tarball = os.path.join(
unsigned_dir, common.get_src_tarball_name(appid, vercode)
)
for f in (remote_apk, unsigned_apk, src_tarball):
if os.path.exists(f):
logging.info(f"...cleaned up {f} after successful verification")
os.remove(f)
logging.info("...successfully verified")
verified += 1

View file

@ -16,16 +16,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from os.path import isdir, isfile, basename, abspath, expanduser
import os
import json
import logging
import os
import shutil
import subprocess
import textwrap
import logging
from .common import FDroidException
import threading
from os.path import abspath, basename, expanduser, isdir, isfile
from .common import FDroidException
lock = threading.Lock()

View file

@ -1,302 +0,0 @@
#!/bin/bash
bindir="$(dirname $0)"
basedir="$(dirname $bindir)"
# Check if GRADLE_VERSION_DIR/CACHEDIR is set from environment
if [ -z "$GRADLE_VERSION_DIR" ]; then
gradle_version_dir="${basedir}/versions"
else
gradle_version_dir="$GRADLE_VERSION_DIR"
fi
BUILDSERVER_CACHEDIR=/vagrant/cache
if [ -n "$CACHEDIR" ]; then
cachedir="$CACHEDIR"
elif [ -d $BUILDSERVER_CACHEDIR ]; then
cachedir=$BUILDSERVER_CACHEDIR
fi
args=("$@")
run_gradle() {
if [ ! -d "${gradle_version_dir}/${v_found}" ]; then
download_gradle ${v_found}
fi
# shellcheck disable=SC2145
echo "Running ${gradle_version_dir}/${v_found}/bin/gradle ${args[@]}"
"${gradle_version_dir}/${v_found}/bin/gradle" "${args[@]}"
exit $?
}
download_gradle() {
URL="https://downloads.gradle.org/distributions/gradle-${1}-bin.zip"
shasum=$(get_sha $1)
if [ $? != 0 ]; then
echo "No hash for gradle version $1! Exiting..."
exit 1
fi
if [ -n "${cachedir}" ] && [ -e "${cachedir}/gradle-$1-bin.zip" ]; then
echo "Using cached ${cachedir}/gradle-$1-bin.zip ..."
gradle_zip="${cachedir}/gradle-$1-bin.zip"
else
echo "Downloading missing gradle version $1"
echo cachedir $cachedir
if [[ -n "${cachedir}" && ! -d "${cachedir}" ]]; then
mkdir -p "${cachedir}"
fi
if [[ -n "${cachedir}" && -d "${cachedir}" && -w "${cachedir}" ]]; then
tmpdir="${cachedir}"
else
tmpdir=$(mktemp -d)
fi
curl -o "${tmpdir}/gradle-$1-bin.zip" --silent --fail --show-error --location --retry 3 --retry-all-errors "${URL}"
gradle_zip="${tmpdir}/gradle-$1-bin.zip"
fi
echo "${shasum} ${gradle_zip}" | sha256sum -c -
if [ $? != 0 ]; then
echo "gradle download checksum mismatch! Exiting..."
exit 1
fi
mkdir -p "${gradle_version_dir}/"
unzip -q -d "${gradle_version_dir}" "${gradle_zip}"
mv "${gradle_version_dir}/gradle-$1" "${gradle_version_dir}/${v_found}"
}
get_sha() {
case $1 in
'0.7') echo '4e354fcb0d5c0b0e7789cd6ee900456edaf993f6dd890c4a1c217d90d2a6a6ad' ;;
'0.8') echo '940e623ea98e40ea9ad398770a6ebb91a61c0869d394dda81aa86b0f4f0025e7' ;;
'0.9') echo '994e46d4b467254a0f25ce92b602618331b9b3ac8b32a094fd84ff0e0ceec135' ;;
'0.9.1') echo '5d48cba95db031ec109ae9ab60561e960b6507046036e8191aa78572ec27e2a5' ;;
'0.9.2') echo 'f94d7642348c558fc05ab5fd6fb947fb1ed8fed5931ddb73dd04fb0de22d669b' ;;
'1.0') echo '894bca0360a7e2040815096788f118a2dd106ff6694221b274efb9c32bce0384' ;;
'1.1') echo '552c1fc9f3a1b9668b79cc447370f0263e664ffb6d5c6e1c21e77ce0c8a20d4c' ;;
'1.2') echo 'eb53da3704d24cabb7565f34a3bf16bcd863c4b0c139917606fb15d4f27c7bdf' ;;
'1.3') echo 'ada68561efbb9f1cae0f9063974cbde15c180351a2f92bc2f1106e39ddcae5ba' ;;
'1.4') echo 'cd99e85fbcd0ae8b99e81c9992a2f10cceb7b5f009c3720ef3a0078f4f92e94e' ;;
'1.5') echo 'a5511a0659caa47d9d74fd2844c9da43157d2f78e63a0223c6289d88f5aaecbe' ;;
'1.6') echo 'de3e89d2113923dcc2e0def62d69be0947ceac910abd38b75ec333230183fac4' ;;
'1.7') echo '360c97d51621b5a1ecf66748c718594e5f790ae4fbc1499543e0c006033c9d30' ;;
'1.8') echo 'a342bbfa15fd18e2482287da4959588f45a41b60910970a16e6d97959aea5703' ;;
'1.9') echo '097ddc2bcbc9da2bb08cbf6bf8079585e35ad088bafd42e8716bc96405db98e9' ;;
'1.10') echo '6e6db4fc595f27ceda059d23693b6f6848583950606112b37dfd0e97a0a0a4fe' ;;
'1.11') echo '07e235df824964f0e19e73ea2327ce345c44bcd06d44a0123d29ab287fc34091' ;;
'1.12') echo '8734b13a401f4311ee418173ed6ca8662d2b0a535be8ff2a43ecb1c13cd406ea' ;;
'2.0') echo 'a1eb880c8755333c4d33c4351b269bebe517002532d3142c0b6164c9e8c081c3' ;;
'2.1') echo '3eee4f9ea2ab0221b89f8e4747a96d4554d00ae46d8d633f11cfda60988bf878' ;;
'2.2') echo '91e5655fe11ef414449f218c4fa2985b3a49b7903c57556da109c84fa26e1dfb' ;;
'2.2.1') echo '420aa50738299327b611c10b8304b749e8d3a579407ee9e755b15921d95ff418' ;;
'2.3') echo '010dd9f31849abc3d5644e282943b1c1c355f8e2635c5789833979ce590a3774' ;;
'2.4') echo 'c4eaecc621a81f567ded1aede4a5ddb281cc02a03a6a87c4f5502add8fc2f16f' ;;
'2.5') echo '3f953e0cb14bb3f9ebbe11946e84071547bf5dfd575d90cfe9cc4e788da38555' ;;
'2.6') echo '18a98c560af231dfa0d3f8e0802c20103ae986f12428bb0a6f5396e8f14e9c83' ;;
'2.7') echo 'cde43b90945b5304c43ee36e58aab4cc6fb3a3d5f9bd9449bb1709a68371cb06' ;;
'2.8') echo 'a88db9c2f104defdaa8011c58cf6cda6c114298ae3695ecfb8beb30da3a903cb' ;;
'2.9') echo 'c9159ec4362284c0a38d73237e224deae6139cbde0db4f0f44e1c7691dd3de2f' ;;
'2.10') echo '66406247f745fc6f05ab382d3f8d3e120c339f34ef54b86f6dc5f6efc18fbb13' ;;
'2.11') echo '8d7437082356c9fd6309a4479c8db307673965546daea445c6c72759cd6b1ed6' ;;
'2.12') echo 'e77064981906cd0476ff1e0de3e6fef747bd18e140960f1915cca8ff6c33ab5c' ;;
'2.13') echo '0f665ec6a5a67865faf7ba0d825afb19c26705ea0597cec80dd191b0f2cbb664' ;;
'2.14') echo '993b4f33b652c689e9721917d8e021cab6bbd3eae81b39ab2fd46fdb19a928d5' ;;
'2.14.1') echo 'cfc61eda71f2d12a572822644ce13d2919407595c2aec3e3566d2aab6f97ef39' ;;
'3.0') echo '39c906941a474444afbddc38144ed44166825acb0a57b0551dddb04bbf157f80' ;;
'3.1') echo 'c7de3442432253525902f7e8d7eac8b5fd6ce1623f96d76916af6d0e383010fc' ;;
'3.2') echo '5321b36837226dc0377047a328f12010f42c7bf88ee4a3b1cee0c11040082935' ;;
'3.2.1') echo '9843a3654d3e57dce54db06d05f18b664b95c22bf90c6becccb61fc63ce60689' ;;
'3.3') echo 'c58650c278d8cf0696cab65108ae3c8d95eea9c1938e0eb8b997095d5ca9a292' ;;
'3.4') echo '72d0cd4dcdd5e3be165eb7cd7bbd25cf8968baf400323d9ab1bba622c3f72205' ;;
'3.4.1') echo 'db1db193d479cc1202be843f17e4526660cfb0b21b57d62f3a87f88c878af9b2' ;;
'3.5') echo '0b7450798c190ff76b9f9a3d02e18b33d94553f708ebc08ebe09bdf99111d110' ;;
'3.5.1') echo '8dce35f52d4c7b4a4946df73aa2830e76ba7148850753d8b5e94c5dc325ceef8' ;;
'4.0') echo '56bd2dde29ba2a93903c557da1745cafd72cdd8b6b0b83c05a40ed7896b79dfe' ;;
'4.0.1') echo 'd717e46200d1359893f891dab047fdab98784143ac76861b53c50dbd03b44fd4' ;;
'4.0.2') echo '79ac421342bd11f6a4f404e0988baa9c1f5fabf07e3c6fa65b0c15c1c31dda22' ;;
'4.1') echo 'd55dfa9cfb5a3da86a1c9e75bb0b9507f9a8c8c100793ccec7beb6e259f9ed43' ;;
'4.2') echo '515dd63d32e55a9c05667809c5e40a947529de3054444ad274b3b75af5582eae' ;;
'4.2.1') echo 'b551cc04f2ca51c78dd14edb060621f0e5439bdfafa6fd167032a09ac708fbc0' ;;
'4.3') echo '8dcbf44eef92575b475dcb1ce12b5f19d38dc79e84c662670248dc8b8247654c' ;;
'4.3.1') echo '15ebe098ce0392a2d06d252bff24143cc88c4e963346582c8d88814758d93ac7' ;;
'4.4') echo 'fa4873ae2c7f5e8c02ec6948ba95848cedced6134772a0169718eadcb39e0a2f' ;;
'4.4.1') echo 'e7cf7d1853dfc30c1c44f571d3919eeeedef002823b66b6a988d27e919686389' ;;
'4.5') echo '03f2a43a314ff0fb843a85ef68078e06d181c4549c1e5fb983f289382b59b5e3' ;;
'4.5.1') echo '3e2ea0d8b96605b7c528768f646e0975bd9822f06df1f04a64fd279b1a17805e' ;;
'4.6') echo '98bd5fd2b30e070517e03c51cbb32beee3e2ee1a84003a5a5d748996d4b1b915' ;;
'4.7') echo 'fca5087dc8b50c64655c000989635664a73b11b9bd3703c7d6cabd31b7dcdb04' ;;
'4.8') echo 'f3e29692a8faa94eb0b02ebf36fa263a642b3ae8694ef806c45c345b8683f1ba' ;;
'4.8.1') echo 'af334d994b5e69e439ab55b5d2b7d086da5ea6763d78054f49f147b06370ed71' ;;
'4.9') echo 'e66e69dce8173dd2004b39ba93586a184628bc6c28461bc771d6835f7f9b0d28' ;;
'4.10') echo '248cfd92104ce12c5431ddb8309cf713fe58de8e330c63176543320022f59f18' ;;
'4.10.1') echo 'e53ce3a01cf016b5d294eef20977ad4e3c13e761ac1e475f1ffad4c6141a92bd' ;;
'4.10.2') echo 'b49c6da1b2cb67a0caf6c7480630b51c70a11ca2016ff2f555eaeda863143a29' ;;
'4.10.3') echo '8626cbf206b4e201ade7b87779090690447054bc93f052954c78480fa6ed186e' ;;
'5.0') echo '6157ac9f3410bc63644625b3b3e9e96c963afd7910ae0697792db57813ee79a6' ;;
'5.1') echo '7506638a380092a0406364c79d6c87d03d23017fc25a5770379d1ce23c3fcd4d' ;;
'5.1.1') echo '4953323605c5d7b89e97d0dc7779e275bccedefcdac090aec123375eae0cc798' ;;
'5.2') echo 'ff322863250159595e93b5a4d17a6f0d21c59a1a0497c1e1cf1d53826485503f' ;;
'5.2.1') echo '748c33ff8d216736723be4037085b8dc342c6a0f309081acf682c9803e407357' ;;
'5.3') echo 'bed2bdd3955be5a09ca7e0201e9d131f194f7f6c466e1795a733733ccfb09f25' ;;
'5.3.1') echo '1c59a17a054e9c82f0dd881871c9646e943ec4c71dd52ebc6137d17f82337436' ;;
'5.4') echo 'c8c17574245ecee9ed7fe4f6b593b696d1692d1adbfef425bef9b333e3a0e8de' ;;
'5.4.1') echo '7bdbad1e4f54f13c8a78abc00c26d44dd8709d4aedb704d913fb1bb78ac025dc' ;;
'5.5') echo '8d78b2ed63e7f07ad169c1186d119761c4773e681f332cfe1901045b1b0141bc' ;;
'5.5.1') echo '222a03fcf2fcaf3691767ce9549f78ebd4a77e73f9e23a396899fb70b420cd00' ;;
'5.6') echo '15c02ef5dd3631ec02ac52e8725703e0285d9a7eecbf4e5939aa9e924604d01d' ;;
'5.6.1') echo '0986244820e4a35d32d91df2ec4b768b5ba5d6c8246753794f85159f9963ec12' ;;
'5.6.2') echo '32fce6628848f799b0ad3205ae8db67d0d828c10ffe62b748a7c0d9f4a5d9ee0' ;;
'5.6.3') echo '60a6d8f687e3e7a4bc901cc6bc3db190efae0f02f0cc697e323e0f9336f224a3' ;;
'5.6.4') echo '1f3067073041bc44554d0efe5d402a33bc3d3c93cc39ab684f308586d732a80d' ;;
'6.0') echo '5a3578b9f0bb162f5e08cf119f447dfb8fa950cedebb4d2a977e912a11a74b91' ;;
'6.0.1') echo 'd364b7098b9f2e58579a3603dc0a12a1991353ac58ed339316e6762b21efba44' ;;
'6.1') echo 'd0c43d14e1c70a48b82442f435d06186351a2d290d72afd5b8866f15e6d7038a' ;;
'6.1.1') echo '9d94e6e4a28ad328072ef6e56bce79a810494ae756751fdcedffdeaf27c093b1' ;;
'6.2') echo 'b93a5f30d01195ec201e240f029c8b42d59c24086b8d1864112c83558e23cf8a' ;;
'6.2.1') echo 'a68ca7ba57f3404c3f6fc1f70a02d3a7d78652e6b46bbfaff83fc9a17168c279' ;;
'6.2.2') echo '0f6ba231b986276d8221d7a870b4d98e0df76e6daf1f42e7c0baec5032fb7d17' ;;
'6.3') echo '038794feef1f4745c6347107b6726279d1c824f3fc634b60f86ace1e9fbd1768' ;;
'6.4') echo 'b888659f637887e759749f6226ddfcb1cb04f828c58c41279de73c463fdbacc9' ;;
'6.4.1') echo 'e58cdff0cee6d9b422dcd08ebeb3177bc44eaa09bd9a2e838ff74c408fe1cbcd' ;;
'6.5') echo '23e7d37e9bb4f8dabb8a3ea7fdee9dd0428b9b1a71d298aefd65b11dccea220f' ;;
'6.5.1') echo '50a7d30529fa939721fe9268a0205142f3f2302bcac5fb45b27a3902e58db54a' ;;
'6.6') echo 'e6f83508f0970452f56197f610d13c5f593baaf43c0e3c6a571e5967be754025' ;;
'6.6.1') echo '7873ed5287f47ca03549ab8dcb6dc877ac7f0e3d7b1eb12685161d10080910ac' ;;
'6.7') echo '8ad57759019a9233dc7dc4d1a530cefe109dc122000d57f7e623f8cf4ba9dfc4' ;;
'6.7.1') echo '3239b5ed86c3838a37d983ac100573f64c1f3fd8e1eb6c89fa5f9529b5ec091d' ;;
'6.8') echo 'e2774e6fb77c43657decde25542dea710aafd78c4022d19b196e7e78d79d8c6c' ;;
'6.8.1') echo 'fd591a34af7385730970399f473afabdb8b28d57fd97d6625c388d090039d6fd' ;;
'6.8.2') echo '8de6efc274ab52332a9c820366dd5cf5fc9d35ec7078fd70c8ec6913431ee610' ;;
'6.8.3') echo '7faa7198769f872826c8ef4f1450f839ec27f0b4d5d1e51bade63667cbccd205' ;;
'6.9') echo '765442b8069c6bee2ea70713861c027587591c6b1df2c857a23361512560894e' ;;
'6.9.1') echo '8c12154228a502b784f451179846e518733cf856efc7d45b2e6691012977b2fe' ;;
'6.9.2') echo '8b356fd8702d5ffa2e066ed0be45a023a779bba4dd1a68fd11bc2a6bdc981e8f' ;;
'6.9.3') echo 'dcf350b8ae1aa192fc299aed6efc77b43825d4fedb224c94118ae7faf5fb035d' ;;
'6.9.4') echo '3e240228538de9f18772a574e99a0ba959e83d6ef351014381acd9631781389a' ;;
'7.0') echo 'eb8b89184261025b0430f5b2233701ff1377f96da1ef5e278af6ae8bac5cc305' ;;
'7.0.1') echo 'dccda8aa069563c8ba2f6cdfd0777df0e34a5b4d15138ca8b9757e94f4e8a8cb' ;;
'7.0.2') echo '0e46229820205440b48a5501122002842b82886e76af35f0f3a069243dca4b3c' ;;
'7.1') echo '2debee19271e1b82c6e41137d78e44e6e841035230a1a169ca47fd3fb09ed87b' ;;
'7.1.1') echo 'bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d' ;;
'7.2') echo 'f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd' ;;
'7.3') echo 'de8f52ad49bdc759164f72439a3bf56ddb1589c4cde802d3cec7d6ad0e0ee410' ;;
'7.3.1') echo '9afb3ca688fc12c761a0e9e4321e4d24e977a4a8916c8a768b1fe05ddb4d6b66' ;;
'7.3.2') echo '23b89f8eac363f5f4b8336e0530c7295c55b728a9caa5268fdd4a532610d5392' ;;
'7.3.3') echo 'b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302' ;;
'7.4') echo '8cc27038d5dbd815759851ba53e70cf62e481b87494cc97cfd97982ada5ba634' ;;
'7.4.1') echo 'e5444a57cda4a95f90b0c9446a9e1b47d3d7f69057765bfb54bd4f482542d548' ;;
'7.4.2') echo '29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda' ;;
'7.5') echo 'cb87f222c5585bd46838ad4db78463a5c5f3d336e5e2b98dc7c0c586527351c2' ;;
'7.5.1') echo 'f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4' ;;
'7.6') echo '7ba68c54029790ab444b39d7e293d3236b2632631fb5f2e012bb28b4ff669e4b' ;;
'7.6.1') echo '6147605a23b4eff6c334927a86ff3508cb5d6722cd624c97ded4c2e8640f1f87' ;;
'7.6.2') echo 'a01b6587e15fe7ed120a0ee299c25982a1eee045abd6a9dd5e216b2f628ef9ac' ;;
'7.6.3') echo '740c2e472ee4326c33bf75a5c9f5cd1e69ecf3f9b580f6e236c86d1f3d98cfac' ;;
'7.6.4') echo 'bed1da33cca0f557ab13691c77f38bb67388119e4794d113e051039b80af9bb1' ;;
'8.0') echo '4159b938ec734a8388ce03f52aa8f3c7ed0d31f5438622545de4f83a89b79788' ;;
'8.0.1') echo '1b6b558be93f29438d3df94b7dfee02e794b94d9aca4611a92cdb79b6b88e909' ;;
'8.0.2') echo 'ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7' ;;
'8.1') echo 'a62c5f99585dd9e1f95dab7b9415a0e698fa9dd1e6c38537faa81ac078f4d23e' ;;
'8.1.1') echo 'e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f' ;;
'8.2') echo '38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3' ;;
'8.2.1') echo '03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1' ;;
'8.3') echo '591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225' ;;
'8.4') echo '3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae' ;;
'8.5') echo '9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026' ;;
'8.6') echo '9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c' ;;
'8.7') echo '544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d' ;;
'8.8') echo 'a4b4158601f8636cdeeab09bd76afb640030bb5b144aafe261a5e8af027dc612' ;;
'8.9') echo 'd725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab' ;;
'8.10') echo '5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a' ;;
'8.10.1') echo '1541fa36599e12857140465f3c91a97409b4512501c26f9631fb113e392c5bd1' ;;
*) exit 1
esac
}
contains() {
local e
for e in $2; do
[[ $e == $1 ]] && return 0;
done
return 1
}
# key-value pairs of what gradle version (value) each gradle plugin version
# (key) should accept. plugin versions are actually prefixes and catch sub-
# versions as well. Pairs are taken from:
# https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
d_gradle_plugin_ver_k=(8.4 8.3 8.2 8.1 8.0 7.4 7.3 7.2.0 7.1 7.0 4.2 4.1 4.0 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.3 2.2 2.1.3 2.1 2.0)
d_plugin_min_gradle_v=(8.6 8.4 8.2 8.0 8.0 7.5 7.4 7.3.3 7.2 7.0.2 6.7.1 6.5 6.1.1 5.6.4 5.4.1 5.1.1 4.10.1 4.6 4.4 4.1 3.3 2.14.1 2.14.1 2.12 2.12 2.4 2.4 2.3 2.2.1 2.2.1 2.1 2.1 1.12 1.12 1.12 1.11 1.10 1.9 1.8 1.6 1.6 1.4 1.4)
# All gradle versions we know about
plugin_v=(8.10.1 8.10 8.9 8.8 8.7 8.6 8.5 8.4 8.3 8.2.1 8.2 8.1.1 8.1 8.0.2 8.0.1 8.0 7.6.4 7.6.3 7.6.2 7.6.1 7.6 7.5.1 7.5 7.4.2 7.4.1 7.4 7.3.3 7.3.2 7.3.1 7.3 7.2 7.1.1 7.1 7.0.2 7.0.1 7.0 6.9.4 6.9.3 6.9.2 6.9.1 6.9 6.8.3 6.8.2 6.8.1 6.8 6.7.1 6.7 6.6.1 6.6 6.5.1 6.5 6.4.1 6.4 6.3 6.2.2 6.2.1 6.2 6.1.1 6.1 6.0.1 6.0 5.6.4 5.6.3 5.6.2 5.6.1 5.6 5.5.1 5.5 5.4.1 5.4 5.3.1 5.3 5.2.1 5.2 5.1.1 5.1 5.0 4.10.3 4.10.2 4.10.1 4.10 4.9 4.8.1 4.8 4.7 4.6 4.5.1 4.5 4.4.1 4.4 4.3.1 4.3 4.2.1 4.2 4.1 4.0.2 4.0.1 4.0 3.5.1 3.5 3.4.1 3.4 3.3 3.2.1 3.2 3.1 3.0 2.14.1 2.14 2.13 2.12 2.11 2.10 2.9 2.8 2.7 2.6 2.5 2.4 2.3 2.2.1 2.2 2.1 2.0 1.12 1.11 1.10 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2 1.1 1.0 0.9.2 0.9.1 0.9 0.8 0.7)
v_all=${plugin_v[@]}
# Earliest file takes priority
# Last key takes priority if there are duplicates (matching java.util.Properties)
for f in {.,..}/gradle/wrapper/gradle-wrapper.properties; do
[[ -f $f ]] || continue
while IFS='' read -r line || [ -n "$line" ]; do
line=$(printf "$line" | tr -d '\r') # strip Windows linefeeds
if [[ $line == 'distributionUrl='* ]]; then
wrapper_ver=${line#*/gradle-}
wrapper_ver=${wrapper_ver%-*.zip}
fi
done < $f
[[ -n $wrapper_ver ]] && break
done
if [[ -n $wrapper_ver ]]; then
v_found=$wrapper_ver
echo "Found $v_found via distributionUrl"
run_gradle
fi
# Earliest takes priority
for f in {.,..}/build.gradle{,.kts}; do
[[ -f $f ]] || continue
while IFS='' read -r line || [ -n "$line" ]; do
line=$(printf "$line" | tr -d '\r') # strip Windows linefeeds
if [[ -z "$plugin_pver" && $line == *'com.android.tools.build:gradle:'* ]]; then
plugin_pver=${line#*[\'\"]com.android.tools.build:gradle:}
plugin_pver=${plugin_pver%[\'\"]*}
elif [[ -z "$wrapper_ver" && $line == *'gradleVersion = '* ]]; then
wrapper_ver=${line#*gradleVersion*=*[\'\"]}
wrapper_ver=${wrapper_ver%[\'\"]*}
fi
done < $f
done
if [[ -n $wrapper_ver ]]; then
v_found=$wrapper_ver
echo "Found $v_found via gradleVersion"
run_gradle
fi
if [[ -n $plugin_pver ]]; then
i=0
match=false
for k in "${d_gradle_plugin_ver_k[@]}"; do
if [[ $plugin_pver == ${k}* ]]; then
plugin_ver=${d_plugin_min_gradle_v[$i]}
match=true
break
fi
let i++
done
if $match; then
v_found=$plugin_ver
echo "Found $v_found via gradle plugin version $k"
fi
fi
# Find the highest version available
for v in ${plugin_v[*]}; do
if contains $v "${v_all[*]}"; then
v_def=$v
break
fi
done
if [[ -z $v_found ]]; then
echo "No suitable gradle version found - defaulting to $v_def"
v_found=$v_def
fi
run_gradle

View file

@ -2,7 +2,7 @@
#
# Install all the client hooks
BASE_DIR="$(cd $(dirname $0); pwd -P)"
BASE_DIR="$(cd $(dirname $0) || exit; pwd -P)"
HOOK_NAMES="applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc"
HOOK_DIR="$(git rev-parse --show-toplevel)/.git/hooks"

View file

@ -9,9 +9,9 @@ exec 1>&2
files=`git diff-index --cached HEAD 2>&1 | sed 's/^:.* //' | uniq | cut -b100-500`
if [ -z "$files" ]; then
PY_FILES="fdroid makebuildserver setup.py fdroidserver/*.py examples/*.py tests/*-release-checksums.py"
PY_TEST_FILES="tests/*.TestCase"
PY_TEST_FILES="tests/test_*.py"
SH_FILES="hooks/pre-commit"
BASH_FILES="gradlew-fdroid jenkins-build-all jenkins-setup-build-environment jenkins-test completion/bash-completion buildserver/provision-*"
BASH_FILES="jenkins-build-all jenkins-setup-build-environment jenkins-test completion/bash-completion buildserver/provision-*"
RB_FILES="buildserver/Vagrantfile"
YML_FILES=".*.yml .yamllint */*.yml */*.yaml"
else
@ -27,16 +27,16 @@ else
for f in $files; do
test -e $f || continue
case $f in
test_*.py)
PY_TEST_FILES+=" $f"
;;
*.py)
PY_FILES+=" $f"
;;
*.TestCase)
PY_TEST_FILES+=" $f"
;;
*.rb)
RB_FILES+=" $f"
;;
*.yml|.*.yml|.yamllint)
*.yml|*.yaml|.yamllint)
YML_FILES+=" $f"
;;
*)
@ -66,7 +66,7 @@ cmd_exists() {
}
find_command() {
for name in $@; do
for name in "$@"; do
for suff in "3" "-3" "-python3" ""; do
cmd=${name}${suff}
if cmd_exists $cmd; then
@ -91,7 +91,7 @@ if [ "$PY_FILES $PY_TEST_FILES" != " " ]; then
err "pyflakes tests failed!"
fi
# ignore vendored files
if ! $PYDOCSTYLE --match='(?!apksigcopier|looseversion).*\.py' $PY_FILES $PY_TEST_FILES; then
if ! $PYDOCSTYLE --match='(?!apksigcopier|looseversion|setup|test_).*\.py' $PY_FILES $PY_TEST_FILES; then
err "pydocstyle tests failed!"
fi
fi

View file

@ -1,8 +1,7 @@
FILES = ../fdroid $(wildcard ../fdroidserver/*.py) \
FILES = $(wildcard ../fdroidserver/*.py) \
$(wildcard /usr/lib/python3.*/argparse.py) \
$(wildcard /usr/lib/python3.*/optparse.py) \
$(wildcard /usr/lib/python3.*/getopt.py)
../fdroid
# these are the supported languages
ALL_LINGUAS = $(shell sed -En 's,include locale/([^/]+)/.*,\1,p' ../MANIFEST.in)

View file

@ -1,17 +0,0 @@
fdroid
fdroidserver/btlog.py
fdroidserver/build.py
fdroidserver/checkupdates.py
fdroidserver/common.py
fdroidserver/deploy.py
fdroidserver/import.py
fdroidserver/init.py
fdroidserver/install.py
fdroidserver/lint.py
fdroidserver/metadata.py
fdroidserver/publish.py
fdroidserver/rewritemeta.py
fdroidserver/scanner.py
fdroidserver/stats.py
fdroidserver/update.py
fdroidserver/verify.py

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,9 +5,10 @@
import json
import os
import re
import requests
import subprocess
import git
import requests
projectbasedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
localedir = os.path.join(projectbasedir, 'locale')
@ -18,37 +19,79 @@ if os.path.exists(cached_file):
with open(cached_file) as fp:
data = json.load(fp)
else:
url = 'https://hosted.weblate.org/exports/stats/f-droid/fdroidserver/?format=json'
url = 'https://hosted.weblate.org/api/components/f-droid/fdroidserver/statistics/?format=json'
r = requests.get(url)
r.raise_for_status()
data = r.json()
data = r.json()['results']
active = set()
print('name locale translated approved error-free')
for locale in sorted(data, key=lambda locale: locale['code']):
print('%26s' % locale['name'],
'%8s' % locale['code'],
'%0.1f%%' % locale['translated_percent'],
'%0.1f%%' % locale['approved_percent'],
'%0.1f%%' % (100 - locale['failing_percent']),
sep='\t')
print(
'%26s' % locale['name'],
'%8s' % locale['code'],
'%0.1f%%' % locale['translated_percent'],
'%0.1f%%' % locale['approved_percent'],
'%0.1f%%' % (100 - locale['failing_percent']),
sep='\t',
)
if locale['translated_percent'] >= 90 and locale['failing'] < 5:
active.add(locale['code'])
manifest_file = os.path.join(projectbasedir, 'MANIFEST.in')
with open(manifest_file) as fp:
for line in fp.readlines():
m = re.match(r'include locale/([^/]+)/.*', line)
if m:
active.add(m.group(1))
manifest_in = fp.read()
for m in re.findall(r'include locale/([^/]+)/LC_MESSAGES/fdroidserver.po', manifest_in):
active.add(m)
repo = git.Repo(projectbasedir)
weblate = repo.remotes.weblate
weblate.fetch()
upstream = repo.remotes.upstream
upstream.fetch()
if 'merge_weblate' in repo.heads:
merge_weblate = repo.heads['merge_weblate']
repo.create_tag(
'previous_merge_weblate',
ref=merge_weblate,
message=('Automatically created by %s' % __file__),
)
else:
merge_weblate = repo.create_head('merge_weblate')
merge_weblate.set_commit(upstream.refs.master)
merge_weblate.checkout()
active = sorted(active)
manifest_lines = set()
for locale in active:
manifest_lines.add('include locale/%s/LC_MESSAGES/fdroidserver.po\n' % locale)
po_file = f'locale/{locale}/LC_MESSAGES/fdroidserver.po'
manifest_lines.add(f'include {po_file}\n')
for commit in repo.iter_commits(
str(weblate.refs.master) + '...' + str(upstream.refs.master),
paths=[po_file],
max_count=10,
reverse=True,
):
print(f'{locale}: git cherry-pick', commit)
repo.git.cherry_pick(commit)
with open(manifest_file, 'a') as fp:
for line in manifest_lines:
if line:
fp.write(line)
# first filter duplicates
subprocess.run(['sort', '-u', '-o', manifest_file, manifest_file])
# then use a stable sort order
subprocess.run(
['sort', '--ignore-case', '--stable', '-o', manifest_file, manifest_file],
env={'LC_ALL': 'C'},
)
print('\tIf all else fails, try:')
print('\tgit checkout -B merge_weblate weblate/master')
print('\tgit rebase -i upstream/master')
print('\t# select all in editor and cut all commit lines')
print('\twl-paste | grep -Eo ".* \((%s)\) .*" | wl-copy' % '|'.join(active))
print('\t# paste into editor, and make rebase\n')

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more