niv 0.2.19 → 0.2.20
raw patch · 16 files changed
+496/−389 lines, 16 filesdep ~aeson
Dependency ranges changed: aeson
Files
- README.md +116/−48
- niv.cabal +4/−6
- nix/sources.nix +3/−1
- src/Data/HashMap/Strict/Extended.hs +3/−2
- src/Niv/Cli.hs +156/−125
- src/Niv/Cmd.hs +9/−10
- src/Niv/Git/Cmd.hs +30/−24
- src/Niv/Git/Test.hs +11/−10
- src/Niv/GitHub.hs +9/−6
- src/Niv/GitHub/API.hs +22/−46
- src/Niv/GitHub/Cmd.hs +18/−16
- src/Niv/GitHub/Test.hs +18/−18
- src/Niv/Local/Cmd.hs +10/−8
- src/Niv/Sources.hs +13/−5
- src/Niv/Update.hs +62/−53
- src/Niv/Update/Test.hs +12/−11
README.md view
@@ -1,6 +1,6 @@ # niv -+[](https://github.com/nmattia/niv/actions/workflows/test.yml) [](https://niv.nmattia.com) Painless dependencies for [Nix] projects. Read more in the [Getting started](#getting-started) section below.@@ -106,52 +106,43 @@ ``` The file `nix/sources.json` is the file used by niv to store versions and is-initialized with niv and nixpkgs:+initialized with nixpkgs: ``` json { "nixpkgs": {- "url": "https://github.com/NixOS/nixpkgs/archive/109a28ab954a0ad129f7621d468f829981b8b96c.tar.gz",+ "branch": "release-21.05",+ "description": "Nix Packages collection",+ "homepage": "", "owner": "NixOS",- "branch": "nixos-19.09",- "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz", "repo": "nixpkgs",- "sha256": "12wnxla7ld4cgpdndaipdh3j4zdalifk287ihxhnmrzrghjahs3q",- "description": "Nix Packages collection",- "rev": "109a28ab954a0ad129f7621d468f829981b8b96c"- },- "niv": {- "homepage": "https://github.com/nmattia/niv",- "url": "https://github.com/nmattia/niv/archive/72e77204544527279e8f1e2d982d29503482b8f4.tar.gz",- "owner": "nmattia",- "branch": "master",- "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",- "repo": "niv",- "sha256": "1zjcyzxhq9iwxh58j5d7sx1vz5s3r1f6gpmnfgj2a3rxmclwvn3c",- "description": "Easy dependency management for Nix projects",- "rev": "72e77204544527279e8f1e2d982d29503482b8f4"+ "rev": "5f244caea76105b63d826911b2a1563d33ff1cdc",+ "sha256": "1xlgynfw9svy7nvh9nkxsxdzncv9hg99gbvbwv3gmrhmzc3sar75",+ "type": "tarball",+ "url": "https://github.com/NixOS/nixpkgs/archive/5f244caea76105b63d826911b2a1563d33ff1cdc.tar.gz",+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz" } } ``` -To use those dependencies `import` the file `nix/sources.nix`, e.g.:+To use this dependency, `import` the file `nix/sources.nix`, e.g.: ``` nix { sources ? import ./sources.nix }: # import the sources-with- { overlay = _: pkgs:- { niv = import sources.niv {}; # use the sources :)- };- }; import sources.nixpkgs # and use them again!- { overlays = [ overlay ] ; config = {}; }+ { overlays = [] ; config = {}; } ``` +For more information about importing sources to your nix files, check+the [frequently asked questions](#Frequently-asked-questions).+ #### Tracking a nixpkgs branch -The `init` command sets the `nix/sources.json` file to track the latest commit-present on nixpkgs 19.09 when the command was run. Run the following command to-update it:+The `init` command sets the `nix/sources.json` to the content of the file+[data/nixpkgs.json](data/nixpkgs.json). Currently, you would be tracking the+`release-21.05` branch.+Run the following command to+update it to the last commit of the configured branch: ``` shell $ niv update nixpkgs@@ -160,7 +151,7 @@ To change the branch being tracked run this command: ``` shell-$ niv update nixpkgs -b nixos-19.09 # equivalent to --branch nixos-19.09+$ niv update nixpkgs -b master # equivalent to --branch master ``` #### Importing packages from GitHub@@ -219,7 +210,7 @@ ``` niv - dependency manager for Nix projects -version: 0.2.19+version: 0.2.20 Usage: niv [-s|--sources-file FILE] [--no-colors] COMMAND @@ -249,10 +240,11 @@ niv add NixOS/nixpkgs -n nixpkgs -b nixpkgs-unstable niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip -Usage: niv add PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |- [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |- [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |- [-t|--template URL] | [-T|--type TYPE])+Usage: niv add PACKAGE [-n|--name NAME] + [(-a|--attribute KEY=VAL) | (-s|--string-attribute KEY=VAL) | + (-b|--branch BRANCH) | (-o|--owner OWNER) | (-r|--rev REV) | + (-v|--version VERSION) | (-t|--template URL) | + (-T|--type TYPE)] Add a GitHub dependency Available options:@@ -287,10 +279,12 @@ niv update nixpkgs # update nixpkgs niv update my-package -v beta-0.2 # update my-package to version "beta-0.2" -Usage: niv update [PACKAGE] ([-a|--attribute KEY=VAL] |- [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |- [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |- [-t|--template URL] | [-T|--type TYPE])+Usage: niv update [PACKAGE + [(-a|--attribute KEY=VAL) | + (-s|--string-attribute KEY=VAL) | (-b|--branch BRANCH) | + (-o|--owner OWNER) | (-r|--rev REV) | + (-v|--version VERSION) | (-t|--template URL) | + (-T|--type TYPE)]] Update dependencies Available options:@@ -318,10 +312,11 @@ niv modify nixpkgs -v beta-0.2 niv modify nixpkgs -a branch=nixpkgs-unstable -Usage: niv modify PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |- [-s|--string-attribute KEY=VAL] | [-b|--branch BRANCH] |- [-o|--owner OWNER] | [-r|--rev REV] | [-v|--version VERSION] |- [-t|--template URL] | [-T|--type TYPE])+Usage: niv modify PACKAGE [-n|--name NAME] + [(-a|--attribute KEY=VAL) | (-s|--string-attribute KEY=VAL) | + (-b|--branch BRANCH) | (-o|--owner OWNER) | (-r|--rev REV) |+ (-v|--version VERSION) | (-t|--template URL) | + (-T|--type TYPE)] Modify dependency attributes without performing an update Available options:@@ -360,15 +355,19 @@ #### Init ```-Usage: niv init ([--no-nixpkgs] | [-b|--nixpkgs-branch ARG]- [--nixpkgs OWNER/REPO])+Usage: niv init [--fast | --latest | --nixpkgs OWNER/REPO+ (-b|--nixpkgs-branch ARG) |+ --no-nixpkgs] Initialize a Nix project. Existing files won't be modified. Available options:+ --fast Use the latest nixpkgs cached at+ 'https://github.com/nmattia/niv/blob/master/data/nixpkgs.json'.+ This is the default.+ --latest Pull the latest unstable nixpkgs from NixOS/nixpkgs.+ --nixpkgs OWNER/REPO Use a custom nixpkgs repository from GitHub.+ -b,--nixpkgs-branch ARG The nixpkgs branch when using --nixpkgs .... --no-nixpkgs Don't add a nixpkgs entry to sources.json.- -b,--nixpkgs-branch ARG The nixpkgs branch to use. (default: "release-20.03")- --nixpkgs OWNER/REPO Use a custom nixpkgs repository from- GitHub. (default: NixOS/nixpkgs) -h,--help Show this help text ``` @@ -389,6 +388,7 @@ ## Frequently Asked Questions * [Can I use private GitHub repositories?](#can-i-use-private-github-repositories)+* [How do I import and use the content of a source?](#how-do-i-import-and-use-the-content-of-a-source) * [How do I import a subpath of a source?](#how-do-i-import-a-subpath-of-a-source) * [How do I import NixOS modules](#how-do-i-import-nixos-modules) * [Can I use local packages?](#can-i-use-local-packages)@@ -426,6 +426,74 @@ ``` GITHUB_TOKEN=$YOUR_GITHUB_TOKEN niv add ... ```++### How do I import and use the content of a source?++The way to import a source depend mainly on the content targetted by this+source. A source could be a file, a repository with no knowledge of nix+or a repository already in the nix ecosystem.++#### 1. Direct import of a nix based source++In the case of a nix based source, you'll often find a `default.nix` at the+root. Let's take this repository as example. We can add it to our `sources.json`+with the following command.++``` shell+$ niv add nmattia/niv+```++We can now import niv to use it a nix expression, e.g.:++``` nix+{ sources ? import nix/sources.nix }:+let niv = import sources.niv {};+in { inherit niv; } # A glorious expression using the reference to niv+```++#### 2. Import of a nix based source via an overlay++Rather than use the resulting derivation directly, you can add it to your custom +nixpkgs via the overlay system.++``` nix+{ sources ? import nix/sources.nix}:+let overlay = _: pkgs: {+ niv = (import sources.niv {}).niv;+ };+ nixpkgs = import sources.nixpkgs { overlays = [ overlay ]; config = {}; };+in { inherit (nixpkgs) niv; } # A glorious expression where nixpkgs.niv is referenced+```++#### 3. Reference to the source's files in the nix store++You can also reference a simple file, a folder or a repo without nix knowledge+with niv. In these cases, you can use the source in your nix expression without+importing it.++The following exemple will compile gnu hello while using this technique to retrieve+the source. First, we need to add the new source.++``` shell+$ niv add hello-src -v 2.10 -t 'https://ftp.gnu.org/gnu/hello/hello-<version>.tar.gz'+```++Then, we can use it inside a nix expression.++``` nix+{ sources ? import nix/sources.nix }:+let hello_src = sources.hello-src;+ nixpkgs = import sources.nixpkgs {};+in nixpkgs.stdenv.mkDerivation {+ pname = "hello";+ version = "custom";+ src = hello_src;+}+```++:warning: If you have problems, consider using the outPath of the source+(e.g. `sources.hello-src.outPath`) instead of the source directly. See +[this issue](https://github.com/nmattia/niv/issues/325) for more details. ### How do I import a subpath of a source?
niv.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.34.6. -- -- see: https://github.com/sol/hpack------ hash: 6551d56f4a527a8b959ff8a47f1bf12e96efb5c6f62bb82d4c61cfb92ff1544f name: niv-version: 0.2.19+version: 0.2.20 synopsis: Easy dependency management for Nix projects description: Easy dependency management for Nix projects. category: Development@@ -86,7 +84,7 @@ app ghc-options: -Wall -optP-Wno-nonportable-include-path -main-is Niv.main build-depends:- aeson+ aeson >=2 , aeson-pretty , ansi-terminal , base <5@@ -118,7 +116,7 @@ app ghc-options: -Wall -optP-Wno-nonportable-include-path -main-is NivTest.main build-depends:- aeson+ aeson >=2 , aeson-pretty , ansi-terminal , base <5
nix/sources.nix view
@@ -31,8 +31,10 @@ if spec ? branch then "refs/heads/${spec.branch}" else if spec ? tag then "refs/tags/${spec.tag}" else abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";+ submodules = if spec ? submodules then spec.submodules else false; in- builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }+ // (if builtins.compareVersions builtins.nixVersion "2.4" >= 0 then { inherit submodules; } else {}); fetch_local = spec: spec.path;
src/Data/HashMap/Strict/Extended.hs view
@@ -26,8 +26,9 @@ HMS.HashMap k v1 -> m (HMS.HashMap k v2) mapWithKeyM f m = do- fmap mconcat $ forM (HMS.toList m) $ \(k, v) ->- HMS.singleton k <$> f k v+ fmap mconcat $+ forM (HMS.toList m) $ \(k, v) ->+ HMS.singleton k <$> f k v mapWithKeyM_ :: (Eq k, Hashable k, Monad m) =>
src/Niv/Cli.hs view
@@ -13,6 +13,8 @@ import Control.Monad.Reader import Data.Aeson ((.=)) import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as KM import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8 import Data.Char (isSpace)@@ -22,9 +24,9 @@ import qualified Data.Text as T import Data.Text.Extended import Data.Version (showVersion)+import qualified Network.HTTP.Simple as HTTP import Niv.Cmd import Niv.Git.Cmd-import Niv.GitHub.API (warnGitHubEnvVars) import Niv.GitHub.Cmd import Niv.Local.Cmd import Niv.Logger@@ -53,7 +55,6 @@ cli :: IO () cli = do- warnGitHubEnvVars ((fsj, colors), nio) <- execParserPure' Opts.defaultPrefs opts <$> getArgs >>= Opts.handleParseResult@@ -62,15 +63,16 @@ where execParserPure' pprefs pinfo [] = Opts.Failure $- Opts.parserFailure pprefs pinfo Opts.ShowHelpText mempty+ Opts.parserFailure pprefs pinfo (Opts.ShowHelpText Nothing) mempty execParserPure' pprefs pinfo args = Opts.execParserPure pprefs pinfo args opts = Opts.info ((,) <$> ((,) <$> parseFindSourcesJson <*> parseColors) <*> (parseCommand <**> Opts.helper <**> versionflag)) $ mconcat desc desc = [ Opts.fullDesc,- Opts.headerDoc $ Just $- "niv - dependency manager for Nix projects"- Opts.<$$> ""- Opts.<$$> "version:" Opts.<+> Opts.text (showVersion version)+ Opts.headerDoc $+ Just $+ "niv - dependency manager for Nix projects"+ Opts.<$$> ""+ Opts.<$$> "version:" Opts.<+> Opts.text (showVersion version) ] parseFindSourcesJson = AtPath@@ -119,55 +121,66 @@ -- | Whether or not to fetch nixpkgs data FetchNixpkgs = NoNixpkgs- | YesNixpkgs T.Text Nixpkgs -- branch, nixpkgs+ | NixpkgsFast -- Pull latest known nixpkgs+ | NixpkgsCustom T.Text Nixpkgs -- branch, nixpkgs+ deriving (Show) data Nixpkgs = Nixpkgs T.Text T.Text -- owner, repo instance Show Nixpkgs where show (Nixpkgs o r) = T.unpack o <> "/" <> T.unpack r --- | The default nixpkgs-defaultNixpkgsRepo, defaultNixpkgsUser, defaultNixpkgsBranch :: T.Text-defaultNixpkgsRepo = "nixpkgs"-defaultNixpkgsUser = "NixOS"-defaultNixpkgsBranch = "release-20.03"- parseCmdInit :: Opts.ParserInfo (NIO ()) parseCmdInit = Opts.info (cmdInit <$> parseNixpkgs <**> Opts.helper) $ mconcat desc where- customNixpkgsReader = Opts.maybeReader $ \(T.pack -> repo) -> case T.splitOn "/" repo of- [owner, reponame] -> Just (Nixpkgs owner reponame)- _ -> Nothing- parseNixpkgs =- Opts.flag'- NoNixpkgs- ( Opts.long "no-nixpkgs"- <> Opts.help "Don't add a nixpkgs entry to sources.json."- )- <|> ( YesNixpkgs- <$> ( Opts.strOption- ( Opts.long "nixpkgs-branch"- <> Opts.short 'b'- <> Opts.help "The nixpkgs branch to use."- <> Opts.showDefault- <> Opts.value defaultNixpkgsBranch- )- )- <*> Opts.option- customNixpkgsReader- ( Opts.long "nixpkgs"- <> Opts.showDefault- <> Opts.help "Use a custom nixpkgs repository from GitHub."- <> Opts.metavar "OWNER/REPO"- <> Opts.value (Nixpkgs defaultNixpkgsUser defaultNixpkgsRepo)- )- ) desc = [ Opts.fullDesc, Opts.progDesc "Initialize a Nix project. Existing files won't be modified." ] +parseNixpkgs :: Opts.Parser FetchNixpkgs+parseNixpkgs = parseNixpkgsFast <|> parseNixpkgsLatest <|> parseNixpkgsCustom <|> parseNoNixpkgs <|> pure NixpkgsFast+ where+ parseNixpkgsFast =+ Opts.flag'+ NixpkgsFast+ ( Opts.long "fast"+ <> Opts.help "Use the latest nixpkgs cached at 'https://github.com/nmattia/niv/blob/master/data/nixpkgs.json'. This is the default."+ )+ parseNixpkgsLatest =+ Opts.flag'+ (NixpkgsCustom "master" (Nixpkgs "NixOS" "nixpkgs"))+ ( Opts.long "latest"+ <> Opts.help "Pull the latest unstable nixpkgs from NixOS/nixpkgs."+ )+ parseNixpkgsCustom =+ (flip NixpkgsCustom)+ <$> ( Opts.option+ customNixpkgsReader+ ( Opts.long "nixpkgs"+ <> Opts.showDefault+ <> Opts.help "Use a custom nixpkgs repository from GitHub."+ <> Opts.metavar "OWNER/REPO"+ )+ )+ <*> ( Opts.strOption+ ( Opts.long "nixpkgs-branch"+ <> Opts.short 'b'+ <> Opts.help "The nixpkgs branch when using --nixpkgs ...."+ <> Opts.showDefault+ )+ )+ parseNoNixpkgs =+ Opts.flag'+ NoNixpkgs+ ( Opts.long "no-nixpkgs"+ <> Opts.help "Don't add a nixpkgs entry to sources.json."+ )+ customNixpkgsReader = Opts.maybeReader $ \(T.pack -> repo) -> case T.splitOn "/" repo of+ [owner, reponame] -> Just (Nixpkgs owner reponame)+ _ -> Nothing+ cmdInit :: FetchNixpkgs -> NIO () cmdInit nixpkgs = do job "Initializing" $ do@@ -187,33 +200,9 @@ ( pathNixSourcesJson fsj, \path -> do createFile path initNixSourcesJsonContent- -- Imports @niv@ and @nixpkgs@- say "Importing 'niv' ..."- cmdAdd- githubCmd- (PackageName "niv")- ( specToFreeAttrs $ PackageSpec $- HMS.fromList- [ "owner" .= ("nmattia" :: T.Text),- "repo" .= ("niv" :: T.Text)- ]- )- case nixpkgs of- NoNixpkgs -> say "Not importing 'nixpkgs'."- YesNixpkgs branch nixpkgs' -> do- say "Importing 'nixpkgs' ..."- let (owner, repo) = case nixpkgs' of- Nixpkgs o r -> (o, r)- cmdAdd- githubCmd- (PackageName "nixpkgs")- ( specToFreeAttrs $ PackageSpec $- HMS.fromList- [ "owner" .= owner,- "repo" .= repo,- "branch" .= branch- ]- ),++ -- Import nixpkgs, if necessary+ initNixpkgs nixpkgs, \path _content -> dontCreateFile path ) ]@@ -248,6 +237,34 @@ dontCreateFile :: FilePath -> NIO () dontCreateFile path = say $ "Not creating " <> path +initNixpkgs :: FetchNixpkgs -> NIO ()+initNixpkgs nixpkgs =+ case nixpkgs of+ NoNixpkgs -> say "Not importing 'nixpkgs'."+ NixpkgsFast -> do+ say "Using known 'nixpkgs' ..."+ packageSpec <- HTTP.getResponseBody <$> HTTP.httpJSON "https://raw.githubusercontent.com/nmattia/niv/master/data/nixpkgs.json"+ cmdAdd+ githubCmd+ (PackageName "nixpkgs")+ (specToLockedAttrs packageSpec)+ pure ()+ NixpkgsCustom branch nixpkgs' -> do+ say "Importing 'nixpkgs' ..."+ let (owner, repo) = case nixpkgs' of+ Nixpkgs o r -> (o, r)+ cmdAdd+ githubCmd+ (PackageName "nixpkgs")+ ( specToFreeAttrs $+ PackageSpec $+ KM.fromList+ [ "owner" .= owner,+ "repo" .= repo,+ "branch" .= branch+ ]+ )+ ------------------------------------------------------------------------------- -- ADD -------------------------------------------------------------------------------@@ -315,8 +332,8 @@ (pname, baseSpec) = case specAndName of (Just (_, spec), Just pname') -> (pname', PackageSpec spec) (Just (pname', spec), Nothing) -> (pname', PackageSpec spec)- (Nothing, Just pname') -> (pname', PackageSpec HMS.empty)- (Nothing, Nothing) -> (PackageName "unnamed", PackageSpec HMS.empty)+ (Nothing, Just pname') -> (pname', PackageSpec KM.empty)+ (Nothing, Nothing) -> (PackageName "unnamed", PackageSpec KM.empty) parseNameAndShortcut = (,) <$> Opts.optional@@ -340,16 +357,18 @@ job ("Adding package " <> T.unpack (unPackageName packageName)) $ do fsj <- getFindSourcesJson sources <- unSources <$> li (getSources fsj)- when (HMS.member packageName sources)- $ li- $ abortCannotAddPackageExists packageName+ when (HMS.member packageName sources) $+ li $+ abortCannotAddPackageExists packageName eFinalSpec <- fmap attrsToSpec <$> li (doUpdate attrs cmd) case eFinalSpec of Left e -> li (abortUpdateFailed [(packageName, e)]) Right finalSpec -> do say $ "Writing new sources file"- li $ setSources fsj $ Sources $- HMS.insert packageName finalSpec sources+ li $+ setSources fsj $+ Sources $+ HMS.insert packageName finalSpec sources ------------------------------------------------------------------------------- -- SHOW@@ -378,11 +397,11 @@ showPackage :: MonadIO io => PackageName -> PackageSpec -> io () showPackage (PackageName pname) (PackageSpec spec) = do tsay $ tbold pname- forM_ (HMS.toList spec) $ \(attrName, attrValValue) -> do+ forM_ (KM.toList spec) $ \(attrName, attrValValue) -> do let attrValue = case attrValValue of Aeson.String str -> str _ -> tfaint "<barabajagal>"- tsay $ " " <> attrName <> ": " <> attrValue+ tsay $ " " <> K.toText attrName <> ": " <> attrValue ------------------------------------------------------------------------------- -- UPDATE@@ -397,21 +416,23 @@ desc = [ Opts.fullDesc, Opts.progDesc "Update dependencies",- Opts.headerDoc $ Just $ Opts.nest 2 $- "Examples:"- Opts.<$$> ""- Opts.<$$> Opts.vcat- [ Opts.fill 30 "niv update" Opts.<+> "# update all packages",- Opts.fill 30 "niv update nixpkgs" Opts.<+> "# update nixpkgs",- Opts.fill 30 "niv update my-package -v beta-0.2" Opts.<+> "# update my-package to version \"beta-0.2\""- ]+ Opts.headerDoc $+ Just $+ Opts.nest 2 $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> Opts.vcat+ [ Opts.fill 30 "niv update" Opts.<+> "# update all packages",+ Opts.fill 30 "niv update nixpkgs" Opts.<+> "# update nixpkgs",+ Opts.fill 30 "niv update my-package -v beta-0.2" Opts.<+> "# update my-package to version \"beta-0.2\""+ ] ] specToFreeAttrs :: PackageSpec -> Attrs-specToFreeAttrs = fmap (Free,) . unPackageSpec+specToFreeAttrs = KM.toHashMapText . fmap (Free,) . unPackageSpec specToLockedAttrs :: PackageSpec -> Attrs-specToLockedAttrs = fmap (Locked,) . unPackageSpec+specToLockedAttrs = KM.toHashMapText . fmap (Locked,) . unPackageSpec cmdUpdate :: Maybe (PackageName, PackageSpec) -> NIO () cmdUpdate = \case@@ -423,7 +444,7 @@ Just defaultSpec -> do -- lookup the "type" to find a Cmd to run, defaulting to legacy -- github- let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of+ let cmd = case KM.lookup "type" (unPackageSpec defaultSpec) of Just "git" -> gitCmd Just "local" -> localCmd _ -> githubCmd@@ -433,8 +454,10 @@ case eFinalSpec of Left e -> li $ abortUpdateFailed [(packageName, e)] Right finalSpec ->- li $ setSources fsj $ Sources $- HMS.insert packageName finalSpec sources+ li $+ setSources fsj $+ Sources $+ HMS.insert packageName finalSpec sources Nothing -> job "Updating all packages" $ do fsj <- getFindSourcesJson sources <- unSources <$> li (getSources fsj)@@ -444,16 +467,16 @@ let initialSpec = specToFreeAttrs defaultSpec -- lookup the "type" to find a Cmd to run, defaulting to legacy -- github- let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of+ let cmd = case KM.lookup "type" (unPackageSpec defaultSpec) of Just "git" -> gitCmd Just "local" -> localCmd _ -> githubCmd finalSpec <- fmap attrsToSpec <$> li (doUpdate initialSpec cmd) pure finalSpec let (failed, sources') = partitionEithersHMS esources'- unless (HMS.null failed)- $ li- $ abortUpdateFailed (HMS.toList failed)+ unless (HMS.null failed) $+ li $+ abortUpdateFailed (HMS.toList failed) li $ setSources fsj $ Sources sources' -- | pretty much tryEvalUpdate but we might issue some warnings first@@ -484,11 +507,12 @@ desc = [ Opts.fullDesc, Opts.progDesc "Modify dependency attributes without performing an update",- Opts.headerDoc $ Just $- "Examples:"- Opts.<$$> ""- Opts.<$$> " niv modify nixpkgs -v beta-0.2"- Opts.<$$> " niv modify nixpkgs -a branch=nixpkgs-unstable"+ Opts.headerDoc $+ Just $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> " niv modify nixpkgs -v beta-0.2"+ Opts.<$$> " niv modify nixpkgs -a branch=nixpkgs-unstable" ] optName = Opts.optional $@@ -510,9 +534,9 @@ Nothing -> li $ abortCannotModifyNoSuchPackage packageName case mNewName of Just newName -> do- when (HMS.member newName sources)- $ li- $ abortCannotAddPackageExists newName+ when (HMS.member newName sources) $+ li $+ abortCannotAddPackageExists newName li $ setSources fsj $ Sources $ HMS.insert newName finalSpec $ HMS.delete packageName sources Nothing -> li $ setSources fsj $ Sources $ HMS.insert packageName finalSpec sources@@ -532,11 +556,12 @@ desc = [ Opts.fullDesc, Opts.progDesc "Drop dependency",- Opts.headerDoc $ Just $- "Examples:"- Opts.<$$> ""- Opts.<$$> " niv drop jq"- Opts.<$$> " niv drop my-package version"+ Opts.headerDoc $+ Just $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> " niv drop jq"+ Opts.<$$> " niv drop my-package version" ] parseDropAttributes :: Opts.Parser [T.Text] parseDropAttributes =@@ -549,11 +574,13 @@ tsay $ "Dropping package: " <> unPackageName packageName fsj <- getFindSourcesJson sources <- unSources <$> li (getSources fsj)- when (not $ HMS.member packageName sources)- $ li- $ abortCannotDropNoSuchPackage packageName- li $ setSources fsj $ Sources $- HMS.delete packageName sources+ when (not $ HMS.member packageName sources) $+ li $+ abortCannotDropNoSuchPackage packageName+ li $+ setSources fsj $+ Sources $+ HMS.delete packageName sources attrs -> do tsay $ "Dropping attributes: " <> T.intercalate " " attrs tsay $ "In package: " <> unPackageName packageName@@ -563,12 +590,15 @@ Nothing -> li $ abortCannotAttributesDropNoSuchPackage packageName Just (PackageSpec packageSpec) ->- pure $ PackageSpec $- HMS.mapMaybeWithKey- (\k v -> if k `elem` attrs then Nothing else Just v)- packageSpec- li $ setSources fsj $ Sources $- HMS.insert packageName packageSpec sources+ pure $+ PackageSpec $+ KM.mapMaybeWithKey+ (\k v -> if K.toText k `elem` attrs then Nothing else Just v)+ packageSpec+ li $+ setSources fsj $+ Sources $+ HMS.insert packageName packageSpec sources ------------------------------------------------------------------------------- -- Files and their content@@ -653,10 +683,11 @@ abortUpdateFailed :: [(PackageName, SomeException)] -> IO a abortUpdateFailed errs =- abort $ T.unlines $- ["One or more packages failed to update:"]- <> map- ( \(PackageName pname, e) ->- pname <> ": " <> tshow e- )- errs+ abort $+ T.unlines $+ ["One or more packages failed to update:"]+ <> map+ ( \(PackageName pname, e) ->+ pname <> ": " <> tshow e+ )+ errs
src/Niv/Cmd.hs view
@@ -9,13 +9,12 @@ import qualified Options.Applicative as Opts -- TODO: add filter-data Cmd- = Cmd- { description :: forall a. Opts.InfoMod a,- parseCmdShortcut :: T.Text -> Maybe (PackageName, Aeson.Object),- parsePackageSpec :: Opts.Parser PackageSpec,- updateCmd :: Update () (),- name :: T.Text,- -- | Some notes to print- extraLogs :: Attrs -> [T.Text]- }+data Cmd = Cmd+ { description :: forall a. Opts.InfoMod a,+ parseCmdShortcut :: T.Text -> Maybe (PackageName, Aeson.Object),+ parsePackageSpec :: Opts.Parser PackageSpec,+ updateCmd :: Update () (),+ name :: T.Text,+ -- | Some notes to print+ extraLogs :: Attrs -> [T.Text]+ }
src/Niv/Git/Cmd.hs view
@@ -10,6 +10,8 @@ import Control.Applicative import Control.Arrow import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as KM import qualified Data.ByteString.Char8 as B8 import qualified Data.HashMap.Strict as HMS import Data.Maybe@@ -60,8 +62,8 @@ then case T.splitOn "/" txt of [] -> Nothing (last -> w) -> case T.stripSuffix ".git" w of- Nothing -> Just (PackageName w, HMS.singleton "repo" (Aeson.String txt'))- Just w' -> Just (PackageName w', HMS.singleton "repo" (Aeson.String txt'))+ Nothing -> Just (PackageName w, KM.singleton "repo" (Aeson.String txt'))+ Just w' -> Just (PackageName w', KM.singleton "repo" (Aeson.String txt')) else Nothing where isGitURL =@@ -71,7 +73,7 @@ parseGitPackageSpec :: Opts.Parser PackageSpec parseGitPackageSpec =- (PackageSpec . HMS.fromList)+ (PackageSpec . KM.fromList) <$> many (parseRepo <|> parseBranch <|> parseRev <|> parseAttr <|> parseSAttr) where parseRepo =@@ -116,9 +118,9 @@ -- | how to convert to JSON (String -> Aeson.Value) -> String ->- Maybe (T.Text, Aeson.Value)+ Maybe (K.Key, Aeson.Value) parseKeyVal toJSON str = case span (/= '=') str of- (key, '=' : val) -> Just (T.pack key, toJSON val)+ (key, '=' : val) -> Just (K.fromString key, toJSON val) _ -> Nothing describeGit :: Opts.InfoMod a@@ -126,13 +128,14 @@ mconcat [ Opts.fullDesc, Opts.progDesc "Add a git dependency. Experimental.",- Opts.headerDoc $ Just $- "Examples:"- Opts.<$$> ""- Opts.<$$> " niv add git git@github.com:stedolan/jq"- Opts.<$$> " niv add git ssh://git@github.com/stedolan/jq --rev deadb33f"- Opts.<$$> " niv add git https://github.com/stedolan/jq.git"- Opts.<$$> " niv add git --repo /my/custom/repo --name custom --branch development"+ Opts.headerDoc $+ Just $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> " niv add git git@github.com:stedolan/jq"+ Opts.<$$> " niv add git ssh://git@github.com/stedolan/jq --rev deadb33f"+ Opts.<$$> " niv add git https://github.com/stedolan/jq.git"+ Opts.<$$> " niv add git --repo /my/custom/repo --name custom --branch development" ] gitUpdate ::@@ -183,8 +186,9 @@ args $ "Git didn't produce any output. Does the branch '" <> branch <> "' exist?" abortTooMuchOutput args ls =- abortGitBug args $ T.unlines $- ["Git produced too much output:"] <> map (" " <>) ls+ abortGitBug args $+ T.unlines $+ ["Git produced too much output:"] <> map (" " <>) ls defaultBranchAndRev :: -- | the repository@@ -195,10 +199,11 @@ case sout of (l1 : l2 : _) -> (,) <$> parseBranch l1 <*> parseRev l2 _ ->- abortGitBug args $ T.unlines $- [ "Could not read reference and revision from stdout:"- ]- <> sout+ abortGitBug args $+ T.unlines $+ [ "Could not read reference and revision from stdout:"+ ]+ <> sout where args = ["ls-remote", "--symref", repo, "HEAD"] parseBranch l = maybe (abortNoRef args l) pure $ do@@ -248,9 +253,10 @@ abortGitBug :: [T.Text] -> T.Text -> IO a abortGitBug args msg =- abort $ bug $- T.unlines- [ "Could not read the output of 'git'.",- T.unwords ("command:" : "git" : args),- msg- ]+ abort $+ bug $+ T.unlines+ [ "Could not read the output of 'git'.",+ T.unwords ("command:" : "git" : args),+ msg+ ]
src/Niv/Git/Test.hs view
@@ -7,6 +7,7 @@ where import Control.Monad+import qualified Data.Aeson.KeyMap as KM import Data.Bifunctor import qualified Data.HashMap.Strict as HMS import Data.IORef@@ -29,21 +30,21 @@ Tasty.testCase "git@github.com:nmattia/niv" $ parseGitShortcut "git@github.com:nmattia/niv" @=? Just- (PackageName "niv", HMS.singleton "repo" "git@github.com:nmattia/niv"),+ (PackageName "niv", KM.singleton "repo" "git@github.com:nmattia/niv"), Tasty.testCase "ssh://git@github.com/stedolan/jq" $ parseGitShortcut "ssh://git@github.com/stedolan/jq" @=? Just- (PackageName "jq", HMS.singleton "repo" "ssh://git@github.com/stedolan/jq"),+ (PackageName "jq", KM.singleton "repo" "ssh://git@github.com/stedolan/jq"), Tasty.testCase "https://github.com/stedolan/jq.git" $ parseGitShortcut "https://github.com/stedolan/jq.git" @=? Just- (PackageName "jq", HMS.singleton "repo" "https://github.com/stedolan/jq.git"),+ (PackageName "jq", KM.singleton "repo" "https://github.com/stedolan/jq.git"), Tasty.testCase "https://github.com/stedolan/jq" $ parseGitShortcut "https://github.com/stedolan/jq" @=? Nothing, Tasty.testCase "~/path/to/repo.git" $ parseGitShortcut "~/path/to/repo.git" @=? Just- (PackageName "repo", HMS.singleton "repo" "~/path/to/repo.git")+ (PackageName "repo", KM.singleton "repo" "~/path/to/repo.git") ] test_gitUpdates :: Tasty.TestTree@@ -61,9 +62,9 @@ let interState' = HMS.map (first (\_ -> Free)) interState actualState <- evalUpdate interState' $ proc () -> gitUpdate latestRev' (error "should update") -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where latestRev' _ _ = pure "some-other-rev" defaultBranchAndHEAD' _ = pure ("some-branch", "some-rev")@@ -111,9 +112,9 @@ let interState' = HMS.map (first (\_ -> Free)) interState actualState <- evalUpdate interState' $ proc () -> gitUpdate latestRev'' (error "should update") -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where latestRev' _ _ = pure "some-other-rev" defaultBranchAndHEAD' _ = pure ("some-branch", "some-rev")
src/Niv/GitHub.hs view
@@ -31,8 +31,9 @@ githubUpdate prefetch latestRev ghRepo = proc () -> do urlTemplate <- template- <<< (useOrSet "url_template" <<< completeSpec) <+> (load "url_template") -<- ()+ <<< (useOrSet "url_template" <<< completeSpec) <+> (load "url_template")+ -<+ () url <- update "url" -< urlTemplate let isTarGuess = (\u -> "tar.gz" `T.isSuffixOf` u || ".tgz" `T.isSuffixOf` u) <$> url type' <- useOrSet "type" -< bool "file" "tarball" <$> isTarGuess :: Box T.Text@@ -46,13 +47,15 @@ repo <- load "repo" -< () repoInfo <- run (\(a, b) -> ghRepo a b) -< (,) <$> owner <*> repo branch <-- useOrSet "branch" <<< arr (fmap $ fromMaybe "master") -<- repoDefaultBranch <$> repoInfo+ useOrSet "branch" <<< arr (fmap $ fromMaybe "master")+ -<+ repoDefaultBranch <$> repoInfo _description <- useOrSet "description" -< repoDescription <$> repoInfo _homepage <- useOrSet "homepage" -< repoHomepage <$> repoInfo _ <-- update "rev" <<< run' (\(a, b, c) -> latestRev a b c) -<- (,,) <$> owner <*> repo <*> branch+ update "rev" <<< run' (\(a, b, c) -> latestRev a b c)+ -<+ (,,) <$> owner <*> repo <*> branch returnA -< pure githubURLTemplate githubURLTemplate :: T.Text
src/Niv/GitHub/API.hs view
@@ -6,16 +6,15 @@ module Niv.GitHub.API where import qualified Data.Aeson as Aeson+import qualified Data.Aeson.KeyMap as KM import qualified Data.ByteString.Char8 as BS8 import Data.Functor-import qualified Data.HashMap.Strict as HMS import Data.Maybe import Data.String.QQ (s) import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Text.Extended import qualified Network.HTTP.Simple as HTTP-import Niv.Logger import System.Environment (lookupEnv) import System.Exit (exitFailure) import System.IO.Unsafe (unsafePerformIO)@@ -23,12 +22,11 @@ -- Bunch of GitHub helpers -data GithubRepo- = GithubRepo- { repoDescription :: Maybe T.Text,- repoHomepage :: Maybe T.Text,- repoDefaultBranch :: Maybe T.Text- }+data GithubRepo = GithubRepo+ { repoDescription :: Maybe T.Text,+ repoHomepage :: Maybe T.Text,+ repoDefaultBranch :: Maybe T.Text+ } githubRepo :: T.Text -> T.Text -> IO GithubRepo githubRepo owner repo = do@@ -39,7 +37,7 @@ let resp = fmap Aeson.eitherDecodeStrict resp0 case (HTTP.getResponseStatusCode resp, HTTP.getResponseBody resp) of (200, Right (Aeson.Object m)) -> do- let lookupText k = case HMS.lookup k m of+ let lookupText k = case KM.lookup k m of Just (Aeson.String t) -> Just t _ -> Nothing pure@@ -82,17 +80,17 @@ defaultRequest (map T.encodeUtf8 -> parts) = do let path = T.encodeUtf8 githubPath <> BS8.intercalate "/" (parts) mtoken <- lookupEnv' "GITHUB_TOKEN"- pure- $ ( flip (maybe id) mtoken $ \token ->- HTTP.addRequestHeader "authorization" ("token " <> BS8.pack token)- )- $ HTTP.setRequestPath path- $ HTTP.addRequestHeader "user-agent" "niv"- $ HTTP.addRequestHeader "accept" "application/vnd.github.v3+json"- $ HTTP.setRequestSecure githubSecure- $ HTTP.setRequestHost (T.encodeUtf8 githubApiHost)- $ HTTP.setRequestPort githubApiPort- $ HTTP.defaultRequest+ pure $+ ( flip (maybe id) mtoken $ \token ->+ HTTP.addRequestHeader "authorization" ("token " <> BS8.pack token)+ )+ $ HTTP.setRequestPath path $+ HTTP.addRequestHeader "user-agent" "niv" $+ HTTP.addRequestHeader "accept" "application/vnd.github.v3+json" $+ HTTP.setRequestSecure githubSecure $+ HTTP.setRequestHost (T.encodeUtf8 githubApiHost) $+ HTTP.setRequestPort githubApiPort $+ HTTP.defaultRequest -- | Get the latest revision for owner, repo and branch. -- TODO: explain no error handling@@ -135,34 +133,12 @@ |] --- Some environment variables may have different meanings (see for instance--- https://github.com/nmattia/niv/issues/280)--- For ambiguous ones, we prepend NIV_.----warnGitHubEnvVars :: IO ()-warnGitHubEnvVars =- mapM_- warnEnvVar- [ "GITHUB_INSECURE",- "GITHUB_PATH"- ]- where- warnEnvVar vn = lookupEnv (T.unpack vn) >>= \case- Nothing -> pure ()- Just {} -> do- twarn $- T.unwords- [ "The environment variable",- vn,- "was renamed to",- "NIV_" <> vn- ]- -- | Like lookupEnv "foo" but also looks up "NIV_foo" lookupEnv' :: String -> IO (Maybe String)-lookupEnv' vn = lookupEnv vn >>= \case- Just x -> pure (Just x)- Nothing -> lookupEnv ("NIV_" <> vn)+lookupEnv' vn =+ lookupEnv vn >>= \case+ Just x -> pure (Just x)+ Nothing -> lookupEnv ("NIV_" <> vn) githubHost :: T.Text githubHost = unsafePerformIO $ do
src/Niv/GitHub/Cmd.hs view
@@ -13,10 +13,11 @@ import Control.Applicative import Data.Aeson ((.=)) import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as KM import Data.Bifunctor import qualified Data.ByteString.Char8 as B8 import Data.Char (isAlphaNum)-import qualified Data.HashMap.Strict as HMS import Data.Maybe import Data.String.QQ (s) import qualified Data.Text as T@@ -45,10 +46,10 @@ parseGitHubPackageSpec :: Opts.Parser PackageSpec parseGitHubPackageSpec =- (PackageSpec . HMS.fromList)+ (PackageSpec . KM.fromList) <$> many parseAttribute where- parseAttribute :: Opts.Parser (T.Text, Aeson.Value)+ parseAttribute :: Opts.Parser (K.Key, Aeson.Value) parseAttribute = Opts.option (Opts.maybeReader parseKeyValJSON)@@ -88,22 +89,22 @@ -- | how to convert to JSON (String -> Aeson.Value) -> String ->- Maybe (T.Text, Aeson.Value)+ Maybe (K.Key, Aeson.Value) parseKeyVal toJSON str = case span (/= '=') str of- (key, '=' : val) -> Just (T.pack key, toJSON val)+ (key, '=' : val) -> Just (K.fromString key, toJSON val) _ -> Nothing -- Shortcuts for common attributes- shortcutAttributes :: Opts.Parser (T.Text, Aeson.Value)+ shortcutAttributes :: Opts.Parser (K.Key, Aeson.Value) shortcutAttributes = foldr (<|>) empty $ mkShortcutAttribute <$> ["branch", "owner", "rev", "version"] -- TODO: infer those shortcuts from 'Update' keys- mkShortcutAttribute :: T.Text -> Opts.Parser (T.Text, Aeson.Value)+ mkShortcutAttribute :: T.Text -> Opts.Parser (K.Key, Aeson.Value) mkShortcutAttribute = \case attr@(T.uncons -> Just (c, _)) -> fmap (second Aeson.String) $- (attr,)+ (K.fromText attr,) <$> Opts.strOption ( Opts.long (T.unpack attr) <> Opts.short c@@ -124,12 +125,13 @@ mconcat [ Opts.fullDesc, Opts.progDesc "Add a GitHub dependency",- Opts.headerDoc $ Just $- "Examples:"- Opts.<$$> ""- Opts.<$$> " niv add stedolan/jq"- Opts.<$$> " niv add NixOS/nixpkgs -n nixpkgs -b nixpkgs-unstable"- Opts.<$$> " niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip"+ Opts.headerDoc $+ Just $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> " niv add stedolan/jq"+ Opts.<$$> " niv add NixOS/nixpkgs -n nixpkgs -b nixpkgs-unstable"+ Opts.<$$> " niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip" ] -- parse a github shortcut of the form "owner/repo"@@ -143,12 +145,12 @@ ) -> Just ( PackageName repo,- HMS.fromList ["owner" .= owner, "repo" .= repo]+ KM.fromList ["owner" .= owner, "repo" .= repo] ) -- 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)+ _ -> Just (PackageName str, KM.empty) -- | The IO (real) github update githubUpdate' :: Update () ()
src/Niv/GitHub/Test.hs view
@@ -16,9 +16,9 @@ test_githubInitsProperly = do actualState <- evalUpdate initialState $ proc () -> githubUpdate prefetch latestRev ghRepo -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where prefetch _ _ = pure "some-sha" latestRev _ _ _ = pure "some-rev"@@ -52,9 +52,9 @@ test_githubUpdates = do actualState <- evalUpdate initialState $ proc () -> githubUpdate prefetch latestRev ghRepo -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where prefetch _ _ = pure "new-sha" latestRev _ _ _ = pure "new-rev"@@ -96,9 +96,9 @@ test_githubDoesntOverrideRev = do actualState <- evalUpdate initialState $ proc () -> githubUpdate prefetch latestRev ghRepo -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where prefetch _ _ = pure "new-sha" latestRev _ _ _ = error "shouldn't fetch rev"@@ -135,9 +135,9 @@ test_githubURLFallback = do actualState <- evalUpdate initialState $ proc () -> githubUpdate prefetch latestRev ghRepo -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where prefetch _ _ = pure "some-sha" latestRev _ _ _ = error "shouldn't fetch rev"@@ -161,16 +161,16 @@ ioref <- newIORef False tmpState <- evalUpdate initialState $ proc () -> githubUpdate (prefetch ioref) latestRev ghRepo -< ()- unless ((snd <$> tmpState) == expectedState)- $ error- $ "State mismatch: " <> show tmpState+ unless ((snd <$> tmpState) == expectedState) $+ error $+ "State mismatch: " <> show tmpState -- Set everything free let tmpState' = HMS.map (first (\_ -> Free)) tmpState actualState <- evalUpdate tmpState' $ proc () -> githubUpdate (prefetch ioref) latestRev ghRepo -< ()- unless ((snd <$> actualState) == expectedState)- $ error- $ "State mismatch: " <> show actualState+ unless ((snd <$> actualState) == expectedState) $+ error $+ "State mismatch: " <> show actualState where prefetch ioref _ _ = do readIORef ioref >>= \case
src/Niv/Local/Cmd.hs view
@@ -10,7 +10,8 @@ import Control.Arrow import qualified Data.Aeson as Aeson-import qualified Data.HashMap.Strict as HMS+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as KM import qualified Data.Text as T import Niv.Cmd import Niv.Sources@@ -36,13 +37,13 @@ if (T.isPrefixOf "./" txt || T.isPrefixOf "/" txt) then do let n = last $ T.splitOn "/" txt- Just (PackageName n, HMS.fromList [("path", Aeson.String txt)])+ Just (PackageName n, KM.fromList [("path", Aeson.String txt)]) else Nothing parseLocalPackageSpec :: Opts.Parser PackageSpec-parseLocalPackageSpec = PackageSpec . HMS.fromList <$> parseParams+parseLocalPackageSpec = PackageSpec . KM.fromList <$> parseParams where- parseParams :: Opts.Parser [(T.Text, Aeson.Value)]+ parseParams :: Opts.Parser [(K.Key, Aeson.Value)] parseParams = maybe [] pure <$> Opts.optional parsePath parsePath = ("path",) . Aeson.String@@ -56,8 +57,9 @@ mconcat [ Opts.fullDesc, Opts.progDesc "Add a local dependency. Experimental.",- Opts.headerDoc $ Just $- "Examples:"- Opts.<$$> ""- Opts.<$$> " niv add local ./foo/bar"+ Opts.headerDoc $+ Just $+ "Examples:"+ Opts.<$$> ""+ Opts.<$$> " niv add local ./foo/bar" ]
src/Niv/Sources.hs view
@@ -10,6 +10,7 @@ import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Extended as Aeson+import qualified Data.Aeson.KeyMap as KM import Data.Bifunctor (first) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy.Char8 as BL8@@ -43,9 +44,8 @@ | SourceIsntJSON | SpecIsntAMap -newtype Sources- = Sources- {unSources :: HMS.HashMap PackageName PackageSpec}+newtype Sources = Sources+ {unSources :: HMS.HashMap PackageName PackageSpec} deriving newtype (FromJSON, ToJSON) getSourcesEither :: FindSourcesJson -> IO (Either SourcesError Sources)@@ -62,7 +62,7 @@ valueToSources :: Aeson.Value -> Maybe Sources valueToSources = \case Aeson.Object obj ->- fmap (Sources . mapKeys PackageName) $+ fmap (Sources . mapKeys PackageName . KM.toHashMapText) $ traverse ( \case Aeson.Object obj' -> Just (PackageSpec obj')@@ -96,7 +96,7 @@ -- | Simply discards the 'Freedom' attrsToSpec :: Attrs -> PackageSpec-attrsToSpec = PackageSpec . fmap snd+attrsToSpec = PackageSpec . KM.fromHashMapText . fmap snd -- | @nix/sources.json@ or pointed at by 'FindSourcesJson' pathNixSourcesJson :: FindSourcesJson -> FilePath@@ -172,6 +172,10 @@ V23 | -- Fix NIV_OVERRIDE_{name} for sandbox V24+ | -- Add the ability to pass submodules to fetchGit+ V25+ | -- formatting fix+ V26 deriving stock (Bounded, Enum, Eq) -- | A user friendly version@@ -201,6 +205,8 @@ V22 -> "22" V23 -> "23" V24 -> "24"+ V25 -> "25"+ V26 -> "26" latestVersionMD5 :: T.Text latestVersionMD5 = sourcesVersionToMD5 maxBound@@ -237,6 +243,8 @@ V22 -> "935d1d2f0bf95fda977a6e3a7e548ed4" V23 -> "4111204b613ec688e2669516dd313440" V24 -> "116c2d936f1847112fef0013771dab28"+ V25 -> "6612caee5814670e5e4d9dd1b71b5f70"+ V26 -> "937bff93370a064c9000f13cec5867f9" -- | The MD5 sum of ./nix/sources.nix sourcesNixMD5 :: IO T.Text
src/Niv/Update.hs view
@@ -120,13 +120,12 @@ runBox :: Box a -> IO a runBox = boxOp -data Box a- = Box- { -- | Whether the value is new or was retrieved (or derived) from old- -- attributes- boxNew :: Bool,- boxOp :: IO a- }+data Box a = Box+ { -- | Whether the value is new or was retrieved (or derived) from old+ -- attributes+ boxNew :: Bool,+ boxOp :: IO a+ } deriving (Functor) mkBox :: Box a -> IO (Box a)@@ -188,28 +187,35 @@ Id -> pure $ UpdateNeedMore $ pure . UpdateSuccess attrs Arr f -> pure $ UpdateNeedMore $ pure . UpdateSuccess attrs . f Zero -> pure $ UpdateReady (UpdateFailed FailZero)- Plus l r -> runUpdate' attrs l >>= \case- UpdateReady (UpdateFailed {}) -> runUpdate' attrs r- UpdateReady (UpdateSuccess f v) -> pure $ UpdateReady (UpdateSuccess f v)- UpdateNeedMore next -> pure $ UpdateNeedMore $ \v -> next v >>= \case- UpdateSuccess f res -> pure $ UpdateSuccess f res- UpdateFailed {} -> runUpdate' attrs r >>= \case- UpdateReady res -> pure res- UpdateNeedMore next' -> next' v- Load k -> pure $ UpdateReady $ do- case HMS.lookup k attrs of- Just (_, v') -> UpdateSuccess attrs v'- Nothing -> UpdateFailed $ FailNoSuchKey k+ Plus l r ->+ runUpdate' attrs l >>= \case+ UpdateReady (UpdateFailed {}) -> runUpdate' attrs r+ UpdateReady (UpdateSuccess f v) -> pure $ UpdateReady (UpdateSuccess f v)+ UpdateNeedMore next -> pure $+ UpdateNeedMore $ \v ->+ next v >>= \case+ UpdateSuccess f res -> pure $ UpdateSuccess f res+ UpdateFailed {} ->+ runUpdate' attrs r >>= \case+ UpdateReady res -> pure res+ UpdateNeedMore next' -> next' v+ Load k -> pure $+ UpdateReady $ do+ case HMS.lookup k attrs of+ Just (_, v') -> UpdateSuccess attrs v'+ Nothing -> UpdateFailed $ FailNoSuchKey k First a -> do runUpdate' attrs a >>= \case UpdateReady (UpdateFailed e) -> pure $ UpdateReady $ UpdateFailed e- UpdateReady (UpdateSuccess fo ba) -> pure $ UpdateNeedMore $ \gtt -> do- pure $ UpdateSuccess fo (ba, snd gtt)- UpdateNeedMore next -> pure $ UpdateNeedMore $ \gtt -> do- next (fst gtt) >>= \case- UpdateFailed e -> pure $ UpdateFailed e- UpdateSuccess f res -> do- pure $ UpdateSuccess f (res, snd gtt)+ UpdateReady (UpdateSuccess fo ba) -> pure $+ UpdateNeedMore $ \gtt -> do+ pure $ UpdateSuccess fo (ba, snd gtt)+ UpdateNeedMore next -> pure $+ UpdateNeedMore $ \gtt -> do+ next (fst gtt) >>= \case+ UpdateFailed e -> pure $ UpdateFailed e+ UpdateSuccess f res -> do+ pure $ UpdateSuccess f (res, snd gtt) Run act -> pure ( UpdateNeedMore $ \gtt -> do@@ -249,28 +255,33 @@ pure $ UpdateSuccess attrs v Nothing -> UpdateNeedMore $ \gtt -> do pure $ UpdateSuccess (HMS.insert k (Locked, gtt) attrs) gtt- Compose (Compose' f g) -> runUpdate' attrs g >>= \case- UpdateReady (UpdateFailed e) -> pure $ UpdateReady $ UpdateFailed e- UpdateReady (UpdateSuccess attrs' act) -> runUpdate' attrs' f >>= \case+ Compose (Compose' f g) ->+ runUpdate' attrs g >>= \case UpdateReady (UpdateFailed e) -> pure $ UpdateReady $ UpdateFailed e- UpdateReady (UpdateSuccess attrs'' act') -> pure $ UpdateReady $ UpdateSuccess attrs'' act'- UpdateNeedMore next -> UpdateReady <$> next act- UpdateNeedMore next -> pure $ UpdateNeedMore $ \gtt -> do- next gtt >>= \case- UpdateFailed e -> pure $ UpdateFailed e- UpdateSuccess attrs' act -> runUpdate' attrs' f >>= \case- UpdateReady ready -> pure ready- UpdateNeedMore next' -> next' act- Template -> pure $ UpdateNeedMore $ \v -> do- v' <- runBox v- case renderTemplate- ( \k ->- ((decodeBox $ "When rendering template " <> v') . snd)- <$> HMS.lookup k attrs- )- v' of- Nothing -> pure $ UpdateFailed $ FailTemplate v' (HMS.keys attrs)- Just v'' -> pure $ UpdateSuccess attrs (v'' <* v) -- carries over v's newness+ UpdateReady (UpdateSuccess attrs' act) ->+ runUpdate' attrs' f >>= \case+ UpdateReady (UpdateFailed e) -> pure $ UpdateReady $ UpdateFailed e+ UpdateReady (UpdateSuccess attrs'' act') -> pure $ UpdateReady $ UpdateSuccess attrs'' act'+ UpdateNeedMore next -> UpdateReady <$> next act+ UpdateNeedMore next -> pure $+ UpdateNeedMore $ \gtt -> do+ next gtt >>= \case+ UpdateFailed e -> pure $ UpdateFailed e+ UpdateSuccess attrs' act ->+ runUpdate' attrs' f >>= \case+ UpdateReady ready -> pure ready+ UpdateNeedMore next' -> next' act+ Template -> pure $+ UpdateNeedMore $ \v -> do+ v' <- runBox v+ case renderTemplate+ ( \k ->+ ((decodeBox $ "When rendering template " <> v') . snd)+ <$> HMS.lookup k attrs+ )+ v' of+ Nothing -> pure $ UpdateFailed $ FailTemplate v' (HMS.keys attrs)+ Just v'' -> pure $ UpdateSuccess attrs (v'' <* v) -- carries over v's newness decodeBox :: FromJSON a => T.Text -> Box Value -> Box a decodeBox msg v = v {boxOp = boxOp v >>= decodeValue msg}@@ -286,17 +297,15 @@ -- renderTemplate ("foo" -> "bar") "<foo>" -> pure (Just "bar") -- renderTemplate ("foo" -> "bar") "<baz>" -> pure Nothing renderTemplate :: (T.Text -> Maybe (Box T.Text)) -> T.Text -> Maybe (Box T.Text)-renderTemplate vals = \case- (T.uncons -> Just ('<', str)) -> do+renderTemplate vals tpl = case T.uncons tpl of+ Just ('<', str) -> do case T.span (/= '>') str of (key, T.uncons -> Just ('>', rest)) -> do let v = vals key (liftA2 (<>) v) (renderTemplate vals rest) _ -> Nothing- (T.uncons -> Just (c, str)) -> fmap (T.cons c) <$> renderTemplate vals str- (T.uncons -> Nothing) -> Just $ pure T.empty- -- XXX: isn't this redundant?- _ -> Just $ pure T.empty+ Just (c, str) -> fmap (T.cons c) <$> renderTemplate vals str+ Nothing -> Just $ pure T.empty template :: Update (Box T.Text) (Box T.Text) template = Template
src/Niv/Update/Test.hs view
@@ -12,8 +12,9 @@ simplyRuns :: IO () simplyRuns =- void $ runUpdate attrs $ proc () -> do- returnA -< ()+ void $+ runUpdate attrs $ proc () -> do+ returnA -< () where attrs = HMS.empty @@ -76,9 +77,9 @@ dirtyForcesUpdate = do let f = constBox ("world" :: T.Text) >>> dirty >>> update "hello" attrs' <- evalUpdate attrs f- unless ((snd <$> HMS.lookup "hello" attrs') == Just "world")- $ error- $ "bad value for hello: " <> show attrs'+ unless ((snd <$> HMS.lookup "hello" attrs') == Just "world") $+ error $+ "bad value for hello: " <> show attrs' where attrs = HMS.singleton "hello" (Free, "foo") @@ -88,16 +89,16 @@ update "hello" -< ("world" :: Box T.Text) run (\() -> error "io shouldn't be run") -< pure () attrs <- evalUpdate HMS.empty f- unless ((snd <$> HMS.lookup "hello" attrs) == Just "world")- $ error- $ "bad value for hello: " <> show attrs+ unless ((snd <$> HMS.lookup "hello" attrs) == Just "world") $+ error $+ "bad value for hello: " <> show attrs let f' = proc () -> do run (\() -> error "io shouldn't be run") -< pure () update "hello" -< ("world" :: Box T.Text) attrs' <- evalUpdate HMS.empty f'- unless ((snd <$> HMS.lookup "hello" attrs') == Just "world")- $ error- $ "bad value for hello: " <> show attrs'+ unless ((snd <$> HMS.lookup "hello" attrs') == Just "world") $+ error $+ "bad value for hello: " <> show attrs' v3 <- execUpdate (HMS.fromList [("hello", (Free, "world")), ("bar", (Free, "baz"))]) $ proc () -> do