Hello!

Guix has updated it's Emacs package to Emacs 31.1 so I have refreshed this file
to work with the latest and greatest.  I've also added some new
features.

Now the default build is with Emacs 31 and I've added a new build for
Emacs 30.

I now pull the org version directly out of org.el instead of hard coding it.

I now have build recipes for emacs 25, 26, and 27.  Although they aren't very
useful as the guix emacs-build-system seems to only work for emacs >= 28.

The org tests currently don't pass on emacs 28 and Ihor has stated that
is a "won't fix".  However, I've updated the emacs-28 org build in this
file to forcefully load compat and that does make the tests pass!

I've updated the build definition of org to match the upstream guix one.

I've added a build that pulls in a bunch of optional dependencies to run the
org babel tests.  I've called this build "emacs-org-with-integration-tests".
Many tests do pass but currently it just hangs forever on the julia and R
tests.

The integration-tests build is what lead me to open this other thread
previously:
https://list.orgmode.org/orgmode/ch3pr84mb3424640fffd53f919ed5d3f5c5...@ch3pr84mb3424.namprd84.prod.outlook.com/

Building a specific commit of org now sets the "GITVERSION" build system
variable.

Enjoy!  Or don't.  This is very useful to me personally and that's enough
reason for me to maintain this.  If someone is using this, please let me know
because that would make me happy!

>From b1bc6c07d2f41917293332aa665450c2d6cbcad8 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Sat, 20 Jun 2026 12:15:54 -0400
Subject: [PATCH] Add guix.scm file to enable building with GNU Guix

This allows us to use Guix as a sort of CI to aid in development.  See
the top of the file for more commentary.

* guix.scm: New file
---
 guix.scm | 718 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 718 insertions(+)
 create mode 100644 guix.scm

diff --git a/guix.scm b/guix.scm
new file mode 100644
index 000000000..e97a2beca
--- /dev/null
+++ b/guix.scm
@@ -0,0 +1,718 @@
+;;; guix.scm  --  Build recipe for GNU Guix.
+
+;; File maintained by Morgan Smith <[email protected]>
+
+;; Much of this code is copied from the GNU Guix project (same
+;; licensing of GPLV3+)
+
+;; GNU Guix has a very useful build system that we can use.  It has
+;; the ability to control the build environment completely.
+;;
+;; If you are not already familiar with the "Make" build system, then
+;; you should do that first.
+;;
+;; By running:
+;;     guix build -f guix.scm
+;;
+;; Guix will build all of the package definitions that are returned by
+;; this file (the list at the bottom).
+;;
+;; If we instead run:
+;;     guix build --max-jobs=4 --keep-going -f guix.scm
+;;
+;; Then Guix will run 4 builds at once and keep going even if a build
+;; fails.  The output of all builds will be mixed together but don't
+;; fret.  Guix will save a log file for each failure that you can open
+;; to see only the output of that build.  Look for lines that start
+;; with "View build log at"
+;;
+;; If Guix has already built a package definition, it is smart enough
+;; to not build it again.  You can force it to build with the
+;; "--check" flag.
+;;
+;; New variants can also be defined on the command-line.  For example:
+;;
+;;     guix build -e '(begin (load "guix.scm") (pkg-with-lang emacs-org "tok"))'
+;;
+;;; Guix Shell
+;;
+;; An interactive shell with packages can be created like so:
+;;
+;;     guix shell -e '(begin (load "guix.scm") (list emacs-org-28 emacs-minimal-28))'
+;;
+;; However, running emacs like this will have strange issues as it
+;; will share your system EMACSLOADPATH environment variable and will
+;; have access to your emacs `user-init-file'.  I recommend running
+;; emacs in a container like this:
+;;
+;;     # Preserve TERM environment variable so emacs can run in the terminal
+;;     guix shell --container --preserve='^TERM$' -e '(begin (load "guix.scm") (list emacs-org-28 emacs-minimal-28))' -- emacs
+;;
+;; Using short flags the same command would look like this:
+;;
+;;     guix shell -C -E '^TERM$' -e '(begin (load "guix.scm") (list emacs-org-28 emacs-minimal-28))' -- emacs
+;;
+;; To run a graphical emacs under X11 try this command:
+;; (the emacs minimal variants don't have graphical capabilities)
+;;
+;;     guix shell -C -E '^DISPLAY$' --share=/tmp -e '(begin (load "guix.scm") (list emacs-org-28 emacs-28))' -- emacs
+;;
+;; To run a graphical emacs under wayland try this command:
+;; (this requires a "pgtk" emacs variant)
+;;
+;;     guix shell -C -E '^WAYLAND_DISPLAY$' -E '^XDG_RUNTIME_DIR$' --expose=$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY -e '(begin (load "guix.scm") (list emacs-org emacs-pgtk))' -- emacs
+
+(use-modules ((guix licenses) #:prefix license:)
+             (gnu packages)
+             (gnu packages base)
+             (gnu packages check)
+             (gnu packages emacs)
+             (gnu packages texinfo)
+             (guix)
+             (guix build utils)
+             (guix build-system emacs)
+             (guix gexp)
+             (guix git)
+             (guix git-download)
+             (guix packages)
+             (guix profiles)
+             (guix utils)
+             (ice-9 popen)
+             (ice-9 rdelim)
+             (ice-9 regex))
+
+(define %source-dir (dirname (current-filename)))
+
+(define vcs-file?
+  ;; Return true if the given file is under version control.
+  (or (git-predicate %source-dir #:recursive? #f)
+      (const #t)))                                ;not in a Git checkout
+
+;; Files that are not pulled into the Guix build.  Modifying these
+;; files will not cause Guix to rebuild so it is useful to exclude any
+;; files that are not needed.
+(define exclude-files
+  (map
+   (lambda (file)
+     (string-append %source-dir "/" file))
+   '("guix.scm" "git-hooks")))
+
+(define (emacs-org-build-file? file stat)
+  (if (member file exclude-files)
+      #f
+      (vcs-file? file stat)))
+
+(define (git-output . args)
+  "Execute 'git ARGS ...' command and return its output without trailing
+newspace."
+  (with-directory-excursion %source-dir
+    (let* ((port   (apply open-pipe* OPEN_READ "git" args))
+           (output (read-string port)))
+      (close-pipe port)
+      (string-trim-right output #\newline))))
+
+(define (string-filter-store-item str)
+  "Filter out any characters from STR that aren't valid in a guix store
+item name."
+  ;; FIXME: Tell upstream to export this variable
+  (string-filter (@@ (guix store) %store-item-charset) str))
+
+(define org-mode-version
+  (delay
+    (with-input-from-file (string-append %source-dir "/lisp/org.el")
+      (lambda ()
+        (let ((regex (make-regexp "^;; Version: (.*)"))
+              (version #f)
+              (str #f))
+          (while (and (not version)
+                      (set! str (read-line)))
+            (let ((match (regexp-exec regex str)))
+              (when (and match
+                         (match:substring match 1))
+                (set! version (match:substring match 1)))))
+          (or version
+              (error "Could not figure out version!")))))))
+
+(define emacs-minimal-25
+  (package
+    (inherit emacs-minimal)
+    (version "25.3")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "02y00y9q42g1iqgz5qhmsja75hwxd88yrn9zp14lanay0zkwafi5"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)
+            (delete 'patch-program-file-names)))
+       ((#:substitutable? _ #f) #f)))
+    (native-inputs (modify-inputs native-inputs
+                     (prepend (@ (gnu packages autotools) automake))))))
+
+(define emacs-minimal-26
+  (package
+    (inherit emacs-minimal)
+    (version "26.3")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "119ldpk7sgn9jlpyngv5y4z3i7bb8q3xp4p0qqi7i5nq39syd42d"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)
+            (delete 'patch-program-file-names)))
+       ((#:substitutable? _ #f) #f)))))
+
+(define emacs-minimal-27
+  (package
+    (inherit emacs-minimal)
+    (version "27.2")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "1ff182gjw9wqsbx1kj5gl2r5pbqhp4ar54g04j33fgz6g17cr9xl"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)
+            (delete 'patch-program-file-names)))
+       ((#:substitutable? _ #f) #f)))))
+
+(define emacs-minimal-28
+  (package
+    (inherit emacs-minimal)
+    (version "28.2")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "12144dcaihv2ymfm7g2vnvdl4h71hqnsz1mljzf34cpg6ci1h8gf"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)))
+       ((#:substitutable? _ #f) #f)))))
+
+(define emacs-28
+  (package
+    (inherit emacs)
+    (version (package-version emacs-minimal-28))
+    (source (package-source emacs-minimal-28))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)
+            (delete 'build-trampolines)
+            (delete 'validate-comp-integrity)))
+       ;; This keyword is not supported by glib-or-gtk-build-system even
+       ;; though it would work :/
+       ;; ((#:substitutable? _ #f) #f)
+       ))))
+
+(define emacs-minimal-29
+  (package
+    (inherit emacs-minimal)
+    (version "29.4")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "0dd2mh6maa7dc5f49qdzj7bi4hda4wfm1cvvgq560djcz537k2ds"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:substitutable? _ #f) #f)))))
+
+(define emacs-29
+  (package
+    (inherit emacs)
+    (version (package-version emacs-minimal-29))
+    (source (package-source emacs-minimal-29))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:tests? _ #f) #f)
+       ((#:phases phases)
+        #~(modify-phases #$phases
+            (delete 'fix-tests)
+            (delete 'install-site-start)
+            (delete 'build-trampolines)
+            (delete 'validate-comp-integrity)))
+       ;; This keyword is not supported by glib-or-gtk-build-system even
+       ;; though it would work :/
+       ;; ((#:substitutable? _ #f) #f)
+       ))))
+
+(define emacs-minimal-30
+  (package
+    (inherit emacs-minimal)
+    (version "30.2")
+    (source (origin
+              (inherit (package-source emacs-minimal))
+              (method url-fetch)
+              (uri (string-append "mirror://gnu/emacs/emacs-"
+                                  version ".tar.xz"))
+              (sha256
+               (base32
+                "1nggbgnns7lvxn68gzlcsgwh3bigvrbn45kh6dqia9yxlqc6zwxk"))
+              (patches '())))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:substitutable? _ #f) #f)))))
+
+(define emacs-org
+  (package
+    (name "emacs-org")
+    (version (force org-mode-version))
+    (source (local-file "." "org-mode-checkout"
+                        #:recursive? #t
+                        #:select? emacs-org-build-file?))
+    (build-system emacs-build-system)
+    (outputs (list "out" "test"))
+    (arguments
+     (list
+      #:substitutable? #f ;; Don't upstream this
+      #:disallowed-references (map cadr (package-native-inputs this-package))
+      #:test-command #~(list "make" "-C" ".." "test-dirty")
+      #:lisp-directory "lisp"
+      #:phases
+      #~(modify-phases %standard-phases
+          (add-after 'unpack 'patch-paths
+            (lambda* (#:key inputs #:allow-other-keys)
+              (substitute* "ob-shell.el"
+                (("/usr/bin/env")
+                 (search-input-file inputs "/bin/env")))))
+          (replace 'make-autoloads
+            (lambda _
+              (invoke "make" "-C" ".." "autoloads"
+                      (string-append "ORGVERSION=" #$version))))
+          (add-before 'check 'fix-tests
+            (lambda* (#:key tests? inputs #:allow-other-keys)
+              (when tests?
+                (with-directory-excursion "../testing"
+                  ;; XXX: Running tests updates ID locations.  The process expects
+                  ;; a file to be writeable in "~/.emacs.d/".
+                  (setenv "HOME" (getcwd))
+                  (mkdir-p ".emacs.d")
+                  ;; These files are modified during testing.
+                  (with-directory-excursion "examples"
+                    (for-each make-file-writable
+                              '("babel.org"
+                                "ob-awk-test.org"
+                                "ob-sed-test.org"))
+                    ;; Specify where sh executable is.
+                    (let ((sh (search-input-file inputs "/bin/sh")))
+                      (substitute* "babel.org"
+                        (("/bin/sh") sh))))
+                  ;; XXX: Fix failure in ob-tangle/collect-blocks.  The test
+                  ;; assumes that ~/../.. corresponds to /.  This isn't true in
+                  ;; our case.
+                  (substitute* "lisp/test-ob-tangle.el"
+                    ((" ~/\\.\\./\\.\\./")
+                     (string-append " ~"
+                                    ;; relative path from ${HOME} to / during
+                                    ;; build
+                                    (string-join
+                                     (map-in-order
+                                      (lambda (x)
+                                        (if (equal? x "") "" ".."))
+                                      (string-split (getcwd) #\/)) "/")
+                                    "/")))
+                  ;; XXX: Skip failing tests.
+                  (substitute* "lisp/test-ob-shell.el"
+                    (("ob-shell/remote-with-stdin-or-cmdline .*" all)
+                     (string-append all "  (skip-unless nil)\n")))))))
+          (add-after 'install 'install-the-rest
+            ;; First install gets the lisp, then this install grabs the rest
+            ;; (info, news, etc)
+            (lambda _
+              (let ((elpa (elpa-directory #$output))
+                    (info (string-append #$output "/share/info")))
+                (invoke "make" "-C" ".." "install-info" "install-etc"
+                        (string-append "datadir=" elpa "/etc")
+                        (string-append "infodir=" info)))))
+          (add-after 'install 'install-org-test
+            (lambda _
+              (with-directory-excursion "../testing"
+                (copy-recursively "."
+                                  (string-append (elpa-directory #$output:test))))))
+          (add-after 'install 'install-org-news
+            ;; Install ORG-NEWS files in doc directory.
+            (lambda _
+              (install-file "../etc/ORG-NEWS"
+                            (string-append #$output "/share/doc/"
+                                           #$name "-" #$version))))
+          (replace 'install-license-files
+            (lambda args
+              ;; Change to top-level so we find the license.
+              (with-directory-excursion ".."
+                (apply (assoc-ref %standard-phases 'install-license-files)
+                       args)))))))
+    (native-inputs
+     (list texinfo tzdata))
+    (home-page "https://orgmode.org/";)
+    (synopsis "Outline-based notes management and organizer")
+    (description "Org is an Emacs mode for keeping notes, maintaining TODO
+lists, and project planning with a fast and effective lightweight markup
+language.  It also is an authoring system with unique support for literate
+programming and reproducible research.  If you work with the LaTeX output
+capabilities of Org-mode, you may want to install the
+@code{emacs-org-texlive-collection} meta-package, which propagates the TexLive
+components required by the produced @file{.tex} file.")
+    (license license:gpl3+)))
+
+;; FIXME: add these languages
+;; - csharp (mono)
+;;   - org-babel-csharp-compiler = dotnet
+;;   - mono package does not provide "dotnet"
+;;     - maybe try "csharp"?
+;; FIXME:
+;; Ran 1555 tests, 1512 results as expected, 28 unexpected, 15 skipped
+;; 9 expected failures
+(define emacs-org-with-integration-tests
+  (package
+    (inherit emacs-org)
+    (name (string-append
+           (package-name emacs-org) "-integration"))
+    (arguments
+     (substitute-keyword-arguments arguments
+       ((#:emacs inherited-emacs #~'())
+        emacs) ; for libxml
+       ((#:test-command test-command #~'())
+        #~(append
+           #$test-command
+           (list
+            (string-append
+             ;; original value
+             "BTEST_OB_LANGUAGES=awk C fortran maxima lilypond octave perl python java sqlite eshell calc"
+             ;; additional
+             " R clojure julia lua scheme haskell java ruby")
+            "BTEST_EXTRA=ess ess-julia inf-ruby geiser haskell-mode haskell")))))
+    (propagated-inputs
+     (modify-inputs propagated-inputs
+       (prepend (@ (gnu packages statistics) emacs-ess)
+                (@ (gnu packages emacs-xyz) emacs-haskell-mode)
+                (@ (gnu packages emacs-xyz) emacs-inf-ruby)
+                (@ (gnu packages emacs-xyz) emacs-geiser)
+                (@ (gnu packages emacs-xyz) emacs-geiser-guile))))
+    (inputs
+     (modify-inputs inputs
+       (prepend
+        (@ (gnu packages clojure) clojure-tools)
+        (@ (gnu packages commencement) gfortran-toolchain)
+        (@ (gnu packages guile) guile-3.0-latest)
+        (@ (gnu packages haskell) ghc)
+        (@ (gnu packages haskell-apps) git-annex)
+        (@ (gnu packages java) openjdk)
+        (list (@ (gnu packages java) openjdk) "jdk")
+        (@ (gnu packages julia) julia)
+        (@ (gnu packages lua) lua)
+        (@ (gnu packages maths) maxima)
+        (@ (gnu packages maths) octave)
+        (@ (gnu packages perl) perl)
+        (@ (gnu packages python) python-wrapper)
+        (@ (gnu packages ruby) ruby)
+        (@ (gnu packages shells) dash)
+        (@ (gnu packages sqlite) sqlite)
+        (@ (gnu packages statistics) r-minimal))))))
+
+(define* (commit-transformer commit #:optional (revision "0"))
+  (lambda (pkg)
+    (package
+      (inherit pkg)
+      (version (git-version (package-version pkg) revision commit))
+      (source (git-checkout
+                (url %source-dir)
+                (commit commit)))
+      (arguments
+       (substitute-keyword-arguments arguments
+         ((#:phases phases)
+          #~(modify-phases #$phases
+              (replace 'make-autoloads
+                (lambda _
+                  (invoke "make" "-C" ".." "autoloads"
+                          ;; Strip git commit and revision from
+                          ;; version.  Version needs to be something
+                          ;; that Emacs can parse with it's
+                          ;; `version-to-list' function
+                          (string-append "ORGVERSION=" (string-drop-right #$version 10))
+                          (string-append "GITVERSION=" #$commit)))))))))))
+
+(define* (pkg-at-commit pkg commit #:optional (revision "0"))
+  ((commit-transformer commit revision) pkg))
+
+(define (timezone-transformer timezone)
+  (lambda (pkg)
+    (package
+      (inherit pkg)
+      (name (string-append
+             (package-name pkg)
+             "-TZ=" (string-replace-substring timezone "/" "-")))
+      (arguments
+       (substitute-keyword-arguments arguments
+         ((#:phases phases)
+          #~(modify-phases #$phases
+              (add-after 'unpack 'set-timezone
+                (lambda _
+                  (setenv "TZ" #$timezone))))))))))
+
+(define (pkg-with-timezone pkg timezone)
+  ((timezone-transformer timezone) pkg))
+
+(define (lang-transformer lang)
+  (lambda (pkg)
+    (package
+      (inherit pkg)
+      (name (string-append (package-name pkg) "-LANG=" lang))
+      (arguments
+       (substitute-keyword-arguments arguments
+         ;; This keyword is not supported by emacs-build-system even
+         ;; though it would work :/
+         ;; ((#:locale _ #f) lang)
+         ((#:phases phases)
+          #~(modify-phases #$phases
+              (replace 'install-locale
+                (lambda _
+                  ;; install-locale demotes errors into warnings so I
+                  ;; have to promote them to errors again
+                  (let ((error-string
+                         (with-error-to-string
+                           (lambda ()
+                             ((assoc-ref #$phases 'install-locale) #:locale #$lang)))))
+                    (if (string-prefix? "warning:" error-string)
+                        (error error-string)
+                        (format (current-error-port) error-string)))))))))
+      (native-inputs (modify-inputs native-inputs
+                       (prepend glibc-locales))))))
+
+(define (pkg-with-lang pkg lang)
+  ((lang-transformer lang) pkg))
+
+(define (time-transformer time)
+  (lambda (pkg)
+    (package
+      (inherit pkg)
+      (name (string-append (package-name pkg) "-at-time-"
+                           (string-filter-store-item
+                            (string-replace-substring time " " "T"))))
+      (arguments
+       (substitute-keyword-arguments arguments
+         ((#:phases phases)
+          #~(modify-phases #$phases
+              (add-after 'unpack 'use-libfaketime
+                (lambda* (#:key inputs #:allow-other-keys)
+                  (substitute* "../mk/default.mk"
+                    ;; FIXME: This fixes the tests erroring with
+                    ;; "File %s changed on disk" but I really should
+                    ;; figure out a better solution
+                    (("^EMACS\t= emacs")
+                     "EMACS\t= emacs --eval='(setq query-about-changed-file nil)'"))
+                  (setenv "FAKETIME" #$time)
+                  (setenv "FAKETIME_DONT_RESET" "1")
+                  (setenv "LD_PRELOAD"
+                          (search-input-file
+                           inputs
+                           "lib/faketime/libfaketimeMT.so.1"))))))))
+      (native-inputs (modify-inputs native-inputs
+                       (prepend libfaketime))))))
+
+(define (pkg-at-time pkg time)
+  ((time-transformer time) pkg))
+
+(define (emacs-transformer emacs)
+  (lambda (pkg)
+    (let* ((emacs-version (version-major (package-version emacs)))
+           (transformer
+            (package-input-rewriting/spec
+             (map (lambda (pkg)
+                    (cons pkg (const emacs)))
+                  (list
+                   "emacs-next-pgtk"
+                   "emacs"
+                   "emacs-minimal"
+                   "emacs-no-x"
+                   "emacs-no-x-toolkit")))))
+      (package
+        (inherit
+         (transformer
+          ;; Older Emacs's require compat
+          (if (version>? emacs-version "28")
+              pkg
+              (package
+                (inherit pkg)
+                (arguments
+                 (substitute-keyword-arguments arguments
+                   ((#:phases phases)
+                    #~(modify-phases #$phases
+                        (add-after 'unpack 'use-compat
+                          (lambda* (#:key inputs #:allow-other-keys)
+                            (substitute* "../mk/default.mk"
+                              (("^EMACS\t= emacs")
+                               "EMACS\t= emacs -l compat"))))))))
+                (propagated-inputs
+                 (modify-inputs propagated-inputs
+                   (prepend (transformer
+                             (package
+                               (inherit (@ (gnu packages emacs-build) emacs-compat))
+                               (arguments
+                                (substitute-keyword-arguments arguments
+                                  ((#:phases phases)
+                                   #~(modify-phases #$phases
+                                       (delete 'ensure-package-description)
+                                       (add-before 'check 'fix-more-tests
+                                         (lambda _
+                                           (if #$(version>? "27" emacs-version)
+                                               (substitute* "compat-tests.el"
+                                                 (("\\(ert-deftest compat-executable-find .*" all)
+                                                  (string-append all " (skip-unless nil)")))))))))))))))))))
+        (name (string-append "emacs-" emacs-version
+                             (string-drop (package-name pkg) 5)))))))
+
+(define (pkg-with-emacs pkg emacs)
+  ((emacs-transformer emacs) pkg))
+
+(define (outgoing-commit-pkgs)
+  "Build all commits between HEAD and upstream."
+  (let ((outgoing-string
+         (git-output "rev-list" "@{upstream}..")))
+    (if (string-null? outgoing-string)
+        #f
+        (map
+         (lambda (commit)
+           (pkg-at-commit emacs-org commit))
+         (string-split
+          outgoing-string
+          #\newline)))))
+
+(define (get-direct-dependent-packages pkg-name)
+  "Return the list of packages that have a direct dependency named
+PKG-NAME."
+  (fold-packages
+   (lambda (package lst)
+     (if (member
+          pkg-name
+          (map car (package-direct-inputs package)))
+         (cons package lst)
+         lst))
+   (list)))
+
+;; This would be a wonderful way to check if our changes affect
+;; downstream packages.  However, this function returns very few
+;; packages (only 35 as of 2026-07-14) as most are actually built
+;; using the org-mode builtin to emacs.  This is not ideal and
+;; upstream knows that.
+;; See https://codeberg.org/guix/guix/issues/1055
+(define (emacs-org-dependent-packages-with-org org)
+  "Return the list of packages that depend on emacs-org with that
+dependency replaced with ORG."
+  (let ((pkgs (get-direct-dependent-packages "emacs-org"))
+        (transformer
+         (package-input-rewriting/spec
+          (list (cons "emacs-org" (const org))))))
+    (map transformer pkgs)))
+
+(define expensive-builds
+  (cons*
+   ;; There is no upstream package for these emacs so they have
+   ;; to built on the local system
+
+   ;; The builtin emacs-build-system uses `native-comp-available-p'
+   ;; which was introduced in emacs-28 so these fail the build phase
+   ;; (pkg-with-emacs emacs-org emacs-minimal-25)
+   ;; (pkg-with-emacs emacs-org emacs-minimal-26)
+   ;; (pkg-with-emacs emacs-org emacs-minimal-27)
+   (pkg-with-emacs emacs-org emacs-minimal-28)
+   (pkg-with-emacs emacs-org emacs-minimal-29)
+   (pkg-with-emacs emacs-org emacs-minimal-30)
+
+   (emacs-org-dependent-packages-with-org emacs-org)))
+
+(apply
+ append
+ (delq #f
+       (list
+        expensive-builds
+        (outgoing-commit-pkgs)
+        (map
+         (lambda (lang)
+           (pkg-with-lang emacs-org lang))
+         ;; FIXME: also test non utf8 locales
+         '("C.UTF-8"
+           "en_US.UTF-8"
+           "fr_FR.UTF-8"
+           "de_DE.UTF-8"
+           "he_IL.UTF-8"
+           ;; FIXME: These fail 'test-org-clock/clocktable/lang'
+           ;; "zh_CN.UTF-8"
+           ;; "ja_JP.UTF-8"
+           ;; FIXME: Failure when abbreviated day name contains spaces
+           ;; see: https://list.orgmode.org/ch3pr84mb342413ebc2dd0045ec233792c5...@ch3pr84mb3424.namprd84.prod.outlook.com
+           ;; "tok.UTF-8"
+           ))
+        ;; FIXME: all of these fail
+        ;; Test DST transitions in EST
+        ;; (let ((emacs-org-est (pkg-with-timezone emacs-org "America/New_York")))
+        ;;   (list
+        ;;    ;; (spring forward) [2009-03-08 01:59] -> [2009-03-08 03:00]
+        ;;    (pkg-at-time emacs-org-est "@2009-03-08 01:00:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-03-08 01:30:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-03-08 03:00:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-03-08 03:30:00")
+        ;;    ;; fall back [2009-11-01 01:59] -> [2009-11-01 01:00]
+        ;;    (pkg-at-time emacs-org-est "@2009-11-01 01:00:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-11-01 01:30:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-11-01 02:00:00")
+        ;;    (pkg-at-time emacs-org-est "@2009-11-01 02:30:00")))
+
+        (list
+         emacs-org
+
+         ;; FIXME: Hangs for a really long time
+         ;; emacs-org-with-integration-tests
+
+         ;; FIXME: test failures when timezone is not an integer number of hours
+         ;; (pkg-with-timezone emacs-org "Asia/Kathmandu")
+         ;; (pkg-with-timezone emacs-org "Canada/Newfoundland")
+         (pkg-with-timezone emacs-org "Europe/Istanbul")
+         (pkg-with-timezone emacs-org "America/New_York")
+
+         (pkg-with-emacs emacs-org emacs-next-minimal)))))
-- 
2.54.0

Reply via email to