diff --git a/README.md b/README.md index 407631a..4ded287 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,7 @@ Available options: Experimental commands: git Add a git dependency. Experimental. github Add a GitHub dependency + local Add a local dependency. Experimental. ``` #### Update diff --git a/default.nix b/default.nix index 7633431..06dc489 100644 --- a/default.nix +++ b/default.nix @@ -35,6 +35,7 @@ with rec "^src/Niv$" "^src/Niv/Git$" "^src/Niv/GitHub$" + "^src/Niv/Local$" "^src/Niv/Sources$" "^src/Niv/Update$" "^src.*.hs$" diff --git a/nix/sources.nix b/nix/sources.nix index 45c97d1..7bd0f3e 100644 --- a/nix/sources.nix +++ b/nix/sources.nix @@ -26,6 +26,8 @@ let fetch_git = spec: builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; }; + fetch_local = spec: spec.path; + fetch_builtin-tarball = name: throw ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. $ niv modify ${name} -a type=tarball -a builtin=true''; @@ -65,6 +67,7 @@ let else if spec.type == "file" then fetch_file pkgs spec else if spec.type == "tarball" then fetch_tarball pkgs name spec else if spec.type == "git" then fetch_git spec + else if spec.type == "local" then fetch_local spec else if spec.type == "builtin-tarball" then fetch_builtin-tarball name else if spec.type == "builtin-url" then fetch_builtin-url name else diff --git a/src/Niv/Cli.hs b/src/Niv/Cli.hs index 9dbdf1e..e0e3f02 100644 --- a/src/Niv/Cli.hs +++ b/src/Niv/Cli.hs @@ -19,6 +19,7 @@ import Data.Text.Extended import Data.Version (showVersion) import Niv.Cmd import Niv.Git.Cmd +import Niv.Local.Cmd import Niv.GitHub.Cmd import Niv.Logger import Niv.Sources @@ -190,13 +191,16 @@ parseCmdAdd = parseCmd cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseCmdArgs cmd) parseCmdAddGit = Opts.info (parseCmd gitCmd <**> Opts.helper) (description gitCmd) + parseCmdAddLocal = + Opts.info (parseCmd localCmd <**> Opts.helper) (description localCmd) parseCmdAddGitHub = Opts.info (parseCmd githubCmd <**> Opts.helper) (description githubCmd) parseCommands = Opts.subparser ( Opts.hidden <> Opts.commandGroup "Experimental commands:" <> Opts.command "git" parseCmdAddGit <> - Opts.command "github" parseCmdAddGitHub + Opts.command "github" parseCmdAddGitHub <> + Opts.command "local" parseCmdAddLocal ) -- | only used in shortcuts (niv add foo/bar ...) because PACKAGE is NOT @@ -341,6 +345,7 @@ cmdUpdate = \case -- github let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of Just "git" -> gitCmd + Just "local" -> localCmd _ -> githubCmd fmap attrsToSpec <$> li (tryEvalUpdate (specToLockedAttrs cliSpec <> specToFreeAttrs defaultSpec) @@ -366,6 +371,7 @@ cmdUpdate = \case -- github let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of Just "git" -> gitCmd + Just "local" -> localCmd _ -> githubCmd finalSpec <- fmap attrsToSpec <$> li (tryEvalUpdate initialSpec diff --git a/src/Niv/Local/Cmd.hs b/src/Niv/Local/Cmd.hs new file mode 100644 index 0000000..385c803 --- /dev/null +++ b/src/Niv/Local/Cmd.hs @@ -0,0 +1,59 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE Arrows #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE ViewPatterns #-} + +module Niv.Local.Cmd where + +import Niv.Cmd +import Control.Arrow +import Niv.Sources +import Niv.Update +import qualified Data.Aeson as Aeson +import qualified Data.HashMap.Strict as HMS +import qualified Data.Text as T +import qualified Options.Applicative as Opts +import qualified Options.Applicative.Help.Pretty as Opts + +localCmd :: Cmd +localCmd = Cmd + { description = describeLocal + , parseCmdShortcut = parseLocalShortcut + , parsePackageSpec = parseLocalPackageSpec + , updateCmd = proc () -> do + useOrSet "type" -< ("local" :: Box T.Text) + returnA -< () + , name = "local" + } + +parseLocalShortcut :: T.Text -> Maybe (PackageName, Aeson.Object) +parseLocalShortcut txt = + if (T.isPrefixOf "./" txt || T.isPrefixOf "/" txt ) then do + let n = last $ T.splitOn "/" txt + Just (PackageName n, HMS.fromList [ ("path", Aeson.String txt) ]) + else Nothing + +parseLocalPackageSpec :: Opts.Parser PackageSpec +parseLocalPackageSpec = PackageSpec . HMS.fromList <$> parseParams + where + parseParams :: Opts.Parser [(T.Text, Aeson.Value)] + parseParams = maybe [] pure <$> Opts.optional parsePath + + parsePath = + ("path", ) . Aeson.String <$> Opts.strOption + ( Opts.long "path" <> + Opts.metavar "PATH" + ) + +describeLocal :: Opts.InfoMod a +describeLocal = mconcat + [ Opts.fullDesc + , Opts.progDesc "Add a local dependency. Experimental." + , Opts.headerDoc $ Just $ + "Examples:" Opts.<$$> + "" Opts.<$$> + " niv add local ./foo/bar" + ] diff --git a/src/Niv/Sources.hs b/src/Niv/Sources.hs index 54757cd..dff9eaa 100644 --- a/src/Niv/Sources.hs +++ b/src/Niv/Sources.hs @@ -148,6 +148,8 @@ data SourcesNixVersion | V15 | V16 | V17 + -- prettify derivation name + -- add 'local' type of sources | V18 deriving stock (Bounded, Enum, Eq) @@ -201,7 +203,7 @@ sourcesVersionToMD5 = \case V15 -> "dc11af910773ec9b4e505e0f49ebcfd2" V16 -> "2d93c52cab8e960e767a79af05ca572a" V17 -> "149b8907f7b08dc1c28164dfa55c7fad" - V18 -> "5fec8217a6e712c817f9de5289d85fbe" + V18 -> "bc5e6aefcaa6f9e0b2155ca4f44e5a33" -- | The MD5 sum of ./nix/sources.nix sourcesNixMD5 :: IO T.Text