packages feed

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 view
@@ -1,6 +1,6 @@ # niv -![GitHub Actions](https://github.com/nmattia/niv/workflows/Test/badge.svg?branch=master)+[![Test](https://github.com/nmattia/niv/actions/workflows/test.yml/badge.svg)](https://github.com/nmattia/niv/actions/workflows/test.yml) [![Netlify Status](https://api.netlify.com/api/v1/badges/48532eaa-259f-4ca2-aadf-67f7c6b957fd/deploy-status)](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