1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-10-05 18:50:09 +02:00

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
script:
- pacman --sync --sysupgrade --refresh --noconfirm git grep python-pip python-virtualenv tar
- pip install -e .
- pip install -e .[test]
- fdroid
- fdroid readmeta
- 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'.log.gz') \
and os.path.basename(filename) not in [
b'index.css',
b'index.jar',
b'index_unsigned.jar',
b'index.xml',
b'index.html',
b'index.png',
b'index-v1.jar',
b'index-v1.json',
b'categories.txt',

View File

@ -30,6 +30,7 @@ import tempfile
import urllib.parse
import zipfile
import calendar
import qrcode
from binascii import hexlify, unhexlify
from datetime import datetime, timezone
from xml.dom.minidom import Document
@ -129,6 +130,334 @@ def make(apps, apks, repodir, archive):
fdroid_signing_key_fingerprints)
make_v1(sortedapps, apks, repodir, repodict, requestsdict,
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):

View File

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

View File

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

View File

@ -354,6 +354,47 @@ class IndexTest(unittest.TestCase):
'https://gitlab.com/group/project/-/raw/master/fdroid'],
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__":
os.chdir(os.path.dirname(__file__))