From fa2f0fd6b4edf8b970a77186d1279226027aad48 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sat, 26 Nov 2022 20:50:22 +0100 Subject: [PATCH] json2nix: use nixfmt internally This helps with creating better error messages, because we can now see where in the pipeline the error occurred --- internals/json2nix/default.nix | 7 ++- internals/json2nix/haskell-overlay.nix | 10 +++++ internals/json2nix/json2nix.hs | 60 +++++++++++++++----------- searchers/home-manager-search.nix | 6 +-- 4 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 internals/json2nix/haskell-overlay.nix diff --git a/internals/json2nix/default.nix b/internals/json2nix/default.nix index 3bd8e9d..81d35c6 100644 --- a/internals/json2nix/default.nix +++ b/internals/json2nix/default.nix @@ -1,4 +1,7 @@ { pkgs, ... }: -pkgs.writers.writeHaskellBin "json2nix" { - libraries = with pkgs.haskellPackages; [ aeson ]; +let + overlayedPkgs = pkgs.extend + (pkgs.callPackage ./haskell-overlay.nix { compiler = "ghc942"; }); +in overlayedPkgs.writers.writeHaskellBin "json2nix" { + libraries = with overlayedPkgs.haskellPackages; [ aeson nixfmt extra text ]; } (builtins.readFile ./json2nix.hs) diff --git a/internals/json2nix/haskell-overlay.nix b/internals/json2nix/haskell-overlay.nix new file mode 100644 index 0000000..a62a63a --- /dev/null +++ b/internals/json2nix/haskell-overlay.nix @@ -0,0 +1,10 @@ +{ pkgs, compiler, ... }: +final: prev: { + haskellPackages = with prev.haskell.lib; + prev.haskell.packages.${compiler}.override { + overrides = hpFinal: hpPrev: { + # Upgrade nixfmts "text" dependency to >= 2 + nixfmt = doJailbreak hpPrev.nixfmt; + }; + }; +} diff --git a/internals/json2nix/json2nix.hs b/internals/json2nix/json2nix.hs index 6beb6ee..debdf34 100644 --- a/internals/json2nix/json2nix.hs +++ b/internals/json2nix/json2nix.hs @@ -1,35 +1,43 @@ {-# LANGUAGE OverloadedStrings #-} -import Data.Aeson (Value(..), decode) -import Data.Aeson.Key (Key, toString) -import Data.Aeson.KeyMap (foldMapWithKey) -import Data.Aeson.Parser (json') -import Data.Aeson.Types (parse) -import Data.String (fromString) -import Data.Text (Text(..), unpack, replace, isInfixOf) -import Data.Vector (Vector) -import Data.Maybe (fromMaybe) +import qualified Data.Aeson as A +import qualified Data.Aeson.Key as A +import qualified Data.Aeson.KeyMap as A +import qualified Data.ByteString as BS +import qualified Data.Either.Extra as E +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Vector as V +import Nixfmt (format) main :: IO () -main = interact f +main = BS.interact parseNixCode + +parseNixCode :: BS.ByteString -> BS.ByteString +parseNixCode input = T.encodeUtf8 $ E.fromEither formattedNixCode where - f input = case decode $ fromString input of - Nothing -> "json2nix error - could not parse input\n" ++ show input - Just jsonValue -> json2Nix jsonValue + addErrPrefix :: T.Text -> Either String a -> Either T.Text a + addErrPrefix prefix = E.mapLeft (T.append prefix . T.pack) -keyValToString :: Key -> Value -> String -keyValToString key value = toString key ++ " = " ++ json2Nix value ++ ";" + rawNixCode :: Either T.Text T.Text + rawNixCode = json2Nix <$> addErrPrefix "json2nix json error -\n" (A.eitherDecode $ BS.fromStrict input) --- escapeDollar :: Text -> Text --- escapeDollar = replace "''${" "\\''${" + formattedNixCode :: Either T.Text T.Text + formattedNixCode = (addErrPrefix "json2nix nixfmt error -\n" . format 80 "") =<< rawNixCode -json2Nix :: Value -> String -json2Nix (Object object) = "{" ++ foldMapWithKey keyValToString object ++ "}" -json2Nix (Array array) = "[" ++ foldr (\x y -> x ++ " " ++ y) "" (fmap json2Nix array) ++ "]" -json2Nix (Number n) = show n -json2Nix (Bool False) = "false" -json2Nix (Bool True) = "true" -json2Nix Null = "null" -json2Nix (String text) = sep ++ unpack text ++ sep +keyValToString :: A.Key -> A.Value -> T.Text +keyValToString key value = T.concat [T.pack $ show key, " = ", json2Nix value, ";"] + +-- escapeDollar :: T.Text -> T.Text +-- escapeDollar = T.replace "''${" "\\''${" + +json2Nix :: A.Value -> T.Text +json2Nix (A.Array array) = T.concat ["[", T.intercalate " " $ V.toList $ fmap json2Nix array, "]"] +json2Nix (A.Object object) = T.concat ["{", A.foldMapWithKey keyValToString object, "}"] +json2Nix (A.Number n) = T.pack $ show n +json2Nix (A.Bool False) = "false" +json2Nix (A.Bool True) = "true" +json2Nix A.Null = "null" +json2Nix (A.String text) = T.concat [sep, text, sep] where - sep = if "\"" `isInfixOf` text then "\'\'" else "\"" + sep = if "\"" `T.isInfixOf` text then "\'\'" else "\"" diff --git a/searchers/home-manager-search.nix b/searchers/home-manager-search.nix index f197076..6107b96 100644 --- a/searchers/home-manager-search.nix +++ b/searchers/home-manager-search.nix @@ -99,13 +99,13 @@ let JSON_DATA=$(${jq} ".\"$OPTION_KEY\"" $JSON_MANUAL_PATH) export DESCRIPTION=$(echo $JSON_DATA | ${jq} -r ".description" | ${perl} ${pArgs}) - EXAMPLE_DATA=$(echo $JSON_DATA | ${jq} -r ".example.text" 2>/dev/null) + EXAMPLE_DATA=$(echo $JSON_DATA | ${jq} -r ".example.text" 2>/dev/null | ${nixfmt}) if [ $? != 0 ]; then EXAMPLE_DATA=$(echo $JSON_DATA | ${jq} -r ".example" | ${json2nix}/bin/json2nix) fi - export EXAMPLE=$(echo $EXAMPLE_DATA | ${nixfmt} | ${bat} ${batColorArg}--style=numbers) + export EXAMPLE=$(echo $EXAMPLE_DATA | ${bat} ${batColorArg}--style=numbers) - export DEFAULT=$(echo $JSON_DATA | ${jq} -r ".default" | ${json2nix}/bin/json2nix | ${nixfmt} | ${bat} ${batColorArg}--style=numbers) + export DEFAULT=$(echo $JSON_DATA | ${jq} -r ".default" | ${json2nix}/bin/json2nix | ${bat} ${batColorArg}--style=numbers) echo $JSON_DATA | ${gomplate} --datasource opt=stdin:?type=application/json --file ${template} '';