Merge branch 'generate-index' into 'master'

Generate index.html and qrcode.png

Closes #688

See merge request fdroid/fdroidserver!853
This commit is contained in:
Hans-Christoph Steiner 2021-02-08 14:30:40 +00:00
commit 0a4c5afd52
6 changed files with 378 additions and 3 deletions

View file

@ -138,7 +138,7 @@ arch_pip_install:
- master@fdroid/fdroidserver - master@fdroid/fdroidserver
script: script:
- pacman --sync --sysupgrade --refresh --noconfirm git grep python-pip python-virtualenv tar - pacman --sync --sysupgrade --refresh --noconfirm git grep python-pip python-virtualenv tar
- pip install -e . - pip install -e .[test]
- fdroid - fdroid
- fdroid readmeta - fdroid readmeta
- fdroid update --help - fdroid update --help

View file

@ -3764,10 +3764,12 @@ def is_repo_file(filename):
and not filename.endswith(b'.idsig') \ and not filename.endswith(b'.idsig') \
and not filename.endswith(b'.log.gz') \ and not filename.endswith(b'.log.gz') \
and os.path.basename(filename) not in [ and os.path.basename(filename) not in [
b'index.css',
b'index.jar', b'index.jar',
b'index_unsigned.jar', b'index_unsigned.jar',
b'index.xml', b'index.xml',
b'index.html', b'index.html',
b'index.png',
b'index-v1.jar', b'index-v1.jar',
b'index-v1.json', b'index-v1.json',
b'categories.txt', b'categories.txt',

View file

@ -30,6 +30,7 @@ import tempfile
import urllib.parse import urllib.parse
import zipfile import zipfile
import calendar import calendar
import qrcode
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
from datetime import datetime, timezone from datetime import datetime, timezone
from xml.dom.minidom import Document from xml.dom.minidom import Document
@ -129,6 +130,334 @@ def make(apps, apks, repodir, archive):
fdroid_signing_key_fingerprints) fdroid_signing_key_fingerprints)
make_v1(sortedapps, apks, repodir, repodict, requestsdict, make_v1(sortedapps, apks, repodir, repodict, requestsdict,
fdroid_signing_key_fingerprints) fdroid_signing_key_fingerprints)
make_website(sortedapps, repodir, repodict)
def _should_file_be_generated(path, magic_string):
if os.path.exists(path):
with open(path) as f:
if magic_string not in f.readline(): # if the magic_string is not in the first line the file should be overwritten
return False
return True
def make_website(apps, repodir, repodict):
_, 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)
autogenerate_comment = "auto-generated - fdroid index updates will overwrite this file" # do not change this string, as it will break the updates for existing files with older versions of this string
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):
with open(html_file, 'w') as f:
name = repodict["name"]
description = repodict["description"]
icon = repodict["icon"]
f.write("""<!-- {autogenerate_comment} -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="width=device-width; initial-scale=1.0; minimum-scale=0.5; maximum-scale=2.0; user-scalable=1;" name="viewport">
<title>
{name}
</title>
<base href="index.html">
<link href="index.css" rel="stylesheet" type="text/css">
<link href="icons/{icon}" rel="icon" type="image/png">
<link href="icons/{icon}" rel="shortcut icon" type="image/png">
<meta content="{name}" property="og:site_name">
<meta content="{name}" property="og:title">
<meta content="" property="og:determiner">
<meta content="{description}" property="og:description">
<meta content="index,nofollow" name="robots">
</head>
<body>
<h2>
{name}
</h2>
<div id="intro">
<p style="margin-bottom:.2em;">
<span style="float:right;width:100px;margin-left:.5em;">
<a href="index.png" title="QR: test">
<img alt="QR: test" src="index.png" width="100">
</a>
</span>
{description}
<br>
<br>
Currently it serves
<kbd>
{number_of_apps}
</kbd>
apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:
</p>
<p class="center" style="margin-top:.5em">
<a href="{link_fingerprinted}">
<code style="color:#000000;font-weight:bold;">
{link}
</code>
</a>
</p>
<p>
If you would like to manually verify the fingerprint (SHA-256) of the repository signing key, here it is:
<br>
<blockcode style="color:#000000;font-weight:bold;">
{fingerprint}
</blockcode>
</p>
</div>
</body>
</html>
""".format(autogenerate_comment=autogenerate_comment,
description=description,
fingerprint=repo_pubkey_fingerprint,
icon=icon,
link=link,
link_fingerprinted=link_fingerprinted,
name=name,
number_of_apps=str(len(apps))))
css_file = os.path.join(repodir, "index.css")
if _should_file_be_generated(css_file, autogenerate_comment):
with open(css_file, "w") as f:
# this auto generated comment was not included via .format(), as python seems to have problems with css files in combination with .format()
f.write("""/* auto-generated - fdroid index updates will overwrite this file */
BODY {
font-family : Arial, Helvetica, Sans-Serif;
color : #0000ee;
background-color : #ffffff;
}
p {
text-align : justify;
}
p.center {
text-align : center;
}
TD {
font-family : Arial, Helvetica, Sans-Serif;
color : #0000ee;
}
body,td {
font-size : 14px;
}
TH {
font-family : Arial, Helvetica, Sans-Serif;
color : #0000ee;
background-color : #F5EAD4;
}
a:link {
color : #bb0000;
}
a:visited {
color : #ff0000;
}
.zitat {
margin-left : 1cm;
margin-right : 1cm;
font-style : italic;
}
#intro {
border-spacing : 1em;
border : 1px solid gray;
border-radius : 0.5em;
box-shadow : 10px 10px 5px #888;
margin : 1.5em;
font-size : .9em;
width : 600px;
max-width : 90%;
display : table;
margin-left : auto;
margin-right : auto;
font-size : .8em;
color : #555555;
}
#intro > p {
margin-top : 0;
}
#intro p:last-child {
margin-bottom : 0;
}
.last {
border-bottom : 1px solid black;
padding-bottom : .5em;
text-align : center;
}
table {
border-collapse : collapse;
}
h2 {
text-align : center;
}
.perms {
font-family : monospace;
font-size : .8em;
}
.repoapplist {
display : table;
border-collapse : collapse;
margin-left : auto;
margin-right : auto;
width : 600px;
max-width : 90%;
}
.approw, appdetailrow {
display : table-row;
}
.appdetailrow {
display : flex;
padding : .5em;
}
.appiconbig, .appdetailblock, .appdetailcell {
display : table-cell
}
.appiconbig {
vertical-align : middle;
text-align : center;
}
.appdetailinner {
width : 100%;
}
.applinkcell {
text-align : center;
float : right;
width : 100%;
margin-bottom : .1em;
}
.paddedlink {
margin : 1em;
}
.approw {
border-spacing : 1em;
border : 1px solid gray;
border-radius : 0.5em;
padding : 0.5em;
margin : 1.5em;
}
.appdetailinner .appdetailrow:first-child {
background-color : #d5d5d5;
}
.appdetailinner .appdetailrow:first-child .appdetailcell {
min-width : 33%;
flex : 1 33%;
text-align : center;
}
.appdetailinner .appdetailrow:first-child .appdetailcell:first-child {
text-align : left;
}
.appdetailinner .appdetailrow:first-child .appdetailcell:last-child {
float : none;
text-align : right;
}
.minor-details {
font-size : .8em;
color : #555555;
}
.boldname {
font-weight : bold;
}
#appcount {
text-align : center;
margin-bottom : .5em;
}
kbd {
padding : 0.1em 0.6em;
border : 1px solid #CCC;
background-color : #F7F7F7;
color : #333;
box-shadow : 0px 1px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 2px #FFF inset;
border-radius : 3px;
display : inline-block;
margin : 0px 0.1em;
text-shadow : 0px 1px 0px #FFF;
white-space : nowrap;
}
div.filterline, div.repoline {
display : table;
margin-left : auto;
margin-right : auto;
margin-bottom : 1em;
vertical-align : middle;
display : table;
font-size : .8em;
}
.filterline form {
display : table-row;
}
.filterline .filtercell {
display : table-cell;
vertical-align : middle;
}
fieldset {
float : left;
}
fieldset select, fieldset input, #reposelect select, #reposelect input {
font-size : .9em;
}
.pager {
display : table;
margin-left : auto;
margin-right : auto;
width : 600px;
max-width : 90%;
padding-top : .6em;
}
/* should correspond to .repoapplist */
.pagerrow {
display : table-row;
}
.pagercell {
display : table-cell;
}
.pagercell.left {
text-align : left;
padding-right : 1em;
}
.pagercell.middle {
text-align : center;
font-size : .9em;
color : #555;
}
.pagercell.right {
text-align : right;
padding-left : 1em;
}
.anti {
color : peru;
}
.antibold {
color : crimson;
}
#footer {
text-align : center;
margin-top : 1em;
font-size : 11px;
color : #555;
}
#footer img {
vertical-align : middle;
}
@media (max-width: 600px) {
.repoapplist {
display : block;
}
.appdetailinner, .appdetailrow {
display : block;
}
.appdetailcell {
display : block;
float : left;
line-height : 1.5em;
}
}""")
def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints): def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints):

View file

@ -88,7 +88,10 @@ setup(name='fdroidserver',
'yamllint', 'yamllint',
], ],
extras_require={ extras_require={
'test': ['pyjks'], 'test': [
'pyjks',
'html5print'
],
}, },
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',

View file

@ -66,7 +66,7 @@ cd $WORKSPACE
rm -rf $WORKSPACE/env rm -rf $WORKSPACE/env
pyvenv $WORKSPACE/env pyvenv $WORKSPACE/env
. $WORKSPACE/env/bin/activate . $WORKSPACE/env/bin/activate
pip3 install --quiet -e $WORKSPACE pip3 install --quiet -e $WORKSPACE[test]
python3 setup.py compile_catalog install python3 setup.py compile_catalog install
# make sure translation files were installed # make sure translation files were installed

View file

@ -354,6 +354,47 @@ class IndexTest(unittest.TestCase):
'https://gitlab.com/group/project/-/raw/master/fdroid'], 'https://gitlab.com/group/project/-/raw/master/fdroid'],
fdroidserver.index.get_mirror_service_urls(url)) fdroidserver.index.get_mirror_service_urls(url))
def test_make_website(self):
tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
dir=self.tmpdir)
os.chdir(tmptestsdir)
os.mkdir('metadata')
os.mkdir('repo')
repodict = {
'address': 'https://example.com/fdroid/repo',
'description': 'This is just a test',
'icon': 'blahblah',
'name': 'test',
'timestamp': datetime.datetime.now(),
'version': 12,
}
fdroidserver.common.config['repo_pubkey'] = 'ffffffffffffffffffffffffffffffffff'
fdroidserver.index.make_website([], "repo", repodict)
self.assertTrue(os.path.exists(os.path.join('repo', 'index.html')))
self.assertTrue(os.path.exists(os.path.join('repo', 'index.css')))
self.assertTrue(os.path.exists(os.path.join('repo', 'index.png')))
try:
from html5print import CSSBeautifier, HTMLBeautifier
except ImportError:
print('WARNING: skipping rest of test since html5print is missing!')
return
with open(os.path.join("repo", "index.html")) as f:
html = f.read()
pretty_html = HTMLBeautifier.beautify(html)
self.maxDiff = None
self.assertEquals(html, pretty_html)
with open(os.path.join("repo", "index.css")) as f:
css = f.read()
pretty_css = CSSBeautifier.beautify(css)
self.maxDiff = None
self.assertEquals(css, pretty_css)
if __name__ == "__main__": if __name__ == "__main__":
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(__file__))