json2nix: use nixfmt internally

This helps with creating better error messages,
because we can now see where in the pipeline
the error occurred
This commit is contained in:
Oystein Kristoffer Tveit 2022-11-26 20:50:22 +01:00
parent eab555988e
commit fa2f0fd6b4
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
4 changed files with 52 additions and 31 deletions

View File

@ -1,4 +1,7 @@
{ pkgs, ... }: { pkgs, ... }:
pkgs.writers.writeHaskellBin "json2nix" { let
libraries = with pkgs.haskellPackages; [ aeson ]; 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) } (builtins.readFile ./json2nix.hs)

View File

@ -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;
};
};
}

View File

@ -1,35 +1,43 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
import Data.Aeson (Value(..), decode) import qualified Data.Aeson as A
import Data.Aeson.Key (Key, toString) import qualified Data.Aeson.Key as A
import Data.Aeson.KeyMap (foldMapWithKey) import qualified Data.Aeson.KeyMap as A
import Data.Aeson.Parser (json') import qualified Data.ByteString as BS
import Data.Aeson.Types (parse) import qualified Data.Either.Extra as E
import Data.String (fromString) import qualified Data.Text as T
import Data.Text (Text(..), unpack, replace, isInfixOf) import qualified Data.Text.Encoding as T
import Data.Vector (Vector) import qualified Data.Vector as V
import Data.Maybe (fromMaybe) import Nixfmt (format)
main :: IO () main :: IO ()
main = interact f main = BS.interact parseNixCode
parseNixCode :: BS.ByteString -> BS.ByteString
parseNixCode input = T.encodeUtf8 $ E.fromEither formattedNixCode
where where
f input = case decode $ fromString input of addErrPrefix :: T.Text -> Either String a -> Either T.Text a
Nothing -> "json2nix error - could not parse input\n" ++ show input addErrPrefix prefix = E.mapLeft (T.append prefix . T.pack)
Just jsonValue -> json2Nix jsonValue
keyValToString :: Key -> Value -> String rawNixCode :: Either T.Text T.Text
keyValToString key value = toString key ++ " = " ++ json2Nix value ++ ";" rawNixCode = json2Nix <$> addErrPrefix "json2nix json error -\n" (A.eitherDecode $ BS.fromStrict input)
-- escapeDollar :: Text -> Text formattedNixCode :: Either T.Text T.Text
-- escapeDollar = replace "''${" "\\''${" formattedNixCode = (addErrPrefix "json2nix nixfmt error -\n" . format 80 "") =<< rawNixCode
json2Nix :: Value -> String keyValToString :: A.Key -> A.Value -> T.Text
json2Nix (Object object) = "{" ++ foldMapWithKey keyValToString object ++ "}" keyValToString key value = T.concat [T.pack $ show key, " = ", json2Nix value, ";"]
json2Nix (Array array) = "[" ++ foldr (\x y -> x ++ " " ++ y) "" (fmap json2Nix array) ++ "]"
json2Nix (Number n) = show n -- escapeDollar :: T.Text -> T.Text
json2Nix (Bool False) = "false" -- escapeDollar = T.replace "''${" "\\''${"
json2Nix (Bool True) = "true"
json2Nix Null = "null" json2Nix :: A.Value -> T.Text
json2Nix (String text) = sep ++ unpack text ++ sep 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 where
sep = if "\"" `isInfixOf` text then "\'\'" else "\"" sep = if "\"" `T.isInfixOf` text then "\'\'" else "\""

View File

@ -99,13 +99,13 @@ let
JSON_DATA=$(${jq} ".\"$OPTION_KEY\"" $JSON_MANUAL_PATH) JSON_DATA=$(${jq} ".\"$OPTION_KEY\"" $JSON_MANUAL_PATH)
export DESCRIPTION=$(echo $JSON_DATA | ${jq} -r ".description" | ${perl} ${pArgs}) 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 if [ $? != 0 ]; then
EXAMPLE_DATA=$(echo $JSON_DATA | ${jq} -r ".example" | ${json2nix}/bin/json2nix) EXAMPLE_DATA=$(echo $JSON_DATA | ${jq} -r ".example" | ${json2nix}/bin/json2nix)
fi 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} echo $JSON_DATA | ${gomplate} --datasource opt=stdin:?type=application/json --file ${template}
''; '';