mirror of
https://github.com/nix-community/emacs-overlay.git
synced 2025-12-06 02:40:25 -08:00
Add emacsWithPackagesFromPackageRequires
This provides a mechanism for creating an Emacs closure that contains the runtime dependencies for a given Emacs package source file, by inspecting its Package-Requires header.
This commit is contained in:
parent
49597c2218
commit
8439afbe1e
5 changed files with 115 additions and 26 deletions
26
README.org
26
README.org
|
|
@ -28,8 +28,12 @@ We also provide two attributes named =emacsGit-nox= and =emacsUnstable-nox=
|
|||
if you wish to have Emacs built without X dependencies.
|
||||
|
||||
** Extra library functionality
|
||||
This overlay comes with an extra function to generate an Emacs closure from =use-package= declarations.
|
||||
This is an abstraction on top of =emacsWithPackages=.
|
||||
This overlay comes with extra functions to generate an Emacs closure
|
||||
from various types of dependency declaration. (These are abstractions
|
||||
on top of =emacsWithPackages=.)
|
||||
|
||||
For example, =emacsWithPackagesFromUsePackage= adds packages which are required in a user's config via =use-package=:
|
||||
|
||||
#+BEGIN_SRC nix
|
||||
{
|
||||
environment.systemPackages = [
|
||||
|
|
@ -52,6 +56,24 @@ This is an abstraction on top of =emacsWithPackages=.
|
|||
}
|
||||
#+END_SRC
|
||||
|
||||
Similarly, =emacsWithPackagesFromPackageRequires= adds packages which
|
||||
are declared in a =.el= package file's =Package-Requires= header, which
|
||||
can be handy for CI purposes:
|
||||
|
||||
#+BEGIN_SRC nix
|
||||
...
|
||||
let
|
||||
emacsForCI = pkgs.emacsWithPackagesFromPackageRequires {
|
||||
packageFile = builtins.readFile ./flycheck.el;
|
||||
extraEmacsPackages = epkgs: [
|
||||
epkgs.package-lint
|
||||
];
|
||||
};
|
||||
pkgs.mkShell {
|
||||
buildInputs = [ emacsForCI ];
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
|
||||
** Usage of the overlay
|
||||
*** Latest master each rebuild
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ let
|
|||
|
||||
buildInputs = old.buildInputs ++ [ self.libgccjit ];
|
||||
});
|
||||
|
||||
in {
|
||||
inherit emacsGit emacsUnstable;
|
||||
|
||||
|
|
@ -106,6 +105,8 @@ in {
|
|||
|
||||
emacsWithPackagesFromUsePackage = import ./elisp.nix { pkgs = self; };
|
||||
|
||||
emacsWithPackagesFromPackageRequires = import ./packreq.nix { pkgs = self; };
|
||||
|
||||
emacsPackagesFor = emacs: (
|
||||
(super.emacsPackagesFor emacs).overrideScope'(eself: esuper: let
|
||||
|
||||
|
|
|
|||
25
elisp.nix
25
elisp.nix
|
|
@ -6,35 +6,14 @@ use-package declarations.
|
|||
{ pkgs }:
|
||||
|
||||
let
|
||||
isStrEmpty = s: (builtins.replaceStrings [" "] [""] s) == "";
|
||||
|
||||
splitString = _sep: _s: builtins.filter
|
||||
(x: builtins.typeOf x == "string")
|
||||
(builtins.split _sep _s);
|
||||
|
||||
stripComments = dotEmacs: let
|
||||
lines = splitString "\n" dotEmacs;
|
||||
stripped = builtins.map (l:
|
||||
builtins.elemAt (splitString ";;" l) 0) lines;
|
||||
in builtins.concatStringsSep " " stripped;
|
||||
|
||||
parsePackages = dotEmacs: let
|
||||
strippedComments = stripComments dotEmacs;
|
||||
tokens = builtins.filter (t: !(isStrEmpty t)) (builtins.map
|
||||
(t: if builtins.typeOf t == "list" then builtins.elemAt t 0 else t)
|
||||
(builtins.split "([\(\)])" strippedComments));
|
||||
matches = builtins.map (t:
|
||||
builtins.match "^use-package[[:space:]]+([A-Za-z0-9_-]+).*" t) tokens;
|
||||
in builtins.map (m: builtins.elemAt m 0)
|
||||
(builtins.filter (m: m != null) matches);
|
||||
|
||||
parse = pkgs.callPackage ./parse.nix {};
|
||||
in {
|
||||
config,
|
||||
extraEmacsPackages ? epkgs: [],
|
||||
package ? pkgs.emacs,
|
||||
override ? (epkgs: epkgs)
|
||||
}: let
|
||||
packages = parsePackages config;
|
||||
packages = parse.parsePackagesFromUsePackage config;
|
||||
emacsPackages = pkgs.emacsPackagesGen package;
|
||||
emacsWithPackages = emacsPackages.emacsWithPackages;
|
||||
in emacsWithPackages (epkgs: let
|
||||
|
|
|
|||
26
packreq.nix
Normal file
26
packreq.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Parse an emacs package file to derive packages from
|
||||
Package-Requires declarations.
|
||||
*/
|
||||
|
||||
{ pkgs }:
|
||||
let
|
||||
parse = pkgs.callPackage ./parse.nix { };
|
||||
in
|
||||
{ packageFile
|
||||
, extraEmacsPackages ? epkgs: [ ]
|
||||
, package ? pkgs.emacs
|
||||
, override ? (epkgs: epkgs)
|
||||
}:
|
||||
let
|
||||
packages = parse.parsePackagesFromPackageRequires packageFile;
|
||||
emacsPackages = pkgs.emacsPackagesGen package;
|
||||
emacsWithPackages = emacsPackages.emacsWithPackages;
|
||||
in
|
||||
emacsWithPackages (epkgs:
|
||||
let
|
||||
overriden = override epkgs;
|
||||
usePkgs = builtins.map (name: overriden.${name}) packages;
|
||||
extraPkgs = extraEmacsPackages overriden;
|
||||
in
|
||||
[ overriden.use-package ] ++ usePkgs ++ extraPkgs)
|
||||
61
parse.nix
Normal file
61
parse.nix
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{ lib }:
|
||||
let
|
||||
isStrEmpty = s: (builtins.replaceStrings [ " " ] [ "" ] s) == "";
|
||||
|
||||
splitString = _sep: _s: builtins.filter
|
||||
(x: builtins.typeOf x == "string")
|
||||
(builtins.split _sep _s);
|
||||
|
||||
parsePackagesFromPackageRequires = packageFile:
|
||||
let
|
||||
lines = splitString "\r?\n" packageFile;
|
||||
requires =
|
||||
lib.concatMapStrings
|
||||
(line:
|
||||
let match = builtins.match "^;;;* *[pP]ackage-[rR]equires *: *\\((.*)\\)" line;
|
||||
in if match == null then "" else builtins.head match)
|
||||
lines;
|
||||
parseReqList = s:
|
||||
let matchAndRest = builtins.match " *\\(? *([^ \"\\)]+)( +\"[^\"]+\" *\\))?(.*)" s;
|
||||
in
|
||||
if isStrEmpty s then
|
||||
[ ]
|
||||
else
|
||||
if matchAndRest == null then
|
||||
throw "Failed to parse package requirements list: ${s}"
|
||||
else
|
||||
[ (builtins.head matchAndRest) ] ++ (parseReqList (builtins.elemAt matchAndRest 2));
|
||||
in
|
||||
parseReqList requires;
|
||||
|
||||
stripComments = dotEmacs:
|
||||
let
|
||||
lines = splitString "\n" dotEmacs;
|
||||
stripped = builtins.map
|
||||
(l:
|
||||
builtins.elemAt (splitString ";;" l) 0)
|
||||
lines;
|
||||
in
|
||||
builtins.concatStringsSep " " stripped;
|
||||
|
||||
parsePackagesFromUsePackage = dotEmacs:
|
||||
let
|
||||
strippedComments = stripComments dotEmacs;
|
||||
tokens = builtins.filter (t: !(isStrEmpty t)) (builtins.map
|
||||
(t: if builtins.typeOf t == "list" then builtins.elemAt t 0 else t)
|
||||
(builtins.split "([\(\)])" strippedComments)
|
||||
);
|
||||
matches = builtins.map
|
||||
(t:
|
||||
builtins.match "^use-package[[:space:]]+([A-Za-z0-9_-]+).*" t)
|
||||
tokens;
|
||||
in
|
||||
builtins.map
|
||||
(m: builtins.elemAt m 0)
|
||||
(builtins.filter (m: m != null) matches);
|
||||
|
||||
in
|
||||
{
|
||||
inherit parsePackagesFromPackageRequires;
|
||||
inherit parsePackagesFromUsePackage;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue