-
-
Notifications
You must be signed in to change notification settings - Fork 168
/
parse.nix
156 lines (145 loc) · 4.65 KB
/
parse.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
{ pkgs, lib }:
let
inherit (import ./repos/fromElisp { inherit pkgs; }) fromElisp fromOrgModeBabelElisp';
isStrEmpty = s: (builtins.replaceStrings [ " " ] [ "" ] s) == "";
splitString = _sep: _s: builtins.filter
(x: builtins.typeOf x == "string")
(builtins.split _sep _s);
# Parse (all) Package-Requires packageElisp headers found in the input string
# `packageElisp` into a list of package name strings.
#
# Example inputs:
#
# ;; Package-Requires: ()
# => [ ]
# ;; Package-Requires: ((dash "2.12.1") (pkg-info "0.4") (let-alist "1.0.4") (seq "1.11") (emacs "24.3"))
# => [ "dash" "pkg-info" "let-alist" "seq" "emacs" ]
# ;; Package-Requires: (dash (pkg-info "0.4"))
# => [ "dash" "pkg-info" ]
# ;; Package-Requires: ((dash) (pkg-info "0.4"))
# => [ "dash" "pkg-info" ]
parsePackagesFromPackageRequires = packageElisp:
let
lines = splitString "\r?\n" packageElisp;
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;
# Get a list of packages declared wanted with `use-package` in the
# input string `config`. The goal is to only list packages that
# would be installed by `use-package` on evaluation; thus we look at
# the `:ensure` and `:disabled` keyword values to attempt to figure
# out which and whether the package should be installed.
#
# Example input:
#
# ''
# (use-package org
# :commands org-mode
# :bind (("C-c a" . org-agenda)
# :map org-mode-map
# ([C-right] . org-demote-subtree)
# ([C-left] . org-promote-subtree)))
#
# (use-package direnv
# :ensure t
# :config (direnv-mode))
#
# (use-package paredit-mode
# :ensure paredit
# :hook (emacs-lisp-mode lisp-mode lisp-interaction-mode))
# ''
# => [ "direnv" "paredit" ]
parsePackagesFromUsePackage = {
configText
, alwaysEnsure ? false
, isOrgModeFile ? false
, alwaysTangle ? false
}:
let
readFunction =
if isOrgModeFile then
fromOrgModeBabelElisp' { ":tangle" = if alwaysTangle then "yes" else "no"; }
else
fromElisp;
find = item: list:
if list == [] then [] else
if builtins.head list == item then
list
else
find item (builtins.tail list);
getKeywordValue = keyword: list:
let
keywordList = find keyword list;
in
if keywordList != [] then
let
keywordValue = builtins.tail keywordList;
in
if keywordValue != [] then
builtins.head keywordValue
else
true
else
null;
isDisabled = item:
let
disabledValue = getKeywordValue ":disabled" item;
in
if disabledValue == [] then
false
else if builtins.isBool disabledValue then
disabledValue
else if builtins.isString disabledValue then
true
else
false;
getName = item:
let
ensureValue = getKeywordValue ":ensure" item;
usePackageName = builtins.head (builtins.tail item);
in
if builtins.isString ensureValue then
if lib.hasPrefix ":" ensureValue then
usePackageName
else
ensureValue
else if ensureValue == true || (ensureValue == null && alwaysEnsure) then
usePackageName
else
[];
recurse = item:
if builtins.isList item && item != [] then
let
packageManager = builtins.head item;
in
if builtins.elem packageManager [ "use-package" "leaf" ] then
if !(isDisabled item) then
[ packageManager (getName item) ] ++ map recurse item
else
[]
else
map recurse item
else
[];
in
lib.flatten (map recurse (readFunction configText));
in
{
inherit parsePackagesFromPackageRequires;
inherit parsePackagesFromUsePackage;
}