Skip to content

Commit a4e2e12

Browse files
authored
Extract applyAdd and infer command from args (#437)
* Extract applyAdd and infer command from args * Fixup
1 parent 8272c93 commit a4e2e12

7 files changed

Lines changed: 115 additions & 49 deletions

File tree

src/Niv/Cli.hs

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -256,31 +256,24 @@ cmdInit nixpkgs = do
256256
dontCreateFile path = say $ "Not creating " <> path
257257

258258
initNixpkgs :: FetchNixpkgs -> NIO ()
259-
initNixpkgs nixpkgs =
259+
initNixpkgs nixpkgs = modifySources $ \sources -> do
260260
case nixpkgs of
261-
NoNixpkgs -> say "Not importing 'nixpkgs'."
261+
NoNixpkgs -> say "Not importing 'nixpkgs'." >> pure sources
262262
NixpkgsFast -> do
263263
say "Using known 'nixpkgs' ..."
264264
packageSpec <- HTTP.getResponseBody <$> HTTP.httpJSON "https://raw.githubusercontent.com/nmattia/niv/master/data/nixpkgs.json"
265-
cmdAdd
266-
githubCmd
267-
(PackageName "nixpkgs")
268-
(specToLockedAttrs packageSpec)
269-
pure ()
270-
NixpkgsCustom branch nixpkgs' -> do
265+
applyAdd sources (PackageName "nixpkgs", packageSpec)
266+
NixpkgsCustom branch (Nixpkgs owner repo) -> do
271267
say "Importing 'nixpkgs' ..."
272-
let (owner, repo) = case nixpkgs' of
273-
Nixpkgs o r -> (o, r)
274-
cmdAdd
275-
githubCmd
276-
(PackageName "nixpkgs")
277-
( specToFreeAttrs $
278-
PackageSpec $
279-
KM.fromList
280-
[ "owner" .= owner,
281-
"repo" .= repo,
282-
"branch" .= branch
283-
]
268+
applyAdd
269+
sources
270+
( PackageName "nixpkgs",
271+
PackageSpec $
272+
KM.fromList
273+
[ "owner" .= owner,
274+
"repo" .= repo,
275+
"branch" .= branch
276+
]
284277
)
285278

286279
-------------------------------------------------------------------------------
@@ -298,8 +291,8 @@ parseCmdAdd =
298291
-- implementer: it'll be tricky to have the correct arguments show up
299292
-- without repeating "PACKAGE PACKAGE PACKAGE" for every package type.
300293
parseShortcuts = parseShortcut githubCmd
301-
parseShortcut cmd = uncurry (cmdAdd cmd) <$> parseShortcutArgs cmd
302-
parseCmd cmd = uncurry (cmdAdd cmd) <$> parseCmdArgs cmd
294+
parseShortcut cmd = uncurry cmdAdd <$> parseShortcutArgs cmd
295+
parseCmd cmd = uncurry cmdAdd <$> parseCmdArgs cmd
303296
parseCmdAddGit =
304297
Opts.info (parseCmd gitCmd <**> Opts.helper) (description gitCmd)
305298
parseCmdAddLocal =
@@ -370,20 +363,32 @@ parseCmdArgs cmd = collapse <$> parseNameAndShortcut <*> parsePackageSpec cmd
370363
<> Opts.help "Set the package name to <NAME>"
371364
)
372365

373-
cmdAdd :: Cmd -> PackageName -> Attrs -> NIO ()
374-
cmdAdd cmd packageName attrs = do
366+
cmdAdd :: PackageName -> Attrs -> NIO ()
367+
cmdAdd packageName attrs = do
375368
job ("Adding package " <> T.unpack (unPackageName packageName)) $ do
376-
modifySources $ \(unSources -> sources) -> do
377-
when (HMS.member packageName sources) $
378-
li $
379-
abortCannotAddPackageExists packageName
380-
eFinalSpec <- fmap attrsToSpec <$> li (doUpdate attrs cmd)
381-
case eFinalSpec of
382-
Left e -> li (abortUpdateFailed [(packageName, e)])
383-
Right finalSpec -> do
384-
pure $
385-
Sources $
386-
HMS.insert packageName finalSpec sources
369+
let spec = attrsToSpec attrs
370+
modifySources $ \sources -> applyAdd sources (packageName, spec)
371+
372+
applyAdd :: Sources -> (PackageName, PackageSpec) -> NIO Sources
373+
applyAdd (unSources -> sources) (packageName, defaultSpec) = do
374+
cmds <- getCmds
375+
376+
-- infer what command (git, github, etc) to use to add the package
377+
cmd <- case inferCmd cmds defaultSpec of
378+
Just cmd -> pure cmd
379+
Nothing -> li $ abortNoSuitableCommandForAdd packageName
380+
381+
when (HMS.member packageName sources) $
382+
li $
383+
abortCannotAddPackageExists packageName
384+
385+
let attrs = specToLockedAttrs defaultSpec
386+
eFinalSpec <- fmap attrsToSpec <$> li (doUpdate attrs cmd)
387+
finalSpec <- case eFinalSpec of
388+
Left e -> li (abortUpdateFailed [(packageName, e)])
389+
Right finalSpec -> pure finalSpec
390+
391+
pure $ Sources $ HMS.insert packageName finalSpec sources
387392

388393
-------------------------------------------------------------------------------
389394
-- SHOW
@@ -464,7 +469,7 @@ updatePackage packageName defaultSpec mSpec = do
464469
-- infer what command (git, github, etc) to use to update the package
465470
cmd <- case inferCmd cmds defaultSpec of
466471
Just cmd -> pure cmd
467-
Nothing -> li $ abortNoSuitableCommand packageName
472+
Nothing -> li $ abortNoSuitableCommandForUpdate packageName
468473

469474
job ("Update " <> T.unpack (unPackageName packageName)) $
470475
fmap attrsToSpec <$> li (doUpdate attrs cmd)
@@ -772,6 +777,10 @@ abortUpdateFailed errs =
772777
)
773778
errs
774779

775-
abortNoSuitableCommand :: PackageName -> IO a
776-
abortNoSuitableCommand pname =
780+
abortNoSuitableCommandForUpdate :: PackageName -> IO a
781+
abortNoSuitableCommandForUpdate pname =
777782
abort $ "Don't know how to update package: " <> unPackageName pname
783+
784+
abortNoSuitableCommandForAdd :: PackageName -> IO a
785+
abortNoSuitableCommandForAdd pname =
786+
abort $ "Don't know how to add package: " <> unPackageName pname

src/Niv/Cmd.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import qualified Options.Applicative as Opts
1010

1111
data Cmd = Cmd
1212
{ description :: forall a. Opts.InfoMod a,
13+
-- | Important: if an object is returned, then it should be accepted by 'acceptsCmd'
1314
parseCmdShortcut :: T.Text -> Maybe (PackageName, Aeson.Object),
15+
16+
-- | Important: if an object is returned, then it should be accepted by 'acceptsCmd'
1417
parsePackageSpec :: Opts.Parser PackageSpec,
1518
updateCmd :: Update () (),
1619
name :: T.Text,

src/Niv/Git/Cmd.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Niv.Git.Cmd where
88

99
import Control.Applicative
1010
import Control.Arrow
11+
import Data.Aeson ((.=))
1112
import qualified Data.Aeson as Aeson
1213
import qualified Data.Aeson.Key as K
1314
import qualified Data.Aeson.KeyMap as KM
@@ -64,8 +65,8 @@ parseGitShortcut txt'@(T.dropWhileEnd (== '/') -> txt) =
6465
then case T.splitOn "/" txt of
6566
[] -> Nothing
6667
(last -> w) -> case T.stripSuffix ".git" w of
67-
Nothing -> Just (PackageName w, KM.singleton "repo" (Aeson.String txt'))
68-
Just w' -> Just (PackageName w', KM.singleton "repo" (Aeson.String txt'))
68+
Nothing -> Just (PackageName w, KM.fromList [ "repo" .= txt', "type" .= Aeson.String "git" ])
69+
Just w' -> Just (PackageName w', KM.fromList [ "repo" .= txt', "type" .= Aeson.String "git" ])
6970
else Nothing
7071
where
7172
isGitURL =
@@ -78,7 +79,7 @@ parseGitShortcut txt'@(T.dropWhileEnd (== '/') -> txt) =
7879

7980
parseGitPackageSpec :: Opts.Parser PackageSpec
8081
parseGitPackageSpec =
81-
PackageSpec . KM.fromList
82+
PackageSpec . KM.fromList . (["type" .= Aeson.String "git"] <> )
8283
<$> many (parseRepo <|> parseBranch <|> parseRev <|> parseAttr <|> parseSAttr)
8384
where
8485
parseRepo =

src/Niv/Git/Test.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Niv.Git.Test
66
)
77
where
88

9+
import Data.Aeson ((.=))
10+
import qualified Data.Aeson as Aeson
911
import Control.Monad
1012
import qualified Data.Aeson.KeyMap as KM
1113
import Data.Bifunctor
@@ -30,21 +32,21 @@ test_repositoryParse =
3032
Tasty.testCase "git@github.com:nmattia/niv" $
3133
parseGitShortcut "git@github.com:nmattia/niv"
3234
@=? Just
33-
(PackageName "niv", KM.singleton "repo" "git@github.com:nmattia/niv"),
35+
(PackageName "niv", KM.fromList [ "repo" .= Aeson.String "git@github.com:nmattia/niv" , "type" .= Aeson.String "git" ]),
3436
Tasty.testCase "ssh://git@github.com/stedolan/jq" $
3537
parseGitShortcut "ssh://git@github.com/stedolan/jq"
3638
@=? Just
37-
(PackageName "jq", KM.singleton "repo" "ssh://git@github.com/stedolan/jq"),
39+
(PackageName "jq", KM.fromList [ "repo" .= Aeson.String "ssh://git@github.com/stedolan/jq", "type" .= Aeson.String "git" ]),
3840
Tasty.testCase "https://github.com/stedolan/jq.git" $
3941
parseGitShortcut "https://github.com/stedolan/jq.git"
4042
@=? Just
41-
(PackageName "jq", KM.singleton "repo" "https://github.com/stedolan/jq.git"),
43+
(PackageName "jq", KM.fromList [ "repo" .= Aeson.String "https://github.com/stedolan/jq.git", "type" .= Aeson.String "git" ]),
4244
Tasty.testCase "https://github.com/stedolan/jq" $
4345
parseGitShortcut "https://github.com/stedolan/jq" @=? Nothing,
4446
Tasty.testCase "~/path/to/repo.git" $
4547
parseGitShortcut "~/path/to/repo.git"
4648
@=? Just
47-
(PackageName "repo", KM.singleton "repo" "~/path/to/repo.git")
49+
(PackageName "repo", KM.fromList [ "repo" .= Aeson.String "~/path/to/repo.git", "type" .= Aeson.String "git" ])
4850
]
4951

5052
test_gitUpdates :: Tasty.TestTree

src/Niv/Local/Cmd.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ parseLocalShortcut txt =
3636
if T.isPrefixOf "./" txt || T.isPrefixOf "/" txt
3737
then do
3838
let n = last $ T.splitOn "/" txt
39-
Just (PackageName n, KM.fromList [("path", Aeson.String txt)])
39+
Just (PackageName n, KM.fromList [("path", Aeson.String txt), ("type", Aeson.String "local")])
4040
else Nothing
4141

4242
parseLocalPackageSpec :: Opts.Parser PackageSpec
43-
parseLocalPackageSpec = PackageSpec . KM.fromList <$> parseParams
43+
parseLocalPackageSpec = PackageSpec . KM.fromList . ([("type", Aeson.String "local")] <> ) <$> parseParams
4444
where
4545
parseParams :: Opts.Parser [(K.Key, Aeson.Value)]
4646
parseParams = maybe [] pure <$> Opts.optional parsePath
@@ -61,6 +61,6 @@ describeLocal =
6161
Opts.vcat
6262
[ "Examples:",
6363
"",
64-
" niv add local ./foo/bar"
64+
" niv add local --name some-package --path ./foo/bar"
6565
]
6666
]

tests/default.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ let
1717
eval = collectResults "eval-tests" (import ./eval { inherit pkgs niv; });
1818
github = collectResults "github-tests" (import ./github { inherit pkgs niv; });
1919
git = collectResults "git-tests" (import ./git { inherit pkgs niv; });
20+
local = collectResults "local-tests" (import ./local { inherit pkgs niv; });
2021

2122
in
2223

23-
{ inherit eval github git; }
24+
{ inherit eval github git local; }

tests/local/default.nix

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{ pkgs, niv }:
2+
3+
{
4+
local =
5+
pkgs.runCommand "local-test"
6+
{ nativeBuildInputs = [ niv pkgs.nix pkgs.jq ]; }
7+
(
8+
9+
''
10+
# don't use /nix/store (even evaluation adds files to the store)
11+
# https://github.com/NixOS/nix/issues/3258
12+
export NIX_REMOTE="local?root=$TMPDIR/local-test-store"
13+
export NIX_STATE_DIR=$TMPDIR
14+
15+
export HOME="$TMPDIR/homeless"
16+
17+
# custom nix.conf
18+
export NIX_USER_CONF_FILES=$(mktemp)
19+
echo 'extra-experimental-features = nix-command flakes' >> "$NIX_USER_CONF_FILES"
20+
21+
# create a dir
22+
23+
localdir="my-dir"
24+
mkdir -p "$localdir"
25+
pushd $localdir > /dev/null
26+
echo hello > file
27+
echo world >> file
28+
popd > /dev/null
29+
30+
# then we niv add the dir containing the files
31+
32+
nivdir=$(mktemp -d)
33+
pushd $nivdir > /dev/null
34+
mkdir -p nix
35+
echo "{}" > nix/sources.json
36+
niv init --latest
37+
niv add local --name my-dir --path=$localdir
38+
39+
nivdir=$(nix eval --json --impure --expr '(import ./nix/sources.nix).my-dir.path' | jq -r)
40+
if [ ! "$localdir" = "$nivdir" ]; then
41+
echo "Mismatched dirs: $localdir != $nivdir"
42+
exit 42
43+
fi
44+
45+
popd > /dev/null
46+
47+
touch $out
48+
''
49+
);
50+
}

0 commit comments

Comments
 (0)