jinja templates support

This commit is contained in:
Evgenii Alekseev 2021-03-08 15:47:05 +03:00
parent 026c896fb7
commit b3345c4184
8 changed files with 85 additions and 23 deletions

View File

@ -50,8 +50,9 @@ Report generation settings:
Group name must refer to architecture, e.g. it should be `html_x86_64` for x86_64 architecture. Group name must refer to architecture, e.g. it should be `html_x86_64` for x86_64 architecture.
* `path` - path to html report file, string, required. * `path` - path to html report file, string, required.
* `css_path` - path to CSS to include in HTML, string, optional. * `homepage` - link to homepage, string, optional.
* `link_path` - prefix for HTML links, string, required. * `link_path` - prefix for HTML links, string, required.
* `template_path` - path to Jinja2 template, string, required.
## `upload` group ## `upload` group

View File

@ -10,13 +10,18 @@ license=('GPL3')
depends=('devtools' 'expac' 'git' 'python-aur' 'python-srcinfo') depends=('devtools' 'expac' 'git' 'python-aur' 'python-srcinfo')
makedepends=('python-pip') makedepends=('python-pip')
optdepends=('aws-cli: sync to s3' optdepends=('aws-cli: sync to s3'
'breezy: -bzr packages support'
'darcs: -darcs packages support'
'gnupg: package and repository sign' 'gnupg: package and repository sign'
'rsync: sync by using rsync') 'mercurial: -hg packages support'
'python-jinja: html report generation'
'rsync: sync by using rsync'
'subversion: -svn packages support')
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver-src.tar.xz" source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgname-$pkgver-src.tar.xz"
'ahriman.sudoers' 'ahriman.sudoers'
'ahriman.sysusers' 'ahriman.sysusers'
'ahriman.tmpfiles') 'ahriman.tmpfiles')
sha512sums=('67a6b6432ca8985491e398b8f2b374cf7cfd40bb69ad844913d9d45d3b510fba2910dfc21fd33a4faf4f2035bb005909cf815523180436c3a30e512757c268e7' sha512sums=('f77b434f5174b2e7a8817bdcc1883e9ded3bd57c30be09b438ec55b65aa83bcd1326f1241ad9ca86552b5fb71f9a15637af7997b37636db9d9ee61c24d235c5c'
'8c9b5b63ac3f7b4d9debaf801a1e9c060877c33d3ecafe18010fcca778e5fa2f2e46909d3d0ff1b229ff8aa978445d8243fd36e1fc104117ed678d5e21901167' '8c9b5b63ac3f7b4d9debaf801a1e9c060877c33d3ecafe18010fcca778e5fa2f2e46909d3d0ff1b229ff8aa978445d8243fd36e1fc104117ed678d5e21901167'
'13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075' '13718afec2c6786a18f0b223ef8e58dccf0688bca4cdbe203f14071f5031ed20120eb0ce38b52c76cfd6e8b6581a9c9eaa2743eb11abbaca637451a84c33f075'
'55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4') '55b20f6da3d66e7bbf2add5d95a3b60632df121717d25a993e56e737d14f51fe063eb6f1b38bd81cc32e05db01c0c1d80aaa720c45cde87f238d8b46cdb8cbc4')

View File

@ -25,8 +25,9 @@ target =
[html_x86_64] [html_x86_64]
path = path =
css_path = homepage =
link_path = link_path =
template_path = /usr/share/ahriman/index.jinja2
[upload] [upload]
target = target =

View File

@ -0,0 +1,31 @@
<!doctype html>
<html lang="en">
<head>
<title>{{ repository|e }}</title>
</head>
<body>
<h1>{{ repository|e }} ArchLinux custom repository</h1>
{% if pgp_key is not none %}
<p>All packages are signed with <a href="http://keys.gnupg.net/pks/lookup?search=0x{{ pgp_key|e }}" title="key search">{{ pgp_key|e }}</a>.</p>
{% endif %}
<code>
$ cat /etc/pacman.conf<br>
[{{ repository|e }}]<br>
Server = {{ link_path|e }}
</code>
<p>Packages:</p>
<ul>
{% for package, package_url in packages.items() %}
<li><a href="{{ package_url|e }}" title="{{ package|e }}">{{ package|e }}</a></li>
{% endfor %}
</ul>
{% if homepage is not none %}
<footer><a href="{{ homepage|e }}" title="homepage">Homepage</a></footer>
{% endif %}
</body>
</html>

View File

@ -17,7 +17,7 @@ setup(
author='arcanis', author='arcanis',
author_email='', author_email='',
url='', url='https://github.com/arcan1s/ahriman',
license='GPL3', license='GPL3',
@ -39,7 +39,7 @@ setup(
include_package_data=True, include_package_data=True,
scripts=[ scripts=[
'package/bin/ahriman' 'package/bin/ahriman',
], ],
data_files=[ data_files=[
('/etc', ['package/etc/ahriman.ini']), ('/etc', ['package/etc/ahriman.ini']),
@ -47,10 +47,12 @@ setup(
('lib/systemd/system', [ ('lib/systemd/system', [
'package/lib/systemd/system/ahriman.service', 'package/lib/systemd/system/ahriman.service',
'package/lib/systemd/system/ahriman.timer' 'package/lib/systemd/system/ahriman.timer'
]) ]),
('share/ahriman', ['package/share/ahriman/index.jinja2']),
], ],
extras_require={ extras_require={
'html-templates': ['Jinja2'],
'test': ['coverage', 'pytest'], 'test': ['coverage', 'pytest'],
}, },
) )

View File

@ -17,10 +17,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import jinja2
import os import os
from typing import Dict
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.report.report import Report from ahriman.core.report.report import Report
from ahriman.core.util import package_like
from ahriman.models.sign_settings import SignSettings
class HTML(Report): class HTML(Report):
@ -29,25 +34,37 @@ class HTML(Report):
Report.__init__(self, architecture, config) Report.__init__(self, architecture, config)
section = self.config.get_section_name('html', self.architecture) section = self.config.get_section_name('html', self.architecture)
self.report_path = config.get(section, 'path') self.report_path = config.get(section, 'path')
self.css_path = config.get(section, 'css_path')
self.link_path = config.get(section, 'link_path') self.link_path = config.get(section, 'link_path')
self.title = config.get('repository', 'name') self.template_path = config.get(section, 'template_path')
# base template vars
if SignSettings.from_option(config.get('sign', 'enabled')) != SignSettings.Disabled:
self.pgp_key = config.get('sign', 'key')
else:
self.pgp_key = None
self.homepage = config.get(section, 'homepage', fallback=None)
self.repository = config.get('repository', 'name')
def generate(self, path: str) -> None: def generate(self, path: str) -> None:
# lets not use libraries here # idea comes from https://stackoverflow.com/a/38642558
html = f'''<html lang="en"><head><title>{self.title}</title>''' templates_dir, template_name = os.path.split(self.template_path)
if self.css_path: loader = jinja2.FileSystemLoader(searchpath=templates_dir)
html += f'''<link rel="stylesheet" type="text/css" href="{self.css_path}">''' environment = jinja2.Environment(loader=loader)
html += '''</head><body>''' template = environment.get_template(template_name)
html += '''<ul>''' packages: Dict[str, str] = {}
for package in sorted(os.listdir(path)): for fn in sorted(os.listdir(path)):
if '.pkg.' not in package: if not package_like(fn):
continue continue
html += f'''<li><a href="{self.link_path}/{package}">{package}</a></li>''' packages[fn] = f'{self.link_path}/{fn}'
html += '''</ul>'''
html += '''</body></html>''' html = template.render(
homepage=self.homepage,
link_path=self.link_path,
packages=packages,
pgp_key=self.pgp_key,
repository=self.repository)
with open(self.report_path, 'w') as out: with open(self.report_path, 'w') as out:
out.write(html) out.write(html)

View File

@ -29,6 +29,7 @@ from ahriman.core.repo.repo_wrapper import RepoWrapper
from ahriman.core.report.report import Report from ahriman.core.report.report import Report
from ahriman.core.sign.gpg_wrapper import GPGWrapper from ahriman.core.sign.gpg_wrapper import GPGWrapper
from ahriman.core.upload.uploader import Uploader from ahriman.core.upload.uploader import Uploader
from ahriman.core.util import package_like
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -64,7 +65,7 @@ class Repository:
def packages(self) -> List[Package]: def packages(self) -> List[Package]:
result: Dict[str, Package] = {} result: Dict[str, Package] = {}
for fn in os.listdir(self.paths.repository): for fn in os.listdir(self.paths.repository):
if '.pkg.' not in fn: if not package_like(fn):
continue continue
full_path = os.path.join(self.paths.repository, fn) full_path = os.path.join(self.paths.repository, fn)
try: try:
@ -101,7 +102,7 @@ class Repository:
def process_remove(self, packages: List[str]) -> str: def process_remove(self, packages: List[str]) -> str:
for fn in os.listdir(self.paths.repository): for fn in os.listdir(self.paths.repository):
if '.pkg.' not in fn: if not package_like(fn):
continue continue
full_path = os.path.join(self.paths.repository, fn) full_path = os.path.join(self.paths.repository, fn)
@ -146,7 +147,7 @@ class Repository:
self.config.get_section_name('build', self.architecture), 'ignore_packages') self.config.get_section_name('build', self.architecture), 'ignore_packages')
for fn in os.listdir(self.paths.repository): for fn in os.listdir(self.paths.repository):
if '.pkg.' not in fn: if not package_like(fn):
continue continue
try: try:

View File

@ -37,3 +37,7 @@ def check_output(*args: str, exception: Optional[Exception],
logger.debug(line) logger.debug(line)
raise exception or e raise exception or e
return result return result
def package_like(filename: str) -> bool:
return '.pkg.' in filename and not filename.endswith('.sig')