discourse.plugins: Make the updater able to package plugins

Let the update.py script handle the initial, repetitive task of
packaging new plugins. With this in place, the plugin only needs to be
added to the list in `update-plugins` and most of the work will be
done automatically when the script is run. Metadata still needs to be
filled in manually and some packages may of course require additional
work/patching.

(cherry picked from commit f8096460bd15d4f13a01cfddf0a30798921fdb42)
This commit is contained in:
talyz 2021-08-13 18:42:56 +02:00
parent 08fde82d77
commit fd169abf9b
No known key found for this signature in database
GPG Key ID: 2DED2151F4671A2B
2 changed files with 65 additions and 3 deletions

View File

@ -284,11 +284,22 @@ services.discourse = {
Ruby dependencies are listed in its Ruby dependencies are listed in its
<filename>plugin.rb</filename> file as function calls to <filename>plugin.rb</filename> file as function calls to
<literal>gem</literal>. To construct the corresponding <literal>gem</literal>. To construct the corresponding
<filename>Gemfile</filename>, run <command>bundle <filename>Gemfile</filename> manually, run <command>bundle
init</command>, then add the <literal>gem</literal> lines to it init</command>, then add the <literal>gem</literal> lines to it
verbatim. verbatim.
</para> </para>
<para>
Much of the packaging can be done automatically by the
<filename>nixpkgs/pkgs/servers/web-apps/discourse/update.py</filename>
script - just add the plugin to the <literal>plugins</literal>
list in the <function>update_plugins</function> function and run
the script:
<programlisting language="bash">
./update.py update-plugins
</programlisting>.
</para>
<para> <para>
Some plugins provide <link Some plugins provide <link
linkend="module-services-discourse-site-settings">site linkend="module-services-discourse-site-settings">site

View File

@ -12,6 +12,7 @@ import os
import stat import stat
import json import json
import requests import requests
import textwrap
from distutils.version import LooseVersion from distutils.version import LooseVersion
from pathlib import Path from pathlib import Path
from typing import Iterable from typing import Iterable
@ -77,7 +78,11 @@ def _call_nix_update(pkg, version):
def _nix_eval(expr: str): def _nix_eval(expr: str):
nixpkgs_path = Path(__file__).parent / '../../../../' nixpkgs_path = Path(__file__).parent / '../../../../'
return json.loads(subprocess.check_output(['nix', 'eval', '--json', f'(with import {nixpkgs_path} {{}}; {expr})'], text=True)) try:
output = subprocess.check_output(['nix', 'eval', '--json', f'(with import {nixpkgs_path} {{}}; {expr})'], text=True)
except subprocess.CalledProcessError:
return None
return json.loads(output)
def _get_current_package_version(pkg: str): def _get_current_package_version(pkg: str):
@ -206,13 +211,59 @@ def update_plugins():
repo_name = plugin.get('repo_name') or name repo_name = plugin.get('repo_name') or name
repo = DiscourseRepo(owner=owner, repo=repo_name) repo = DiscourseRepo(owner=owner, repo=repo_name)
filename = _nix_eval(f'builtins.unsafeGetAttrPos "src" discourse.plugins.{name}')
if filename is None:
filename = Path(__file__).parent / 'plugins' / name / 'default.nix'
filename.parent.mkdir()
has_ruby_deps = False
for line in repo.get_file('plugin.rb', repo.latest_commit_sha).splitlines():
if 'gem ' in line:
has_ruby_deps = True
break
with open(filename, 'w') as f:
f.write(textwrap.dedent(f"""
{{ lib, mkDiscoursePlugin, fetchFromGitHub }}:
mkDiscoursePlugin {{
name = "{name}";"""[1:] + ("""
bundlerEnvArgs.gemdir = ./.;""" if has_ruby_deps else "") + f"""
src = {fetcher} {{
owner = "{owner}";
repo = "{repo_name}";
rev = "replace-with-git-rev";
sha256 = "replace-with-sha256";
}};
meta = with lib; {{
homepage = "";
maintainers = with maintainers; [ ];
license = licenses.mit; # change to the correct license!
description = "";
}};
}}"""))
all_plugins_filename = Path(__file__).parent / 'plugins' / 'all-plugins.nix'
with open(all_plugins_filename, 'r+') as f:
content = f.read()
pos = -1
while content[pos] != '}':
pos -= 1
content = content[:pos] + f' {name} = callPackage ./{name} {{}};' + os.linesep + content[pos:]
f.seek(0)
f.write(content)
f.truncate()
else:
filename = filename['file']
prev_commit_sha = _nix_eval(f'discourse.plugins.{name}.src.rev') prev_commit_sha = _nix_eval(f'discourse.plugins.{name}.src.rev')
if prev_commit_sha == repo.latest_commit_sha: if prev_commit_sha == repo.latest_commit_sha:
click.echo(f'Plugin {name} is already at the latest revision') click.echo(f'Plugin {name} is already at the latest revision')
continue continue
filename = _nix_eval(f'builtins.unsafeGetAttrPos "src" discourse.plugins.{name}')['file']
prev_hash = _nix_eval(f'discourse.plugins.{name}.src.outputHash') prev_hash = _nix_eval(f'discourse.plugins.{name}.src.outputHash')
new_hash = subprocess.check_output([ new_hash = subprocess.check_output([
'nix-universal-prefetch', fetcher, 'nix-universal-prefetch', fetcher,