all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [bug#49828] [PATCH 00/20] Add minetest mods
@ 2021-08-02 15:46 Maxime Devos
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
  2021-08-05 12:46 ` [bug#49828] [PATCH 00/20] Add minetest mods Andrew Ward
  0 siblings, 2 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:46 UTC (permalink / raw)
  To: 49828

[-- Attachment #1: Type: text/plain, Size: 3015 bytes --]

Hi Guix,

This patch series adds a bunch of Minetest mods, but first,
it patches Minetest such that the mods will actually be found.
An importer for Minetest mods from ContentDB
(https://content.minetest.net) is included as well.

I have verified:

  * "guix lint" doesn't find any issues,
    except ‘no updated found for ...’ and some incorrect
    ‘... can be upgraded to’.

  * the source code doesn't appear to contain any malware

  * the license information

  * "./pre-inst-env guix build ALL-THE-NEW-PACKAGES" succeeds

  * "make check 'TESTS=tests/contentdb.scm'" succeeds

I've also constructed an environment (./pre-inst-env guix environment --ad-hoc)
containing all the mods and minetest, started minetest, created a new world,
enabled all the mods, and placed some random nodes and tried out "worldedit".
This seems to work, but I did not yet try out every mod.

I also constructed an environment with only "minetest" and tried out the
built-in ContentDB installer.  It still appears to work.

(The actual patches will be sent once debbugs gives me an issue number)

Maxime Devos (20):
  gnu: minetest: Respect --without-tests.
  gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  gnu: minetest: New package module.
  build-system: Add 'minetest-mod-build-system'.
  build-system: minetest: Don't retain references to "bash-minimal".
  guix: Add ContentDB importer.
  gnu: Add minetest-mesecons.
  gnu: Add minetest-basic-materials.
  gnu: Add minetest-unifieddyes.
  gnu: Add minetest-pipeworks.
  gnu: Add minetest-coloredwood.
  gnu: Add minetest-ethereal.
  gnu: Add minetest-technic.
  gnu: Add minetest-throwing.
  gnu: Add minetest-throwing-arrows.
  gnu: Add minetest-unified-inventory.
  gnu: Add minetest-worldedit.
  gnu: Add minetest-mobs.
  gnu: Add minetest-mobs-animal.
  gnu: Add minetest-homedecor-modpack.

 Makefile.am                                   |   4 +
 doc/guix.texi                                 |  32 ++
 gnu/local.mk                                  |   2 +
 gnu/packages/games.scm                        |  14 +-
 gnu/packages/minetest.scm                     | 423 ++++++++++++++++++
 ...vironment-variable-MINETEST_MOD_PATH.patch | 115 +++++
 guix/build-system/minetest.scm                |  62 +++
 guix/import/contentdb.scm                     | 310 +++++++++++++
 guix/scripts/import.scm                       |   3 +-
 guix/scripts/import/contentdb.scm             | 106 +++++
 po/guix/POTFILES.in                           |   1 +
 tests/contentdb.scm                           | 227 ++++++++++
 12 files changed, 1293 insertions(+), 6 deletions(-)
 create mode 100644 gnu/packages/minetest.scm
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/import/contentdb.scm
 create mode 100644 guix/scripts/import/contentdb.scm
 create mode 100644 tests/contentdb.scm

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests.
  2021-08-02 15:46 [bug#49828] [PATCH 00/20] Add minetest mods Maxime Devos
@ 2021-08-02 15:50 ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
                     ` (19 more replies)
  2021-08-05 12:46 ` [bug#49828] [PATCH 00/20] Add minetest mods Andrew Ward
  1 sibling, 20 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/games.scm
  (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
  of ',(%current-target-system)'. Remove trailing #t.
---
 gnu/packages/games.scm | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 8c6b5523f1..3e7086b398 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3590,13 +3590,12 @@ match, cannon keep, and grave-itation pit.")
                      (string-append (getcwd) "/games")) ; for check
              #t))
          (replace 'check
-           (lambda _
+           (lambda* (#:key tests? #:allow-other-keys)
              ;; Thanks to our substitutions, the tests should also run
              ;; when invoked on the target outside of `guix build'.
-             (unless ,(%current-target-system)
+             (when tests?
                (setenv "HOME" "/tmp")
-               (invoke "src/minetest" "--run-unittests"))
-             #t)))))
+               (invoke "src/minetest" "--run-unittests")))))))
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 17:28     ` Leo Prikler
  2021-08-02 15:50   ` [bug#49828] [PATCH 03/20] gnu: minetest: New package module Maxime Devos
                     ` (18 subsequent siblings)
  19 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch:
  New file.
* gnu/packages/games.scm
  (minetest)[source]{patches}: Add it.
  (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/games.scm                        |   7 +-
 ...vironment-variable-MINETEST_MOD_PATH.patch | 115 ++++++++++++++++++
 3 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c80a9af78c..d96d4e3dbc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -801,6 +801,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
   %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
   %D%/packages/patches/adb-add-libraries.patch			\
+  %D%/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch	\
   %D%/packages/patches/aegis-constness-error.patch         	\
   %D%/packages/patches/aegis-perl-tempdir1.patch           	\
   %D%/packages/patches/aegis-perl-tempdir2.patch           	\
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 3e7086b398..2f3285c6ea 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3553,6 +3553,7 @@ match, cannon keep, and grave-itation pit.")
                (base32
                 "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8"))
               (modules '((guix build utils)))
+              (patches (search-patches "Add-environment-variable-MINETEST_MOD_PATH.patch"))
               (snippet
                '(begin
                   ;; Delete bundled libraries.
@@ -3599,7 +3600,11 @@ match, cannon keep, and grave-itation pit.")
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-            (files '("share/minetest/games")))))
+            (files '("share/minetest/games")))
+           (search-path-specification
+            (variable "MINETEST_MOD_PATH")
+            (files '("share/minetest/mods"))
+            (separator #f))))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (inputs
diff --git a/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
new file mode 100644
index 0000000000..8478a7bf72
--- /dev/null
+++ b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
@@ -0,0 +1,115 @@
+From 6eb753c5bf67764890856cf23a67c0bf65973c16 Mon Sep 17 00:00:00 2001
+From: Maxime Devos <maximedevos@telenet.be>
+Date: Thu, 29 Jul 2021 22:24:50 +0200
+Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
+
+This adds an environment variable MINETEST_MOD_PATH.
+When it exists, Minetest will look there for mods
+in addition to ~/.minetest/mods/.
+
+This patch as-is is not yet ready for upstream, because:
+
+  * the GUI will only display mods in MINETEST_MOD_PATH
+    or mods in ~/.minetest/mods, it won't combine the two
+
+  * the GUI for installing mods from ContentDB is disabled
+    when MINETEST_MOD_PATH is set, because otherwise Minetest
+    would try to install mods in the store.
+
+  * MINETEST_MOD_PATH can only have a single component
+---
+ builtin/mainmenu/dlg_contentstore.lua |  7 +++++++
+ src/content/subgames.cpp              |  3 +++
+ src/script/lua_api/l_mainmenu.cpp     | 14 +++++++++++++-
+ src/script/lua_api/l_mainmenu.h       |  2 ++
+ 4 files changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
+index 7096c9187..c4a2cbd18 100644
+--- a/builtin/mainmenu/dlg_contentstore.lua
++++ b/builtin/mainmenu/dlg_contentstore.lua
+@@ -22,6 +22,13 @@ if not core.get_http_api then
+ 	end
+ 	return
+ end
++if core.mod_path_set() then
++	function create_store_dlg()
++		return messagebox("store",
++				fgettext("Mods from ContentDB cannot be installed when mods from Guix are also installed"))
++	end
++	return
++end
+ 
+ -- Unordered preserves the original order of the ContentDB API,
+ -- before the package list is ordered based on installed state.
+diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
+index e9dc609b0..1809f189e 100644
+--- a/src/content/subgames.cpp
++++ b/src/content/subgames.cpp
+@@ -110,6 +110,9 @@ SubgameSpec findSubgame(const std::string &id)
+ 	std::set<std::string> mods_paths;
+ 	if (!user_game)
+ 		mods_paths.insert(share + DIR_DELIM + "mods");
++	const char *env_mod_path = getenv("MINETEST_MOD_PATH");
++	if (env_mod_path)
++		mods_paths.insert(std::string(env_mod_path));
+ 	if (user != share || user_game)
+ 		mods_paths.insert(user + DIR_DELIM + "mods");
+ 
+diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
+index ad00de1c4..737550c42 100644
+--- a/src/script/lua_api/l_mainmenu.cpp
++++ b/src/script/lua_api/l_mainmenu.cpp
+@@ -495,9 +495,19 @@ int ModApiMainMenu::l_get_user_path(lua_State *L)
+ /******************************************************************************/
+ int ModApiMainMenu::l_get_modpath(lua_State *L)
+ {
++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
+ 	std::string modpath = fs::RemoveRelativePathComponents(
+ 		porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
+-	lua_pushstring(L, modpath.c_str());
++	if (c_modpath == NULL)
++		c_modpath = modpath.c_str();
++	lua_pushstring(L, c_modpath);
++	return 1;
++}
++
++/******************************************************************************/
++int ModApiMainMenu::l_mod_path_set(lua_State *L)
++{
++	lua_pushboolean(L, NULL != getenv("MINETEST_MOD_PATH"));
+ 	return 1;
+ }
+ 
+@@ -855,6 +865,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(mod_path_set);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+@@ -888,6 +899,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(mod_path_set);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
+index ec2d20da2..719c26077 100644
+--- a/src/script/lua_api/l_mainmenu.h
++++ b/src/script/lua_api/l_mainmenu.h
+@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
+ 
+ 	static int l_get_modpath(lua_State *L);
+ 
++	static int l_mod_path_set(lua_State *L);
++
+ 	static int l_get_clientmodpath(lua_State *L);
+ 
+ 	static int l_get_gamepath(lua_State *L);
+-- 
+2.32.0
+
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 03/20] gnu: minetest: New package module.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
                     ` (17 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

Aside from the 'minetest-topic' procedure which will be used
for the 'home-page' field of some packages, this module is
currently empty.  The 'contentdb' importer defined in the
following patches will be used to populate this module.

* gnu/packages/minetest.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk              |  1 +
 gnu/packages/minetest.scm | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 gnu/packages/minetest.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index d96d4e3dbc..5de08b1b09 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -383,6 +383,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/mercury.scm			\
   %D%/packages/mes.scm				\
   %D%/packages/messaging.scm			\
+  %D%/packages/minetest.scm			\
   %D%/packages/mingw.scm			\
   %D%/packages/microcom.scm			\
   %D%/packages/moe.scm				\
diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
new file mode 100644
index 0000000000..f8aca3005c
--- /dev/null
+++ b/gnu/packages/minetest.scm
@@ -0,0 +1,26 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+(define-module (gnu packages minetest)
+  #:use-module (guix packages)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system minetest)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public (minetest-topic topic-id)
+  "Return an URL (as a string) pointing to the forum topic with
+numeric identifier TOPIC-ID on the official Minetest forums."
+  (string-append "https://forum.minetest.net/viewtopic.php?t="
+                 (number->string topic-id)))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 04/20] build-system: Add 'minetest-mod-build-system'.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 03/20] gnu: minetest: New package module Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal" Maxime Devos
                     ` (16 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* guix/build-system/minetest.scm: New module.
* Makefile.am (MODULES): Add it.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                    |  1 +
 doc/guix.texi                  |  7 +++++
 guix/build-system/minetest.scm | 53 ++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 guix/build-system/minetest.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f6fae09579 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..43c248234d 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,13 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying lua code, images and other resources to
+the location Minetest searches for mods.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..29866ced6d
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,53 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+(define (guix-name->mod-name package-name)
+  ;; The "minetest-" prefix is useless.  Don't make it appear in the
+  ;; ‘select mods’ menu when "modpack.conf" or "mod.conf" do not have
+  ;; the "name" field set.
+  (if (string-prefix? "minetest-" package-name)
+      (substring package-name 9)
+      package-name))
+
+(define (lower-mod name . arguments)
+  (define lower (build-system-lower copy-build-system))
+  (apply lower
+    name
+    #:install-plan
+    `'(("." ,(string-append "share/minetest/mods/"
+                            (guix-name->mod-name name))))
+    arguments))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (2 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-03  9:17     ` Leo Prikler
  2021-08-02 15:50   ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
                     ` (15 subsequent siblings)
  19 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* guix/build-system/minetest.scm
  (%standard-phases): New variable.  Delete "patch-source-shebangs"
  phase.
  (lower-mod): Set #:phases to value of new variable.
---
 guix/build-system/minetest.scm | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
index 29866ced6d..993c5631eb 100644
--- a/guix/build-system/minetest.scm
+++ b/guix/build-system/minetest.scm
@@ -35,6 +35,14 @@
       (substring package-name 9)
       package-name))
 
+(define %standard-phases
+  ;; The source code sometimes contains shell scripts which are used for
+  ;; development but not at run time (e.g. listnodes.sh in
+  ;; minetest-homedecor-modpack).  Don't make them retain a reference
+  ;; to bash-minimal.
+  '(modify-phases (@ (guix build copy-build-system) %standard-phases)
+     (delete 'patch-source-shebangs)))
+
 (define (lower-mod name . arguments)
   (define lower (build-system-lower copy-build-system))
   (apply lower
@@ -42,6 +50,7 @@
     #:install-plan
     `'(("." ,(string-append "share/minetest/mods/"
                             (guix-name->mod-name name))))
+    #:phases %standard-phases
     arguments))
 
 (define minetest-mod-build-system
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (3 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal" Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-05 16:41     ` Leo Prikler
  2021-08-02 15:50   ` [bug#49828] [PATCH 07/20] gnu: Add minetest-mesecons Maxime Devos
                     ` (14 subsequent siblings)
  19 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* guix/import/contentdb.scm: New file.
* guix/scripts/import/contentdb.scm: New file.
* tests/contentdb.scm: New file.
* Makefile.am (MODULES, SCM_TESTS): Register them.
* po/guix/POTFILES.in: Likewise.
* doc/guix.texi (Invoking guix import): Document it.
---
 Makefile.am                       |   3 +
 doc/guix.texi                     |  25 +++
 guix/import/contentdb.scm         | 310 ++++++++++++++++++++++++++++++
 guix/scripts/import.scm           |   3 +-
 guix/scripts/import/contentdb.scm | 106 ++++++++++
 po/guix/POTFILES.in               |   1 +
 tests/contentdb.scm               | 227 ++++++++++++++++++++++
 7 files changed, 674 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/contentdb.scm
 create mode 100644 guix/scripts/import/contentdb.scm
 create mode 100644 tests/contentdb.scm

diff --git a/Makefile.am b/Makefile.am
index f6fae09579..b9265c154d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -261,6 +261,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/contentdb.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
   guix/import/pypi.scm				\
@@ -303,6 +304,7 @@ MODULES =					\
   guix/scripts/import/go.scm			\
   guix/scripts/import/hackage.scm		\
   guix/scripts/import/json.scm  		\
+  guix/scripts/import/contentdb.scm  		\
   guix/scripts/import/opam.scm			\
   guix/scripts/import/pypi.scm			\
   guix/scripts/import/stackage.scm		\
@@ -445,6 +447,7 @@ SCM_TESTS =					\
   tests/channels.scm				\
   tests/combinators.scm			\
   tests/containers.scm				\
+  tests/contentdb.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
   tests/cran.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 43c248234d..d06c9b73c5 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -11313,6 +11313,31 @@ and generate package expressions for all those packages that are not yet
 in Guix.
 @end table
 
+@item contentdb
+@cindex ContentDB
+Import metadata from @uref{https://content.minetest.net, ContentDB}.
+Information is taken from the JSON-formatted metadata provided through
+@uref{https://content.minetest.net/help/api/, ContentDB's API} and
+includes most relevant information, including dependencies.  There are
+some caveats, however.  The license information on ContentDB does not
+distinguish between GPLvN-only and GPLvN-or-later.  The commit id is
+sometimes missing.  The descriptions are in the Markdown format, but
+Guix uses Texinfo instead.  Texture packs and subgames are unsupported.
+
+The command below imports metadata for the Mesecons mod by Jeija:
+
+@example
+guix import contentdb Jeija mesecons
+@end example
+
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
 @item cpan
 @cindex CPAN
 Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}.
diff --git a/guix/import/contentdb.scm b/guix/import/contentdb.scm
new file mode 100644
index 0000000000..1a36a09c92
--- /dev/null
+++ b/guix/import/contentdb.scm
@@ -0,0 +1,310 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet;be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import contentdb)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 receive)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix utils)
+  #:use-module (guix memoization)
+  #:use-module (guix serialization)
+  #:use-module (guix import utils)
+  #:use-module (guix import json)
+  #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256))
+  #:use-module (json)
+  #:use-module (guix base32)
+  #:use-module (guix git)
+  #:use-module (guix store)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:export (%contentdb-api
+            contentdb->guix-package
+            contentdb-recursive-import))
+
+;; The ContentDB API is documented at
+;; <https://content.minetest.net>.
+
+(define %contentdb-api
+  (make-parameter "https://content.minetest.net/api/"))
+
+(define (string-or-false x)
+  (and (string? x) x))
+
+(define (natural-or-false x)
+  (and (exact-integer? x) (>= x 0) x))
+
+;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
+(define (delete-cr text)
+  (string-delete #\cr text))
+
+;; Minetest package.
+;;
+;; API endpoint: /packages/AUTHOR/NAME/
+(define-json-mapping <package> make-package package?
+  json->package
+  (author            package-author) ; string
+  (creation-date     package-creation-date ; string
+                     "created_at")
+  (downloads         package-downloads) ; integer
+  (forums            package-forums "forums" natural-or-false) ; natural | #f
+  (issue-tracker     package-issue-tracker "issue_tracker") ; string
+  (license           package-license) ; string
+  (long-description  package-long-description "long_description") ; string
+  (maintainers       package-maintainers ; list of strings
+                     "maintainers" vector->list)
+  (media-license     package-media-license "media_license") ; string
+  (name              package-name) ; string
+  (provides          package-provides ; list of strings
+                     "provides" vector->list)
+  (release           package-release) ; integer
+  (repository        package-repository "repo" string-or-false) ; string | #f
+  (score             package-score) ; flonum
+  (screenshots       package-screenshots "screenshots" vector->list) ; list of strings
+  (short-description package-short-description "short_description") ; string
+  (state             package-state) ; string
+  (tags              package-tags "tags" vector->list) ; list of strings
+  (thumbnail         package-thumbnail) ; string
+  (title             package-title) ; string
+  (type              package-type) ; string
+  (url               package-url) ; string
+  (website           package-website "website" string-or-false)) ; string | #f
+
+(define-json-mapping <release> make-release release?
+  json->release
+  (commit               release-commit "commit" string-or-false) ; string | #f
+  (downloads            release-downloads) ; integer
+  (id                   release-id) ; integer
+  (max-minetest-version release-max-minetest-version) ; string | #f
+  (min-minetest-version release-min-minetest-version) ; string | #f
+  (release-date         release-data) ; string
+  (title                release-title) ; string
+  (url                  release-url)) ; string
+
+(define-json-mapping <dependency> make-dependency dependency?
+  json->dependency
+  (optional? dependency-optional? "is_optional") ; #t | #f
+  (name dependency-name) ; string
+  (packages dependency-packages "packages" vector->list)) ; list of strings
+
+(define (contentdb-fetch author name)
+  "Return a <package> record for package NAME by AUTHOR, or #f on failure."
+  (and=> (json-fetch
+          (string-append (%contentdb-api) "packages/" author "/" name "/"))
+         json->package))
+
+(define (contentdb-fetch-releases author name)
+  "Return a list of <release> records for package NAME by AUTHOR, or #f
+on failure."
+  (and=> (json-fetch (string-append (%contentdb-api) "packages/" author "/" name
+                                    "/releases/"))
+         (lambda (json)
+           (map json->release (vector->list json)))))
+
+(define (latest-release author name)
+  "Return the latest source release for package NAME by AUTHOR,
+or #f if this package does not exist."
+  (and=> (contentdb-fetch-releases author name)
+         car))
+
+(define (contentdb-fetch-dependencies author name)
+  "Return an alist of lists of <dependency> records for package NAME by AUTHOR
+and possibly some other packages as well, or #f on failure."
+  (define url (string-append (%contentdb-api) "packages/" author "/" name
+                             "/dependencies/"))
+  (and=> (json-fetch url)
+         (lambda (json)
+           (map (match-lambda
+                  ((key . value)
+                   (cons key (map json->dependency (vector->list value)))))
+                json))))
+
+(define (contentdb->package-name name)
+  "Given the NAME of a package on ContentDB, return a Guix-compliant name for the
+package."
+  ;; The author is not included, as the names of popular mods
+  ;; tend to be unique.
+  (string-append "minetest-" (snake-case name)))
+
+;; XXX copied from (guix import elpa)
+(define* (download-git-repository url ref)
+  "Fetch the given REF from the Git repository at URL."
+  (with-store store
+    (latest-repository-commit store url #:ref ref)))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+;; XXX likewise.
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (make-minetest-sexp name version repository commit
+                            inputs home-page synopsis
+                            description media-license license)
+  "Return a S-expression for the minetest package with the given NAME,
+VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
+MEDIA-LICENSE and LICENSE."
+  `(package
+     (name ,(contentdb->package-name name))
+     (version ,version)
+     (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+                (url ,repository)
+                (commit ,commit)))
+         (sha256
+          (base32
+           ;; The commit id is not always available.
+           ,(and commit
+                 (bytevector->nix-base32-string
+                  (file-hash
+                   (download-git-repository repository `(commit . ,commit))
+                   (negate vcs-file?) #t)))))
+         (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs
+        (map (compose contentdb->package-name cdr) inputs))
+     (home-page ,home-page)
+     (synopsis ,(delete-cr synopsis))
+     (description ,(delete-cr description))
+     (license ,(if (eq? media-license license)
+                   (license->symbol license)
+                   `(list ,(license->symbol media-license)
+                          ,(license->symbol license))))))
+
+(define (package-home-page package)
+  "Guess the home page of the ContentDB package PACKAGE.
+
+In order of preference, try the 'website', the forum topic on the
+official Minetest forum and the Git repository (if any)."
+  (define (topic->url-sexp topic)
+    ;; 'minetest-topic' is a procedure defined in (gnu packages minetest)
+    `(minetest-topic ,topic))
+  (or (package-website package)
+      (and=> (package-forums package) topic->url-sexp)
+      (package-repository package)))
+
+(define (important-dependencies dependencies author name)
+  (define dependency-list
+    (assoc-ref dependencies (string-append author "/" name)))
+  (filter-map
+   (lambda (dependency)
+     (and (not (dependency-optional? dependency))
+          ;; "default" must be provided by the 'subgame' in use
+          ;; and does not refer to a specific minetest mod.
+          ;; "doors", "bucket" ... are provided by the default minetest
+          ;; subgame.
+          (not (member (dependency-name dependency)
+                       '("default" "doors" "beds" "bucket" "doors" "farming"
+                         "flowers" "stairs" "xpanes")))
+          ;; Dependencies often have only one implementation.
+          (let* ((/name (string-append "/" (dependency-name dependency)))
+                 (likewise-named-implementations
+                  (filter (cut string-suffix? /name <>)
+                          (dependency-packages dependency)))
+                 (implementation
+                  (and (not (null? likewise-named-implementations))
+                       (first likewise-named-implementations))))
+            (and implementation
+                 (apply cons (string-split implementation #\/))))))
+   dependency-list))
+
+(define* (%contentdb->guix-package author name)
+  "Fetch the metadata for NAME by AUTHOR from https://content.minetest.net, and
+return the 'package' S-expression corresponding to that package, or #f on failure.
+On success, also return the upstream dependencies as a list of
+(AUTHOR . NAME) pairs."
+  (and-let* ((package (contentdb-fetch author name))
+             (dependencies (contentdb-fetch-dependencies author name))
+             (release (latest-release author name)))
+    (let ((important-upstream-dependencies
+           (important-dependencies dependencies author name)))
+      (values (make-minetest-sexp name
+                                  (release-title release) ; version
+                                  (package-repository package)
+                                  (release-commit release)
+                                  important-upstream-dependencies
+                                  (package-home-page package)
+                                  (package-short-description package)
+                                  (package-long-description package)
+                                  (string->license
+                                   (package-media-license package))
+                                  (string->license
+                                   (package-license package)))
+              important-upstream-dependencies))))
+
+(define contentdb->guix-package
+  (memoize %contentdb->guix-package))
+
+(define (contentdb-recursive-import author name)
+  ;; recursive-import expects upstream package names to be strings,
+  ;; so do some conversions.
+  (define (split-author/name author/name)
+    (string-split author/name #\/))
+  (define (author+name->author/name author+name)
+    (string-append (car author+name) "/" (cdr author+name)))
+  (define* (contentdb->guix-package* author/name #:key repo version)
+    (receive (package . maybe-dependencies)
+        (apply contentdb->guix-package (split-author/name author/name))
+      (and package
+           (receive (dependencies)
+               (apply values maybe-dependencies)
+             (values package
+                     (map author+name->author/name dependencies))))))
+  (recursive-import (author+name->author/name (cons author name))
+                    #:repo->guix-package contentdb->guix-package*
+                    #:guix-name
+                    (lambda (author/name)
+                      (contentdb->package-name
+                       (second (split-author/name author/name))))))
+
+;; A list of license names is available at
+;; <https://content.minetest.net/api/licenses/>.
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GPLv3"        license:gpl3)
+    ("GPLv2"        license:gpl2)
+    ("ISC"          license:isc)
+    ;; "MIT" means the Expat license on ContentDB,
+    ;; see <https://github.com/minetest/contentdb/issues/326#issuecomment-890143784>.
+    ("MIT"          license:expat)
+    ("CC BY-SA 3.0" license:cc-by-sa3.0)
+    ("CC BY-SA 4.0" license:cc-by-sa4.0)
+    ("LGPLv2.1"     license:lgpl2.1)
+    ("LGPLv3"       license:lgpl3)
+    ("MPL 2.0"      license:mpl2.0)
+    ("ZLib"         license:zlib)
+    ("Unlicense"    license:unlicense)
+    (_ #f)))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f53d1ac1f4..015677e719 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,8 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
-                    "gem" "go" "cran" "crate" "texlive" "json" "opam"))
+                    "gem" "go" "cran" "crate" "texlive" "json" "opam"
+                    "contentdb"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/contentdb.scm b/guix/scripts/import/contentdb.scm
new file mode 100644
index 0000000000..4170fff950
--- /dev/null
+++ b/guix/scripts/import/contentdb.scm
@@ -0,0 +1,106 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import contentdb)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import contentdb)
+  #:use-module (guix import utils)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-contentdb))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import contentdb AUTHOR NAME
+Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import contentdb")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-contentdb . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((author name)
+       (with-error-handling
+         (if (assoc-ref opts 'recursive)
+             ;; Recursive import
+             (filter-map package->definition
+                         (contentdb-recursive-import author name))
+             ;; Single import
+             (let ((sexp (contentdb->guix-package author name)))
+               (unless sexp
+                 (leave (G_ "failed to download meta-data for package '~a' by '~a'~%")
+                        name author))
+               sexp))))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index a3bced1a8f..f25a7b4802 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -60,6 +60,7 @@ guix/scripts/git.scm
 guix/scripts/git/authenticate.scm
 guix/scripts/hash.scm
 guix/scripts/import.scm
+guix/scripts/import/contentdb.scm
 guix/scripts/import/cran.scm
 guix/scripts/import/elpa.scm
 guix/scripts/pull.scm
diff --git a/tests/contentdb.scm b/tests/contentdb.scm
new file mode 100644
index 0000000000..1293ac40cf
--- /dev/null
+++ b/tests/contentdb.scm
@@ -0,0 +1,227 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-contentdb)
+  #:use-module (guix memoization)
+  #:use-module (guix import contentdb)
+  #:use-module (guix import utils)
+  #:use-module (guix tests)
+  #:use-module (json)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-64))
+
+\f
+;; Some procedures for populating a ‘fake’ ContentDB server.
+
+(define* (make-package-sexp #:key
+                            (guix-name "minetest-foo")
+                            (home-page "https://example.org/foo")
+                            (repo "https://example.org/foo.git")
+                            (synopsis "synopsis")
+                            (guix-description "description")
+                            (guix-license '(list license:cc-by-sa4.0 license:lgpl3))
+                            (inputs '())
+                            #:allow-other-keys)
+  `(package
+     (name ,guix-name)
+     ;; This is not a proper version number but ContentDB does not include
+     ;; version numbers.
+     (version "2021-07-25")
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url ,(and (not (eq? repo 'null)) repo))
+              (commit #f)))
+        (sha256
+         (base32 #f))
+        (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs inputs)
+     (home-page ,home-page)
+     (synopsis ,synopsis)
+     (description ,guix-description)
+     (license ,guix-license)))
+
+(define* (make-package-json #:key
+                            (author "Author")
+                            (name "foo")
+                            (media-license "CC BY-SA 4.0")
+                            (license "LGPLv3")
+                            (short-description "synopsis")
+                            (long-description "description")
+                            (repo "https://example.org/foo.git")
+                            (website "https://example.org/foo")
+                            (forums 321)
+                            #:allow-other-keys)
+  `(("author" . ,author)
+    ("content_warnings" . #())
+    ("created_at" . "2018-05-23T19:58:07.422108")
+    ("downloads" . 123)
+    ("forums" . ,forums)
+    ("issue_tracker" . "https://example.org/foo/issues")
+    ("license" . ,license)
+    ("long_description" . ,long-description)
+    ("maintainers" . #("maintainer"))
+    ("media_license" . ,media-license)
+    ("name" . ,name)
+    ("provides" . #("stuff"))
+    ("release" . 456)
+    ("repo" . ,repo)
+    ("score" . ,987.654)
+    ("screenshots" . #())
+    ("short_description" . ,short-description)
+    ("state" . "APPROVED")
+    ("tags" . #("some" "tags"))
+    ("thumbnail" . null)
+    ("title" . "The name")
+    ("type" . "mod")
+    ("url" . ,(string-append "https://content.minetest.net/packages/"
+                             author "/" name "/download/"))
+    ("website" . ,website)))
+
+(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
+  `#((("commit" . ,commit)
+      ("downloads" . 469)
+      ("id" . 8614)
+      ("max_minetest_version" . null)
+      ("min_minetest_version" . null)
+      ("release_date" . "2021-07-25T01:10:23.207584")
+      ("title" . "2021-07-25"))))
+
+(define* (make-dependencies-json #:key (author "Author")
+                                 (name "foo")
+                                 (requirements '(("default" #f ())))
+                                 #:allow-other-keys)
+  `((,(string-append author "/" name)
+     . ,(list->vector
+         (map (match-lambda
+                ((symbolic-name optional? implementations)
+                 `(("is_optional" . ,optional?)
+                   ("name" . ,symbolic-name)
+                   ("packages" . ,(list->vector implementations)))))
+              requirements)))
+    ("something/else" . #())))
+
+(define (call-with-packages thunk . argument-lists)
+  (mock ((guix http-client) http-fetch
+         (lambda* (url #:key headers)
+           (unless (string-prefix? "mock://api/packages/" url)
+             (error "the URL ~a should not be used" url))
+           (define resource
+             (substring url (string-length "mock://api/packages/")))
+           (define components (string-split resource #\/))
+           (unless (>= (length components) 2)
+             (error "the URL ~a should have an author and name component" url))
+           (define requested-author (list-ref components 0))
+           (define requested-name (list-ref components 1))
+           (define rest (cddr components))
+           (define relevant-argument-list
+             (any (lambda (argument-list)
+                    (apply (lambda* (#:key (author "Author") (name "foo")
+                                     #:allow-other-keys)
+                             (and (equal? requested-author author)
+                                  (equal? requested-name name)
+                                  argument-list))
+                           argument-list))
+                  argument-lists))
+           (when (not relevant-argument-list)
+             (error "the package ~a/~a should be irrelevant, but ~a is fetched"
+                    requested-author requested-name url))
+           (define (scm->json-port scm)
+             (open-input-string (scm->json-string scm)))
+           (scm->json-port
+            (apply (match rest
+                     (("") make-package-json)
+                     (("dependencies" "") make-dependencies-json)
+                     (("releases" "") make-releases-json)
+                     (_ (error "TODO ~a" rest)))
+                   relevant-argument-list))))
+        (parameterize ((%contentdb-api "mock://api/"))
+          (thunk))))
+
+(define* (contentdb->guix-package* #:key (author "Author") (name "foo")
+                                   #:allow-other-keys)
+  (contentdb->guix-package author name))
+
+(define (imported-package-sexp . extra-arguments)
+  (call-with-packages
+   (lambda ()
+     ;; Don't reuse results from previous tests.
+     (invalidate-memoization! contentdb->guix-package)
+     (apply contentdb->guix-package* extra-arguments))
+   extra-arguments))
+
+(define-syntax-rule (test-package test-case . extra-arguments)
+  (test-equal test-case
+    (make-package-sexp . extra-arguments)
+    (imported-package-sexp . extra-arguments)))
+
+(test-begin "contentdb")
+
+\f
+;; Package names
+(test-package "contentdb->guix-package")
+(test-package "contentdb->guix-package, _ → - in package name"
+              #:name "foo_bar"
+              #:guix-name "minetest-foo-bar")
+
+\f
+;; Determining the home page
+(test-package "contentdb->guix-package, website is used as home page"
+              #:home-page "web://site"
+              #:website "web://site")
+(test-package "contentdb->guix-package, if absent, the forum is used"
+              #:home-page '(minetest-topic 628)
+              #:forums 628
+              #:website 'null)
+(test-package "contentdb->guix-package, if absent, the git repo is used"
+              #:home-page "https://github.com/minetest-mods/mesecons"
+              #:forums 'null
+              #:website 'null
+              #:repo "https://github.com/minetest-mods/mesecons")
+(test-package "contentdb->guix-package, all home page information absent"
+              #:home-page #f
+              #:forums 'null
+              #:website 'null
+              #:repo 'null)
+
+\f
+
+;; Dependencies
+(test-package "contentdb->guix-package, dependency"
+              #:requirements '(("mesecons" #f
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '("minetest-mesecons"))
+
+(test-package "contentdb->guix-package, optional dependency"
+              #:requirements '(("mesecons" #t
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '())
+
+\f
+;; License
+(test-package "contentdb->guix-package, identical licenses"
+              #:guix-license 'license:lgpl3
+              #:license "LGPLv3"
+              #:media-license "LGPLv3")
+
+(test-end "contentdb")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 07/20] gnu: Add minetest-mesecons.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (4 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 08/20] gnu: Add minetest-basic-materials Maxime Devos
                     ` (13 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-mesecons): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f8aca3005c..72e04c4b33 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -24,3 +24,38 @@
 numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
+
+(define-public minetest-mesecons
+  ;; The release on ContentDB does not have its own version number.
+  (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
+        (revision "0"))
+  (package
+    (name "minetest-mesecons")
+    (version (git-version "1.2.1" revision commit))
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/mesecons")
+             (commit commit)))
+       (sha256
+        (base32 "04m9s9l3frw1lgki41hgvjsw2zkrvfv0sy750b6j12arzb3lv645"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page "https://mesecons.net")
+    (synopsis
+     "Digital circuitry for Minetest, including wires, buttons and lights")
+    (description
+     "Mesecons is a mod for Minetest implementing various items related
+to digital circuitry, such as wires, buttons, lights and programmable
+controllers.  Among other things, there are also pistons, solar panels,
+pressure plates and note blocks.
+
+Mesecons has a similar goal to Redstone in Minecraft, but works in its own way,
+with different rules and mechanics.")
+    ;; LGPL for code, CC-BY-SA for textures.
+    ;; The README.md and COPYING.txt disagree about the "+" in license:lgpl3+.
+    ;; For now, assume README.md is correct.  Upstream has been asked to
+    ;; correct the inconsistency:
+    ;; <https://github.com/minetest-mods/mesecons/issues/575>.
+    (license (list license:lgpl3+ license:cc-by-sa3.0)))))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 08/20] gnu: Add minetest-basic-materials.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (5 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 07/20] gnu: Add minetest-mesecons Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 09/20] gnu: Add minetest-unifieddyes Maxime Devos
                     ` (12 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-basic-materials): New variable.
---
 gnu/packages/minetest.scm | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 72e04c4b33..a97065ad4c 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -25,6 +25,30 @@ numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
 
+(define-public minetest-basic-materials
+  (package
+    (name "minetest-basic-materials")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-01-30")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/basic_materials.git")
+             (commit "e72665b2ed98d7be115779a32d35e6d9ffa231bd")))
+       (sha256
+        (base32 "0v6l3lrjgshy4sccjhfhmfxc3gk0cdy73qb02i9wd2vw506v5asx"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 21000))
+    (synopsis "Some \"basic\" materials and items for other Minetest mods to use")
+    (description
+     "The Minetest mod \"basic_materials\" provides a small selection of
+\"basic\" materials and items that other mods should use when possible -- things
+like steel bars and chains, wire, plastic strips and sheets, and more.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 09/20] gnu: Add minetest-unifieddyes.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (6 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 08/20] gnu: Add minetest-basic-materials Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 10/20] gnu: Add minetest-pipeworks Maxime Devos
                     ` (11 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-unifieddyes): New variable.
---
 gnu/packages/minetest.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index a97065ad4c..b845e5a2b3 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -83,3 +83,31 @@ with different rules and mechanics.")
     ;; correct the inconsistency:
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0)))))
+
+(define-public minetest-unifieddyes
+  (package
+    (name "minetest-unifieddyes")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-20-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/unifieddyes")
+             (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
+       (sha256
+        (base32
+         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2178))
+    (synopsis
+     "Unified Dyes expands the standard dye set of Minetest to up to 256 colours")
+    (description "The purpose of this mod originally was to supply a complete
+set of colours for Minetest mod authors to use for colourised nodes or
+reference in recipes.  Since the advent of the default dyes mod in the standard
+Minetest game, this mod has become an extension of the default mod an a library
+for general colour handling.")
+    (license license:gpl2+)))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 10/20] gnu: Add minetest-pipeworks.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (7 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 09/20] gnu: Add minetest-unifieddyes Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 11/20] gnu: Add minetest-coloredwood Maxime Devos
                     ` (10 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-pipeworks): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index b845e5a2b3..a281eddea0 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -84,6 +84,36 @@ with different rules and mechanics.")
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0)))))
 
+(define-public minetest-pipeworks
+  (package
+    (name "minetest-pipeworks")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/pipeworks")
+             (commit "db6d1bd9c109e1e543b97cc3fa8a11400da23bcd")))
+       (sha256
+        (base32 "1flhcnf17dn1v86kcg47a1n4cb0lybd11ncxrkxn3wmf10ibsrm0"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2155))
+    (synopsis "Pipes, item-transport tubes and related devices for Minetest")
+    (description
+     "Pipeworks is a mod for Minetest implementing 3D pipes and tubes for
+transporting liquids and items and some related devices.  Pipes and tubes can
+go horizontally or vertically.  Item tubes can also be used for sorting items
+and extracting items from chests or putting items in chests.  Autocrafters can
+automatically follow craft recipes to make new items and can be fed by item
+tubes.  Deployers can place items in the world as a player would.  Node
+breakers simulate a player punching a node.")
+    ;; CC-BY-SA for textures, LGPL for code
+    (license (list license:cc-by-sa4.0 license:lgpl3))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 11/20] gnu: Add minetest-coloredwood.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (8 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 10/20] gnu: Add minetest-pipeworks Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 12/20] gnu: Add minetest-ethereal Maxime Devos
                     ` (9 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-coloredwood): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index a281eddea0..fd2e78ade8 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -49,6 +49,33 @@ like steel bars and chains, wire, plastic strips and sheets, and more.")
     (license
      (list license:cc-by-sa4.0 license:lgpl3))))
 
+(define-public minetest-coloredwood
+  (package
+    (name "minetest-coloredwood")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/coloredwood")
+             (commit "be4df6fc889419155bed8638bbb752493e78cbd5")))
+       (sha256
+        (base32 "1swirfk6b4xfbiwv8adyw5yl2lyfpp8ymfipzq9ivyvmif8nl3ki"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2411))
+    (synopsis "Painted wood in Minetest")
+    (description
+     "This Minetest mod provides hundreds of colours of wood and fences to
+Minetest, using Unified Dyes.  If the \"moreblocks\" mod is active,
+coloured and cut wood shapes are provided as well.")
+    (license
+     ;; LGPL for code, CC-BY-SA for textures
+     (list license:cc-by-sa4.0 license:lgpl3))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 12/20] gnu: Add minetest-ethereal.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (9 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 11/20] gnu: Add minetest-coloredwood Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 13/20] gnu: Add minetest-technic Maxime Devos
                     ` (8 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-ethereal): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index fd2e78ade8..12e15ee946 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -76,6 +76,34 @@ coloured and cut wood shapes are provided as well.")
      ;; LGPL for code, CC-BY-SA for textures
      (list license:cc-by-sa4.0 license:lgpl3))))
 
+(define-public minetest-ethereal
+  ;; ContentDB release 2021-07-28 is slightly ahead of the
+  ;; initial version 1.29 -- i.e., some released changes have been
+  ;; made to version 1.29 without a corresponding version bump.
+  (let ((commit "7670c1da9274901f57f6682384af2b3bae005a86")
+        (revision "0"))
+    (package
+      (name "minetest-ethereal")
+      (version (git-version "1.29" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://notabug.org/TenPlus1/ethereal")
+               (commit commit)))
+         (sha256
+          (base32 "1hal8bq4fydsip7s8rqz4vlaaqy9rhzxmryd0j2qnqm9286yjgkk"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 14638))
+      (synopsis "The Ethereal mod adds many new biomes to Minetest")
+      (description
+       "The Ethereal Minetest mod uses the v7 map generator to add many new
+biomes to the world.  It adds new trees, plants, food items, tweaks and some
+special items, intending to make an interesting adventure.")
+      ;; CC0: some textures
+      (license (list license:cc0 license:expat)))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
@@ -153,8 +181,7 @@ breakers simulate a player punching a node.")
              (url "https://gitlab.com/VanessaE/unifieddyes")
              (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
        (sha256
-        (base32
-         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+        (base32 "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
        (file-name (git-file-name name version))))
     (build-system minetest-mod-build-system)
     (propagated-inputs
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 13/20] gnu: Add minetest-technic.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (10 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 12/20] gnu: Add minetest-ethereal Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 14/20] gnu: Add minetest-throwing Maxime Devos
                     ` (7 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-technic): New variable.
---
 gnu/packages/minetest.scm | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 12e15ee946..c901c5fcc7 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -169,6 +169,40 @@ breakers simulate a player punching a node.")
     ;; CC-BY-SA for textures, LGPL for code
     (license (list license:cc-by-sa4.0 license:lgpl3))))
 
+(define-public minetest-technic
+  (package
+    (name "minetest-technic")
+    ;; Upstream doesn't keep version numbers, so use the release
+    ;; date on ContentDB instead.
+    (version "2021-04-15")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/technic")
+             (commit "1c219487d3f4dd03c01ff9aa1f298c7c18c7e189")))
+       (sha256
+        (base32 "1k9hdgzp7jnhsk6rgrlrv1lr5xrmh8ln4wv6r25v6f0fwbyj57sf"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-pipeworks" ,minetest-pipeworks)
+       ("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2538))
+    (synopsis "Machinery and automation for Minetest")
+    (description
+     "This Minetest mod adds machinery and automation to Minetest.
+It adds various ores that can be processed for constructing various
+machinery, such as power generators, force field emitters, quarries
+and a workshop for repairing tools.  Most machines are electrically
+powered.")
+    ;; CC BY-SA 3.0: some texture
+    ;; WTFPL: some textures
+    ;; CC BY-SA3.0: some textures
+    ;; CC BY-SA4.0: some sounds
+    (license (list license:lgpl2.1+ license:cc-by-sa3.0 license:cc-by-sa4.0
+                   license:wtfpl2))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 14/20] gnu: Add minetest-throwing.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (11 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 13/20] gnu: Add minetest-technic Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
                     ` (6 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-throwing): New variable.
---
 gnu/packages/minetest.scm | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index c901c5fcc7..25038a5f6b 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -203,6 +203,28 @@ powered.")
     (license (list license:lgpl2.1+ license:cc-by-sa3.0 license:cc-by-sa4.0
                    license:wtfpl2))))
 
+(define-public minetest-throwing
+  (package
+    (name "minetest-throwing")
+    (version "2020-08-14")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/throwing")
+             (commit "31f0cf5f868673dc82f24ddc432b45c9cd282d27")))
+       (sha256
+        (base32 "1s5kkr6rxxv2dhbbjzv62gw1s617hnpjavw1v9fv11v3mgigdfjb"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 16365))
+    (synopsis "API for throwing things in Minetest")
+    (description
+     "This Minetest mod provides an API for registering throwable things and
+throwing things like arrows.  However, this mod does not provide an actual
+arrow and bow, but @code{minetest-throwing-arrows} does.")
+    (license license:mpl2.0)))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 15/20] gnu: Add minetest-throwing-arrows.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (12 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 14/20] gnu: Add minetest-throwing Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 16/20] gnu: Add minetest-unified-inventory Maxime Devos
                     ` (5 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm
  (minetest-throwing-arrows): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 25038a5f6b..6b792bf071 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -225,6 +225,36 @@ throwing things like arrows.  However, this mod does not provide an actual
 arrow and bow, but @code{minetest-throwing-arrows} does.")
     (license license:mpl2.0)))
 
+(define-public minetest-throwing-arrows
+  ;; There is only one tagged commit (version 1.1),
+  ;; there are no releases on ContentDB and the latest
+  ;; commit has a compatibility fix for Minetest 5.4.0-dev.
+  (let ((commit "059cc897af0aebfbd2c54ac5588f2b842f44f159")
+        (revision "0"))
+    (package
+      (name "minetest-throwing-arrows")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing_arrows")
+               (commit commit)))
+         (sha256
+          (base32 "0m2pmccpfxn878zd00pmrpga2h6gknz4f3qprck0fq94mksmwqs3"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (propagated-inputs
+       `(("minetest-throwing" ,minetest-throwing)))
+      (home-page (minetest-topic 16365))
+      (synopsis "Arrows and bows for Minetest")
+      (description
+       ;; TRANSLATORS: "throwing" is the name of a Minetest mod and should
+       ;; not be translated.
+       "This mod adds arrows and bows to Minetest.  It is a compatible
+replacement for the throwing mod by PilzAdam that uses the throwing API.")
+      (license license:mpl2.0))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 16/20] gnu: Add minetest-unified-inventory.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (13 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 17/20] gnu: Add minetest-worldedit Maxime Devos
                     ` (4 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm
  (minetest-unified-inventory): New variable.
---
 gnu/packages/minetest.scm | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 6b792bf071..2c028e3e87 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -281,3 +281,37 @@ reference in recipes.  Since the advent of the default dyes mod in the standard
 Minetest game, this mod has become an extension of the default mod an a library
 for general colour handling.")
     (license license:gpl2+)))
+
+(define-public minetest-unified-inventory
+  (package
+    (name "minetest-unified-inventory")
+    ;; Upstream doesn't keep version numbers, so use the release title
+    ;; on ContentDB instead.
+    (version "2021-03-25-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/unified_inventory")
+             (commit "c044f5e3b08f0c68ab028d757b2fa63d9a1b0370")))
+       (sha256
+        (base32 "198g945gzbfl0kps46gwjw0c601l3b3wvn4c7dw8manskri1jr4g"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 12767))
+    (synopsis "Replace the default inventory in Minetest and add a crafting guide")
+    (description
+     "The Unified Inventory Minetest mod relaces the default survival an
+creative inventory.  It includes a node, item and tool browser, a crafting
+guide, a trash and refill slot for creative mode, bags and waypoints for keeping
+track of important locations.")
+    ;; CC-BY: some textures and icons
+    ;; CC-BY-SA: some textures and icons
+    ;; LGLPL2.1+: code and some textures
+    ;; GPL2+: some textures
+    ;; GPL3: bags.lua
+    ;; GFDL: some icons
+    ;; public domain, CC0: some icons
+    (license (list license:gpl3 license:gpl2+ license:lgpl2.1+ license:cc-by3.0
+                   license:cc-by4.0 license:cc-by-sa3.0 license:public-domain
+                   license:cc0 license:fdl1.2+))))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 17/20] gnu: Add minetest-worldedit.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (14 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 16/20] gnu: Add minetest-unified-inventory Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 18/20] gnu: Add minetest-mobs Maxime Devos
                     ` (3 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-worldedit): New variable.
---
 gnu/packages/minetest.scm | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 2c028e3e87..0e16743823 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -255,6 +255,28 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
 replacement for the throwing mod by PilzAdam that uses the throwing API.")
       (license license:mpl2.0))))
 
+(define-public minetest-worldedit
+  (package
+    (name "minetest-worldedit")
+    (version "1.3")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/Uberi/Minetest-WorldEdit")
+             (commit "2f26fb76459c587868199160b9d7b5d6d7852e50")))
+       (sha256
+        (base32 "0lsvihkixi2na1b0vmml9vwgs0g24hqqshl73ffhkzh6jsq4cagq"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 572))
+    (synopsis "In-game world editor for Minetest")
+    (description
+     "WorldEdit is a mod for Minetest.  It allows for creating various
+geometric shapes and copying regions.  It can also export and import regions
+to and from the file system.")
+    (license license:agpl3)))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 18/20] gnu: Add minetest-mobs.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (15 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 17/20] gnu: Add minetest-worldedit Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 19/20] gnu: Add minetest-mobs-animal Maxime Devos
                     ` (2 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-mobs): New variable.
---
 gnu/packages/minetest.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 0e16743823..4910fa72bb 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -139,6 +139,34 @@ with different rules and mechanics.")
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0)))))
 
+(define-public minetest-mobs
+  (package
+    (name "minetest-mobs")
+    ;; Upstream does not tag release, so use the ContentDB release
+    ;; title instead.
+    (version "2021-07-22")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_redo")
+             (commit "9f46182bb4b1a390f9a140bc2b443f3cda702332")))
+       (sha256
+        (base32 "026kqjis4lipgskjivb3jh9ris3iz80vy2q1jvgxhxmfghjjzp4j"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 9917))
+    (synopsis "Mob library for Minetest mods, for animals, monsters etc.")
+    (description
+     "This Minetest mod provides an API for adding mods (moving entities
+like animals and monsters), but does not include any mobs itself.  To actually
+add some mobs, a mod like e.g. @code{mobs_animal} provided by the
+@code{minetest-mobs-animal} package needs to be enabled.")
+    ;; CC0: mob_swing.ogg
+    ;; CC-BY 3.0: mob_spell.ogg
+    ;; Expat: everything else
+    (license (list license:expat license:cc0 license:cc-by3.0))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 19/20] gnu: Add minetest-mobs-animal.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (16 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 18/20] gnu: Add minetest-mobs Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 15:50   ` [bug#49828] [PATCH 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
  2021-08-02 17:14   ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Leo Prikler
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm (minetest-mobs-animal): New variable.
---
 gnu/packages/minetest.scm | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4910fa72bb..fcc3648795 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -167,6 +167,32 @@ add some mobs, a mod like e.g. @code{mobs_animal} provided by the
     ;; Expat: everything else
     (license (list license:expat license:cc0 license:cc-by3.0))))
 
+(define-public minetest-mobs-animal
+  (package
+    (name "minetest-mobs-animal")
+    ;; Upstream does not use version numbers, so use the release title
+    ;; from ContentDB instead;
+    (version "2021-07-24")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_animal")
+             (commit "c2fa3e300c79c7dd80b6fe91a8b5082bb6b3d934")))
+       (sha256
+        (base32 "1j719f079ia9vjxrmjrcj8s6jvaz5kgs1r4dh66z8ql6s70kx7vh"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-mobs" ,minetest-mobs)))
+    (home-page "https://notabug.org/TenPlus1/mobs_animal")
+    (synopsis "Add animals to Minetest")
+    (description
+     "This Minetest mod adds various animals to Minetest, such as bees,
+bunnies, chickens, cows, kittens, rats, sheep, warthogs, penguins and pandas.")
+    ;; CC0: some textures and sounds
+    (license (list license:cc0 license:expat))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 20/20] gnu: Add minetest-homedecor-modpack.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (17 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 19/20] gnu: Add minetest-mobs-animal Maxime Devos
@ 2021-08-02 15:50   ` Maxime Devos
  2021-08-02 17:14   ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Leo Prikler
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 15:50 UTC (permalink / raw)
  To: 49828; +Cc: Maxime Devos

* gnu/packages/minetest.scm
  (minetest-homedecor-modpack): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index fcc3648795..7c483acd0c 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -104,6 +104,36 @@ special items, intending to make an interesting adventure.")
       ;; CC0: some textures
       (license (list license:cc0 license:expat)))))
 
+(define-public minetest-homedecor-modpack
+  (package
+    (name "minetest-homedecor-modpack")
+    ;; Upstream doesn't tag releases, so use the release title from
+    ;; ContentDB as version.
+    (version "2021-03-27-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/homedecor_modpack")
+             (commit "9ffe2b7d691133e1a067546574fbe7364fd02f32")))
+       (sha256
+        (base32 "1lfajqvc2adf9hqskghky4arccqzpjw4i9a01hv4qcckvivm04ag"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)
+       ("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2041))
+    (synopsis "Home decor mod for Minetest")
+    (description
+     ;; TRANSLATORS: ‘homedecor’ is the name is the name of a Minetest mod
+     ;; and should not be translated.
+     "The homedecor Minetest mod provides a large seleection of items that
+might be found inside and around homes, such as sofas, chairs, tables, fences
+and a variety of other stuff.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests.
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                     ` (18 preceding siblings ...)
  2021-08-02 15:50   ` [bug#49828] [PATCH 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
@ 2021-08-02 17:14   ` Leo Prikler
  2021-08-02 17:18     ` Maxime Devos
  19 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-02 17:14 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi Maxime,

Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> * gnu/packages/games.scm
>   (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
>   of ',(%current-target-system)'. Remove trailing #t.
For context, (%current-target-system) is used because tests only work
in native builds.  If this can't be reflected in the value of tests?,
we should have both checks, imo.
> ---
>  gnu/packages/games.scm | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
> index 8c6b5523f1..3e7086b398 100644
> --- a/gnu/packages/games.scm
> +++ b/gnu/packages/games.scm
> @@ -3590,13 +3590,12 @@ match, cannon keep, and grave-itation pit.")
>                       (string-append (getcwd) "/games")) ; for check
>               #t))
>           (replace 'check
> -           (lambda _
> +           (lambda* (#:key tests? #:allow-other-keys)
>               ;; Thanks to our substitutions, the tests should also
> run
>               ;; when invoked on the target outside of `guix build'.
> -             (unless ,(%current-target-system)
> +             (when tests?
>                 (setenv "HOME" "/tmp")
> -               (invoke "src/minetest" "--run-unittests"))
> -             #t)))))
> +               (invoke "src/minetest" "--run-unittests")))))))
>      (native-search-paths
>       (list (search-path-specification
>              (variable "MINETEST_SUBGAME_PATH")





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests.
  2021-08-02 17:14   ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Leo Prikler
@ 2021-08-02 17:18     ` Maxime Devos
  2021-08-02 17:22       ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 17:18 UTC (permalink / raw)
  To: Leo Prikler, 49828

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

Leo Prikler schreef op ma 02-08-2021 om 19:14 [+0200]:
> Hi Maxime,
> 
> Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> > * gnu/packages/games.scm
> >   (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
> >   of ',(%current-target-system)'. Remove trailing #t.
> For context, (%current-target-system) is used because tests only work
> in native builds.  If this can't be reflected in the value of tests?,
> we should have both checks, imo.

'cmake-cross-build' sets '#:tests?' to #f by default, so I don't think
both checks are needed.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests.
  2021-08-02 17:18     ` Maxime Devos
@ 2021-08-02 17:22       ` Leo Prikler
  0 siblings, 0 replies; 71+ messages in thread
From: Leo Prikler @ 2021-08-02 17:22 UTC (permalink / raw)
  To: Maxime Devos, 49828

Am Montag, den 02.08.2021, 19:18 +0200 schrieb Maxime Devos:
> Leo Prikler schreef op ma 02-08-2021 om 19:14 [+0200]:
> > Hi Maxime,
> > 
> > Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> > > * gnu/packages/games.scm
> > >   (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
> > >   of ',(%current-target-system)'. Remove trailing #t.
> > For context, (%current-target-system) is used because tests only
> > work in native builds.  If this can't be reflected in the value of
> > tests?, we should have both checks, imo.
> 
> 'cmake-cross-build' sets '#:tests?' to #f by default, so I don't
> think both checks are needed.
In that case nvm and thanks for clearing that up :)





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-02 15:50   ` [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
@ 2021-08-02 17:28     ` Leo Prikler
  2021-08-02 17:53       ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-02 17:28 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi Maxime,

Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> * gnu/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch:
>   New file.
> * gnu/packages/games.scm
>   (minetest)[source]{patches}: Add it.
>   (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
> * gnu/local.mk (dist_patch_DATA): Add the patch.
> ---
>  gnu/local.mk                                  |   1 +
>  gnu/packages/games.scm                        |   7 +-
>  ...vironment-variable-MINETEST_MOD_PATH.patch | 115
> ++++++++++++++++++
>  3 files changed, 122 insertions(+), 1 deletion(-)
>  create mode 100644 gnu/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch
> 
> diff --git a/gnu/local.mk b/gnu/local.mk
> index c80a9af78c..d96d4e3dbc 100644
> --- a/gnu/local.mk
> +++ b/gnu/local.mk
> @@ -801,6 +801,7 @@ dist_patch_DATA =					
> 	\
>    %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
>    %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
>    %D%/packages/patches/adb-add-libraries.patch			
> \
> +  %D%/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch	\
>    %D%/packages/patches/aegis-constness-error.patch         	\
>    %D%/packages/patches/aegis-perl-tempdir1.patch           	\
>    %D%/packages/patches/aegis-perl-tempdir2.patch           	\
> diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
> index 3e7086b398..2f3285c6ea 100644
> --- a/gnu/packages/games.scm
> +++ b/gnu/packages/games.scm
> @@ -3553,6 +3553,7 @@ match, cannon keep, and grave-itation pit.")
>                 (base32
>                  "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb
> 8"))
>                (modules '((guix build utils)))
> +              (patches (search-patches "Add-environment-variable-
> MINETEST_MOD_PATH.patch"))
>                (snippet
>                 '(begin
>                    ;; Delete bundled libraries.
> @@ -3599,7 +3600,11 @@ match, cannon keep, and grave-itation pit.")
>      (native-search-paths
>       (list (search-path-specification
>              (variable "MINETEST_SUBGAME_PATH")
> -            (files '("share/minetest/games")))))
> +            (files '("share/minetest/games")))
> +           (search-path-specification
> +            (variable "MINETEST_MOD_PATH")
> +            (files '("share/minetest/mods"))
> +            (separator #f))))
>      (native-inputs
>       `(("pkg-config" ,pkg-config)))
>      (inputs
> diff --git a/gnu/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-
> variable-MINETEST_MOD_PATH.patch
> new file mode 100644
> index 0000000000..8478a7bf72
> --- /dev/null
> +++ b/gnu/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch
> @@ -0,0 +1,115 @@
> +From 6eb753c5bf67764890856cf23a67c0bf65973c16 Mon Sep 17 00:00:00
> 2001
> +From: Maxime Devos <maximedevos@telenet.be>
> +Date: Thu, 29 Jul 2021 22:24:50 +0200
> +Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
> +
> +This adds an environment variable MINETEST_MOD_PATH.
> +When it exists, Minetest will look there for mods
> +in addition to ~/.minetest/mods/.
> +
> +This patch as-is is not yet ready for upstream, because:
> +
> +  * the GUI will only display mods in MINETEST_MOD_PATH
> +    or mods in ~/.minetest/mods, it won't combine the two
> +
> +  * the GUI for installing mods from ContentDB is disabled
> +    when MINETEST_MOD_PATH is set, because otherwise Minetest
> +    would try to install mods in the store.
These two are fine for a "Guix-only" patch, although I do think we
should still read ~/.minetest/mods for backwards compatibility.

> +  * MINETEST_MOD_PATH can only have a single component
This one seems kinda arbitrary, though, and does not fit well with
MINETEST_SUBGAME_PATH.

> +---
> + builtin/mainmenu/dlg_contentstore.lua |  7 +++++++
> + src/content/subgames.cpp              |  3 +++
> + src/script/lua_api/l_mainmenu.cpp     | 14 +++++++++++++-
> + src/script/lua_api/l_mainmenu.h       |  2 ++
> + 4 files changed, 25 insertions(+), 1 deletion(-)
> +
> +diff --git a/builtin/mainmenu/dlg_contentstore.lua
> b/builtin/mainmenu/dlg_contentstore.lua
> +index 7096c9187..c4a2cbd18 100644
> +--- a/builtin/mainmenu/dlg_contentstore.lua
> ++++ b/builtin/mainmenu/dlg_contentstore.lua
> +@@ -22,6 +22,13 @@ if not core.get_http_api then
> + 	end
> + 	return
> + end
> ++if core.mod_path_set() then
> ++	function create_store_dlg()
> ++		return messagebox("store",
> ++				fgettext("Mods from ContentDB cannot be
> installed when mods from Guix are also installed"))
> ++	end
> ++	return
> ++end
> + 
> + -- Unordered preserves the original order of the ContentDB API,
> + -- before the package list is ordered based on installed state.
> +diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
> +index e9dc609b0..1809f189e 100644
> +--- a/src/content/subgames.cpp
> ++++ b/src/content/subgames.cpp
> +@@ -110,6 +110,9 @@ SubgameSpec findSubgame(const std::string &id)
> + 	std::set<std::string> mods_paths;
> + 	if (!user_game)
> + 		mods_paths.insert(share + DIR_DELIM + "mods");
> ++	const char *env_mod_path = getenv("MINETEST_MOD_PATH");
> ++	if (env_mod_path)
> ++		mods_paths.insert(std::string(env_mod_path));
Here, I would instead use an std::istringstream together with
std::getline(<>, <>, ':') to get the components of MINETEST_MOD_PATH
and insert each of them.  Either that or copy whatever is used for
MINETEST_SUBGAME_PATH.
> + 	if (user != share || user_game)
> + 		mods_paths.insert(user + DIR_DELIM + "mods");
> + 
> +diff --git a/src/script/lua_api/l_mainmenu.cpp
> b/src/script/lua_api/l_mainmenu.cpp
> +index ad00de1c4..737550c42 100644
> +--- a/src/script/lua_api/l_mainmenu.cpp
> ++++ b/src/script/lua_api/l_mainmenu.cpp
> +@@ -495,9 +495,19 @@ int ModApiMainMenu::l_get_user_path(lua_State
> *L)
> +
> /********************************************************************
> **********/
> + int ModApiMainMenu::l_get_modpath(lua_State *L)
> + {
> ++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
> + 	std::string modpath = fs::RemoveRelativePathComponents(
> + 		porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
> +-	lua_pushstring(L, modpath.c_str());
> ++	if (c_modpath == NULL)
> ++		c_modpath = modpath.c_str();
> ++	lua_pushstring(L, c_modpath);
> ++	return 1;
> ++}
> ++
> ++/******************************************************************
> ************/
> ++int ModApiMainMenu::l_mod_path_set(lua_State *L)
> ++{
> ++	lua_pushboolean(L, NULL != getenv("MINETEST_MOD_PATH"));
> + 	return 1;
> + }
> + 
> +@@ -855,6 +865,7 @@ void ModApiMainMenu::Initialize(lua_State *L,
> int top)
> + 	API_FCT(get_mapgen_names);
> + 	API_FCT(get_user_path);
> + 	API_FCT(get_modpath);
> ++	API_FCT(mod_path_set);
> + 	API_FCT(get_clientmodpath);
> + 	API_FCT(get_gamepath);
> + 	API_FCT(get_texturepath);
> +@@ -888,6 +899,7 @@ void ModApiMainMenu::InitializeAsync(lua_State
> *L, int top)
> + 	API_FCT(get_mapgen_names);
> + 	API_FCT(get_user_path);
> + 	API_FCT(get_modpath);
> ++	API_FCT(mod_path_set);
> + 	API_FCT(get_clientmodpath);
> + 	API_FCT(get_gamepath);
> + 	API_FCT(get_texturepath);
> +diff --git a/src/script/lua_api/l_mainmenu.h
> b/src/script/lua_api/l_mainmenu.h
> +index ec2d20da2..719c26077 100644
> +--- a/src/script/lua_api/l_mainmenu.h
> ++++ b/src/script/lua_api/l_mainmenu.h
> +@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
> + 
> + 	static int l_get_modpath(lua_State *L);
> + 
> ++	static int l_mod_path_set(lua_State *L);
> ++
> + 	static int l_get_clientmodpath(lua_State *L);
> + 
> + 	static int l_get_gamepath(lua_State *L);
> +-- 
> +2.32.0
What are these modpaths used for?  For mod installation or for querying
mod existence?  If it's the former, you could leave them as-is, similar
to how elpa stays enabled in Emacs.

Regards,





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-02 17:28     ` Leo Prikler
@ 2021-08-02 17:53       ` Maxime Devos
  2021-08-02 18:47         ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-02 17:53 UTC (permalink / raw)
  To: Leo Prikler, 49828

[-- Attachment #1: Type: text/plain, Size: 5078 bytes --]

> > +This patch as-is is not yet ready for upstream, because:
> > +
> > +  * the GUI will only display mods in MINETEST_MOD_PATH
> > +    or mods in ~/.minetest/mods, it won't combine the two
> > +
> > +  * the GUI for installing mods from ContentDB is disabled
> > +    when MINETEST_MOD_PATH is set, because otherwise Minetest
> > +    would try to install mods in the store.
> These two are fine for a "Guix-only" patch, although I do think we
> should still read ~/.minetest/mods for backwards compatibility.

~/.minetest/mods is still read when MINETEST_MOD_PATH is unset.
MINETEST_MOD_PATH is only set when some mod is actually installed.
So backwards compatibility should be ok.

> > +  * MINETEST_MOD_PATH can only have a single component
> This one seems kinda arbitrary, though, and does not fit well with
> MINETEST_SUBGAME_PATH.

Yes, I know.  I didn't know how to adjust pkgmgr.lua and dlg_contentstore.lua
to support multiple components, though I have an idea now to try.

> > + -- Unordered preserves the original order of the ContentDB API,
> > + -- before the package list is ordered based on installed state.
> > +diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
> > +index e9dc609b0..1809f189e 100644
> > +--- a/src/content/subgames.cpp
> > ++++ b/src/content/subgames.cpp
> > +@@ -110,6 +110,9 @@ SubgameSpec findSubgame(const std::string &id)
> > + 	std::set<std::string> mods_paths;
> > + 	if (!user_game)
> > + 		mods_paths.insert(share + DIR_DELIM + "mods");
> > ++	const char *env_mod_path = getenv("MINETEST_MOD_PATH");
> > ++	if (env_mod_path)
> > ++		mods_paths.insert(std::string(env_mod_path));

> Here, I would instead use an std::istringstream together with
> std::getline(<>, <>, ':') to get the components of MINETEST_MOD_PATH
> and insert each of them.  Either that or copy whatever is used for
> MINETEST_SUBGAME_PATH.

Minetest has a class 'Strfnd' supporting iteration.  Using that,
it should be easy to allow MINETEST_MOD_PATH to contain ":" seperators.
However, the GUI client code (pkgmgr.lua)
uses some other logic for determining which mods exists, and currently,
that logic does not support ":" separators.

> > +diff --git a/src/script/lua_api/l_mainmenu.cpp
> > b/src/script/lua_api/l_mainmenu.cpp
> > +index ad00de1c4..737550c42 100644
> > +--- a/src/script/lua_api/l_mainmenu.cpp
> > ++++ b/src/script/lua_api/l_mainmenu.cpp
> > +@@ -495,9 +495,19 @@ int ModApiMainMenu::l_get_user_path(lua_State
> > *L)
> > +
> > /********************************************************************
> > **********/
> > + int ModApiMainMenu::l_get_modpath(lua_State *L)
> > + {
> > ++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
> > + 	std::string modpath = fs::RemoveRelativePathComponents(
> > + 		porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
> > +-	lua_pushstring(L, modpath.c_str());
> > ++	if (c_modpath == NULL)
> > ++		c_modpath = modpath.c_str();
> > ++	lua_pushstring(L, c_modpath);
> > ++	return 1;
> > ++}
> > ++
> > ++/******************************************************************
> > ************/
> > ++int ModApiMainMenu::l_mod_path_set(lua_State *L)
> > ++{
> > ++	lua_pushboolean(L, NULL != getenv("MINETEST_MOD_PATH"));
> > + 	return 1;
> > + }
> > + 
> > +@@ -855,6 +865,7 @@ void ModApiMainMenu::Initialize(lua_State *L,
> > int top)
> > + 	API_FCT(get_mapgen_names);
> > + 	API_FCT(get_user_path);
> > + 	API_FCT(get_modpath);
> > ++	API_FCT(mod_path_set);
> > + 	API_FCT(get_clientmodpath);
> > + 	API_FCT(get_gamepath);
> > + 	API_FCT(get_texturepath);
> > +@@ -888,6 +899,7 @@ void ModApiMainMenu::InitializeAsync(lua_State
> > *L, int top)
> > + 	API_FCT(get_mapgen_names);
> > + 	API_FCT(get_user_path);
> > + 	API_FCT(get_modpath);
> > ++	API_FCT(mod_path_set);
> > + 	API_FCT(get_clientmodpath);
> > + 	API_FCT(get_gamepath);
> > + 	API_FCT(get_texturepath);
> > +diff --git a/src/script/lua_api/l_mainmenu.h
> > b/src/script/lua_api/l_mainmenu.h
> > +index ec2d20da2..719c26077 100644
> > +--- a/src/script/lua_api/l_mainmenu.h
> > ++++ b/src/script/lua_api/l_mainmenu.h
> > +@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
> > + 
> > + 	static int l_get_modpath(lua_State *L);
> > + 
> > ++	static int l_mod_path_set(lua_State *L);
> > ++
> > + 	static int l_get_clientmodpath(lua_State *L);
> > + 
> > + 	static int l_get_gamepath(lua_State *L);
> > +-- 
> > +2.32.0

> What are these modpaths used for?  For mod installation or for querying
> mod existence?  If it's the former, you could leave them as-is, similar
> to how elpa stays enabled in Emacs.

It is only used by the GUI.  The GUI looks in the directory returned by
"get_modpath" for two things:

(1) to determine which mods exist (and to find their descriptions, their
    dependency list, screenshots ...).  Only the mods that exist there
    can be enabled.

(2) to determine where mods must be installed when using Minetest's
    built-in installer.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-02 17:53       ` Maxime Devos
@ 2021-08-02 18:47         ` Leo Prikler
  2021-08-03 11:09           ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-02 18:47 UTC (permalink / raw)
  To: Maxime Devos, 49828

Am Montag, den 02.08.2021, 19:53 +0200 schrieb Maxime Devos:
> > > +This patch as-is is not yet ready for upstream, because:
> > > +
> > > +  * the GUI will only display mods in MINETEST_MOD_PATH
> > > +    or mods in ~/.minetest/mods, it won't combine the two
> > > +
> > > +  * the GUI for installing mods from ContentDB is disabled
> > > +    when MINETEST_MOD_PATH is set, because otherwise Minetest
> > > +    would try to install mods in the store.
> > These two are fine for a "Guix-only" patch, although I do think we
> > should still read ~/.minetest/mods for backwards compatibility.
> 
> ~/.minetest/mods is still read when MINETEST_MOD_PATH is unset.
> MINETEST_MOD_PATH is only set when some mod is actually installed.
> So backwards compatibility should be ok.
I mean in the sense of "have some mods in ~/.minetest/mods, that aren't
yet packaged in Guix and have the rest sit in the profile where they
belong".  Not everyone will like the the import to manifest approach
that is needed while you're waiting for review.
> > > +  * MINETEST_MOD_PATH can only have a single component
> > This one seems kinda arbitrary, though, and does not fit well with
> > MINETEST_SUBGAME_PATH.
> 
> Yes, I know.  I didn't know how to adjust pkgmgr.lua and
> dlg_contentstore.lua
> to support multiple components, though I have an idea now to try.
> 
> > > + -- Unordered preserves the original order of the ContentDB API,
> > > + -- before the package list is ordered based on installed state.
> > > +diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
> > > +index e9dc609b0..1809f189e 100644
> > > +--- a/src/content/subgames.cpp
> > > ++++ b/src/content/subgames.cpp
> > > +@@ -110,6 +110,9 @@ SubgameSpec findSubgame(const std::string
> > > &id)
> > > + 	std::set<std::string> mods_paths;
> > > + 	if (!user_game)
> > > + 		mods_paths.insert(share + DIR_DELIM + "mods");
> > > ++	const char *env_mod_path = getenv("MINETEST_MOD_PATH");
> > > ++	if (env_mod_path)
> > > ++		mods_paths.insert(std::string(env_mod_path));
> > Here, I would instead use an std::istringstream together with
> > std::getline(<>, <>, ':') to get the components of
> > MINETEST_MOD_PATH
> > and insert each of them.  Either that or copy whatever is used for
> > MINETEST_SUBGAME_PATH.
> 
> Minetest has a class 'Strfnd' supporting iteration.  Using that,
> it should be easy to allow MINETEST_MOD_PATH to contain ":"
> seperators.
> However, the GUI client code (pkgmgr.lua)
> uses some other logic for determining which mods exists, and
> currently,
> that logic does not support ":" separators.
Hmm, how important is the GUI side here?  Can we sneek mods into it?

> > > +diff --git a/src/script/lua_api/l_mainmenu.cpp
> > > b/src/script/lua_api/l_mainmenu.cpp
> > > +index ad00de1c4..737550c42 100644
> > > +--- a/src/script/lua_api/l_mainmenu.cpp
> > > ++++ b/src/script/lua_api/l_mainmenu.cpp
> > > +@@ -495,9 +495,19 @@ int
> > > ModApiMainMenu::l_get_user_path(lua_State
> > > *L)
> > > +
> > > /****************************************************************
> > > ****
> > > **********/
> > > + int ModApiMainMenu::l_get_modpath(lua_State *L)
> > > + {
> > > ++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
> > > + 	std::string modpath = fs::RemoveRelativePathComponents(
> > > + 		porting::path_user + DIR_DELIM + "mods" +
> > > DIR_DELIM);
> > > +-	lua_pushstring(L, modpath.c_str());
> > > ++	if (c_modpath == NULL)
> > > ++		c_modpath = modpath.c_str();
> > > ++	lua_pushstring(L, c_modpath);
> > > ++	return 1;
> > > ++}
> > > ++
> > > ++/**************************************************************
> > > ****
> > > ************/
> > > ++int ModApiMainMenu::l_mod_path_set(lua_State *L)
> > > ++{
> > > ++	lua_pushboolean(L, NULL !=
> > > getenv("MINETEST_MOD_PATH"));
> > > + 	return 1;
> > > + }
> > > + 
> > > +@@ -855,6 +865,7 @@ void ModApiMainMenu::Initialize(lua_State
> > > *L,
> > > int top)
> > > + 	API_FCT(get_mapgen_names);
> > > + 	API_FCT(get_user_path);
> > > + 	API_FCT(get_modpath);
> > > ++	API_FCT(mod_path_set);
> > > + 	API_FCT(get_clientmodpath);
> > > + 	API_FCT(get_gamepath);
> > > + 	API_FCT(get_texturepath);
> > > +@@ -888,6 +899,7 @@ void
> > > ModApiMainMenu::InitializeAsync(lua_State
> > > *L, int top)
> > > + 	API_FCT(get_mapgen_names);
> > > + 	API_FCT(get_user_path);
> > > + 	API_FCT(get_modpath);
> > > ++	API_FCT(mod_path_set);
> > > + 	API_FCT(get_clientmodpath);
> > > + 	API_FCT(get_gamepath);
> > > + 	API_FCT(get_texturepath);
> > > +diff --git a/src/script/lua_api/l_mainmenu.h
> > > b/src/script/lua_api/l_mainmenu.h
> > > +index ec2d20da2..719c26077 100644
> > > +--- a/src/script/lua_api/l_mainmenu.h
> > > ++++ b/src/script/lua_api/l_mainmenu.h
> > > +@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
> > > + 
> > > + 	static int l_get_modpath(lua_State *L);
> > > + 
> > > ++	static int l_mod_path_set(lua_State *L);
> > > ++
> > > + 	static int l_get_clientmodpath(lua_State *L);
> > > + 
> > > + 	static int l_get_gamepath(lua_State *L);
> > > +-- 
> > > +2.32.0
> > What are these modpaths used for?  For mod installation or for
> > querying mod existence?  If it's the former, you could leave them
> > as-is, similar to how elpa stays enabled in Emacs.
> 
> It is only used by the GUI.  The GUI looks in the directory returned
> by "get_modpath" for two things:
> 
> (1) to determine which mods exist (and to find their descriptions,  
>     their dependency list, screenshots ...).  Only the mods that 
>     exist there can be enabled.
> 
> (2) to determine where mods must be installed when using Minetest's
>     built-in installer.
I see.  Is this the same GUI for all parts or different GUIs?  I think
if we can handle the world creation parts, everything should be fine,
no?

Regards,





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-02 15:50   ` [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal" Maxime Devos
@ 2021-08-03  9:17     ` Leo Prikler
  2021-08-03 11:59       ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-03  9:17 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

I'd merge this and 04/20 into a single patch.  04/20 does of its own
give a good incentive as to why a new build system is to be used (this
could instead be handled by the importer), with this phase added it
makes slightly more sense.

OTOH, perhaps we shouldn't install those shell scripts in the first
place?  Perhaps we can instead make the importer generate packages
based directly on copy-build-system, in which those static strings are
already evaluated.  WDYT?

Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> * guix/build-system/minetest.scm
>   (%standard-phases): New variable.  Delete "patch-source-shebangs"
>   phase.
>   (lower-mod): Set #:phases to value of new variable.
> ---
>  guix/build-system/minetest.scm | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/guix/build-system/minetest.scm b/guix/build-
> system/minetest.scm
> index 29866ced6d..993c5631eb 100644
> --- a/guix/build-system/minetest.scm
> +++ b/guix/build-system/minetest.scm
> @@ -35,6 +35,14 @@
>        (substring package-name 9)
>        package-name))
>  
> +(define %standard-phases
> +  ;; The source code sometimes contains shell scripts which are used
> for
> +  ;; development but not at run time (e.g. listnodes.sh in
> +  ;; minetest-homedecor-modpack).  Don't make them retain a
> reference
> +  ;; to bash-minimal.
> +  '(modify-phases (@ (guix build copy-build-system) %standard-
> phases)
> +     (delete 'patch-source-shebangs)))
> +
>  (define (lower-mod name . arguments)
>    (define lower (build-system-lower copy-build-system))
>    (apply lower
> @@ -42,6 +50,7 @@
>      #:install-plan
>      `'(("." ,(string-append "share/minetest/mods/"
>                              (guix-name->mod-name name))))
> +    #:phases %standard-phases
>      arguments))
>  
>  (define minetest-mod-build-system





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-02 18:47         ` Leo Prikler
@ 2021-08-03 11:09           ` Maxime Devos
  2021-08-03 11:10             ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-03 11:09 UTC (permalink / raw)
  To: Leo Prikler, 49828

[-- Attachment #1: Type: text/plain, Size: 4124 bytes --]

Hi,

I've modified this patch such that:

  * the GUI will display mods in MINETEST_MOD_PATH as well as
    mods in ~/.minetest/mods

  * the built-in installer works even if MINETEST_MOD_PATH is set

  * MINETEST_MOD_PATH can contain multiple components

Please tell if there are other issues

I'll look into the upstream procedure for submitting patches.

Leo Prikler schreef op ma 02-08-2021 om 20:47 [+0200]:
> Am Montag, den 02.08.2021, 19:53 +0200 schrieb Maxime Devos:
> > > > +This patch as-is is not yet ready for upstream, because:
> > > > +
> > > > +  * the GUI will only display mods in MINETEST_MOD_PATH
> > > > +    or mods in ~/.minetest/mods, it won't combine the two
> > > > +
> > > > +  * the GUI for installing mods from ContentDB is disabled
> > > > +    when MINETEST_MOD_PATH is set, because otherwise Minetest
> > > > +    would try to install mods in the store.
> > > These two are fine for a "Guix-only" patch, although I do think we
> > > should still read ~/.minetest/mods for backwards compatibility.
> > 
> > ~/.minetest/mods is still read when MINETEST_MOD_PATH is unset.
> > MINETEST_MOD_PATH is only set when some mod is actually installed.
> > So backwards compatibility should be ok.
> I mean in the sense of "have some mods in ~/.minetest/mods, that aren't
> yet packaged in Guix and have the rest sit in the profile where they
> belong".  Not everyone will like the the import to manifest approach
> that is needed while you're waiting for review.

All three points should be addresed by the new patch.

> > > > + -- Unordered preserves the original order of the ContentDB API,
> > > > + -- before the package list is ordered based on installed state.
> > > > +diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
> > > > +index e9dc609b0..1809f189e 100644
> > > > +--- a/src/content/subgames.cpp
> > > > ++++ b/src/content/subgames.cpp
> > > > +@@ -110,6 +110,9 @@ SubgameSpec findSubgame(const std::string
> > > > &id)
> > > > + 	std::set<std::string> mods_paths;
> > > > + 	if (!user_game)
> > > > + 		mods_paths.insert(share + DIR_DELIM + "mods");
> > > > ++	const char *env_mod_path = getenv("MINETEST_MOD_PATH");
> > > > ++	if (env_mod_path)
> > > > ++		mods_paths.insert(std::string(env_mod_path));
> > > Here, I would instead use an std::istringstream together with
> > > std::getline(<>, <>, ':') to get the components of
> > > MINETEST_MOD_PATH
> > > and insert each of them.  Either that or copy whatever is used for
> > > MINETEST_SUBGAME_PATH.
> > 
> > Minetest has a class 'Strfnd' supporting iteration.  Using that,
> > it should be easy to allow MINETEST_MOD_PATH to contain ":"
> > seperators.
> > However, the GUI client code (pkgmgr.lua)
> > uses some other logic for determining which mods exists, and
> > currently,
> > that logic does not support ":" separators.
> Hmm, how important is the GUI side here?  Can we sneek mods into it?

The GUI side is very important.  All mods are disabled by default,
and in the GUI you need to choose which mods to enable.  If the GUI
doesn't know about the existence of the mod, then the mod cannot be
enabled.

> > It is only used by the GUI.  The GUI looks in the directory returned
> > by "get_modpath" for two things:
> > 
> > (1) to determine which mods exist (and to find their descriptions,  
> >     their dependency list, screenshots ...).  Only the mods that 
> >     exist there can be enabled.
> > 
> > (2) to determine where mods must be installed when using Minetest's
> >     built-in installer.
> I see.  Is this the same GUI for all parts or different GUIs?  I think
> if we can handle the world creation parts, everything should be fine,
> no?

The ‘mod selecter’ (1) and installer (2) have separate graphical interfaces,
but they use some common code 'pkgmgr.lua'.  In the new patch, 'get_modpath()'
(a string) is where mods should be installed by the built-in installer,
and 'get_modpaths()' (a list of strings) is where mods can be found.
Both interfaces work with the new patch.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-03 11:09           ` Maxime Devos
@ 2021-08-03 11:10             ` Maxime Devos
  2021-08-03 11:54               ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-03 11:10 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 31 bytes --]

I forgot to attach the patch.

[-- Attachment #1.2: 0002-gnu-minetest-Search-for-mods-in-MINETEST_MOD_PATH.patch --]
[-- Type: text/x-patch, Size: 8725 bytes --]

From e999b5ef71d393eddd5767a108a7bd864ff6ec50 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 18:08:44 +0200
Subject: [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.

* gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch:
  New file.
* gnu/packages/games.scm
  (minetest)[source]{patches}: Add it.
  (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/games.scm                        |   6 +-
 ...vironment-variable-MINETEST_MOD_PATH.patch | 162 ++++++++++++++++++
 3 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c80a9af78c..d96d4e3dbc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -801,6 +801,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
   %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
   %D%/packages/patches/adb-add-libraries.patch			\
+  %D%/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch	\
   %D%/packages/patches/aegis-constness-error.patch         	\
   %D%/packages/patches/aegis-perl-tempdir1.patch           	\
   %D%/packages/patches/aegis-perl-tempdir2.patch           	\
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 3e7086b398..6a30c53e32 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3553,6 +3553,7 @@ match, cannon keep, and grave-itation pit.")
                (base32
                 "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8"))
               (modules '((guix build utils)))
+              (patches (search-patches "Add-environment-variable-MINETEST_MOD_PATH.patch"))
               (snippet
                '(begin
                   ;; Delete bundled libraries.
@@ -3599,7 +3600,10 @@ match, cannon keep, and grave-itation pit.")
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-            (files '("share/minetest/games")))))
+            (files '("share/minetest/games")))
+           (search-path-specification
+            (variable "MINETEST_MOD_PATH")
+            (files '("share/minetest/mods")))))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (inputs
diff --git a/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
new file mode 100644
index 0000000000..8d72c42bf9
--- /dev/null
+++ b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
@@ -0,0 +1,162 @@
+From dccaae3aebedb5178201ba818b8264fdb9e5e832 Mon Sep 17 00:00:00 2001
+From: Maxime Devos <maximedevos@telenet.be>
+Date: Tue, 3 Aug 2021 01:00:23 +0200
+Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
+
+This adds an environment variable MINETEST_MOD_PATH.
+When it exists, Minetest will look there for mods
+in addition to ~/.minetest/mods/.  Mods can still be
+installed to ~/.minetest/mods/ with the built-in installer.
+---
+ builtin/mainmenu/pkgmgr.lua       |  7 +++----
+ doc/menu_lua_api.txt              |  8 +++++++-
+ src/content/subgames.cpp          | 11 +++++++++++
+ src/script/lua_api/l_mainmenu.cpp | 31 +++++++++++++++++++++++++++++++
+ src/script/lua_api/l_mainmenu.h   |  2 ++
+ 5 files changed, 54 insertions(+), 5 deletions(-)
+
+diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
+index 787936e31..d8fba0ebe 100644
+--- a/builtin/mainmenu/pkgmgr.lua
++++ b/builtin/mainmenu/pkgmgr.lua
+@@ -682,10 +682,9 @@ function pkgmgr.preparemodlist(data)
+ 	local game_mods = {}
+ 
+ 	--read global mods
+-	local modpath = core.get_modpath()
+-
+-	if modpath ~= nil and
+-		modpath ~= "" then
++	local modpaths = core.get_modpaths()
++	--XXX what was ‘modpath ~= ""’ and ‘modpath ~= nil’ for?
++	for _,modpath in ipairs(modpaths) do
+ 		get_mods(modpath,global_mods)
+ 	end
+ 
+diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
+index b3975bc1d..132444b14 100644
+--- a/doc/menu_lua_api.txt
++++ b/doc/menu_lua_api.txt
+@@ -218,7 +218,13 @@ Package - content which is downloadable from the content db, may or may not be i
+     * returns path to global user data,
+       the directory that contains user-provided mods, worlds, games, and texture packs.
+ * core.get_modpath() (possible in async calls)
+-    * returns path to global modpath
++    * returns path to global modpath, where mods can be installed
++* core.get_modpaths() (possible in async calls)
++    * returns list of paths to global modpaths, where mods have been installed
++
++      The difference with "core.get_modpath" is that no mods should be installed in these
++      directories by Minetest -- they might be read-only.
++
+ * core.get_clientmodpath() (possible in async calls)
+     * returns path to global client-side modpath
+ * core.get_gamepath() (possible in async calls)
+diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
+index e9dc609b0..d73f95a1f 100644
+--- a/src/content/subgames.cpp
++++ b/src/content/subgames.cpp
+@@ -61,6 +61,12 @@ std::string getSubgamePathEnv()
+ 	return subgame_path ? std::string(subgame_path) : "";
+ }
+ 
++std::string getModPathEnv()
++{
++	char *mod_path = getenv("MINETEST_MOD_PATH");
++	return mod_path ? std::string(mod_path) : "";
++}
++
+ SubgameSpec findSubgame(const std::string &id)
+ {
+ 	if (id.empty())
+@@ -110,6 +116,11 @@ SubgameSpec findSubgame(const std::string &id)
+ 	std::set<std::string> mods_paths;
+ 	if (!user_game)
+ 		mods_paths.insert(share + DIR_DELIM + "mods");
++
++	Strfnd mod_search_paths(getModPathEnv());
++	while (!mod_search_paths.at_end())
++		mods_paths.insert(mod_search_paths.next(PATH_DELIM));
++
+ 	if (user != share || user_game)
+ 		mods_paths.insert(user + DIR_DELIM + "mods");
+ 
+diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
+index 3e9709bde..c1647195f 100644
+--- a/src/script/lua_api/l_mainmenu.cpp
++++ b/src/script/lua_api/l_mainmenu.cpp
+@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ #include "lua_api/l_internal.h"
+ #include "common/c_content.h"
+ #include "cpp_api/s_async.h"
++#include "util/strfnd.h"
+ #include "gui/guiEngine.h"
+ #include "gui/guiMainMenu.h"
+ #include "gui/guiKeyChangeMenu.h"
+@@ -502,6 +503,34 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
+ 	return 1;
+ }
+ 
++/******************************************************************************/
++int ModApiMainMenu::l_get_modpaths(lua_State *L)
++{
++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
++	if (c_modpath == NULL)
++		c_modpath = "";
++	int index = 1;
++	lua_newtable(L);
++	// XXX: for some reason, simply writing
++	// Strfnd mod_search_paths (std::string(c_modpath));
++	// leads to a compilation error:
++	//
++	// request for member ‘at_end’ in ‘mod_search_paths’, which is of
++	// non-class type ‘Strfnd(std::__cxx11::string)
++	// {aka BasicStrfnd<char>(std::__cxx11::basic_string<char>)}’
++	std::string modpath = std::string(c_modpath);
++	Strfnd mod_search_paths(modpath);
++	while (!mod_search_paths.at_end()) {
++		std::string component = mod_search_paths.next(PATH_DELIM);
++		lua_pushstring(L, component.c_str());
++		lua_rawseti(L, -2, index);
++		index++;
++	}
++	ModApiMainMenu::l_get_modpath(L);
++	lua_rawseti(L, -2, index);
++	return 1;
++}
++
+ /******************************************************************************/
+ int ModApiMainMenu::l_get_clientmodpath(lua_State *L)
+ {
+@@ -949,6 +978,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+@@ -983,6 +1013,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
+index 33ac9e721..a6a54a2cb 100644
+--- a/src/script/lua_api/l_mainmenu.h
++++ b/src/script/lua_api/l_mainmenu.h
+@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
+ 
+ 	static int l_get_modpath(lua_State *L);
+ 
++	static int l_get_modpaths(lua_State *L);
++
+ 	static int l_get_clientmodpath(lua_State *L);
+ 
+ 	static int l_get_gamepath(lua_State *L);
+-- 
+2.32.0
+
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-03 11:10             ` Maxime Devos
@ 2021-08-03 11:54               ` Leo Prikler
  0 siblings, 0 replies; 71+ messages in thread
From: Leo Prikler @ 2021-08-03 11:54 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Dienstag, den 03.08.2021, 13:10 +0200 schrieb Maxime Devos:
>               (patches (search-patches "Add-environment-variable-
> MINETEST_MOD_PATH.patch"))
This line is a bit long.  Even if might look a little weird, I think
it's better split in three.

> ++	// XXX: for some reason, simply writing
> ++	// Strfnd mod_search_paths (std::string(c_modpath));
> ++	// leads to a compilation error:
> ++	//
> ++	// request for member ‘at_end’ in ‘mod_search_paths’, which is
> of
> ++	// non-class type ‘Strfnd(std::__cxx11::string)
> ++	// {aka BasicStrfnd<char>(std::__cxx11::basic_string<char>)}’
> ++	std::string modpath = std::string(c_modpath);
> ++	Strfnd mod_search_paths(modpath);
Try Strfnd mod_search_paths{modpath}.  The normal bracket style
confuses C++, because it can also be parsed as a function declaration.

> + * core.get_modpath() (possible in async calls)
> +-    * returns path to global modpath
> ++    * returns path to global modpath, where mods can be installed
> ++* core.get_modpaths() (possible in async calls)
> ++    * returns list of paths to global modpaths, where mods have
> been installed
> ++
> ++      The difference with "core.get_modpath" is that no mods should
> be installed in these
> ++      directories by Minetest -- they might be read-only.
This is a somewhat weird interface imo.  I think core.get_modpath
should be the first element of core.get_modpaths and documented in that
way, so that any GUI that deals with "all known mods" needs to simply
call the latter, whereas any GUI that deals with installing can
comfortably use either the former or whatever Lua has for car.  WDYT?

Otherwise LGTM.






^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-03  9:17     ` Leo Prikler
@ 2021-08-03 11:59       ` Maxime Devos
  2021-08-03 12:28         ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-03 11:59 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 2146 bytes --]

Leo Prikler schreef op di 03-08-2021 om 11:17 [+0200]:
> Hi,
> 
> I'd merge this and 04/20 into a single patch.  04/20 does of its own
> give a good incentive as to why a new build system is to be used (this
> could instead be handled by the importer), with this phase added it
> makes slightly more sense.

As an argument for having a 'minetest-mod-build-system', consider
some ways 'minetest-mod-build-system' could be improved in the future:

  * a phase could be added to minimise PNG images (e.g. using 'optipng')
  * likewise, for lua code
  * some basic tests could be added (e.g. creating a new world and
    loading the mod, testing that Minetest doesn't raise an error during
    mod loading)

Also, having "#:install-plan '(("." "share/minetest/mods/the-mod-name"))"
appear in every package definition seems rather repetitive to me.

The idea behind "04/20" and "05/20" being separate patches, is to start
with a basic "minetest-mod-build-system" and gradually improve it.
The small improvements (currently only one, i.e., 05/20) could be reviewed
separately from each other and whether there should be a
"minetest-mod-build-system" at all.

E.g., see attached a patch that sets #:allowed-references '(), ensuring
nothing sneaks into the closure.  Another change I'm thinking of, is including
only "tar", "gzip" and the like as implicit inputs, and not "bash" or "coreutils",
though that's probably useless if shebang patching has been disabled.

> OTOH, perhaps we shouldn't install those shell scripts in the first
> place?  Perhaps we can instead make the importer generate packages
> based directly on copy-build-system, in which those static strings are
> already evaluated.  WDYT?

Directly using 'copy-build-system' makes it more difficult to make the
improvements listed above. I don't know what you mean with ‘in which those
static strings are already evaluated’ -- what are ‘those static strings’ here?

I suppose it is possible to exclude shell scripts from installation, but
just installing everything (and disabling shebang patching) seems simpler.

Greetings,
Maxime.

[-- Attachment #1.2: 0001-build-system-copy-Support-allowed-references.patch --]
[-- Type: text/x-patch, Size: 2176 bytes --]

From eef6cb11a923458cba50bbc4e6440c0b2f372da2 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Tue, 3 Aug 2021 13:50:49 +0200
Subject: [PATCH 1/2] build-system/copy: Support #:allowed-references.

* guix/build-system/copy.scm
  (copy-build): Add #:allowed-references argument.
  (copy-build)[canonicalize-reference]: New procedure.
---
 guix/build-system/copy.scm | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/guix/build-system/copy.scm b/guix/build-system/copy.scm
index d1bf8fb654..1cd0a95150 100644
--- a/guix/build-system/copy.scm
+++ b/guix/build-system/copy.scm
@@ -92,8 +92,22 @@
                      (system (%current-system))
                      (imported-modules %copy-build-system-modules)
                      (modules '((guix build copy-build-system)
-                                (guix build utils))))
+                                (guix build utils)))
+                     allowed-references)
   "Build SOURCE using INSTALL-PLAN, and with INPUTS."
+  ;; XXX: procedure copied from (guix build-system gnu)
+  (define canonicalize-reference
+    (match-lambda
+     ((? package? p)
+      (derivation->output-path (package-derivation store p system
+                                                   #:graft? #f)))
+     (((? package? p) output)
+      (derivation->output-path (package-derivation store p system
+                                                   #:graft? #f)
+                               output))
+     ((? string? output)
+      output)))
+
   (define builder
     `(begin
        (use-modules ,@modules)
@@ -131,6 +145,10 @@
                                 #:system system
                                 #:inputs inputs
                                 #:modules imported-modules
+                                #:allowed-references
+                                (and allowed-references
+                                     (map canonicalize-reference
+                                          allowed-references))
                                 #:outputs outputs
                                 #:guile-for-build guile-for-build))
 
-- 
2.32.0


[-- Attachment #1.3: 0002-build-system-minetest-Don-t-let-anything-sneak-into-.patch --]
[-- Type: text/x-patch, Size: 901 bytes --]

From f383aa1c886701631f6ae924a93e13cdad2eaa59 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Tue, 3 Aug 2021 13:52:37 +0200
Subject: [PATCH 2/2] build-system/minetest: Don't let anything sneak into the
 closure.

* guix/build-system/minetest.scm (lower-mod): Set #:allowed-references
  to the empty list.
---
 guix/build-system/minetest.scm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
index 993c5631eb..1d63e5ffcf 100644
--- a/guix/build-system/minetest.scm
+++ b/guix/build-system/minetest.scm
@@ -51,6 +51,8 @@
     `'(("." ,(string-append "share/minetest/mods/"
                             (guix-name->mod-name name))))
     #:phases %standard-phases
+    ;; Ensure nothing sneaks into the closure.
+    #:allowed-references '()
     arguments))
 
 (define minetest-mod-build-system
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-03 11:59       ` Maxime Devos
@ 2021-08-03 12:28         ` Leo Prikler
  2021-08-05 11:01           ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-03 12:28 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Dienstag, den 03.08.2021, 13:59 +0200 schrieb Maxime Devos:
> Leo Prikler schreef op di 03-08-2021 om 11:17 [+0200]:
> > Hi,
> > 
> > I'd merge this and 04/20 into a single patch.  04/20 does of its
> > own
> > give a good incentive as to why a new build system is to be used
> > (this
> > could instead be handled by the importer), with this phase added it
> > makes slightly more sense.
> 
> As an argument for having a 'minetest-mod-build-system', consider
> some ways 'minetest-mod-build-system' could be improved in the
> future:
> 
>   * a phase could be added to minimise PNG images (e.g. using
> 'optipng')
>   * likewise, for lua code
>   * some basic tests could be added (e.g. creating a new world and
>     loading the mod, testing that Minetest doesn't raise an error
> during
>     mod loading)
Of course there's more that can be done here, but this just reaffirms
my earlier point, that the build system on its own as it is in 04/20
looks rather unfinished.  I'd personally prefer introducing it as one
whole as it gives a bigger picture of the whole thing rather than
digging into every detail.

> Also, having "#:install-plan '(("." "share/minetest/mods/the-mod-
> name"))"
> appear in every package definition seems rather repetitive to me.
Perhaps, but it's not like there aren't other groups of things that can
be implemented trivially in terms of copy-build-system.

> The idea behind "04/20" and "05/20" being separate patches, is to
> start
> with a basic "minetest-mod-build-system" and gradually improve it.
> The small improvements (currently only one, i.e., 05/20) could be
> reviewed
> separately from each other and whether there should be a
> "minetest-mod-build-system" at all.
See above.

> E.g., see attached a patch that sets #:allowed-references '(),
> ensuring
> nothing sneaks into the closure.  Another change I'm thinking of, is
> including
> only "tar", "gzip" and the like as implicit inputs, and not "bash" or
> "coreutils",
> though that's probably useless if shebang patching has been disabled.
IMO that patch should also be merged "as one" with the others.

> > OTOH, perhaps we shouldn't install those shell scripts in the first
> > place?  Perhaps we can instead make the importer generate packages
> > based directly on copy-build-system, in which those static strings
> > are
> > already evaluated.  WDYT?
> 
> Directly using 'copy-build-system' makes it more difficult to make
> the improvements listed above. I don't know what you mean with ‘in
> which those static strings are already evaluated’ -- what are ‘those
> static strings’ here?
‘Those static strings’ are exactly "the-mod-name" in 
> #:install-plan '(("." "share/minetest/mods/the-mod-name"))
I'm still not quite convinced, that whatever improvements you seem
there to be can't be made by using a good enough include regexp.

> I suppose it is possible to exclude shell scripts from installation,
> but just installing everything (and disabling shebang patching) seems
> simpler.
Likewise leaving shell references in there and using plain copy-build-
system would be simpler than making a new build system, wouldn't it?  I
don't think that's a good reason not to make a proper install plan.

Greetings





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-03 12:28         ` Leo Prikler
@ 2021-08-05 11:01           ` Maxime Devos
  2021-08-05 12:04             ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-05 11:01 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 567 bytes --]

Hi,

The attached patch squashes "PATCH 04" and "PATCH 05" together
and extends the build system.  It now has an install plan only installing
what's necessary (Lua code, PNG images, some configuration files ...),
a 'check' build phase verifying Minetest can actually load the mod,
and a 'minimise-png' phase minimising PNG images.

The mod name for ‘(("." "share/minetest/mods/the-mod-name"))’ can now
be determined exactly in most cases (Minetest doesn't really care but
the directory name can appear in the GUI in some cases).

Greetings,
Maxime.

[-- Attachment #1.2: build-system-Add-minetest-mod-build-system.patch --]
[-- Type: text/x-patch, Size: 15375 bytes --]

From e21ef78f6fdfd6d3952b2cc4f0fb1fa8b59ae5e1 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 13:52:39 +0200
Subject: [PATCH] build-system: Add 'minetest-mod-build-system'.

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  87 +++++++++++
 guix/build/minetest-build-system.scm | 220 +++++++++++++++++++++++++++
 4 files changed, 317 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..f7dba4f293 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..e99cc411c9
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,87 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define (lower-mod name . arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         #:imported-modules %minetest-build-system-modules
+         #:modules %default-modules
+         #:phases '%standard-phases
+         #:implicit-inputs? #f
+         ;; Mods are architecture-independent.
+         #:target #f
+         ;; Ensure nothing sneaks into the closure.
+         #:allowed-references '()
+         (substitute-keyword-arguments arguments
+           ((#:native-inputs native-inputs '())
+            (append native-inputs (standard-minetest-packages))))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..e0c11e91f6
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,220 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make the guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           (file-name (basename source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-minetest")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply (@@ (guix build copy-build-system) install)
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimisation."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-05 11:01           ` Maxime Devos
@ 2021-08-05 12:04             ` Leo Prikler
  2021-08-05 13:16               ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-05 12:04 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Donnerstag, den 05.08.2021, 13:01 +0200 schrieb Maxime Devos:
> Hi,
> 
> The attached patch squashes "PATCH 04" and "PATCH 05" together
> and extends the build system.  It now has an install plan only
> installing
> what's necessary (Lua code, PNG images, some configuration files
> ...),
> a 'check' build phase verifying Minetest can actually load the mod,
> and a 'minimise-png' phase minimising PNG images.
> 
> The mod name for ‘(("." "share/minetest/mods/the-mod-name"))’ can now
> be determined exactly in most cases (Minetest doesn't really care but
> the directory name can appear in the GUI in some cases).
> 
> Greetings,
> Maxime.

> +mods, which consists of copying lua code, images and other resources
> to
s/lua/Lua/ :)

> +(define* (install #:key inputs #:allow-other-keys #:rest arguments)
> +  (apply (@@ (guix build copy-build-system) install)
> +         #:install-plan (mod-install-plan (apply guess-mod-name
> arguments))
> +         arguments))
@@ is a code smell, as far as Guix is concerned.  Rather import copy-
build-system with the copy: prefix.

> +(define png-file?
> +  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
Likewise import (guix build utils) directly.

> +(define (lower-mod name . arguments)
> +  (define lower (build-system-lower gnu-build-system))
> +  (apply lower
> +         name
> +         #:imported-modules %minetest-build-system-modules
> +         #:modules %default-modules
> +         #:phases '%standard-phases
> +         #:implicit-inputs? #f
> +         ;; Mods are architecture-independent.
> +         #:target #f
> +         ;; Ensure nothing sneaks into the closure.
> +         #:allowed-references '()
> +         (substitute-keyword-arguments arguments
> +           ((#:native-inputs native-inputs '())
> +            (append native-inputs (standard-minetest-packages))))))
This appears a little confusing.  On first glance, it does not seem to
allow overriding e.g. #:phases, but on a second look using `apply'
together with shallowly substituted arguments would enable that.  The
only thing that's missing imo is that #:implicit-inputs? is not
honoured for (standard-minetest-packages) -- I think you might want to
rectify that.

Otherwise looks pretty good to me.





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 00/20] Add minetest mods
  2021-08-02 15:46 [bug#49828] [PATCH 00/20] Add minetest mods Maxime Devos
  2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
@ 2021-08-05 12:46 ` Andrew Ward
  2021-08-05 21:10   ` Maxime Devos
  1 sibling, 1 reply; 71+ messages in thread
From: Andrew Ward @ 2021-08-05 12:46 UTC (permalink / raw)
  To: 49828

[-- Attachment #1: Type: text/html, Size: 1386 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-05 12:04             ` Leo Prikler
@ 2021-08-05 13:16               ` Maxime Devos
  2021-08-05 13:42                 ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-05 13:16 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 2519 bytes --]

Leo Prikler schreef op do 05-08-2021 om 14:04 [+0200]:
> > +mods, which consists of copying lua code, images and other resources
> > to
> s/lua/Lua/ :)

Fixed.

> > +(define* (install #:key inputs #:allow-other-keys #:rest arguments)
> > +  (apply (@@ (guix build copy-build-system) install)
> > +         #:install-plan (mod-install-plan (apply guess-mod-name
> > arguments))
> > +         arguments))
> @@ is a code smell, as far as Guix is concerned.  Rather import copy-
> build-system with the copy: prefix.

'copy-build-system' does not export 'install', so I have to use '@@' here.
Modifying 'copy-build-system' to export 'install' would presumably entail
a many rebuilds.

> > +(define png-file?
> > +  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
> Likewise import (guix build utils) directly.

Likewise.

> > +(define (lower-mod name . arguments)
> > +  (define lower (build-system-lower gnu-build-system))
> > +  (apply lower
> > +         name
> > +         #:imported-modules %minetest-build-system-modules
> > +         #:modules %default-modules
> > +         #:phases '%standard-phases
> > +         #:implicit-inputs? #f
> > +         ;; Mods are architecture-independent.
> > +         #:target #f
> > +         ;; Ensure nothing sneaks into the closure.
> > +         #:allowed-references '()
> > +         (substitute-keyword-arguments arguments
> > +           ((#:native-inputs native-inputs '())
> > +            (append native-inputs (standard-minetest-packages))))))

> This appears a little confusing.  On first glance, it does not seem to
> allow overriding e.g. #:phases, but on a second look using `apply'
> together with shallowly substituted arguments would enable that. 

I modified the patch to move more things into 'substitute-keyword-arguments'
to reduce confusion.

>  The
> only thing that's missing imo is that #:implicit-inputs? is not
> honoured for (standard-minetest-packages) -- I think you might want to
> rectify that.

I modified 'lower-mod' to _not_ add 'standard-minetest-packages' to
'native-inputs' when #:implicit-inputs? is false, though I don't see
why a package definition for a Minetest mod would do that.

I also found a spellig bug ("to minimisation" -> "to minimise") which
is now fixed.

btw, I submitted the "MINETEST_MOD_PATH" patch upstream, with your suggestion
for "{std::string(...)}" construction:
<https://github.com/minetest/minetest/pull/11515>.

Greetings,
Maxime.

[-- Attachment #1.2: build-system-Add-minetest-mod-build-system.patch --]
[-- Type: text/x-patch, Size: 15963 bytes --]

From dbd9cf53d359b461c01176e3170ba0663ce9007c Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 13:52:39 +0200
Subject: [PATCH] build-system: Add 'minetest-mod-build-system'.

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  99 ++++++++++++
 guix/build/minetest-build-system.scm | 220 +++++++++++++++++++++++++++
 4 files changed, 329 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..d44ecc2005 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying Lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..98bcbc9e0c
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,99 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys
+                    #:rest arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         (substitute-keyword-arguments arguments
+           ;; minetest-mod-build-system adds implicit inputs by itself,
+           ;; so don't let gnu-build-system add its own implicit inputs
+           ;; as well.
+           ((#:implicit-inputs? implicit-inputs? #t)
+            #f)
+           ((#:imported-modules imported-modules %minetest-build-system-modules)
+            imported-modules)
+           ((#:modules modules %default-modules)
+            modules)
+           ((#:phases phases '%standard-phases)
+            phases)
+           ;; Mods are architecture-independent.
+           ((#:target target #f) #f)
+           ;; Ensure nothing sneaks into the closure.
+           ((#:allowed-references allowed-references '())
+            allowed-references)
+           ;; Add the implicit inputs.
+           ((#:native-inputs native-inputs '())
+            (if implicit-inputs?
+                (append native-inputs (standard-minetest-packages))
+                native-inputs)))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..e9eb491b1b
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,220 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make the guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           (file-name (basename source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-minetest")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply (@@ (guix build copy-build-system) install)
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimise."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-05 13:16               ` Maxime Devos
@ 2021-08-05 13:42                 ` Leo Prikler
  2021-08-05 14:41                   ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-05 13:42 UTC (permalink / raw)
  To: Maxime Devos, 49828

Am Donnerstag, den 05.08.2021, 15:16 +0200 schrieb Maxime Devos:
> [...]
> > > +(define* (install #:key inputs #:allow-other-keys #:rest
> > > arguments)
> > > +  (apply (@@ (guix build copy-build-system) install)
> > > +         #:install-plan (mod-install-plan (apply guess-mod-name
> > > arguments))
> > > +         arguments))
> > @@ is a code smell, as far as Guix is concerned.  Rather import
> > copy-build-system with the copy: prefix.
> 
> 'copy-build-system' does not export 'install', so I have to use '@@'
> here.
> Modifying 'copy-build-system' to export 'install' would presumably
> entail
> a many rebuilds.
I think the thing that's usually done here is fetching through
%standard-phases.
I.e. (define copy:install (assoc-ref copy-build-system:%standard-phases 
'install))

> > > +(define png-file?
> > > +  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
> > Likewise import (guix build utils) directly.
> 
> Likewise.
In that case fine, but make a note to move the variable and procedure
over to (guix build utils).

> > > +(define (lower-mod name . arguments)
> > > +  (define lower (build-system-lower gnu-build-system))
> > > +  (apply lower
> > > +         name
> > > +         #:imported-modules %minetest-build-system-modules
> > > +         #:modules %default-modules
> > > +         #:phases '%standard-phases
> > > +         #:implicit-inputs? #f
> > > +         ;; Mods are architecture-independent.
> > > +         #:target #f
> > > +         ;; Ensure nothing sneaks into the closure.
> > > +         #:allowed-references '()
> > > +         (substitute-keyword-arguments arguments
> > > +           ((#:native-inputs native-inputs '())
> > > +            (append native-inputs (standard-minetest-
> > > packages))))))
> > This appears a little confusing.  On first glance, it does not seem
> > to
> > allow overriding e.g. #:phases, but on a second look using `apply'
> > together with shallowly substituted arguments would enable that. 
> 
> I modified the patch to move more things into 'substitute-keyword-
> arguments' to reduce confusion.
LGTM.

> >  The
> > only thing that's missing imo is that #:implicit-inputs? is not
> > honoured for (standard-minetest-packages) -- I think you might want
> > to
> > rectify that.
> 
> I modified 'lower-mod' to _not_ add 'standard-minetest-packages' to
> 'native-inputs' when #:implicit-inputs? is false, though I don't see
> why a package definition for a Minetest mod would do that.
> 
> I also found a spellig bug ("to minimisation" -> "to minimise") which
> is now fixed.
The new lower-mod mostly LGTM, but
> +           ;; Mods are architecture-independent.
> +           ((#:target target #f) #f)
should be `target' imho.  What if the mod e.g. actually builds a shared
object and somehow uses Lua's very dynamic FFI to load it?  (Even if
that's not currently possible, it might be in the future).  Setting it
to #f by default OTOH sounds very reasonable to me.

> btw, I submitted the "MINETEST_MOD_PATH" patch upstream, with your
> suggestion for "{std::string(...)}" construction:
> <https://github.com/minetest/minetest/pull/11515>;.
Nice, perhaps in 5.5 we will be able to enjoy this out-of-the-box.

Greetings





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-05 13:42                 ` Leo Prikler
@ 2021-08-05 14:41                   ` Maxime Devos
  2021-08-05 15:15                     ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-05 14:41 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 2328 bytes --]

Leo Prikler schreef op do 05-08-2021 om 15:42 [+0200]:
> Am Donnerstag, den 05.08.2021, 15:16 +0200 schrieb Maxime Devos:
> > [...]
> > > > +(define* (install #:key inputs #:allow-other-keys #:rest
> > > > arguments)
> > > > +  (apply (@@ (guix build copy-build-system) install)
> > > > +         #:install-plan (mod-install-plan (apply guess-mod-name
> > > > arguments))
> > > > +         arguments))
> > > @@ is a code smell, as far as Guix is concerned.  Rather import
> > > copy-build-system with the copy: prefix.
> > 
> > 'copy-build-system' does not export 'install', so I have to use '@@'
> > here.
> > Modifying 'copy-build-system' to export 'install' would presumably
> > entail
> > a many rebuilds.
> I think the thing that's usually done here is fetching through
> %standard-phases.
> I.e. (define copy:install (assoc-ref copy-build-system:%standard-phases 
> 'install))

Done.

> > > > +(define png-file?
> > > > +  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
> > > Likewise import (guix build utils) directly.
> > 
> > Likewise.
> In that case fine, but make a note to move the variable and procedure
> over to (guix build utils).

I made a note.

> The new lower-mod mostly LGTM, but
> > +           ;; Mods are architecture-independent.
> > +           ((#:target target #f) #f)

> should be `target' imho.  What if the mod e.g. actually builds a shared
> object and somehow uses Lua's very dynamic FFI to load it?  (Even if
> that's not currently possible, it might be in the future).  Setting it
> to #f by default OTOH sounds very reasonable to me.

'target' is set by 'make-bag' in (guix build-system), so if the code above
is made

    ((#:target target #f) target)

then #:target will always be set to some triplet.  Mostly harmless, but a
bit a waste of disk space since this leads to (slightly) different derivations
depending on the value of "target".

I don't think any mods use Lua's FFI, but some mods use 'os.execute',
which takes a file name referring to an executable, which might need to be
absolutised in Guix, and therefore some mods are architecture-dependent.

It dropped the ((#:target target #f) #f).  I noticed "#:implicit-cross-inputs?"
wasn't set to #f.  That has been corrected as well.

Greetings,
Maxime.

[-- Attachment #1.2: build-system-Add-minetest-mod-build-system.patch --]
[-- Type: text/x-patch, Size: 16124 bytes --]

From 93aa8e1976e762d30be70aef6d5c50b1d06ca4be Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 13:52:39 +0200
Subject: [PATCH] build-system: Add 'minetest-mod-build-system'.

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  99 ++++++++++++
 guix/build/minetest-build-system.scm | 225 +++++++++++++++++++++++++++
 4 files changed, 334 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..d44ecc2005 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying Lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..f33e97559d
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,99 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys
+                    #:rest arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         (substitute-keyword-arguments arguments
+           ;; minetest-mod-build-system adds implicit inputs by itself,
+           ;; so don't let gnu-build-system add its own implicit inputs
+           ;; as well.
+           ((#:implicit-inputs? implicit-inputs? #t)
+            #f)
+           ((#:implicit-cross-inputs? implicit-cross-inputs? #t)
+            #f)
+           ((#:imported-modules imported-modules %minetest-build-system-modules)
+            imported-modules)
+           ((#:modules modules %default-modules)
+            modules)
+           ((#:phases phases '%standard-phases)
+            phases)
+           ;; Ensure nothing sneaks into the closure.
+           ((#:allowed-references allowed-references '())
+            allowed-references)
+           ;; Add the implicit inputs.
+           ((#:native-inputs native-inputs '())
+            (if implicit-inputs?
+                (append native-inputs (standard-minetest-packages))
+                native-inputs)))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..b051d9c288
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,225 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module ((guix build copy-build-system) #:prefix copy:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+;; (guix build copy-build-system) does not export 'install'.
+(define copy:install
+  (assoc-ref copy:%standard-phases 'install))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make the guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           (file-name (basename source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-minetest")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply copy:install
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimise."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal".
  2021-08-05 14:41                   ` Maxime Devos
@ 2021-08-05 15:15                     ` Leo Prikler
  0 siblings, 0 replies; 71+ messages in thread
From: Leo Prikler @ 2021-08-05 15:15 UTC (permalink / raw)
  To: Maxime Devos, 49828

Am Donnerstag, den 05.08.2021, 16:41 +0200 schrieb Maxime Devos:
> Leo Prikler schreef op do 05-08-2021 om 15:42 [+0200]:
> > Am Donnerstag, den 05.08.2021, 15:16 +0200 schrieb Maxime Devos:
> > > [...]
> > > > > +(define* (install #:key inputs #:allow-other-keys #:rest
> > > > > arguments)
> > > > > +  (apply (@@ (guix build copy-build-system) install)
> > > > > +         #:install-plan (mod-install-plan (apply guess-mod-
> > > > > name
> > > > > arguments))
> > > > > +         arguments))
> > > > @@ is a code smell, as far as Guix is concerned.  Rather import
> > > > copy-build-system with the copy: prefix.
> > > 
> > > 'copy-build-system' does not export 'install', so I have to use
> > > '@@'
> > > here.
> > > Modifying 'copy-build-system' to export 'install' would
> > > presumably
> > > entail
> > > a many rebuilds.
> > I think the thing that's usually done here is fetching through
> > %standard-phases.
> > I.e. (define copy:install (assoc-ref copy-build-system:%standard-
> > phases 
> > 'install))
> 
> Done.
LGTM.

> > > > > +(define png-file?
> > > > > +  ((@@ (guix build utils) file-header-match) %png-magic-
> > > > > bytes))
> > > > Likewise import (guix build utils) directly.
> > > 
> > > Likewise.
> > In that case fine, but make a note to move the variable and
> > procedure
> > over to (guix build utils).
> 
> I made a note.
I'm not seeing it, did you send the right file?

> > The new lower-mod mostly LGTM, but
> > > +           ;; Mods are architecture-independent.
> > > +           ((#:target target #f) #f)
> > should be `target' imho.  What if the mod e.g. actually builds a
> > shared
> > object and somehow uses Lua's very dynamic FFI to load it?  (Even
> > if
> > that's not currently possible, it might be in the future).  Setting
> > it
> > to #f by default OTOH sounds very reasonable to me.
> 
> 'target' is set by 'make-bag' in (guix build-system), so if the code
> above is made
> 
>     ((#:target target #f) target)
> 
> then #:target will always be set to some triplet.  Mostly harmless,
> but a bit a waste of disk space since this leads to (slightly)
> different derivations depending on the value of "target".
I think deduplication should take care of that, but yeah.

> I don't think any mods use Lua's FFI, but some mods use 'os.execute',
> which takes a file name referring to an executable, which might need
> to be absolutised in Guix, and therefore some mods are architecture-
> dependent.
> 
> It dropped the ((#:target target #f) #f).  I noticed "#:implicit-
> cross-inputs?" wasn't set to #f.  That has been corrected as well.
Good catch.  

Since my only remaining complaint is somewhat minor, you don't need to
resend this patch; I'll have a look at the importer later (or maybe
someone else gets to do that in between), but I won't cover the package
definitions for the mods.  If they work for you and you checked the
licenses, they're probably going to be fine.

Greetings





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-02 15:50   ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
@ 2021-08-05 16:41     ` Leo Prikler
  2021-08-07 18:31       ` Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-05 16:41 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> * guix/import/contentdb.scm: New file.
> * guix/scripts/import/contentdb.scm: New file.
> * tests/contentdb.scm: New file.
> * Makefile.am (MODULES, SCM_TESTS): Register them.
> * po/guix/POTFILES.in: Likewise.
> * doc/guix.texi (Invoking guix import): Document it.
> [...]
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 43c248234d..d06c9b73c5 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -11313,6 +11313,31 @@ and generate package expressions for all
> those packages that are not yet
>  in Guix.
>  @end table
>  
> +@item contentdb
> +@cindex ContentDB
> +Import metadata from @uref{https://content.minetest.net, ContentDB}.
> +Information is taken from the JSON-formatted metadata provided
> through
> +@uref{https://content.minetest.net/help/api/, ContentDB's API} and
> +includes most relevant information, including dependencies.  There
> are
> +some caveats, however.  The license information on ContentDB does
> not
> +distinguish between GPLvN-only and GPLvN-or-later.  The commit id is
> +sometimes missing.  The descriptions are in the Markdown format, but
> +Guix uses Texinfo instead.  Texture packs and subgames are
> unsupported.
What is the "commit id"?  Is it the hash?  A tag?  Anything that
resolves to a commit?

Also, since ContentDB sounds fairly generic (a database of content?),
perhaps we ought to call this the "minetest" importer instead?

> [...]
> +;; The ContentDB API is documented at
> +;; <https://content.minetest.net>;.
> +
> +(define %contentdb-api
> +  (make-parameter "https://content.minetest.net/api/"))
> +
> +(define (string-or-false x)
> +  (and (string? x) x))
> +
> +(define (natural-or-false x)
> +  (and (exact-integer? x) (>= x 0) x))
> +
> +;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
> +(define (delete-cr text)
> +  (string-delete #\cr text))
> +
> +;; Minetest package.
> +;;
> +;; API endpoint: /packages/AUTHOR/NAME/
> +(define-json-mapping <package> make-package package?
> +  json->package
> +  (author            package-author) ; string
> +  (creation-date     package-creation-date ; string
> +                     "created_at")
> +  (downloads         package-downloads) ; integer
> +  (forums            package-forums "forums" natural-or-false) ;
> natural | #f
This comment and some others like it seem to simply be repeating
already present information.  Is there a use for them?  Should we
instead provide a third argument on every field to verify/enforce the
type?
> +  (issue-tracker     package-issue-tracker "issue_tracker") ; string
> +  (license           package-license) ; string
> +  (long-description  package-long-description "long_description") ;
> string
> +  (maintainers       package-maintainers ; list of strings
> +                     "maintainers" vector->list)
> +  (media-license     package-media-license "media_license") ; string
> +  (name              package-name) ; string
> +  (provides          package-provides ; list of strings
> +                     "provides" vector->list)
> +  (release           package-release) ; integer
> +  (repository        package-repository "repo" string-or-false) ;
> string | #f
> +  (score             package-score) ; flonum
> +  (screenshots       package-screenshots "screenshots" vector->list) 
> ; list of strings
> +  (short-description package-short-description "short_description")
> ; string
> +  (state             package-state) ; string
> +  (tags              package-tags "tags" vector->list) ; list of
> strings
> +  (thumbnail         package-thumbnail) ; string
> +  (title             package-title) ; string
> +  (type              package-type) ; string
> +  (url               package-url) ; string
> +  (website           package-website "website" string-or-false)) ;
> string | #f
> +
> +(define-json-mapping <release> make-release release?
> +  json->release
> +  (commit               release-commit "commit" string-or-false) ;
> string | #f
> +  (downloads            release-downloads) ; integer
> +  (id                   release-id) ; integer
> +  (max-minetest-version release-max-minetest-version) ; string | #f
> +  (min-minetest-version release-min-minetest-version) ; string | #f
> +  (release-date         release-data) ; string
> +  (title                release-title) ; string
> +  (url                  release-url)) ; string
> +
> +(define-json-mapping <dependency> make-dependency dependency?
> +  json->dependency
> +  (optional? dependency-optional? "is_optional") ; #t | #f
Also known as "boolean".
> +  (name dependency-name) ; string
> +  (packages dependency-packages "packages" vector->list)) ; list of
> strings
> +
> +(define (contentdb-fetch author name)
> +  "Return a <package> record for package NAME by AUTHOR, or #f on
> failure."
> +  (and=> (json-fetch
> +          (string-append (%contentdb-api) "packages/" author "/"
> name "/"))
> +         json->package))
Is there a reason for author and name to be separate keys?  For me it
makes more sense to take AUTHOR/NAME as a singular search string from
users and then perform queries based on that.  If ContentDB allows
searching, we might also resolve NAME to a singular package where
possible and otherwise error out, telling the user to choose one.

> [...]
> +
> +(define (important-dependencies dependencies author name)
> +  (define dependency-list
> +    (assoc-ref dependencies (string-append author "/" name)))
> +  (filter-map
> +   (lambda (dependency)
> +     (and (not (dependency-optional? dependency))
> +          ;; "default" must be provided by the 'subgame' in use
> +          ;; and does not refer to a specific minetest mod.
> +          ;; "doors", "bucket" ... are provided by the default
> minetest
> +          ;; subgame.
> +          (not (member (dependency-name dependency)
> +                       '("default" "doors" "beds" "bucket" "doors"
> "farming"
> +                         "flowers" "stairs" "xpanes")))
> +          ;; Dependencies often have only one implementation.
> +          (let* ((/name (string-append "/" (dependency-name
> dependency)))
> +                 (likewise-named-implementations
> +                  (filter (cut string-suffix? /name <>)
> +                          (dependency-packages dependency)))
> +                 (implementation
> +                  (and (not (null? likewise-named-implementations))
> +                       (first likewise-named-implementations))))
> +            (and implementation
> +                 (apply cons (string-split implementation #\/))))))
> +   dependency-list))
What exactly does the likewise-named-implementations bit do here?

> +(define (contentdb-recursive-import author name)
> +  ;; recursive-import expects upstream package names to be strings,
> +  ;; so do some conversions.
> +  (define (split-author/name author/name)
> +    (string-split author/name #\/))
+1 for my author/name splitting, as it's already required for recursive
imports.
> +  (define (author+name->author/name author+name)
> +    (string-append (car author+name) "/" (cdr author+name)))
> +  (define* (contentdb->guix-package* author/name #:key repo version)
> +    (receive (package . maybe-dependencies)
> +        (apply contentdb->guix-package (split-author/name
> author/name))
> +      (and package
> +           (receive (dependencies)
> +               (apply values maybe-dependencies)
> +             (values package
> +                     (map author+name->author/name
> dependencies))))))
> +  (recursive-import (author+name->author/name (cons author name))
> +                    #:repo->guix-package contentdb->guix-package*
> +                    #:guix-name
> +                    (lambda (author/name)
> +                      (contentdb->package-name
> +                       (second (split-author/name author/name))))))
> +
> +;; A list of license names is available at
> +;; <https://content.minetest.net/api/licenses/>;.
> +(define (string->license str)
> +  "Convert the string STR into a license object."
> +  (match str
> +    ("GPLv3"        license:gpl3)
> +    ("GPLv2"        license:gpl2)
> +    ("ISC"          license:isc)
> +    ;; "MIT" means the Expat license on ContentDB,
> +    ;; see <
> https://github.com/minetest/contentdb/issues/326#issuecomment-890143784>
> ;.
> +    ("MIT"          license:expat)
> +    ("CC BY-SA 3.0" license:cc-by-sa3.0)
> +    ("CC BY-SA 4.0" license:cc-by-sa4.0)
> +    ("LGPLv2.1"     license:lgpl2.1)
> +    ("LGPLv3"       license:lgpl3)
> +    ("MPL 2.0"      license:mpl2.0)
> +    ("ZLib"         license:zlib)
> +    ("Unlicense"    license:unlicense)
> +    (_ #f)))
The link mentions, that ContentDB now supports all SPDX identifiers. 
Do we have a SPDX->Guix converter lying around in some other importer
that we could use as default case here (especially w.r.t. "or later")

WDYT?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 00/20] Add minetest mods
  2021-08-05 12:46 ` [bug#49828] [PATCH 00/20] Add minetest mods Andrew Ward
@ 2021-08-05 21:10   ` Maxime Devos
  0 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-05 21:10 UTC (permalink / raw)
  To: Andrew Ward, 49828

[-- Attachment #1: Type: text/plain, Size: 3604 bytes --]

Hi,

Andrew Ward schreef op do 05-08-2021 om 13:46 [+0100]:
> Hi, I'm a Minetest core dev and the creator of ContentDB (the service the powers
> the built-in mod/game/etc manager in Minetest).
> 
> It's very annoying when distros include mods but then never update them.
> It causes confusion with users, as mods change over time and there can be breakages.
> So, I'd like to make sure that these packages are kept in sync with ContentDB.

When the mod is being ‘built’ in Guix, the 'check' phase will start Minetest
with a new world where the mod and its dependencies are activated.  It is verified
there are no errors in the log.  That should help with detecting breakage.
It actually detected some breakage: ".mts" files were not being installed, leading
to errors at load time.  This is fixed now.

To keep in sync, there is "guix refresh minetest-MODA minetest-MODB ..." which
can automatically upgrade packages to the latest version.  It currently doesn't
know about ContentDB however, so it has to fall-back to the generic updaters
which do not appear to work well with Minetest mods:

gnu/packages/minetest.scm:345:13: 1.3 is already the latest version of minetest-worldedit
gnu/packages/minetest.scm:365:2: warning: no updater for minetest-unifieddyes
gnu/packages/minetest.scm:173:2: warning: no updater for minetest-mobs
gnu/packages/minetest.scm:143:13: minetest-mesecons would be upgraded from 1.2.1-0.db58797 to 2017.03.05
   ^ this is actually a downgrade IIRC
gnu/packages/minetest.scm:227:2: warning: no updater for minetest-pipeworks

Hopefully that can be improved in the future (maybe keep the "release date" in
the 'properties' field of the Guix package and use that to determine if an update
is available?).

> ContentDB also provides two other features: it only provides you with versions of
> mods/games that support your Minetest version. It also handles dependencies, so I
> hope this is set up correctly.

The ContentDB->guix importer handles dependencies.  It reads the dependencies
from ContentDB (with the /api/packages/AUTHOR/NAME/dependencies/ API) and
adds the hard dependencies to 'propagated-inputs', so "minetest-mobs-animal"
has "minetest-mobs" in its 'propagated-inputs'.  See also the 'check' phase
mentioned above.

> If you are disabling ContentDB completely, you should have the vast majority of mods,
> games, and texture packs available - especially all the hard dependencies needed, as
> not having these will cause load issues. Minetest is all about customisation.

In the original patch series I sent, ContentDB was indeed disabled completely when
guix-installed mods are present.  But with the revised patch (using the MINETEST_MOD_PATH
patch I submitted <https://github.com/minetest/minetest/pull/11515>), this is no
longer the case --- ContentDB and Guix can be used together.

I tested installing mods with both Minetest's built-in installer and guix.  They can
be used together.

> I recommend adding a button and core.open_url call to the guix dialog that replaces
> the content store. It should link to a page describing how to install mods using guix,
> and how to allow use of ContentDB again if the user desires

ContentDB and mods installed with guix can be used together with the revised patches.
It would be useful though to add some kind of dialog or something, telling the user
that mods can be installed with guix, and how to do so.

> Anyway, sorry for being critical - it's great to see more distro support and integration

Greetings,
Maxime (aka maximed aka emixa-d).

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-05 16:41     ` Leo Prikler
@ 2021-08-07 18:31       ` Maxime Devos
  2021-08-07 19:47         ` Leo Prikler
  0 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-07 18:31 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 8450 bytes --]

Leo Prikler schreef op do 05-08-2021 om 18:41 [+0200]:
> Hi,
> 
> Am Montag, den 02.08.2021, 17:50 +0200 schrieb Maxime Devos:
> > * guix/import/contentdb.scm: New file.
> > * guix/scripts/import/contentdb.scm: New file.
> > * tests/contentdb.scm: New file.
> > * Makefile.am (MODULES, SCM_TESTS): Register them.
> > * po/guix/POTFILES.in: Likewise.
> > * doc/guix.texi (Invoking guix import): Document it.
> > [...]
> > diff --git a/doc/guix.texi b/doc/guix.texi
> > index 43c248234d..d06c9b73c5 100644
> > --- a/doc/guix.texi
> > +++ b/doc/guix.texi
> > @@ -11313,6 +11313,31 @@ and generate package expressions for all
> > those packages that are not yet
> >  in Guix.
> >  @end table
> >  
> > +@item contentdb
> > +@cindex ContentDB
> > +Import metadata from @uref{https://content.minetest.net, ContentDB}.
> > +Information is taken from the JSON-formatted metadata provided
> > through
> > +@uref{https://content.minetest.net/help/api/, ContentDB's API} and
> > +includes most relevant information, including dependencies.  There
> > are
> > +some caveats, however.  The license information on ContentDB does
> > not
> > +distinguish between GPLvN-only and GPLvN-or-later.

ContentDB uses SPDX license identifiers now, and distinguishes between
GPL-N-only and GPL-N-or-later, so I adjusted the documentation appropriately.

> >   The commit id is
> > +sometimes missing.  The descriptions are in the Markdown format, but
> > +Guix uses Texinfo instead.  Texture packs and subgames are
> > unsupported.
> What is the "commit id"?  Is it the hash?  A tag?  Anything that
> resolves to a commit?

It's the SHA-1 of the Git commit.  I changes this to ‘the commit's SHA-1’.

> Also, since ContentDB sounds fairly generic (a database of content?),
> perhaps we ought to call this the "minetest" importer instead?

Technically, minetest has another mod repository as well:
<https://bower.minetest.org/>.  It's unmoderated though, and
<https://content.minetest.net> has some moderation and seems more
‘official’ (it's integrated in Minetest itself).  I replaced
(guix import contentdb) with (guix import minetest), likewise
for (guix script import minetest) and tests/minetest.scm.

> > +;; Minetest package.
> > +;;
> > +;; API endpoint: /packages/AUTHOR/NAME/
> > +(define-json-mapping <package> make-package package?
> > +  json->package
> > +  (author            package-author) ; string
> > +  (creation-date     package-creation-date ; string
> > +                     "created_at")
> > +  (downloads         package-downloads) ; integer
> > +  (forums            package-forums "forums" natural-or-false) ;
> > natural | #f
> This comment and some others like it seem to simply be repeating
> already present information.  Is there a use for them?  Should we
> instead provide a third argument on every field to verify/enforce the
> type?

I first added the ‘; natural-or-false’.  I only added the procedure
"natural-false" later.  Indeed, ‘; natural-or-false’ is redundant.
I removed the redundant ones in the revised patch.

I don't think there is need to verify types for each field.
Most aren't used by Guix.  If a type check would fail, that would
presumably mean the type check guix is incorrect (or not up-to-date).
Except for perhaps a backtrace, ill-typed fields are harmless.

> > +(define (contentdb-fetch author name)
> > +  "Return a <package> record for package NAME by AUTHOR, or #f on
> > failure."
> > +  (and=> (json-fetch
> > +          (string-append (%contentdb-api) "packages/" author "/"
> > name "/"))
> > +         json->package))
> Is there a reason for author and name to be separate keys?  For me it
> makes more sense to take AUTHOR/NAME as a singular search string from
> users and then perform queries based on that.

Not really actually, AUTHOR tends to go togehter with NAME except for
some exceptions.  I modified the code such that AUTHOR/NAME is a single
string.  It simplified code somewhat.

>   If ContentDB allows
> searching, we might also resolve NAME to a singular package where
> possible and otherwise error out, telling the user to choose one.

ContentDB allows searching.  I wrote some a procedure 'elaborate-contentdb-name'
used by (guix scripts import contentdb) that resolves "mesecons" to "Jeija/mesecons",
using the search API and added some tests.  If there are multiple candidates,
the one with the highest ‘score’ is choosen (alternatively, --sort=downloads can
be used instead).

> > +(define (important-dependencies dependencies author name)
> > +  (define dependency-list
> > +    (assoc-ref dependencies (string-append author "/" name)))
> > +  (filter-map
> > +   (lambda (dependency)
> > +     (and (not (dependency-optional? dependency))
> > +          ;; "default" must be provided by the 'subgame' in use
> > +          ;; and does not refer to a specific minetest mod.
> > +          ;; "doors", "bucket" ... are provided by the default
> > minetest
> > +          ;; subgame.
> > +          (not (member (dependency-name dependency)
> > +                       '("default" "doors" "beds" "bucket" "doors"
> > "farming"
> > +                         "flowers" "stairs" "xpanes")))

I tested this some more, and it appears that some mods depend on "dyes",
which is part of the default Minetest game, so I added all the mods
provided by the default (sub?)game.  The list began looking a little
long, so I replaced it with a hash table.

> > +          ;; Dependencies often have only one implementation.
> > +          (let* ((/name (string-append "/" (dependency-name
> > dependency)))
> > +                 (likewise-named-implementations
> > +                  (filter (cut string-suffix? /name <>)
> > +                          (dependency-packages dependency)))
> > +                 (implementation
> > +                  (and (not (null? likewise-named-implementations))
> > +                       (first likewise-named-implementations))))
> > +            (and implementation
> > +                 (apply cons (string-split implementation #\/))))))
> > +   dependency-list))
> What exactly does the likewise-named-implementations bit do here?

The list returned by 'dependency-packages' not only contains the mod
we need, but possibly also various ‘subgames’ that include that mod.
Filtering on '/name' filters out these subgames we don't need.

Also, theoretically another mod could implement the same interface.
The filtering would filter out the alternative implementations.

Anyway, I changes the implementation a bit.  It now explicitely
filters out ‘subgames’ and ‘texture packs’ using the ‘package-mod?’
procedure.  The resulting list tends to consist of only a single
element.  If it consists of multiple, the one with the highest score
(or the one with the highest download count, depending on --sort)
will be choosen (and a warning is printed).

> > +;; A list of license names is available at
> > +;; <https://content.minetest.net/api/licenses/>;;.
> > +(define (string->license str)
> > +  "Convert the string STR into a license object." [...]
> The link mentions, that ContentDB now supports all SPDX identifiers. 
> Do we have a SPDX->Guix converter lying around in some other importer
> that we could use as default case here (especially w.r.t. "or later")

There's a a converter in (guix import utils): spdx-string->license.
The old license identifiers appear to be removed, now only SPDX information
is available.  I modified the code to use spdx->string-license and removed
string->license.

It turns out it does not recognise GPL-N-only and GPL-N-or-later,
so I added a patch ‘import/utils: Recognise GPL-3.0-or-later and friends.’.

I tried implementing "guix refresh -t minetest ...".  It seems to work, but
requires some changes to (guix upstream) that needs some more work, so I left it
out of the revised patch set.  The refresher needs to know the author name
(or perform extra HTTP requests), so I added 'upstream-name' the package properties.

The revised patch series is attached.  It can also be found at
<https://notabug.org/maximed/guix-gnunet/src/minetest-2>.  It includes
the latest MINETEST_MOD_PATH patch.  I'll make the patch to export more things in
(guix build utils) later (for core-updates).

reetings,
Maxime.

[-- Attachment #1.2: 0001-gnu-minetest-Respect-without-tests.patch --]
[-- Type: text/x-patch, Size: 1389 bytes --]

From 292dce14ea4811f1554965d83af5e33687cd00b7 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 14:50:32 +0200
Subject: [PATCH 01/20] gnu: minetest: Respect --without-tests.

* gnu/packages/games.scm
  (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
  of ',(%current-target-system)'. Remove trailing #t.
---
 gnu/packages/games.scm | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 8c6b5523f1..3e7086b398 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3590,13 +3590,12 @@ match, cannon keep, and grave-itation pit.")
                      (string-append (getcwd) "/games")) ; for check
              #t))
          (replace 'check
-           (lambda _
+           (lambda* (#:key tests? #:allow-other-keys)
              ;; Thanks to our substitutions, the tests should also run
              ;; when invoked on the target outside of `guix build'.
-             (unless ,(%current-target-system)
+             (when tests?
                (setenv "HOME" "/tmp")
-               (invoke "src/minetest" "--run-unittests"))
-             #t)))))
+               (invoke "src/minetest" "--run-unittests")))))))
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-- 
2.32.0


[-- Attachment #1.3: 0002-gnu-minetest-Search-for-mods-in-MINETEST_MOD_PATH.patch --]
[-- Type: text/x-patch, Size: 8409 bytes --]

From 54222f167107e36cb76f93c551aaee0659d17b40 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 18:08:44 +0200
Subject: [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.

* gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch:
  New file.
* gnu/packages/games.scm
  (minetest)[source]{patches}: Add it.
  (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/games.scm                        |   8 +-
 ...vironment-variable-MINETEST_MOD_PATH.patch | 156 ++++++++++++++++++
 3 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c80a9af78c..d96d4e3dbc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -801,6 +801,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
   %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
   %D%/packages/patches/adb-add-libraries.patch			\
+  %D%/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch	\
   %D%/packages/patches/aegis-constness-error.patch         	\
   %D%/packages/patches/aegis-perl-tempdir1.patch           	\
   %D%/packages/patches/aegis-perl-tempdir2.patch           	\
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 3e7086b398..48d46a0379 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3553,6 +3553,9 @@ match, cannon keep, and grave-itation pit.")
                (base32
                 "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8"))
               (modules '((guix build utils)))
+              (patches
+               (search-patches
+                "Add-environment-variable-MINETEST_MOD_PATH.patch"))
               (snippet
                '(begin
                   ;; Delete bundled libraries.
@@ -3599,7 +3602,10 @@ match, cannon keep, and grave-itation pit.")
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-            (files '("share/minetest/games")))))
+            (files '("share/minetest/games")))
+           (search-path-specification
+            (variable "MINETEST_MOD_PATH")
+            (files '("share/minetest/mods")))))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (inputs
diff --git a/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
new file mode 100644
index 0000000000..a74034a2c5
--- /dev/null
+++ b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
@@ -0,0 +1,156 @@
+From d10ea2ad7efc2364a8a2007b4c6d3e85511e2f84 Mon Sep 17 00:00:00 2001
+From: Maxime Devos <maximedevos@telenet.be>
+Date: Tue, 3 Aug 2021 01:00:23 +0200
+Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
+
+This adds an environment variable MINETEST_MOD_PATH.
+When it exists, Minetest will look there for mods
+in addition to ~/.minetest/mods/.  Mods can still be
+installed to ~/.minetest/mods/ with the built-in installer.
+
+With thanks to Leo Prikler.
+---
+ builtin/mainmenu/pkgmgr.lua       |  7 +++----
+ doc/menu_lua_api.txt              |  8 +++++++-
+ src/content/subgames.cpp          | 11 +++++++++++
+ src/script/lua_api/l_mainmenu.cpp | 23 +++++++++++++++++++++++
+ src/script/lua_api/l_mainmenu.h   |  2 ++
+ 5 files changed, 46 insertions(+), 5 deletions(-)
+
+diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
+index 787936e31..d8fba0ebe 100644
+--- a/builtin/mainmenu/pkgmgr.lua
++++ b/builtin/mainmenu/pkgmgr.lua
+@@ -682,10 +682,9 @@ function pkgmgr.preparemodlist(data)
+ 	local game_mods = {}
+ 
+ 	--read global mods
+-	local modpath = core.get_modpath()
+-
+-	if modpath ~= nil and
+-		modpath ~= "" then
++	local modpaths = core.get_modpaths()
++	--XXX what was ‘modpath ~= ""’ and ‘modpath ~= nil’ for?
++	for _,modpath in ipairs(modpaths) do
+ 		get_mods(modpath,global_mods)
+ 	end
+ 
+diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
+index b3975bc1d..132444b14 100644
+--- a/doc/menu_lua_api.txt
++++ b/doc/menu_lua_api.txt
+@@ -218,7 +218,13 @@ Package - content which is downloadable from the content db, may or may not be i
+     * returns path to global user data,
+       the directory that contains user-provided mods, worlds, games, and texture packs.
+ * core.get_modpath() (possible in async calls)
+-    * returns path to global modpath
++    * returns path to global modpath, where mods can be installed
++* core.get_modpaths() (possible in async calls)
++    * returns list of paths to global modpaths, where mods have been installed
++
++      The difference with "core.get_modpath" is that no mods should be installed in these
++      directories by Minetest -- they might be read-only.
++
+ * core.get_clientmodpath() (possible in async calls)
+     * returns path to global client-side modpath
+ * core.get_gamepath() (possible in async calls)
+diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
+index e9dc609b0..d73f95a1f 100644
+--- a/src/content/subgames.cpp
++++ b/src/content/subgames.cpp
+@@ -61,6 +61,12 @@ std::string getSubgamePathEnv()
+ 	return subgame_path ? std::string(subgame_path) : "";
+ }
+ 
++std::string getModPathEnv()
++{
++	char *mod_path = getenv("MINETEST_MOD_PATH");
++	return mod_path ? std::string(mod_path) : "";
++}
++
+ SubgameSpec findSubgame(const std::string &id)
+ {
+ 	if (id.empty())
+@@ -110,6 +116,11 @@ SubgameSpec findSubgame(const std::string &id)
+ 	std::set<std::string> mods_paths;
+ 	if (!user_game)
+ 		mods_paths.insert(share + DIR_DELIM + "mods");
++
++	Strfnd mod_search_paths(getModPathEnv());
++	while (!mod_search_paths.at_end())
++		mods_paths.insert(mod_search_paths.next(PATH_DELIM));
++
+ 	if (user != share || user_game)
+ 		mods_paths.insert(user + DIR_DELIM + "mods");
+ 
+diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
+index 3e9709bde..903ac3a22 100644
+--- a/src/script/lua_api/l_mainmenu.cpp
++++ b/src/script/lua_api/l_mainmenu.cpp
+@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ #include "lua_api/l_internal.h"
+ #include "common/c_content.h"
+ #include "cpp_api/s_async.h"
++#include "util/strfnd.h"
+ #include "gui/guiEngine.h"
+ #include "gui/guiMainMenu.h"
+ #include "gui/guiKeyChangeMenu.h"
+@@ -502,6 +503,26 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
+ 	return 1;
+ }
+ 
++/******************************************************************************/
++int ModApiMainMenu::l_get_modpaths(lua_State *L)
++{
++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
++	if (c_modpath == NULL)
++		c_modpath = "";
++	int index = 1;
++	lua_newtable(L);
++	Strfnd mod_search_paths{std::string(c_modpath)};
++	while (!mod_search_paths.at_end()) {
++		std::string component = mod_search_paths.next(PATH_DELIM);
++		lua_pushstring(L, component.c_str());
++		lua_rawseti(L, -2, index);
++		index++;
++	}
++	ModApiMainMenu::l_get_modpath(L);
++	lua_rawseti(L, -2, index);
++	return 1;
++}
++
+ /******************************************************************************/
+ int ModApiMainMenu::l_get_clientmodpath(lua_State *L)
+ {
+@@ -949,6 +970,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+@@ -983,6 +1005,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
+index 33ac9e721..a6a54a2cb 100644
+--- a/src/script/lua_api/l_mainmenu.h
++++ b/src/script/lua_api/l_mainmenu.h
+@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
+ 
+ 	static int l_get_modpath(lua_State *L);
+ 
++	static int l_get_modpaths(lua_State *L);
++
+ 	static int l_get_clientmodpath(lua_State *L);
+ 
+ 	static int l_get_gamepath(lua_State *L);
+-- 
+2.32.0
+
-- 
2.32.0


[-- Attachment #1.4: 0003-gnu-minetest-New-package-module.patch --]
[-- Type: text/x-patch, Size: 2531 bytes --]

From f5148ad853b113db84634912c3eaa936d689eb22 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 18:32:50 +0200
Subject: [PATCH 03/20] gnu: minetest: New package module.

Aside from the 'minetest-topic' procedure which will be used
for the 'home-page' field of some packages, this module is
currently empty.  The 'contentdb' importer defined in the
following patches will be used to populate this module.

* gnu/packages/minetest.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk              |  1 +
 gnu/packages/minetest.scm | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 gnu/packages/minetest.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index d96d4e3dbc..5de08b1b09 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -383,6 +383,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/mercury.scm			\
   %D%/packages/mes.scm				\
   %D%/packages/messaging.scm			\
+  %D%/packages/minetest.scm			\
   %D%/packages/mingw.scm			\
   %D%/packages/microcom.scm			\
   %D%/packages/moe.scm				\
diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
new file mode 100644
index 0000000000..f8aca3005c
--- /dev/null
+++ b/gnu/packages/minetest.scm
@@ -0,0 +1,26 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+(define-module (gnu packages minetest)
+  #:use-module (guix packages)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system minetest)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public (minetest-topic topic-id)
+  "Return an URL (as a string) pointing to the forum topic with
+numeric identifier TOPIC-ID on the official Minetest forums."
+  (string-append "https://forum.minetest.net/viewtopic.php?t="
+                 (number->string topic-id)))
-- 
2.32.0


[-- Attachment #1.5: 0004-build-system-Add-minetest-mod-build-system.patch --]
[-- Type: text/x-patch, Size: 16130 bytes --]

From 93aa8e1976e762d30be70aef6d5c50b1d06ca4be Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 13:52:39 +0200
Subject: [PATCH 04/20] build-system: Add 'minetest-mod-build-system'.

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  99 ++++++++++++
 guix/build/minetest-build-system.scm | 225 +++++++++++++++++++++++++++
 4 files changed, 334 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..d44ecc2005 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying Lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..f33e97559d
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,99 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys
+                    #:rest arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         (substitute-keyword-arguments arguments
+           ;; minetest-mod-build-system adds implicit inputs by itself,
+           ;; so don't let gnu-build-system add its own implicit inputs
+           ;; as well.
+           ((#:implicit-inputs? implicit-inputs? #t)
+            #f)
+           ((#:implicit-cross-inputs? implicit-cross-inputs? #t)
+            #f)
+           ((#:imported-modules imported-modules %minetest-build-system-modules)
+            imported-modules)
+           ((#:modules modules %default-modules)
+            modules)
+           ((#:phases phases '%standard-phases)
+            phases)
+           ;; Ensure nothing sneaks into the closure.
+           ((#:allowed-references allowed-references '())
+            allowed-references)
+           ;; Add the implicit inputs.
+           ((#:native-inputs native-inputs '())
+            (if implicit-inputs?
+                (append native-inputs (standard-minetest-packages))
+                native-inputs)))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..b051d9c288
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,225 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module ((guix build copy-build-system) #:prefix copy:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+;; (guix build copy-build-system) does not export 'install'.
+(define copy:install
+  (assoc-ref copy:%standard-phases 'install))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make the guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           (file-name (basename source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-minetest")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply copy:install
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimise."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0


[-- Attachment #1.6: 0005-import-utils-Recognise-GPL-3.0-or-later-and-friends.patch --]
[-- Type: text/x-patch, Size: 3318 bytes --]

From 9858d43e51cdfdbf4ca022399469d99f437bf596 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Thu, 5 Aug 2021 21:00:41 +0200
Subject: [PATCH 05/20] import/utils: Recognise GPL-3.0-or-later and friends.

* guix/import/utils.scm (spdx-string->license): Recognise
  GPL-N-only and GPL-N-or-later.  Likewise for LGPL and AGPL.
---
 guix/import/utils.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index d817318a91..d1b8076ddd 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -133,8 +133,14 @@ of the string VERSION is replaced by the symbol 'version."
   ;; Please update guix/licenses.scm when modifying
   ;; this list to avoid mismatches.
   (match str
+    ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later".
+    ;; "GPL-N" has been deprecated in favour of "GPL-N-only"
+    ;; or "GPL-N-or-later" as appropriate.  Likewise for LGPL
+    ;; and AGPL
     ("AGPL-1.0"                    'license:agpl1)
     ("AGPL-3.0"                    'license:agpl3)
+    ("AGPL-3.0-only"               'license:agpl3)
+    ("AGPL-3.0-or-later"           'license:agpl3+)
     ("Apache-1.1"                  'license:asl1.1)
     ("Apache-2.0"                  'license:asl2.0)
     ("BSL-1.0"                     'license:boost1.0)
@@ -161,11 +167,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("GFDL-1.3"                    'license:fdl1.3+)
     ("Giftware"                    'license:giftware)
     ("GPL-1.0"                     'license:gpl1)
+    ("GPL-1.0-only"                'license:gpl1)
     ("GPL-1.0+"                    'license:gpl1+)
+    ("GPL-1.0-or-later"            'license:gpl1+)
     ("GPL-2.0"                     'license:gpl2)
+    ("GPL-2.0-only"                'license:gpl2)
     ("GPL-2.0+"                    'license:gpl2+)
+    ("GPL-2.0-or-later"            'license:gpl2+)
     ("GPL-3.0"                     'license:gpl3)
+    ("GPL-3.0-only"                'license:gpl3)
     ("GPL-3.0+"                    'license:gpl3+)
+    ("GPL-3.0-or-later"            'license:gpl3+)
     ("ISC"                         'license:isc)
     ("IJG"                         'license:ijg)
     ("Imlib2"                      'license:imlib2)
@@ -173,11 +185,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("IPL-1.0"                     'license:ibmpl1.0)
     ("LAL-1.3"                     'license:lal1.3)
     ("LGPL-2.0"                    'license:lgpl2.0)
+    ("LGPL-2.0-only"               'license:lgpl2.0)
     ("LGPL-2.0+"                   'license:lgpl2.0+)
+    ("LGPL-2.0-or-later"           'license:lgpl2.0+)
     ("LGPL-2.1"                    'license:lgpl2.1)
+    ("LGPL-2.1-only"               'license:lgpl2.1)
     ("LGPL-2.1+"                   'license:lgpl2.1+)
+    ("LGPL-2.1-or-later"           'license:lgpl2.1+)
     ("LGPL-3.0"                    'license:lgpl3)
+    ("LGPL-3.0-only"               'license:lgpl3)
     ("LGPL-3.0+"                   'license:lgpl3+)
+    ("LGPL-3.0-or-later"           'license:lgpl3+)
     ("MPL-1.0"                     'license:mpl1.0)
     ("MPL-1.1"                     'license:mpl1.1)
     ("MPL-2.0"                     'license:mpl2.0)
-- 
2.32.0


[-- Attachment #1.7: 0006-guix-Add-ContentDB-importer.patch --]
[-- Type: text/x-patch, Size: 43084 bytes --]

From 1ea774e7ff007e60cf612f4f74f656be3de9f1f3 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 14:44:11 +0200
Subject: [PATCH 06/20] guix: Add ContentDB importer.

* guix/import/contentdb.scm: New file.
* guix/scripts/import/contentdb.scm: New file.
* tests/contentdb.scm: New file.
* Makefile.am (MODULES, SCM_TESTS): Register them.
* po/guix/POTFILES.in: Likewise.
* doc/guix.texi (Invoking guix import): Document it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  32 +++
 guix/import/minetest.scm         | 467 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/minetest.scm | 117 ++++++++
 po/guix/POTFILES.in              |   1 +
 tests/minetest.scm               | 355 +++++++++++++++++++++++
 7 files changed, 977 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/minetest.scm
 create mode 100644 guix/scripts/import/minetest.scm
 create mode 100644 tests/minetest.scm

diff --git a/Makefile.am b/Makefile.am
index f4439ce93b..6243583616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -262,6 +262,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/minetest.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
   guix/import/pypi.scm				\
@@ -304,6 +305,7 @@ MODULES =					\
   guix/scripts/import/go.scm			\
   guix/scripts/import/hackage.scm		\
   guix/scripts/import/json.scm  		\
+  guix/scripts/import/minetest.scm  		\
   guix/scripts/import/opam.scm			\
   guix/scripts/import/pypi.scm			\
   guix/scripts/import/stackage.scm		\
@@ -470,6 +472,7 @@ SCM_TESTS =					\
   tests/import-utils.scm			\
   tests/inferior.scm				\
   tests/lint.scm				\
+  tests/minetest.scm				\
   tests/modules.scm				\
   tests/monads.scm				\
   tests/nar.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index d44ecc2005..47861047eb 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -11314,6 +11314,38 @@ and generate package expressions for all those packages that are not yet
 in Guix.
 @end table
 
+@item contentdb
+@cindex minetest
+@cindex ContentDB
+Import metadata from @uref{https://content.minetest.net, ContentDB}.
+Information is taken from the JSON-formatted metadata provided through
+@uref{https://content.minetest.net/help/api/, ContentDB's API} and
+includes most relevant information, including dependencies.  There are
+some caveats, however.  The license information is often incomplete.
+The commit's SHA-1 is sometimes missing.  The descriptions are in the
+Markdown format, but Guix uses Texinfo instead.  Texture packs and
+subgames are unsupported.
+
+The command below imports metadata for the Mesecons mod by Jeija:
+
+@example
+guix import minetest Jeija/mesecons
+@end example
+
+The author name can also be left out:
+
+@example
+guix import minetest mesecons
+@end example
+
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
 @item cpan
 @cindex CPAN
 Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}.
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
new file mode 100644
index 0000000000..5728f4613a
--- /dev/null
+++ b/guix/import/minetest.scm
@@ -0,0 +1,467 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import minetest)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 threads)
+  #:use-module (ice-9 hash-table)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix utils)
+  #:use-module (guix ui)
+  #:use-module (guix i18n)
+  #:use-module (guix memoization)
+  #:use-module (guix serialization)
+  #:use-module (guix import utils)
+  #:use-module (guix import json)
+  #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256))
+  #:use-module (json)
+  #:use-module (guix base32)
+  #:use-module (guix git)
+  #:use-module (guix store)
+  #:export (%default-sort-key
+            %contentdb-api
+            json->package
+            contentdb-fetch
+            elaborate-contentdb-name
+            minetest->guix-package
+            minetest-recursive-import
+            sort-packages))
+
+;; The ContentDB API is documented at
+;; <https://content.minetest.net>.
+
+(define %contentdb-api
+  (make-parameter "https://content.minetest.net/api/"))
+
+(define (string-or-false x)
+  (and (string? x) x))
+
+(define (natural-or-false x)
+  (and (exact-integer? x) (>= x 0) x))
+
+;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
+(define (delete-cr text)
+  (string-delete #\cr text))
+
+\f
+
+;;;
+;;; JSON mappings
+;;;
+
+;; Minetest package.
+;;
+;; API endpoint: /packages/AUTHOR/NAME/
+(define-json-mapping <package> make-package package?
+  json->package
+  (author            package-author) ; string
+  (creation-date     package-creation-date ; string
+                     "created_at")
+  (downloads         package-downloads) ; integer
+  (forums            package-forums "forums" natural-or-false)
+  (issue-tracker     package-issue-tracker "issue_tracker") ; string
+  (license           package-license) ; string
+  (long-description  package-long-description "long_description") ; string
+  (maintainers       package-maintainers ; list of strings
+                     "maintainers" vector->list)
+  (media-license     package-media-license "media_license") ; string
+  (name              package-name) ; string
+  (provides          package-provides ; list of strings
+                     "provides" vector->list)
+  (release           package-release) ; integer
+  (repository        package-repository "repo" string-or-false)
+  (score             package-score) ; flonum
+  (screenshots       package-screenshots "screenshots" vector->list) ; list of strings
+  (short-description package-short-description "short_description") ; string
+  (state             package-state) ; string
+  (tags              package-tags "tags" vector->list) ; list of strings
+  (thumbnail         package-thumbnail) ; string
+  (title             package-title) ; string
+  (type              package-type) ; string
+  (url               package-url) ; string
+  (website           package-website "website" string-or-false))
+
+(define-json-mapping <release> make-release release?
+  json->release
+  ;; If present, a git commit identified by its hash
+  (commit               release-commit "commit" string-or-false)
+  (downloads            release-downloads) ; integer
+  (id                   release-id) ; integer
+  (max-minetest-version release-max-minetest-version string-or-false)
+  (min-minetest-version release-min-minetest-version string-or-false)
+  (release-date         release-data) ; string
+  (title                release-title) ; string
+  (url                  release-url)) ; string
+
+(define-json-mapping <dependency> make-dependency dependency?
+  json->dependency
+  (optional? dependency-optional? "is_optional") ; bool
+  (name dependency-name) ; string
+  (packages dependency-packages "packages" vector->list)) ; list of strings
+
+;; A structure returned by the /api/packages/?fmt=keys endpoint
+(define-json-mapping <package/keys> make-package/keys package/keys?
+  json->package/keys
+  (author package/keys-author) ; string
+  (name package/keys-name)     ; string
+  (type package/keys-type))    ; string
+
+(define (package-mod? package)
+  "Is the ContentDB package PACKAGE a mod?"
+  ;; ContentDB also has ‘games’ and ‘texture packs’.
+  (string=? (package-type package) "mod"))
+
+\f
+
+;;;
+;;; Manipulating names of packages
+;;;
+;;; There are three kind of names:
+;;;
+;;;   * names of guix packages, e.g. minetest-basic-materials.
+;;;   * names of mods on ContentDB, e.g. basic_materials
+;;;   * a combination of author and mod name on ContentDB, e.g. VanessaE/basic_materials
+;;;
+
+(define (package-author/name package)
+  "Given a <package> object, return the corresponding AUTHOR/NAME string."
+  (string-append (package-author package) "/" (package-name package)))
+
+(define (package/keys-author/name package)
+  "Given a <package/keys> object, return the corresponding AUTHOR/NAME string."
+  (string-append (package/keys-author package)
+                 "/" (package/keys-name package)))
+
+(define (contentdb->package-name name)
+  "Given the NAME of a package on ContentDB, return a Guix-compliant name for the
+package."
+  ;; The author is not included, as the names of popular mods
+  ;; tend to be unique.
+  (string-append "minetest-" (snake-case name)))
+
+(define (author/name->name author/name)
+  "Extract NAME from the AUTHOR/NAME string, or raise an error if AUTHOR/NAME
+is ill-formatted."
+  (match (string-split author/name #\/)
+    ((author name)
+     (when (string-null? author)
+       (leave
+        (G_ "In ~a: author names must consist of at least a single character.~%")
+        author/name))
+     (when (string-null? name)
+       (leave
+        (G_ "In ~a: mod names must consist of at least a single character.~%")
+        author/name))
+     name)
+    ((too many . components)
+     (leave
+      (G_ "In ~a: author names and mod names may not contain forward slashes.~%")
+      author/name))
+    ((name)
+     (if (string-null? name)
+         (leave (G_ "mod names may not be empty.~%"))
+         (leave (G_ "The name of the author is missing in ~a.~%")
+                author/name)))))
+
+(define* (elaborate-contentdb-name name #:key (sort %default-sort-key))
+  "If NAME is an AUTHOR/NAME string, return it.  Otherwise, try to determine
+the author and return an appropriate AUTHOR/NAME string.  If that fails,
+raise an exception."
+  (if (or (string-contains name "/") (string-null? name))
+      ;; Call 'author/name->name' to verify that NAME seems reasonable
+      ;; and raise an appropriate exception if it isn't.
+      (begin
+        (author/name->name name)
+        name)
+      (let* ((package/keys (contentdb-query-packages name #:sort sort))
+             (correctly-named
+              (filter (lambda (package/key)
+                        (string=? name (package/keys-name package/key)))
+                      package/keys)))
+        (match correctly-named
+          ((one) (package/keys-author/name one))
+          ((too . many)
+           (warning (G_ "~a is ambigious, presuming ~a (other options include: ~a)~%")
+                    name (package/keys-author/name too)
+                    (map package/keys-author/name many))
+           (package/keys-author/name too))
+          (()
+           (leave (G_ "No mods with name ~a were found.~%") name))))))
+
+\f
+
+;;;
+;;; API endpoints
+;;;
+
+(define contentdb-fetch
+  (mlambda (author/name)
+    "Return a <package> record for package AUTHOR/NAME, or #f on failure."
+    (and=> (json-fetch
+            (string-append (%contentdb-api) "packages/" author/name "/"))
+           json->package)))
+
+(define (contentdb-fetch-releases author/name)
+  "Return a list of <release> records for package NAME by AUTHOR, or #f
+on failure."
+  (and=> (json-fetch (string-append (%contentdb-api) "packages/" author/name
+                                    "/releases/"))
+         (lambda (json)
+           (map json->release (vector->list json)))))
+
+(define (latest-release author/name)
+  "Return the latest source release for package NAME by AUTHOR,
+or #f if this package does not exist."
+  (and=> (contentdb-fetch-releases author/name)
+         car))
+
+(define (contentdb-fetch-dependencies author/name)
+  "Return an alist of lists of <dependency> records for package NAME by AUTHOR
+and possibly some other packages as well, or #f on failure."
+  (define url (string-append (%contentdb-api) "packages/" author/name
+                             "/dependencies/"))
+  (and=> (json-fetch url)
+         (lambda (json)
+           (map (match-lambda
+                  ((key . value)
+                   (cons key (map json->dependency (vector->list value)))))
+                json))))
+
+(define* (contentdb-query-packages q #:key
+                                   (type "mod")
+                                   (limit 50)
+                                   (sort %default-sort-key)
+                                   (order "desc"))
+  "Search ContentDB for Q (a string).  Sort by SORT, in ascending order
+if ORDER is \"asc\" or descending order if ORDER is \"desc\".  TYPE must
+be \"mod\", \"game\" or \"txp\", restricting thes search results to
+respectively mods, games and texture packs.  Limit to at most LIMIT
+results.  The return value is a list of <package/keys> records."
+  ;; XXX does Guile have something for constructing (and, when necessary,
+  ;; escaping) query strings?
+  (define url (string-append (%contentdb-api) "packages/?type=" type
+                             "&q=" q "&fmt=keys"
+                             "&limit=" (number->string limit)
+                             "&order=" order
+                             "&sort=" sort))
+  (let ((json (json-fetch url)))
+    (if json
+        (map json->package/keys (vector->list json))
+        (leave
+         (G_ "The package search API doesn't exist anymore.~%")))))
+
+\f
+
+;; XXX copied from (guix import elpa)
+(define* (download-git-repository url ref)
+  "Fetch the given REF from the Git repository at URL."
+  (with-store store
+    (latest-repository-commit store url #:ref ref)))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+;; XXX likewise.
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (make-minetest-sexp author/name version repository commit
+                            inputs home-page synopsis
+                            description media-license license)
+  "Return a S-expression for the minetest package with the given author/NAME,
+VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
+MEDIA-LICENSE and LICENSE."
+  `(package
+     (name ,(contentdb->package-name (author/name->name author/name)))
+     (version ,version)
+     (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+                (url ,repository)
+                (commit ,commit)))
+         (sha256
+          (base32
+           ;; The git commit is not always available.
+           ,(and commit
+                 (bytevector->nix-base32-string
+                  (file-hash
+                   (download-git-repository repository `(commit . ,commit))
+                   (negate vcs-file?) #t)))))
+         (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs
+        (map (compose contentdb->package-name author/name->name) inputs))
+     (home-page ,home-page)
+     (synopsis ,(delete-cr synopsis))
+     (description ,(delete-cr description))
+     (license ,(if (eq? media-license license)
+                   license
+                   `(list ,media-license ,license)))
+     ;; The Minetest updater (not yet in Guix; it requires not-yet-submitted
+     ;; patches to (guix upstream) that require some work) needs to know both
+     ;; the author name and mod name for efficiency.
+     (properties ,(list 'quasiquote `((upstream-name . ,author/name))))))
+
+(define (package-home-page package)
+  "Guess the home page of the ContentDB package PACKAGE.
+
+In order of preference, try the 'website', the forum topic on the
+official Minetest forum and the Git repository (if any)."
+  (define (topic->url-sexp topic)
+    ;; 'minetest-topic' is a procedure defined in (gnu packages minetest)
+    `(minetest-topic ,topic))
+  (or (package-website package)
+      (and=> (package-forums package) topic->url-sexp)
+      (package-repository package)))
+
+;; If the default sort key is changed, make sure to modify 'show-help'
+;; in (guix scripts import minetest) appropriately as well.
+(define %default-sort-key "score")
+
+(define* (sort-packages packages #:key (sort %default-sort-key))
+  "Sort PACKAGES by SORT, in descending order."
+  (define package->key
+    (match sort
+      ("score" package-score)
+      ("downloads" package-downloads)))
+  (define (greater x y)
+    (> (package->key x) (package->key y)))
+  (sort-list packages greater))
+
+(define builtin-mod?
+  (let ((%builtin-mods
+         (alist->hash-table
+          (map (lambda (x) (cons x #t))
+               '("beds" "binoculars" "boats" "bones" "bucket" "butterflies"
+                 "carts" "creative" "default" "doors" "dungeon_loot" "dye"
+                 "env_sounds" "farming" "fire" "fireflies" "flowers"
+                 "game_commands" "give_initial_stuff" "map" "mtg_craftguide"
+                 "player_api" "screwdriver" "sethome" "sfinv" "spawn" "stairs"
+                 "tnt" "vessels" "walls" "weather" "wool" "xpanes")))))
+    (lambda (mod)
+      "Is MOD provided by the default minetest subgame?"
+      (hash-ref %builtin-mods mod))))
+
+(define* (important-dependencies dependencies author/name
+                                 #:key (sort %default-sort-key))
+  "Return the hard dependencies of AUTHOR/NAME in the association list
+DEPENDENCIES as a list of AUTHOR/NAME strings."
+  (define dependency-list
+    (assoc-ref dependencies author/name))
+  (filter-map
+   (lambda (dependency)
+     (and (not (dependency-optional? dependency))
+          (not (builtin-mod? (dependency-name dependency)))
+          ;; The dependency information contains symbolic names
+          ;; that can be ‘provided’ by multiple mods, so we need to choose one
+          ;; of the implementations.
+          (let* ((implementations
+                  (par-map contentdb-fetch (dependency-packages dependency)))
+                 ;; Fetching package information about the packages is racy:
+                 ;; some packages might be removed from ContentDB between the
+                 ;; construction of DEPENDENCIES and the call to
+                 ;; 'contentdb-fetch'.  So filter out #f.
+                 ;;
+                 ;; Filter out ‘games’ that include the requested mod -- it's
+                 ;; the mod itself we want.
+                 (mods (filter (lambda (p) (and=> p package-mod?))
+                               implementations))
+                 (sorted-mods (sort-packages mods #:sort sort)))
+            (match sorted-mods
+              ((package) (package-author/name package))
+              ((too . many)
+               (warning
+                (G_ "The dependency ~a of ~a has multiple different implementations ~a.~%")
+                (dependency-name dependency)
+                author/name
+                (map package-author/name sorted-mods))
+               (match sort
+                 ("score"
+                  (warning
+                   (G_ "The implementation with the highest score will be choosen!~%")))
+                 ("downloads"
+                  (warning
+                   (G_ "The implementation that has been downloaded the most will be choosen!~%"))))
+               (package-author/name too))
+              (()
+               (warning
+                (G_ "The dependency ~a of ~a does not have any implementation.  It will be ignored!~%")
+                (dependency-name dependency) author/name)
+               #f)))))
+   dependency-list))
+
+(define* (%minetest->guix-package author/name #:key (sort %default-sort-key))
+  "Fetch the metadata for AUTHOR/NAME from https://content.minetest.net, and
+return the 'package' S-expression corresponding to that package, or raise an
+exception on failure.  On success, also return the upstream dependencies as a
+list of AUTHOR/NAME strings."
+  ;; Call 'author/name->name' to verify that AUTHOR/NAME seems reasonable.
+  (author/name->name author/name)
+  (define package (contentdb-fetch author/name))
+  (unless package
+    (leave (G_ "no package metadata for ~a on ContentDB~%") author/name))
+  (define dependencies (contentdb-fetch-dependencies author/name))
+  (unless dependencies
+    (leave (G_ "no dependency information for ~a on ContentDB~%") author/name))
+  (define release (latest-release author/name))
+  (unless release
+    (leave (G_ "no release of ~a on ContentDB~%") author/name))
+  (define important-upstream-dependencies
+    (important-dependencies dependencies author/name #:sort sort))
+  (values (make-minetest-sexp author/name
+                              (release-title release) ; version
+                              (package-repository package)
+                              (release-commit release)
+                              important-upstream-dependencies
+                              (package-home-page package)
+                              (package-short-description package)
+                              (package-long-description package)
+                              (spdx-string->license
+                               (package-media-license package))
+                              (spdx-string->license
+                               (package-license package)))
+          important-upstream-dependencies))
+
+(define minetest->guix-package
+  (memoize %minetest->guix-package))
+
+(define* (minetest-recursive-import author/name #:key (sort %default-sort-key))
+  (define* (minetest->guix-package* author/name #:key repo version)
+    (minetest->guix-package author/name #:sort sort))
+  (recursive-import author/name
+                    #:repo->guix-package minetest->guix-package*
+                    #:guix-name
+                    (compose contentdb->package-name author/name->name)))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f53d1ac1f4..b369a362d0 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,8 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
-                    "gem" "go" "cran" "crate" "texlive" "json" "opam"))
+                    "gem" "go" "cran" "crate" "texlive" "json" "opam"
+                    "minetest"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/minetest.scm b/guix/scripts/import/minetest.scm
new file mode 100644
index 0000000000..5f204d90fc
--- /dev/null
+++ b/guix/scripts/import/minetest.scm
@@ -0,0 +1,117 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import minetest)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-minetest))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((sort . ,%default-sort-key)))
+
+(define (show-help)
+  (display (G_ "Usage: guix import minetest AUTHOR/NAME
+Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+      --sort=KEY         when choosing between multiple implementations,
+                         choose the one with the highest value for KEY
+                         (one of \"score\" (standard) or \"downloads\")"))
+  (newline)
+  (show-bug-report-information))
+
+(define (verify-sort-order sort)
+  "Verify SORT can be used to sort mods by."
+  (unless (member sort '("score" "downloads" "reviews"))
+    (leave (G_ "~a: not a valid key to sort by~%") sort))
+  sort)
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import minetest")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         (option '("sort") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'sort (verify-sort-order arg) result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-minetest . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((name)
+       (with-error-handling
+         (let* ((sort (assoc-ref opts 'sort))
+                (author/name (elaborate-contentdb-name name #:sort sort)))
+           (if (assoc-ref opts 'recursive)
+               ;; Recursive import
+               (filter-map package->definition
+                           (minetest-recursive-import author/name #:sort sort))
+               ;; Single import
+               (minetest->guix-package author/name #:sort sort)))))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index a3bced1a8f..f25a7b4802 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -60,6 +60,7 @@ guix/scripts/git.scm
 guix/scripts/git/authenticate.scm
 guix/scripts/hash.scm
 guix/scripts/import.scm
+guix/scripts/import/contentdb.scm
 guix/scripts/import/cran.scm
 guix/scripts/import/elpa.scm
 guix/scripts/pull.scm
diff --git a/tests/minetest.scm b/tests/minetest.scm
new file mode 100644
index 0000000000..1ef202c0fd
--- /dev/null
+++ b/tests/minetest.scm
@@ -0,0 +1,355 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-minetest)
+  #:use-module (guix memoization)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix tests)
+  #:use-module (json)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-64))
+
+\f
+;; Some procedures for populating a ‘fake’ ContentDB server.
+
+(define* (make-package-sexp #:key
+                            (guix-name "minetest-foo")
+                            (home-page "https://example.org/foo")
+                            (repo "https://example.org/foo.git")
+                            (synopsis "synopsis")
+                            (guix-description "description")
+                            (guix-license
+                             '(list license:cc-by-sa4.0 license:lgpl3+))
+                            (inputs '())
+                            (upstream-name "Author/foo")
+                            #:allow-other-keys)
+  `(package
+     (name ,guix-name)
+     ;; This is not a proper version number but ContentDB does not include
+     ;; version numbers.
+     (version "2021-07-25")
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url ,(and (not (eq? repo 'null)) repo))
+              (commit #f)))
+        (sha256
+         (base32 #f))
+        (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs inputs)
+     (home-page ,home-page)
+     (synopsis ,synopsis)
+     (description ,guix-description)
+     (license ,guix-license)
+     (properties
+      ,(list 'quasiquote
+             `((upstream-name . ,upstream-name))))))
+
+(define* (make-package-json #:key
+                            (author "Author")
+                            (name "foo")
+                            (media-license "CC-BY-SA-4.0")
+                            (license "LGPL-3.0-or-later")
+                            (short-description "synopsis")
+                            (long-description "description")
+                            (repo "https://example.org/foo.git")
+                            (website "https://example.org/foo")
+                            (forums 321)
+                            (score 987.654)
+                            (downloads 123)
+                            (type "mod")
+                            #:allow-other-keys)
+  `(("author" . ,author)
+    ("content_warnings" . #())
+    ("created_at" . "2018-05-23T19:58:07.422108")
+    ("downloads" . ,downloads)
+    ("forums" . ,forums)
+    ("issue_tracker" . "https://example.org/foo/issues")
+    ("license" . ,license)
+    ("long_description" . ,long-description)
+    ("maintainers" . #("maintainer"))
+    ("media_license" . ,media-license)
+    ("name" . ,name)
+    ("provides" . #("stuff"))
+    ("release" . 456)
+    ("repo" . ,repo)
+    ("score" . ,score)
+    ("screenshots" . #())
+    ("short_description" . ,short-description)
+    ("state" . "APPROVED")
+    ("tags" . #("some" "tags"))
+    ("thumbnail" . null)
+    ("title" . "The name")
+    ("type" . ,type)
+    ("url" . ,(string-append "https://content.minetest.net/packages/"
+                             author "/" name "/download/"))
+    ("website" . ,website)))
+
+(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
+  `#((("commit" . ,commit)
+      ("downloads" . 469)
+      ("id" . 8614)
+      ("max_minetest_version" . null)
+      ("min_minetest_version" . null)
+      ("release_date" . "2021-07-25T01:10:23.207584")
+      ("title" . "2021-07-25"))))
+
+(define* (make-dependencies-json #:key (author "Author")
+                                 (name "foo")
+                                 (requirements '(("default" #f ())))
+                                 #:allow-other-keys)
+  `((,(string-append author "/" name)
+     . ,(list->vector
+         (map (match-lambda
+                ((symbolic-name optional? implementations)
+                 `(("is_optional" . ,optional?)
+                   ("name" . ,symbolic-name)
+                   ("packages" . ,(list->vector implementations)))))
+              requirements)))
+    ("something/else" . #())))
+
+(define* (make-packages/keys-json #:key (author "Author")
+                                  (name "Name")
+                                  (type "mod"))
+  `(("author" . ,author)
+    ("name" . ,name)
+    ("type" . ,type)))
+
+(define (call-with-packages thunk . argument-lists)
+  ;; Don't reuse results from previous tests.
+  (invalidate-memoization! contentdb-fetch)
+  (invalidate-memoization! minetest->guix-package)
+  (define (scm->json-port scm)
+    (open-input-string (scm->json-string scm)))
+  (define (handle-package url requested-author requested-name . rest)
+    (define relevant-argument-list
+      (any (lambda (argument-list)
+             (apply (lambda* (#:key (author "Author") (name "foo")
+                              #:allow-other-keys)
+                      (and (equal? requested-author author)
+                           (equal? requested-name name)
+                           argument-list))
+                    argument-list))
+           argument-lists))
+    (when (not relevant-argument-list)
+      (error "the package ~a/~a should be irrelevant, but ~a is fetched"
+             requested-author requested-name url))
+    (scm->json-port
+     (apply (match rest
+              (("") make-package-json)
+              (("dependencies" "") make-dependencies-json)
+              (("releases" "") make-releases-json)
+              (_ (error "TODO ~a" rest)))
+            relevant-argument-list)))
+  (define (handle-mod-search sort)
+    ;; Produce search results, sorted by SORT in descending order.
+    (define arguments->key
+      (match sort
+        ("score" (lambda* (#:key (score 987.654) #:allow-other-keys)
+                   score))
+        ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys)
+                       downloads))))
+    (define argument-list->key (cut apply arguments->key <>))
+    (define (greater x y)
+      (> (argument-list->key x) (argument-list->key y)))
+    (define sorted-argument-lists (sort-list argument-lists greater))
+    (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod")
+                              #:allow-other-keys)
+      (and (string=? type "mod")
+           `(("author" . ,author)
+             ("name" . ,name)
+             ("type" . ,type))))
+    (define argument-list->json (cut apply arguments->json <>))
+    (scm->json-port
+     (list->vector (filter-map argument-list->json sorted-argument-lists))))
+  (mock ((guix http-client) http-fetch
+         (lambda* (url #:key headers)
+           (unless (string-prefix? "mock://api/packages/" url)
+             (error "the URL ~a should not be used" url))
+           (define resource
+             (substring url (string-length "mock://api/packages/")))
+           (define components (string-split resource #\/))
+           (match components
+             ((author name . rest)
+              (apply handle-package url author name rest))
+             (((? (cut string-prefix? "?type=mod&q=" <>) query))
+              (handle-mod-search
+               (cond ((string-contains query "sort=score") "score")
+                     ((string-contains query "sort=downloads") "downloads")
+                     (#t (error "search query ~a has unknown sort key"
+                                query)))))
+             (_
+              (error "the URL ~a should have an author and name component"
+                     url)))))
+        (parameterize ((%contentdb-api "mock://api/"))
+          (thunk))))
+
+(define* (minetest->guix-package* #:key (author "Author") (name "foo")
+                                  (sort %default-sort-key)
+                                  #:allow-other-keys)
+  (minetest->guix-package (string-append author "/" name) #:sort sort))
+
+(define (imported-package-sexp* primary-arguments . secondary-arguments)
+  "Ask the importer to import a package specified by PRIMARY-ARGUMENTS,
+during a dynamic where that package and the packages specified by
+SECONDARY-ARGUMENTS are available on ContentDB."
+  (apply call-with-packages
+         (lambda ()
+           ;; The memoization cache is reset by call-with-packages
+           (apply minetest->guix-package* primary-arguments))
+   primary-arguments
+   secondary-arguments))
+
+(define (imported-package-sexp . extra-arguments)
+  "Ask the importer to import a package specified by EXTRA-ARGUMENTS,
+during a dynamic extent where that package is available on ContentDB."
+  (imported-package-sexp* extra-arguments))
+
+(define-syntax-rule (test-package test-case . extra-arguments)
+  (test-equal test-case
+    (make-package-sexp . extra-arguments)
+    (imported-package-sexp . extra-arguments)))
+
+(define-syntax-rule (test-package* test-case primary-arguments extra-arguments
+                                   ...)
+  (test-equal test-case
+    (apply make-package-sexp primary-arguments)
+    (imported-package-sexp* primary-arguments extra-arguments ...)))
+
+(test-begin "minetest")
+
+\f
+;; Package names
+(test-package "minetest->guix-package")
+(test-package "minetest->guix-package, _ → - in package name"
+              #:name "foo_bar"
+              #:guix-name "minetest-foo-bar"
+              #:upstream-name "Author/foo_bar")
+
+(test-equal "elaborate names, unambigious"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeija")
+   '(#:name "something" #:author "else")))
+
+(test-equal "elaborate name, ambigious (highest score)"
+  "Jeija/mesecons"
+  (call-with-packages
+   ;; #:sort "score" is the default
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeijc" #:score 777)
+   '(#:name "mesecons" #:author "Jeijb" #:score 888)
+   '(#:name "mesecons" #:author "Jeija" #:score 999)))
+
+
+(test-equal "elaborate name, ambigious (most downloads)"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons" #:sort "downloads")
+   '(#:name "mesecons" #:author "Jeijc" #:downloads 777)
+   '(#:name "mesecons" #:author "Jeijb" #:downloads 888)
+   '(#:name "mesecons" #:author "Jeija" #:downloads 999)))
+
+\f
+;; Determining the home page
+(test-package "minetest->guix-package, website is used as home page"
+              #:home-page "web://site"
+              #:website "web://site")
+(test-package "minetest->guix-package, if absent, the forum is used"
+              #:home-page '(minetest-topic 628)
+              #:forums 628
+              #:website 'null)
+(test-package "minetest->guix-package, if absent, the git repo is used"
+              #:home-page "https://github.com/minetest-mods/mesecons"
+              #:forums 'null
+              #:website 'null
+              #:repo "https://github.com/minetest-mods/mesecons")
+(test-package "minetest->guix-package, all home page information absent"
+              #:home-page #f
+              #:forums 'null
+              #:website 'null
+              #:repo 'null)
+
+\f
+
+;; Dependencies
+(test-package* "minetest->guix-package, unambigious dependency"
+  (list #:requirements '(("mesecons" #f
+                          ("Jeija/mesecons"
+                           "some-modpack/containing-mese")))
+        #:inputs '("minetest-mesecons"))
+  (list #:author "Jeija" #:name "mesecons")
+  (list #:author "some-modpack" #:name "containing-mese" #:type "modpack"))
+
+(test-package* "minetest->guix-package, ambigious dependency (highest score)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        ;; #:sort "score" is the default
+        #:inputs '("minetest-bar"))
+  (list #:author "Author" #:name "foo" #:score 0)
+  (list #:author "Author" #:name "bar" #:score 9999))
+
+(test-package* "minetest->guix-package, ambigious dependency (most downloads)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        #:inputs '("minetest-bar")
+        #:sort "downloads")
+  (list #:author "Author" #:name "foo" #:downloads 0)
+  (list #:author "Author" #:name "bar" #:downloads 9999))
+
+(test-package "minetest->guix-package, optional dependency"
+              #:requirements '(("mesecons" #t
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '())
+
+\f
+;; License
+(test-package "minetest->guix-package, identical licenses"
+              #:guix-license 'license:lgpl3+
+              #:license "LGPL-3.0-or-later"
+              #:media-license "LGPL-3.0-or-later")
+
+;; Sorting
+(let* ((make-package
+        (lambda arguments
+          (json->package (apply make-package-json arguments))))
+       (x (make-package #:score 0))
+       (y (make-package #:score 1))
+       (z (make-package #:score 2)))
+  (test-equal "sort-packages, already sorted"
+    (list z y x)
+    (sort-packages (list z y x)))
+  (test-equal "sort-packages, reverse"
+    (list z y x)
+    (sort-packages (list x y z))))
+
+(test-end "minetest")
-- 
2.32.0


[-- Attachment #1.8: 0007-gnu-Add-minetest-mesecons.patch --]
[-- Type: text/x-patch, Size: 2338 bytes --]

From c0a76311be73aef41096f3e52ca329cf2fd2950f Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:00:45 +0200
Subject: [PATCH 07/20] gnu: Add minetest-mesecons.

* gnu/packages/minetest.scm (minetest-mesecons): New variable.
---
 gnu/packages/minetest.scm | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f8aca3005c..d99efa4625 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -24,3 +24,39 @@
 numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
+
+(define-public minetest-mesecons
+  ;; The release on ContentDB does not have its own version number.
+  (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
+        (revision "0"))
+  (package
+    (name "minetest-mesecons")
+    (version (git-version "1.2.1" revision commit))
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/mesecons")
+             (commit commit)))
+       (sha256
+        (base32 "04m9s9l3frw1lgki41hgvjsw2zkrvfv0sy750b6j12arzb3lv645"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page "https://mesecons.net")
+    (synopsis
+     "Digital circuitry for Minetest, including wires, buttons and lights")
+    (description
+     "Mesecons is a mod for Minetest implementing various items related
+to digital circuitry, such as wires, buttons, lights and programmable
+controllers.  Among other things, there are also pistons, solar panels,
+pressure plates and note blocks.
+
+Mesecons has a similar goal to Redstone in Minecraft, but works in its own way,
+with different rules and mechanics.")
+    ;; LGPL for code, CC-BY-SA for textures.
+    ;; The README.md and COPYING.txt disagree about the "+" in license:lgpl3+.
+    ;; For now, assume README.md is correct.  Upstream has been asked to
+    ;; correct the inconsistency:
+    ;; <https://github.com/minetest-mods/mesecons/issues/575>.
+    (license (list license:lgpl3+ license:cc-by-sa3.0))
+    (properties `((upstream-name . "Jeija/mesecons"))))))
-- 
2.32.0


[-- Attachment #1.9: 0008-gnu-Add-minetest-basic-materials.patch --]
[-- Type: text/x-patch, Size: 1994 bytes --]

From fdf99927d0dd0090fe66f04e9a6e7e68f882f2e0 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:23:50 +0200
Subject: [PATCH 08/20] gnu: Add minetest-basic-materials.

* gnu/packages/minetest.scm (minetest-basic-materials): New variable.
---
 gnu/packages/minetest.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d99efa4625..97d4d3c9ac 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -25,6 +25,31 @@ numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
 
+(define-public minetest-basic-materials
+  (package
+    (name "minetest-basic-materials")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-01-30")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/basic_materials.git")
+             (commit "e72665b2ed98d7be115779a32d35e6d9ffa231bd")))
+       (sha256
+        (base32 "0v6l3lrjgshy4sccjhfhmfxc3gk0cdy73qb02i9wd2vw506v5asx"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 21000))
+    (synopsis "Some \"basic\" materials and items for other Minetest mods to use")
+    (description
+     "The Minetest mod \"basic_materials\" provides a small selection of
+\"basic\" materials and items that other mods should use when possible -- things
+like steel bars and chains, wire, plastic strips and sheets, and more.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/basic_materials")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #1.10: 0009-gnu-Add-minetest-unifieddyes.patch --]
[-- Type: text/x-patch, Size: 2029 bytes --]

From 6ea28df67b5402634b14867ce334a2b9764e6d40 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:40:24 +0200
Subject: [PATCH 09/20] gnu: Add minetest-unifieddyes.

* gnu/packages/minetest.scm (minetest-unifieddyes): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 97d4d3c9ac..8b9eb30a6a 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -85,3 +85,32 @@ with different rules and mechanics.")
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
+
+(define-public minetest-unifieddyes
+  (package
+    (name "minetest-unifieddyes")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-20-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/unifieddyes")
+             (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
+       (sha256
+        (base32
+         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2178))
+    (synopsis
+     "Unified Dyes expands the standard dye set of Minetest to up to 256 colours")
+    (description "The purpose of this mod originally was to supply a complete
+set of colours for Minetest mod authors to use for colourised nodes or
+reference in recipes.  Since the advent of the default dyes mod in the standard
+Minetest game, this mod has become an extension of the default mod an a library
+for general colour handling.")
+    (license license:gpl2+)
+    (properties `((upstream-name . "VanessaE/unifieddyes")))))
-- 
2.32.0


[-- Attachment #1.11: 0010-gnu-Add-minetest-pipeworks.patch --]
[-- Type: text/x-patch, Size: 2266 bytes --]

From 799bf39bb88a16d09a8473a43ea458fa98df86ae Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 23:39:02 +0200
Subject: [PATCH 10/20] gnu: Add minetest-pipeworks.

* gnu/packages/minetest.scm (minetest-pipeworks): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 8b9eb30a6a..782166daef 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -86,6 +86,37 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-pipeworks
+  (package
+    (name "minetest-pipeworks")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/pipeworks")
+             (commit "db6d1bd9c109e1e543b97cc3fa8a11400da23bcd")))
+       (sha256
+        (base32 "1flhcnf17dn1v86kcg47a1n4cb0lybd11ncxrkxn3wmf10ibsrm0"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2155))
+    (synopsis "Pipes, item-transport tubes and related devices for Minetest")
+    (description
+     "Pipeworks is a mod for Minetest implementing 3D pipes and tubes for
+transporting liquids and items and some related devices.  Pipes and tubes can
+go horizontally or vertically.  Item tubes can also be used for sorting items
+and extracting items from chests or putting items in chests.  Autocrafters can
+automatically follow craft recipes to make new items and can be fed by item
+tubes.  Deployers can place items in the world as a player would.  Node
+breakers simulate a player punching a node.")
+    ;; CC-BY-SA for textures, LGPL for code
+    (license (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/pipeworks")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.12: 0011-gnu-Add-minetest-coloredwood.patch --]
[-- Type: text/x-patch, Size: 2041 bytes --]

From 93deef7431a986c41b085aa107055b0348a8ed8f Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 00:50:12 +0200
Subject: [PATCH 11/20] gnu: Add minetest-coloredwood.

* gnu/packages/minetest.scm (minetest-coloredwood): New variable.
---
 gnu/packages/minetest.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 782166daef..4c542c6061 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -50,6 +50,34 @@ like steel bars and chains, wire, plastic strips and sheets, and more.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/basic_materials")))))
 
+(define-public minetest-coloredwood
+  (package
+    (name "minetest-coloredwood")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/coloredwood")
+             (commit "be4df6fc889419155bed8638bbb752493e78cbd5")))
+       (sha256
+        (base32 "1swirfk6b4xfbiwv8adyw5yl2lyfpp8ymfipzq9ivyvmif8nl3ki"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2411))
+    (synopsis "Painted wood in Minetest")
+    (description
+     "This Minetest mod provides hundreds of colours of wood and fences to
+Minetest, using Unified Dyes.  If the \"moreblocks\" mod is active,
+coloured and cut wood shapes are provided as well.")
+    (license
+     ;; LGPL for code, CC-BY-SA for textures
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/coloredwood")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #1.13: 0012-gnu-Add-minetest-ethereal.patch --]
[-- Type: text/x-patch, Size: 2697 bytes --]

From 42b3daf2756e5eb3f7890b9a43fea90bdff4ba91 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 01:24:48 +0200
Subject: [PATCH 12/20] gnu: Add minetest-ethereal.

* gnu/packages/minetest.scm (minetest-ethereal): New variable.
---
 gnu/packages/minetest.scm | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4c542c6061..a1aa90276d 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -78,6 +78,35 @@ coloured and cut wood shapes are provided as well.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/coloredwood")))))
 
+(define-public minetest-ethereal
+  ;; ContentDB release 2021-07-28 is slightly ahead of the
+  ;; initial version 1.29 -- i.e., some released changes have been
+  ;; made to version 1.29 without a corresponding version bump.
+  (let ((commit "7670c1da9274901f57f6682384af2b3bae005a86")
+        (revision "0"))
+    (package
+      (name "minetest-ethereal")
+      (version (git-version "1.29" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://notabug.org/TenPlus1/ethereal")
+               (commit commit)))
+         (sha256
+          (base32 "1hal8bq4fydsip7s8rqz4vlaaqy9rhzxmryd0j2qnqm9286yjgkk"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 14638))
+      (synopsis "The Ethereal mod adds many new biomes to Minetest")
+      (description
+       "The Ethereal Minetest mod uses the v7 map generator to add many new
+biomes to the world.  It adds new trees, plants, food items, tweaks and some
+special items, intending to make an interesting adventure.")
+      ;; CC0: some textures
+      (license (list license:cc0 license:expat))
+      (properties `((upstream-name . "TenPlus1/ethereal"))))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
@@ -157,8 +186,7 @@ breakers simulate a player punching a node.")
              (url "https://gitlab.com/VanessaE/unifieddyes")
              (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
        (sha256
-        (base32
-         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+        (base32 "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
        (file-name (git-file-name name version))))
     (build-system minetest-mod-build-system)
     (propagated-inputs
-- 
2.32.0


[-- Attachment #1.14: 0013-gnu-Add-minetest-technic.patch --]
[-- Type: text/x-patch, Size: 2279 bytes --]

From e8b540369b51ce74c3f9e83179a7a17f17c21117 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 13:40:56 +0200
Subject: [PATCH 13/20] gnu: Add minetest-technic.

* gnu/packages/minetest.scm (minetest-technic): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index a1aa90276d..bb914f32b4 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -174,6 +174,41 @@ breakers simulate a player punching a node.")
     (license (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/pipeworks")))))
 
+(define-public minetest-technic
+  (package
+    (name "minetest-technic")
+    ;; Upstream doesn't keep version numbers, so use the release
+    ;; date on ContentDB instead.
+    (version "2021-04-15")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/technic")
+             (commit "1c219487d3f4dd03c01ff9aa1f298c7c18c7e189")))
+       (sha256
+        (base32 "1k9hdgzp7jnhsk6rgrlrv1lr5xrmh8ln4wv6r25v6f0fwbyj57sf"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-pipeworks" ,minetest-pipeworks)
+       ("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2538))
+    (synopsis "Machinery and automation for Minetest")
+    (description
+     "This Minetest mod adds machinery and automation to Minetest.
+It adds various ores that can be processed for constructing various
+machinery, such as power generators, force field emitters, quarries
+and a workshop for repairing tools.  Most machines are electrically
+powered.")
+    ;; CC BY-SA 3.0: some texture
+    ;; WTFPL: some textures
+    ;; CC BY-SA3.0: some textures
+    ;; CC BY-SA4.0: some sounds
+    (license (list license:lgpl2.1+ license:cc-by-sa3.0 license:cc-by-sa4.0
+                   license:wtfpl2))
+    (properties `((upstream-name . "RealBadAngel/technic")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.15: 0014-gnu-Add-minetest-throwing.patch --]
[-- Type: text/x-patch, Size: 1684 bytes --]

From 9f2a20d664fb8d280f49db9ca46247de8242f53b Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 14:16:27 +0200
Subject: [PATCH 14/20] gnu: Add minetest-throwing.

* gnu/packages/minetest.scm (minetest-throwing): New variable.
---
 gnu/packages/minetest.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index bb914f32b4..1444ddf4d8 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -209,6 +209,29 @@ powered.")
                    license:wtfpl2))
     (properties `((upstream-name . "RealBadAngel/technic")))))
 
+(define-public minetest-throwing
+  (package
+    (name "minetest-throwing")
+    (version "2020-08-14")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/throwing")
+             (commit "31f0cf5f868673dc82f24ddc432b45c9cd282d27")))
+       (sha256
+        (base32 "1s5kkr6rxxv2dhbbjzv62gw1s617hnpjavw1v9fv11v3mgigdfjb"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 16365))
+    (synopsis "API for throwing things in Minetest")
+    (description
+     "This Minetest mod provides an API for registering throwable things and
+throwing things like arrows.  However, this mod does not provide an actual
+arrow and bow, but @code{minetest-throwing-arrows} does.")
+    (license license:mpl2.0)
+    (properties `((upstream-name . "Palige/throwing")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.16: 0015-gnu-Add-minetest-throwing-arrows.patch --]
[-- Type: text/x-patch, Size: 2097 bytes --]

From f1477ba3edb9729b63041863611704af1621bf29 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 14:34:12 +0200
Subject: [PATCH 15/20] gnu: Add minetest-throwing-arrows.

* gnu/packages/minetest.scm
  (minetest-throwing-arrows): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 1444ddf4d8..6183367101 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -232,6 +232,36 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
     (license license:mpl2.0)
     (properties `((upstream-name . "Palige/throwing")))))
 
+(define-public minetest-throwing-arrows
+  ;; There is only one tagged commit (version 1.1),
+  ;; there are no releases on ContentDB and the latest
+  ;; commit has a compatibility fix for Minetest 5.4.0-dev.
+  (let ((commit "059cc897af0aebfbd2c54ac5588f2b842f44f159")
+        (revision "0"))
+    (package
+      (name "minetest-throwing-arrows")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing_arrows")
+               (commit commit)))
+         (sha256
+          (base32 "0m2pmccpfxn878zd00pmrpga2h6gknz4f3qprck0fq94mksmwqs3"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (propagated-inputs
+       `(("minetest-throwing" ,minetest-throwing)))
+      (home-page (minetest-topic 16365))
+      (synopsis "Arrows and bows for Minetest")
+      (description
+       ;; TRANSLATORS: "throwing" is the name of a Minetest mod and should
+       ;; not be translated.
+       "This mod adds arrows and bows to Minetest.  It is a compatible
+replacement for the throwing mod by PilzAdam that uses the throwing API.")
+      (license license:mpl2.0))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.17: 0016-gnu-Add-minetest-unified-inventory.patch --]
[-- Type: text/x-patch, Size: 2370 bytes --]

From 7188ac29a73be4f15df9977ce75b1dd60d837e44 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 17:39:36 +0200
Subject: [PATCH 16/20] gnu: Add minetest-unified-inventory.

* gnu/packages/minetest.scm
  (minetest-unified-inventory): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 6183367101..042f710c85 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -289,3 +289,38 @@ Minetest game, this mod has become an extension of the default mod an a library
 for general colour handling.")
     (license license:gpl2+)
     (properties `((upstream-name . "VanessaE/unifieddyes")))))
+
+(define-public minetest-unified-inventory
+  (package
+    (name "minetest-unified-inventory")
+    ;; Upstream doesn't keep version numbers, so use the release title
+    ;; on ContentDB instead.
+    (version "2021-03-25-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/unified_inventory")
+             (commit "c044f5e3b08f0c68ab028d757b2fa63d9a1b0370")))
+       (sha256
+        (base32 "198g945gzbfl0kps46gwjw0c601l3b3wvn4c7dw8manskri1jr4g"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 12767))
+    (synopsis "Replace the default inventory in Minetest and add a crafting guide")
+    (description
+     "The Unified Inventory Minetest mod relaces the default survival an
+creative inventory.  It includes a node, item and tool browser, a crafting
+guide, a trash and refill slot for creative mode, bags and waypoints for keeping
+track of important locations.")
+    ;; CC-BY: some textures and icons
+    ;; CC-BY-SA: some textures and icons
+    ;; LGLPL2.1+: code and some textures
+    ;; GPL2+: some textures
+    ;; GPL3: bags.lua
+    ;; GFDL: some icons
+    ;; public domain, CC0: some icons
+    (license (list license:gpl3 license:gpl2+ license:lgpl2.1+ license:cc-by3.0
+                   license:cc-by4.0 license:cc-by-sa3.0 license:public-domain
+                   license:cc0 license:fdl1.2+))
+    (properties `((upstream-name . "RealBadAngel/unified_inventory")))))
-- 
2.32.0


[-- Attachment #1.18: 0017-gnu-Add-minetest-worldedit.patch --]
[-- Type: text/x-patch, Size: 1704 bytes --]

From 664aa8de09e10b4699eb1e5ea95bde3b51ca2f36 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 17:58:24 +0200
Subject: [PATCH 17/20] gnu: Add minetest-worldedit.

* gnu/packages/minetest.scm (minetest-worldedit): New variable.
---
 gnu/packages/minetest.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 042f710c85..f26e7e0ff3 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -262,6 +262,29 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
 replacement for the throwing mod by PilzAdam that uses the throwing API.")
       (license license:mpl2.0))))
 
+(define-public minetest-worldedit
+  (package
+    (name "minetest-worldedit")
+    (version "1.3")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/Uberi/Minetest-WorldEdit")
+             (commit "2f26fb76459c587868199160b9d7b5d6d7852e50")))
+       (sha256
+        (base32 "0lsvihkixi2na1b0vmml9vwgs0g24hqqshl73ffhkzh6jsq4cagq"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 572))
+    (synopsis "In-game world editor for Minetest")
+    (description
+     "WorldEdit is a mod for Minetest.  It allows for creating various
+geometric shapes and copying regions.  It can also export and import regions
+to and from the file system.")
+    (license license:agpl3)
+    (properties `((upstream-name . "sfan5/worldedit")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.19: 0018-gnu-Add-minetest-mobs.patch --]
[-- Type: text/x-patch, Size: 2012 bytes --]

From 3d2a67158927e10bd2a8169b8199bb6de118c844 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 18:53:54 +0200
Subject: [PATCH 18/20] gnu: Add minetest-mobs.

* gnu/packages/minetest.scm (minetest-mobs): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f26e7e0ff3..2a7bd0081e 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -143,6 +143,35 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-mobs
+  (package
+    (name "minetest-mobs")
+    ;; Upstream does not tag release, so use the ContentDB release
+    ;; title instead.
+    (version "2021-07-22")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_redo")
+             (commit "9f46182bb4b1a390f9a140bc2b443f3cda702332")))
+       (sha256
+        (base32 "026kqjis4lipgskjivb3jh9ris3iz80vy2q1jvgxhxmfghjjzp4j"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 9917))
+    (synopsis "Mob library for Minetest mods, for animals, monsters etc.")
+    (description
+     "This Minetest mod provides an API for adding mods (moving entities
+like animals and monsters), but does not include any mobs itself.  To actually
+add some mobs, a mod like e.g. @code{mobs_animal} provided by the
+@code{minetest-mobs-animal} package needs to be enabled.")
+    ;; CC0: mob_swing.ogg
+    ;; CC-BY 3.0: mob_spell.ogg
+    ;; Expat: everything else
+    (license (list license:expat license:cc0 license:cc-by3.0))
+    (properties `((upstream-name . "TenPlus1/mobs")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0


[-- Attachment #1.20: 0019-gnu-Add-minetest-mobs-animal.patch --]
[-- Type: text/x-patch, Size: 1951 bytes --]

From f7d9cd92bf9eb5043332c1d0ba915b6923c60cc1 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 19:43:47 +0200
Subject: [PATCH 19/20] gnu: Add minetest-mobs-animal.

* gnu/packages/minetest.scm (minetest-mobs-animal): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 2a7bd0081e..f49e0080f2 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -172,6 +172,33 @@ add some mobs, a mod like e.g. @code{mobs_animal} provided by the
     (license (list license:expat license:cc0 license:cc-by3.0))
     (properties `((upstream-name . "TenPlus1/mobs")))))
 
+(define-public minetest-mobs-animal
+  (package
+    (name "minetest-mobs-animal")
+    ;; Upstream does not use version numbers, so use the release title
+    ;; from ContentDB instead;
+    (version "2021-07-24")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_animal")
+             (commit "c2fa3e300c79c7dd80b6fe91a8b5082bb6b3d934")))
+       (sha256
+        (base32 "1j719f079ia9vjxrmjrcj8s6jvaz5kgs1r4dh66z8ql6s70kx7vh"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-mobs" ,minetest-mobs)))
+    (home-page "https://notabug.org/TenPlus1/mobs_animal")
+    (synopsis "Add animals to Minetest")
+    (description
+     "This Minetest mod adds various animals to Minetest, such as bees,
+bunnies, chickens, cows, kittens, rats, sheep, warthogs, penguins and pandas.")
+    ;; CC0: some textures and sounds
+    (license (list license:cc0 license:expat))
+    (properties `((upstream-name . "TenPlus1/mobs_animal")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0


[-- Attachment #1.21: 0020-gnu-Add-minetest-homedecor-modpack.patch --]
[-- Type: text/x-patch, Size: 2249 bytes --]

From 33e15111c00d9988d8123a674930a27b61e891b3 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 20:03:07 +0200
Subject: [PATCH 20/20] gnu: Add minetest-homedecor-modpack.

* gnu/packages/minetest.scm
  (minetest-homedecor-modpack): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f49e0080f2..ca9d0ac720 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -107,6 +107,37 @@ special items, intending to make an interesting adventure.")
       (license (list license:cc0 license:expat))
       (properties `((upstream-name . "TenPlus1/ethereal"))))))
 
+(define-public minetest-homedecor-modpack
+  (package
+    (name "minetest-homedecor-modpack")
+    ;; Upstream doesn't tag releases, so use the release title from
+    ;; ContentDB as version.
+    (version "2021-03-27-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/homedecor_modpack")
+             (commit "9ffe2b7d691133e1a067546574fbe7364fd02f32")))
+       (sha256
+        (base32 "1lfajqvc2adf9hqskghky4arccqzpjw4i9a01hv4qcckvivm04ag"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)
+       ("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2041))
+    (synopsis "Home decor mod for Minetest")
+    (description
+     ;; TRANSLATORS: ‘homedecor’ is the name is the name of a Minetest mod
+     ;; and should not be translated.
+     "The homedecor Minetest mod provides a large seleection of items that
+might be found inside and around homes, such as sofas, chairs, tables, fences
+and a variety of other stuff.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/homedecor_modpack")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-07 18:31       ` Maxime Devos
@ 2021-08-07 19:47         ` Leo Prikler
  2021-08-09 20:00           ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet) Maxime Devos
  0 siblings, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-07 19:47 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Samstag, den 07.08.2021, 20:31 +0200 schrieb Maxime Devos:
> [...]
> ContentDB uses SPDX license identifiers now, and distinguishes
> between GPL-N-only and GPL-N-or-later, so I adjusted the
> documentation appropriately.
Nice.

> > > The commit id is
> > > +sometimes missing.  The descriptions are in the Markdown format,
> > > but
> > > +Guix uses Texinfo instead.  Texture packs and subgames are
> > > unsupported.
> > What is the "commit id"?  Is it the hash?  A tag?  Anything that
> > resolves to a commit?
> 
> It's the SHA-1 of the Git commit.  I changes this to ‘the commit's
> SHA-1’.
We usually call it the hash around here :)

> > Also, since ContentDB sounds fairly generic (a database of
> > content?),
> > perhaps we ought to call this the "minetest" importer instead?
> 
> Technically, minetest has another mod repository as well:
> <https://bower.minetest.org/>;.  It's unmoderated though, and
> <https://content.minetest.net> has some moderation and seems more
> ‘official’ (it's integrated in Minetest itself).  I replaced
> (guix import contentdb) with (guix import minetest), likewise
> for (guix script import minetest) and tests/minetest.scm.
If we get more of these we could label them like elpa repos, but I
don't think we'll get many third party repos with ContentDB existing.

> > > +;; Minetest package.
> > > +;;
> > > +;; API endpoint: /packages/AUTHOR/NAME/
> > > +(define-json-mapping <package> make-package package?
> > > +  json->package
> > > +  (author            package-author) ; string
> > > +  (creation-date     package-creation-date ; string
> > > +                     "created_at")
> > > +  (downloads         package-downloads) ; integer
> > > +  (forums            package-forums "forums" natural-or-false) ;
> > > natural | #f
> > This comment and some others like it seem to simply be repeating
> > already present information.  Is there a use for them?  Should we
> > instead provide a third argument on every field to verify/enforce
> > the
> > type?
> 
> I first added the ‘; natural-or-false’.  I only added the procedure
> "natural-false" later.  Indeed, ‘; natural-or-false’ is redundant.
> I removed the redundant ones in the revised patch.
> 
> I don't think there is need to verify types for each field.
> Most aren't used by Guix.  If a type check would fail, that would
> presumably mean the type check guix is incorrect (or not up-to-date).
> Except for perhaps a backtrace, ill-typed fields are harmless.
Fair enough, gratuitous redundancy is the bigger issue here.

> [...]
> ContentDB allows searching.  I wrote some a procedure 'elaborate-
> contentdb-name' used by (guix scripts import contentdb) that resolves
> "mesecons" to "Jeija/mesecons", using the search API and added some
> tests.  If there are multiple candidates, the one with the highest
> ‘score’ is choosen (alternatively, --sort=downloads can be used
> instead).
Sounds good to me.

> > > +(define (important-dependencies dependencies author name)
> > > +  (define dependency-list
> > > +    (assoc-ref dependencies (string-append author "/" name)))
> > > +  (filter-map
> > > +   (lambda (dependency)
> > > +     (and (not (dependency-optional? dependency))
> > > +          ;; "default" must be provided by the 'subgame' in use
> > > +          ;; and does not refer to a specific minetest mod.
> > > +          ;; "doors", "bucket" ... are provided by the default
> > > minetest
> > > +          ;; subgame.
> > > +          (not (member (dependency-name dependency)
> > > +                       '("default" "doors" "beds" "bucket"
> > > "doors"
> > > "farming"
> > > +                         "flowers" "stairs" "xpanes")))
> 
> I tested this some more, and it appears that some mods depend on
> "dyes",
> which is part of the default Minetest game, so I added all the mods
> provided by the default (sub?)game.  The list began looking a little
> long, so I replaced it with a hash table.
> 
> > > +          ;; Dependencies often have only one implementation.
> > > +          (let* ((/name (string-append "/" (dependency-name
> > > dependency)))
> > > +                 (likewise-named-implementations
> > > +                  (filter (cut string-suffix? /name <>)
> > > +                          (dependency-packages dependency)))
> > > +                 (implementation
> > > +                  (and (not (null? likewise-named-
> > > implementations))
> > > +                       (first likewise-named-implementations))))
> > > +            (and implementation
> > > +                 (apply cons (string-split implementation
> > > #\/))))))
> > > +   dependency-list))
> > What exactly does the likewise-named-implementations bit do here?
> 
> The list returned by 'dependency-packages' not only contains the mod
> we need, but possibly also various ‘subgames’ that include that mod.
> Filtering on '/name' filters out these subgames we don't need.
> 
> Also, theoretically another mod could implement the same interface.
> The filtering would filter out the alternative implementations.
> 
> Anyway, I changes the implementation a bit.  It now explicitely
> filters out ‘subgames’ and ‘texture packs’ using the ‘package-mod?’
> procedure.  The resulting list tends to consist of only a single
> element.  If it consists of multiple, the one with the highest score
> (or the one with the highest download count, depending on --sort)
> will be choosen (and a warning is printed).
Sounds good.

> > > +;; A list of license names is available at
> > > +;; <https://content.minetest.net/api/licenses/>;;;.
> > > +(define (string->license str)
> > > +  "Convert the string STR into a license object." [...]
> > The link mentions, that ContentDB now supports all SPDX
> > identifiers. 
> > Do we have a SPDX->Guix converter lying around in some other
> > importer
> > that we could use as default case here (especially w.r.t. "or
> > later")
> 
> There's a a converter in (guix import utils): spdx-string->license.
> The old license identifiers appear to be removed, now only SPDX
> information is available.  I modified the code to use spdx->string-
> license and removed string->license.
Nice.

> It turns out it does not recognise GPL-N-only and GPL-N-or-later,
> so I added a patch ‘import/utils: Recognise GPL-3.0-or-later and
> friends.’.
Said patch LGTM.

> I tried implementing "guix refresh -t minetest ...".  It seems to
> work, but requires some changes to (guix upstream) that needs some
> more work, so I left it out of the revised patch set.  The refresher
> needs to know the author name (or perform extra HTTP requests), so I
> added 'upstream-name' the package properties.
Could we somehow define a (minetest-uri) procedure that can be supplied
to (guix download)?  Somehow Minetest must get the package to
installations across operating systems, so surely there's some download
link somewhere.

> The revised patch series is attached.  It can also be found at
> <https://notabug.org/maximed/guix-gnunet/src/minetest-2>;.  It
> includes the latest MINETEST_MOD_PATH patch.  I'll make the patch to
> export more things in (guix build utils) later (for core-updates).
For the rest of this, I'll only look over 06/20 v2.  I'll assume you
did nothing naughty to 01..04.

> +;; A structure returned by the /api/packages/?fmt=keys endpoint
> +(define-json-mapping <package/keys> make-package/keys package/keys?
> +  json->package/keys
> +  (author package/keys-author) ; string
> +  (name package/keys-name)     ; string
> +  (type package/keys-type))    ; string
Not sure about this slash, as it typically specifies extension of some
sort.  Perhaps just naming this package-keys would be better?

> +(define (package-author/name package)
> +  "Given a <package> object, return the corresponding AUTHOR/NAME
> string."
> +  (string-append (package-author package) "/" (package-name
> package)))
> +
> +(define (package/keys-author/name package)
> +  "Given a <package/keys> object, return the corresponding
> AUTHOR/NAME string."
> +  (string-append (package/keys-author package)
> +                 "/" (package/keys-name package)))
I think it's probably be better to merge this into a single procedure
called "package-full-name", "package-unique-name" or "package-id"
(whichever you prefer naming-wise), which handles both cases.

> +(define (contentdb->package-name name)
> +  "Given the NAME of a package on ContentDB, return a Guix-compliant 
> name for the
> +package."
> +  ;; The author is not included, as the names of popular mods
> +  ;; tend to be unique.
> +  (string-append "minetest-" (snake-case name)))
I'd at least add an option to generate full names instead, for cases in
which as before we warn about non-uniqueness.  Though actually, this
comment is a little misleading as the actual stripping happens...
> +     (name ,(contentdb->package-name (author/name->name
> author/name)))
here.

> +(define* (make-package-sexp #:key
> +                            (guix-name "minetest-foo")
> +                            (home-page "https://example.org/foo")
> +                            (repo "https://example.org/foo.git")
> +                            (synopsis "synopsis")
> +                            (guix-description "description")
> +                            (guix-license
> +                             '(list license:cc-by-sa4.0
> license:lgpl3+))
> +                            (inputs '())
> +                            (upstream-name "Author/foo")
> +                            #:allow-other-keys)
> + [...]
As noted above, this procedure would be somewhat simplified if we could
define a (mintest-uri).

Regards





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet)
  2021-08-07 19:47         ` Leo Prikler
@ 2021-08-09 20:00           ` Maxime Devos
  2021-08-09 20:04             ` Maxime Devos
  2021-08-09 21:45             ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Yes send now) Leo Prikler
  0 siblings, 2 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-09 20:00 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 6908 bytes --]

Hi,

Leo Prikler schreef op za 07-08-2021 om 21:47 [+0200]:
> > > > The commit id is
> > > > +sometimes missing.  The descriptions are in the Markdown format,
> > > > but
> > > > +Guix uses Texinfo instead.  Texture packs and subgames are
> > > > unsupported.
> > > What is the "commit id"?  Is it the hash?  A tag?  Anything that
> > > resolves to a commit?
> > 
> > It's the SHA-1 of the Git commit.  I changes this to ‘the commit's
> > SHA-1’.
> We usually call it the hash around here :)

I adjusted the documentation to call it ‘the commit hash’.

> > I tried implementing "guix refresh -t minetest ...".  It seems to
> > work, but requires some changes to (guix upstream) that needs some
> > more work, so I left it out of the revised patch set.  The refresher
> > needs to know the author name (or perform extra HTTP requests), so I
> > added 'upstream-name' the package properties.
> Could we somehow define a (minetest-uri) procedure that can be supplied
> to (guix download)?  Somehow Minetest must get the package to
> installations across operating systems, so surely there's some download
> link somewhere.

What is this 'minetest-uri' supposed to do?  I assume it would be a
procedure like 'pypi-uri', 'cran-uri', 'crate-uri', which takes a
package name, the version and should return an URL string pointing to
a tarball.

That would be possible.  ContentDB allows for downloading zips:

https://github.com/minetest/contentdb/blob/master/docs/minetest_client.md#downloading-and-installing

The URL would look like: /packages/<author>/<name>/releases/<release>/download/.
Here, <release> is a the ‘release id’, which is an integer (e.g. 4209).  It
is _not_ the version number, but it is monotonically increasing.

There are some problems however:

  * Old archives are sometimes deleted.

    TenPlus1/ethereal was added to ContentDB on 2018-02-23, but it only has
    a single release on ContentDB, from 2021-07-28
    <https://content.minetest.net/packages/TenPlus1/ethereal/releases/>.
    Likewise for TenPlus1/bakedclay, TenPlus1/wine, TenPlus1/bees.

    Most other mods still have the old archives though (e.g., Jeija/mesecons,
    sfan5/worldedit, PilzAdam/nether).  The mods by TenPlus1 seems to be an
    exception.

  * The version number is not included in the download URL, the release id is.
    So IIUC, update-package-source in (guix upstream) would still need to be
    adjusted somewhat to support Minetest packages.

+(define* (make-package-sexp #:key
> > +                            (guix-name "minetest-foo")
> > +                            (home-page "https://example.org/foo")
> > +                            (repo "https://example.org/foo.git")
> > +                            (synopsis "synopsis")
> > +                            (guix-description "description")
> > +                            (guix-license
> > +                             '(list license:cc-by-sa4.0
> > license:lgpl3+))
> > +                            (inputs '())
> > +                            (upstream-name "Author/foo")
> > +                            #:allow-other-keys)
> > + [...]
> As noted above, this procedure would be somewhat simplified if we could
> define a (mintest-uri).
> 

I don't see how a 'minetest-uri' would simplify the definition of
'make-package-sexp'.  Using 'minetest-uri' would avoid the need
to specify the commit, but 'minetest-uri' needs a release id anyway,
so no simplification there.

I guess it would avoid the 'download-git-repository' procedure
and 'vcs-file?', but see two points above.  Also, 'latest-repository-commit'
returns a store path, which does not include the '.git' directory,
so 'vcs-file?' isn't necessary, so I removed 'vcs-file?'.

> > The revised patch series is attached.  It can also be found at
> > <https://notabug.org/maximed/guix-gnunet/src/minetest-2>;;.  It
> > includes the latest MINETEST_MOD_PATH patch.  I'll make the patch to
> > export more things in (guix build utils) later (for core-updates).
> For the rest of this, I'll only look over 06/20 v2.  I'll assume you
> did nothing naughty to 01..04.
> 
> > +;; A structure returned by the /api/packages/?fmt=keys endpoint
> > +(define-json-mapping <package/keys> make-package/keys package/keys?
> > +  json->package/keys
> > +  (author package/keys-author) ; string
> > +  (name package/keys-name)     ; string
> > +  (type package/keys-type))    ; string
> Not sure about this slash, as it typically specifies extension of some
> sort.  Perhaps just naming this package-keys would be better?

Done.

> > +(define (package-author/name package)
> > +  "Given a <package> object, return the corresponding AUTHOR/NAME
> > string."
> > +  (string-append (package-author package) "/" (package-name
> > package)))
> > +
> > +(define (package/keys-author/name package)
> > +  "Given a <package/keys> object, return the corresponding
> > AUTHOR/NAME string."
> > +  (string-append (package/keys-author package)
> > +                 "/" (package/keys-name package)))
> I think it's probably be better to merge this into a single procedure
> called "package-full-name", "package-unique-name" or "package-id"
> (whichever you prefer naming-wise), which handles both cases.

I like the name 'package-full-name'.  <package> and <package-keys>
are rather different structures and used in different contexts though,
so I kept package-full-name and package-keys-full-name separate.

FWIW, I added a procedure

(define (%construct-full-name author name)
  (string-append author "/" name))

used by 'package-full-name' and 'package-keys-full-name'.

> > +(define (contentdb->package-name name)
> > +  "Given the NAME of a package on ContentDB, return a Guix-compliant 
> > name for the
> > +package."
> > +  ;; The author is not included, as the names of popular mods
> > +  ;; tend to be unique.
> > +  (string-append "minetest-" (snake-case name)))
> I'd at least add an option to generate full names instead, for cases in
> which as before we warn about non-uniqueness.  Though actually, this
> comment is a little misleading as the actual stripping happens...
> > +     (name ,(contentdb->package-name (author/name->name
> > author/name)))
> here

ContentDB has a policy of requiring mod names to be unique in order to
be a ‘approved’, so I don't think name conflict will be a problem in
practice.  If full names were generated, keep in mind that dependencies
would need to use the full names a well.  I couldn't find any mods
with name conflicts.  I would just emit a warning for now.

contentdb->package-name was always used together with 'author/name->name',
so I modified contentdb->package-name to call author/name->name as you
seem to suggest.  It maked the code a little simpler.

Thanks,
Maxime.





[-- Attachment #1.2: guix-Add-ContentDB-importer.patch --]
[-- Type: text/x-patch, Size: 42657 bytes --]

From 39d869370e7a286fb30a06512c08fd3399d92d4f Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 14:44:11 +0200
Subject: [PATCH] guix: Add ContentDB importer.

* guix/import/contentdb.scm: New file.
* guix/scripts/import/contentdb.scm: New file.
* tests/contentdb.scm: New file.
* Makefile.am (MODULES, SCM_TESTS): Register them.
* po/guix/POTFILES.in: Likewise.
* doc/guix.texi (Invoking guix import): Document it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  32 +++
 guix/import/minetest.scm         | 456 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/minetest.scm | 117 ++++++++
 po/guix/POTFILES.in              |   1 +
 tests/minetest.scm               | 355 ++++++++++++++++++++++++
 7 files changed, 966 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/minetest.scm
 create mode 100644 guix/scripts/import/minetest.scm
 create mode 100644 tests/minetest.scm

diff --git a/Makefile.am b/Makefile.am
index f4439ce93b..6243583616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -262,6 +262,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/minetest.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
   guix/import/pypi.scm				\
@@ -304,6 +305,7 @@ MODULES =					\
   guix/scripts/import/go.scm			\
   guix/scripts/import/hackage.scm		\
   guix/scripts/import/json.scm  		\
+  guix/scripts/import/minetest.scm  		\
   guix/scripts/import/opam.scm			\
   guix/scripts/import/pypi.scm			\
   guix/scripts/import/stackage.scm		\
@@ -470,6 +472,7 @@ SCM_TESTS =					\
   tests/import-utils.scm			\
   tests/inferior.scm				\
   tests/lint.scm				\
+  tests/minetest.scm				\
   tests/modules.scm				\
   tests/monads.scm				\
   tests/nar.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index d44ecc2005..854e282b38 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -11314,6 +11314,38 @@ and generate package expressions for all those packages that are not yet
 in Guix.
 @end table
 
+@item contentdb
+@cindex minetest
+@cindex ContentDB
+Import metadata from @uref{https://content.minetest.net, ContentDB}.
+Information is taken from the JSON-formatted metadata provided through
+@uref{https://content.minetest.net/help/api/, ContentDB's API} and
+includes most relevant information, including dependencies.  There are
+some caveats, however.  The license information is often incomplete.
+The commit hash is sometimes missing.  The descriptions are in the
+Markdown format, but Guix uses Texinfo instead.  Texture packs and
+subgames are unsupported.
+
+The command below imports metadata for the Mesecons mod by Jeija:
+
+@example
+guix import minetest Jeija/mesecons
+@end example
+
+The author name can also be left out:
+
+@example
+guix import minetest mesecons
+@end example
+
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
 @item cpan
 @cindex CPAN
 Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}.
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
new file mode 100644
index 0000000000..e1f8487b75
--- /dev/null
+++ b/guix/import/minetest.scm
@@ -0,0 +1,456 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import minetest)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 threads)
+  #:use-module (ice-9 hash-table)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix utils)
+  #:use-module (guix ui)
+  #:use-module (guix i18n)
+  #:use-module (guix memoization)
+  #:use-module (guix serialization)
+  #:use-module (guix import utils)
+  #:use-module (guix import json)
+  #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256))
+  #:use-module (json)
+  #:use-module (guix base32)
+  #:use-module (guix git)
+  #:use-module (guix store)
+  #:export (%default-sort-key
+            %contentdb-api
+            json->package
+            contentdb-fetch
+            elaborate-contentdb-name
+            minetest->guix-package
+            minetest-recursive-import
+            sort-packages))
+
+;; The ContentDB API is documented at
+;; <https://content.minetest.net>.
+
+(define %contentdb-api
+  (make-parameter "https://content.minetest.net/api/"))
+
+(define (string-or-false x)
+  (and (string? x) x))
+
+(define (natural-or-false x)
+  (and (exact-integer? x) (>= x 0) x))
+
+;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
+(define (delete-cr text)
+  (string-delete #\cr text))
+
+\f
+
+;;;
+;;; JSON mappings
+;;;
+
+;; Minetest package.
+;;
+;; API endpoint: /packages/AUTHOR/NAME/
+(define-json-mapping <package> make-package package?
+  json->package
+  (author            package-author) ; string
+  (creation-date     package-creation-date ; string
+                     "created_at")
+  (downloads         package-downloads) ; integer
+  (forums            package-forums "forums" natural-or-false)
+  (issue-tracker     package-issue-tracker "issue_tracker") ; string
+  (license           package-license) ; string
+  (long-description  package-long-description "long_description") ; string
+  (maintainers       package-maintainers ; list of strings
+                     "maintainers" vector->list)
+  (media-license     package-media-license "media_license") ; string
+  (name              package-name) ; string
+  (provides          package-provides ; list of strings
+                     "provides" vector->list)
+  (release           package-release) ; integer
+  (repository        package-repository "repo" string-or-false)
+  (score             package-score) ; flonum
+  (screenshots       package-screenshots "screenshots" vector->list) ; list of strings
+  (short-description package-short-description "short_description") ; string
+  (state             package-state) ; string
+  (tags              package-tags "tags" vector->list) ; list of strings
+  (thumbnail         package-thumbnail) ; string
+  (title             package-title) ; string
+  (type              package-type) ; string
+  (url               package-url) ; string
+  (website           package-website "website" string-or-false))
+
+(define-json-mapping <release> make-release release?
+  json->release
+  ;; If present, a git commit identified by its hash
+  (commit               release-commit "commit" string-or-false)
+  (downloads            release-downloads) ; integer
+  (id                   release-id) ; integer
+  (max-minetest-version release-max-minetest-version string-or-false)
+  (min-minetest-version release-min-minetest-version string-or-false)
+  (release-date         release-data) ; string
+  (title                release-title) ; string
+  (url                  release-url)) ; string
+
+(define-json-mapping <dependency> make-dependency dependency?
+  json->dependency
+  (optional? dependency-optional? "is_optional") ; bool
+  (name dependency-name) ; string
+  (packages dependency-packages "packages" vector->list)) ; list of strings
+
+;; A structure returned by the /api/packages/?fmt=keys endpoint
+(define-json-mapping <package-keys> make-package-keys package-keys?
+  json->package-keys
+  (author package-keys-author) ; string
+  (name package-keys-name)     ; string
+  (type package-keys-type))    ; string
+
+(define (package-mod? package)
+  "Is the ContentDB package PACKAGE a mod?"
+  ;; ContentDB also has ‘games’ and ‘texture packs’.
+  (string=? (package-type package) "mod"))
+
+\f
+
+;;;
+;;; Manipulating names of packages
+;;;
+;;; There are three kind of names:
+;;;
+;;;   * names of guix packages, e.g. minetest-basic-materials.
+;;;   * names of mods on ContentDB, e.g. basic_materials
+;;;   * a combination of author and mod name on ContentDB, e.g. VanessaE/basic_materials
+;;;
+
+(define (%construct-full-name author name)
+  (string-append author "/" name))
+
+(define (package-full-name package)
+  "Given a <package> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-author package) (package-name package)))
+
+(define (package-keys-full-name package)
+  "Given a <package-keys> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-keys-author package)
+                        (package-keys-name package)))
+
+(define (contentdb->package-name author/name)
+  "Given the AUTHOR/NAME of a package on ContentDB, return a Guix-compliant
+name for the package."
+  ;; The author is not included, as the names of popular mods
+  ;; tend to be unique.
+  (string-append "minetest-" (snake-case (author/name->name author/name))))
+
+(define (author/name->name author/name)
+  "Extract NAME from the AUTHOR/NAME string, or raise an error if AUTHOR/NAME
+is ill-formatted."
+  (match (string-split author/name #\/)
+    ((author name)
+     (when (string-null? author)
+       (leave
+        (G_ "In ~a: author names must consist of at least a single character.~%")
+        author/name))
+     (when (string-null? name)
+       (leave
+        (G_ "In ~a: mod names must consist of at least a single character.~%")
+        author/name))
+     name)
+    ((too many . components)
+     (leave
+      (G_ "In ~a: author names and mod names may not contain forward slashes.~%")
+      author/name))
+    ((name)
+     (if (string-null? name)
+         (leave (G_ "mod names may not be empty.~%"))
+         (leave (G_ "The name of the author is missing in ~a.~%")
+                author/name)))))
+
+(define* (elaborate-contentdb-name name #:key (sort %default-sort-key))
+  "If NAME is an AUTHOR/NAME string, return it.  Otherwise, try to determine
+the author and return an appropriate AUTHOR/NAME string.  If that fails,
+raise an exception."
+  (if (or (string-contains name "/") (string-null? name))
+      ;; Call 'author/name->name' to verify that NAME seems reasonable
+      ;; and raise an appropriate exception if it isn't.
+      (begin
+        (author/name->name name)
+        name)
+      (let* ((package-keys (contentdb-query-packages name #:sort sort))
+             (correctly-named
+              (filter (lambda (package-key)
+                        (string=? name (package-keys-name package-key)))
+                      package-keys)))
+        (match correctly-named
+          ((one) (package-keys-full-name one))
+          ((too . many)
+           (warning (G_ "~a is ambigious, presuming ~a (other options include: ~a)~%")
+                    name (package-keys-full-name too)
+                    (map package-keys-full-name many))
+           (package-keys-full-name too))
+          (()
+           (leave (G_ "No mods with name ~a were found.~%") name))))))
+
+\f
+
+;;;
+;;; API endpoints
+;;;
+
+(define contentdb-fetch
+  (mlambda (author/name)
+    "Return a <package> record for package AUTHOR/NAME, or #f on failure."
+    (and=> (json-fetch
+            (string-append (%contentdb-api) "packages/" author/name "/"))
+           json->package)))
+
+(define (contentdb-fetch-releases author/name)
+  "Return a list of <release> records for package NAME by AUTHOR, or #f
+on failure."
+  (and=> (json-fetch (string-append (%contentdb-api) "packages/" author/name
+                                    "/releases/"))
+         (lambda (json)
+           (map json->release (vector->list json)))))
+
+(define (latest-release author/name)
+  "Return the latest source release for package NAME by AUTHOR,
+or #f if this package does not exist."
+  (and=> (contentdb-fetch-releases author/name)
+         car))
+
+(define (contentdb-fetch-dependencies author/name)
+  "Return an alist of lists of <dependency> records for package NAME by AUTHOR
+and possibly some other packages as well, or #f on failure."
+  (define url (string-append (%contentdb-api) "packages/" author/name
+                             "/dependencies/"))
+  (and=> (json-fetch url)
+         (lambda (json)
+           (map (match-lambda
+                  ((key . value)
+                   (cons key (map json->dependency (vector->list value)))))
+                json))))
+
+(define* (contentdb-query-packages q #:key
+                                   (type "mod")
+                                   (limit 50)
+                                   (sort %default-sort-key)
+                                   (order "desc"))
+  "Search ContentDB for Q (a string).  Sort by SORT, in ascending order
+if ORDER is \"asc\" or descending order if ORDER is \"desc\".  TYPE must
+be \"mod\", \"game\" or \"txp\", restricting thes search results to
+respectively mods, games and texture packs.  Limit to at most LIMIT
+results.  The return value is a list of <package-keys> records."
+  ;; XXX does Guile have something for constructing (and, when necessary,
+  ;; escaping) query strings?
+  (define url (string-append (%contentdb-api) "packages/?type=" type
+                             "&q=" q "&fmt=keys"
+                             "&limit=" (number->string limit)
+                             "&order=" order
+                             "&sort=" sort))
+  (let ((json (json-fetch url)))
+    (if json
+        (map json->package-keys (vector->list json))
+        (leave
+         (G_ "The package search API doesn't exist anymore.~%")))))
+
+\f
+
+;; XXX copied from (guix import elpa)
+(define* (download-git-repository url ref)
+  "Fetch the given REF from the Git repository at URL."
+  (with-store store
+    (latest-repository-commit store url #:ref ref)))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file)
+  "Compute the hash of FILE."
+  (let-values (((port get-hash) (open-sha256-port)))
+    (write-file file port)
+    (force-output port)
+    (get-hash)))
+
+(define (make-minetest-sexp author/name version repository commit
+                            inputs home-page synopsis
+                            description media-license license)
+  "Return a S-expression for the minetest package with the given author/NAME,
+VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
+MEDIA-LICENSE and LICENSE."
+  `(package
+     (name ,(contentdb->package-name author/name))
+     (version ,version)
+     (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+                (url ,repository)
+                (commit ,commit)))
+         (sha256
+          (base32
+           ;; The git commit is not always available.
+           ,(and commit
+                 (bytevector->nix-base32-string
+                  (file-hash
+                   (download-git-repository repository
+                                            `(commit . ,commit)))))))
+         (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs (map contentdb->package-name inputs))
+     (home-page ,home-page)
+     (synopsis ,(delete-cr synopsis))
+     (description ,(delete-cr description))
+     (license ,(if (eq? media-license license)
+                   license
+                   `(list ,media-license ,license)))
+     ;; The Minetest updater (not yet in Guix; it requires not-yet-submitted
+     ;; patches to (guix upstream) that require some work) needs to know both
+     ;; the author name and mod name for efficiency.
+     (properties ,(list 'quasiquote `((upstream-name . ,author/name))))))
+
+(define (package-home-page package)
+  "Guess the home page of the ContentDB package PACKAGE.
+
+In order of preference, try the 'website', the forum topic on the
+official Minetest forum and the Git repository (if any)."
+  (define (topic->url-sexp topic)
+    ;; 'minetest-topic' is a procedure defined in (gnu packages minetest)
+    `(minetest-topic ,topic))
+  (or (package-website package)
+      (and=> (package-forums package) topic->url-sexp)
+      (package-repository package)))
+
+;; If the default sort key is changed, make sure to modify 'show-help'
+;; in (guix scripts import minetest) appropriately as well.
+(define %default-sort-key "score")
+
+(define* (sort-packages packages #:key (sort %default-sort-key))
+  "Sort PACKAGES by SORT, in descending order."
+  (define package->key
+    (match sort
+      ("score" package-score)
+      ("downloads" package-downloads)))
+  (define (greater x y)
+    (> (package->key x) (package->key y)))
+  (sort-list packages greater))
+
+(define builtin-mod?
+  (let ((%builtin-mods
+         (alist->hash-table
+          (map (lambda (x) (cons x #t))
+               '("beds" "binoculars" "boats" "bones" "bucket" "butterflies"
+                 "carts" "creative" "default" "doors" "dungeon_loot" "dye"
+                 "env_sounds" "farming" "fire" "fireflies" "flowers"
+                 "game_commands" "give_initial_stuff" "map" "mtg_craftguide"
+                 "player_api" "screwdriver" "sethome" "sfinv" "spawn" "stairs"
+                 "tnt" "vessels" "walls" "weather" "wool" "xpanes")))))
+    (lambda (mod)
+      "Is MOD provided by the default minetest subgame?"
+      (hash-ref %builtin-mods mod))))
+
+(define* (important-dependencies dependencies author/name
+                                 #:key (sort %default-sort-key))
+  "Return the hard dependencies of AUTHOR/NAME in the association list
+DEPENDENCIES as a list of AUTHOR/NAME strings."
+  (define dependency-list
+    (assoc-ref dependencies author/name))
+  (filter-map
+   (lambda (dependency)
+     (and (not (dependency-optional? dependency))
+          (not (builtin-mod? (dependency-name dependency)))
+          ;; The dependency information contains symbolic names
+          ;; that can be ‘provided’ by multiple mods, so we need to choose one
+          ;; of the implementations.
+          (let* ((implementations
+                  (par-map contentdb-fetch (dependency-packages dependency)))
+                 ;; Fetching package information about the packages is racy:
+                 ;; some packages might be removed from ContentDB between the
+                 ;; construction of DEPENDENCIES and the call to
+                 ;; 'contentdb-fetch'.  So filter out #f.
+                 ;;
+                 ;; Filter out ‘games’ that include the requested mod -- it's
+                 ;; the mod itself we want.
+                 (mods (filter (lambda (p) (and=> p package-mod?))
+                               implementations))
+                 (sorted-mods (sort-packages mods #:sort sort)))
+            (match sorted-mods
+              ((package) (package-full-name package))
+              ((too . many)
+               (warning
+                (G_ "The dependency ~a of ~a has multiple different implementations ~a.~%")
+                (dependency-name dependency)
+                author/name
+                (map package-full-name sorted-mods))
+               (match sort
+                 ("score"
+                  (warning
+                   (G_ "The implementation with the highest score will be choosen!~%")))
+                 ("downloads"
+                  (warning
+                   (G_ "The implementation that has been downloaded the most will be choosen!~%"))))
+               (package-full-name too))
+              (()
+               (warning
+                (G_ "The dependency ~a of ~a does not have any implementation.  It will be ignored!~%")
+                (dependency-name dependency) author/name)
+               #f)))))
+   dependency-list))
+
+(define* (%minetest->guix-package author/name #:key (sort %default-sort-key))
+  "Fetch the metadata for AUTHOR/NAME from https://content.minetest.net, and
+return the 'package' S-expression corresponding to that package, or raise an
+exception on failure.  On success, also return the upstream dependencies as a
+list of AUTHOR/NAME strings."
+  ;; Call 'author/name->name' to verify that AUTHOR/NAME seems reasonable.
+  (author/name->name author/name)
+  (define package (contentdb-fetch author/name))
+  (unless package
+    (leave (G_ "no package metadata for ~a on ContentDB~%") author/name))
+  (define dependencies (contentdb-fetch-dependencies author/name))
+  (unless dependencies
+    (leave (G_ "no dependency information for ~a on ContentDB~%") author/name))
+  (define release (latest-release author/name))
+  (unless release
+    (leave (G_ "no release of ~a on ContentDB~%") author/name))
+  (define important-upstream-dependencies
+    (important-dependencies dependencies author/name #:sort sort))
+  (values (make-minetest-sexp author/name
+                              (release-title release) ; version
+                              (package-repository package)
+                              (release-commit release)
+                              important-upstream-dependencies
+                              (package-home-page package)
+                              (package-short-description package)
+                              (package-long-description package)
+                              (spdx-string->license
+                               (package-media-license package))
+                              (spdx-string->license
+                               (package-license package)))
+          important-upstream-dependencies))
+
+(define minetest->guix-package
+  (memoize %minetest->guix-package))
+
+(define* (minetest-recursive-import author/name #:key (sort %default-sort-key))
+  (define* (minetest->guix-package* author/name #:key repo version)
+    (minetest->guix-package author/name #:sort sort))
+  (recursive-import author/name
+                    #:repo->guix-package minetest->guix-package*
+                    #:guix-name contentdb->package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f53d1ac1f4..b369a362d0 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,8 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
-                    "gem" "go" "cran" "crate" "texlive" "json" "opam"))
+                    "gem" "go" "cran" "crate" "texlive" "json" "opam"
+                    "minetest"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/minetest.scm b/guix/scripts/import/minetest.scm
new file mode 100644
index 0000000000..5f204d90fc
--- /dev/null
+++ b/guix/scripts/import/minetest.scm
@@ -0,0 +1,117 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import minetest)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-minetest))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((sort . ,%default-sort-key)))
+
+(define (show-help)
+  (display (G_ "Usage: guix import minetest AUTHOR/NAME
+Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+      --sort=KEY         when choosing between multiple implementations,
+                         choose the one with the highest value for KEY
+                         (one of \"score\" (standard) or \"downloads\")"))
+  (newline)
+  (show-bug-report-information))
+
+(define (verify-sort-order sort)
+  "Verify SORT can be used to sort mods by."
+  (unless (member sort '("score" "downloads" "reviews"))
+    (leave (G_ "~a: not a valid key to sort by~%") sort))
+  sort)
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import minetest")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         (option '("sort") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'sort (verify-sort-order arg) result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-minetest . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((name)
+       (with-error-handling
+         (let* ((sort (assoc-ref opts 'sort))
+                (author/name (elaborate-contentdb-name name #:sort sort)))
+           (if (assoc-ref opts 'recursive)
+               ;; Recursive import
+               (filter-map package->definition
+                           (minetest-recursive-import author/name #:sort sort))
+               ;; Single import
+               (minetest->guix-package author/name #:sort sort)))))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index a3bced1a8f..f25a7b4802 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -60,6 +60,7 @@ guix/scripts/git.scm
 guix/scripts/git/authenticate.scm
 guix/scripts/hash.scm
 guix/scripts/import.scm
+guix/scripts/import/contentdb.scm
 guix/scripts/import/cran.scm
 guix/scripts/import/elpa.scm
 guix/scripts/pull.scm
diff --git a/tests/minetest.scm b/tests/minetest.scm
new file mode 100644
index 0000000000..6ae476fe5f
--- /dev/null
+++ b/tests/minetest.scm
@@ -0,0 +1,355 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-minetest)
+  #:use-module (guix memoization)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix tests)
+  #:use-module (json)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-64))
+
+\f
+;; Some procedures for populating a ‘fake’ ContentDB server.
+
+(define* (make-package-sexp #:key
+                            (guix-name "minetest-foo")
+                            (home-page "https://example.org/foo")
+                            (repo "https://example.org/foo.git")
+                            (synopsis "synopsis")
+                            (guix-description "description")
+                            (guix-license
+                             '(list license:cc-by-sa4.0 license:lgpl3+))
+                            (inputs '())
+                            (upstream-name "Author/foo")
+                            #:allow-other-keys)
+  `(package
+     (name ,guix-name)
+     ;; This is not a proper version number but ContentDB does not include
+     ;; version numbers.
+     (version "2021-07-25")
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url ,(and (not (eq? repo 'null)) repo))
+              (commit #f)))
+        (sha256
+         (base32 #f))
+        (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs inputs)
+     (home-page ,home-page)
+     (synopsis ,synopsis)
+     (description ,guix-description)
+     (license ,guix-license)
+     (properties
+      ,(list 'quasiquote
+             `((upstream-name . ,upstream-name))))))
+
+(define* (make-package-json #:key
+                            (author "Author")
+                            (name "foo")
+                            (media-license "CC-BY-SA-4.0")
+                            (license "LGPL-3.0-or-later")
+                            (short-description "synopsis")
+                            (long-description "description")
+                            (repo "https://example.org/foo.git")
+                            (website "https://example.org/foo")
+                            (forums 321)
+                            (score 987.654)
+                            (downloads 123)
+                            (type "mod")
+                            #:allow-other-keys)
+  `(("author" . ,author)
+    ("content_warnings" . #())
+    ("created_at" . "2018-05-23T19:58:07.422108")
+    ("downloads" . ,downloads)
+    ("forums" . ,forums)
+    ("issue_tracker" . "https://example.org/foo/issues")
+    ("license" . ,license)
+    ("long_description" . ,long-description)
+    ("maintainers" . #("maintainer"))
+    ("media_license" . ,media-license)
+    ("name" . ,name)
+    ("provides" . #("stuff"))
+    ("release" . 456)
+    ("repo" . ,repo)
+    ("score" . ,score)
+    ("screenshots" . #())
+    ("short_description" . ,short-description)
+    ("state" . "APPROVED")
+    ("tags" . #("some" "tags"))
+    ("thumbnail" . null)
+    ("title" . "The name")
+    ("type" . ,type)
+    ("url" . ,(string-append "https://content.minetest.net/packages/"
+                             author "/" name "/download/"))
+    ("website" . ,website)))
+
+(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
+  `#((("commit" . ,commit)
+      ("downloads" . 469)
+      ("id" . 8614)
+      ("max_minetest_version" . null)
+      ("min_minetest_version" . null)
+      ("release_date" . "2021-07-25T01:10:23.207584")
+      ("title" . "2021-07-25"))))
+
+(define* (make-dependencies-json #:key (author "Author")
+                                 (name "foo")
+                                 (requirements '(("default" #f ())))
+                                 #:allow-other-keys)
+  `((,(string-append author "/" name)
+     . ,(list->vector
+         (map (match-lambda
+                ((symbolic-name optional? implementations)
+                 `(("is_optional" . ,optional?)
+                   ("name" . ,symbolic-name)
+                   ("packages" . ,(list->vector implementations)))))
+              requirements)))
+    ("something/else" . #())))
+
+(define* (make-packages-keys-json #:key (author "Author")
+                                  (name "Name")
+                                  (type "mod"))
+  `(("author" . ,author)
+    ("name" . ,name)
+    ("type" . ,type)))
+
+(define (call-with-packages thunk . argument-lists)
+  ;; Don't reuse results from previous tests.
+  (invalidate-memoization! contentdb-fetch)
+  (invalidate-memoization! minetest->guix-package)
+  (define (scm->json-port scm)
+    (open-input-string (scm->json-string scm)))
+  (define (handle-package url requested-author requested-name . rest)
+    (define relevant-argument-list
+      (any (lambda (argument-list)
+             (apply (lambda* (#:key (author "Author") (name "foo")
+                              #:allow-other-keys)
+                      (and (equal? requested-author author)
+                           (equal? requested-name name)
+                           argument-list))
+                    argument-list))
+           argument-lists))
+    (when (not relevant-argument-list)
+      (error "the package ~a/~a should be irrelevant, but ~a is fetched"
+             requested-author requested-name url))
+    (scm->json-port
+     (apply (match rest
+              (("") make-package-json)
+              (("dependencies" "") make-dependencies-json)
+              (("releases" "") make-releases-json)
+              (_ (error "TODO ~a" rest)))
+            relevant-argument-list)))
+  (define (handle-mod-search sort)
+    ;; Produce search results, sorted by SORT in descending order.
+    (define arguments->key
+      (match sort
+        ("score" (lambda* (#:key (score 987.654) #:allow-other-keys)
+                   score))
+        ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys)
+                       downloads))))
+    (define argument-list->key (cut apply arguments->key <>))
+    (define (greater x y)
+      (> (argument-list->key x) (argument-list->key y)))
+    (define sorted-argument-lists (sort-list argument-lists greater))
+    (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod")
+                              #:allow-other-keys)
+      (and (string=? type "mod")
+           `(("author" . ,author)
+             ("name" . ,name)
+             ("type" . ,type))))
+    (define argument-list->json (cut apply arguments->json <>))
+    (scm->json-port
+     (list->vector (filter-map argument-list->json sorted-argument-lists))))
+  (mock ((guix http-client) http-fetch
+         (lambda* (url #:key headers)
+           (unless (string-prefix? "mock://api/packages/" url)
+             (error "the URL ~a should not be used" url))
+           (define resource
+             (substring url (string-length "mock://api/packages/")))
+           (define components (string-split resource #\/))
+           (match components
+             ((author name . rest)
+              (apply handle-package url author name rest))
+             (((? (cut string-prefix? "?type=mod&q=" <>) query))
+              (handle-mod-search
+               (cond ((string-contains query "sort=score") "score")
+                     ((string-contains query "sort=downloads") "downloads")
+                     (#t (error "search query ~a has unknown sort key"
+                                query)))))
+             (_
+              (error "the URL ~a should have an author and name component"
+                     url)))))
+        (parameterize ((%contentdb-api "mock://api/"))
+          (thunk))))
+
+(define* (minetest->guix-package* #:key (author "Author") (name "foo")
+                                  (sort %default-sort-key)
+                                  #:allow-other-keys)
+  (minetest->guix-package (string-append author "/" name) #:sort sort))
+
+(define (imported-package-sexp* primary-arguments . secondary-arguments)
+  "Ask the importer to import a package specified by PRIMARY-ARGUMENTS,
+during a dynamic where that package and the packages specified by
+SECONDARY-ARGUMENTS are available on ContentDB."
+  (apply call-with-packages
+         (lambda ()
+           ;; The memoization cache is reset by call-with-packages
+           (apply minetest->guix-package* primary-arguments))
+   primary-arguments
+   secondary-arguments))
+
+(define (imported-package-sexp . extra-arguments)
+  "Ask the importer to import a package specified by EXTRA-ARGUMENTS,
+during a dynamic extent where that package is available on ContentDB."
+  (imported-package-sexp* extra-arguments))
+
+(define-syntax-rule (test-package test-case . extra-arguments)
+  (test-equal test-case
+    (make-package-sexp . extra-arguments)
+    (imported-package-sexp . extra-arguments)))
+
+(define-syntax-rule (test-package* test-case primary-arguments extra-arguments
+                                   ...)
+  (test-equal test-case
+    (apply make-package-sexp primary-arguments)
+    (imported-package-sexp* primary-arguments extra-arguments ...)))
+
+(test-begin "minetest")
+
+\f
+;; Package names
+(test-package "minetest->guix-package")
+(test-package "minetest->guix-package, _ → - in package name"
+              #:name "foo_bar"
+              #:guix-name "minetest-foo-bar"
+              #:upstream-name "Author/foo_bar")
+
+(test-equal "elaborate names, unambigious"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeija")
+   '(#:name "something" #:author "else")))
+
+(test-equal "elaborate name, ambigious (highest score)"
+  "Jeija/mesecons"
+  (call-with-packages
+   ;; #:sort "score" is the default
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeijc" #:score 777)
+   '(#:name "mesecons" #:author "Jeijb" #:score 888)
+   '(#:name "mesecons" #:author "Jeija" #:score 999)))
+
+
+(test-equal "elaborate name, ambigious (most downloads)"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons" #:sort "downloads")
+   '(#:name "mesecons" #:author "Jeijc" #:downloads 777)
+   '(#:name "mesecons" #:author "Jeijb" #:downloads 888)
+   '(#:name "mesecons" #:author "Jeija" #:downloads 999)))
+
+\f
+;; Determining the home page
+(test-package "minetest->guix-package, website is used as home page"
+              #:home-page "web://site"
+              #:website "web://site")
+(test-package "minetest->guix-package, if absent, the forum is used"
+              #:home-page '(minetest-topic 628)
+              #:forums 628
+              #:website 'null)
+(test-package "minetest->guix-package, if absent, the git repo is used"
+              #:home-page "https://github.com/minetest-mods/mesecons"
+              #:forums 'null
+              #:website 'null
+              #:repo "https://github.com/minetest-mods/mesecons")
+(test-package "minetest->guix-package, all home page information absent"
+              #:home-page #f
+              #:forums 'null
+              #:website 'null
+              #:repo 'null)
+
+\f
+
+;; Dependencies
+(test-package* "minetest->guix-package, unambigious dependency"
+  (list #:requirements '(("mesecons" #f
+                          ("Jeija/mesecons"
+                           "some-modpack/containing-mese")))
+        #:inputs '("minetest-mesecons"))
+  (list #:author "Jeija" #:name "mesecons")
+  (list #:author "some-modpack" #:name "containing-mese" #:type "modpack"))
+
+(test-package* "minetest->guix-package, ambigious dependency (highest score)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        ;; #:sort "score" is the default
+        #:inputs '("minetest-bar"))
+  (list #:author "Author" #:name "foo" #:score 0)
+  (list #:author "Author" #:name "bar" #:score 9999))
+
+(test-package* "minetest->guix-package, ambigious dependency (most downloads)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        #:inputs '("minetest-bar")
+        #:sort "downloads")
+  (list #:author "Author" #:name "foo" #:downloads 0)
+  (list #:author "Author" #:name "bar" #:downloads 9999))
+
+(test-package "minetest->guix-package, optional dependency"
+              #:requirements '(("mesecons" #t
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '())
+
+\f
+;; License
+(test-package "minetest->guix-package, identical licenses"
+              #:guix-license 'license:lgpl3+
+              #:license "LGPL-3.0-or-later"
+              #:media-license "LGPL-3.0-or-later")
+
+;; Sorting
+(let* ((make-package
+        (lambda arguments
+          (json->package (apply make-package-json arguments))))
+       (x (make-package #:score 0))
+       (y (make-package #:score 1))
+       (z (make-package #:score 2)))
+  (test-equal "sort-packages, already sorted"
+    (list z y x)
+    (sort-packages (list z y x)))
+  (test-equal "sort-packages, reverse"
+    (list z y x)
+    (sort-packages (list x y z))))
+
+(test-end "minetest")
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet)
  2021-08-09 20:00           ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet) Maxime Devos
@ 2021-08-09 20:04             ` Maxime Devos
  2021-08-09 21:45             ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Yes send now) Leo Prikler
  1 sibling, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-09 20:04 UTC (permalink / raw)
  To: Leo Prikler, 49828

[-- Attachment #1: Type: text/plain, Size: 108 bytes --]

Don't mind the subject line, I actually meant to sent this
but forgot to remove ‘XXX Don't send yet’.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Yes send now)
  2021-08-09 20:00           ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet) Maxime Devos
  2021-08-09 20:04             ` Maxime Devos
@ 2021-08-09 21:45             ` Leo Prikler
  2021-08-10 11:02               ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
  1 sibling, 1 reply; 71+ messages in thread
From: Leo Prikler @ 2021-08-09 21:45 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Montag, den 09.08.2021, 22:00 +0200 schrieb Maxime Devos:
> [...]
> The URL would look like:
> /packages/<author>/<name>/releases/<release>/download/.
> Here, <release> is a the ‘release id’, which is an integer (e.g.
> 4209).  It is _not_ the version number, but it is monotonically
> increasing.
> 
> There are some problems however:
> 
>   * Old archives are sometimes deleted.
> 
>     TenPlus1/ethereal was added to ContentDB on 2018-02-23, but it 
>     only has a single release on ContentDB, from 2021-07-28
>     [...]
>     Likewise for TenPlus1/bakedclay, TenPlus1/wine, TenPlus1/bees.
> 
>     Most other mods still have the old archives though (e.g., 
>     Jeija/mesecons, sfan5/worldedit, PilzAdam/nether).  The mods by 
>     TenPlus1 seems to be an exception.
> 
>   * The version number is not included in the download URL, the 
>     release id is.
>     So IIUC, update-package-source in (guix upstream) would still 
>     need to be adjusted somewhat to support Minetest packages.
> 
> +(define* (make-package-sexp #:key
> > > +                            (guix-name "minetest-foo")
> > > +                            (home-page "https://example.org/foo"
> > > )
> > > +                            (repo "https://example.org/foo.git")
> > > +                            (synopsis "synopsis")
> > > +                            (guix-description "description")
> > > +                            (guix-license
> > > +                             '(list license:cc-by-sa4.0
> > > license:lgpl3+))
> > > +                            (inputs '())
> > > +                            (upstream-name "Author/foo")
> > > +                            #:allow-other-keys)
> > > + [...]
> > As noted above, this procedure would be somewhat simplified if we
> > could define a (mintest-uri).
> > 
> 
> I don't see how a 'minetest-uri' would simplify the definition of
> 'make-package-sexp'.  Using 'minetest-uri' would avoid the need
> to specify the commit, but 'minetest-uri' needs a release id anyway,
> so no simplification there.
> 
> I guess it would avoid the 'download-git-repository' procedure
> and 'vcs-file?', but see two points above.  Also, 'latest-repository-
> commit' returns a store path, which does not include the '.git'
> directory, so 'vcs-file?' isn't necessary, so I removed 'vcs-file?'.
In other words, taking minetest-uri as is currently doesn't seem too
good of an idea.  Does the plain git/vcs updater work for those
packages then?  I assume at least some of the packages should be tagged
properly in git, are they not?

> [...]
> I like the name 'package-full-name'.  <package> and <package-keys> 
> are rather different structures and used in different contexts
> though, so I kept package-full-name and package-keys-full-name
> separate.
> 
> FWIW, I added a procedure
> 
> (define (%construct-full-name author name)
>   (string-append author "/" name))
> 
> used by 'package-full-name' and 'package-keys-full-name'.
Sounds good to me.

> > > +(define (contentdb->package-name name)
> > > +  "Given the NAME of a package on ContentDB, return a Guix-
> > > compliant 
> > > name for the
> > > +package."
> > > +  ;; The author is not included, as the names of popular mods
> > > +  ;; tend to be unique.
> > > +  (string-append "minetest-" (snake-case name)))
> > I'd at least add an option to generate full names instead, for
> > cases in
> > which as before we warn about non-uniqueness.  Though actually,
> > this
> > comment is a little misleading as the actual stripping happens...
> > > +     (name ,(contentdb->package-name (author/name->name
> > > author/name)))
> > here
> 
> ContentDB has a policy of requiring mod names to be unique in order
> to be a ‘approved’, so I don't think name conflict will be a problem
> in practice.  If full names were generated, keep in mind that
> dependencies would need to use the full names a well.  I couldn't
> find any mods with name conflicts.  I would just emit a warning for
> now.
Fair enough, if that requirement is actually enforced by ContentDB,
that's good.  It does make the AUTHOR/NAME URI syntax look a bit weird
tho.

> contentdb->package-name was always used together with 'author/name-
> >name', so I modified contentdb->package-name to call author/name-
> >name as you seem to suggest.  It maked the code a little simpler.
Well, that's one way of resolving this issue, another would have been
to move the comment to where it makes sense.

All in all, I think I'm rather content with this patch now, but I have
a final nitpick w.r.t the updater.  "upstream-name" is a weird name for
a property that will supposedly be used by only one updater (and even
if different updaters were to use it, would not each one have slightly
different, but perhaps sometimes overlapping expectations for that
field?)  I think a better solution would be to set home-page to the
ContentDB page, assuming that is acceptable.  If not, perhaps having a
"refresh-url" that is well defined over all refreshers and supersedes
home-page if specified might be a more appropriate solution.  

WDYT?





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-09 21:45             ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Yes send now) Leo Prikler
@ 2021-08-10 11:02               ` Maxime Devos
  2021-08-10 12:16                 ` Leo Prikler
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
  0 siblings, 2 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 11:02 UTC (permalink / raw)
  To: Leo Prikler, 49828


[-- Attachment #1.1: Type: text/plain, Size: 5418 bytes --]

Hi,

I re-ran "./pre-inst-env guix build [all-minetest-mods]" and it turns
out "minetest-unified-inventory" retains a reference to the corresponding
git checkout.  Using 'strip-store-file-name' instead of 'basename'
in 'guess-mod-name' in ‘build-system: Add 'minetest-mod-build-system'’
fixed this.

Leo Prikler schreef op ma 09-08-2021 om 23:45 [+0200]:
> Hi,
> 
> [...]
> In other words, taking minetest-uri as is currently doesn't seem too
> good of an idea.  Does the plain git/vcs updater work for those
> packages then?  I assume at least some of the packages should be tagged
> properly in git, are they not?

FWIW, there is no git/vcs updater, but there is a GitHub updater
(a git updater looking at tags in a git repository if the package
origin uses the git-fetch method could be written though).

The GitHub updater could theoretically work, but look at the output:

./pre-inst-env guix refresh minetest-{unified-inventory,unifieddyes,worldedit,throwing-arrows,throwing,technic,pipeworks,mobs-animal,mobs,mesecons,homedecor-modpack,ethereal,coloredwood,basic-
materials}

gnu/packages/minetest.scm:29:2: warning: no updater for minetest-basic-materials
gnu/packages/minetest.scm:54:2: warning: no updater for minetest-coloredwood
gnu/packages/minetest.scm:87:4: warning: no updater for minetest-ethereal
gnu/packages/minetest.scm:111:2: warning: no updater for minetest-homedecor-modpack
gnu/packages/minetest.scm:147:13: minetest-mesecons would be upgraded from 1.2.1-0.db58797 to 2017.03.05
gnu/packages/minetest.scm:178:2: warning: no updater for minetest-mobs
gnu/packages/minetest.scm:207:2: warning: no updater for minetest-mobs-animal
gnu/packages/minetest.scm:234:2: warning: no updater for minetest-pipeworks
gnu/packages/minetest.scm:265:2: warning: 'github' updater failed to determine available releases for minetest-technic
gnu/packages/minetest.scm:302:13: warning: 2020-08-14 is greater than the latest known version of minetest-throwing (1.1)
gnu/packages/minetest.scm:330:15: warning: 1.1-0.059cc89 is greater than the latest known version of minetest-throwing-arrows (1.1)
gnu/packages/minetest.scm:355:13: 1.3 is already the latest version of minetest-worldedit
gnu/packages/minetest.scm:376:2: warning: no updater for minetest-unifieddyes
gnu/packages/minetest.scm:408:13: minetest-unified-inventory would be upgraded from 2021-03-25-1 to 20180810

Apparently, the git repos of minetest mods often don't keep version numbers,
or aren't on github, or uses multiple version schemes simultanuously
(x.y[.z] version numbers + dates) ... "minetest-worldedit" is properly
tagged though.  For the other cases, an updater for ContentDB packages
may be required.

I modified the definition of 'minetest-throwing' to use "1.1" as 'version'
(the commit remains the same).

> All in all, I think I'm rather content with this patch now, but I have
> a final nitpick w.r.t the updater.  "upstream-name" is a weird name for
> a property that will supposedly be used by only one updater (and even
> if different updaters were to use it, would not each one have slightly
> different, but perhaps sometimes overlapping expectations for that
> field?)  I think a better solution would be to set home-page to the
> ContentDB page, assuming that is acceptable.  If not, perhaps having a
> "refresh-url" that is well defined over all refreshers and supersedes
> home-page if specified might be a more appropriate solution.  

'upstream-name' is used by the refresher of "egg", "cpan" and "opam".
I searched for "package-properties" in (guix import ...), and the only
package property used by refreshers in 'upstream-name'.  So using
anything other than 'upstream-name' for Minetest would be unusual.

The documentation of "guix refresh" mentions:

   Sometimes the upstream name differs from the package name used in
Guix, and ‘guix refresh’ needs a little help.  Most updaters honor the
‘upstream-name’ property in package definitions, which can be used to
that effect:

     (define-public network-manager
       (package
         (name "network-manager")
         ;; ...
         (properties '((upstream-name . "NetworkManager")))))

So using a different package property than 'upstream-name' would
be unexpected.

I assume 'refresh-url' would be
"https://content.minetest.net/api/packages/AUTHOR/NAME" for minetest
packages, "https://github.com/ocaml/opam-repository/packages/NAME"
for opam packages?  That seems rather verbose though, and every
refresher would have a different idea of how to fetch the package
description from the URL and interpret it, so this doesn't seem
to be an improvement over 'upstream-name' to me.

About pointing the home page to content.minetest.net: that would
work for the refresher, but the ContentDB page isn't really the
home page, not unlike how the pypi page for python packages isn't
the home page.  Likewise for opam and ocaml.  Compare

https://content.minetest.net/packages/Jeija/mesecons/

with https://mesecons.net/, which one seems more ‘homey’?  I'd
say the latter is the home page.

The revised patch series is attached.  Only
‘build-system: Add 'minetest-mod-build-system'’ and ‘gnu: Add minetest-throwing’
have been changed.  It can also be found at
<https://notabug.org/maximed/guix-gnunet/src/minetest-3>.

Greetings,
Maxime.

[-- Attachment #1.2: 0001-gnu-minetest-Respect-without-tests.patch --]
[-- Type: text/x-patch, Size: 1389 bytes --]

From 292dce14ea4811f1554965d83af5e33687cd00b7 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 14:50:32 +0200
Subject: [PATCH 01/20] gnu: minetest: Respect --without-tests.

* gnu/packages/games.scm
  (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
  of ',(%current-target-system)'. Remove trailing #t.
---
 gnu/packages/games.scm | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 8c6b5523f1..3e7086b398 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3590,13 +3590,12 @@ match, cannon keep, and grave-itation pit.")
                      (string-append (getcwd) "/games")) ; for check
              #t))
          (replace 'check
-           (lambda _
+           (lambda* (#:key tests? #:allow-other-keys)
              ;; Thanks to our substitutions, the tests should also run
              ;; when invoked on the target outside of `guix build'.
-             (unless ,(%current-target-system)
+             (when tests?
                (setenv "HOME" "/tmp")
-               (invoke "src/minetest" "--run-unittests"))
-             #t)))))
+               (invoke "src/minetest" "--run-unittests")))))))
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-- 
2.32.0


[-- Attachment #1.3: 0002-gnu-minetest-Search-for-mods-in-MINETEST_MOD_PATH.patch --]
[-- Type: text/x-patch, Size: 8409 bytes --]

From 54222f167107e36cb76f93c551aaee0659d17b40 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 18:08:44 +0200
Subject: [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.

* gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch:
  New file.
* gnu/packages/games.scm
  (minetest)[source]{patches}: Add it.
  (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/games.scm                        |   8 +-
 ...vironment-variable-MINETEST_MOD_PATH.patch | 156 ++++++++++++++++++
 3 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c80a9af78c..d96d4e3dbc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -801,6 +801,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
   %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
   %D%/packages/patches/adb-add-libraries.patch			\
+  %D%/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch	\
   %D%/packages/patches/aegis-constness-error.patch         	\
   %D%/packages/patches/aegis-perl-tempdir1.patch           	\
   %D%/packages/patches/aegis-perl-tempdir2.patch           	\
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 3e7086b398..48d46a0379 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3553,6 +3553,9 @@ match, cannon keep, and grave-itation pit.")
                (base32
                 "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8"))
               (modules '((guix build utils)))
+              (patches
+               (search-patches
+                "Add-environment-variable-MINETEST_MOD_PATH.patch"))
               (snippet
                '(begin
                   ;; Delete bundled libraries.
@@ -3599,7 +3602,10 @@ match, cannon keep, and grave-itation pit.")
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-            (files '("share/minetest/games")))))
+            (files '("share/minetest/games")))
+           (search-path-specification
+            (variable "MINETEST_MOD_PATH")
+            (files '("share/minetest/mods")))))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (inputs
diff --git a/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
new file mode 100644
index 0000000000..a74034a2c5
--- /dev/null
+++ b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
@@ -0,0 +1,156 @@
+From d10ea2ad7efc2364a8a2007b4c6d3e85511e2f84 Mon Sep 17 00:00:00 2001
+From: Maxime Devos <maximedevos@telenet.be>
+Date: Tue, 3 Aug 2021 01:00:23 +0200
+Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
+
+This adds an environment variable MINETEST_MOD_PATH.
+When it exists, Minetest will look there for mods
+in addition to ~/.minetest/mods/.  Mods can still be
+installed to ~/.minetest/mods/ with the built-in installer.
+
+With thanks to Leo Prikler.
+---
+ builtin/mainmenu/pkgmgr.lua       |  7 +++----
+ doc/menu_lua_api.txt              |  8 +++++++-
+ src/content/subgames.cpp          | 11 +++++++++++
+ src/script/lua_api/l_mainmenu.cpp | 23 +++++++++++++++++++++++
+ src/script/lua_api/l_mainmenu.h   |  2 ++
+ 5 files changed, 46 insertions(+), 5 deletions(-)
+
+diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
+index 787936e31..d8fba0ebe 100644
+--- a/builtin/mainmenu/pkgmgr.lua
++++ b/builtin/mainmenu/pkgmgr.lua
+@@ -682,10 +682,9 @@ function pkgmgr.preparemodlist(data)
+ 	local game_mods = {}
+ 
+ 	--read global mods
+-	local modpath = core.get_modpath()
+-
+-	if modpath ~= nil and
+-		modpath ~= "" then
++	local modpaths = core.get_modpaths()
++	--XXX what was ‘modpath ~= ""’ and ‘modpath ~= nil’ for?
++	for _,modpath in ipairs(modpaths) do
+ 		get_mods(modpath,global_mods)
+ 	end
+ 
+diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
+index b3975bc1d..132444b14 100644
+--- a/doc/menu_lua_api.txt
++++ b/doc/menu_lua_api.txt
+@@ -218,7 +218,13 @@ Package - content which is downloadable from the content db, may or may not be i
+     * returns path to global user data,
+       the directory that contains user-provided mods, worlds, games, and texture packs.
+ * core.get_modpath() (possible in async calls)
+-    * returns path to global modpath
++    * returns path to global modpath, where mods can be installed
++* core.get_modpaths() (possible in async calls)
++    * returns list of paths to global modpaths, where mods have been installed
++
++      The difference with "core.get_modpath" is that no mods should be installed in these
++      directories by Minetest -- they might be read-only.
++
+ * core.get_clientmodpath() (possible in async calls)
+     * returns path to global client-side modpath
+ * core.get_gamepath() (possible in async calls)
+diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
+index e9dc609b0..d73f95a1f 100644
+--- a/src/content/subgames.cpp
++++ b/src/content/subgames.cpp
+@@ -61,6 +61,12 @@ std::string getSubgamePathEnv()
+ 	return subgame_path ? std::string(subgame_path) : "";
+ }
+ 
++std::string getModPathEnv()
++{
++	char *mod_path = getenv("MINETEST_MOD_PATH");
++	return mod_path ? std::string(mod_path) : "";
++}
++
+ SubgameSpec findSubgame(const std::string &id)
+ {
+ 	if (id.empty())
+@@ -110,6 +116,11 @@ SubgameSpec findSubgame(const std::string &id)
+ 	std::set<std::string> mods_paths;
+ 	if (!user_game)
+ 		mods_paths.insert(share + DIR_DELIM + "mods");
++
++	Strfnd mod_search_paths(getModPathEnv());
++	while (!mod_search_paths.at_end())
++		mods_paths.insert(mod_search_paths.next(PATH_DELIM));
++
+ 	if (user != share || user_game)
+ 		mods_paths.insert(user + DIR_DELIM + "mods");
+ 
+diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
+index 3e9709bde..903ac3a22 100644
+--- a/src/script/lua_api/l_mainmenu.cpp
++++ b/src/script/lua_api/l_mainmenu.cpp
+@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ #include "lua_api/l_internal.h"
+ #include "common/c_content.h"
+ #include "cpp_api/s_async.h"
++#include "util/strfnd.h"
+ #include "gui/guiEngine.h"
+ #include "gui/guiMainMenu.h"
+ #include "gui/guiKeyChangeMenu.h"
+@@ -502,6 +503,26 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
+ 	return 1;
+ }
+ 
++/******************************************************************************/
++int ModApiMainMenu::l_get_modpaths(lua_State *L)
++{
++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
++	if (c_modpath == NULL)
++		c_modpath = "";
++	int index = 1;
++	lua_newtable(L);
++	Strfnd mod_search_paths{std::string(c_modpath)};
++	while (!mod_search_paths.at_end()) {
++		std::string component = mod_search_paths.next(PATH_DELIM);
++		lua_pushstring(L, component.c_str());
++		lua_rawseti(L, -2, index);
++		index++;
++	}
++	ModApiMainMenu::l_get_modpath(L);
++	lua_rawseti(L, -2, index);
++	return 1;
++}
++
+ /******************************************************************************/
+ int ModApiMainMenu::l_get_clientmodpath(lua_State *L)
+ {
+@@ -949,6 +970,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+@@ -983,6 +1005,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
+index 33ac9e721..a6a54a2cb 100644
+--- a/src/script/lua_api/l_mainmenu.h
++++ b/src/script/lua_api/l_mainmenu.h
+@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
+ 
+ 	static int l_get_modpath(lua_State *L);
+ 
++	static int l_get_modpaths(lua_State *L);
++
+ 	static int l_get_clientmodpath(lua_State *L);
+ 
+ 	static int l_get_gamepath(lua_State *L);
+-- 
+2.32.0
+
-- 
2.32.0


[-- Attachment #1.4: 0003-gnu-minetest-New-package-module.patch --]
[-- Type: text/x-patch, Size: 2531 bytes --]

From f5148ad853b113db84634912c3eaa936d689eb22 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 18:32:50 +0200
Subject: [PATCH 03/20] gnu: minetest: New package module.

Aside from the 'minetest-topic' procedure which will be used
for the 'home-page' field of some packages, this module is
currently empty.  The 'contentdb' importer defined in the
following patches will be used to populate this module.

* gnu/packages/minetest.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk              |  1 +
 gnu/packages/minetest.scm | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 gnu/packages/minetest.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index d96d4e3dbc..5de08b1b09 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -383,6 +383,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/mercury.scm			\
   %D%/packages/mes.scm				\
   %D%/packages/messaging.scm			\
+  %D%/packages/minetest.scm			\
   %D%/packages/mingw.scm			\
   %D%/packages/microcom.scm			\
   %D%/packages/moe.scm				\
diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
new file mode 100644
index 0000000000..f8aca3005c
--- /dev/null
+++ b/gnu/packages/minetest.scm
@@ -0,0 +1,26 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+(define-module (gnu packages minetest)
+  #:use-module (guix packages)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system minetest)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public (minetest-topic topic-id)
+  "Return an URL (as a string) pointing to the forum topic with
+numeric identifier TOPIC-ID on the official Minetest forums."
+  (string-append "https://forum.minetest.net/viewtopic.php?t="
+                 (number->string topic-id)))
-- 
2.32.0


[-- Attachment #1.5: 0004-build-system-Add-minetest-mod-build-system.patch --]
[-- Type: text/x-patch, Size: 16197 bytes --]

From 545499de52c6869df498b0df5d5b403d05448fe3 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 13:52:39 +0200
Subject: [PATCH 04/20] build-system: Add 'minetest-mod-build-system'.

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  99 ++++++++++++
 guix/build/minetest-build-system.scm | 226 +++++++++++++++++++++++++++
 4 files changed, 335 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..d44ecc2005 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying Lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..f33e97559d
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,99 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys
+                    #:rest arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         (substitute-keyword-arguments arguments
+           ;; minetest-mod-build-system adds implicit inputs by itself,
+           ;; so don't let gnu-build-system add its own implicit inputs
+           ;; as well.
+           ((#:implicit-inputs? implicit-inputs? #t)
+            #f)
+           ((#:implicit-cross-inputs? implicit-cross-inputs? #t)
+            #f)
+           ((#:imported-modules imported-modules %minetest-build-system-modules)
+            imported-modules)
+           ((#:modules modules %default-modules)
+            modules)
+           ((#:phases phases '%standard-phases)
+            phases)
+           ;; Ensure nothing sneaks into the closure.
+           ((#:allowed-references allowed-references '())
+            allowed-references)
+           ;; Add the implicit inputs.
+           ((#:native-inputs native-inputs '())
+            (if implicit-inputs?
+                (append native-inputs (standard-minetest-packages))
+                native-inputs)))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..4968d3f560
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,226 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module ((guix build copy-build-system) #:prefix copy:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+;; (guix build copy-build-system) does not export 'install'.
+(define copy:install
+  (assoc-ref copy:%standard-phases 'install))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make the guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           ;; Don't retain a reference to the store.
+           (file-name (strip-store-file-name source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-minetest")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply copy:install
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimise."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0


[-- Attachment #1.6: 0005-import-utils-Recognise-GPL-3.0-or-later-and-friends.patch --]
[-- Type: text/x-patch, Size: 3318 bytes --]

From 8cf2245d9ecdd6f8dd65d5bf2b9bf6532511ca5b Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Thu, 5 Aug 2021 21:00:41 +0200
Subject: [PATCH 05/20] import/utils: Recognise GPL-3.0-or-later and friends.

* guix/import/utils.scm (spdx-string->license): Recognise
  GPL-N-only and GPL-N-or-later.  Likewise for LGPL and AGPL.
---
 guix/import/utils.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index d817318a91..d1b8076ddd 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -133,8 +133,14 @@ of the string VERSION is replaced by the symbol 'version."
   ;; Please update guix/licenses.scm when modifying
   ;; this list to avoid mismatches.
   (match str
+    ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later".
+    ;; "GPL-N" has been deprecated in favour of "GPL-N-only"
+    ;; or "GPL-N-or-later" as appropriate.  Likewise for LGPL
+    ;; and AGPL
     ("AGPL-1.0"                    'license:agpl1)
     ("AGPL-3.0"                    'license:agpl3)
+    ("AGPL-3.0-only"               'license:agpl3)
+    ("AGPL-3.0-or-later"           'license:agpl3+)
     ("Apache-1.1"                  'license:asl1.1)
     ("Apache-2.0"                  'license:asl2.0)
     ("BSL-1.0"                     'license:boost1.0)
@@ -161,11 +167,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("GFDL-1.3"                    'license:fdl1.3+)
     ("Giftware"                    'license:giftware)
     ("GPL-1.0"                     'license:gpl1)
+    ("GPL-1.0-only"                'license:gpl1)
     ("GPL-1.0+"                    'license:gpl1+)
+    ("GPL-1.0-or-later"            'license:gpl1+)
     ("GPL-2.0"                     'license:gpl2)
+    ("GPL-2.0-only"                'license:gpl2)
     ("GPL-2.0+"                    'license:gpl2+)
+    ("GPL-2.0-or-later"            'license:gpl2+)
     ("GPL-3.0"                     'license:gpl3)
+    ("GPL-3.0-only"                'license:gpl3)
     ("GPL-3.0+"                    'license:gpl3+)
+    ("GPL-3.0-or-later"            'license:gpl3+)
     ("ISC"                         'license:isc)
     ("IJG"                         'license:ijg)
     ("Imlib2"                      'license:imlib2)
@@ -173,11 +185,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("IPL-1.0"                     'license:ibmpl1.0)
     ("LAL-1.3"                     'license:lal1.3)
     ("LGPL-2.0"                    'license:lgpl2.0)
+    ("LGPL-2.0-only"               'license:lgpl2.0)
     ("LGPL-2.0+"                   'license:lgpl2.0+)
+    ("LGPL-2.0-or-later"           'license:lgpl2.0+)
     ("LGPL-2.1"                    'license:lgpl2.1)
+    ("LGPL-2.1-only"               'license:lgpl2.1)
     ("LGPL-2.1+"                   'license:lgpl2.1+)
+    ("LGPL-2.1-or-later"           'license:lgpl2.1+)
     ("LGPL-3.0"                    'license:lgpl3)
+    ("LGPL-3.0-only"               'license:lgpl3)
     ("LGPL-3.0+"                   'license:lgpl3+)
+    ("LGPL-3.0-or-later"           'license:lgpl3+)
     ("MPL-1.0"                     'license:mpl1.0)
     ("MPL-1.1"                     'license:mpl1.1)
     ("MPL-2.0"                     'license:mpl2.0)
-- 
2.32.0


[-- Attachment #1.7: 0006-guix-Add-ContentDB-importer.patch --]
[-- Type: text/x-patch, Size: 42663 bytes --]

From 65614c021ad33f4116d631a7e24a356d9236803b Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 14:44:11 +0200
Subject: [PATCH 06/20] guix: Add ContentDB importer.

* guix/import/contentdb.scm: New file.
* guix/scripts/import/contentdb.scm: New file.
* tests/contentdb.scm: New file.
* Makefile.am (MODULES, SCM_TESTS): Register them.
* po/guix/POTFILES.in: Likewise.
* doc/guix.texi (Invoking guix import): Document it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  32 +++
 guix/import/minetest.scm         | 456 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/minetest.scm | 117 ++++++++
 po/guix/POTFILES.in              |   1 +
 tests/minetest.scm               | 355 ++++++++++++++++++++++++
 7 files changed, 966 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/minetest.scm
 create mode 100644 guix/scripts/import/minetest.scm
 create mode 100644 tests/minetest.scm

diff --git a/Makefile.am b/Makefile.am
index f4439ce93b..6243583616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -262,6 +262,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/minetest.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
   guix/import/pypi.scm				\
@@ -304,6 +305,7 @@ MODULES =					\
   guix/scripts/import/go.scm			\
   guix/scripts/import/hackage.scm		\
   guix/scripts/import/json.scm  		\
+  guix/scripts/import/minetest.scm  		\
   guix/scripts/import/opam.scm			\
   guix/scripts/import/pypi.scm			\
   guix/scripts/import/stackage.scm		\
@@ -470,6 +472,7 @@ SCM_TESTS =					\
   tests/import-utils.scm			\
   tests/inferior.scm				\
   tests/lint.scm				\
+  tests/minetest.scm				\
   tests/modules.scm				\
   tests/monads.scm				\
   tests/nar.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index d44ecc2005..854e282b38 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -11314,6 +11314,38 @@ and generate package expressions for all those packages that are not yet
 in Guix.
 @end table
 
+@item contentdb
+@cindex minetest
+@cindex ContentDB
+Import metadata from @uref{https://content.minetest.net, ContentDB}.
+Information is taken from the JSON-formatted metadata provided through
+@uref{https://content.minetest.net/help/api/, ContentDB's API} and
+includes most relevant information, including dependencies.  There are
+some caveats, however.  The license information is often incomplete.
+The commit hash is sometimes missing.  The descriptions are in the
+Markdown format, but Guix uses Texinfo instead.  Texture packs and
+subgames are unsupported.
+
+The command below imports metadata for the Mesecons mod by Jeija:
+
+@example
+guix import minetest Jeija/mesecons
+@end example
+
+The author name can also be left out:
+
+@example
+guix import minetest mesecons
+@end example
+
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
 @item cpan
 @cindex CPAN
 Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}.
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
new file mode 100644
index 0000000000..e1f8487b75
--- /dev/null
+++ b/guix/import/minetest.scm
@@ -0,0 +1,456 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import minetest)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 threads)
+  #:use-module (ice-9 hash-table)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix utils)
+  #:use-module (guix ui)
+  #:use-module (guix i18n)
+  #:use-module (guix memoization)
+  #:use-module (guix serialization)
+  #:use-module (guix import utils)
+  #:use-module (guix import json)
+  #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256))
+  #:use-module (json)
+  #:use-module (guix base32)
+  #:use-module (guix git)
+  #:use-module (guix store)
+  #:export (%default-sort-key
+            %contentdb-api
+            json->package
+            contentdb-fetch
+            elaborate-contentdb-name
+            minetest->guix-package
+            minetest-recursive-import
+            sort-packages))
+
+;; The ContentDB API is documented at
+;; <https://content.minetest.net>.
+
+(define %contentdb-api
+  (make-parameter "https://content.minetest.net/api/"))
+
+(define (string-or-false x)
+  (and (string? x) x))
+
+(define (natural-or-false x)
+  (and (exact-integer? x) (>= x 0) x))
+
+;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
+(define (delete-cr text)
+  (string-delete #\cr text))
+
+\f
+
+;;;
+;;; JSON mappings
+;;;
+
+;; Minetest package.
+;;
+;; API endpoint: /packages/AUTHOR/NAME/
+(define-json-mapping <package> make-package package?
+  json->package
+  (author            package-author) ; string
+  (creation-date     package-creation-date ; string
+                     "created_at")
+  (downloads         package-downloads) ; integer
+  (forums            package-forums "forums" natural-or-false)
+  (issue-tracker     package-issue-tracker "issue_tracker") ; string
+  (license           package-license) ; string
+  (long-description  package-long-description "long_description") ; string
+  (maintainers       package-maintainers ; list of strings
+                     "maintainers" vector->list)
+  (media-license     package-media-license "media_license") ; string
+  (name              package-name) ; string
+  (provides          package-provides ; list of strings
+                     "provides" vector->list)
+  (release           package-release) ; integer
+  (repository        package-repository "repo" string-or-false)
+  (score             package-score) ; flonum
+  (screenshots       package-screenshots "screenshots" vector->list) ; list of strings
+  (short-description package-short-description "short_description") ; string
+  (state             package-state) ; string
+  (tags              package-tags "tags" vector->list) ; list of strings
+  (thumbnail         package-thumbnail) ; string
+  (title             package-title) ; string
+  (type              package-type) ; string
+  (url               package-url) ; string
+  (website           package-website "website" string-or-false))
+
+(define-json-mapping <release> make-release release?
+  json->release
+  ;; If present, a git commit identified by its hash
+  (commit               release-commit "commit" string-or-false)
+  (downloads            release-downloads) ; integer
+  (id                   release-id) ; integer
+  (max-minetest-version release-max-minetest-version string-or-false)
+  (min-minetest-version release-min-minetest-version string-or-false)
+  (release-date         release-data) ; string
+  (title                release-title) ; string
+  (url                  release-url)) ; string
+
+(define-json-mapping <dependency> make-dependency dependency?
+  json->dependency
+  (optional? dependency-optional? "is_optional") ; bool
+  (name dependency-name) ; string
+  (packages dependency-packages "packages" vector->list)) ; list of strings
+
+;; A structure returned by the /api/packages/?fmt=keys endpoint
+(define-json-mapping <package-keys> make-package-keys package-keys?
+  json->package-keys
+  (author package-keys-author) ; string
+  (name package-keys-name)     ; string
+  (type package-keys-type))    ; string
+
+(define (package-mod? package)
+  "Is the ContentDB package PACKAGE a mod?"
+  ;; ContentDB also has ‘games’ and ‘texture packs’.
+  (string=? (package-type package) "mod"))
+
+\f
+
+;;;
+;;; Manipulating names of packages
+;;;
+;;; There are three kind of names:
+;;;
+;;;   * names of guix packages, e.g. minetest-basic-materials.
+;;;   * names of mods on ContentDB, e.g. basic_materials
+;;;   * a combination of author and mod name on ContentDB, e.g. VanessaE/basic_materials
+;;;
+
+(define (%construct-full-name author name)
+  (string-append author "/" name))
+
+(define (package-full-name package)
+  "Given a <package> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-author package) (package-name package)))
+
+(define (package-keys-full-name package)
+  "Given a <package-keys> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-keys-author package)
+                        (package-keys-name package)))
+
+(define (contentdb->package-name author/name)
+  "Given the AUTHOR/NAME of a package on ContentDB, return a Guix-compliant
+name for the package."
+  ;; The author is not included, as the names of popular mods
+  ;; tend to be unique.
+  (string-append "minetest-" (snake-case (author/name->name author/name))))
+
+(define (author/name->name author/name)
+  "Extract NAME from the AUTHOR/NAME string, or raise an error if AUTHOR/NAME
+is ill-formatted."
+  (match (string-split author/name #\/)
+    ((author name)
+     (when (string-null? author)
+       (leave
+        (G_ "In ~a: author names must consist of at least a single character.~%")
+        author/name))
+     (when (string-null? name)
+       (leave
+        (G_ "In ~a: mod names must consist of at least a single character.~%")
+        author/name))
+     name)
+    ((too many . components)
+     (leave
+      (G_ "In ~a: author names and mod names may not contain forward slashes.~%")
+      author/name))
+    ((name)
+     (if (string-null? name)
+         (leave (G_ "mod names may not be empty.~%"))
+         (leave (G_ "The name of the author is missing in ~a.~%")
+                author/name)))))
+
+(define* (elaborate-contentdb-name name #:key (sort %default-sort-key))
+  "If NAME is an AUTHOR/NAME string, return it.  Otherwise, try to determine
+the author and return an appropriate AUTHOR/NAME string.  If that fails,
+raise an exception."
+  (if (or (string-contains name "/") (string-null? name))
+      ;; Call 'author/name->name' to verify that NAME seems reasonable
+      ;; and raise an appropriate exception if it isn't.
+      (begin
+        (author/name->name name)
+        name)
+      (let* ((package-keys (contentdb-query-packages name #:sort sort))
+             (correctly-named
+              (filter (lambda (package-key)
+                        (string=? name (package-keys-name package-key)))
+                      package-keys)))
+        (match correctly-named
+          ((one) (package-keys-full-name one))
+          ((too . many)
+           (warning (G_ "~a is ambigious, presuming ~a (other options include: ~a)~%")
+                    name (package-keys-full-name too)
+                    (map package-keys-full-name many))
+           (package-keys-full-name too))
+          (()
+           (leave (G_ "No mods with name ~a were found.~%") name))))))
+
+\f
+
+;;;
+;;; API endpoints
+;;;
+
+(define contentdb-fetch
+  (mlambda (author/name)
+    "Return a <package> record for package AUTHOR/NAME, or #f on failure."
+    (and=> (json-fetch
+            (string-append (%contentdb-api) "packages/" author/name "/"))
+           json->package)))
+
+(define (contentdb-fetch-releases author/name)
+  "Return a list of <release> records for package NAME by AUTHOR, or #f
+on failure."
+  (and=> (json-fetch (string-append (%contentdb-api) "packages/" author/name
+                                    "/releases/"))
+         (lambda (json)
+           (map json->release (vector->list json)))))
+
+(define (latest-release author/name)
+  "Return the latest source release for package NAME by AUTHOR,
+or #f if this package does not exist."
+  (and=> (contentdb-fetch-releases author/name)
+         car))
+
+(define (contentdb-fetch-dependencies author/name)
+  "Return an alist of lists of <dependency> records for package NAME by AUTHOR
+and possibly some other packages as well, or #f on failure."
+  (define url (string-append (%contentdb-api) "packages/" author/name
+                             "/dependencies/"))
+  (and=> (json-fetch url)
+         (lambda (json)
+           (map (match-lambda
+                  ((key . value)
+                   (cons key (map json->dependency (vector->list value)))))
+                json))))
+
+(define* (contentdb-query-packages q #:key
+                                   (type "mod")
+                                   (limit 50)
+                                   (sort %default-sort-key)
+                                   (order "desc"))
+  "Search ContentDB for Q (a string).  Sort by SORT, in ascending order
+if ORDER is \"asc\" or descending order if ORDER is \"desc\".  TYPE must
+be \"mod\", \"game\" or \"txp\", restricting thes search results to
+respectively mods, games and texture packs.  Limit to at most LIMIT
+results.  The return value is a list of <package-keys> records."
+  ;; XXX does Guile have something for constructing (and, when necessary,
+  ;; escaping) query strings?
+  (define url (string-append (%contentdb-api) "packages/?type=" type
+                             "&q=" q "&fmt=keys"
+                             "&limit=" (number->string limit)
+                             "&order=" order
+                             "&sort=" sort))
+  (let ((json (json-fetch url)))
+    (if json
+        (map json->package-keys (vector->list json))
+        (leave
+         (G_ "The package search API doesn't exist anymore.~%")))))
+
+\f
+
+;; XXX copied from (guix import elpa)
+(define* (download-git-repository url ref)
+  "Fetch the given REF from the Git repository at URL."
+  (with-store store
+    (latest-repository-commit store url #:ref ref)))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file)
+  "Compute the hash of FILE."
+  (let-values (((port get-hash) (open-sha256-port)))
+    (write-file file port)
+    (force-output port)
+    (get-hash)))
+
+(define (make-minetest-sexp author/name version repository commit
+                            inputs home-page synopsis
+                            description media-license license)
+  "Return a S-expression for the minetest package with the given author/NAME,
+VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
+MEDIA-LICENSE and LICENSE."
+  `(package
+     (name ,(contentdb->package-name author/name))
+     (version ,version)
+     (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+                (url ,repository)
+                (commit ,commit)))
+         (sha256
+          (base32
+           ;; The git commit is not always available.
+           ,(and commit
+                 (bytevector->nix-base32-string
+                  (file-hash
+                   (download-git-repository repository
+                                            `(commit . ,commit)))))))
+         (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs (map contentdb->package-name inputs))
+     (home-page ,home-page)
+     (synopsis ,(delete-cr synopsis))
+     (description ,(delete-cr description))
+     (license ,(if (eq? media-license license)
+                   license
+                   `(list ,media-license ,license)))
+     ;; The Minetest updater (not yet in Guix; it requires not-yet-submitted
+     ;; patches to (guix upstream) that require some work) needs to know both
+     ;; the author name and mod name for efficiency.
+     (properties ,(list 'quasiquote `((upstream-name . ,author/name))))))
+
+(define (package-home-page package)
+  "Guess the home page of the ContentDB package PACKAGE.
+
+In order of preference, try the 'website', the forum topic on the
+official Minetest forum and the Git repository (if any)."
+  (define (topic->url-sexp topic)
+    ;; 'minetest-topic' is a procedure defined in (gnu packages minetest)
+    `(minetest-topic ,topic))
+  (or (package-website package)
+      (and=> (package-forums package) topic->url-sexp)
+      (package-repository package)))
+
+;; If the default sort key is changed, make sure to modify 'show-help'
+;; in (guix scripts import minetest) appropriately as well.
+(define %default-sort-key "score")
+
+(define* (sort-packages packages #:key (sort %default-sort-key))
+  "Sort PACKAGES by SORT, in descending order."
+  (define package->key
+    (match sort
+      ("score" package-score)
+      ("downloads" package-downloads)))
+  (define (greater x y)
+    (> (package->key x) (package->key y)))
+  (sort-list packages greater))
+
+(define builtin-mod?
+  (let ((%builtin-mods
+         (alist->hash-table
+          (map (lambda (x) (cons x #t))
+               '("beds" "binoculars" "boats" "bones" "bucket" "butterflies"
+                 "carts" "creative" "default" "doors" "dungeon_loot" "dye"
+                 "env_sounds" "farming" "fire" "fireflies" "flowers"
+                 "game_commands" "give_initial_stuff" "map" "mtg_craftguide"
+                 "player_api" "screwdriver" "sethome" "sfinv" "spawn" "stairs"
+                 "tnt" "vessels" "walls" "weather" "wool" "xpanes")))))
+    (lambda (mod)
+      "Is MOD provided by the default minetest subgame?"
+      (hash-ref %builtin-mods mod))))
+
+(define* (important-dependencies dependencies author/name
+                                 #:key (sort %default-sort-key))
+  "Return the hard dependencies of AUTHOR/NAME in the association list
+DEPENDENCIES as a list of AUTHOR/NAME strings."
+  (define dependency-list
+    (assoc-ref dependencies author/name))
+  (filter-map
+   (lambda (dependency)
+     (and (not (dependency-optional? dependency))
+          (not (builtin-mod? (dependency-name dependency)))
+          ;; The dependency information contains symbolic names
+          ;; that can be ‘provided’ by multiple mods, so we need to choose one
+          ;; of the implementations.
+          (let* ((implementations
+                  (par-map contentdb-fetch (dependency-packages dependency)))
+                 ;; Fetching package information about the packages is racy:
+                 ;; some packages might be removed from ContentDB between the
+                 ;; construction of DEPENDENCIES and the call to
+                 ;; 'contentdb-fetch'.  So filter out #f.
+                 ;;
+                 ;; Filter out ‘games’ that include the requested mod -- it's
+                 ;; the mod itself we want.
+                 (mods (filter (lambda (p) (and=> p package-mod?))
+                               implementations))
+                 (sorted-mods (sort-packages mods #:sort sort)))
+            (match sorted-mods
+              ((package) (package-full-name package))
+              ((too . many)
+               (warning
+                (G_ "The dependency ~a of ~a has multiple different implementations ~a.~%")
+                (dependency-name dependency)
+                author/name
+                (map package-full-name sorted-mods))
+               (match sort
+                 ("score"
+                  (warning
+                   (G_ "The implementation with the highest score will be choosen!~%")))
+                 ("downloads"
+                  (warning
+                   (G_ "The implementation that has been downloaded the most will be choosen!~%"))))
+               (package-full-name too))
+              (()
+               (warning
+                (G_ "The dependency ~a of ~a does not have any implementation.  It will be ignored!~%")
+                (dependency-name dependency) author/name)
+               #f)))))
+   dependency-list))
+
+(define* (%minetest->guix-package author/name #:key (sort %default-sort-key))
+  "Fetch the metadata for AUTHOR/NAME from https://content.minetest.net, and
+return the 'package' S-expression corresponding to that package, or raise an
+exception on failure.  On success, also return the upstream dependencies as a
+list of AUTHOR/NAME strings."
+  ;; Call 'author/name->name' to verify that AUTHOR/NAME seems reasonable.
+  (author/name->name author/name)
+  (define package (contentdb-fetch author/name))
+  (unless package
+    (leave (G_ "no package metadata for ~a on ContentDB~%") author/name))
+  (define dependencies (contentdb-fetch-dependencies author/name))
+  (unless dependencies
+    (leave (G_ "no dependency information for ~a on ContentDB~%") author/name))
+  (define release (latest-release author/name))
+  (unless release
+    (leave (G_ "no release of ~a on ContentDB~%") author/name))
+  (define important-upstream-dependencies
+    (important-dependencies dependencies author/name #:sort sort))
+  (values (make-minetest-sexp author/name
+                              (release-title release) ; version
+                              (package-repository package)
+                              (release-commit release)
+                              important-upstream-dependencies
+                              (package-home-page package)
+                              (package-short-description package)
+                              (package-long-description package)
+                              (spdx-string->license
+                               (package-media-license package))
+                              (spdx-string->license
+                               (package-license package)))
+          important-upstream-dependencies))
+
+(define minetest->guix-package
+  (memoize %minetest->guix-package))
+
+(define* (minetest-recursive-import author/name #:key (sort %default-sort-key))
+  (define* (minetest->guix-package* author/name #:key repo version)
+    (minetest->guix-package author/name #:sort sort))
+  (recursive-import author/name
+                    #:repo->guix-package minetest->guix-package*
+                    #:guix-name contentdb->package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f53d1ac1f4..b369a362d0 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,8 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
-                    "gem" "go" "cran" "crate" "texlive" "json" "opam"))
+                    "gem" "go" "cran" "crate" "texlive" "json" "opam"
+                    "minetest"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/minetest.scm b/guix/scripts/import/minetest.scm
new file mode 100644
index 0000000000..5f204d90fc
--- /dev/null
+++ b/guix/scripts/import/minetest.scm
@@ -0,0 +1,117 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import minetest)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-minetest))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((sort . ,%default-sort-key)))
+
+(define (show-help)
+  (display (G_ "Usage: guix import minetest AUTHOR/NAME
+Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+      --sort=KEY         when choosing between multiple implementations,
+                         choose the one with the highest value for KEY
+                         (one of \"score\" (standard) or \"downloads\")"))
+  (newline)
+  (show-bug-report-information))
+
+(define (verify-sort-order sort)
+  "Verify SORT can be used to sort mods by."
+  (unless (member sort '("score" "downloads" "reviews"))
+    (leave (G_ "~a: not a valid key to sort by~%") sort))
+  sort)
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import minetest")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         (option '("sort") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'sort (verify-sort-order arg) result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-minetest . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((name)
+       (with-error-handling
+         (let* ((sort (assoc-ref opts 'sort))
+                (author/name (elaborate-contentdb-name name #:sort sort)))
+           (if (assoc-ref opts 'recursive)
+               ;; Recursive import
+               (filter-map package->definition
+                           (minetest-recursive-import author/name #:sort sort))
+               ;; Single import
+               (minetest->guix-package author/name #:sort sort)))))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index a3bced1a8f..f25a7b4802 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -60,6 +60,7 @@ guix/scripts/git.scm
 guix/scripts/git/authenticate.scm
 guix/scripts/hash.scm
 guix/scripts/import.scm
+guix/scripts/import/contentdb.scm
 guix/scripts/import/cran.scm
 guix/scripts/import/elpa.scm
 guix/scripts/pull.scm
diff --git a/tests/minetest.scm b/tests/minetest.scm
new file mode 100644
index 0000000000..6ae476fe5f
--- /dev/null
+++ b/tests/minetest.scm
@@ -0,0 +1,355 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-minetest)
+  #:use-module (guix memoization)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix tests)
+  #:use-module (json)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-64))
+
+\f
+;; Some procedures for populating a ‘fake’ ContentDB server.
+
+(define* (make-package-sexp #:key
+                            (guix-name "minetest-foo")
+                            (home-page "https://example.org/foo")
+                            (repo "https://example.org/foo.git")
+                            (synopsis "synopsis")
+                            (guix-description "description")
+                            (guix-license
+                             '(list license:cc-by-sa4.0 license:lgpl3+))
+                            (inputs '())
+                            (upstream-name "Author/foo")
+                            #:allow-other-keys)
+  `(package
+     (name ,guix-name)
+     ;; This is not a proper version number but ContentDB does not include
+     ;; version numbers.
+     (version "2021-07-25")
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url ,(and (not (eq? repo 'null)) repo))
+              (commit #f)))
+        (sha256
+         (base32 #f))
+        (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs inputs)
+     (home-page ,home-page)
+     (synopsis ,synopsis)
+     (description ,guix-description)
+     (license ,guix-license)
+     (properties
+      ,(list 'quasiquote
+             `((upstream-name . ,upstream-name))))))
+
+(define* (make-package-json #:key
+                            (author "Author")
+                            (name "foo")
+                            (media-license "CC-BY-SA-4.0")
+                            (license "LGPL-3.0-or-later")
+                            (short-description "synopsis")
+                            (long-description "description")
+                            (repo "https://example.org/foo.git")
+                            (website "https://example.org/foo")
+                            (forums 321)
+                            (score 987.654)
+                            (downloads 123)
+                            (type "mod")
+                            #:allow-other-keys)
+  `(("author" . ,author)
+    ("content_warnings" . #())
+    ("created_at" . "2018-05-23T19:58:07.422108")
+    ("downloads" . ,downloads)
+    ("forums" . ,forums)
+    ("issue_tracker" . "https://example.org/foo/issues")
+    ("license" . ,license)
+    ("long_description" . ,long-description)
+    ("maintainers" . #("maintainer"))
+    ("media_license" . ,media-license)
+    ("name" . ,name)
+    ("provides" . #("stuff"))
+    ("release" . 456)
+    ("repo" . ,repo)
+    ("score" . ,score)
+    ("screenshots" . #())
+    ("short_description" . ,short-description)
+    ("state" . "APPROVED")
+    ("tags" . #("some" "tags"))
+    ("thumbnail" . null)
+    ("title" . "The name")
+    ("type" . ,type)
+    ("url" . ,(string-append "https://content.minetest.net/packages/"
+                             author "/" name "/download/"))
+    ("website" . ,website)))
+
+(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
+  `#((("commit" . ,commit)
+      ("downloads" . 469)
+      ("id" . 8614)
+      ("max_minetest_version" . null)
+      ("min_minetest_version" . null)
+      ("release_date" . "2021-07-25T01:10:23.207584")
+      ("title" . "2021-07-25"))))
+
+(define* (make-dependencies-json #:key (author "Author")
+                                 (name "foo")
+                                 (requirements '(("default" #f ())))
+                                 #:allow-other-keys)
+  `((,(string-append author "/" name)
+     . ,(list->vector
+         (map (match-lambda
+                ((symbolic-name optional? implementations)
+                 `(("is_optional" . ,optional?)
+                   ("name" . ,symbolic-name)
+                   ("packages" . ,(list->vector implementations)))))
+              requirements)))
+    ("something/else" . #())))
+
+(define* (make-packages-keys-json #:key (author "Author")
+                                  (name "Name")
+                                  (type "mod"))
+  `(("author" . ,author)
+    ("name" . ,name)
+    ("type" . ,type)))
+
+(define (call-with-packages thunk . argument-lists)
+  ;; Don't reuse results from previous tests.
+  (invalidate-memoization! contentdb-fetch)
+  (invalidate-memoization! minetest->guix-package)
+  (define (scm->json-port scm)
+    (open-input-string (scm->json-string scm)))
+  (define (handle-package url requested-author requested-name . rest)
+    (define relevant-argument-list
+      (any (lambda (argument-list)
+             (apply (lambda* (#:key (author "Author") (name "foo")
+                              #:allow-other-keys)
+                      (and (equal? requested-author author)
+                           (equal? requested-name name)
+                           argument-list))
+                    argument-list))
+           argument-lists))
+    (when (not relevant-argument-list)
+      (error "the package ~a/~a should be irrelevant, but ~a is fetched"
+             requested-author requested-name url))
+    (scm->json-port
+     (apply (match rest
+              (("") make-package-json)
+              (("dependencies" "") make-dependencies-json)
+              (("releases" "") make-releases-json)
+              (_ (error "TODO ~a" rest)))
+            relevant-argument-list)))
+  (define (handle-mod-search sort)
+    ;; Produce search results, sorted by SORT in descending order.
+    (define arguments->key
+      (match sort
+        ("score" (lambda* (#:key (score 987.654) #:allow-other-keys)
+                   score))
+        ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys)
+                       downloads))))
+    (define argument-list->key (cut apply arguments->key <>))
+    (define (greater x y)
+      (> (argument-list->key x) (argument-list->key y)))
+    (define sorted-argument-lists (sort-list argument-lists greater))
+    (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod")
+                              #:allow-other-keys)
+      (and (string=? type "mod")
+           `(("author" . ,author)
+             ("name" . ,name)
+             ("type" . ,type))))
+    (define argument-list->json (cut apply arguments->json <>))
+    (scm->json-port
+     (list->vector (filter-map argument-list->json sorted-argument-lists))))
+  (mock ((guix http-client) http-fetch
+         (lambda* (url #:key headers)
+           (unless (string-prefix? "mock://api/packages/" url)
+             (error "the URL ~a should not be used" url))
+           (define resource
+             (substring url (string-length "mock://api/packages/")))
+           (define components (string-split resource #\/))
+           (match components
+             ((author name . rest)
+              (apply handle-package url author name rest))
+             (((? (cut string-prefix? "?type=mod&q=" <>) query))
+              (handle-mod-search
+               (cond ((string-contains query "sort=score") "score")
+                     ((string-contains query "sort=downloads") "downloads")
+                     (#t (error "search query ~a has unknown sort key"
+                                query)))))
+             (_
+              (error "the URL ~a should have an author and name component"
+                     url)))))
+        (parameterize ((%contentdb-api "mock://api/"))
+          (thunk))))
+
+(define* (minetest->guix-package* #:key (author "Author") (name "foo")
+                                  (sort %default-sort-key)
+                                  #:allow-other-keys)
+  (minetest->guix-package (string-append author "/" name) #:sort sort))
+
+(define (imported-package-sexp* primary-arguments . secondary-arguments)
+  "Ask the importer to import a package specified by PRIMARY-ARGUMENTS,
+during a dynamic where that package and the packages specified by
+SECONDARY-ARGUMENTS are available on ContentDB."
+  (apply call-with-packages
+         (lambda ()
+           ;; The memoization cache is reset by call-with-packages
+           (apply minetest->guix-package* primary-arguments))
+   primary-arguments
+   secondary-arguments))
+
+(define (imported-package-sexp . extra-arguments)
+  "Ask the importer to import a package specified by EXTRA-ARGUMENTS,
+during a dynamic extent where that package is available on ContentDB."
+  (imported-package-sexp* extra-arguments))
+
+(define-syntax-rule (test-package test-case . extra-arguments)
+  (test-equal test-case
+    (make-package-sexp . extra-arguments)
+    (imported-package-sexp . extra-arguments)))
+
+(define-syntax-rule (test-package* test-case primary-arguments extra-arguments
+                                   ...)
+  (test-equal test-case
+    (apply make-package-sexp primary-arguments)
+    (imported-package-sexp* primary-arguments extra-arguments ...)))
+
+(test-begin "minetest")
+
+\f
+;; Package names
+(test-package "minetest->guix-package")
+(test-package "minetest->guix-package, _ → - in package name"
+              #:name "foo_bar"
+              #:guix-name "minetest-foo-bar"
+              #:upstream-name "Author/foo_bar")
+
+(test-equal "elaborate names, unambigious"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeija")
+   '(#:name "something" #:author "else")))
+
+(test-equal "elaborate name, ambigious (highest score)"
+  "Jeija/mesecons"
+  (call-with-packages
+   ;; #:sort "score" is the default
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeijc" #:score 777)
+   '(#:name "mesecons" #:author "Jeijb" #:score 888)
+   '(#:name "mesecons" #:author "Jeija" #:score 999)))
+
+
+(test-equal "elaborate name, ambigious (most downloads)"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons" #:sort "downloads")
+   '(#:name "mesecons" #:author "Jeijc" #:downloads 777)
+   '(#:name "mesecons" #:author "Jeijb" #:downloads 888)
+   '(#:name "mesecons" #:author "Jeija" #:downloads 999)))
+
+\f
+;; Determining the home page
+(test-package "minetest->guix-package, website is used as home page"
+              #:home-page "web://site"
+              #:website "web://site")
+(test-package "minetest->guix-package, if absent, the forum is used"
+              #:home-page '(minetest-topic 628)
+              #:forums 628
+              #:website 'null)
+(test-package "minetest->guix-package, if absent, the git repo is used"
+              #:home-page "https://github.com/minetest-mods/mesecons"
+              #:forums 'null
+              #:website 'null
+              #:repo "https://github.com/minetest-mods/mesecons")
+(test-package "minetest->guix-package, all home page information absent"
+              #:home-page #f
+              #:forums 'null
+              #:website 'null
+              #:repo 'null)
+
+\f
+
+;; Dependencies
+(test-package* "minetest->guix-package, unambigious dependency"
+  (list #:requirements '(("mesecons" #f
+                          ("Jeija/mesecons"
+                           "some-modpack/containing-mese")))
+        #:inputs '("minetest-mesecons"))
+  (list #:author "Jeija" #:name "mesecons")
+  (list #:author "some-modpack" #:name "containing-mese" #:type "modpack"))
+
+(test-package* "minetest->guix-package, ambigious dependency (highest score)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        ;; #:sort "score" is the default
+        #:inputs '("minetest-bar"))
+  (list #:author "Author" #:name "foo" #:score 0)
+  (list #:author "Author" #:name "bar" #:score 9999))
+
+(test-package* "minetest->guix-package, ambigious dependency (most downloads)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        #:inputs '("minetest-bar")
+        #:sort "downloads")
+  (list #:author "Author" #:name "foo" #:downloads 0)
+  (list #:author "Author" #:name "bar" #:downloads 9999))
+
+(test-package "minetest->guix-package, optional dependency"
+              #:requirements '(("mesecons" #t
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '())
+
+\f
+;; License
+(test-package "minetest->guix-package, identical licenses"
+              #:guix-license 'license:lgpl3+
+              #:license "LGPL-3.0-or-later"
+              #:media-license "LGPL-3.0-or-later")
+
+;; Sorting
+(let* ((make-package
+        (lambda arguments
+          (json->package (apply make-package-json arguments))))
+       (x (make-package #:score 0))
+       (y (make-package #:score 1))
+       (z (make-package #:score 2)))
+  (test-equal "sort-packages, already sorted"
+    (list z y x)
+    (sort-packages (list z y x)))
+  (test-equal "sort-packages, reverse"
+    (list z y x)
+    (sort-packages (list x y z))))
+
+(test-end "minetest")
-- 
2.32.0


[-- Attachment #1.8: 0007-gnu-Add-minetest-mesecons.patch --]
[-- Type: text/x-patch, Size: 2338 bytes --]

From eab75f7b436f6fd069262462841080bf692851d0 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:00:45 +0200
Subject: [PATCH 07/20] gnu: Add minetest-mesecons.

* gnu/packages/minetest.scm (minetest-mesecons): New variable.
---
 gnu/packages/minetest.scm | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f8aca3005c..d99efa4625 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -24,3 +24,39 @@
 numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
+
+(define-public minetest-mesecons
+  ;; The release on ContentDB does not have its own version number.
+  (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
+        (revision "0"))
+  (package
+    (name "minetest-mesecons")
+    (version (git-version "1.2.1" revision commit))
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/mesecons")
+             (commit commit)))
+       (sha256
+        (base32 "04m9s9l3frw1lgki41hgvjsw2zkrvfv0sy750b6j12arzb3lv645"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page "https://mesecons.net")
+    (synopsis
+     "Digital circuitry for Minetest, including wires, buttons and lights")
+    (description
+     "Mesecons is a mod for Minetest implementing various items related
+to digital circuitry, such as wires, buttons, lights and programmable
+controllers.  Among other things, there are also pistons, solar panels,
+pressure plates and note blocks.
+
+Mesecons has a similar goal to Redstone in Minecraft, but works in its own way,
+with different rules and mechanics.")
+    ;; LGPL for code, CC-BY-SA for textures.
+    ;; The README.md and COPYING.txt disagree about the "+" in license:lgpl3+.
+    ;; For now, assume README.md is correct.  Upstream has been asked to
+    ;; correct the inconsistency:
+    ;; <https://github.com/minetest-mods/mesecons/issues/575>.
+    (license (list license:lgpl3+ license:cc-by-sa3.0))
+    (properties `((upstream-name . "Jeija/mesecons"))))))
-- 
2.32.0


[-- Attachment #1.9: 0008-gnu-Add-minetest-basic-materials.patch --]
[-- Type: text/x-patch, Size: 1994 bytes --]

From 9b3d85969d5ac46a9b0e9b0f8cb347ec66df9d08 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:23:50 +0200
Subject: [PATCH 08/20] gnu: Add minetest-basic-materials.

* gnu/packages/minetest.scm (minetest-basic-materials): New variable.
---
 gnu/packages/minetest.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d99efa4625..97d4d3c9ac 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -25,6 +25,31 @@ numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
 
+(define-public minetest-basic-materials
+  (package
+    (name "minetest-basic-materials")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-01-30")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/basic_materials.git")
+             (commit "e72665b2ed98d7be115779a32d35e6d9ffa231bd")))
+       (sha256
+        (base32 "0v6l3lrjgshy4sccjhfhmfxc3gk0cdy73qb02i9wd2vw506v5asx"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 21000))
+    (synopsis "Some \"basic\" materials and items for other Minetest mods to use")
+    (description
+     "The Minetest mod \"basic_materials\" provides a small selection of
+\"basic\" materials and items that other mods should use when possible -- things
+like steel bars and chains, wire, plastic strips and sheets, and more.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/basic_materials")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #1.10: 0009-gnu-Add-minetest-unifieddyes.patch --]
[-- Type: text/x-patch, Size: 2029 bytes --]

From 52ed6ed145b054cf049a745d4c3c2ad85ebca57f Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 20:40:24 +0200
Subject: [PATCH 09/20] gnu: Add minetest-unifieddyes.

* gnu/packages/minetest.scm (minetest-unifieddyes): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 97d4d3c9ac..8b9eb30a6a 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -85,3 +85,32 @@ with different rules and mechanics.")
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
+
+(define-public minetest-unifieddyes
+  (package
+    (name "minetest-unifieddyes")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-20-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/unifieddyes")
+             (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
+       (sha256
+        (base32
+         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2178))
+    (synopsis
+     "Unified Dyes expands the standard dye set of Minetest to up to 256 colours")
+    (description "The purpose of this mod originally was to supply a complete
+set of colours for Minetest mod authors to use for colourised nodes or
+reference in recipes.  Since the advent of the default dyes mod in the standard
+Minetest game, this mod has become an extension of the default mod an a library
+for general colour handling.")
+    (license license:gpl2+)
+    (properties `((upstream-name . "VanessaE/unifieddyes")))))
-- 
2.32.0


[-- Attachment #1.11: 0010-gnu-Add-minetest-pipeworks.patch --]
[-- Type: text/x-patch, Size: 2266 bytes --]

From fd414b9da2fc746730536b7770240f2c32fdbee1 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sat, 31 Jul 2021 23:39:02 +0200
Subject: [PATCH 10/20] gnu: Add minetest-pipeworks.

* gnu/packages/minetest.scm (minetest-pipeworks): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 8b9eb30a6a..782166daef 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -86,6 +86,37 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-pipeworks
+  (package
+    (name "minetest-pipeworks")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/pipeworks")
+             (commit "db6d1bd9c109e1e543b97cc3fa8a11400da23bcd")))
+       (sha256
+        (base32 "1flhcnf17dn1v86kcg47a1n4cb0lybd11ncxrkxn3wmf10ibsrm0"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2155))
+    (synopsis "Pipes, item-transport tubes and related devices for Minetest")
+    (description
+     "Pipeworks is a mod for Minetest implementing 3D pipes and tubes for
+transporting liquids and items and some related devices.  Pipes and tubes can
+go horizontally or vertically.  Item tubes can also be used for sorting items
+and extracting items from chests or putting items in chests.  Autocrafters can
+automatically follow craft recipes to make new items and can be fed by item
+tubes.  Deployers can place items in the world as a player would.  Node
+breakers simulate a player punching a node.")
+    ;; CC-BY-SA for textures, LGPL for code
+    (license (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/pipeworks")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.12: 0011-gnu-Add-minetest-coloredwood.patch --]
[-- Type: text/x-patch, Size: 2041 bytes --]

From b9b98dc8bec8784e0941989da1f9cce7b5063412 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 00:50:12 +0200
Subject: [PATCH 11/20] gnu: Add minetest-coloredwood.

* gnu/packages/minetest.scm (minetest-coloredwood): New variable.
---
 gnu/packages/minetest.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 782166daef..4c542c6061 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -50,6 +50,34 @@ like steel bars and chains, wire, plastic strips and sheets, and more.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/basic_materials")))))
 
+(define-public minetest-coloredwood
+  (package
+    (name "minetest-coloredwood")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/coloredwood")
+             (commit "be4df6fc889419155bed8638bbb752493e78cbd5")))
+       (sha256
+        (base32 "1swirfk6b4xfbiwv8adyw5yl2lyfpp8ymfipzq9ivyvmif8nl3ki"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2411))
+    (synopsis "Painted wood in Minetest")
+    (description
+     "This Minetest mod provides hundreds of colours of wood and fences to
+Minetest, using Unified Dyes.  If the \"moreblocks\" mod is active,
+coloured and cut wood shapes are provided as well.")
+    (license
+     ;; LGPL for code, CC-BY-SA for textures
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/coloredwood")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #1.13: 0012-gnu-Add-minetest-ethereal.patch --]
[-- Type: text/x-patch, Size: 2697 bytes --]

From fdb72067e442979319220ca833f8e5088246eccd Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 01:24:48 +0200
Subject: [PATCH 12/20] gnu: Add minetest-ethereal.

* gnu/packages/minetest.scm (minetest-ethereal): New variable.
---
 gnu/packages/minetest.scm | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4c542c6061..a1aa90276d 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -78,6 +78,35 @@ coloured and cut wood shapes are provided as well.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/coloredwood")))))
 
+(define-public minetest-ethereal
+  ;; ContentDB release 2021-07-28 is slightly ahead of the
+  ;; initial version 1.29 -- i.e., some released changes have been
+  ;; made to version 1.29 without a corresponding version bump.
+  (let ((commit "7670c1da9274901f57f6682384af2b3bae005a86")
+        (revision "0"))
+    (package
+      (name "minetest-ethereal")
+      (version (git-version "1.29" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://notabug.org/TenPlus1/ethereal")
+               (commit commit)))
+         (sha256
+          (base32 "1hal8bq4fydsip7s8rqz4vlaaqy9rhzxmryd0j2qnqm9286yjgkk"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 14638))
+      (synopsis "The Ethereal mod adds many new biomes to Minetest")
+      (description
+       "The Ethereal Minetest mod uses the v7 map generator to add many new
+biomes to the world.  It adds new trees, plants, food items, tweaks and some
+special items, intending to make an interesting adventure.")
+      ;; CC0: some textures
+      (license (list license:cc0 license:expat))
+      (properties `((upstream-name . "TenPlus1/ethereal"))))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
@@ -157,8 +186,7 @@ breakers simulate a player punching a node.")
              (url "https://gitlab.com/VanessaE/unifieddyes")
              (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
        (sha256
-        (base32
-         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+        (base32 "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
        (file-name (git-file-name name version))))
     (build-system minetest-mod-build-system)
     (propagated-inputs
-- 
2.32.0


[-- Attachment #1.14: 0013-gnu-Add-minetest-technic.patch --]
[-- Type: text/x-patch, Size: 2279 bytes --]

From e9ddc33e346bbb1723bc77d396c3c6daff4e69ad Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 13:40:56 +0200
Subject: [PATCH 13/20] gnu: Add minetest-technic.

* gnu/packages/minetest.scm (minetest-technic): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index a1aa90276d..bb914f32b4 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -174,6 +174,41 @@ breakers simulate a player punching a node.")
     (license (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/pipeworks")))))
 
+(define-public minetest-technic
+  (package
+    (name "minetest-technic")
+    ;; Upstream doesn't keep version numbers, so use the release
+    ;; date on ContentDB instead.
+    (version "2021-04-15")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/technic")
+             (commit "1c219487d3f4dd03c01ff9aa1f298c7c18c7e189")))
+       (sha256
+        (base32 "1k9hdgzp7jnhsk6rgrlrv1lr5xrmh8ln4wv6r25v6f0fwbyj57sf"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-pipeworks" ,minetest-pipeworks)
+       ("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2538))
+    (synopsis "Machinery and automation for Minetest")
+    (description
+     "This Minetest mod adds machinery and automation to Minetest.
+It adds various ores that can be processed for constructing various
+machinery, such as power generators, force field emitters, quarries
+and a workshop for repairing tools.  Most machines are electrically
+powered.")
+    ;; CC BY-SA 3.0: some texture
+    ;; WTFPL: some textures
+    ;; CC BY-SA3.0: some textures
+    ;; CC BY-SA4.0: some sounds
+    (license (list license:lgpl2.1+ license:cc-by-sa3.0 license:cc-by-sa4.0
+                   license:wtfpl2))
+    (properties `((upstream-name . "RealBadAngel/technic")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.15: 0014-gnu-Add-minetest-throwing.patch --]
[-- Type: text/x-patch, Size: 1881 bytes --]

From f28bb06110b08f1f2816a748f8b1d4fe48371914 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 14:16:27 +0200
Subject: [PATCH 14/20] gnu: Add minetest-throwing.

* gnu/packages/minetest.scm (minetest-throwing): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index bb914f32b4..4566d94489 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -209,6 +209,33 @@ powered.")
                    license:wtfpl2))
     (properties `((upstream-name . "RealBadAngel/technic")))))
 
+(define-public minetest-throwing
+  ;; The latest release on ContentDB is ahead of the latet
+  ;; tagged commit.
+  (let ((commit "31f0cf5f868673dc82f24ddc432b45c9cd282d27")
+        (revision "0"))
+    (package
+      (name "minetest-throwing")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing")
+               (commit commit)))
+         (sha256
+          (base32 "1s5kkr6rxxv2dhbbjzv62gw1s617hnpjavw1v9fv11v3mgigdfjb"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 16365))
+      (synopsis "API for throwing things in Minetest")
+      (description
+       "This Minetest mod provides an API for registering throwable things and
+throwing things like arrows.  However, this mod does not provide an actual
+arrow and bow, but @code{minetest-throwing-arrows} does.")
+      (license license:mpl2.0)
+      (properties `((upstream-name . "Palige/throwing"))))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.16: 0015-gnu-Add-minetest-throwing-arrows.patch --]
[-- Type: text/x-patch, Size: 2102 bytes --]

From 3a54d4daa59cfa29f336071407816e40c5fbab7e Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 14:34:12 +0200
Subject: [PATCH 15/20] gnu: Add minetest-throwing-arrows.

* gnu/packages/minetest.scm
  (minetest-throwing-arrows): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4566d94489..1f785098f9 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -236,6 +236,36 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
       (license license:mpl2.0)
       (properties `((upstream-name . "Palige/throwing"))))))
 
+(define-public minetest-throwing-arrows
+  ;; There is only one tagged commit (version 1.1),
+  ;; there are no releases on ContentDB and the latest
+  ;; commit has a compatibility fix for Minetest 5.4.0-dev.
+  (let ((commit "059cc897af0aebfbd2c54ac5588f2b842f44f159")
+        (revision "0"))
+    (package
+      (name "minetest-throwing-arrows")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing_arrows")
+               (commit commit)))
+         (sha256
+          (base32 "0m2pmccpfxn878zd00pmrpga2h6gknz4f3qprck0fq94mksmwqs3"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (propagated-inputs
+       `(("minetest-throwing" ,minetest-throwing)))
+      (home-page (minetest-topic 16365))
+      (synopsis "Arrows and bows for Minetest")
+      (description
+       ;; TRANSLATORS: "throwing" is the name of a Minetest mod and should
+       ;; not be translated.
+       "This mod adds arrows and bows to Minetest.  It is a compatible
+replacement for the throwing mod by PilzAdam that uses the throwing API.")
+      (license license:mpl2.0))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.17: 0016-gnu-Add-minetest-unified-inventory.patch --]
[-- Type: text/x-patch, Size: 2370 bytes --]

From 826415b801ae96cc622233092252fea96b624a46 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 17:39:36 +0200
Subject: [PATCH 16/20] gnu: Add minetest-unified-inventory.

* gnu/packages/minetest.scm
  (minetest-unified-inventory): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 1f785098f9..d6ff6c9e47 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -293,3 +293,38 @@ Minetest game, this mod has become an extension of the default mod an a library
 for general colour handling.")
     (license license:gpl2+)
     (properties `((upstream-name . "VanessaE/unifieddyes")))))
+
+(define-public minetest-unified-inventory
+  (package
+    (name "minetest-unified-inventory")
+    ;; Upstream doesn't keep version numbers, so use the release title
+    ;; on ContentDB instead.
+    (version "2021-03-25-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/unified_inventory")
+             (commit "c044f5e3b08f0c68ab028d757b2fa63d9a1b0370")))
+       (sha256
+        (base32 "198g945gzbfl0kps46gwjw0c601l3b3wvn4c7dw8manskri1jr4g"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 12767))
+    (synopsis "Replace the default inventory in Minetest and add a crafting guide")
+    (description
+     "The Unified Inventory Minetest mod relaces the default survival an
+creative inventory.  It includes a node, item and tool browser, a crafting
+guide, a trash and refill slot for creative mode, bags and waypoints for keeping
+track of important locations.")
+    ;; CC-BY: some textures and icons
+    ;; CC-BY-SA: some textures and icons
+    ;; LGLPL2.1+: code and some textures
+    ;; GPL2+: some textures
+    ;; GPL3: bags.lua
+    ;; GFDL: some icons
+    ;; public domain, CC0: some icons
+    (license (list license:gpl3 license:gpl2+ license:lgpl2.1+ license:cc-by3.0
+                   license:cc-by4.0 license:cc-by-sa3.0 license:public-domain
+                   license:cc0 license:fdl1.2+))
+    (properties `((upstream-name . "RealBadAngel/unified_inventory")))))
-- 
2.32.0


[-- Attachment #1.18: 0017-gnu-Add-minetest-worldedit.patch --]
[-- Type: text/x-patch, Size: 1704 bytes --]

From 75a8e7069310d6a4ae3468d6cf26621413ff98f2 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 17:58:24 +0200
Subject: [PATCH 17/20] gnu: Add minetest-worldedit.

* gnu/packages/minetest.scm (minetest-worldedit): New variable.
---
 gnu/packages/minetest.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d6ff6c9e47..700a9b2872 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -266,6 +266,29 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
 replacement for the throwing mod by PilzAdam that uses the throwing API.")
       (license license:mpl2.0))))
 
+(define-public minetest-worldedit
+  (package
+    (name "minetest-worldedit")
+    (version "1.3")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/Uberi/Minetest-WorldEdit")
+             (commit "2f26fb76459c587868199160b9d7b5d6d7852e50")))
+       (sha256
+        (base32 "0lsvihkixi2na1b0vmml9vwgs0g24hqqshl73ffhkzh6jsq4cagq"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 572))
+    (synopsis "In-game world editor for Minetest")
+    (description
+     "WorldEdit is a mod for Minetest.  It allows for creating various
+geometric shapes and copying regions.  It can also export and import regions
+to and from the file system.")
+    (license license:agpl3)
+    (properties `((upstream-name . "sfan5/worldedit")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0


[-- Attachment #1.19: 0018-gnu-Add-minetest-mobs.patch --]
[-- Type: text/x-patch, Size: 2012 bytes --]

From be4ec577c21e90496754c5b5735efd0904417bd4 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 18:53:54 +0200
Subject: [PATCH 18/20] gnu: Add minetest-mobs.

* gnu/packages/minetest.scm (minetest-mobs): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 700a9b2872..d36ca06ef5 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -143,6 +143,35 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-mobs
+  (package
+    (name "minetest-mobs")
+    ;; Upstream does not tag release, so use the ContentDB release
+    ;; title instead.
+    (version "2021-07-22")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_redo")
+             (commit "9f46182bb4b1a390f9a140bc2b443f3cda702332")))
+       (sha256
+        (base32 "026kqjis4lipgskjivb3jh9ris3iz80vy2q1jvgxhxmfghjjzp4j"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 9917))
+    (synopsis "Mob library for Minetest mods, for animals, monsters etc.")
+    (description
+     "This Minetest mod provides an API for adding mods (moving entities
+like animals and monsters), but does not include any mobs itself.  To actually
+add some mobs, a mod like e.g. @code{mobs_animal} provided by the
+@code{minetest-mobs-animal} package needs to be enabled.")
+    ;; CC0: mob_swing.ogg
+    ;; CC-BY 3.0: mob_spell.ogg
+    ;; Expat: everything else
+    (license (list license:expat license:cc0 license:cc-by3.0))
+    (properties `((upstream-name . "TenPlus1/mobs")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0


[-- Attachment #1.20: 0019-gnu-Add-minetest-mobs-animal.patch --]
[-- Type: text/x-patch, Size: 1951 bytes --]

From a7baa3adb190936f8f99521f577ae9cef5211ab2 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 19:43:47 +0200
Subject: [PATCH 19/20] gnu: Add minetest-mobs-animal.

* gnu/packages/minetest.scm (minetest-mobs-animal): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d36ca06ef5..3cd14a6df8 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -172,6 +172,33 @@ add some mobs, a mod like e.g. @code{mobs_animal} provided by the
     (license (list license:expat license:cc0 license:cc-by3.0))
     (properties `((upstream-name . "TenPlus1/mobs")))))
 
+(define-public minetest-mobs-animal
+  (package
+    (name "minetest-mobs-animal")
+    ;; Upstream does not use version numbers, so use the release title
+    ;; from ContentDB instead;
+    (version "2021-07-24")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_animal")
+             (commit "c2fa3e300c79c7dd80b6fe91a8b5082bb6b3d934")))
+       (sha256
+        (base32 "1j719f079ia9vjxrmjrcj8s6jvaz5kgs1r4dh66z8ql6s70kx7vh"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-mobs" ,minetest-mobs)))
+    (home-page "https://notabug.org/TenPlus1/mobs_animal")
+    (synopsis "Add animals to Minetest")
+    (description
+     "This Minetest mod adds various animals to Minetest, such as bees,
+bunnies, chickens, cows, kittens, rats, sheep, warthogs, penguins and pandas.")
+    ;; CC0: some textures and sounds
+    (license (list license:cc0 license:expat))
+    (properties `((upstream-name . "TenPlus1/mobs_animal")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0


[-- Attachment #1.21: 0020-gnu-Add-minetest-homedecor-modpack.patch --]
[-- Type: text/x-patch, Size: 2249 bytes --]

From dbca87ad489d883487047af2c2a957a665096477 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 1 Aug 2021 20:03:07 +0200
Subject: [PATCH 20/20] gnu: Add minetest-homedecor-modpack.

* gnu/packages/minetest.scm
  (minetest-homedecor-modpack): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 3cd14a6df8..3bd640da45 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -107,6 +107,37 @@ special items, intending to make an interesting adventure.")
       (license (list license:cc0 license:expat))
       (properties `((upstream-name . "TenPlus1/ethereal"))))))
 
+(define-public minetest-homedecor-modpack
+  (package
+    (name "minetest-homedecor-modpack")
+    ;; Upstream doesn't tag releases, so use the release title from
+    ;; ContentDB as version.
+    (version "2021-03-27-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/homedecor_modpack")
+             (commit "9ffe2b7d691133e1a067546574fbe7364fd02f32")))
+       (sha256
+        (base32 "1lfajqvc2adf9hqskghky4arccqzpjw4i9a01hv4qcckvivm04ag"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)
+       ("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2041))
+    (synopsis "Home decor mod for Minetest")
+    (description
+     ;; TRANSLATORS: ‘homedecor’ is the name is the name of a Minetest mod
+     ;; and should not be translated.
+     "The homedecor Minetest mod provides a large seleection of items that
+might be found inside and around homes, such as sofas, chairs, tables, fences
+and a variety of other stuff.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/homedecor_modpack")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH 06/20] guix: Add ContentDB importer.
  2021-08-10 11:02               ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
@ 2021-08-10 12:16                 ` Leo Prikler
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
  1 sibling, 0 replies; 71+ messages in thread
From: Leo Prikler @ 2021-08-10 12:16 UTC (permalink / raw)
  To: Maxime Devos, 49828

Hi,

Am Dienstag, den 10.08.2021, 13:02 +0200 schrieb Maxime Devos:
> [...]
> FWIW, there is no git/vcs updater, but there is a GitHub updater
> (a git updater looking at tags in a git repository if the package
> origin uses the git-fetch method could be written though).
My bad, I thought that worked for more than just GitHub (having at
least GitLab as well would cover most git repos anyway.)

> The GitHub updater could theoretically work, but look at the output:
> 
> ./pre-inst-env guix refresh minetest-{unified-
> inventory,unifieddyes,worldedit,throwing-
> arrows,throwing,technic,pipeworks,mobs-
> animal,mobs,mesecons,homedecor-modpack,ethereal,coloredwood,basic-
> materials}
> [...]
> Apparently, the git repos of minetest mods often don't keep version
> numbers,
> or aren't on github, or uses multiple version schemes simultanuously
> (x.y[.z] version numbers + dates) ... "minetest-worldedit" is
> properly
> tagged though.  For the other cases, an updater for ContentDB
> packages
> may be required.
> 
> I modified the definition of 'minetest-throwing' to use "1.1" as
> 'version' (the commit remains the same).
Okay, it seems a separate updater using contentdb is still very much
needed.

> 'upstream-name' is used by the refresher of "egg", "cpan" and "opam".
> I searched for "package-properties" in (guix import ...), and the
> only
> package property used by refreshers in 'upstream-name'.  So using
> anything other than 'upstream-name' for Minetest would be unusual.
> 
> The documentation of "guix refresh" mentions:
> 
>    Sometimes the upstream name differs from the package name used in
> Guix, and ‘guix refresh’ needs a little help.  Most updaters honor
> the
> ‘upstream-name’ property in package definitions, which can be used to
> that effect:
> 
>      (define-public network-manager
>        (package
>          (name "network-manager")
>          ;; ...
>          (properties '((upstream-name . "NetworkManager")))))
> 
> So using a different package property than 'upstream-name' would
> be unexpected.
> [...]
Fair enough, I should probably read up on the code in `guix refresh` to
understand how it ensures the correct updater is chosen.

> About pointing the home page to content.minetest.net: that would
> work for the refresher, but the ContentDB page isn't really the
> home page, not unlike how the pypi page for python packages isn't
> the home page.  Likewise for opam and ocaml.  Compare
> 
> https://content.minetest.net/packages/Jeija/mesecons/
> 
> with https://mesecons.net/, which one seems more ‘homey’?  I'd
> say the latter is the home page.
Point taken.

> The revised patch series is attached.  Only
> ‘build-system: Add 'minetest-mod-build-system'’ and ‘gnu: Add
> minetest-throwing’
> have been changed.  It can also be found at
> <https://notabug.org/maximed/guix-gnunet/src/minetest-3>;.
Can you resend this v3 (with or without amendments to the points below)
via `git send-email'?  The series appears pretty "final" to me, but
having one mail per patch might make it easier for others to point out
issues if they find them.

> +           (file-name (if (string-suffix? "-checkout" file-name)
> +                          (substring file-name
> +                                     0
> +                                     (- (string-length file-name)
> +                                        (string-length "-
> minetest")))
> +                          file-name))
It is probably an accident, that "-checkout" and "-minetest" have the
same string length :P
I think we should probably add a (guix build utils) procedure to take
care of such string prefix/suffix stripping in next core-updates.

> +  (cond ((file-exists? "mod.conf")
> +         (read-mod-name "mod.conf"))
> +        ((file-exists? "modpack.conf")
> +         (read-mod-name "modpack.conf" guess))
> +        (#t (guess))))
Why do we yield an error if there's no name in mod.conf instead of
trying to read from modpack.conf or just guessing?

> [PATCH 14/20] gnu: Add minetest-throwing.
LGTM





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 00/20] Add minetest mods
  2021-08-10 11:02               ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
  2021-08-10 12:16                 ` Leo Prikler
@ 2021-08-10 15:07                 ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 01/20] gnu: minetest: Respect --without-tests Maxime Devos
                                     ` (19 more replies)
  1 sibling, 20 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

Hi Guix,

This patch series adds a bunch of Minetest mods, but first,
it patches Minetest such that the mods will actually be found.
An importer for Minetest mods from ContentDB
(https://content.minetest.net) is included as well.

Leo Prikler wrote:
  It is probably an accident, that "-checkout" and "-minetest" have the
  same string length :P

Fixed.

Leo Prikler wrote:
  > +  (cond ((file-exists? "mod.conf")
  > +         (read-mod-name "mod.conf"))
  > +        ((file-exists? "modpack.conf")
  > +         (read-mod-name "modpack.conf" guess))
  > +        (#t (guess))))
  Why do we yield an error if there's no name in mod.conf instead of
  trying to read from modpack.conf or just guessing?

IIUC, mod.conf must always have 'name' set.  This requirement
does not exist for "modpack.conf".  I added some comments to the
code in the v3.  I also corrected ‘make the guess’ -> ‘make a guess’
in a comment in 'guess-mod-name'.

Maxime Devos (20):
  gnu: minetest: Respect --without-tests.
  gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  gnu: minetest: New package module.
  build-system: Add 'minetest-mod-build-system'.
  import/utils: Recognise GPL-3.0-or-later and friends.
  guix: Add ContentDB importer.
  gnu: Add minetest-mesecons.
  gnu: Add minetest-basic-materials.
  gnu: Add minetest-unifieddyes.
  gnu: Add minetest-pipeworks.
  gnu: Add minetest-coloredwood.
  gnu: Add minetest-ethereal.
  gnu: Add minetest-technic.
  gnu: Add minetest-throwing.
  gnu: Add minetest-throwing-arrows.
  gnu: Add minetest-unified-inventory.
  gnu: Add minetest-worldedit.
  gnu: Add minetest-mobs.
  gnu: Add minetest-mobs-animal.
  gnu: Add minetest-homedecor-modpack.

 Makefile.am                                   |   5 +
 doc/guix.texi                                 |  40 ++
 gnu/local.mk                                  |   2 +
 gnu/packages/games.scm                        |  15 +-
 gnu/packages/minetest.scm                     | 440 +++++++++++++++++
 ...vironment-variable-MINETEST_MOD_PATH.patch | 156 ++++++
 guix/build-system/minetest.scm                |  99 ++++
 guix/build/minetest-build-system.scm          | 229 +++++++++
 guix/import/minetest.scm                      | 456 ++++++++++++++++++
 guix/import/utils.scm                         |  18 +
 guix/scripts/import.scm                       |   3 +-
 guix/scripts/import/minetest.scm              | 117 +++++
 po/guix/POTFILES.in                           |   1 +
 tests/minetest.scm                            | 355 ++++++++++++++
 14 files changed, 1930 insertions(+), 6 deletions(-)
 create mode 100644 gnu/packages/minetest.scm
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm
 create mode 100644 guix/import/minetest.scm
 create mode 100644 guix/scripts/import/minetest.scm
 create mode 100644 tests/minetest.scm

-- 
2.32.0





^ permalink raw reply	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 01/20] gnu: minetest: Respect --without-tests.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
                                     ` (18 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/games.scm
  (minetest)[arguments]<#:phases>{check}: Use 'tests?' instead
  of ',(%current-target-system)'. Remove trailing #t.
---
 gnu/packages/games.scm | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 8c6b5523f1..3e7086b398 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3590,13 +3590,12 @@ match, cannon keep, and grave-itation pit.")
                      (string-append (getcwd) "/games")) ; for check
              #t))
          (replace 'check
-           (lambda _
+           (lambda* (#:key tests? #:allow-other-keys)
              ;; Thanks to our substitutions, the tests should also run
              ;; when invoked on the target outside of `guix build'.
-             (unless ,(%current-target-system)
+             (when tests?
                (setenv "HOME" "/tmp")
-               (invoke "src/minetest" "--run-unittests"))
-             #t)))))
+               (invoke "src/minetest" "--run-unittests")))))))
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 01/20] gnu: minetest: Respect --without-tests Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-20 11:45                     ` bug#49828: " Leo Prikler
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 03/20] gnu: minetest: New package module Maxime Devos
                                     ` (17 subsequent siblings)
  19 siblings, 1 reply; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch:
  New file.
* gnu/packages/games.scm
  (minetest)[source]{patches}: Add it.
  (minetest)[native-search-paths]: Add "MINETEST_MOD_PATH".
* gnu/local.mk (dist_patch_DATA): Add the patch.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/games.scm                        |   8 +-
 ...vironment-variable-MINETEST_MOD_PATH.patch | 156 ++++++++++++++++++
 3 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c80a9af78c..d96d4e3dbc 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -801,6 +801,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/abseil-cpp-fix-gtest.patch		\
   %D%/packages/patches/abseil-cpp-fix-strerror_test.patch	\
   %D%/packages/patches/adb-add-libraries.patch			\
+  %D%/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch	\
   %D%/packages/patches/aegis-constness-error.patch         	\
   %D%/packages/patches/aegis-perl-tempdir1.patch           	\
   %D%/packages/patches/aegis-perl-tempdir2.patch           	\
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 3e7086b398..48d46a0379 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -3553,6 +3553,9 @@ match, cannon keep, and grave-itation pit.")
                (base32
                 "062ilb7s377q3hwfhl8q06vvcw2raydz5ljzlzwy2dmyzmdcndb8"))
               (modules '((guix build utils)))
+              (patches
+               (search-patches
+                "Add-environment-variable-MINETEST_MOD_PATH.patch"))
               (snippet
                '(begin
                   ;; Delete bundled libraries.
@@ -3599,7 +3602,10 @@ match, cannon keep, and grave-itation pit.")
     (native-search-paths
      (list (search-path-specification
             (variable "MINETEST_SUBGAME_PATH")
-            (files '("share/minetest/games")))))
+            (files '("share/minetest/games")))
+           (search-path-specification
+            (variable "MINETEST_MOD_PATH")
+            (files '("share/minetest/mods")))))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
     (inputs
diff --git a/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
new file mode 100644
index 0000000000..a74034a2c5
--- /dev/null
+++ b/gnu/packages/patches/Add-environment-variable-MINETEST_MOD_PATH.patch
@@ -0,0 +1,156 @@
+From d10ea2ad7efc2364a8a2007b4c6d3e85511e2f84 Mon Sep 17 00:00:00 2001
+From: Maxime Devos <maximedevos@telenet.be>
+Date: Tue, 3 Aug 2021 01:00:23 +0200
+Subject: [PATCH] Add environment variable MINETEST_MOD_PATH
+
+This adds an environment variable MINETEST_MOD_PATH.
+When it exists, Minetest will look there for mods
+in addition to ~/.minetest/mods/.  Mods can still be
+installed to ~/.minetest/mods/ with the built-in installer.
+
+With thanks to Leo Prikler.
+---
+ builtin/mainmenu/pkgmgr.lua       |  7 +++----
+ doc/menu_lua_api.txt              |  8 +++++++-
+ src/content/subgames.cpp          | 11 +++++++++++
+ src/script/lua_api/l_mainmenu.cpp | 23 +++++++++++++++++++++++
+ src/script/lua_api/l_mainmenu.h   |  2 ++
+ 5 files changed, 46 insertions(+), 5 deletions(-)
+
+diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
+index 787936e31..d8fba0ebe 100644
+--- a/builtin/mainmenu/pkgmgr.lua
++++ b/builtin/mainmenu/pkgmgr.lua
+@@ -682,10 +682,9 @@ function pkgmgr.preparemodlist(data)
+ 	local game_mods = {}
+ 
+ 	--read global mods
+-	local modpath = core.get_modpath()
+-
+-	if modpath ~= nil and
+-		modpath ~= "" then
++	local modpaths = core.get_modpaths()
++	--XXX what was ‘modpath ~= ""’ and ‘modpath ~= nil’ for?
++	for _,modpath in ipairs(modpaths) do
+ 		get_mods(modpath,global_mods)
+ 	end
+ 
+diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
+index b3975bc1d..132444b14 100644
+--- a/doc/menu_lua_api.txt
++++ b/doc/menu_lua_api.txt
+@@ -218,7 +218,13 @@ Package - content which is downloadable from the content db, may or may not be i
+     * returns path to global user data,
+       the directory that contains user-provided mods, worlds, games, and texture packs.
+ * core.get_modpath() (possible in async calls)
+-    * returns path to global modpath
++    * returns path to global modpath, where mods can be installed
++* core.get_modpaths() (possible in async calls)
++    * returns list of paths to global modpaths, where mods have been installed
++
++      The difference with "core.get_modpath" is that no mods should be installed in these
++      directories by Minetest -- they might be read-only.
++
+ * core.get_clientmodpath() (possible in async calls)
+     * returns path to global client-side modpath
+ * core.get_gamepath() (possible in async calls)
+diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
+index e9dc609b0..d73f95a1f 100644
+--- a/src/content/subgames.cpp
++++ b/src/content/subgames.cpp
+@@ -61,6 +61,12 @@ std::string getSubgamePathEnv()
+ 	return subgame_path ? std::string(subgame_path) : "";
+ }
+ 
++std::string getModPathEnv()
++{
++	char *mod_path = getenv("MINETEST_MOD_PATH");
++	return mod_path ? std::string(mod_path) : "";
++}
++
+ SubgameSpec findSubgame(const std::string &id)
+ {
+ 	if (id.empty())
+@@ -110,6 +116,11 @@ SubgameSpec findSubgame(const std::string &id)
+ 	std::set<std::string> mods_paths;
+ 	if (!user_game)
+ 		mods_paths.insert(share + DIR_DELIM + "mods");
++
++	Strfnd mod_search_paths(getModPathEnv());
++	while (!mod_search_paths.at_end())
++		mods_paths.insert(mod_search_paths.next(PATH_DELIM));
++
+ 	if (user != share || user_game)
+ 		mods_paths.insert(user + DIR_DELIM + "mods");
+ 
+diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
+index 3e9709bde..903ac3a22 100644
+--- a/src/script/lua_api/l_mainmenu.cpp
++++ b/src/script/lua_api/l_mainmenu.cpp
+@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
+ #include "lua_api/l_internal.h"
+ #include "common/c_content.h"
+ #include "cpp_api/s_async.h"
++#include "util/strfnd.h"
+ #include "gui/guiEngine.h"
+ #include "gui/guiMainMenu.h"
+ #include "gui/guiKeyChangeMenu.h"
+@@ -502,6 +503,26 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
+ 	return 1;
+ }
+ 
++/******************************************************************************/
++int ModApiMainMenu::l_get_modpaths(lua_State *L)
++{
++	const char *c_modpath = getenv("MINETEST_MOD_PATH");
++	if (c_modpath == NULL)
++		c_modpath = "";
++	int index = 1;
++	lua_newtable(L);
++	Strfnd mod_search_paths{std::string(c_modpath)};
++	while (!mod_search_paths.at_end()) {
++		std::string component = mod_search_paths.next(PATH_DELIM);
++		lua_pushstring(L, component.c_str());
++		lua_rawseti(L, -2, index);
++		index++;
++	}
++	ModApiMainMenu::l_get_modpath(L);
++	lua_rawseti(L, -2, index);
++	return 1;
++}
++
+ /******************************************************************************/
+ int ModApiMainMenu::l_get_clientmodpath(lua_State *L)
+ {
+@@ -949,6 +970,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+@@ -983,6 +1005,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
+ 	API_FCT(get_mapgen_names);
+ 	API_FCT(get_user_path);
+ 	API_FCT(get_modpath);
++	API_FCT(get_modpaths);
+ 	API_FCT(get_clientmodpath);
+ 	API_FCT(get_gamepath);
+ 	API_FCT(get_texturepath);
+diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
+index 33ac9e721..a6a54a2cb 100644
+--- a/src/script/lua_api/l_mainmenu.h
++++ b/src/script/lua_api/l_mainmenu.h
+@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
+ 
+ 	static int l_get_modpath(lua_State *L);
+ 
++	static int l_get_modpaths(lua_State *L);
++
+ 	static int l_get_clientmodpath(lua_State *L);
+ 
+ 	static int l_get_gamepath(lua_State *L);
+-- 
+2.32.0
+
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 03/20] gnu: minetest: New package module.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 01/20] gnu: minetest: Respect --without-tests Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
                                     ` (16 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

Aside from the 'minetest-topic' procedure which will be used
for the 'home-page' field of some packages, this module is
currently empty.  The 'contentdb' importer defined in the
following patches will be used to populate this module.

* gnu/packages/minetest.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk              |  1 +
 gnu/packages/minetest.scm | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 gnu/packages/minetest.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index d96d4e3dbc..5de08b1b09 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -383,6 +383,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/mercury.scm			\
   %D%/packages/mes.scm				\
   %D%/packages/messaging.scm			\
+  %D%/packages/minetest.scm			\
   %D%/packages/mingw.scm			\
   %D%/packages/microcom.scm			\
   %D%/packages/moe.scm				\
diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
new file mode 100644
index 0000000000..f8aca3005c
--- /dev/null
+++ b/gnu/packages/minetest.scm
@@ -0,0 +1,26 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+(define-module (gnu packages minetest)
+  #:use-module (guix packages)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system minetest)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public (minetest-topic topic-id)
+  "Return an URL (as a string) pointing to the forum topic with
+numeric identifier TOPIC-ID on the official Minetest forums."
+  (string-append "https://forum.minetest.net/viewtopic.php?t="
+                 (number->string topic-id)))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 04/20] build-system: Add 'minetest-mod-build-system'.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (2 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 03/20] gnu: minetest: New package module Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 05/20] import/utils: Recognise GPL-3.0-or-later and friends Maxime Devos
                                     ` (15 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* guix/build-system/minetest.scm: New module.
* guix/build/minetest-build-system.scm: Likewise.
* Makefile.am (MODULES): Add them.
* doc/guix.texi (Build Systems): Document 'minetest-mod-build-system'.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |   8 +
 guix/build-system/minetest.scm       |  99 ++++++++++++
 guix/build/minetest-build-system.scm | 229 +++++++++++++++++++++++++++
 4 files changed, 338 insertions(+)
 create mode 100644 guix/build-system/minetest.scm
 create mode 100644 guix/build/minetest-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index d5ec909213..f4439ce93b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ MODULES =					\
   guix/build-system/go.scm			\
   guix/build-system/meson.scm			\
   guix/build-system/minify.scm			\
+  guix/build-system/minetest.scm		\
   guix/build-system/asdf.scm			\
   guix/build-system/copy.scm			\
   guix/build-system/glib-or-gtk.scm		\
@@ -203,6 +204,7 @@ MODULES =					\
   guix/build/gnu-dist.scm			\
   guix/build/guile-build-system.scm		\
   guix/build/maven-build-system.scm		\
+  guix/build/minetest-build-system.scm		\
   guix/build/node-build-system.scm		\
   guix/build/perl-build-system.scm		\
   guix/build/python-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index b3c16e6507..d44ecc2005 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7895,6 +7895,14 @@ declaration.  Its default value is @code{(default-maven-plugins)} which is
 also exported.
 @end defvr
 
+@defvr {Scheme Variable} minetest-mod-build-system
+This variable is exported by @code{(guix build-system minetest)}.  It
+implements a build procedure for @uref{https://www.minetest.net, Minetest}
+mods, which consists of copying Lua code, images and other resources to
+the location Minetest searches for mods.  The build system also minimises
+PNG images and verifies that Minetest can load the mod without errors.
+@end defvr
+
 @defvr {Scheme Variable} minify-build-system
 This variable is exported by @code{(guix build-system minify)}.  It
 implements a minification procedure for simple JavaScript packages.
diff --git a/guix/build-system/minetest.scm b/guix/build-system/minetest.scm
new file mode 100644
index 0000000000..f33e97559d
--- /dev/null
+++ b/guix/build-system/minetest.scm
@@ -0,0 +1,99 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system minetest)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix build-system)
+  #:use-module (guix utils)
+  #:export (minetest-mod-build-system))
+
+;;
+;; Build procedure for minetest mods.  This is implemented as an extension
+;; of ‘copy-build-system’.
+;;
+;; Code:
+
+;; Lazily resolve the bindings to avoid circular dependencies.
+(define (default-optipng)
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (module-ref (resolve-interface '(gnu packages image)) 'optipng))
+
+(define (default-minetest)
+  (module-ref (resolve-interface '(gnu packages games)) 'minetest))
+
+(define (default-xvfb-run)
+  (module-ref (resolve-interface '(gnu packages xorg)) 'xvfb-run))
+
+(define %minetest-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build minetest-build-system)
+    ,@%copy-build-system-modules))
+
+(define %default-modules
+  ;; Modules in scope in the build-side environment.
+  '((guix build gnu-build-system)
+    (guix build minetest-build-system)
+    (guix build utils)))
+
+(define (standard-minetest-packages)
+  "Return the list of (NAME PACKAGE OUTPUT) or (NAME PACKAGE) tuples of
+standard packages used as implicit inputs of the Minetest build system."
+  `(("xvfb-run" ,(default-xvfb-run))
+    ("optipng" ,(default-optipng))
+    ("minetest" ,(default-minetest))
+    ,@(filter (lambda (input)
+                (member (car input)
+                        '("libc" "tar" "gzip" "bzip2" "xz" "locales")))
+              (standard-packages))))
+
+(define* (lower-mod name #:key (implicit-inputs? #t) #:allow-other-keys
+                    #:rest arguments)
+  (define lower (build-system-lower gnu-build-system))
+  (apply lower
+         name
+         (substitute-keyword-arguments arguments
+           ;; minetest-mod-build-system adds implicit inputs by itself,
+           ;; so don't let gnu-build-system add its own implicit inputs
+           ;; as well.
+           ((#:implicit-inputs? implicit-inputs? #t)
+            #f)
+           ((#:implicit-cross-inputs? implicit-cross-inputs? #t)
+            #f)
+           ((#:imported-modules imported-modules %minetest-build-system-modules)
+            imported-modules)
+           ((#:modules modules %default-modules)
+            modules)
+           ((#:phases phases '%standard-phases)
+            phases)
+           ;; Ensure nothing sneaks into the closure.
+           ((#:allowed-references allowed-references '())
+            allowed-references)
+           ;; Add the implicit inputs.
+           ((#:native-inputs native-inputs '())
+            (if implicit-inputs?
+                (append native-inputs (standard-minetest-packages))
+                native-inputs)))))
+
+(define minetest-mod-build-system
+  (build-system
+    (name 'minetest-mod)
+    (description "The build system for minetest mods")
+    (lower lower-mod)))
+
+;;; minetest.scm ends here
diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm
new file mode 100644
index 0000000000..477cc3d1d0
--- /dev/null
+++ b/guix/build/minetest-build-system.scm
@@ -0,0 +1,229 @@
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build minetest-build-system)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 regex)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module ((guix build copy-build-system) #:prefix copy:)
+  #:export (%standard-phases
+            mod-install-plan minimise-png read-mod-name check))
+
+;; (guix build copy-build-system) does not export 'install'.
+(define copy:install
+  (assoc-ref copy:%standard-phases 'install))
+
+(define (mod-install-plan mod-name)
+  `(("." ,(string-append "share/minetest/mods/" mod-name)
+     ;; Only install files that will actually be used at run time.
+     ;; This can save a little disk space.
+     ;;
+     ;; See <https://github.com/minetest/minetest/blob/master/doc/lua_api.txt>
+     ;; for an incomple list of files that can be found in mods.
+     #:include ("mod.conf" "modpack.conf" "settingtypes.txt" "depends.txt"
+                "description.txt")
+     #:include-regexp (".lua$" ".png$" ".ogg$" ".obj$" ".b3d$" ".tr$"
+                       ".mts$"))))
+
+(define* (guess-mod-name #:key inputs #:allow-other-keys)
+  "Try to determine the name of the mod or modpack that is being built.
+If it is unknown, make an educated guess."
+  ;; Minetest doesn't care about the directory names in "share/minetest/mods"
+  ;; so there is no technical problem if the directory names don't match
+  ;; the mod names.  The directory can appear in the GUI if the modpack
+  ;; doesn't have the 'name' set though, so try to make a guess.
+  (define (guess)
+    (let* ((source (assoc-ref inputs "source"))
+           ;; Don't retain a reference to the store.
+           (file-name (strip-store-file-name source))
+           ;; The "minetest-" prefix is not informative, so strip it.
+           (file-name (if (string-prefix? "minetest-" file-name)
+                          (substring file-name (string-length "minetest-"))
+                          file-name))
+           ;; Strip "-checkout" suffixes of git checkouts.
+           (file-name (if (string-suffix? "-checkout" file-name)
+                          (substring file-name
+                                     0
+                                     (- (string-length file-name)
+                                        (string-length "-checkout")))
+                          file-name))
+           (first-dot (string-index file-name #\.))
+           ;; If the source code is in an archive (.tar.gz, .zip, ...),
+           ;; strip the extension.
+           (file-name (if first-dot
+                          (substring file-name 0 first-dot)
+                          file-name)))
+      (format (current-error-port)
+              "warning: the modpack ~a did not set 'name' in 'modpack.conf'~%"
+              file-name)
+      file-name))
+  (cond ((file-exists? "mod.conf")
+         ;; Mods must have 'name' set in "mod.conf", so don't guess.
+         (read-mod-name "mod.conf"))
+        ((file-exists? "modpack.conf")
+         ;; While it is recommended to have 'name' set in 'modpack.conf',
+         ;; it is optional, so guess a name if necessary.
+         (read-mod-name "modpack.conf" guess))
+        (#t (guess))))
+
+(define* (install #:key inputs #:allow-other-keys #:rest arguments)
+  (apply copy:install
+         #:install-plan (mod-install-plan (apply guess-mod-name arguments))
+         arguments))
+
+(define %png-magic-bytes
+  ;; Magic bytes of PNG images, see ‘5.2 PNG signatures’ in
+  ;; ‘Portable Network Graphics (PNG) Specification (Second Edition)’
+  ;; on <https://www.w3.org/TR/PNG/>.
+  #vu8(137 80 78 71 13 10 26 10))
+
+(define png-file?
+  ((@@ (guix build utils) file-header-match) %png-magic-bytes))
+
+(define* (minimise-png #:key inputs native-inputs #:allow-other-keys)
+  "Minimise PNG images found in the working directory."
+  (define optipng (which "optipng"))
+  (define (optimise image)
+    (format #t "Optimising ~a~%" image)
+    (make-file-writable (dirname image))
+    (make-file-writable image)
+    (define old-size (stat:size (stat image)))
+    ;; The mod "technic" has a file "technic_music_player_top.png" that
+    ;; actually is a JPEG file, see
+    ;; <https://github.com/minetest-mods/technic/issues/590>.
+    (if (png-file? image)
+        (invoke optipng "-o4" "-quiet" image)
+        (format #t "warning: skipping ~a because it's not actually a PNG image~%"
+                image))
+    (define new-size (stat:size (stat image)))
+    (values old-size new-size))
+  (define files (find-files "." ".png$"))
+  (let loop ((total-old-size 0)
+             (total-new-size 0)
+             (images (find-files "." ".png$")))
+    (cond ((pair? images)
+           (receive (old-size new-size)
+               (optimise (car images))
+             (loop (+ total-old-size old-size)
+                   (+ total-new-size new-size)
+                   (cdr images))))
+          ((= total-old-size 0)
+           (format #t "There were no PNG images to minimise."))
+          (#t
+           (format #t "Minimisation reduced size of images by ~,2f% (~,2f MiB to ~,2f MiB)~%"
+                   (* 100.0 (- 1 (/ total-new-size total-old-size)))
+                   (/ total-old-size (expt 1024 2))
+                   (/ total-new-size (expt 1024 2)))))))
+
+(define name-regexp (make-regexp "^name[ ]*=(.+)$"))
+
+(define* (read-mod-name mod.conf #:optional not-found)
+  "Read the name of a mod from MOD.CONF.  If MOD.CONF
+does not have a name field and NOT-FOUND is #false, raise an
+error.  If NOT-FOUND is TRUE, call NOT-FOUND instead."
+  (call-with-input-file mod.conf
+    (lambda (port)
+      (let loop ()
+        (define line (read-line port))
+        (if (eof-object? line)
+            (if not-found
+                (not-found)
+                (error "~a does not have a 'name' field" mod.conf))
+            (let ((match (regexp-exec name-regexp line)))
+              (if (regexp-match? match)
+                  (string-trim-both (match:substring match 1) #\ )
+                  (loop))))))))
+
+(define* (check #:key outputs tests? #:allow-other-keys)
+  "Test whether the mod loads.  The mod must first be installed first."
+  (define (all-mod-names directories)
+    (append-map
+     (lambda (directory)
+       (map read-mod-name (find-files directory "mod.conf")))
+     directories))
+  (when tests?
+    (mkdir "guix_testworld")
+    ;; Add the mod to the mod search path, such that Minetest can find it.
+    (setenv "MINETEST_MOD_PATH"
+            (list->search-path-as-string
+             (cons
+              (string-append (assoc-ref outputs "out") "/share/minetest/mods")
+              (search-path-as-string->list
+               (or (getenv "MINETEST_MOD_PATH") "")))
+             ":"))
+    (with-directory-excursion "guix_testworld"
+      (setenv "HOME" (getcwd))
+      ;; Create a world in which all mods are loaded.
+      (call-with-output-file "world.mt"
+        (lambda (port)
+          (display
+           "gameid = minetest
+world_name = guix_testworld
+backend = sqlite3
+player_backend = sqlite3
+auth_backend = sqlite3
+" port)
+          (for-each
+           (lambda (mod)
+             (format port "load_mod_~a = true~%" mod))
+           (all-mod-names (search-path-as-string->list
+                           (getenv "MINETEST_MOD_PATH"))))))
+      (receive (port pid)
+          ((@@ (guix build utils) open-pipe-with-stderr)
+           "xvfb-run" "--" "minetest" "--info" "--world" "." "--go")
+        (format #t "Started Minetest with all mods loaded for testing~%")
+        ;; Scan the output for error messages.
+        ;; When the player has joined the server, stop minetest.
+        (define (error? line)
+          (and (string? line)
+               (string-contains line ": ERROR[")))
+        (define (stop? line)
+          (and (string? line)
+               (string-contains line "ACTION[Server]: singleplayer [127.0.0.1] joins game.")))
+        (let loop ()
+          (match (read-line port)
+            ((? error? line)
+             (error "minetest raised an error: ~a" line))
+            ((? stop?)
+             (kill pid SIGINT)
+             (close-port port)
+             (waitpid pid))
+            ((? string? line)
+             (display line)
+             (newline)
+             (loop))
+            ((? eof-object?)
+             (error "minetest didn't start"))))))))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (add-before 'build 'minimise-png minimise-png)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    ;; The 'check' phase requires the mod to be installed,
+    ;; so move the 'check' phase after the 'install' phase.
+    (add-after 'install 'check check)))
+
+;;; minetest-build-system.scm ends here
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 05/20] import/utils: Recognise GPL-3.0-or-later and friends.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (3 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 06/20] guix: Add ContentDB importer Maxime Devos
                                     ` (14 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* guix/import/utils.scm (spdx-string->license): Recognise
  GPL-N-only and GPL-N-or-later.  Likewise for LGPL and AGPL.
---
 guix/import/utils.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index d817318a91..d1b8076ddd 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -133,8 +133,14 @@ of the string VERSION is replaced by the symbol 'version."
   ;; Please update guix/licenses.scm when modifying
   ;; this list to avoid mismatches.
   (match str
+    ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later".
+    ;; "GPL-N" has been deprecated in favour of "GPL-N-only"
+    ;; or "GPL-N-or-later" as appropriate.  Likewise for LGPL
+    ;; and AGPL
     ("AGPL-1.0"                    'license:agpl1)
     ("AGPL-3.0"                    'license:agpl3)
+    ("AGPL-3.0-only"               'license:agpl3)
+    ("AGPL-3.0-or-later"           'license:agpl3+)
     ("Apache-1.1"                  'license:asl1.1)
     ("Apache-2.0"                  'license:asl2.0)
     ("BSL-1.0"                     'license:boost1.0)
@@ -161,11 +167,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("GFDL-1.3"                    'license:fdl1.3+)
     ("Giftware"                    'license:giftware)
     ("GPL-1.0"                     'license:gpl1)
+    ("GPL-1.0-only"                'license:gpl1)
     ("GPL-1.0+"                    'license:gpl1+)
+    ("GPL-1.0-or-later"            'license:gpl1+)
     ("GPL-2.0"                     'license:gpl2)
+    ("GPL-2.0-only"                'license:gpl2)
     ("GPL-2.0+"                    'license:gpl2+)
+    ("GPL-2.0-or-later"            'license:gpl2+)
     ("GPL-3.0"                     'license:gpl3)
+    ("GPL-3.0-only"                'license:gpl3)
     ("GPL-3.0+"                    'license:gpl3+)
+    ("GPL-3.0-or-later"            'license:gpl3+)
     ("ISC"                         'license:isc)
     ("IJG"                         'license:ijg)
     ("Imlib2"                      'license:imlib2)
@@ -173,11 +185,17 @@ of the string VERSION is replaced by the symbol 'version."
     ("IPL-1.0"                     'license:ibmpl1.0)
     ("LAL-1.3"                     'license:lal1.3)
     ("LGPL-2.0"                    'license:lgpl2.0)
+    ("LGPL-2.0-only"               'license:lgpl2.0)
     ("LGPL-2.0+"                   'license:lgpl2.0+)
+    ("LGPL-2.0-or-later"           'license:lgpl2.0+)
     ("LGPL-2.1"                    'license:lgpl2.1)
+    ("LGPL-2.1-only"               'license:lgpl2.1)
     ("LGPL-2.1+"                   'license:lgpl2.1+)
+    ("LGPL-2.1-or-later"           'license:lgpl2.1+)
     ("LGPL-3.0"                    'license:lgpl3)
+    ("LGPL-3.0-only"               'license:lgpl3)
     ("LGPL-3.0+"                   'license:lgpl3+)
+    ("LGPL-3.0-or-later"           'license:lgpl3+)
     ("MPL-1.0"                     'license:mpl1.0)
     ("MPL-1.1"                     'license:mpl1.1)
     ("MPL-2.0"                     'license:mpl2.0)
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 06/20] guix: Add ContentDB importer.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (4 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 05/20] import/utils: Recognise GPL-3.0-or-later and friends Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 07/20] gnu: Add minetest-mesecons Maxime Devos
                                     ` (13 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* guix/import/contentdb.scm: New file.
* guix/scripts/import/contentdb.scm: New file.
* tests/contentdb.scm: New file.
* Makefile.am (MODULES, SCM_TESTS): Register them.
* po/guix/POTFILES.in: Likewise.
* doc/guix.texi (Invoking guix import): Document it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  32 +++
 guix/import/minetest.scm         | 456 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/minetest.scm | 117 ++++++++
 po/guix/POTFILES.in              |   1 +
 tests/minetest.scm               | 355 ++++++++++++++++++++++++
 7 files changed, 966 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/minetest.scm
 create mode 100644 guix/scripts/import/minetest.scm
 create mode 100644 tests/minetest.scm

diff --git a/Makefile.am b/Makefile.am
index f4439ce93b..6243583616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -262,6 +262,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/minetest.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
   guix/import/pypi.scm				\
@@ -304,6 +305,7 @@ MODULES =					\
   guix/scripts/import/go.scm			\
   guix/scripts/import/hackage.scm		\
   guix/scripts/import/json.scm  		\
+  guix/scripts/import/minetest.scm  		\
   guix/scripts/import/opam.scm			\
   guix/scripts/import/pypi.scm			\
   guix/scripts/import/stackage.scm		\
@@ -470,6 +472,7 @@ SCM_TESTS =					\
   tests/import-utils.scm			\
   tests/inferior.scm				\
   tests/lint.scm				\
+  tests/minetest.scm				\
   tests/modules.scm				\
   tests/monads.scm				\
   tests/nar.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index d44ecc2005..854e282b38 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -11314,6 +11314,38 @@ and generate package expressions for all those packages that are not yet
 in Guix.
 @end table
 
+@item contentdb
+@cindex minetest
+@cindex ContentDB
+Import metadata from @uref{https://content.minetest.net, ContentDB}.
+Information is taken from the JSON-formatted metadata provided through
+@uref{https://content.minetest.net/help/api/, ContentDB's API} and
+includes most relevant information, including dependencies.  There are
+some caveats, however.  The license information is often incomplete.
+The commit hash is sometimes missing.  The descriptions are in the
+Markdown format, but Guix uses Texinfo instead.  Texture packs and
+subgames are unsupported.
+
+The command below imports metadata for the Mesecons mod by Jeija:
+
+@example
+guix import minetest Jeija/mesecons
+@end example
+
+The author name can also be left out:
+
+@example
+guix import minetest mesecons
+@end example
+
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
 @item cpan
 @cindex CPAN
 Import metadata from @uref{https://www.metacpan.org/, MetaCPAN}.
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
new file mode 100644
index 0000000000..e1f8487b75
--- /dev/null
+++ b/guix/import/minetest.scm
@@ -0,0 +1,456 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import minetest)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 receive)
+  #:use-module (ice-9 threads)
+  #:use-module (ice-9 hash-table)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-2)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix utils)
+  #:use-module (guix ui)
+  #:use-module (guix i18n)
+  #:use-module (guix memoization)
+  #:use-module (guix serialization)
+  #:use-module (guix import utils)
+  #:use-module (guix import json)
+  #:use-module ((gcrypt hash) #:select (open-sha256-port port-sha256))
+  #:use-module (json)
+  #:use-module (guix base32)
+  #:use-module (guix git)
+  #:use-module (guix store)
+  #:export (%default-sort-key
+            %contentdb-api
+            json->package
+            contentdb-fetch
+            elaborate-contentdb-name
+            minetest->guix-package
+            minetest-recursive-import
+            sort-packages))
+
+;; The ContentDB API is documented at
+;; <https://content.minetest.net>.
+
+(define %contentdb-api
+  (make-parameter "https://content.minetest.net/api/"))
+
+(define (string-or-false x)
+  (and (string? x) x))
+
+(define (natural-or-false x)
+  (and (exact-integer? x) (>= x 0) x))
+
+;; Descriptions on ContentDB use carriage returns, but Guix doesn't.
+(define (delete-cr text)
+  (string-delete #\cr text))
+
+\f
+
+;;;
+;;; JSON mappings
+;;;
+
+;; Minetest package.
+;;
+;; API endpoint: /packages/AUTHOR/NAME/
+(define-json-mapping <package> make-package package?
+  json->package
+  (author            package-author) ; string
+  (creation-date     package-creation-date ; string
+                     "created_at")
+  (downloads         package-downloads) ; integer
+  (forums            package-forums "forums" natural-or-false)
+  (issue-tracker     package-issue-tracker "issue_tracker") ; string
+  (license           package-license) ; string
+  (long-description  package-long-description "long_description") ; string
+  (maintainers       package-maintainers ; list of strings
+                     "maintainers" vector->list)
+  (media-license     package-media-license "media_license") ; string
+  (name              package-name) ; string
+  (provides          package-provides ; list of strings
+                     "provides" vector->list)
+  (release           package-release) ; integer
+  (repository        package-repository "repo" string-or-false)
+  (score             package-score) ; flonum
+  (screenshots       package-screenshots "screenshots" vector->list) ; list of strings
+  (short-description package-short-description "short_description") ; string
+  (state             package-state) ; string
+  (tags              package-tags "tags" vector->list) ; list of strings
+  (thumbnail         package-thumbnail) ; string
+  (title             package-title) ; string
+  (type              package-type) ; string
+  (url               package-url) ; string
+  (website           package-website "website" string-or-false))
+
+(define-json-mapping <release> make-release release?
+  json->release
+  ;; If present, a git commit identified by its hash
+  (commit               release-commit "commit" string-or-false)
+  (downloads            release-downloads) ; integer
+  (id                   release-id) ; integer
+  (max-minetest-version release-max-minetest-version string-or-false)
+  (min-minetest-version release-min-minetest-version string-or-false)
+  (release-date         release-data) ; string
+  (title                release-title) ; string
+  (url                  release-url)) ; string
+
+(define-json-mapping <dependency> make-dependency dependency?
+  json->dependency
+  (optional? dependency-optional? "is_optional") ; bool
+  (name dependency-name) ; string
+  (packages dependency-packages "packages" vector->list)) ; list of strings
+
+;; A structure returned by the /api/packages/?fmt=keys endpoint
+(define-json-mapping <package-keys> make-package-keys package-keys?
+  json->package-keys
+  (author package-keys-author) ; string
+  (name package-keys-name)     ; string
+  (type package-keys-type))    ; string
+
+(define (package-mod? package)
+  "Is the ContentDB package PACKAGE a mod?"
+  ;; ContentDB also has ‘games’ and ‘texture packs’.
+  (string=? (package-type package) "mod"))
+
+\f
+
+;;;
+;;; Manipulating names of packages
+;;;
+;;; There are three kind of names:
+;;;
+;;;   * names of guix packages, e.g. minetest-basic-materials.
+;;;   * names of mods on ContentDB, e.g. basic_materials
+;;;   * a combination of author and mod name on ContentDB, e.g. VanessaE/basic_materials
+;;;
+
+(define (%construct-full-name author name)
+  (string-append author "/" name))
+
+(define (package-full-name package)
+  "Given a <package> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-author package) (package-name package)))
+
+(define (package-keys-full-name package)
+  "Given a <package-keys> object, return the corresponding AUTHOR/NAME string."
+  (%construct-full-name (package-keys-author package)
+                        (package-keys-name package)))
+
+(define (contentdb->package-name author/name)
+  "Given the AUTHOR/NAME of a package on ContentDB, return a Guix-compliant
+name for the package."
+  ;; The author is not included, as the names of popular mods
+  ;; tend to be unique.
+  (string-append "minetest-" (snake-case (author/name->name author/name))))
+
+(define (author/name->name author/name)
+  "Extract NAME from the AUTHOR/NAME string, or raise an error if AUTHOR/NAME
+is ill-formatted."
+  (match (string-split author/name #\/)
+    ((author name)
+     (when (string-null? author)
+       (leave
+        (G_ "In ~a: author names must consist of at least a single character.~%")
+        author/name))
+     (when (string-null? name)
+       (leave
+        (G_ "In ~a: mod names must consist of at least a single character.~%")
+        author/name))
+     name)
+    ((too many . components)
+     (leave
+      (G_ "In ~a: author names and mod names may not contain forward slashes.~%")
+      author/name))
+    ((name)
+     (if (string-null? name)
+         (leave (G_ "mod names may not be empty.~%"))
+         (leave (G_ "The name of the author is missing in ~a.~%")
+                author/name)))))
+
+(define* (elaborate-contentdb-name name #:key (sort %default-sort-key))
+  "If NAME is an AUTHOR/NAME string, return it.  Otherwise, try to determine
+the author and return an appropriate AUTHOR/NAME string.  If that fails,
+raise an exception."
+  (if (or (string-contains name "/") (string-null? name))
+      ;; Call 'author/name->name' to verify that NAME seems reasonable
+      ;; and raise an appropriate exception if it isn't.
+      (begin
+        (author/name->name name)
+        name)
+      (let* ((package-keys (contentdb-query-packages name #:sort sort))
+             (correctly-named
+              (filter (lambda (package-key)
+                        (string=? name (package-keys-name package-key)))
+                      package-keys)))
+        (match correctly-named
+          ((one) (package-keys-full-name one))
+          ((too . many)
+           (warning (G_ "~a is ambigious, presuming ~a (other options include: ~a)~%")
+                    name (package-keys-full-name too)
+                    (map package-keys-full-name many))
+           (package-keys-full-name too))
+          (()
+           (leave (G_ "No mods with name ~a were found.~%") name))))))
+
+\f
+
+;;;
+;;; API endpoints
+;;;
+
+(define contentdb-fetch
+  (mlambda (author/name)
+    "Return a <package> record for package AUTHOR/NAME, or #f on failure."
+    (and=> (json-fetch
+            (string-append (%contentdb-api) "packages/" author/name "/"))
+           json->package)))
+
+(define (contentdb-fetch-releases author/name)
+  "Return a list of <release> records for package NAME by AUTHOR, or #f
+on failure."
+  (and=> (json-fetch (string-append (%contentdb-api) "packages/" author/name
+                                    "/releases/"))
+         (lambda (json)
+           (map json->release (vector->list json)))))
+
+(define (latest-release author/name)
+  "Return the latest source release for package NAME by AUTHOR,
+or #f if this package does not exist."
+  (and=> (contentdb-fetch-releases author/name)
+         car))
+
+(define (contentdb-fetch-dependencies author/name)
+  "Return an alist of lists of <dependency> records for package NAME by AUTHOR
+and possibly some other packages as well, or #f on failure."
+  (define url (string-append (%contentdb-api) "packages/" author/name
+                             "/dependencies/"))
+  (and=> (json-fetch url)
+         (lambda (json)
+           (map (match-lambda
+                  ((key . value)
+                   (cons key (map json->dependency (vector->list value)))))
+                json))))
+
+(define* (contentdb-query-packages q #:key
+                                   (type "mod")
+                                   (limit 50)
+                                   (sort %default-sort-key)
+                                   (order "desc"))
+  "Search ContentDB for Q (a string).  Sort by SORT, in ascending order
+if ORDER is \"asc\" or descending order if ORDER is \"desc\".  TYPE must
+be \"mod\", \"game\" or \"txp\", restricting thes search results to
+respectively mods, games and texture packs.  Limit to at most LIMIT
+results.  The return value is a list of <package-keys> records."
+  ;; XXX does Guile have something for constructing (and, when necessary,
+  ;; escaping) query strings?
+  (define url (string-append (%contentdb-api) "packages/?type=" type
+                             "&q=" q "&fmt=keys"
+                             "&limit=" (number->string limit)
+                             "&order=" order
+                             "&sort=" sort))
+  (let ((json (json-fetch url)))
+    (if json
+        (map json->package-keys (vector->list json))
+        (leave
+         (G_ "The package search API doesn't exist anymore.~%")))))
+
+\f
+
+;; XXX copied from (guix import elpa)
+(define* (download-git-repository url ref)
+  "Fetch the given REF from the Git repository at URL."
+  (with-store store
+    (latest-repository-commit store url #:ref ref)))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file)
+  "Compute the hash of FILE."
+  (let-values (((port get-hash) (open-sha256-port)))
+    (write-file file port)
+    (force-output port)
+    (get-hash)))
+
+(define (make-minetest-sexp author/name version repository commit
+                            inputs home-page synopsis
+                            description media-license license)
+  "Return a S-expression for the minetest package with the given author/NAME,
+VERSION, REPOSITORY, COMMIT, INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION,
+MEDIA-LICENSE and LICENSE."
+  `(package
+     (name ,(contentdb->package-name author/name))
+     (version ,version)
+     (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+                (url ,repository)
+                (commit ,commit)))
+         (sha256
+          (base32
+           ;; The git commit is not always available.
+           ,(and commit
+                 (bytevector->nix-base32-string
+                  (file-hash
+                   (download-git-repository repository
+                                            `(commit . ,commit)))))))
+         (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs (map contentdb->package-name inputs))
+     (home-page ,home-page)
+     (synopsis ,(delete-cr synopsis))
+     (description ,(delete-cr description))
+     (license ,(if (eq? media-license license)
+                   license
+                   `(list ,media-license ,license)))
+     ;; The Minetest updater (not yet in Guix; it requires not-yet-submitted
+     ;; patches to (guix upstream) that require some work) needs to know both
+     ;; the author name and mod name for efficiency.
+     (properties ,(list 'quasiquote `((upstream-name . ,author/name))))))
+
+(define (package-home-page package)
+  "Guess the home page of the ContentDB package PACKAGE.
+
+In order of preference, try the 'website', the forum topic on the
+official Minetest forum and the Git repository (if any)."
+  (define (topic->url-sexp topic)
+    ;; 'minetest-topic' is a procedure defined in (gnu packages minetest)
+    `(minetest-topic ,topic))
+  (or (package-website package)
+      (and=> (package-forums package) topic->url-sexp)
+      (package-repository package)))
+
+;; If the default sort key is changed, make sure to modify 'show-help'
+;; in (guix scripts import minetest) appropriately as well.
+(define %default-sort-key "score")
+
+(define* (sort-packages packages #:key (sort %default-sort-key))
+  "Sort PACKAGES by SORT, in descending order."
+  (define package->key
+    (match sort
+      ("score" package-score)
+      ("downloads" package-downloads)))
+  (define (greater x y)
+    (> (package->key x) (package->key y)))
+  (sort-list packages greater))
+
+(define builtin-mod?
+  (let ((%builtin-mods
+         (alist->hash-table
+          (map (lambda (x) (cons x #t))
+               '("beds" "binoculars" "boats" "bones" "bucket" "butterflies"
+                 "carts" "creative" "default" "doors" "dungeon_loot" "dye"
+                 "env_sounds" "farming" "fire" "fireflies" "flowers"
+                 "game_commands" "give_initial_stuff" "map" "mtg_craftguide"
+                 "player_api" "screwdriver" "sethome" "sfinv" "spawn" "stairs"
+                 "tnt" "vessels" "walls" "weather" "wool" "xpanes")))))
+    (lambda (mod)
+      "Is MOD provided by the default minetest subgame?"
+      (hash-ref %builtin-mods mod))))
+
+(define* (important-dependencies dependencies author/name
+                                 #:key (sort %default-sort-key))
+  "Return the hard dependencies of AUTHOR/NAME in the association list
+DEPENDENCIES as a list of AUTHOR/NAME strings."
+  (define dependency-list
+    (assoc-ref dependencies author/name))
+  (filter-map
+   (lambda (dependency)
+     (and (not (dependency-optional? dependency))
+          (not (builtin-mod? (dependency-name dependency)))
+          ;; The dependency information contains symbolic names
+          ;; that can be ‘provided’ by multiple mods, so we need to choose one
+          ;; of the implementations.
+          (let* ((implementations
+                  (par-map contentdb-fetch (dependency-packages dependency)))
+                 ;; Fetching package information about the packages is racy:
+                 ;; some packages might be removed from ContentDB between the
+                 ;; construction of DEPENDENCIES and the call to
+                 ;; 'contentdb-fetch'.  So filter out #f.
+                 ;;
+                 ;; Filter out ‘games’ that include the requested mod -- it's
+                 ;; the mod itself we want.
+                 (mods (filter (lambda (p) (and=> p package-mod?))
+                               implementations))
+                 (sorted-mods (sort-packages mods #:sort sort)))
+            (match sorted-mods
+              ((package) (package-full-name package))
+              ((too . many)
+               (warning
+                (G_ "The dependency ~a of ~a has multiple different implementations ~a.~%")
+                (dependency-name dependency)
+                author/name
+                (map package-full-name sorted-mods))
+               (match sort
+                 ("score"
+                  (warning
+                   (G_ "The implementation with the highest score will be choosen!~%")))
+                 ("downloads"
+                  (warning
+                   (G_ "The implementation that has been downloaded the most will be choosen!~%"))))
+               (package-full-name too))
+              (()
+               (warning
+                (G_ "The dependency ~a of ~a does not have any implementation.  It will be ignored!~%")
+                (dependency-name dependency) author/name)
+               #f)))))
+   dependency-list))
+
+(define* (%minetest->guix-package author/name #:key (sort %default-sort-key))
+  "Fetch the metadata for AUTHOR/NAME from https://content.minetest.net, and
+return the 'package' S-expression corresponding to that package, or raise an
+exception on failure.  On success, also return the upstream dependencies as a
+list of AUTHOR/NAME strings."
+  ;; Call 'author/name->name' to verify that AUTHOR/NAME seems reasonable.
+  (author/name->name author/name)
+  (define package (contentdb-fetch author/name))
+  (unless package
+    (leave (G_ "no package metadata for ~a on ContentDB~%") author/name))
+  (define dependencies (contentdb-fetch-dependencies author/name))
+  (unless dependencies
+    (leave (G_ "no dependency information for ~a on ContentDB~%") author/name))
+  (define release (latest-release author/name))
+  (unless release
+    (leave (G_ "no release of ~a on ContentDB~%") author/name))
+  (define important-upstream-dependencies
+    (important-dependencies dependencies author/name #:sort sort))
+  (values (make-minetest-sexp author/name
+                              (release-title release) ; version
+                              (package-repository package)
+                              (release-commit release)
+                              important-upstream-dependencies
+                              (package-home-page package)
+                              (package-short-description package)
+                              (package-long-description package)
+                              (spdx-string->license
+                               (package-media-license package))
+                              (spdx-string->license
+                               (package-license package)))
+          important-upstream-dependencies))
+
+(define minetest->guix-package
+  (memoize %minetest->guix-package))
+
+(define* (minetest-recursive-import author/name #:key (sort %default-sort-key))
+  (define* (minetest->guix-package* author/name #:key repo version)
+    (minetest->guix-package author/name #:sort sort))
+  (recursive-import author/name
+                    #:repo->guix-package minetest->guix-package*
+                    #:guix-name contentdb->package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f53d1ac1f4..b369a362d0 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,8 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
-                    "gem" "go" "cran" "crate" "texlive" "json" "opam"))
+                    "gem" "go" "cran" "crate" "texlive" "json" "opam"
+                    "minetest"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/minetest.scm b/guix/scripts/import/minetest.scm
new file mode 100644
index 0000000000..5f204d90fc
--- /dev/null
+++ b/guix/scripts/import/minetest.scm
@@ -0,0 +1,117 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2014 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts import minetest)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-minetest))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((sort . ,%default-sort-key)))
+
+(define (show-help)
+  (display (G_ "Usage: guix import minetest AUTHOR/NAME
+Import and convert the Minetest mod NAME by AUTHOR from ContentDB.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+      --sort=KEY         when choosing between multiple implementations,
+                         choose the one with the highest value for KEY
+                         (one of \"score\" (standard) or \"downloads\")"))
+  (newline)
+  (show-bug-report-information))
+
+(define (verify-sort-order sort)
+  "Verify SORT can be used to sort mods by."
+  (unless (member sort '("score" "downloads" "reviews"))
+    (leave (G_ "~a: not a valid key to sort by~%") sort))
+  sort)
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import minetest")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         (option '("sort") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'sort (verify-sort-order arg) result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-minetest . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((name)
+       (with-error-handling
+         (let* ((sort (assoc-ref opts 'sort))
+                (author/name (elaborate-contentdb-name name #:sort sort)))
+           (if (assoc-ref opts 'recursive)
+               ;; Recursive import
+               (filter-map package->definition
+                           (minetest-recursive-import author/name #:sort sort))
+               ;; Single import
+               (minetest->guix-package author/name #:sort sort)))))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index a3bced1a8f..f25a7b4802 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -60,6 +60,7 @@ guix/scripts/git.scm
 guix/scripts/git/authenticate.scm
 guix/scripts/hash.scm
 guix/scripts/import.scm
+guix/scripts/import/contentdb.scm
 guix/scripts/import/cran.scm
 guix/scripts/import/elpa.scm
 guix/scripts/pull.scm
diff --git a/tests/minetest.scm b/tests/minetest.scm
new file mode 100644
index 0000000000..6ae476fe5f
--- /dev/null
+++ b/tests/minetest.scm
@@ -0,0 +1,355 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-minetest)
+  #:use-module (guix memoization)
+  #:use-module (guix import minetest)
+  #:use-module (guix import utils)
+  #:use-module (guix tests)
+  #:use-module (json)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-64))
+
+\f
+;; Some procedures for populating a ‘fake’ ContentDB server.
+
+(define* (make-package-sexp #:key
+                            (guix-name "minetest-foo")
+                            (home-page "https://example.org/foo")
+                            (repo "https://example.org/foo.git")
+                            (synopsis "synopsis")
+                            (guix-description "description")
+                            (guix-license
+                             '(list license:cc-by-sa4.0 license:lgpl3+))
+                            (inputs '())
+                            (upstream-name "Author/foo")
+                            #:allow-other-keys)
+  `(package
+     (name ,guix-name)
+     ;; This is not a proper version number but ContentDB does not include
+     ;; version numbers.
+     (version "2021-07-25")
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url ,(and (not (eq? repo 'null)) repo))
+              (commit #f)))
+        (sha256
+         (base32 #f))
+        (file-name (git-file-name name version))))
+     (build-system minetest-mod-build-system)
+     ,@(maybe-propagated-inputs inputs)
+     (home-page ,home-page)
+     (synopsis ,synopsis)
+     (description ,guix-description)
+     (license ,guix-license)
+     (properties
+      ,(list 'quasiquote
+             `((upstream-name . ,upstream-name))))))
+
+(define* (make-package-json #:key
+                            (author "Author")
+                            (name "foo")
+                            (media-license "CC-BY-SA-4.0")
+                            (license "LGPL-3.0-or-later")
+                            (short-description "synopsis")
+                            (long-description "description")
+                            (repo "https://example.org/foo.git")
+                            (website "https://example.org/foo")
+                            (forums 321)
+                            (score 987.654)
+                            (downloads 123)
+                            (type "mod")
+                            #:allow-other-keys)
+  `(("author" . ,author)
+    ("content_warnings" . #())
+    ("created_at" . "2018-05-23T19:58:07.422108")
+    ("downloads" . ,downloads)
+    ("forums" . ,forums)
+    ("issue_tracker" . "https://example.org/foo/issues")
+    ("license" . ,license)
+    ("long_description" . ,long-description)
+    ("maintainers" . #("maintainer"))
+    ("media_license" . ,media-license)
+    ("name" . ,name)
+    ("provides" . #("stuff"))
+    ("release" . 456)
+    ("repo" . ,repo)
+    ("score" . ,score)
+    ("screenshots" . #())
+    ("short_description" . ,short-description)
+    ("state" . "APPROVED")
+    ("tags" . #("some" "tags"))
+    ("thumbnail" . null)
+    ("title" . "The name")
+    ("type" . ,type)
+    ("url" . ,(string-append "https://content.minetest.net/packages/"
+                             author "/" name "/download/"))
+    ("website" . ,website)))
+
+(define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
+  `#((("commit" . ,commit)
+      ("downloads" . 469)
+      ("id" . 8614)
+      ("max_minetest_version" . null)
+      ("min_minetest_version" . null)
+      ("release_date" . "2021-07-25T01:10:23.207584")
+      ("title" . "2021-07-25"))))
+
+(define* (make-dependencies-json #:key (author "Author")
+                                 (name "foo")
+                                 (requirements '(("default" #f ())))
+                                 #:allow-other-keys)
+  `((,(string-append author "/" name)
+     . ,(list->vector
+         (map (match-lambda
+                ((symbolic-name optional? implementations)
+                 `(("is_optional" . ,optional?)
+                   ("name" . ,symbolic-name)
+                   ("packages" . ,(list->vector implementations)))))
+              requirements)))
+    ("something/else" . #())))
+
+(define* (make-packages-keys-json #:key (author "Author")
+                                  (name "Name")
+                                  (type "mod"))
+  `(("author" . ,author)
+    ("name" . ,name)
+    ("type" . ,type)))
+
+(define (call-with-packages thunk . argument-lists)
+  ;; Don't reuse results from previous tests.
+  (invalidate-memoization! contentdb-fetch)
+  (invalidate-memoization! minetest->guix-package)
+  (define (scm->json-port scm)
+    (open-input-string (scm->json-string scm)))
+  (define (handle-package url requested-author requested-name . rest)
+    (define relevant-argument-list
+      (any (lambda (argument-list)
+             (apply (lambda* (#:key (author "Author") (name "foo")
+                              #:allow-other-keys)
+                      (and (equal? requested-author author)
+                           (equal? requested-name name)
+                           argument-list))
+                    argument-list))
+           argument-lists))
+    (when (not relevant-argument-list)
+      (error "the package ~a/~a should be irrelevant, but ~a is fetched"
+             requested-author requested-name url))
+    (scm->json-port
+     (apply (match rest
+              (("") make-package-json)
+              (("dependencies" "") make-dependencies-json)
+              (("releases" "") make-releases-json)
+              (_ (error "TODO ~a" rest)))
+            relevant-argument-list)))
+  (define (handle-mod-search sort)
+    ;; Produce search results, sorted by SORT in descending order.
+    (define arguments->key
+      (match sort
+        ("score" (lambda* (#:key (score 987.654) #:allow-other-keys)
+                   score))
+        ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys)
+                       downloads))))
+    (define argument-list->key (cut apply arguments->key <>))
+    (define (greater x y)
+      (> (argument-list->key x) (argument-list->key y)))
+    (define sorted-argument-lists (sort-list argument-lists greater))
+    (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod")
+                              #:allow-other-keys)
+      (and (string=? type "mod")
+           `(("author" . ,author)
+             ("name" . ,name)
+             ("type" . ,type))))
+    (define argument-list->json (cut apply arguments->json <>))
+    (scm->json-port
+     (list->vector (filter-map argument-list->json sorted-argument-lists))))
+  (mock ((guix http-client) http-fetch
+         (lambda* (url #:key headers)
+           (unless (string-prefix? "mock://api/packages/" url)
+             (error "the URL ~a should not be used" url))
+           (define resource
+             (substring url (string-length "mock://api/packages/")))
+           (define components (string-split resource #\/))
+           (match components
+             ((author name . rest)
+              (apply handle-package url author name rest))
+             (((? (cut string-prefix? "?type=mod&q=" <>) query))
+              (handle-mod-search
+               (cond ((string-contains query "sort=score") "score")
+                     ((string-contains query "sort=downloads") "downloads")
+                     (#t (error "search query ~a has unknown sort key"
+                                query)))))
+             (_
+              (error "the URL ~a should have an author and name component"
+                     url)))))
+        (parameterize ((%contentdb-api "mock://api/"))
+          (thunk))))
+
+(define* (minetest->guix-package* #:key (author "Author") (name "foo")
+                                  (sort %default-sort-key)
+                                  #:allow-other-keys)
+  (minetest->guix-package (string-append author "/" name) #:sort sort))
+
+(define (imported-package-sexp* primary-arguments . secondary-arguments)
+  "Ask the importer to import a package specified by PRIMARY-ARGUMENTS,
+during a dynamic where that package and the packages specified by
+SECONDARY-ARGUMENTS are available on ContentDB."
+  (apply call-with-packages
+         (lambda ()
+           ;; The memoization cache is reset by call-with-packages
+           (apply minetest->guix-package* primary-arguments))
+   primary-arguments
+   secondary-arguments))
+
+(define (imported-package-sexp . extra-arguments)
+  "Ask the importer to import a package specified by EXTRA-ARGUMENTS,
+during a dynamic extent where that package is available on ContentDB."
+  (imported-package-sexp* extra-arguments))
+
+(define-syntax-rule (test-package test-case . extra-arguments)
+  (test-equal test-case
+    (make-package-sexp . extra-arguments)
+    (imported-package-sexp . extra-arguments)))
+
+(define-syntax-rule (test-package* test-case primary-arguments extra-arguments
+                                   ...)
+  (test-equal test-case
+    (apply make-package-sexp primary-arguments)
+    (imported-package-sexp* primary-arguments extra-arguments ...)))
+
+(test-begin "minetest")
+
+\f
+;; Package names
+(test-package "minetest->guix-package")
+(test-package "minetest->guix-package, _ → - in package name"
+              #:name "foo_bar"
+              #:guix-name "minetest-foo-bar"
+              #:upstream-name "Author/foo_bar")
+
+(test-equal "elaborate names, unambigious"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeija")
+   '(#:name "something" #:author "else")))
+
+(test-equal "elaborate name, ambigious (highest score)"
+  "Jeija/mesecons"
+  (call-with-packages
+   ;; #:sort "score" is the default
+   (cut elaborate-contentdb-name "mesecons")
+   '(#:name "mesecons" #:author "Jeijc" #:score 777)
+   '(#:name "mesecons" #:author "Jeijb" #:score 888)
+   '(#:name "mesecons" #:author "Jeija" #:score 999)))
+
+
+(test-equal "elaborate name, ambigious (most downloads)"
+  "Jeija/mesecons"
+  (call-with-packages
+   (cut elaborate-contentdb-name "mesecons" #:sort "downloads")
+   '(#:name "mesecons" #:author "Jeijc" #:downloads 777)
+   '(#:name "mesecons" #:author "Jeijb" #:downloads 888)
+   '(#:name "mesecons" #:author "Jeija" #:downloads 999)))
+
+\f
+;; Determining the home page
+(test-package "minetest->guix-package, website is used as home page"
+              #:home-page "web://site"
+              #:website "web://site")
+(test-package "minetest->guix-package, if absent, the forum is used"
+              #:home-page '(minetest-topic 628)
+              #:forums 628
+              #:website 'null)
+(test-package "minetest->guix-package, if absent, the git repo is used"
+              #:home-page "https://github.com/minetest-mods/mesecons"
+              #:forums 'null
+              #:website 'null
+              #:repo "https://github.com/minetest-mods/mesecons")
+(test-package "minetest->guix-package, all home page information absent"
+              #:home-page #f
+              #:forums 'null
+              #:website 'null
+              #:repo 'null)
+
+\f
+
+;; Dependencies
+(test-package* "minetest->guix-package, unambigious dependency"
+  (list #:requirements '(("mesecons" #f
+                          ("Jeija/mesecons"
+                           "some-modpack/containing-mese")))
+        #:inputs '("minetest-mesecons"))
+  (list #:author "Jeija" #:name "mesecons")
+  (list #:author "some-modpack" #:name "containing-mese" #:type "modpack"))
+
+(test-package* "minetest->guix-package, ambigious dependency (highest score)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        ;; #:sort "score" is the default
+        #:inputs '("minetest-bar"))
+  (list #:author "Author" #:name "foo" #:score 0)
+  (list #:author "Author" #:name "bar" #:score 9999))
+
+(test-package* "minetest->guix-package, ambigious dependency (most downloads)"
+  (list #:name "frobnicate"
+        #:guix-name "minetest-frobnicate"
+        #:upstream-name "Author/frobnicate"
+        #:requirements '(("frob" #f
+                          ("Author/foo" "Author/bar")))
+        #:inputs '("minetest-bar")
+        #:sort "downloads")
+  (list #:author "Author" #:name "foo" #:downloads 0)
+  (list #:author "Author" #:name "bar" #:downloads 9999))
+
+(test-package "minetest->guix-package, optional dependency"
+              #:requirements '(("mesecons" #t
+                                ("Jeija/mesecons"
+                                 "some-modpack/containing-mese")))
+              #:inputs '())
+
+\f
+;; License
+(test-package "minetest->guix-package, identical licenses"
+              #:guix-license 'license:lgpl3+
+              #:license "LGPL-3.0-or-later"
+              #:media-license "LGPL-3.0-or-later")
+
+;; Sorting
+(let* ((make-package
+        (lambda arguments
+          (json->package (apply make-package-json arguments))))
+       (x (make-package #:score 0))
+       (y (make-package #:score 1))
+       (z (make-package #:score 2)))
+  (test-equal "sort-packages, already sorted"
+    (list z y x)
+    (sort-packages (list z y x)))
+  (test-equal "sort-packages, reverse"
+    (list z y x)
+    (sort-packages (list x y z))))
+
+(test-end "minetest")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 07/20] gnu: Add minetest-mesecons.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (5 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 06/20] guix: Add ContentDB importer Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 08/20] gnu: Add minetest-basic-materials Maxime Devos
                                     ` (12 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-mesecons): New variable.
---
 gnu/packages/minetest.scm | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index f8aca3005c..d99efa4625 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -24,3 +24,39 @@
 numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
+
+(define-public minetest-mesecons
+  ;; The release on ContentDB does not have its own version number.
+  (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
+        (revision "0"))
+  (package
+    (name "minetest-mesecons")
+    (version (git-version "1.2.1" revision commit))
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/mesecons")
+             (commit commit)))
+       (sha256
+        (base32 "04m9s9l3frw1lgki41hgvjsw2zkrvfv0sy750b6j12arzb3lv645"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page "https://mesecons.net")
+    (synopsis
+     "Digital circuitry for Minetest, including wires, buttons and lights")
+    (description
+     "Mesecons is a mod for Minetest implementing various items related
+to digital circuitry, such as wires, buttons, lights and programmable
+controllers.  Among other things, there are also pistons, solar panels,
+pressure plates and note blocks.
+
+Mesecons has a similar goal to Redstone in Minecraft, but works in its own way,
+with different rules and mechanics.")
+    ;; LGPL for code, CC-BY-SA for textures.
+    ;; The README.md and COPYING.txt disagree about the "+" in license:lgpl3+.
+    ;; For now, assume README.md is correct.  Upstream has been asked to
+    ;; correct the inconsistency:
+    ;; <https://github.com/minetest-mods/mesecons/issues/575>.
+    (license (list license:lgpl3+ license:cc-by-sa3.0))
+    (properties `((upstream-name . "Jeija/mesecons"))))))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 08/20] gnu: Add minetest-basic-materials.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (6 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 07/20] gnu: Add minetest-mesecons Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 09/20] gnu: Add minetest-unifieddyes Maxime Devos
                                     ` (11 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-basic-materials): New variable.
---
 gnu/packages/minetest.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d99efa4625..97d4d3c9ac 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -25,6 +25,31 @@ numeric identifier TOPIC-ID on the official Minetest forums."
   (string-append "https://forum.minetest.net/viewtopic.php?t="
                  (number->string topic-id)))
 
+(define-public minetest-basic-materials
+  (package
+    (name "minetest-basic-materials")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-01-30")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/basic_materials.git")
+             (commit "e72665b2ed98d7be115779a32d35e6d9ffa231bd")))
+       (sha256
+        (base32 "0v6l3lrjgshy4sccjhfhmfxc3gk0cdy73qb02i9wd2vw506v5asx"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 21000))
+    (synopsis "Some \"basic\" materials and items for other Minetest mods to use")
+    (description
+     "The Minetest mod \"basic_materials\" provides a small selection of
+\"basic\" materials and items that other mods should use when possible -- things
+like steel bars and chains, wire, plastic strips and sheets, and more.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/basic_materials")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 09/20] gnu: Add minetest-unifieddyes.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (7 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 08/20] gnu: Add minetest-basic-materials Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 10/20] gnu: Add minetest-pipeworks Maxime Devos
                                     ` (10 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-unifieddyes): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 97d4d3c9ac..8b9eb30a6a 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -85,3 +85,32 @@ with different rules and mechanics.")
     ;; <https://github.com/minetest-mods/mesecons/issues/575>.
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
+
+(define-public minetest-unifieddyes
+  (package
+    (name "minetest-unifieddyes")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-20-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/unifieddyes")
+             (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
+       (sha256
+        (base32
+         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2178))
+    (synopsis
+     "Unified Dyes expands the standard dye set of Minetest to up to 256 colours")
+    (description "The purpose of this mod originally was to supply a complete
+set of colours for Minetest mod authors to use for colourised nodes or
+reference in recipes.  Since the advent of the default dyes mod in the standard
+Minetest game, this mod has become an extension of the default mod an a library
+for general colour handling.")
+    (license license:gpl2+)
+    (properties `((upstream-name . "VanessaE/unifieddyes")))))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 10/20] gnu: Add minetest-pipeworks.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (8 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 09/20] gnu: Add minetest-unifieddyes Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 11/20] gnu: Add minetest-coloredwood Maxime Devos
                                     ` (9 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-pipeworks): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 8b9eb30a6a..782166daef 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -86,6 +86,37 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-pipeworks
+  (package
+    (name "minetest-pipeworks")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/pipeworks")
+             (commit "db6d1bd9c109e1e543b97cc3fa8a11400da23bcd")))
+       (sha256
+        (base32 "1flhcnf17dn1v86kcg47a1n4cb0lybd11ncxrkxn3wmf10ibsrm0"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2155))
+    (synopsis "Pipes, item-transport tubes and related devices for Minetest")
+    (description
+     "Pipeworks is a mod for Minetest implementing 3D pipes and tubes for
+transporting liquids and items and some related devices.  Pipes and tubes can
+go horizontally or vertically.  Item tubes can also be used for sorting items
+and extracting items from chests or putting items in chests.  Autocrafters can
+automatically follow craft recipes to make new items and can be fed by item
+tubes.  Deployers can place items in the world as a player would.  Node
+breakers simulate a player punching a node.")
+    ;; CC-BY-SA for textures, LGPL for code
+    (license (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/pipeworks")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 11/20] gnu: Add minetest-coloredwood.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (9 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 10/20] gnu: Add minetest-pipeworks Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 12/20] gnu: Add minetest-ethereal Maxime Devos
                                     ` (8 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-coloredwood): New variable.
---
 gnu/packages/minetest.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 782166daef..4c542c6061 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -50,6 +50,34 @@ like steel bars and chains, wire, plastic strips and sheets, and more.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/basic_materials")))))
 
+(define-public minetest-coloredwood
+  (package
+    (name "minetest-coloredwood")
+    ;; Upstream uses dates as version numbers.
+    (version "2021-04-14-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/coloredwood")
+             (commit "be4df6fc889419155bed8638bbb752493e78cbd5")))
+       (sha256
+        (base32 "1swirfk6b4xfbiwv8adyw5yl2lyfpp8ymfipzq9ivyvmif8nl3ki"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2411))
+    (synopsis "Painted wood in Minetest")
+    (description
+     "This Minetest mod provides hundreds of colours of wood and fences to
+Minetest, using Unified Dyes.  If the \"moreblocks\" mod is active,
+coloured and cut wood shapes are provided as well.")
+    (license
+     ;; LGPL for code, CC-BY-SA for textures
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/coloredwood")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 12/20] gnu: Add minetest-ethereal.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (10 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 11/20] gnu: Add minetest-coloredwood Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 13/20] gnu: Add minetest-technic Maxime Devos
                                     ` (7 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-ethereal): New variable.
---
 gnu/packages/minetest.scm | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4c542c6061..a1aa90276d 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -78,6 +78,35 @@ coloured and cut wood shapes are provided as well.")
      (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/coloredwood")))))
 
+(define-public minetest-ethereal
+  ;; ContentDB release 2021-07-28 is slightly ahead of the
+  ;; initial version 1.29 -- i.e., some released changes have been
+  ;; made to version 1.29 without a corresponding version bump.
+  (let ((commit "7670c1da9274901f57f6682384af2b3bae005a86")
+        (revision "0"))
+    (package
+      (name "minetest-ethereal")
+      (version (git-version "1.29" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://notabug.org/TenPlus1/ethereal")
+               (commit commit)))
+         (sha256
+          (base32 "1hal8bq4fydsip7s8rqz4vlaaqy9rhzxmryd0j2qnqm9286yjgkk"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 14638))
+      (synopsis "The Ethereal mod adds many new biomes to Minetest")
+      (description
+       "The Ethereal Minetest mod uses the v7 map generator to add many new
+biomes to the world.  It adds new trees, plants, food items, tweaks and some
+special items, intending to make an interesting adventure.")
+      ;; CC0: some textures
+      (license (list license:cc0 license:expat))
+      (properties `((upstream-name . "TenPlus1/ethereal"))))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
@@ -157,8 +186,7 @@ breakers simulate a player punching a node.")
              (url "https://gitlab.com/VanessaE/unifieddyes")
              (commit "ff3b2d30fa0df5c7181fdd401b989de6271c3bb3")))
        (sha256
-        (base32
-         "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
+        (base32 "0rba9n192xcpmxwnq7ixb6mn32gkpic247j3w4mwinrqcyscacsv"))
        (file-name (git-file-name name version))))
     (build-system minetest-mod-build-system)
     (propagated-inputs
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 13/20] gnu: Add minetest-technic.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (11 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 12/20] gnu: Add minetest-ethereal Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 14/20] gnu: Add minetest-throwing Maxime Devos
                                     ` (6 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-technic): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index a1aa90276d..bb914f32b4 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -174,6 +174,41 @@ breakers simulate a player punching a node.")
     (license (list license:cc-by-sa4.0 license:lgpl3))
     (properties `((upstream-name . "VanessaE/pipeworks")))))
 
+(define-public minetest-technic
+  (package
+    (name "minetest-technic")
+    ;; Upstream doesn't keep version numbers, so use the release
+    ;; date on ContentDB instead.
+    (version "2021-04-15")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/technic")
+             (commit "1c219487d3f4dd03c01ff9aa1f298c7c18c7e189")))
+       (sha256
+        (base32 "1k9hdgzp7jnhsk6rgrlrv1lr5xrmh8ln4wv6r25v6f0fwbyj57sf"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-pipeworks" ,minetest-pipeworks)
+       ("minetest-basic-materials" ,minetest-basic-materials)))
+    (home-page (minetest-topic 2538))
+    (synopsis "Machinery and automation for Minetest")
+    (description
+     "This Minetest mod adds machinery and automation to Minetest.
+It adds various ores that can be processed for constructing various
+machinery, such as power generators, force field emitters, quarries
+and a workshop for repairing tools.  Most machines are electrically
+powered.")
+    ;; CC BY-SA 3.0: some texture
+    ;; WTFPL: some textures
+    ;; CC BY-SA3.0: some textures
+    ;; CC BY-SA4.0: some sounds
+    (license (list license:lgpl2.1+ license:cc-by-sa3.0 license:cc-by-sa4.0
+                   license:wtfpl2))
+    (properties `((upstream-name . "RealBadAngel/technic")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 14/20] gnu: Add minetest-throwing.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (12 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 13/20] gnu: Add minetest-technic Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
                                     ` (5 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-throwing): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index bb914f32b4..4566d94489 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -209,6 +209,33 @@ powered.")
                    license:wtfpl2))
     (properties `((upstream-name . "RealBadAngel/technic")))))
 
+(define-public minetest-throwing
+  ;; The latest release on ContentDB is ahead of the latet
+  ;; tagged commit.
+  (let ((commit "31f0cf5f868673dc82f24ddc432b45c9cd282d27")
+        (revision "0"))
+    (package
+      (name "minetest-throwing")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing")
+               (commit commit)))
+         (sha256
+          (base32 "1s5kkr6rxxv2dhbbjzv62gw1s617hnpjavw1v9fv11v3mgigdfjb"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (home-page (minetest-topic 16365))
+      (synopsis "API for throwing things in Minetest")
+      (description
+       "This Minetest mod provides an API for registering throwable things and
+throwing things like arrows.  However, this mod does not provide an actual
+arrow and bow, but @code{minetest-throwing-arrows} does.")
+      (license license:mpl2.0)
+      (properties `((upstream-name . "Palige/throwing"))))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 15/20] gnu: Add minetest-throwing-arrows.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (13 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 14/20] gnu: Add minetest-throwing Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 16/20] gnu: Add minetest-unified-inventory Maxime Devos
                                     ` (4 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm
  (minetest-throwing-arrows): New variable.
---
 gnu/packages/minetest.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 4566d94489..1f785098f9 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -236,6 +236,36 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
       (license license:mpl2.0)
       (properties `((upstream-name . "Palige/throwing"))))))
 
+(define-public minetest-throwing-arrows
+  ;; There is only one tagged commit (version 1.1),
+  ;; there are no releases on ContentDB and the latest
+  ;; commit has a compatibility fix for Minetest 5.4.0-dev.
+  (let ((commit "059cc897af0aebfbd2c54ac5588f2b842f44f159")
+        (revision "0"))
+    (package
+      (name "minetest-throwing-arrows")
+      (version (git-version "1.1" revision commit))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/minetest-mods/throwing_arrows")
+               (commit commit)))
+         (sha256
+          (base32 "0m2pmccpfxn878zd00pmrpga2h6gknz4f3qprck0fq94mksmwqs3"))
+         (file-name (git-file-name name version))))
+      (build-system minetest-mod-build-system)
+      (propagated-inputs
+       `(("minetest-throwing" ,minetest-throwing)))
+      (home-page (minetest-topic 16365))
+      (synopsis "Arrows and bows for Minetest")
+      (description
+       ;; TRANSLATORS: "throwing" is the name of a Minetest mod and should
+       ;; not be translated.
+       "This mod adds arrows and bows to Minetest.  It is a compatible
+replacement for the throwing mod by PilzAdam that uses the throwing API.")
+      (license license:mpl2.0))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 16/20] gnu: Add minetest-unified-inventory.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (14 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 17/20] gnu: Add minetest-worldedit Maxime Devos
                                     ` (3 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm
  (minetest-unified-inventory): New variable.
---
 gnu/packages/minetest.scm | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 1f785098f9..d6ff6c9e47 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -293,3 +293,38 @@ Minetest game, this mod has become an extension of the default mod an a library
 for general colour handling.")
     (license license:gpl2+)
     (properties `((upstream-name . "VanessaE/unifieddyes")))))
+
+(define-public minetest-unified-inventory
+  (package
+    (name "minetest-unified-inventory")
+    ;; Upstream doesn't keep version numbers, so use the release title
+    ;; on ContentDB instead.
+    (version "2021-03-25-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/minetest-mods/unified_inventory")
+             (commit "c044f5e3b08f0c68ab028d757b2fa63d9a1b0370")))
+       (sha256
+        (base32 "198g945gzbfl0kps46gwjw0c601l3b3wvn4c7dw8manskri1jr4g"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 12767))
+    (synopsis "Replace the default inventory in Minetest and add a crafting guide")
+    (description
+     "The Unified Inventory Minetest mod relaces the default survival an
+creative inventory.  It includes a node, item and tool browser, a crafting
+guide, a trash and refill slot for creative mode, bags and waypoints for keeping
+track of important locations.")
+    ;; CC-BY: some textures and icons
+    ;; CC-BY-SA: some textures and icons
+    ;; LGLPL2.1+: code and some textures
+    ;; GPL2+: some textures
+    ;; GPL3: bags.lua
+    ;; GFDL: some icons
+    ;; public domain, CC0: some icons
+    (license (list license:gpl3 license:gpl2+ license:lgpl2.1+ license:cc-by3.0
+                   license:cc-by4.0 license:cc-by-sa3.0 license:public-domain
+                   license:cc0 license:fdl1.2+))
+    (properties `((upstream-name . "RealBadAngel/unified_inventory")))))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 17/20] gnu: Add minetest-worldedit.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (15 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 16/20] gnu: Add minetest-unified-inventory Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 18/20] gnu: Add minetest-mobs Maxime Devos
                                     ` (2 subsequent siblings)
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-worldedit): New variable.
---
 gnu/packages/minetest.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d6ff6c9e47..700a9b2872 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -266,6 +266,29 @@ arrow and bow, but @code{minetest-throwing-arrows} does.")
 replacement for the throwing mod by PilzAdam that uses the throwing API.")
       (license license:mpl2.0))))
 
+(define-public minetest-worldedit
+  (package
+    (name "minetest-worldedit")
+    (version "1.3")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/Uberi/Minetest-WorldEdit")
+             (commit "2f26fb76459c587868199160b9d7b5d6d7852e50")))
+       (sha256
+        (base32 "0lsvihkixi2na1b0vmml9vwgs0g24hqqshl73ffhkzh6jsq4cagq"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 572))
+    (synopsis "In-game world editor for Minetest")
+    (description
+     "WorldEdit is a mod for Minetest.  It allows for creating various
+geometric shapes and copying regions.  It can also export and import regions
+to and from the file system.")
+    (license license:agpl3)
+    (properties `((upstream-name . "sfan5/worldedit")))))
+
 (define-public minetest-unifieddyes
   (package
     (name "minetest-unifieddyes")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 18/20] gnu: Add minetest-mobs.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (16 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 17/20] gnu: Add minetest-worldedit Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 19/20] gnu: Add minetest-mobs-animal Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-mobs): New variable.
---
 gnu/packages/minetest.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 700a9b2872..d36ca06ef5 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -143,6 +143,35 @@ with different rules and mechanics.")
     (license (list license:lgpl3+ license:cc-by-sa3.0))
     (properties `((upstream-name . "Jeija/mesecons"))))))
 
+(define-public minetest-mobs
+  (package
+    (name "minetest-mobs")
+    ;; Upstream does not tag release, so use the ContentDB release
+    ;; title instead.
+    (version "2021-07-22")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_redo")
+             (commit "9f46182bb4b1a390f9a140bc2b443f3cda702332")))
+       (sha256
+        (base32 "026kqjis4lipgskjivb3jh9ris3iz80vy2q1jvgxhxmfghjjzp4j"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (home-page (minetest-topic 9917))
+    (synopsis "Mob library for Minetest mods, for animals, monsters etc.")
+    (description
+     "This Minetest mod provides an API for adding mods (moving entities
+like animals and monsters), but does not include any mobs itself.  To actually
+add some mobs, a mod like e.g. @code{mobs_animal} provided by the
+@code{minetest-mobs-animal} package needs to be enabled.")
+    ;; CC0: mob_swing.ogg
+    ;; CC-BY 3.0: mob_spell.ogg
+    ;; Expat: everything else
+    (license (list license:expat license:cc0 license:cc-by3.0))
+    (properties `((upstream-name . "TenPlus1/mobs")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 19/20] gnu: Add minetest-mobs-animal.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (17 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 18/20] gnu: Add minetest-mobs Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm (minetest-mobs-animal): New variable.
---
 gnu/packages/minetest.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index d36ca06ef5..3cd14a6df8 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -172,6 +172,33 @@ add some mobs, a mod like e.g. @code{mobs_animal} provided by the
     (license (list license:expat license:cc0 license:cc-by3.0))
     (properties `((upstream-name . "TenPlus1/mobs")))))
 
+(define-public minetest-mobs-animal
+  (package
+    (name "minetest-mobs-animal")
+    ;; Upstream does not use version numbers, so use the release title
+    ;; from ContentDB instead;
+    (version "2021-07-24")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://notabug.org/TenPlus1/mobs_animal")
+             (commit "c2fa3e300c79c7dd80b6fe91a8b5082bb6b3d934")))
+       (sha256
+        (base32 "1j719f079ia9vjxrmjrcj8s6jvaz5kgs1r4dh66z8ql6s70kx7vh"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-mobs" ,minetest-mobs)))
+    (home-page "https://notabug.org/TenPlus1/mobs_animal")
+    (synopsis "Add animals to Minetest")
+    (description
+     "This Minetest mod adds various animals to Minetest, such as bees,
+bunnies, chickens, cows, kittens, rats, sheep, warthogs, penguins and pandas.")
+    ;; CC0: some textures and sounds
+    (license (list license:cc0 license:expat))
+    (properties `((upstream-name . "TenPlus1/mobs_animal")))))
+
 (define-public minetest-pipeworks
   (package
     (name "minetest-pipeworks")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [bug#49828] [PATCH v3 20/20] gnu: Add minetest-homedecor-modpack.
  2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
                                     ` (18 preceding siblings ...)
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 19/20] gnu: Add minetest-mobs-animal Maxime Devos
@ 2021-08-10 15:07                   ` Maxime Devos
  19 siblings, 0 replies; 71+ messages in thread
From: Maxime Devos @ 2021-08-10 15:07 UTC (permalink / raw)
  To: 49828; +Cc: Leo Prikler, Maxime Devos

* gnu/packages/minetest.scm
  (minetest-homedecor-modpack): New variable.
---
 gnu/packages/minetest.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/minetest.scm b/gnu/packages/minetest.scm
index 3cd14a6df8..3bd640da45 100644
--- a/gnu/packages/minetest.scm
+++ b/gnu/packages/minetest.scm
@@ -107,6 +107,37 @@ special items, intending to make an interesting adventure.")
       (license (list license:cc0 license:expat))
       (properties `((upstream-name . "TenPlus1/ethereal"))))))
 
+(define-public minetest-homedecor-modpack
+  (package
+    (name "minetest-homedecor-modpack")
+    ;; Upstream doesn't tag releases, so use the release title from
+    ;; ContentDB as version.
+    (version "2021-03-27-1")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://gitlab.com/VanessaE/homedecor_modpack")
+             (commit "9ffe2b7d691133e1a067546574fbe7364fd02f32")))
+       (sha256
+        (base32 "1lfajqvc2adf9hqskghky4arccqzpjw4i9a01hv4qcckvivm04ag"))
+       (file-name (git-file-name name version))))
+    (build-system minetest-mod-build-system)
+    (propagated-inputs
+     `(("minetest-basic-materials" ,minetest-basic-materials)
+       ("minetest-unifieddyes" ,minetest-unifieddyes)))
+    (home-page (minetest-topic 2041))
+    (synopsis "Home decor mod for Minetest")
+    (description
+     ;; TRANSLATORS: ‘homedecor’ is the name is the name of a Minetest mod
+     ;; and should not be translated.
+     "The homedecor Minetest mod provides a large seleection of items that
+might be found inside and around homes, such as sofas, chairs, tables, fences
+and a variety of other stuff.")
+    (license
+     (list license:cc-by-sa4.0 license:lgpl3))
+    (properties `((upstream-name . "VanessaE/homedecor_modpack")))))
+
 (define-public minetest-mesecons
   ;; The release on ContentDB does not have its own version number.
   (let ((commit "db5879706d04d3480bc4863ce0c03fa73e5f10c7")
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 71+ messages in thread

* bug#49828: [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH.
  2021-08-10 15:07                   ` [bug#49828] [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
@ 2021-08-20 11:45                     ` Leo Prikler
  0 siblings, 0 replies; 71+ messages in thread
From: Leo Prikler @ 2021-08-20 11:45 UTC (permalink / raw)
  To: Maxime Devos, 49828-done

Hi Maxime,

I've now pushed this patch set to master with the following
adjustments:

Am Dienstag, den 10.08.2021, 17:07 +0200 schrieb Maxime Devos:
> * gnu/packages/patches/Add-environment-variable-
> MINETEST_MOD_PATH.patch:
>   New file.
I've renamed this patch to minetest-add-MINETEST_MOD_PATH.patch and
adjusted the rest accordingly.  Please note, that patches should always
state which package they apply to in their name.

Furthermore I've followed up with patches, that move the existing
minetest packages to minetest.scm.

Thanks






^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2021-08-20 11:47 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-02 15:46 [bug#49828] [PATCH 00/20] Add minetest mods Maxime Devos
2021-08-02 15:50 ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
2021-08-02 17:28     ` Leo Prikler
2021-08-02 17:53       ` Maxime Devos
2021-08-02 18:47         ` Leo Prikler
2021-08-03 11:09           ` Maxime Devos
2021-08-03 11:10             ` Maxime Devos
2021-08-03 11:54               ` Leo Prikler
2021-08-02 15:50   ` [bug#49828] [PATCH 03/20] gnu: minetest: New package module Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 05/20] build-system: minetest: Don't retain references to "bash-minimal" Maxime Devos
2021-08-03  9:17     ` Leo Prikler
2021-08-03 11:59       ` Maxime Devos
2021-08-03 12:28         ` Leo Prikler
2021-08-05 11:01           ` Maxime Devos
2021-08-05 12:04             ` Leo Prikler
2021-08-05 13:16               ` Maxime Devos
2021-08-05 13:42                 ` Leo Prikler
2021-08-05 14:41                   ` Maxime Devos
2021-08-05 15:15                     ` Leo Prikler
2021-08-02 15:50   ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
2021-08-05 16:41     ` Leo Prikler
2021-08-07 18:31       ` Maxime Devos
2021-08-07 19:47         ` Leo Prikler
2021-08-09 20:00           ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Don't send yet) Maxime Devos
2021-08-09 20:04             ` Maxime Devos
2021-08-09 21:45             ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer. (XXX Yes send now) Leo Prikler
2021-08-10 11:02               ` [bug#49828] [PATCH 06/20] guix: Add ContentDB importer Maxime Devos
2021-08-10 12:16                 ` Leo Prikler
2021-08-10 15:07                 ` [bug#49828] [PATCH v3 00/20] Add minetest mods Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 01/20] gnu: minetest: Respect --without-tests Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 02/20] gnu: minetest: Search for mods in MINETEST_MOD_PATH Maxime Devos
2021-08-20 11:45                     ` bug#49828: " Leo Prikler
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 03/20] gnu: minetest: New package module Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 04/20] build-system: Add 'minetest-mod-build-system' Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 05/20] import/utils: Recognise GPL-3.0-or-later and friends Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 06/20] guix: Add ContentDB importer Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 07/20] gnu: Add minetest-mesecons Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 08/20] gnu: Add minetest-basic-materials Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 09/20] gnu: Add minetest-unifieddyes Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 10/20] gnu: Add minetest-pipeworks Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 11/20] gnu: Add minetest-coloredwood Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 12/20] gnu: Add minetest-ethereal Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 13/20] gnu: Add minetest-technic Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 14/20] gnu: Add minetest-throwing Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 16/20] gnu: Add minetest-unified-inventory Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 17/20] gnu: Add minetest-worldedit Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 18/20] gnu: Add minetest-mobs Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 19/20] gnu: Add minetest-mobs-animal Maxime Devos
2021-08-10 15:07                   ` [bug#49828] [PATCH v3 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 07/20] gnu: Add minetest-mesecons Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 08/20] gnu: Add minetest-basic-materials Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 09/20] gnu: Add minetest-unifieddyes Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 10/20] gnu: Add minetest-pipeworks Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 11/20] gnu: Add minetest-coloredwood Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 12/20] gnu: Add minetest-ethereal Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 13/20] gnu: Add minetest-technic Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 14/20] gnu: Add minetest-throwing Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 15/20] gnu: Add minetest-throwing-arrows Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 16/20] gnu: Add minetest-unified-inventory Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 17/20] gnu: Add minetest-worldedit Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 18/20] gnu: Add minetest-mobs Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 19/20] gnu: Add minetest-mobs-animal Maxime Devos
2021-08-02 15:50   ` [bug#49828] [PATCH 20/20] gnu: Add minetest-homedecor-modpack Maxime Devos
2021-08-02 17:14   ` [bug#49828] [PATCH 01/20] gnu: minetest: Respect --without-tests Leo Prikler
2021-08-02 17:18     ` Maxime Devos
2021-08-02 17:22       ` Leo Prikler
2021-08-05 12:46 ` [bug#49828] [PATCH 00/20] Add minetest mods Andrew Ward
2021-08-05 21:10   ` Maxime Devos

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.