feat(users/Profpatsch): add a rewriter for lib.stdenv changes
This is in order to advance the rewriting from stdenv.lib to lib. https://github.com/NixOS/nixpkgs/issues/108938 The hard part about changing the argument is that a package might not include lib in its arguments, which is why I use hnix to check whether lib is included and add it to the import list if it doesn’t already exist there. So far, only the really common pattern of meta = with stdenv.lib; is rewritten. Change-Id: I370f0a321b0e5a5bd21ec21fc7cefdd65ec845ed Reviewed-on: https://cl.tvl.fyi/c/depot/+/2345 Tested-by: BuildkiteCI Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
parent
c1cb4c260c
commit
2f807d7f14
3 changed files with 187 additions and 0 deletions
23
users/Profpatsch/lib.nix
Normal file
23
users/Profpatsch/lib.nix
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{ depot, pkgs, ... }:
|
||||||
|
let
|
||||||
|
bins = depot.nix.getBins pkgs.coreutils ["printf" "echo"];
|
||||||
|
|
||||||
|
debugExec = msg: depot.nix.writeExecline "debug-exec" {} [
|
||||||
|
"if" [
|
||||||
|
"fdmove" "-c" "1" "2"
|
||||||
|
"if" [ bins.printf "%s: " msg ]
|
||||||
|
"if" [ bins.echo "$@" ]
|
||||||
|
]
|
||||||
|
"$@"
|
||||||
|
];
|
||||||
|
|
||||||
|
eprintf = depot.nix.writeExecline "eprintf" {} [
|
||||||
|
"fdmove" "-c" "1" "2" bins.printf "%s" "$@"
|
||||||
|
];
|
||||||
|
|
||||||
|
in {
|
||||||
|
inherit
|
||||||
|
debugExec
|
||||||
|
eprintf
|
||||||
|
;
|
||||||
|
}
|
80
users/Profpatsch/nixpkgs-rewriter/MetaStdenvLib.hs
Normal file
80
users/Profpatsch/nixpkgs-rewriter/MetaStdenvLib.hs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
{-# LANGUAGE PartialTypeSignatures #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
import Nix.Parser
|
||||||
|
import Nix.Expr.Types
|
||||||
|
import Nix.Expr.Types.Annotated
|
||||||
|
import System.Environment (getArgs)
|
||||||
|
import System.Exit (die)
|
||||||
|
import Data.Fix (Fix(..))
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as BL
|
||||||
|
import qualified Data.Aeson as A
|
||||||
|
import qualified Data.Aeson.Encoding as A
|
||||||
|
import Data.Function ((&))
|
||||||
|
import qualified System.IO as IO
|
||||||
|
import qualified Text.Megaparsec.Pos as MP
|
||||||
|
|
||||||
|
main = do
|
||||||
|
(nixFile:_) <- getArgs
|
||||||
|
(parseNixFileLoc nixFile :: IO _) >>= \case
|
||||||
|
Failure err -> do
|
||||||
|
ePutStrLn $ show err
|
||||||
|
die "oh no"
|
||||||
|
Success expr -> do
|
||||||
|
case snd $ match expr of
|
||||||
|
NoArguments -> do
|
||||||
|
ePutStrLn $ "NoArguments in " <> nixFile
|
||||||
|
printPairs mempty
|
||||||
|
YesLib vars -> do
|
||||||
|
ePutStrLn $ "lib in " <> show vars <> " in " <> nixFile
|
||||||
|
printPairs mempty
|
||||||
|
NoLib vars srcSpan -> do
|
||||||
|
ePutStrLn $ nixFile <> " needs lib added"
|
||||||
|
printPairs
|
||||||
|
$ "fileName" A..= nixFile
|
||||||
|
<> "fromLine" A..= (srcSpan & spanBegin & sourceLine)
|
||||||
|
<> "fromColumn" A..= (srcSpan & spanBegin & sourceColumn)
|
||||||
|
<> "toLine" A..= (srcSpan & spanEnd & sourceLine)
|
||||||
|
<> "toColumn" A..= (srcSpan & spanEnd & sourceColumn)
|
||||||
|
|
||||||
|
printPairs pairs = BL.putStrLn $ A.encodingToLazyByteString $ A.pairs pairs
|
||||||
|
|
||||||
|
ePutStrLn = IO.hPutStrLn IO.stderr
|
||||||
|
|
||||||
|
data Descend = YesDesc | NoDesc
|
||||||
|
deriving Show
|
||||||
|
data Matched = NoArguments | NoLib [VarName] SrcSpan | YesLib [VarName]
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
match :: Fix (Compose (Ann SrcSpan) NExprF) -> (Descend, Matched)
|
||||||
|
match = \case
|
||||||
|
(AnnE outerSpan (NAbs (ParamSet params _ _) (AnnE innerSpan _))) -> (NoDesc,
|
||||||
|
let vars = map fst params in
|
||||||
|
case (any (== "lib") vars) of
|
||||||
|
True -> YesLib vars
|
||||||
|
False ->
|
||||||
|
-- The span of the arglist is from the beginning of the match
|
||||||
|
-- to the beginning of the inner expression
|
||||||
|
let varSpan = SrcSpan
|
||||||
|
{ spanBegin = outerSpan & spanBegin
|
||||||
|
-- -1 to prevent the spans from overlapping
|
||||||
|
, spanEnd = sourcePosMinus1 (innerSpan & spanBegin) }
|
||||||
|
in NoLib vars varSpan)
|
||||||
|
_ -> (NoDesc, NoArguments)
|
||||||
|
|
||||||
|
-- | Remove one from a source positon.
|
||||||
|
--
|
||||||
|
-- That means if the current position is at the very beginning of a line,
|
||||||
|
-- jump to the previous line.
|
||||||
|
sourcePosMinus1 :: SourcePos -> SourcePos
|
||||||
|
sourcePosMinus1 src@(SourcePos { sourceLine, sourceColumn }) =
|
||||||
|
let
|
||||||
|
col = MP.mkPos $ max (MP.unPos sourceColumn - 1) 1
|
||||||
|
line = MP.mkPos $ case MP.unPos sourceColumn of
|
||||||
|
1 -> max (MP.unPos sourceLine - 1) 1
|
||||||
|
_ -> MP.unPos sourceLine
|
||||||
|
in src
|
||||||
|
{ sourceLine = line
|
||||||
|
, sourceColumn = col }
|
84
users/Profpatsch/nixpkgs-rewriter/default.nix
Normal file
84
users/Profpatsch/nixpkgs-rewriter/default.nix
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
{ depot, pkgs, ... }:
|
||||||
|
let
|
||||||
|
inherit (depot.nix)
|
||||||
|
writeExecline
|
||||||
|
;
|
||||||
|
inherit (depot.users.Profpatsch.lib)
|
||||||
|
debugExec
|
||||||
|
eprintf
|
||||||
|
;
|
||||||
|
|
||||||
|
export-json-object = pkgs.writers.writePython3 "export-json-object" {} ''
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
|
||||||
|
if d == {}:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
for k, v in d.items():
|
||||||
|
os.environ[k] = str(v)
|
||||||
|
|
||||||
|
os.execvp(sys.argv[1], sys.argv[1:])
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta-stdenv-lib = pkgs.writers.writeHaskell "meta-stdenv-lib" {
|
||||||
|
libraries = [
|
||||||
|
pkgs.haskellPackages.hnix
|
||||||
|
pkgs.haskellPackages.aeson
|
||||||
|
];
|
||||||
|
} ./MetaStdenvLib.hs;
|
||||||
|
|
||||||
|
replace-between-lines = writeExecline "replace-between-lines" { readNArgs = 1; } [
|
||||||
|
"importas" "-ui" "file" "fileName"
|
||||||
|
"importas" "-ui" "from" "fromLine"
|
||||||
|
"importas" "-ui" "to" "toLine"
|
||||||
|
"if" [ eprintf "\${from}-\${to}" ]
|
||||||
|
(debugExec "adding lib")
|
||||||
|
"sed"
|
||||||
|
"-e" "\${from},\${to} \${1}"
|
||||||
|
"-i" "$file"
|
||||||
|
];
|
||||||
|
|
||||||
|
add-lib-if-necessary = writeExecline "add-lib-if-necessary" { readNArgs = 1; } [
|
||||||
|
"pipeline" [ meta-stdenv-lib "$1" ]
|
||||||
|
export-json-object
|
||||||
|
# first replace any stdenv.lib mentions in the arg header
|
||||||
|
# if this is not done, the replace below kills these.
|
||||||
|
# Since we want it anyway ultimately, let’s do it here.
|
||||||
|
"if" [ replace-between-lines "s/stdenv\.lib/lib/" ]
|
||||||
|
# then add the lib argument
|
||||||
|
# (has to be before stdenv, otherwise default arguments might be in the way)
|
||||||
|
replace-between-lines "s/stdenv/lib, stdenv/"
|
||||||
|
];
|
||||||
|
|
||||||
|
metaString = ''meta = with stdenv.lib; {'';
|
||||||
|
|
||||||
|
replace-stdenv-lib = pkgs.writers.writeBash "replace-stdenv-lib" ''
|
||||||
|
set -euo pipefail
|
||||||
|
sourceDir="$1"
|
||||||
|
for file in $(
|
||||||
|
${pkgs.ripgrep}/bin/rg \
|
||||||
|
--files-with-matches \
|
||||||
|
--fixed-strings \
|
||||||
|
-e '${metaString}' \
|
||||||
|
"$sourceDir"
|
||||||
|
)
|
||||||
|
do
|
||||||
|
echo "replacing stdenv.lib meta in $file" >&2
|
||||||
|
sed -e '/${metaString}/ s/stdenv.lib/lib/' \
|
||||||
|
-i "$file"
|
||||||
|
${add-lib-if-necessary} "$file"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
# requires hnix, which we don’t want in tvl for now
|
||||||
|
# uncomment manually if you want to use it.
|
||||||
|
# inherit
|
||||||
|
# meta-stdenv-lib
|
||||||
|
# replace-stdenv-lib
|
||||||
|
# ;
|
||||||
|
}
|
Loading…
Reference in a new issue