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.

talyz f8096460 4197b6dd

Changed files
+65 -3
nixos
modules
services
web-apps
pkgs
servers
web-apps
discourse
+12 -1
nixos/modules/services/web-apps/discourse.xml
···
Ruby dependencies are listed in its
<filename>plugin.rb</filename> file as function calls to
<literal>gem</literal>. To construct the corresponding
-
<filename>Gemfile</filename>, run <command>bundle
init</command>, then add the <literal>gem</literal> lines to it
verbatim.
</para>
<para>
···
Ruby dependencies are listed in its
<filename>plugin.rb</filename> file as function calls to
<literal>gem</literal>. To construct the corresponding
+
<filename>Gemfile</filename> manually, run <command>bundle
init</command>, then add the <literal>gem</literal> lines to it
verbatim.
+
</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>
+53 -2
pkgs/servers/web-apps/discourse/update.py
···
import stat
import json
import requests
from distutils.version import LooseVersion
from pathlib import Path
from typing import Iterable
···
def _nix_eval(expr: str):
nixpkgs_path = Path(__file__).parent / '../../../../'
-
return json.loads(subprocess.check_output(['nix', 'eval', '--json', f'(with import {nixpkgs_path} {{}}; {expr})'], text=True))
def _get_current_package_version(pkg: str):
···
repo_name = plugin.get('repo_name') or name
repo = DiscourseRepo(owner=owner, repo=repo_name)
prev_commit_sha = _nix_eval(f'discourse.plugins.{name}.src.rev')
if prev_commit_sha == repo.latest_commit_sha:
click.echo(f'Plugin {name} is already at the latest revision')
continue
-
filename = _nix_eval(f'builtins.unsafeGetAttrPos "src" discourse.plugins.{name}')['file']
prev_hash = _nix_eval(f'discourse.plugins.{name}.src.outputHash')
new_hash = subprocess.check_output([
'nix-universal-prefetch', fetcher,
···
import stat
import json
import requests
+
import textwrap
from distutils.version import LooseVersion
from pathlib import Path
from typing import Iterable
···
def _nix_eval(expr: str):
nixpkgs_path = Path(__file__).parent / '../../../../'
+
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):
···
repo_name = plugin.get('repo_name') or 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')
if prev_commit_sha == repo.latest_commit_sha:
click.echo(f'Plugin {name} is already at the latest revision')
continue
prev_hash = _nix_eval(f'discourse.plugins.{name}.src.outputHash')
new_hash = subprocess.check_output([
'nix-universal-prefetch', fetcher,