mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-05 23:10:29 +03:00
install: download from GitHub Releases
This commit is contained in:
parent
1eb6516f16
commit
560472e4e5
3 changed files with 49 additions and 7 deletions
|
|
@ -23,12 +23,15 @@ import urllib.parse
|
||||||
|
|
||||||
|
|
||||||
class GithubApi:
|
class GithubApi:
|
||||||
"""
|
"""Wrapper for some select calls to GitHub Json/REST API.
|
||||||
Warpper 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
|
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
|
general API wrapper. Instead it's purpose is to return pre-filtered and
|
||||||
transformed data that's playing well with other fdroidserver functions.
|
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):
|
def __init__(self, api_token, repo_path):
|
||||||
|
|
@ -41,9 +44,10 @@ class GithubApi:
|
||||||
def _req(self, url, data=None):
|
def _req(self, url, data=None):
|
||||||
h = {
|
h = {
|
||||||
"Accept": "application/vnd.github+json",
|
"Accept": "application/vnd.github+json",
|
||||||
"Authorization": f"Bearer {self._api_token}",
|
|
||||||
"X-GitHub-Api-Version": "2022-11-28",
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
}
|
}
|
||||||
|
if self._api_token:
|
||||||
|
h["Authorization"] = f"Bearer {self._api_token}"
|
||||||
return urllib.request.Request(
|
return urllib.request.Request(
|
||||||
url,
|
url,
|
||||||
headers=h,
|
headers=h,
|
||||||
|
|
@ -65,6 +69,17 @@ class GithubApi:
|
||||||
released_tags = self.list_released_tags()
|
released_tags = self.list_released_tags()
|
||||||
return [x for x in all_tags if x not in 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):
|
def tag_exists(self, tag):
|
||||||
"""
|
"""
|
||||||
Check if git tag is present on github.
|
Check if git tag is present on github.
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ from pathlib import Path
|
||||||
from urllib.parse import urlencode, urlparse, urlunparse
|
from urllib.parse import urlencode, urlparse, urlunparse
|
||||||
|
|
||||||
from . import _
|
from . import _
|
||||||
from . import common, index, net
|
from . import common, github, index, net
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -106,6 +106,17 @@ def download_fdroid_apk(privacy_mode=False): # pylint: disable=unused-argument
|
||||||
return net.download_using_mirrors([mirror])
|
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()
|
||||||
|
return net.download_file(latest_apk)
|
||||||
|
|
||||||
|
|
||||||
def download_fdroid_apk_from_ipns(privacy_mode=False):
|
def download_fdroid_apk_from_ipns(privacy_mode=False):
|
||||||
"""Download the F-Droid APK from an IPNS repo."""
|
"""Download the F-Droid APK from an IPNS repo."""
|
||||||
cid = 'k51qzi5uqu5dl4hbcksbdmplanu9n4hivnqsupqe6vzve1pdbeh418ssptldd3'
|
cid = 'k51qzi5uqu5dl4hbcksbdmplanu9n4hivnqsupqe6vzve1pdbeh418ssptldd3'
|
||||||
|
|
@ -161,11 +172,13 @@ def install_fdroid_apk(privacy_mode=False):
|
||||||
download_methods = [
|
download_methods = [
|
||||||
download_fdroid_apk_from_maven,
|
download_fdroid_apk_from_maven,
|
||||||
download_fdroid_apk_from_ipns,
|
download_fdroid_apk_from_ipns,
|
||||||
|
download_fdroid_apk_from_github,
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
download_methods = [
|
download_methods = [
|
||||||
download_apk,
|
download_apk,
|
||||||
download_fdroid_apk_from_maven,
|
download_fdroid_apk_from_maven,
|
||||||
|
download_fdroid_apk_from_github,
|
||||||
download_fdroid_apk_from_ipns,
|
download_fdroid_apk_from_ipns,
|
||||||
download_fdroid_apk,
|
download_fdroid_apk,
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -177,56 +177,65 @@ class InstallTest(unittest.TestCase):
|
||||||
|
|
||||||
@patch('fdroidserver.install.download_apk')
|
@patch('fdroidserver.install.download_apk')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk')
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk_from_github')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
||||||
def test_install_fdroid_apk_privacy_mode_true(
|
def test_install_fdroid_apk_privacy_mode_true(
|
||||||
self, maven, ipns, download_fdroid_apk, download_apk
|
self, maven, ipns, github, download_fdroid_apk, download_apk
|
||||||
):
|
):
|
||||||
download_apk.side_effect = self._download_raise
|
download_apk.side_effect = self._download_raise
|
||||||
download_fdroid_apk.side_effect = self._download_raise
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
github.side_effect = self._download_raise
|
||||||
ipns.side_effect = self._download_raise
|
ipns.side_effect = self._download_raise
|
||||||
maven.side_effect = self._download_raise
|
maven.side_effect = self._download_raise
|
||||||
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
install.install_fdroid_apk(privacy_mode=True)
|
install.install_fdroid_apk(privacy_mode=True)
|
||||||
download_apk.assert_not_called()
|
download_apk.assert_not_called()
|
||||||
download_fdroid_apk.assert_not_called()
|
download_fdroid_apk.assert_not_called()
|
||||||
|
github.assert_called_once()
|
||||||
ipns.assert_called_once()
|
ipns.assert_called_once()
|
||||||
maven.assert_called_once()
|
maven.assert_called_once()
|
||||||
|
|
||||||
@patch('fdroidserver.install.download_apk')
|
@patch('fdroidserver.install.download_apk')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk')
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk_from_github')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
||||||
def test_install_fdroid_apk_privacy_mode_false(
|
def test_install_fdroid_apk_privacy_mode_false(
|
||||||
self, maven, ipns, download_fdroid_apk, download_apk
|
self, maven, ipns, github, download_fdroid_apk, download_apk
|
||||||
):
|
):
|
||||||
download_apk.side_effect = self._download_raise
|
download_apk.side_effect = self._download_raise
|
||||||
download_fdroid_apk.side_effect = self._download_raise
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
github.side_effect = self._download_raise
|
||||||
ipns.side_effect = self._download_raise
|
ipns.side_effect = self._download_raise
|
||||||
maven.side_effect = self._download_raise
|
maven.side_effect = self._download_raise
|
||||||
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
install.install_fdroid_apk(privacy_mode=False)
|
install.install_fdroid_apk(privacy_mode=False)
|
||||||
download_apk.assert_called_once()
|
download_apk.assert_called_once()
|
||||||
download_fdroid_apk.assert_called_once()
|
download_fdroid_apk.assert_called_once()
|
||||||
|
github.assert_called_once()
|
||||||
ipns.assert_called_once()
|
ipns.assert_called_once()
|
||||||
maven.assert_called_once()
|
maven.assert_called_once()
|
||||||
|
|
||||||
@patch('fdroidserver.install.download_apk')
|
@patch('fdroidserver.install.download_apk')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk')
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk_from_github')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
@patch('fdroidserver.install.download_fdroid_apk_from_ipns')
|
||||||
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
@patch('fdroidserver.install.download_fdroid_apk_from_maven')
|
||||||
@patch('locale.getlocale', lambda: ('zh_CN', 'UTF-8'))
|
@patch('locale.getlocale', lambda: ('zh_CN', 'UTF-8'))
|
||||||
def test_install_fdroid_apk_privacy_mode_locale_auto(
|
def test_install_fdroid_apk_privacy_mode_locale_auto(
|
||||||
self, maven, ipns, download_fdroid_apk, download_apk
|
self, maven, ipns, github, download_fdroid_apk, download_apk
|
||||||
):
|
):
|
||||||
download_apk.side_effect = self._download_raise
|
download_apk.side_effect = self._download_raise
|
||||||
download_fdroid_apk.side_effect = self._download_raise
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
github.side_effect = self._download_raise
|
||||||
ipns.side_effect = self._download_raise
|
ipns.side_effect = self._download_raise
|
||||||
maven.side_effect = self._download_raise
|
maven.side_effect = self._download_raise
|
||||||
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
install.install_fdroid_apk(privacy_mode=None)
|
install.install_fdroid_apk(privacy_mode=None)
|
||||||
download_apk.assert_not_called()
|
download_apk.assert_not_called()
|
||||||
download_fdroid_apk.assert_not_called()
|
download_fdroid_apk.assert_not_called()
|
||||||
|
github.assert_called_once()
|
||||||
ipns.assert_called_once()
|
ipns.assert_called_once()
|
||||||
maven.assert_called_once()
|
maven.assert_called_once()
|
||||||
|
|
||||||
|
|
@ -249,6 +258,11 @@ class InstallTest(unittest.TestCase):
|
||||||
f = install.download_fdroid_apk_from_ipns()
|
f = install.download_fdroid_apk_from_ipns()
|
||||||
self.assertTrue(Path(f).exists())
|
self.assertTrue(Path(f).exists())
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.getenv('test_download_fdroid_apk'), 'requires net access')
|
||||||
|
def test_download_fdroid_apk_from_github(self):
|
||||||
|
f = install.download_fdroid_apk_from_github()
|
||||||
|
self.assertTrue(Path(f).exists())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.chdir(os.path.dirname(__file__))
|
os.chdir(os.path.dirname(__file__))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue