1
1
mirror of https://github.com/nmattia/niv.git synced 2024-09-19 11:27:40 +03:00

Fix parsing of subcommands

This commit is contained in:
Nicolas Mattia 2019-11-24 14:46:33 +01:00
parent c8b5412835
commit 1e7abae029
5 changed files with 73 additions and 37 deletions

View File

@ -209,7 +209,7 @@ Available options:
Available commands: Available commands:
init Initialize a Nix project. Existing files won't be init Initialize a Nix project. Existing files won't be
modified. modified.
add Add dependency add Add a GitHub dependency
show show
update Update dependencies update Update dependencies
modify Modify dependency modify Modify dependency
@ -226,11 +226,11 @@ Examples:
niv add NixOS/nixpkgs-channels -n nixpkgs -b nixos-19.03 niv add NixOS/nixpkgs-channels -n nixpkgs -b nixos-19.03
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 PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |
[-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] | [-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])
Add dependency Add a GitHub dependency
Available options: Available options:
-n,--name NAME Set the package name to <NAME> -n,--name NAME Set the package name to <NAME>
@ -250,8 +250,8 @@ Available options:
-h,--help Show this help text -h,--help Show this help text
Experimental commands: Experimental commands:
git Echo a message back git Add a git dependency. Experimental.
github Add dependency github Add a GitHub dependency
``` ```

View File

@ -12,7 +12,6 @@ import Control.Applicative
import Control.Monad import Control.Monad
import Data.Aeson ((.=)) import Data.Aeson ((.=))
import Data.Char (isSpace) import Data.Char (isSpace)
import Data.Functor
import Data.HashMap.Strict.Extended import Data.HashMap.Strict.Extended
import Data.Hashable (Hashable) import Data.Hashable (Hashable)
import Data.String.QQ (s) import Data.String.QQ (s)
@ -141,38 +140,67 @@ cmdInit = do
parseCmdAdd :: Opts.ParserInfo (IO ()) parseCmdAdd :: Opts.ParserInfo (IO ())
parseCmdAdd = parseCmdAdd =
Opts.info Opts.info
((sp <|> shortcutGitHub) <**> Opts.helper) $ ((parseCommands <|> parseShortcuts) <**> Opts.helper) $
(description githubCmd) (description githubCmd)
where where
shortcutGitHub = uncurry (cmdAdd (updateCmd githubCmd)) <$> parseArgs -- XXX: this should parse many shortcuts (github, git). Right now we only
-- parse GitHub because the git interface is still experimental. note to
-- implementer: it'll be tricky to have the correct arguments show up
-- without repeating "PACKAGE PACKAGE PACKAGE" for every package type.
parseShortcuts = parseShortcut githubCmd
parseShortcut cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseShortcutArgs cmd)
parseCmd cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseCmdArgs cmd)
parseCmdAddGit = parseCmdAddGit =
Opts.info Opts.info (parseCmd gitCmd <**> Opts.helper) (description gitCmd)
(uncurry (cmdAdd (updateCmd gitCmd)) <$> parseArgs <**> Opts.helper) $
(description gitCmd)
parseCmdAddGitHub = parseCmdAddGitHub =
Opts.info Opts.info (parseCmd githubCmd <**> Opts.helper) (description githubCmd)
(uncurry (cmdAdd (updateCmd githubCmd)) <$> parseArgs <**> Opts.helper) $ parseCommands = Opts.subparser
(description githubCmd)
sp = Opts.subparser
( Opts.hidden <> ( Opts.hidden <>
Opts.commandGroup "Experimental commands:" <> Opts.commandGroup "Experimental commands:" <>
Opts.command "git" parseCmdAddGit <> Opts.command "git" parseCmdAddGit <>
Opts.command "github" parseCmdAddGitHub Opts.command "github" parseCmdAddGitHub
) )
parseArgs :: Opts.Parser (PackageName, Attrs) -- | only used in shortcuts (niv add foo/bar ...) because PACKAGE is NOT
parseArgs = collapse <$> parseNameAndShortcut <*> (parsePackageSpec githubCmd) -- optional
parseShortcutArgs :: Cmd -> Opts.Parser (PackageName, Attrs)
parseShortcutArgs cmd = collapse <$> parseNameAndShortcut <*> parsePackageSpec cmd
where
collapse specAndName pspec = (pname, specToLockedAttrs $ pspec <> baseSpec)
where
(pname, baseSpec) = case specAndName of
((_, spec), Just pname') -> (pname', PackageSpec spec)
((pname', spec), Nothing) -> (pname', PackageSpec spec)
parseNameAndShortcut = parseNameAndShortcut =
(,) <$> (,) <$>
optName <*> Opts.argument
(Opts.strArgument (Opts.metavar "PACKAGE") <&> (parseShortcut githubCmd)) (Opts.maybeReader (parseCmdShortcut cmd . T.pack))
-- collaspe a "name or shortcut" with package spec (Opts.metavar "PACKAGE") <*>
collapse nameAndSpec pspec = (pname, specToLockedAttrs $ pspec <> baseSpec) optName
optName = Opts.optional $ PackageName <$> Opts.strOption
( Opts.long "name" <>
Opts.short 'n' <>
Opts.metavar "NAME" <>
Opts.help "Set the package name to <NAME>"
)
-- | only used in command (niv add <cmd> ...) because PACKAGE is optional
parseCmdArgs :: Cmd -> Opts.Parser (PackageName, Attrs)
parseCmdArgs cmd = collapse <$> parseNameAndShortcut <*> parsePackageSpec cmd
where
collapse specAndName pspec = (pname, specToLockedAttrs $ pspec <> baseSpec)
where where
(pname, baseSpec) = case nameAndSpec of (pname, baseSpec) = case specAndName of
(Just pname', (_, spec)) -> (pname', PackageSpec spec) (Just (_, spec), Just pname') -> (pname', PackageSpec spec)
(Nothing, (pname', spec)) -> (pname', PackageSpec spec) (Just (pname', spec), Nothing) -> (pname', PackageSpec spec)
(Nothing, Just pname') -> (pname', PackageSpec HMS.empty)
(Nothing, Nothing) -> (PackageName "unnamed", PackageSpec HMS.empty)
parseNameAndShortcut =
(,) <$>
Opts.optional (Opts.argument
(Opts.maybeReader (parseCmdShortcut cmd . T.pack))
(Opts.metavar "PACKAGE")) <*>
optName
optName = Opts.optional $ PackageName <$> Opts.strOption optName = Opts.optional $ PackageName <$> Opts.strOption
( Opts.long "name" <> ( Opts.long "name" <>
Opts.short 'n' <> Opts.short 'n' <>

View File

@ -11,8 +11,7 @@ import qualified Options.Applicative as Opts
-- TODO: add filter -- TODO: add filter
data Cmd = Cmd data Cmd = Cmd
{ description :: forall a. Opts.InfoMod a { description :: forall a. Opts.InfoMod a
-- TODO: should be "Maybe" , parseCmdShortcut :: T.Text -> Maybe (PackageName, Aeson.Object)
, parseShortcut :: T.Text -> (PackageName, Aeson.Object)
, parsePackageSpec :: Opts.Parser PackageSpec , parsePackageSpec :: Opts.Parser PackageSpec
, updateCmd :: Update () () , updateCmd :: Update () ()
, name :: T.Text , name :: T.Text

View File

@ -4,20 +4,27 @@ module Niv.Git.Cmd (gitCmd) where
import Niv.Cmd import Niv.Cmd
import qualified Options.Applicative as Opts import qualified Options.Applicative as Opts
import qualified Options.Applicative.Help.Pretty as Opts
gitCmd :: Cmd gitCmd :: Cmd
gitCmd = Cmd gitCmd = Cmd
{ description = describeGit { description = describeGit
, parseShortcut = error "no parse for git" , parseCmdShortcut = pure Nothing
, parsePackageSpec = pure mempty , parsePackageSpec = pure mempty
, updateCmd = undefined , updateCmd = error "git update is not implemented yet"
, name = "git" , name = "git"
} }
describeGit :: Opts.InfoMod a describeGit :: Opts.InfoMod a
describeGit = mconcat describeGit = mconcat
[ Opts.fullDesc [ Opts.fullDesc
, Opts.progDesc "Echo a message back" , Opts.progDesc "Add a git dependency. Experimental."
, Opts.headerDoc $ Just $
"Examples:" Opts.<$$>
"" Opts.<$$>
" niv add git@github.com:stedolan/jq" Opts.<$$>
" niv add ssh://git@github.com/stedolan/jq" Opts.<$$>
" niv add https://github.com/stedolan/jq.git"
] ]
-- for git: -- for git:

View File

@ -30,7 +30,7 @@ import qualified Options.Applicative.Help.Pretty as Opts
githubCmd :: Cmd githubCmd :: Cmd
githubCmd = Cmd githubCmd = Cmd
{ description = describeGitHub { description = describeGitHub
, parseShortcut = parseAddShortcutGitHub , parseCmdShortcut = parseAddShortcutGitHub
, parsePackageSpec = parseGitHubPackageSpec , parsePackageSpec = parseGitHubPackageSpec
, updateCmd = githubUpdate' , updateCmd = githubUpdate'
, name = "github" , name = "github"
@ -104,7 +104,7 @@ parseGitHubPackageSpec =
describeGitHub :: Opts.InfoMod a describeGitHub :: Opts.InfoMod a
describeGitHub = mconcat describeGitHub = mconcat
[ Opts.fullDesc [ Opts.fullDesc
, Opts.progDesc "Add dependency" , Opts.progDesc "Add a GitHub dependency"
, Opts.headerDoc $ Just $ , Opts.headerDoc $ Just $
"Examples:" Opts.<$$> "Examples:" Opts.<$$>
"" Opts.<$$> "" Opts.<$$>
@ -114,17 +114,19 @@ describeGitHub = mconcat
] ]
-- parse a github shortcut of the form "owner/repo" -- parse a github shortcut of the form "owner/repo"
parseAddShortcutGitHub :: T.Text -> (PackageName, Aeson.Object) parseAddShortcutGitHub :: T.Text -> Maybe (PackageName, Aeson.Object)
parseAddShortcutGitHub str = -- Opts.strArgument (Opts.metavar "PACKAGE") <&> parseAddShortcutGitHub str =
-- parses a string "owner/repo" into package name (repo) and spec (owner + -- parses a string "owner/repo" into package name (repo) and spec (owner +
-- repo) -- repo)
case T.span (/= '/') str of case T.span (/= '/') str of
(owner@(T.null -> False) (owner@(T.null -> False)
, T.uncons -> Just ('/', repo@(T.null -> False))) -> , T.uncons -> Just ('/', repo@(T.null -> False))) -> Just
( PackageName repo ( PackageName repo
, HMS.fromList [ "owner" .= owner, "repo" .= repo ]) , HMS.fromList [ "owner" .= owner, "repo" .= repo ])
_ -> (PackageName str, HMS.empty) -- XXX: this should be "Nothing" but for the time being we keep
-- backwards compatibility with "niv add foo" adding "foo" as a
-- package name.
_ -> Just (PackageName str, HMS.empty)
-- | The IO (real) github update -- | The IO (real) github update
githubUpdate' :: Update () () githubUpdate' :: Update () ()