diff --git a/Main.hs b/Main.hs index 7a52048..001acb8 100644 --- a/Main.hs +++ b/Main.hs @@ -13,6 +13,7 @@ import Control.Monad import Control.Monad.State import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey) import Data.Char (toUpper) +import Data.Functor ((<&>)) import Data.Hashable (Hashable) import Data.Maybe (mapMaybe, fromMaybe) import Data.String.QQ (s) @@ -100,6 +101,12 @@ parsePackageSpec = Opts.short 't' <> Opts.metavar "URL" <> Opts.help "Used during 'update' when building URL. Occurrences of are replaced with attribute 'foo'." + )) <|> + (("type",) <$> Opts.strOption + ( Opts.long "type" <> + Opts.short 'T' <> + Opts.metavar "TYPE" <> + Opts.help "The type of the URL target. The value can be either 'file' or 'tarball'. If not set, the value is inferred from the suffix of the URL." )) -- Parse "key=val" into ("key", "val") @@ -153,6 +160,20 @@ updatePackageSpec = execStateT $ do _ -> pure () ) + -- If the type attribute is not set, we try to infer its value based on the url suffix + (,) <$> getPackageSpecAttr "type" <*> getPackageSpecAttr "url" >>= \case + -- If an url type is set, we'll use it + (Just _, _) -> pure () + -- We need an url to infer a url type + (_, Nothing) -> pure () + (Nothing, Just (Aeson.String url)) -> do + let urlType = if "tar.gz" `T.isSuffixOf` url + then "tarball" + else "file" + setPackageSpecAttr "type" (Aeson.String $ T.pack urlType) + -- If the JSON value is not a string, we ignore it + (_, _) -> pure () + -- Updates the sha256 based on the URL contents (,) <$> getPackageSpecAttr "url" <*> getPackageSpecAttr "sha256" >>= \case -- If no URL is set, we simply can't prefetch @@ -167,7 +188,11 @@ updatePackageSpec = execStateT $ do prefetch :: Aeson.Value -> StateT PackageSpec IO () prefetch = \case Aeson.String (T.unpack -> url) -> do - sha256 <- liftIO $ nixPrefetchURL url + unpack <- getPackageSpecAttr "type" <&> \case + -- Do not unpack if the url type is 'file' + Just (Aeson.String urlType) -> not $ T.unpack urlType == "file" + _ -> True + sha256 <- liftIO $ nixPrefetchURL unpack url setPackageSpecAttr "sha256" (Aeson.String $ T.pack sha256) _ -> pure () @@ -564,12 +589,13 @@ abort msg = do putStrLn msg exitFailure -nixPrefetchURL :: String -> IO String -nixPrefetchURL url = - lines <$> readProcess "nix-prefetch-url" ["--unpack", url] "" >>= +nixPrefetchURL :: Bool -> String -> IO String +nixPrefetchURL unpack url = + lines <$> readProcess "nix-prefetch-url" args "" >>= \case (l:_) -> pure l _ -> abortNixPrefetchExpectedOutput + where args = if unpack then ["--unpack", url] else [url] ------------------------------------------------------------------------------- -- Files and their content @@ -583,7 +609,7 @@ pathNixSourcesNix = "nix" "sources.nix" initNixSourcesNixContent :: String initNixSourcesNixContent = [s| # A record, from name to path, of the third-party packages -with +with rec { sources = builtins.fromJSON (builtins.readFile ./sources.json); @@ -597,8 +623,17 @@ with mapAttrs = builtins.mapAttrs or (f: set: with builtins; listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))); -}; + getFetcher = spec: + let fetcherName = + if builtins.hasAttr "type" spec + then builtins.getAttr "type" spec + else "tarball"; + in builtins.getAttr fetcherName { + "tarball" = builtins.fetchTarball; + "file" = builtins.fetchurl; + }; +}; # NOTE: spec must _not_ have an "outPath" attribute mapAttrs (_: spec: if builtins.hasAttr "outPath" spec @@ -608,7 +643,7 @@ mapAttrs (_: spec: if builtins.hasAttr "url" spec && builtins.hasAttr "sha256" spec then spec // - { outPath = fetchTarball { inherit (spec) url sha256; } ; } + { outPath = getFetcher spec { inherit (spec) url sha256; } ; } else spec ) sources |] diff --git a/README.md b/README.md index 3478876..3fd581a 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ Examples: Usage: niv add [-n|--name NAME] PACKAGE ([-a|--attribute KEY=VAL] | [-b|--branch BRANCH] | [-o|--owner OWNER] | [-r|--repo REPO] | - [-v|--version VERSION] | [-t|--template URL]) + [-v|--version VERSION] | [-t|--template URL] | [-T|--type TYPE]) Add dependency Available options: @@ -232,6 +232,9 @@ Available options: -v,--version VERSION Equivalent to --attribute version= -t,--template URL Used during 'update' when building URL. Occurrences of are replaced with attribute 'foo'. + -T,--type TYPE The type of the URL target. The value can be either + 'file' or 'tarball'. If not set, the value is + inferred from the suffix of the URL. -h,--help Show this help text ``` @@ -247,7 +250,7 @@ Examples: Usage: niv update [PACKAGE] ([-a|--attribute KEY=VAL] | [-b|--branch BRANCH] | [-o|--owner OWNER] | [-r|--repo REPO] | [-v|--version VERSION] - | [-t|--template URL]) + | [-t|--template URL] | [-T|--type TYPE]) Update dependencies Available options: @@ -258,6 +261,9 @@ Available options: -v,--version VERSION Equivalent to --attribute version= -t,--template URL Used during 'update' when building URL. Occurrences of are replaced with attribute 'foo'. + -T,--type TYPE The type of the URL target. The value can be either + 'file' or 'tarball'. If not set, the value is + inferred from the suffix of the URL. -h,--help Show this help text ```