style: format entire depot with nixpkgs-fmt
This CL can be used to compare the style of nixpkgs-fmt against other formatters (nixpkgs, alejandra). Change-Id: I87c6abff6bcb546b02ead15ad0405f81e01b6d9e Reviewed-on: https://cl.tvl.fyi/c/depot/+/4397 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org> Reviewed-by: lukegb <lukegb@tvl.fyi> Reviewed-by: wpcarro <wpcarro@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: tazjin <tazjin@tvl.su> Reviewed-by: cynthia <cynthia@tvl.fyi> Reviewed-by: edef <edef@edef.eu> Reviewed-by: eta <tvl@eta.st> Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
parent
2d10d60fac
commit
aa122cbae7
310 changed files with 7278 additions and 5490 deletions
|
|
@ -36,4 +36,4 @@ let
|
|||
];
|
||||
};
|
||||
in
|
||||
clhs-lookup
|
||||
clhs-lookup
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ let
|
|||
res = builtins.filter ({ username, ... }: username == user) depot.ops.users;
|
||||
len = builtins.length res;
|
||||
in
|
||||
if len == 1
|
||||
then (builtins.head res).email
|
||||
else builtins.throw "findEmail: got ${toString len} results instead of 1";
|
||||
if len == 1
|
||||
then (builtins.head res).email
|
||||
else builtins.throw "findEmail: got ${toString len} results instead of 1";
|
||||
|
||||
# dot-time(7) man page, ported from dotti.me
|
||||
dot-time = rec {
|
||||
|
|
@ -65,6 +65,6 @@ let
|
|||
};
|
||||
|
||||
in
|
||||
depot.nix.buildManPages "dot-time" {} [
|
||||
dot-time
|
||||
]
|
||||
depot.nix.buildManPages "dot-time" { } [
|
||||
dot-time
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ depot ? import ../../../../.. {}
|
||||
{ depot ? import ../../../../.. { }
|
||||
, pkgs ? depot.third_party.nixpkgs
|
||||
, ...
|
||||
}:
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ let
|
|||
;
|
||||
|
||||
bins = getBins cheddar [ "cheddar" ]
|
||||
// getBins mandoc [ "mandoc" ]
|
||||
// getBins coreutils [ "cat" "mv" "mkdir" ]
|
||||
;
|
||||
// getBins mandoc [ "mandoc" ]
|
||||
// getBins coreutils [ "cat" "mv" "mkdir" ]
|
||||
;
|
||||
|
||||
normalizeDrv = fetchurl {
|
||||
url = "https://necolas.github.io/normalize.css/8.0.1/normalize.css";
|
||||
|
|
@ -29,7 +29,10 @@ let
|
|||
};
|
||||
|
||||
execlineStdoutInto = target: line: [
|
||||
"redirfd" "-w" "1" target
|
||||
"redirfd"
|
||||
"-w"
|
||||
"1"
|
||||
target
|
||||
] ++ line;
|
||||
|
||||
# I will not write a pure nix markdown renderer
|
||||
|
|
@ -39,16 +42,24 @@ let
|
|||
# I will not write a pure nix markdown renderer
|
||||
markdown = md:
|
||||
let
|
||||
html = runExecline.local "rendered-markdown" {
|
||||
stdin = md;
|
||||
} ([
|
||||
"importas" "-iu" "out" "out"
|
||||
] ++ execlineStdoutInto "$out" [
|
||||
bins.cheddar "--about-filter" "description.md"
|
||||
]);
|
||||
in builtins.readFile html;
|
||||
html = runExecline.local "rendered-markdown"
|
||||
{
|
||||
stdin = md;
|
||||
}
|
||||
([
|
||||
"importas"
|
||||
"-iu"
|
||||
"out"
|
||||
"out"
|
||||
] ++ execlineStdoutInto "$out" [
|
||||
bins.cheddar
|
||||
"--about-filter"
|
||||
"description.md"
|
||||
]);
|
||||
in
|
||||
builtins.readFile html;
|
||||
|
||||
indexTemplate = { title, description, pages ? [] }: ''
|
||||
indexTemplate = { title, description, pages ? [ ] }: ''
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
|
|
@ -137,40 +148,40 @@ let
|
|||
|
||||
htmlman =
|
||||
{ title
|
||||
# title of the index page
|
||||
# title of the index page
|
||||
, description ? ""
|
||||
# description which is displayed after
|
||||
# the main heading on the index page
|
||||
, pages ? []
|
||||
# man pages of the following structure:
|
||||
# {
|
||||
# name : string;
|
||||
# section : int;
|
||||
# path : either path string;
|
||||
# }
|
||||
# path is optional, if it is not given,
|
||||
# the man page source must be located at
|
||||
# "${manDir}/${name}.${toString section}"
|
||||
# description which is displayed after
|
||||
# the main heading on the index page
|
||||
, pages ? [ ]
|
||||
# man pages of the following structure:
|
||||
# {
|
||||
# name : string;
|
||||
# section : int;
|
||||
# path : either path string;
|
||||
# }
|
||||
# path is optional, if it is not given,
|
||||
# the man page source must be located at
|
||||
# "${manDir}/${name}.${toString section}"
|
||||
, manDir ? null
|
||||
# directory in which man page sources are located
|
||||
# directory in which man page sources are located
|
||||
, style ? defaultStyle
|
||||
# CSS to use as a string
|
||||
# CSS to use as a string
|
||||
, normalizeCss ? true
|
||||
# whether to include normalize.css before the custom CSS
|
||||
# whether to include normalize.css before the custom CSS
|
||||
, linkXr ? "all"
|
||||
# How to handle cross references in the html output:
|
||||
#
|
||||
# * none: don't convert cross references into hyperlinks
|
||||
# * all: link all cross references as if they were
|
||||
# rendered into $out by htmlman
|
||||
# * inManDir: link to all man pages which have their source
|
||||
# in `manDir` and use the format string defined
|
||||
# in linkXrFallback for all other cross references.
|
||||
# How to handle cross references in the html output:
|
||||
#
|
||||
# * none: don't convert cross references into hyperlinks
|
||||
# * all: link all cross references as if they were
|
||||
# rendered into $out by htmlman
|
||||
# * inManDir: link to all man pages which have their source
|
||||
# in `manDir` and use the format string defined
|
||||
# in linkXrFallback for all other cross references.
|
||||
, linkXrFallback ? "https://manpages.debian.org/unstable/%N.%S.en.html"
|
||||
# fallback link to use if linkXr == "inManDir" and the man
|
||||
# page is not in ${manDir}. Placeholders %N (name of page)
|
||||
# and %S (section of page) can be used. See mandoc(1) for
|
||||
# more information.
|
||||
# fallback link to use if linkXr == "inManDir" and the man
|
||||
# page is not in ${manDir}. Placeholders %N (name of page)
|
||||
# and %S (section of page) can be used. See mandoc(1) for
|
||||
# more information.
|
||||
}:
|
||||
|
||||
let
|
||||
|
|
@ -188,47 +199,70 @@ let
|
|||
mandocOpts = lib.concatStringsSep "," ([
|
||||
"style=style.css"
|
||||
] ++ linkXrEnum.match linkXr {
|
||||
all = [ "man=./%N.%S.html" ];
|
||||
all = [ "man=./%N.%S.html" ];
|
||||
inManDir = [ "man=./%N.%S.html;${linkXrFallback}" ];
|
||||
none = [ ];
|
||||
none = [ ];
|
||||
});
|
||||
|
||||
html =
|
||||
runExecline.local "htmlman-${title}" {
|
||||
derivationArgs = {
|
||||
inherit index style;
|
||||
passAsFile = [ "index" "style" ];
|
||||
};
|
||||
} ([
|
||||
"multisubstitute" [
|
||||
"importas" "-iu" "out" "out"
|
||||
"importas" "-iu" "index" "indexPath"
|
||||
"importas" "-iu" "style" "stylePath"
|
||||
]
|
||||
"if" [ bins.mkdir "-p" "$out" ]
|
||||
"if" [ bins.mv "$index" "\${out}/index.html" ]
|
||||
"if" (execlineStdoutInto "\${out}/style.css" [
|
||||
"if" ([
|
||||
bins.cat
|
||||
] ++ lib.optional normalizeCss normalizeDrv
|
||||
runExecline.local "htmlman-${title}"
|
||||
{
|
||||
derivationArgs = {
|
||||
inherit index style;
|
||||
passAsFile = [ "index" "style" ];
|
||||
};
|
||||
}
|
||||
([
|
||||
"multisubstitute"
|
||||
[
|
||||
"importas"
|
||||
"-iu"
|
||||
"out"
|
||||
"out"
|
||||
"importas"
|
||||
"-iu"
|
||||
"index"
|
||||
"indexPath"
|
||||
"importas"
|
||||
"-iu"
|
||||
"style"
|
||||
"stylePath"
|
||||
]
|
||||
"if"
|
||||
[ bins.mkdir "-p" "$out" ]
|
||||
"if"
|
||||
[ bins.mv "$index" "\${out}/index.html" ]
|
||||
"if"
|
||||
(execlineStdoutInto "\${out}/style.css" [
|
||||
"if"
|
||||
([
|
||||
bins.cat
|
||||
] ++ lib.optional normalizeCss normalizeDrv
|
||||
++ [
|
||||
"$style"
|
||||
"$style"
|
||||
])
|
||||
])
|
||||
])
|
||||
# let mandoc check for available man pages
|
||||
"execline-cd" "${manDir}"
|
||||
] ++ lib.concatMap ({ name, section, ... }@p:
|
||||
execlineStdoutInto "\${out}/${name}.${toString section}.html" [
|
||||
"if" [
|
||||
bins.mandoc
|
||||
"-mdoc"
|
||||
"-T" "html"
|
||||
"-O" mandocOpts
|
||||
(resolvePath p)
|
||||
]
|
||||
]) pages);
|
||||
in html // {
|
||||
# let mandoc check for available man pages
|
||||
"execline-cd"
|
||||
"${manDir}"
|
||||
] ++ lib.concatMap
|
||||
({ name, section, ... }@p:
|
||||
execlineStdoutInto "\${out}/${name}.${toString section}.html" [
|
||||
"if"
|
||||
[
|
||||
bins.mandoc
|
||||
"-mdoc"
|
||||
"-T"
|
||||
"html"
|
||||
"-O"
|
||||
mandocOpts
|
||||
(resolvePath p)
|
||||
]
|
||||
])
|
||||
pages);
|
||||
in
|
||||
html // {
|
||||
deploy = deployScript title html;
|
||||
};
|
||||
in
|
||||
htmlman
|
||||
htmlman
|
||||
|
|
|
|||
|
|
@ -53,17 +53,20 @@ let
|
|||
asciiAlpha = c:
|
||||
let
|
||||
v = ord c;
|
||||
in (v >= 65 && v <= 90)
|
||||
in
|
||||
(v >= 65 && v <= 90)
|
||||
|| (v >= 97 && v <= 122);
|
||||
|
||||
asciiNum = c:
|
||||
let
|
||||
v = ord c;
|
||||
in v >= 48 && v <= 57;
|
||||
in
|
||||
v >= 48 && v <= 57;
|
||||
|
||||
asciiAlphaNum = c: asciiAlpha c || asciiNum c;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
allChars
|
||||
char
|
||||
|
|
@ -78,18 +81,19 @@ in {
|
|||
# originally I generated a nix file containing a list of
|
||||
# characters, but infinisil uses a better way which I adapt
|
||||
# which is using builtins.readFile instead of import.
|
||||
__generateAllChars = pkgs.runCommandCC "generate-all-chars" {
|
||||
source = ''
|
||||
#include <stdio.h>
|
||||
__generateAllChars = pkgs.runCommandCC "generate-all-chars"
|
||||
{
|
||||
source = ''
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
for(int i = 1; i <= 0xff; i++) {
|
||||
putchar(i);
|
||||
int main(void) {
|
||||
for(int i = 1; i <= 0xff; i++) {
|
||||
putchar(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
passAsFile = [ "source" ];
|
||||
} ''
|
||||
'';
|
||||
passAsFile = [ "source" ];
|
||||
} ''
|
||||
$CC -o "$out" -x c "$sourcePath"
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,6 @@ let
|
|||
];
|
||||
|
||||
in
|
||||
runTestsuite "char" [
|
||||
testAllCharConversion
|
||||
]
|
||||
runTestsuite "char" [
|
||||
testAllCharConversion
|
||||
]
|
||||
|
|
|
|||
|
|
@ -68,13 +68,14 @@ let
|
|||
then s x
|
||||
else x == s;
|
||||
in
|
||||
if b
|
||||
then builtins.elemAt c 1
|
||||
else switch x (builtins.tail conds);
|
||||
if b
|
||||
then builtins.elemAt c 1
|
||||
else switch x (builtins.tail conds);
|
||||
|
||||
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
cond
|
||||
switch
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ let
|
|||
(cond [ [ true 1 2 ] [ false 1 ] ]))
|
||||
(assertEq "last is true" "last"
|
||||
(cond [
|
||||
[ false dontEval]
|
||||
[ false dontEval ]
|
||||
[ false dontEval ]
|
||||
[ true "last" ]
|
||||
]))
|
||||
|
|
@ -34,6 +34,6 @@ let
|
|||
];
|
||||
|
||||
in
|
||||
runTestsuite "nix.flow" [
|
||||
testCond
|
||||
]
|
||||
runTestsuite "nix.flow" [
|
||||
testCond
|
||||
]
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@ let
|
|||
(fun.hasEllipsis ({ depot, pkgs, ... }: 42)))
|
||||
];
|
||||
in
|
||||
runTestsuite "nix.fun" [
|
||||
hasEllipsisTests
|
||||
]
|
||||
runTestsuite "nix.fun" [
|
||||
hasEllipsisTests
|
||||
]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ let
|
|||
=> "<hello>"
|
||||
*/
|
||||
escapeMinimal = builtins.replaceStrings
|
||||
[ "<" ">" "&" "\"" "'" ]
|
||||
[ "<" ">" "&" "\"" "'" ]
|
||||
[ "<" ">" "&" """ "'" ];
|
||||
|
||||
/* Return a string with a correctly rendered tag of the given name,
|
||||
|
|
@ -87,18 +87,20 @@ let
|
|||
renderTag = tag: attrs: content:
|
||||
let
|
||||
attrs' = builtins.concatStringsSep "" (
|
||||
builtins.map (n:
|
||||
" ${escapeMinimal n}=\"${escapeMinimal (toString attrs.${n})}\""
|
||||
) (builtins.attrNames attrs)
|
||||
builtins.map
|
||||
(n:
|
||||
" ${escapeMinimal n}=\"${escapeMinimal (toString attrs.${n})}\""
|
||||
)
|
||||
(builtins.attrNames attrs)
|
||||
);
|
||||
content' =
|
||||
if builtins.isList content
|
||||
then builtins.concatStringsSep "" content
|
||||
else content;
|
||||
in
|
||||
if content == null
|
||||
then "<${tag}${attrs'}/>"
|
||||
else "<${tag}${attrs'}>${content'}</${tag}>";
|
||||
if content == null
|
||||
then "<${tag}${attrs'}/>"
|
||||
else "<${tag}${attrs'}>${content'}</${tag}>";
|
||||
|
||||
/* Prepend "<!DOCTYPE html>" to a string.
|
||||
|
||||
|
|
@ -111,7 +113,8 @@ let
|
|||
*/
|
||||
withDoctype = doc: "<!DOCTYPE html>" + doc;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit escapeMinimal renderTag withDoctype;
|
||||
|
||||
__findFile = _: renderTag;
|
||||
|
|
|
|||
|
|
@ -8,15 +8,17 @@ let
|
|||
;
|
||||
|
||||
exampleDocument = withDoctype (<html> { lang = "en"; } [
|
||||
(<head> {} [
|
||||
(<head> { } [
|
||||
(<meta> { charset = "utf-8"; } null)
|
||||
(<title> {} "html.nix example document")
|
||||
(<link> {
|
||||
rel = "license";
|
||||
href = "https://code.tvl.fyi/about/LICENSE";
|
||||
type = "text/html";
|
||||
} null)
|
||||
(<style> {} (esc ''
|
||||
(<title> { } "html.nix example document")
|
||||
(<link>
|
||||
{
|
||||
rel = "license";
|
||||
href = "https://code.tvl.fyi/about/LICENSE";
|
||||
type = "text/html";
|
||||
}
|
||||
null)
|
||||
(<style> { } (esc ''
|
||||
hgroup h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
|
@ -26,39 +28,45 @@ let
|
|||
}
|
||||
''))
|
||||
])
|
||||
(<body> {} [
|
||||
(<main> {} [
|
||||
(<hgroup> {} [
|
||||
(<h1> {} (esc "html.nix"))
|
||||
(<h2> {} [
|
||||
(<em> {} "the")
|
||||
(<body> { } [
|
||||
(<main> { } [
|
||||
(<hgroup> { } [
|
||||
(<h1> { } (esc "html.nix"))
|
||||
(<h2> { } [
|
||||
(<em> { } "the")
|
||||
(esc " most cursed HTML DSL ever!")
|
||||
])
|
||||
])
|
||||
(<dl> {} [
|
||||
(<dt> {} [
|
||||
(<dl> { } [
|
||||
(<dt> { } [
|
||||
(esc "Q: Wait, it's all ")
|
||||
(<a> {
|
||||
href = "https://cl.tvl.fyi/q/hashtag:cursed";
|
||||
} (esc "cursed"))
|
||||
(<a>
|
||||
{
|
||||
href = "https://cl.tvl.fyi/q/hashtag:cursed";
|
||||
}
|
||||
(esc "cursed"))
|
||||
(esc " nix hacks?")
|
||||
])
|
||||
(<dd> {} (esc "A: Always has been. 🔫"))
|
||||
(<dt> {} (esc "Q: Why does this work?"))
|
||||
(<dd> {} [
|
||||
(<dd> { } (esc "A: Always has been. 🔫"))
|
||||
(<dt> { } (esc "Q: Why does this work?"))
|
||||
(<dd> { } [
|
||||
(esc "Because nix ")
|
||||
(<a> {
|
||||
href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/parser.y#L410-L416";
|
||||
} (esc "translates "))
|
||||
(<a> {
|
||||
href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/lexer.l#L100";
|
||||
} (esc "SPATH tokens"))
|
||||
(<a>
|
||||
{
|
||||
href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/parser.y#L410-L416";
|
||||
}
|
||||
(esc "translates "))
|
||||
(<a>
|
||||
{
|
||||
href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/lexer.l#L100";
|
||||
}
|
||||
(esc "SPATH tokens"))
|
||||
(esc " like ")
|
||||
(<code> {} (esc "<nixpkgs>"))
|
||||
(<code> { } (esc "<nixpkgs>"))
|
||||
(esc " into calls to ")
|
||||
(<code> {} (esc "__findFile"))
|
||||
(<code> { } (esc "__findFile"))
|
||||
(esc " in the ")
|
||||
(<em> {} (esc "current"))
|
||||
(<em> { } (esc "current"))
|
||||
(esc " scope.")
|
||||
])
|
||||
])
|
||||
|
|
@ -67,7 +75,8 @@ let
|
|||
]);
|
||||
in
|
||||
|
||||
pkgs.runCommandNoCC "html.nix.html" {
|
||||
pkgs.runCommandNoCC "html.nix.html"
|
||||
{
|
||||
passAsFile = [ "exampleDocument" ];
|
||||
inherit exampleDocument;
|
||||
nativeBuildInputs = [ pkgs.html5validator ];
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ let
|
|||
if i == 0
|
||||
then ""
|
||||
else go (bitShiftR i 4)
|
||||
+ string.charAt (bitAnd i 15) hexdigits;
|
||||
+ string.charAt (bitAnd i 15) hexdigits;
|
||||
sign = lib.optionalString (int < 0) "-";
|
||||
in
|
||||
if int == 0
|
||||
then "0"
|
||||
else "${sign}${go (abs int)}";
|
||||
if int == 0
|
||||
then "0"
|
||||
else "${sign}${go (abs int)}";
|
||||
|
||||
fromHexMap = builtins.listToAttrs
|
||||
(lib.imap0 (i: c: { name = c; value = i; })
|
||||
|
|
@ -72,11 +72,12 @@ let
|
|||
val = v.val + (fromHexMap."${d}" * v.mul);
|
||||
mul = v.mul * 16;
|
||||
})
|
||||
{ val = 0; mul = 1; } digits;
|
||||
{ val = 0; mul = 1; }
|
||||
digits;
|
||||
in
|
||||
if negative
|
||||
then -parsed.val
|
||||
else parsed.val;
|
||||
if negative
|
||||
then -parsed.val
|
||||
else parsed.val;
|
||||
|
||||
# A nix integer is a 64bit signed integer
|
||||
maxBound = 9223372036854775807;
|
||||
|
|
@ -99,7 +100,8 @@ let
|
|||
|
||||
inRange = a: b: x: x >= a && x <= b;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
maxBound
|
||||
minBound
|
||||
|
|
|
|||
|
|
@ -31,22 +31,262 @@ let
|
|||
];
|
||||
|
||||
expectedBytes = [
|
||||
"00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B" "0C" "0D" "0E" "0F"
|
||||
"10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "1A" "1B" "1C" "1D" "1E" "1F"
|
||||
"20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "2A" "2B" "2C" "2D" "2E" "2F"
|
||||
"30" "31" "32" "33" "34" "35" "36" "37" "38" "39" "3A" "3B" "3C" "3D" "3E" "3F"
|
||||
"40" "41" "42" "43" "44" "45" "46" "47" "48" "49" "4A" "4B" "4C" "4D" "4E" "4F"
|
||||
"50" "51" "52" "53" "54" "55" "56" "57" "58" "59" "5A" "5B" "5C" "5D" "5E" "5F"
|
||||
"60" "61" "62" "63" "64" "65" "66" "67" "68" "69" "6A" "6B" "6C" "6D" "6E" "6F"
|
||||
"70" "71" "72" "73" "74" "75" "76" "77" "78" "79" "7A" "7B" "7C" "7D" "7E" "7F"
|
||||
"80" "81" "82" "83" "84" "85" "86" "87" "88" "89" "8A" "8B" "8C" "8D" "8E" "8F"
|
||||
"90" "91" "92" "93" "94" "95" "96" "97" "98" "99" "9A" "9B" "9C" "9D" "9E" "9F"
|
||||
"A0" "A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" "A9" "AA" "AB" "AC" "AD" "AE" "AF"
|
||||
"B0" "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" "B9" "BA" "BB" "BC" "BD" "BE" "BF"
|
||||
"C0" "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" "C9" "CA" "CB" "CC" "CD" "CE" "CF"
|
||||
"D0" "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" "D9" "DA" "DB" "DC" "DD" "DE" "DF"
|
||||
"E0" "E1" "E2" "E3" "E4" "E5" "E6" "E7" "E8" "E9" "EA" "EB" "EC" "ED" "EE" "EF"
|
||||
"F0" "F1" "F2" "F3" "F4" "F5" "F6" "F7" "F8" "F9" "FA" "FB" "FC" "FD" "FE" "FF"
|
||||
"00"
|
||||
"01"
|
||||
"02"
|
||||
"03"
|
||||
"04"
|
||||
"05"
|
||||
"06"
|
||||
"07"
|
||||
"08"
|
||||
"09"
|
||||
"0A"
|
||||
"0B"
|
||||
"0C"
|
||||
"0D"
|
||||
"0E"
|
||||
"0F"
|
||||
"10"
|
||||
"11"
|
||||
"12"
|
||||
"13"
|
||||
"14"
|
||||
"15"
|
||||
"16"
|
||||
"17"
|
||||
"18"
|
||||
"19"
|
||||
"1A"
|
||||
"1B"
|
||||
"1C"
|
||||
"1D"
|
||||
"1E"
|
||||
"1F"
|
||||
"20"
|
||||
"21"
|
||||
"22"
|
||||
"23"
|
||||
"24"
|
||||
"25"
|
||||
"26"
|
||||
"27"
|
||||
"28"
|
||||
"29"
|
||||
"2A"
|
||||
"2B"
|
||||
"2C"
|
||||
"2D"
|
||||
"2E"
|
||||
"2F"
|
||||
"30"
|
||||
"31"
|
||||
"32"
|
||||
"33"
|
||||
"34"
|
||||
"35"
|
||||
"36"
|
||||
"37"
|
||||
"38"
|
||||
"39"
|
||||
"3A"
|
||||
"3B"
|
||||
"3C"
|
||||
"3D"
|
||||
"3E"
|
||||
"3F"
|
||||
"40"
|
||||
"41"
|
||||
"42"
|
||||
"43"
|
||||
"44"
|
||||
"45"
|
||||
"46"
|
||||
"47"
|
||||
"48"
|
||||
"49"
|
||||
"4A"
|
||||
"4B"
|
||||
"4C"
|
||||
"4D"
|
||||
"4E"
|
||||
"4F"
|
||||
"50"
|
||||
"51"
|
||||
"52"
|
||||
"53"
|
||||
"54"
|
||||
"55"
|
||||
"56"
|
||||
"57"
|
||||
"58"
|
||||
"59"
|
||||
"5A"
|
||||
"5B"
|
||||
"5C"
|
||||
"5D"
|
||||
"5E"
|
||||
"5F"
|
||||
"60"
|
||||
"61"
|
||||
"62"
|
||||
"63"
|
||||
"64"
|
||||
"65"
|
||||
"66"
|
||||
"67"
|
||||
"68"
|
||||
"69"
|
||||
"6A"
|
||||
"6B"
|
||||
"6C"
|
||||
"6D"
|
||||
"6E"
|
||||
"6F"
|
||||
"70"
|
||||
"71"
|
||||
"72"
|
||||
"73"
|
||||
"74"
|
||||
"75"
|
||||
"76"
|
||||
"77"
|
||||
"78"
|
||||
"79"
|
||||
"7A"
|
||||
"7B"
|
||||
"7C"
|
||||
"7D"
|
||||
"7E"
|
||||
"7F"
|
||||
"80"
|
||||
"81"
|
||||
"82"
|
||||
"83"
|
||||
"84"
|
||||
"85"
|
||||
"86"
|
||||
"87"
|
||||
"88"
|
||||
"89"
|
||||
"8A"
|
||||
"8B"
|
||||
"8C"
|
||||
"8D"
|
||||
"8E"
|
||||
"8F"
|
||||
"90"
|
||||
"91"
|
||||
"92"
|
||||
"93"
|
||||
"94"
|
||||
"95"
|
||||
"96"
|
||||
"97"
|
||||
"98"
|
||||
"99"
|
||||
"9A"
|
||||
"9B"
|
||||
"9C"
|
||||
"9D"
|
||||
"9E"
|
||||
"9F"
|
||||
"A0"
|
||||
"A1"
|
||||
"A2"
|
||||
"A3"
|
||||
"A4"
|
||||
"A5"
|
||||
"A6"
|
||||
"A7"
|
||||
"A8"
|
||||
"A9"
|
||||
"AA"
|
||||
"AB"
|
||||
"AC"
|
||||
"AD"
|
||||
"AE"
|
||||
"AF"
|
||||
"B0"
|
||||
"B1"
|
||||
"B2"
|
||||
"B3"
|
||||
"B4"
|
||||
"B5"
|
||||
"B6"
|
||||
"B7"
|
||||
"B8"
|
||||
"B9"
|
||||
"BA"
|
||||
"BB"
|
||||
"BC"
|
||||
"BD"
|
||||
"BE"
|
||||
"BF"
|
||||
"C0"
|
||||
"C1"
|
||||
"C2"
|
||||
"C3"
|
||||
"C4"
|
||||
"C5"
|
||||
"C6"
|
||||
"C7"
|
||||
"C8"
|
||||
"C9"
|
||||
"CA"
|
||||
"CB"
|
||||
"CC"
|
||||
"CD"
|
||||
"CE"
|
||||
"CF"
|
||||
"D0"
|
||||
"D1"
|
||||
"D2"
|
||||
"D3"
|
||||
"D4"
|
||||
"D5"
|
||||
"D6"
|
||||
"D7"
|
||||
"D8"
|
||||
"D9"
|
||||
"DA"
|
||||
"DB"
|
||||
"DC"
|
||||
"DD"
|
||||
"DE"
|
||||
"DF"
|
||||
"E0"
|
||||
"E1"
|
||||
"E2"
|
||||
"E3"
|
||||
"E4"
|
||||
"E5"
|
||||
"E6"
|
||||
"E7"
|
||||
"E8"
|
||||
"E9"
|
||||
"EA"
|
||||
"EB"
|
||||
"EC"
|
||||
"ED"
|
||||
"EE"
|
||||
"EF"
|
||||
"F0"
|
||||
"F1"
|
||||
"F2"
|
||||
"F3"
|
||||
"F4"
|
||||
"F5"
|
||||
"F6"
|
||||
"F7"
|
||||
"F8"
|
||||
"F9"
|
||||
"FA"
|
||||
"FB"
|
||||
"FC"
|
||||
"FD"
|
||||
"FE"
|
||||
"FF"
|
||||
];
|
||||
|
||||
hexByte = i: string.fit { width = 2; char = "0"; } (int.toHex i);
|
||||
|
|
@ -64,14 +304,18 @@ let
|
|||
];
|
||||
|
||||
testHex = it "checks conversion to hex" (lib.flatten [
|
||||
(lib.imap0 (i: hex: [
|
||||
(assertEq "hexByte ${toString i} == ${hex}" (hexByte i) hex)
|
||||
(assertEq "${toString i} == fromHex ${hex}" i (int.fromHex hex))
|
||||
]) expectedBytes)
|
||||
(builtins.map ({ left, right }: [
|
||||
(assertEq "toHex ${toString left} == ${right}" (int.toHex left) right)
|
||||
(assertEq "${toString left} == fromHex ${right}" left (int.fromHex right))
|
||||
]) hexInts)
|
||||
(lib.imap0
|
||||
(i: hex: [
|
||||
(assertEq "hexByte ${toString i} == ${hex}" (hexByte i) hex)
|
||||
(assertEq "${toString i} == fromHex ${hex}" i (int.fromHex hex))
|
||||
])
|
||||
expectedBytes)
|
||||
(builtins.map
|
||||
({ left, right }: [
|
||||
(assertEq "toHex ${toString left} == ${right}" (int.toHex left) right)
|
||||
(assertEq "${toString left} == fromHex ${right}" left (int.fromHex right))
|
||||
])
|
||||
hexInts)
|
||||
]);
|
||||
|
||||
testBasic = it "checks basic int operations" [
|
||||
|
|
@ -94,20 +338,23 @@ let
|
|||
];
|
||||
|
||||
testExp = it "checks exponentiation"
|
||||
(builtins.map ({ left, right }:
|
||||
assertEq
|
||||
"2 ^ ${toString left} == ${toString right}"
|
||||
(int.exp 2 left) right) expNumbers);
|
||||
(builtins.map
|
||||
({ left, right }:
|
||||
assertEq
|
||||
"2 ^ ${toString left} == ${toString right}"
|
||||
(int.exp 2 left)
|
||||
right)
|
||||
expNumbers);
|
||||
|
||||
shifts = [
|
||||
{ a = 2; b = 5; c = 64; op = "<<"; }
|
||||
{ a = -2; b = 5; c = -64; op = "<<"; }
|
||||
{ a = 2; b = 5; c = 64; op = "<<"; }
|
||||
{ a = -2; b = 5; c = -64; op = "<<"; }
|
||||
{ a = 123; b = 4; c = 1968; op = "<<"; }
|
||||
{ a = 1; b = 8; c = 256; op = "<<"; }
|
||||
{ a = 256; b = 8; c = 1; op = ">>"; }
|
||||
{ a = 374; b = 2; c = 93; op = ">>"; }
|
||||
{ a = 2; b = 2; c = 0; op = ">>"; }
|
||||
{ a = 99; b = 9; c = 0; op = ">>"; }
|
||||
{ a = 1; b = 8; c = 256; op = "<<"; }
|
||||
{ a = 256; b = 8; c = 1; op = ">>"; }
|
||||
{ a = 374; b = 2; c = 93; op = ">>"; }
|
||||
{ a = 2; b = 2; c = 0; op = ">>"; }
|
||||
{ a = 99; b = 9; c = 0; op = ">>"; }
|
||||
];
|
||||
|
||||
checkShift = { a, b, c, op }@args:
|
||||
|
|
@ -116,15 +363,18 @@ let
|
|||
"<<" = int.bitShiftL;
|
||||
">>" = int.bitShiftR;
|
||||
};
|
||||
in assertEq "${toString a} ${op} ${toString b} == ${toString c}" (f a b) c;
|
||||
in
|
||||
assertEq "${toString a} ${op} ${toString b} == ${toString c}" (f a b) c;
|
||||
|
||||
checkShiftRDivExp = n:
|
||||
assertEq "${toString n} >> 5 == ${toString n} / 2 ^ 5"
|
||||
(int.bitShiftR n 5) (int.div n (int.exp 2 5));
|
||||
(int.bitShiftR n 5)
|
||||
(int.div n (int.exp 2 5));
|
||||
|
||||
checkShiftLMulExp = n:
|
||||
assertEq "${toString n} >> 6 == ${toString n} * 2 ^ 6"
|
||||
(int.bitShiftL n 5) (int.mul n (int.exp 2 5));
|
||||
(int.bitShiftL n 5)
|
||||
(int.mul n (int.exp 2 5));
|
||||
|
||||
testBit = it "checks bitwise operations" (lib.flatten [
|
||||
(builtins.map checkShift shifts)
|
||||
|
|
@ -160,11 +410,11 @@ let
|
|||
]);
|
||||
|
||||
divisions = [
|
||||
{ a = 2; b = 1; c = 2; mod = 0;}
|
||||
{ a = 2; b = 2; c = 1; mod = 0;}
|
||||
{ a = 20; b = 10; c = 2; mod = 0;}
|
||||
{ a = 12; b = 5; c = 2; mod = 2;}
|
||||
{ a = 23; b = 4; c = 5; mod = 3;}
|
||||
{ a = 2; b = 1; c = 2; mod = 0; }
|
||||
{ a = 2; b = 2; c = 1; mod = 0; }
|
||||
{ a = 20; b = 10; c = 2; mod = 0; }
|
||||
{ a = 12; b = 5; c = 2; mod = 2; }
|
||||
{ a = 23; b = 4; c = 5; mod = 3; }
|
||||
];
|
||||
|
||||
checkDiv = n: { a, b, c, mod }: [
|
||||
|
|
@ -176,28 +426,34 @@ let
|
|||
testDivMod = it "checks integer division and modulo"
|
||||
(lib.flatten [
|
||||
(builtins.map (checkDiv "+a / +b") divisions)
|
||||
(builtins.map (fun.rl (checkDiv "-a / +b") (x: x // {
|
||||
a = -x.a;
|
||||
c = -x.c;
|
||||
mod = -x.mod;
|
||||
})) divisions)
|
||||
(builtins.map (fun.rl (checkDiv "+a / -b") (x: x // {
|
||||
b = -x.b;
|
||||
c = -x.c;
|
||||
})) divisions)
|
||||
(builtins.map (fun.rl (checkDiv "-a / -b") (x: x // {
|
||||
a = -x.a;
|
||||
b = -x.b;
|
||||
mod = -x.mod;
|
||||
})) divisions)
|
||||
(builtins.map
|
||||
(fun.rl (checkDiv "-a / +b") (x: x // {
|
||||
a = -x.a;
|
||||
c = -x.c;
|
||||
mod = -x.mod;
|
||||
}))
|
||||
divisions)
|
||||
(builtins.map
|
||||
(fun.rl (checkDiv "+a / -b") (x: x // {
|
||||
b = -x.b;
|
||||
c = -x.c;
|
||||
}))
|
||||
divisions)
|
||||
(builtins.map
|
||||
(fun.rl (checkDiv "-a / -b") (x: x // {
|
||||
a = -x.a;
|
||||
b = -x.b;
|
||||
mod = -x.mod;
|
||||
}))
|
||||
divisions)
|
||||
]);
|
||||
|
||||
in
|
||||
runTestsuite "nix.int" [
|
||||
testBounds
|
||||
testHex
|
||||
testBasic
|
||||
testExp
|
||||
testBit
|
||||
testDivMod
|
||||
]
|
||||
runTestsuite "nix.int" [
|
||||
testBounds
|
||||
testHex
|
||||
testBasic
|
||||
testExp
|
||||
testBit
|
||||
testDivMod
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ let
|
|||
charAt = i: s:
|
||||
let
|
||||
r = builtins.substring i 1 s;
|
||||
in if r == "" then null else r;
|
||||
in
|
||||
if r == "" then null else r;
|
||||
|
||||
charIndex = char: s:
|
||||
let
|
||||
|
|
@ -32,7 +33,8 @@ let
|
|||
[ (charAt i s == char) i ]
|
||||
[ true (go (i + 1)) ]
|
||||
];
|
||||
in go 0;
|
||||
in
|
||||
go 0;
|
||||
|
||||
toChars = lib.stringToCharacters;
|
||||
fromChars = lib.concatStrings;
|
||||
|
|
@ -46,15 +48,16 @@ let
|
|||
let
|
||||
leftS = fromChars (builtins.genList (_: char) left);
|
||||
rightS = fromChars (builtins.genList (_: char) right);
|
||||
in "${leftS}${s}${rightS}";
|
||||
in
|
||||
"${leftS}${s}${rightS}";
|
||||
|
||||
fit = { char ? " ", width, side ? "left" }: s:
|
||||
let
|
||||
diff = width - builtins.stringLength s;
|
||||
in
|
||||
if diff <= 0
|
||||
then s
|
||||
else pad { inherit char; "${side}" = diff; } s;
|
||||
if diff <= 0
|
||||
then s
|
||||
else pad { inherit char; "${side}" = diff; } s;
|
||||
|
||||
# pattern matching for strings only
|
||||
match = val: matcher: matcher."${val}";
|
||||
|
|
@ -80,23 +83,28 @@ let
|
|||
tokens = lib.flatten (builtins.split "(%.)" formatString);
|
||||
argsNeeded = builtins.length (builtins.filter specifierWithArg tokens);
|
||||
|
||||
format = args: (builtins.foldl' ({ out ? "", argIndex ? 0 }: token: {
|
||||
argIndex = argIndex + (if specifierWithArg token then 1 else 0);
|
||||
out =
|
||||
/**/ if token == "%s" then out + builtins.elemAt args argIndex
|
||||
else if token == "%%" then out + "%"
|
||||
else if isSpecifier token then throw "Unsupported format specifier ${token}"
|
||||
else out + token;
|
||||
}) {} tokens).out;
|
||||
format = args: (builtins.foldl'
|
||||
({ out ? "", argIndex ? 0 }: token: {
|
||||
argIndex = argIndex + (if specifierWithArg token then 1 else 0);
|
||||
out =
|
||||
/**/
|
||||
if token == "%s" then out + builtins.elemAt args argIndex
|
||||
else if token == "%%" then out + "%"
|
||||
else if isSpecifier token then throw "Unsupported format specifier ${token}"
|
||||
else out + token;
|
||||
})
|
||||
{ }
|
||||
tokens).out;
|
||||
|
||||
accumulateArgs = argCount: args:
|
||||
if argCount > 0
|
||||
then arg: accumulateArgs (argCount - 1) (args ++ [ arg ])
|
||||
else format args;
|
||||
in
|
||||
accumulateArgs argsNeeded [];
|
||||
accumulateArgs argsNeeded [ ];
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
take
|
||||
drop
|
||||
|
|
|
|||
|
|
@ -63,10 +63,10 @@ let
|
|||
];
|
||||
|
||||
in
|
||||
runTestsuite "nix.string" [
|
||||
testTakeDrop
|
||||
testIndexing
|
||||
testFinding
|
||||
testMatch
|
||||
testPrintf
|
||||
]
|
||||
runTestsuite "nix.string" [
|
||||
testTakeDrop
|
||||
testIndexing
|
||||
testFinding
|
||||
testMatch
|
||||
testPrintf
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,9 +10,24 @@ let
|
|||
;
|
||||
|
||||
reserved = c: builtins.elem c [
|
||||
"!" "#" "$" "&" "'" "(" ")"
|
||||
"*" "+" "," "/" ":" ";" "="
|
||||
"?" "@" "[" "]"
|
||||
"!"
|
||||
"#"
|
||||
"$"
|
||||
"&"
|
||||
"'"
|
||||
"("
|
||||
")"
|
||||
"*"
|
||||
"+"
|
||||
","
|
||||
"/"
|
||||
":"
|
||||
";"
|
||||
"="
|
||||
"?"
|
||||
"@"
|
||||
"["
|
||||
"]"
|
||||
];
|
||||
|
||||
unreserved = c: char.asciiAlphaNum c
|
||||
|
|
@ -21,11 +36,13 @@ let
|
|||
percentEncode = c:
|
||||
if unreserved c
|
||||
then c
|
||||
else "%" + (string.fit {
|
||||
width = 2;
|
||||
char = "0";
|
||||
side = "left";
|
||||
} (int.toHex (char.ord c)));
|
||||
else "%" + (string.fit
|
||||
{
|
||||
width = 2;
|
||||
char = "0";
|
||||
side = "left";
|
||||
}
|
||||
(int.toHex (char.ord c)));
|
||||
|
||||
encode = { leaveReserved ? false }: s:
|
||||
let
|
||||
|
|
@ -34,7 +51,8 @@ let
|
|||
if leaveReserved && reserved c
|
||||
then c
|
||||
else percentEncode c;
|
||||
in lib.concatStrings (builtins.map tr chars);
|
||||
in
|
||||
lib.concatStrings (builtins.map tr chars);
|
||||
|
||||
decode = s:
|
||||
let
|
||||
|
|
@ -71,9 +89,10 @@ let
|
|||
];
|
||||
|
||||
in
|
||||
(builtins.foldl' decodeStep {} tokens).result;
|
||||
(builtins.foldl' decodeStep { } tokens).result;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
encode
|
||||
decode
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ let
|
|||
|
||||
checkEncoding = args: { left, right }:
|
||||
assertEq "encode ${builtins.toJSON left} == ${builtins.toJSON right}"
|
||||
(url.encode args left) right;
|
||||
(url.encode args left)
|
||||
right;
|
||||
|
||||
checkDecoding = { left, right }:
|
||||
assertEq "${builtins.toJSON left} == decode ${builtins.toJSON right}"
|
||||
(url.decode left) right;
|
||||
assertEq "${builtins.toJSON left} == decode ${builtins.toJSON right}"
|
||||
(url.decode left)
|
||||
right;
|
||||
|
||||
unreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_~";
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ let
|
|||
];
|
||||
|
||||
testEncode = it "checks url.encode"
|
||||
(builtins.map (checkEncoding {}) encodeExpected);
|
||||
(builtins.map (checkEncoding { }) encodeExpected);
|
||||
|
||||
testDecode = it "checks url.decode"
|
||||
(builtins.map checkDecoding encodeExpected);
|
||||
|
|
@ -50,7 +52,7 @@ let
|
|||
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2"
|
||||
]);
|
||||
in
|
||||
runTestsuite "nix.url" [
|
||||
testEncode
|
||||
testLeaveReserved
|
||||
]
|
||||
runTestsuite "nix.url" [
|
||||
testEncode
|
||||
testLeaveReserved
|
||||
]
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ let
|
|||
Type: integer -> integer
|
||||
*/
|
||||
byteCount = i: flow.cond [
|
||||
[ (int.bitAnd i 128 == 0) 1 ]
|
||||
[ (int.bitAnd i 128 == 0) 1 ]
|
||||
[ (int.bitAnd i 224 == 192) 2 ]
|
||||
[ (int.bitAnd i 240 == 224) 3 ]
|
||||
[ (int.bitAnd i 248 == 240) 4 ]
|
||||
|
|
@ -45,30 +45,30 @@ let
|
|||
first:
|
||||
# byte position as an index starting with 0
|
||||
pos:
|
||||
let
|
||||
defaultRange = int.inRange 128 191;
|
||||
let
|
||||
defaultRange = int.inRange 128 191;
|
||||
|
||||
secondBytePredicate = flow.switch first [
|
||||
[ (int.inRange 194 223) defaultRange ] # C2..DF
|
||||
[ 224 (int.inRange 160 191) ] # E0
|
||||
[ (int.inRange 225 236) defaultRange ] # E1..EC
|
||||
[ 237 (int.inRange 128 159) ] # ED
|
||||
[ (int.inRange 238 239) defaultRange ] # EE..EF
|
||||
[ 240 (int.inRange 144 191) ] # F0
|
||||
[ (int.inRange 241 243) defaultRange ] # F1..F3
|
||||
[ 244 (int.inRange 128 143) ] # F4
|
||||
[ (fun.const true) null ]
|
||||
];
|
||||
secondBytePredicate = flow.switch first [
|
||||
[ (int.inRange 194 223) defaultRange ] # C2..DF
|
||||
[ 224 (int.inRange 160 191) ] # E0
|
||||
[ (int.inRange 225 236) defaultRange ] # E1..EC
|
||||
[ 237 (int.inRange 128 159) ] # ED
|
||||
[ (int.inRange 238 239) defaultRange ] # EE..EF
|
||||
[ 240 (int.inRange 144 191) ] # F0
|
||||
[ (int.inRange 241 243) defaultRange ] # F1..F3
|
||||
[ 244 (int.inRange 128 143) ] # F4
|
||||
[ (fun.const true) null ]
|
||||
];
|
||||
|
||||
firstBytePredicate = byte: assert first == byte;
|
||||
first < 128 || secondBytePredicate != null;
|
||||
in
|
||||
# Either ASCII or in one of the byte ranges of Table 3-6.
|
||||
if pos == 0 then firstBytePredicate
|
||||
# return predicate according to Table 3-6.
|
||||
else if pos == 1 then assert secondBytePredicate != null; secondBytePredicate
|
||||
# 3rd and 4th byte have only one validity rule
|
||||
else defaultRange;
|
||||
firstBytePredicate = byte: assert first == byte;
|
||||
first < 128 || secondBytePredicate != null;
|
||||
in
|
||||
# Either ASCII or in one of the byte ranges of Table 3-6.
|
||||
if pos == 0 then firstBytePredicate
|
||||
# return predicate according to Table 3-6.
|
||||
else if pos == 1 then assert secondBytePredicate != null; secondBytePredicate
|
||||
# 3rd and 4th byte have only one validity rule
|
||||
else defaultRange;
|
||||
|
||||
/* Iteration step for decoding an UTF-8 byte sequence.
|
||||
It decodes incrementally, i. e. it has to be fed
|
||||
|
|
@ -128,23 +128,24 @@ let
|
|||
# the current value by the amount of bytes left.
|
||||
offset = (count - (pos + 1)) * 6;
|
||||
in
|
||||
code + (int.bitShiftL (int.bitAnd mask value) offset);
|
||||
code + (int.bitShiftL (int.bitAnd mask value) offset);
|
||||
illFormedMsg =
|
||||
"Ill-formed byte ${int.toHex value} at position ${toString pos} in ${toString count} byte UTF-8 sequence";
|
||||
in
|
||||
if !(wellFormedByte first pos value) then builtins.throw illFormedMsg
|
||||
else if pos + 1 == count
|
||||
then (builtins.removeAttrs args [ # allow extra state being passed through
|
||||
"count"
|
||||
"code"
|
||||
"pos"
|
||||
"first"
|
||||
]) // { result = newCode; }
|
||||
else (builtins.removeAttrs args [ "result" ]) // {
|
||||
inherit count first;
|
||||
code = newCode;
|
||||
pos = pos + 1;
|
||||
};
|
||||
if !(wellFormedByte first pos value) then builtins.throw illFormedMsg
|
||||
else if pos + 1 == count
|
||||
then (builtins.removeAttrs args [
|
||||
# allow extra state being passed through
|
||||
"count"
|
||||
"code"
|
||||
"pos"
|
||||
"first"
|
||||
]) // { result = newCode; }
|
||||
else (builtins.removeAttrs args [ "result" ]) // {
|
||||
inherit count first;
|
||||
code = newCode;
|
||||
pos = pos + 1;
|
||||
};
|
||||
|
||||
/* Decode an UTF-8 string into a list of codepoints.
|
||||
|
||||
|
|
@ -161,7 +162,7 @@ let
|
|||
{
|
||||
key = "start";
|
||||
stringIndex = -1;
|
||||
state = {};
|
||||
state = { };
|
||||
codepoint = null;
|
||||
}
|
||||
];
|
||||
|
|
@ -170,7 +171,8 @@ let
|
|||
# updated values for current iteration step
|
||||
newIndex = stringIndex + 1;
|
||||
newState = step state (builtins.substring newIndex 1 s);
|
||||
in lib.optional (newIndex < stringLength) {
|
||||
in
|
||||
lib.optional (newIndex < stringLength) {
|
||||
# unique keys to make genericClosure happy
|
||||
key = toString newIndex;
|
||||
# carryover state for the next step
|
||||
|
|
@ -183,35 +185,39 @@ let
|
|||
in
|
||||
# extract all steps that yield a code point into a list
|
||||
builtins.map (v: v.codepoint) (
|
||||
builtins.filter (
|
||||
{ codepoint, stringIndex, state, ... }:
|
||||
builtins.filter
|
||||
(
|
||||
{ codepoint, stringIndex, state, ... }:
|
||||
|
||||
let
|
||||
# error message in case we are missing bytes at the end of input
|
||||
earlyEndMsg =
|
||||
if state ? count && state ? pos
|
||||
then "Missing ${toString (with state; count - pos)} bytes at end of input"
|
||||
else "Unexpected end of input";
|
||||
in
|
||||
let
|
||||
# error message in case we are missing bytes at the end of input
|
||||
earlyEndMsg =
|
||||
if state ? count && state ? pos
|
||||
then "Missing ${toString (with state; count - pos)} bytes at end of input"
|
||||
else "Unexpected end of input";
|
||||
in
|
||||
|
||||
# filter out all iteration steps without a codepoint value
|
||||
codepoint != null
|
||||
# filter out all iteration steps without a codepoint value
|
||||
codepoint != null
|
||||
# if we are at the iteration step of a non-empty input string, throw
|
||||
# an error if no codepoint was returned, as it indicates an incomplete
|
||||
# UTF-8 sequence.
|
||||
|| (stringLength > 0 && stringIndex == stringLength - 1 && throw earlyEndMsg)
|
||||
|
||||
) iterResult
|
||||
)
|
||||
iterResult
|
||||
);
|
||||
|
||||
/* Pretty prints a Unicode codepoint in the U+<HEX> notation.
|
||||
|
||||
Type: integer -> string
|
||||
*/
|
||||
formatCodepoint = cp: "U+" + string.fit {
|
||||
width = 4;
|
||||
char = "0";
|
||||
} (int.toHex cp);
|
||||
formatCodepoint = cp: "U+" + string.fit
|
||||
{
|
||||
width = 4;
|
||||
char = "0";
|
||||
}
|
||||
(int.toHex cp);
|
||||
|
||||
encodeCodepoint = cp:
|
||||
let
|
||||
|
|
@ -219,11 +225,11 @@ let
|
|||
# Note that this doesn't check if the Unicode codepoint is allowed,
|
||||
# but rather allows all theoretically UTF-8-encodeable ones.
|
||||
count = flow.switch cp [
|
||||
[ (int.inRange 0 127) 1 ] # 00000000 0xxxxxxx
|
||||
[ (int.inRange 128 2047) 2 ] # 00000yyy yyxxxxxx
|
||||
[ (int.inRange 2048 65535) 3 ] # zzzzyyyy yyxxxxxx
|
||||
[ (int.inRange 0 127) 1 ] # 00000000 0xxxxxxx
|
||||
[ (int.inRange 128 2047) 2 ] # 00000yyy yyxxxxxx
|
||||
[ (int.inRange 2048 65535) 3 ] # zzzzyyyy yyxxxxxx
|
||||
[ (int.inRange 65536 1114111) 4 ] # 000uuuuu zzzzyyyy yyxxxxxx,
|
||||
# capped at U+10FFFF
|
||||
# capped at U+10FFFF
|
||||
|
||||
[ (fun.const true) (builtins.throw invalidCodepointMsg) ]
|
||||
];
|
||||
|
|
@ -234,32 +240,34 @@ let
|
|||
# according to Table 3-6. from The Unicode Standard, Version 13.0,
|
||||
# section 3.9. u is split into uh and ul since they are used in
|
||||
# different bytes in the end.
|
||||
components = lib.mapAttrs (_: { mask, offset }:
|
||||
int.bitAnd (int.bitShiftR cp offset) mask
|
||||
) {
|
||||
x = {
|
||||
mask = if count > 1 then 63 else 127;
|
||||
offset = 0;
|
||||
components = lib.mapAttrs
|
||||
(_: { mask, offset }:
|
||||
int.bitAnd (int.bitShiftR cp offset) mask
|
||||
)
|
||||
{
|
||||
x = {
|
||||
mask = if count > 1 then 63 else 127;
|
||||
offset = 0;
|
||||
};
|
||||
y = {
|
||||
mask = if count > 2 then 63 else 31;
|
||||
offset = 6;
|
||||
};
|
||||
z = {
|
||||
mask = 15;
|
||||
offset = 12;
|
||||
};
|
||||
# u which belongs into the second byte
|
||||
ul = {
|
||||
mask = 3;
|
||||
offset = 16;
|
||||
};
|
||||
# u which belongs into the first byte
|
||||
uh = {
|
||||
mask = 7;
|
||||
offset = 18;
|
||||
};
|
||||
};
|
||||
y = {
|
||||
mask = if count > 2 then 63 else 31;
|
||||
offset = 6;
|
||||
};
|
||||
z = {
|
||||
mask = 15;
|
||||
offset = 12;
|
||||
};
|
||||
# u which belongs into the second byte
|
||||
ul = {
|
||||
mask = 3;
|
||||
offset = 16;
|
||||
};
|
||||
# u which belongs into the first byte
|
||||
uh = {
|
||||
mask = 7;
|
||||
offset = 18;
|
||||
};
|
||||
};
|
||||
inherit (components) x y z ul uh;
|
||||
|
||||
# Finally construct the byte sequence for the given codepoint. This is
|
||||
|
|
@ -286,15 +294,18 @@ let
|
|||
|
||||
unableToEncodeMessage = "Can't encode ${formatCodepoint cp} as UTF-8";
|
||||
|
||||
in string.fromBytes (
|
||||
builtins.genList (i:
|
||||
let
|
||||
byte = builtins.elemAt bytes i;
|
||||
in
|
||||
in
|
||||
string.fromBytes (
|
||||
builtins.genList
|
||||
(i:
|
||||
let
|
||||
byte = builtins.elemAt bytes i;
|
||||
in
|
||||
if wellFormedByte firstByte i byte
|
||||
then byte
|
||||
else builtins.throw unableToEncodeMessage
|
||||
) count
|
||||
)
|
||||
count
|
||||
);
|
||||
|
||||
/* Encode a list of Unicode codepoints into an UTF-8 string.
|
||||
|
|
@ -303,7 +314,8 @@ let
|
|||
*/
|
||||
encode = lib.concatMapStrings encodeCodepoint;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
inherit
|
||||
encode
|
||||
decode
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ let
|
|||
char
|
||||
;
|
||||
|
||||
rustDecoder = rustSimple {
|
||||
name = "utf8-decode";
|
||||
} ''
|
||||
rustDecoder = rustSimple
|
||||
{
|
||||
name = "utf8-decode";
|
||||
} ''
|
||||
use std::io::{self, Read};
|
||||
fn main() -> std::io::Result<()> {
|
||||
let mut buffer = String::new();
|
||||
|
|
@ -47,10 +48,11 @@ let
|
|||
|
||||
rustDecode = s:
|
||||
let
|
||||
expr = runCommandLocal "${s}-decoded" {} ''
|
||||
expr = runCommandLocal "${s}-decoded" { } ''
|
||||
printf '%s' ${lib.escapeShellArg s} | ${rustDecoder} > $out
|
||||
'';
|
||||
in import expr;
|
||||
in
|
||||
import expr;
|
||||
|
||||
hexDecode = l:
|
||||
utf8.decode (string.fromBytes (builtins.map int.fromHex l));
|
||||
|
|
@ -65,23 +67,27 @@ let
|
|||
(assertEq "well-formed: F4 80 83 92" (hexDecode [ "F4" "80" "83" "92" ]) [ 1048786 ])
|
||||
(assertThrows "Codepoint out of range: 0xFFFFFF" (hexEncode [ "FFFFFF" ]))
|
||||
(assertThrows "Codepoint out of range: -0x02" (hexEncode [ "-02" ]))
|
||||
] ++ builtins.genList (i:
|
||||
let
|
||||
cp = i + int.fromHex "D800";
|
||||
in
|
||||
] ++ builtins.genList
|
||||
(i:
|
||||
let
|
||||
cp = i + int.fromHex "D800";
|
||||
in
|
||||
assertThrows "Can't encode UTF-16 reserved characters: ${utf8.formatCodepoint cp}"
|
||||
(utf8.encode [ cp ])
|
||||
) (int.fromHex "07FF"));
|
||||
)
|
||||
(int.fromHex "07FF"));
|
||||
|
||||
testAscii = it "checks decoding of ascii strings"
|
||||
(builtins.map (s: assertEq "ASCII decoding is equal to UTF-8 decoding for \"${s}\""
|
||||
(string.toBytes s) (utf8.decode s)) [
|
||||
"foo bar"
|
||||
"hello\nworld"
|
||||
"carriage\r\nreturn"
|
||||
"1238398494829304 []<><>({})[]!!)"
|
||||
(string.take 127 char.allChars)
|
||||
]);
|
||||
(builtins.map
|
||||
(s: assertEq "ASCII decoding is equal to UTF-8 decoding for \"${s}\""
|
||||
(string.toBytes s)
|
||||
(utf8.decode s)) [
|
||||
"foo bar"
|
||||
"hello\nworld"
|
||||
"carriage\r\nreturn"
|
||||
"1238398494829304 []<><>({})[]!!)"
|
||||
(string.take 127 char.allChars)
|
||||
]);
|
||||
|
||||
randomUnicode = [
|
||||
"" # empty string should yield empty list
|
||||
|
|
@ -126,16 +132,17 @@ let
|
|||
testDecodingEncoding = it "checks that decoding and then encoding forms an identity"
|
||||
(builtins.map
|
||||
(s: assertEq "Decoding and then encoding “${s}” yields itself"
|
||||
(utf8.encode (utf8.decode s)) s)
|
||||
(utf8.encode (utf8.decode s))
|
||||
s)
|
||||
(lib.flatten [
|
||||
glassSentences
|
||||
randomUnicode
|
||||
]));
|
||||
|
||||
in
|
||||
runTestsuite "nix.utf8" [
|
||||
testFailures
|
||||
testAscii
|
||||
testDecoding
|
||||
testDecodingEncoding
|
||||
]
|
||||
runTestsuite "nix.utf8" [
|
||||
testFailures
|
||||
testAscii
|
||||
testDecoding
|
||||
testDecodingEncoding
|
||||
]
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ let
|
|||
symphorien
|
||||
erictapen
|
||||
expipiplus1
|
||||
;
|
||||
;
|
||||
};
|
||||
|
||||
# buildRustPackage handling
|
||||
|
|
@ -55,24 +55,25 @@ let
|
|||
extractCargoLock = drv:
|
||||
if !(drv ? cargoDeps.outPath)
|
||||
then null
|
||||
else pkgs.runCommandNoCC "${drv.name}-Cargo.lock" {} ''
|
||||
if test -d "${drv.cargoDeps}"; then
|
||||
cp "${drv.cargoDeps}/Cargo.lock" "$out"
|
||||
fi
|
||||
else
|
||||
pkgs.runCommandNoCC "${drv.name}-Cargo.lock" { } ''
|
||||
if test -d "${drv.cargoDeps}"; then
|
||||
cp "${drv.cargoDeps}/Cargo.lock" "$out"
|
||||
fi
|
||||
|
||||
if test -f "${drv.cargoDeps}"; then
|
||||
tar -xO \
|
||||
--no-wildcards-match-slash --wildcards \
|
||||
-f "${drv.cargoDeps}" \
|
||||
'*/Cargo.lock' \
|
||||
> "$out"
|
||||
fi
|
||||
'';
|
||||
if test -f "${drv.cargoDeps}"; then
|
||||
tar -xO \
|
||||
--no-wildcards-match-slash --wildcards \
|
||||
-f "${drv.cargoDeps}" \
|
||||
'*/Cargo.lock' \
|
||||
> "$out"
|
||||
fi
|
||||
'';
|
||||
|
||||
# nixpkgs traversal
|
||||
|
||||
# Condition for us to recurse: Either at top-level or recurseForDerivation.
|
||||
recurseInto = path: x: path == [] ||
|
||||
recurseInto = path: x: path == [ ] ||
|
||||
(lib.isAttrs x && (x.recurseForDerivations or false));
|
||||
|
||||
# Returns the value or false if an eval error occurs.
|
||||
|
|
@ -97,46 +98,69 @@ let
|
|||
doRec = tryEvalOrFalse (recurseInto path x);
|
||||
isRust = tryEvalOrFalse (isRustPackage x);
|
||||
in
|
||||
if doRec then lib.concatLists (
|
||||
lib.mapAttrsToList (n: go (path ++ [ n ])) x
|
||||
) else if isDrv && isRust then [
|
||||
{
|
||||
attr = path;
|
||||
lock = extractCargoLock x;
|
||||
maintainers = x.meta.maintainers or [];
|
||||
}
|
||||
] else [];
|
||||
in go [];
|
||||
if doRec then
|
||||
lib.concatLists
|
||||
(
|
||||
lib.mapAttrsToList (n: go (path ++ [ n ])) x
|
||||
) else if isDrv && isRust then [
|
||||
{
|
||||
attr = path;
|
||||
lock = extractCargoLock x;
|
||||
maintainers = x.meta.maintainers or [ ];
|
||||
}
|
||||
] else [ ];
|
||||
in
|
||||
go [ ];
|
||||
|
||||
# Report generation and formatting
|
||||
|
||||
reportFor = { attr, lock, maintainers ? [] }: let
|
||||
# naïve attribute path to Nix syntax conversion
|
||||
strAttr = lib.concatStringsSep "." attr;
|
||||
strMaintainers = lib.concatMapStringsSep " " (m: "@${m.github}") (
|
||||
builtins.filter (x: builtins.elem x maintainerWhitelist) maintainers
|
||||
);
|
||||
in
|
||||
reportFor = { attr, lock, maintainers ? [ ] }:
|
||||
let
|
||||
# naïve attribute path to Nix syntax conversion
|
||||
strAttr = lib.concatStringsSep "." attr;
|
||||
strMaintainers = lib.concatMapStringsSep " " (m: "@${m.github}") (
|
||||
builtins.filter (x: builtins.elem x maintainerWhitelist) maintainers
|
||||
);
|
||||
in
|
||||
if lock == null
|
||||
then pkgs.emptyFile
|
||||
else depot.nix.runExecline "${strAttr}-vulnerability-report" {} [
|
||||
"pipeline" [
|
||||
bins.cargo-audit
|
||||
"audit" "--json"
|
||||
"-n" "--db" rustsec-advisory-db
|
||||
"-f" lock
|
||||
]
|
||||
"importas" "out" "out"
|
||||
"redirfd" "-w" "1" "$out"
|
||||
bins.jq "-rj" "-f" ./format-audit-result.jq
|
||||
"--arg" "attr" strAttr
|
||||
"--arg" "maintainers" strMaintainers
|
||||
];
|
||||
else
|
||||
depot.nix.runExecline "${strAttr}-vulnerability-report" { } [
|
||||
"pipeline"
|
||||
[
|
||||
bins.cargo-audit
|
||||
"audit"
|
||||
"--json"
|
||||
"-n"
|
||||
"--db"
|
||||
rustsec-advisory-db
|
||||
"-f"
|
||||
lock
|
||||
]
|
||||
"importas"
|
||||
"out"
|
||||
"out"
|
||||
"redirfd"
|
||||
"-w"
|
||||
"1"
|
||||
"$out"
|
||||
bins.jq
|
||||
"-rj"
|
||||
"-f"
|
||||
./format-audit-result.jq
|
||||
"--arg"
|
||||
"attr"
|
||||
strAttr
|
||||
"--arg"
|
||||
"maintainers"
|
||||
strMaintainers
|
||||
];
|
||||
|
||||
# GHMF in issues splits paragraphs on newlines
|
||||
description = lib.concatMapStringsSep "\n\n" (
|
||||
builtins.replaceStrings [ "\n" ] [ " " ]
|
||||
) [
|
||||
description = lib.concatMapStringsSep "\n\n"
|
||||
(
|
||||
builtins.replaceStrings [ "\n" ] [ " " ]
|
||||
) [
|
||||
''
|
||||
The vulnerability report below was generated by
|
||||
[nixpkgs-crate-holes](https://code.tvl.fyi/tree/users/sterni/nixpkgs-crate-holes)
|
||||
|
|
@ -194,39 +218,63 @@ let
|
|||
);
|
||||
in
|
||||
|
||||
depot.nix.runExecline "nixpkgs-rust-pkgs-vulnerability-report.md" {
|
||||
stdin = lib.concatMapStrings (report: "${report}\n") reports;
|
||||
} [
|
||||
"importas" "out" "out"
|
||||
"redirfd" "-w" "1" "$out"
|
||||
depot.nix.runExecline "nixpkgs-rust-pkgs-vulnerability-report.md"
|
||||
{
|
||||
stdin = lib.concatMapStrings (report: "${report}\n") reports;
|
||||
} [
|
||||
"importas"
|
||||
"out"
|
||||
"out"
|
||||
"redirfd"
|
||||
"-w"
|
||||
"1"
|
||||
"$out"
|
||||
# Print introduction paragraph for the issue
|
||||
"if" [ bins.printf "%s\n\n" description ]
|
||||
"if"
|
||||
[ bins.printf "%s\n\n" description ]
|
||||
# Print all reports
|
||||
"foreground" [
|
||||
"forstdin" "-E" "report" bins.cat "$report"
|
||||
"foreground"
|
||||
[
|
||||
"forstdin"
|
||||
"-E"
|
||||
"report"
|
||||
bins.cat
|
||||
"$report"
|
||||
]
|
||||
# Print stats at the end (mostly as a gimmick), we already know how many
|
||||
# attributes there are and count the attributes with vulnerability by
|
||||
# finding the number of checkable list entries in the output.
|
||||
"backtick" "-E" "vulnerableCount" [
|
||||
"pipeline" [
|
||||
bins.grep "^- \\[ \\]" "$out"
|
||||
"backtick"
|
||||
"-E"
|
||||
"vulnerableCount"
|
||||
[
|
||||
"pipeline"
|
||||
[
|
||||
bins.grep
|
||||
"^- \\[ \\]"
|
||||
"$out"
|
||||
]
|
||||
bins.wc "-l"
|
||||
bins.wc
|
||||
"-l"
|
||||
]
|
||||
"if" [
|
||||
"if"
|
||||
[
|
||||
bins.printf
|
||||
"\n%s of %s checked attributes have vulnerable dependencies.\n\n"
|
||||
"$vulnerableCount"
|
||||
(toString (builtins.length reports))
|
||||
]
|
||||
"if" [
|
||||
bins.printf "%s\n\n" runInstructions
|
||||
"if"
|
||||
[
|
||||
bins.printf
|
||||
"%s\n\n"
|
||||
runInstructions
|
||||
]
|
||||
];
|
||||
|
||||
singleReport =
|
||||
{ # Attribute to check: string or list of strings (attr path)
|
||||
{
|
||||
# Attribute to check: string or list of strings (attr path)
|
||||
attr
|
||||
# Path to importable nixpkgs checkout
|
||||
, nixpkgsPath
|
||||
|
|
@ -241,37 +289,63 @@ let
|
|||
strAttr = lib.concatStringsSep "." attr';
|
||||
in
|
||||
|
||||
depot.nix.runExecline "${strAttr}-report.html" {} [
|
||||
"importas" "out" "out"
|
||||
"backtick" "-I" "-E" "-N" "report" [
|
||||
bins.cargo-audit "audit"
|
||||
depot.nix.runExecline "${strAttr}-report.html" { } [
|
||||
"importas"
|
||||
"out"
|
||||
"out"
|
||||
"backtick"
|
||||
"-I"
|
||||
"-E"
|
||||
"-N"
|
||||
"report"
|
||||
[
|
||||
bins.cargo-audit
|
||||
"audit"
|
||||
"--quiet"
|
||||
"-n" "--db" rustsec-advisory-db
|
||||
"-f" lockFile
|
||||
"-n"
|
||||
"--db"
|
||||
rustsec-advisory-db
|
||||
"-f"
|
||||
lockFile
|
||||
]
|
||||
"pipeline" [
|
||||
"ifte" [
|
||||
bins.printf "%s" "$report"
|
||||
] [
|
||||
bins.printf "%s\n" "No vulnerabilities found"
|
||||
"pipeline"
|
||||
[
|
||||
"ifte"
|
||||
[
|
||||
bins.printf
|
||||
"%s"
|
||||
"$report"
|
||||
]
|
||||
bins.test "-n" "$report"
|
||||
[
|
||||
bins.printf
|
||||
"%s\n"
|
||||
"No vulnerabilities found"
|
||||
]
|
||||
bins.test
|
||||
"-n"
|
||||
"$report"
|
||||
]
|
||||
"pipeline" [
|
||||
bins.tee "/dev/stderr"
|
||||
"pipeline"
|
||||
[
|
||||
bins.tee
|
||||
"/dev/stderr"
|
||||
]
|
||||
"redirfd" "-w" "1" "$out"
|
||||
"redirfd"
|
||||
"-w"
|
||||
"1"
|
||||
"$out"
|
||||
bins.ansi2html
|
||||
];
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
full = reportForNixpkgs;
|
||||
single = singleReport;
|
||||
|
||||
inherit
|
||||
extractCargoLock
|
||||
allLockFiles
|
||||
;
|
||||
;
|
||||
|
||||
# simple sanity check, doesn't cover everything, but testing the full report
|
||||
# is quite expensive in terms of evaluation.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue