From 12682f063d5b61852238c8f99d535a304d04d5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 18 Jan 2021 11:54:04 +0100 Subject: [PATCH 01/13] First draft of index.html generation --- fdroidserver/index.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index fb62014b..c2d287db 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -230,6 +230,41 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_ else: json.dump(output, fp, default=_index_encoder_default) + html_name = 'index.html' + html_file = os.path.join(repodir, html_name) + with open(html_file, 'w') as f: + name = repodict["name"] + description = repodict["description"] + f.write(""" + + + + {name} + + + + + + + + + + +

{name}

+
+

+QR: {name} + +{description}
+{details}

+{link} +
+""".format(name=name, +description=description, +details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(output['apps'])), +link=repodict["address"] +)) + if common.options.nosign: logging.debug(_('index-v1 must have a signature, use `fdroid signindex` to create it!')) else: From 788333991d61ad4492aecda87dbfdf95c0e2c766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 18 Jan 2021 13:12:46 +0100 Subject: [PATCH 02/13] move code to own method --- fdroidserver/index.py | 75 +++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index c2d287db..52dee442 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -129,7 +129,47 @@ 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 make_website(apps, repodir, repodict): + website_dir = os.path.join(repodir, "www") + if not os.path.exists(website_dir): + os.makedirs(website_dir) + html_name = 'index.html' + + html_file = os.path.join(website_dir, html_name) + with open(html_file, 'w') as f: + name = repodict["name"] + description = repodict["description"] + f.write(""" + + + + {name} + + + + + + + + + + +

{name}

+
+

+QR: {name} + +{description}
+{details}

+{link} +
+""".format(name=name, +description=description, +details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), +link=repodict["address"] +)) def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints): @@ -230,41 +270,6 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_ else: json.dump(output, fp, default=_index_encoder_default) - html_name = 'index.html' - html_file = os.path.join(repodir, html_name) - with open(html_file, 'w') as f: - name = repodict["name"] - description = repodict["description"] - f.write(""" - - - - {name} - - - - - - - - - - -

{name}

-
-

-QR: {name} - -{description}
-{details}

-{link} -
-""".format(name=name, -description=description, -details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(output['apps'])), -link=repodict["address"] -)) - if common.options.nosign: logging.debug(_('index-v1 must have a signature, use `fdroid signindex` to create it!')) else: From 44ee531426c9848aa03f7a495fa66c061a838ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 25 Jan 2021 09:35:25 +0100 Subject: [PATCH 03/13] Add QR code and css --- fdroidserver/index.py | 138 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 52dee442..76f92030 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -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 @@ -132,12 +133,13 @@ def make(apps, apks, repodir, archive): make_website(sortedapps, repodir, repodict) def make_website(apps, repodir, repodict): - website_dir = os.path.join(repodir, "www") - if not os.path.exists(website_dir): - os.makedirs(website_dir) + if not os.path.exists(repodir): + os.makedirs(repodir) html_name = 'index.html' - html_file = os.path.join(website_dir, html_name) + link=repodict["address"] + + html_file = os.path.join(repodir, html_name) with open(html_file, 'w') as f: name = repodict["name"] description = repodict["description"] @@ -146,8 +148,8 @@ def make_website(apps, repodir, repodict): {name} - - + + @@ -168,8 +170,128 @@ def make_website(apps, repodir, repodict): """.format(name=name, description=description, details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), -link=repodict["address"] -)) +link=link)) + + css_file = os.path.join(repodir, "index.css") + with open(css_file, "w") as f: + f.write(""" +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; } +} + """) + + #qrcode.make(repodir["address"]).save(os.path.join(repodir, "images", "fdroid_repo_qr.png")) + images_dir = os.path.join(repodir, "images") + if not os.path.exists(images_dir): + os.makedirs(images_dir) + qrcode.make(link).save(os.path.join(images_dir, "fdroid_repo_qr.png")) + def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints): From 997f5d267b6aeb9264e136252705bffc667a086a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 25 Jan 2021 09:59:10 +0100 Subject: [PATCH 04/13] Properly add css --- fdroidserver/common.py | 1 + fdroidserver/index.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index a19795a0..4a5a39df 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -3764,6 +3764,7 @@ 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', diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 76f92030..5465573d 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -149,7 +149,7 @@ def make_website(apps, repodir, repodict): {name} - + @@ -160,16 +160,20 @@ def make_website(apps, repodir, repodict):

{name}

-

-QR: {name} +

+QR: {name} {description}
{details}

+

+ {link} + +

""".format(name=name, description=description, -details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), +details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), link=link)) css_file = os.path.join(repodir, "index.css") @@ -286,7 +290,6 @@ fieldset select, fieldset input, #reposelect select, #reposelect input { font-si } """) - #qrcode.make(repodir["address"]).save(os.path.join(repodir, "images", "fdroid_repo_qr.png")) images_dir = os.path.join(repodir, "images") if not os.path.exists(images_dir): os.makedirs(images_dir) From 4d464051ff5e7615aa2aea02e81e3c41589f516f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 25 Jan 2021 10:17:06 +0100 Subject: [PATCH 05/13] Fix pycodestlye errors --- fdroidserver/index.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 5465573d..609d9f1f 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -132,12 +132,13 @@ def make(apps, apks, repodir, archive): fdroid_signing_key_fingerprints) make_website(sortedapps, repodir, repodict) + def make_website(apps, repodir, repodict): if not os.path.exists(repodir): os.makedirs(repodir) html_name = 'index.html' - link=repodict["address"] + link = repodict["address"] html_file = os.path.join(repodir, html_name) with open(html_file, 'w') as f: @@ -172,9 +173,9 @@ def make_website(apps, repodir, repodict):

""".format(name=name, -description=description, -details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), -link=link)) + description=description, + details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), + link=link)) css_file = os.path.join(repodir, "index.css") with open(css_file, "w") as f: @@ -287,8 +288,7 @@ fieldset select, fieldset input, #reposelect select, #reposelect input { font-si .repoapplist { display:block; } .appdetailinner, .appdetailrow { display:block; } .appdetailcell { display:block; float:left; line-height:1.5em; } -} - """) +}""") images_dir = os.path.join(repodir, "images") if not os.path.exists(images_dir): From 8d51566a70d2fc717820b8b85cf16fd6580f773c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 25 Jan 2021 11:25:49 +0100 Subject: [PATCH 06/13] * Change image name * add fingerprint --- fdroidserver/common.py | 1 + fdroidserver/index.py | 85 +++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 4a5a39df..84451d70 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -3769,6 +3769,7 @@ def is_repo_file(filename): b'index_unsigned.jar', b'index.xml', b'index.html', + b'index.png', b'index-v1.jar', b'index-v1.json', b'categories.txt', diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 609d9f1f..ff391abd 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -134,48 +134,66 @@ def make(apps, apks, repodir, archive): 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) + if not os.path.exists(repodir): os.makedirs(repodir) html_name = 'index.html' - link = repodict["address"] - html_file = os.path.join(repodir, html_name) with open(html_file, 'w') as f: name = repodict["name"] description = repodict["description"] f.write(""" - - - - {name} - - - - - - - - - - -

{name}

-
-

-QR: {name} - -{description}
-{details}

-

- -{link} - -

-
-""".format(name=name, + + + + + {name} + + + + + + + + + + + +

{name}

+
+

+ + QR: {name} + + {description} +
+
+ {details} +

+

+ + + {link} + + +

+

If you would like to manually verify the fingerprint (SHA-256) of the repository signing key, here it is:
+ + {fingerprint} + +

+
+ """.format(name=name, description=description, details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), - link=link)) + fingerprint=repo_pubkey_fingerprint, + link=link, + link_fingerprinted=link_fingerprinted)) css_file = os.path.join(repodir, "index.css") with open(css_file, "w") as f: @@ -290,10 +308,7 @@ fieldset select, fieldset input, #reposelect select, #reposelect input { font-si .appdetailcell { display:block; float:left; line-height:1.5em; } }""") - images_dir = os.path.join(repodir, "images") - if not os.path.exists(images_dir): - os.makedirs(images_dir) - qrcode.make(link).save(os.path.join(images_dir, "fdroid_repo_qr.png")) + qrcode.make(link_fingerprinted).save(os.path.join(repodir, "index.png")) def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints): From 96854be84a9374ceed4d9c74870d068f8516de56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Tue, 26 Jan 2021 13:06:06 +0100 Subject: [PATCH 07/13] Only overwrite index.html/css files which were created by fdroid update Further changes: * use real value for icon instead of hard coded value * Move qrcode.make() to top * fix identation of css file generation --- fdroidserver/index.py | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index ff391abd..8ba53b88 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -133,21 +133,36 @@ def make(apps, apks, repodir, archive): make_website(sortedapps, repodir, repodict) +def _should_file_be_generated(path, magic_string): + if os.path.exists(path): + with open(path) as f: + if not magic_string 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) - html_name = 'index.html' + + qrcode.make(link_fingerprinted).save(os.path.join(repodir, "index.png")) + html_name = 'index.html' html_file = os.path.join(repodir, html_name) - with open(html_file, 'w') as f: - name = repodict["name"] - description = repodict["description"] - f.write(""" + + 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(""" + @@ -155,8 +170,8 @@ def make_website(apps, repodir, repodict): {name} - - + + @@ -188,16 +203,20 @@ def make_website(apps, repodir, repodict):

- """.format(name=name, + """.format(autogenerate_comment=autogenerate_comment, description=description, details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), fingerprint=repo_pubkey_fingerprint, + icon=icon, link=link, - link_fingerprinted=link_fingerprinted)) + link_fingerprinted=link_fingerprinted, + name=name)) - css_file = os.path.join(repodir, "index.css") + css_file = os.path.join(repodir, "index.css") + if _should_file_be_generated(css_file, autogenerate_comment): with open(css_file, "w") as f: - f.write(""" + # 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; @@ -308,8 +327,6 @@ fieldset select, fieldset input, #reposelect select, #reposelect input { font-si .appdetailcell { display:block; float:left; line-height:1.5em; } }""") - qrcode.make(link_fingerprinted).save(os.path.join(repodir, "index.png")) - def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_fingerprints): From 0936051c7bb579f65f17e76f8955099bb98320da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 1 Feb 2021 06:42:53 +0100 Subject: [PATCH 08/13] Fix pep8 --- fdroidserver/index.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 8ba53b88..2b73ec4c 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -136,7 +136,7 @@ def make(apps, apks, repodir, archive): def _should_file_be_generated(path, magic_string): if os.path.exists(path): with open(path) as f: - if not magic_string in f.readline(): # if the magic_string is not in the first line the file should be overwritten + 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 @@ -146,11 +146,11 @@ def make_website(apps, repodir, repodict): 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 + 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' @@ -204,13 +204,13 @@ def make_website(apps, repodir, repodict):

""".format(autogenerate_comment=autogenerate_comment, - description=description, - details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), - fingerprint=repo_pubkey_fingerprint, - icon=icon, - link=link, - link_fingerprinted=link_fingerprinted, - name=name)) + description=description, + details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), + fingerprint=repo_pubkey_fingerprint, + icon=icon, + link=link, + link_fingerprinted=link_fingerprinted, + name=name)) css_file = os.path.join(repodir, "index.css") if _should_file_be_generated(css_file, autogenerate_comment): From 022d73b3b6b0c25b0e01af5e9a63df2a1606e700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 1 Feb 2021 07:54:48 +0100 Subject: [PATCH 09/13] Add HTML/CSS tidy test and tidy up the content --- fdroidserver/index.py | 402 ++++++++++++++++++++++++++++-------------- tests/index.TestCase | 36 ++++ 2 files changed, 303 insertions(+), 135 deletions(-) diff --git a/fdroidserver/index.py b/fdroidserver/index.py index 2b73ec4c..f9120bd8 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -162,55 +162,69 @@ def make_website(apps, repodir, repodict): description = repodict["description"] icon = repodict["icon"] f.write(""" - - - - - - {name} - - - - - - - - - - - -

{name}

-
-

- - QR: {name} - - {description} -
-
- {details} -

-

- - - {link} - - -

-

If you would like to manually verify the fingerprint (SHA-256) of the repository signing key, here it is:
- - {fingerprint} - -

-
- """.format(autogenerate_comment=autogenerate_comment, + + + + + + + {name} + + + + + + + + + + + + +

+ {name} +

+
+

+ + + QR: test + + + {description} +
+
+ Currently it serves + + {number_of_apps} + + apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL: +

+

+ + + {link} + + +

+

+ If you would like to manually verify the fingerprint (SHA-256) of the repository signing key, here it is: +
+ + {fingerprint} + +

+
+ + +""".format(autogenerate_comment=autogenerate_comment, description=description, - details="Currently it serves {} apps. To add it to your F-Droid client, scan the QR code (click it to enlarge) or use this URL:".format(len(apps)), fingerprint=repo_pubkey_fingerprint, icon=icon, link=link, link_fingerprinted=link_fingerprinted, - name=name)) + 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): @@ -218,113 +232,231 @@ def make_website(apps, repodir, repodict): # 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; + font-family : Arial, Helvetica, Sans-Serif; + color : #0000ee; + background-color : #ffffff; +} +p { + text-align : justify; +} +p.center { + text-align : center; } -p { text-align:justify; } -p.center { text-align:center; } TD { - font-family: Arial, Helvetica, Sans-Serif; - color: #0000ee; + font-family : Arial, Helvetica, Sans-Serif; + color : #0000ee; +} +body,td { + font-size : 14px; } -body,td { font-size:14px;} TH { - font-family: Arial, Helvetica, Sans-Serif; - color: #0000ee; - background-color: #F5EAD4; + 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; } -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; + 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; } -#intro > p { margin-top:0;} -#intro p:last-child {margin-bottom:0;} .last { - border-bottom: 1px solid black; - padding-bottom:.5em; - text-align:center; + 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; } -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; + 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; } -.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; + 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; } - -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; + text-align : center; + margin-top : 1em; + font-size : 11px; + color : #555; +} +#footer img { + vertical-align : middle; } -#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; } + .repoapplist { + display : block; + } + .appdetailinner, .appdetailrow { + display : block; + } + .appdetailcell { + display : block; + float : left; + line-height : 1.5em; + } }""") diff --git a/tests/index.TestCase b/tests/index.TestCase index 16885dbf..abd1cc24 100755 --- a/tests/index.TestCase +++ b/tests/index.TestCase @@ -13,6 +13,7 @@ import requests import tempfile import json import shutil +from html5print import CSSBeautifier, HTMLBeautifier localmodule = os.path.realpath( os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')) @@ -354,6 +355,41 @@ 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'))) + + 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__)) From d5a90ed60e02cfa8994e827b9fea5e661a2012d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 1 Feb 2021 08:09:25 +0100 Subject: [PATCH 10/13] add html5print as test dependency --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 669ec33a..3d751489 100755 --- a/setup.py +++ b/setup.py @@ -88,7 +88,10 @@ setup(name='fdroidserver', 'yamllint', ], extras_require={ - 'test': ['pyjks'], + 'test': [ + 'pyjks', + 'html5print' + ], }, classifiers=[ 'Development Status :: 4 - Beta', From b1bde9e407e9f055e5a84b61f4e3b27c22d3f07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 8 Feb 2021 06:37:44 +0100 Subject: [PATCH 11/13] * Skip tidy check if html5print is not available * install test dependencies on arch --- .gitlab-ci.yml | 2 +- tests/index.TestCase | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 800c2057..0f3ffc83 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -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 diff --git a/tests/index.TestCase b/tests/index.TestCase index abd1cc24..14383959 100755 --- a/tests/index.TestCase +++ b/tests/index.TestCase @@ -13,7 +13,6 @@ import requests import tempfile import json import shutil -from html5print import CSSBeautifier, HTMLBeautifier localmodule = os.path.realpath( os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')) @@ -378,6 +377,12 @@ class IndexTest(unittest.TestCase): 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 androguard is missing!') + return + with open(os.path.join("repo", "index.html")) as f: html = f.read() pretty_html = HTMLBeautifier.beautify(html) From 23931e6818303ff259ec237b36f52d39441667cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 8 Feb 2021 11:54:12 +0100 Subject: [PATCH 12/13] Install [test] dependencies when running complete-ci-tests --- tests/complete-ci-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/complete-ci-tests b/tests/complete-ci-tests index 75fe515e..07e0b2a0 100755 --- a/tests/complete-ci-tests +++ b/tests/complete-ci-tests @@ -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 From 9c609aa36113233e17bd9f0cef767eebab6c8ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Br=C3=BCckmann?= <64bit@posteo.de> Date: Mon, 8 Feb 2021 11:56:41 +0100 Subject: [PATCH 13/13] Fix copy-paste error --- tests/index.TestCase | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/index.TestCase b/tests/index.TestCase index 14383959..e8f22036 100755 --- a/tests/index.TestCase +++ b/tests/index.TestCase @@ -380,7 +380,7 @@ class IndexTest(unittest.TestCase): try: from html5print import CSSBeautifier, HTMLBeautifier except ImportError: - print('WARNING: skipping rest of test since androguard is missing!') + print('WARNING: skipping rest of test since html5print is missing!') return with open(os.path.join("repo", "index.html")) as f: