1
1
mirror of https://github.com/nmattia/niv.git synced 2024-11-12 23:06:35 +03:00

Allow JSON attributes values with -a foo=bar

This commit is contained in:
Nicolas Mattia 2019-11-24 20:21:35 +01:00
parent d9e35d67d8
commit 271677ec6e
2 changed files with 41 additions and 22 deletions

View File

@ -227,13 +227,17 @@ Examples:
niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip
Usage: niv add [-n|--name NAME] PACKAGE ([-a|--attribute KEY=VAL] | Usage: niv add [-n|--name NAME] PACKAGE ([-a|--attribute KEY=VAL] |
[-b|--branch BRANCH] | [-o|--owner OWNER] | [-r|--repo REPO] | [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |
[-v|--version VERSION] | [-t|--template URL] | [-T|--type TYPE]) [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION] |
[-t|--template URL] | [-T|--type TYPE])
Add dependency Add dependency
Available options: Available options:
-n,--name NAME Set the package name to <NAME> -n,--name NAME Set the package name to <NAME>
-a,--attribute KEY=VAL Set the package spec attribute <KEY> to <VAL> -a,--attribute KEY=VAL Set the package spec attribute <KEY> to <VAL>, where
<VAL> may be JSON.
-s,--string-attribute KEY=VAL
Set the package spec attribute <KEY> to <VAL>.
-b,--branch BRANCH Equivalent to --attribute branch=<BRANCH> -b,--branch BRANCH Equivalent to --attribute branch=<BRANCH>
-o,--owner OWNER Equivalent to --attribute owner=<OWNER> -o,--owner OWNER Equivalent to --attribute owner=<OWNER>
-r,--repo REPO Equivalent to --attribute repo=<REPO> -r,--repo REPO Equivalent to --attribute repo=<REPO>
@ -256,13 +260,17 @@ Examples:
niv update nixpkgs # update nixpkgs niv update nixpkgs # update nixpkgs
niv update my-package -v beta-0.2 # update my-package to version "beta-0.2" niv update my-package -v beta-0.2 # update my-package to version "beta-0.2"
Usage: niv update [PACKAGE] ([-a|--attribute KEY=VAL] | [-b|--branch BRANCH] | Usage: niv update [PACKAGE] ([-a|--attribute KEY=VAL] |
[-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |
[-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION] [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION]
| [-t|--template URL] | [-T|--type TYPE]) | [-t|--template URL] | [-T|--type TYPE])
Update dependencies Update dependencies
Available options: Available options:
-a,--attribute KEY=VAL Set the package spec attribute <KEY> to <VAL> -a,--attribute KEY=VAL Set the package spec attribute <KEY> to <VAL>, where
<VAL> may be JSON.
-s,--string-attribute KEY=VAL
Set the package spec attribute <KEY> to <VAL>.
-b,--branch BRANCH Equivalent to --attribute branch=<BRANCH> -b,--branch BRANCH Equivalent to --attribute branch=<BRANCH>
-o,--owner OWNER Equivalent to --attribute owner=<OWNER> -o,--owner OWNER Equivalent to --attribute owner=<OWNER>
-r,--repo REPO Equivalent to --attribute repo=<REPO> -r,--repo REPO Equivalent to --attribute repo=<REPO>

View File

@ -11,6 +11,8 @@ module Niv.Cli where
import Control.Applicative import Control.Applicative
import Control.Monad import Control.Monad
import Data.Aeson ((.=)) import Data.Aeson ((.=))
import Data.Bifunctor
import Data.Maybe
import Data.Char (isSpace) import Data.Char (isSpace)
import Data.Functor import Data.Functor
import Data.HashMap.Strict.Extended import Data.HashMap.Strict.Extended
@ -70,45 +72,57 @@ parsePackageName = PackageName <$>
parsePackageSpec :: Opts.Parser PackageSpec parsePackageSpec :: Opts.Parser PackageSpec
parsePackageSpec = parsePackageSpec =
(PackageSpec . HMS.fromList . fmap fixupAttributes) <$> (PackageSpec . HMS.fromList) <$>
many parseAttribute many parseAttribute
where where
parseAttribute :: Opts.Parser (T.Text, T.Text) parseAttribute :: Opts.Parser (T.Text, Aeson.Value)
parseAttribute = parseAttribute =
Opts.option (Opts.maybeReader parseKeyVal) Opts.option (Opts.maybeReader parseKeyValJSON)
( Opts.long "attribute" <> ( Opts.long "attribute" <>
Opts.short 'a' <> Opts.short 'a' <>
Opts.metavar "KEY=VAL" <> Opts.metavar "KEY=VAL" <>
Opts.help "Set the package spec attribute <KEY> to <VAL>" Opts.help "Set the package spec attribute <KEY> to <VAL>, where <VAL> may be JSON."
) <|> shortcutAttributes <|> ) <|>
(("url_template",) <$> Opts.strOption Opts.option (Opts.maybeReader (parseKeyVal (Aeson.String . T.pack)))
( Opts.long "string-attribute" <>
Opts.short 's' <>
Opts.metavar "KEY=VAL" <>
Opts.help "Set the package spec attribute <KEY> to <VAL>."
) <|>
shortcutAttributes <|>
((\x -> ("url_template",Aeson.String x)) <$> Opts.strOption
( Opts.long "template" <> ( Opts.long "template" <>
Opts.short 't' <> Opts.short 't' <>
Opts.metavar "URL" <> Opts.metavar "URL" <>
Opts.help "Used during 'update' when building URL. Occurrences of <foo> are replaced with attribute 'foo'." Opts.help "Used during 'update' when building URL. Occurrences of <foo> are replaced with attribute 'foo'."
)) <|> )) <|>
(("type",) <$> Opts.strOption ((\x -> ("type", Aeson.String x)) <$> Opts.strOption
( Opts.long "type" <> ( Opts.long "type" <>
Opts.short 'T' <> Opts.short 'T' <>
Opts.metavar "TYPE" <> Opts.metavar "TYPE" <>
Opts.help "The type of the URL target. The value can be either 'file' or 'tarball'. If not set, the value is inferred from the suffix of the URL." Opts.help "The type of the URL target. The value can be either 'file' or 'tarball'. If not set, the value is inferred from the suffix of the URL."
)) ))
-- Parse "key=val" into ("key", "val") parseKeyValJSON = parseKeyVal $ \x ->
parseKeyVal :: String -> Maybe (T.Text, T.Text) fromMaybe (Aeson.String $ T.pack x) (Aeson.decodeStrict (B8.pack x))
parseKeyVal str = case span (/= '=') str of
(key, '=':val) -> Just (T.pack key, T.pack val) -- Parse "key=val" into ("key", val)
parseKeyVal
:: (String -> Aeson.Value) -- ^ how to convert to JSON
-> String -> Maybe (T.Text, Aeson.Value)
parseKeyVal toJSON str = case span (/= '=') str of
(key, '=':val) -> Just (T.pack key, toJSON val)
_ -> Nothing _ -> Nothing
-- Shortcuts for common attributes -- Shortcuts for common attributes
shortcutAttributes :: Opts.Parser (T.Text, T.Text) shortcutAttributes :: Opts.Parser (T.Text, Aeson.Value)
shortcutAttributes = foldr (<|>) empty $ mkShortcutAttribute <$> shortcutAttributes = foldr (<|>) empty $ mkShortcutAttribute <$>
[ "branch", "owner", "repo", "version" ] [ "branch", "owner", "repo", "version" ]
-- TODO: infer those shortcuts from 'Update' keys -- TODO: infer those shortcuts from 'Update' keys
mkShortcutAttribute :: T.Text -> Opts.Parser (T.Text, T.Text) mkShortcutAttribute :: T.Text -> Opts.Parser (T.Text, Aeson.Value)
mkShortcutAttribute = \case mkShortcutAttribute = \case
attr@(T.uncons -> Just (c,_)) -> (attr,) <$> Opts.strOption attr@(T.uncons -> Just (c,_)) -> fmap (second Aeson.String) $ (attr,) <$> Opts.strOption
( Opts.long (T.unpack attr) <> ( Opts.long (T.unpack attr) <>
Opts.short c <> Opts.short c <>
Opts.metavar (T.unpack $ T.toUpper attr) <> Opts.metavar (T.unpack $ T.toUpper attr) <>
@ -120,9 +134,6 @@ parsePackageSpec =
) )
_ -> empty _ -> empty
fixupAttributes :: (T.Text, T.Text) -> (T.Text, Aeson.Value)
fixupAttributes (k, v) = (k, Aeson.String v)
parsePackage :: Opts.Parser (PackageName, PackageSpec) parsePackage :: Opts.Parser (PackageName, PackageSpec)
parsePackage = (,) <$> parsePackageName <*> parsePackageSpec parsePackage = (,) <$> parsePackageName <*> parsePackageSpec