{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}

module Niv.Cli where

import Control.Applicative
import Control.Monad
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)
import qualified Data.HashMap.Strict as HMS
import Data.HashMap.Strict.Extended
import Data.Hashable (Hashable)
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.Cmd
import Niv.Local.Cmd
import Niv.Logger
import Niv.Sources
import Niv.Update
import qualified Options.Applicative as Opts
import qualified Options.Applicative.Help.Pretty as Opts
-- I died a little
import Paths_niv (version)
import qualified System.Directory as Dir
import System.Environment (getArgs)
import System.FilePath (takeDirectory)
import UnliftIO

newtype NIO a = NIO {forall a. NIO a -> ReaderT FindSourcesJson IO a
runNIO :: ReaderT FindSourcesJson IO a}
  deriving (forall a b. a -> NIO b -> NIO a
forall a b. (a -> b) -> NIO a -> NIO b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> NIO b -> NIO a
$c<$ :: forall a b. a -> NIO b -> NIO a
fmap :: forall a b. (a -> b) -> NIO a -> NIO b
$cfmap :: forall a b. (a -> b) -> NIO a -> NIO b
Functor, Functor NIO
forall a. a -> NIO a
forall a b. NIO a -> NIO b -> NIO a
forall a b. NIO a -> NIO b -> NIO b
forall a b. NIO (a -> b) -> NIO a -> NIO b
forall a b c. (a -> b -> c) -> NIO a -> NIO b -> NIO c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. NIO a -> NIO b -> NIO a
$c<* :: forall a b. NIO a -> NIO b -> NIO a
*> :: forall a b. NIO a -> NIO b -> NIO b
$c*> :: forall a b. NIO a -> NIO b -> NIO b
liftA2 :: forall a b c. (a -> b -> c) -> NIO a -> NIO b -> NIO c
$cliftA2 :: forall a b c. (a -> b -> c) -> NIO a -> NIO b -> NIO c
<*> :: forall a b. NIO (a -> b) -> NIO a -> NIO b
$c<*> :: forall a b. NIO (a -> b) -> NIO a -> NIO b
pure :: forall a. a -> NIO a
$cpure :: forall a. a -> NIO a
Applicative, Applicative NIO
forall a. a -> NIO a
forall a b. NIO a -> NIO b -> NIO b
forall a b. NIO a -> (a -> NIO b) -> NIO b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> NIO a
$creturn :: forall a. a -> NIO a
>> :: forall a b. NIO a -> NIO b -> NIO b
$c>> :: forall a b. NIO a -> NIO b -> NIO b
>>= :: forall a b. NIO a -> (a -> NIO b) -> NIO b
$c>>= :: forall a b. NIO a -> (a -> NIO b) -> NIO b
Monad, Monad NIO
forall a. IO a -> NIO a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> NIO a
$cliftIO :: forall a. IO a -> NIO a
MonadIO, MonadReader FindSourcesJson)

instance MonadUnliftIO NIO where
  withRunInIO :: forall b. ((forall a. NIO a -> IO a) -> IO b) -> NIO b
withRunInIO = forall (n :: * -> *) b (m :: * -> *).
MonadUnliftIO n =>
(n b -> m b)
-> (forall a. m a -> n a)
-> ((forall a. m a -> IO a) -> IO b)
-> m b
wrappedWithRunInIO forall a. ReaderT FindSourcesJson IO a -> NIO a
NIO forall a. NIO a -> ReaderT FindSourcesJson IO a
runNIO

getFindSourcesJson :: NIO FindSourcesJson
getFindSourcesJson :: NIO FindSourcesJson
getFindSourcesJson = forall r (m :: * -> *). MonadReader r m => m r
ask

li :: MonadIO io => IO a -> io a
li :: forall (io :: * -> *) a. MonadIO io => IO a -> io a
li = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO

cli :: IO ()
cli :: IO ()
cli = do
  ((FindSourcesJson
fsj, Colors
colors), NIO ()
nio) <-
    forall {a}.
ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
execParserPure' ParserPrefs
Opts.defaultPrefs ParserInfo ((FindSourcesJson, Colors), NIO ())
opts forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [String]
getArgs
      forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. ParserResult a -> IO a
Opts.handleParseResult
  Colors -> IO ()
setColors Colors
colors
  forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (forall a. NIO a -> ReaderT FindSourcesJson IO a
runNIO NIO ()
nio) FindSourcesJson
fsj
  where
    execParserPure' :: ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
execParserPure' ParserPrefs
pprefs ParserInfo a
pinfo [] =
      forall a. ParserFailure ParserHelp -> ParserResult a
Opts.Failure forall a b. (a -> b) -> a -> b
$
        forall a.
ParserPrefs
-> ParserInfo a
-> ParseError
-> [Context]
-> ParserFailure ParserHelp
Opts.parserFailure ParserPrefs
pprefs ParserInfo a
pinfo (Maybe String -> ParseError
Opts.ShowHelpText forall a. Maybe a
Nothing) forall a. Monoid a => a
mempty
    execParserPure' ParserPrefs
pprefs ParserInfo a
pinfo [String]
args = forall {a}.
ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
Opts.execParserPure ParserPrefs
pprefs ParserInfo a
pinfo [String]
args
    opts :: ParserInfo ((FindSourcesJson, Colors), NIO ())
opts = forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info ((,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser FindSourcesJson
parseFindSourcesJson forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Colors
parseColors) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Parser (NIO ())
parseCommand forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
versionflag)) forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall {a}. [InfoMod a]
desc
    desc :: [InfoMod a]
desc =
      [ forall a. InfoMod a
Opts.fullDesc,
        forall a. Maybe Doc -> InfoMod a
Opts.headerDoc forall a b. (a -> b) -> a -> b
$
          forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
            Doc
"niv - dependency manager for Nix projects"
              Doc -> Doc -> Doc
Opts.<$$> Doc
""
              Doc -> Doc -> Doc
Opts.<$$> Doc
"version:" Doc -> Doc -> Doc
Opts.<+> String -> Doc
Opts.text (Version -> String
showVersion Version
version)
      ]
    parseFindSourcesJson :: Parser FindSourcesJson
parseFindSourcesJson =
      String -> FindSourcesJson
AtPath
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s. IsString s => Mod OptionFields s -> Parser s
Opts.strOption
          ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"sources-file"
              forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opts.short Char
's'
              forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"FILE"
              forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Use FILE instead of nix/sources.json"
          )
        forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (f :: * -> *) a. Applicative f => a -> f a
pure FindSourcesJson
Auto
    parseColors :: Parser Colors
parseColors =
      (\case Bool
True -> Colors
Never; Bool
False -> Colors
Always)
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mod FlagFields Bool -> Parser Bool
Opts.switch
          ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"no-colors"
              forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Don't use colors in output"
          )
    versionflag :: Opts.Parser (a -> a)
    versionflag :: forall a. Parser (a -> a)
versionflag =
      forall a.
ParseError -> Mod OptionFields (a -> a) -> Parser (a -> a)
Opts.abortOption (String -> ParseError
Opts.InfoMsg (Version -> String
showVersion Version
version)) forall a b. (a -> b) -> a -> b
$
        forall a. Monoid a => [a] -> a
mconcat
          [forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"version", forall (f :: * -> *) a. Mod f a
Opts.hidden, forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Print version"]

parseCommand :: Opts.Parser (NIO ())
parseCommand :: Parser (NIO ())
parseCommand =
  forall a. Mod CommandFields a -> Parser a
Opts.subparser
    ( forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"init" ParserInfo (NIO ())
parseCmdInit
        forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"add" ParserInfo (NIO ())
parseCmdAdd
        forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"show" ParserInfo (NIO ())
parseCmdShow
        forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"update" ParserInfo (NIO ())
parseCmdUpdate
        forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"modify" ParserInfo (NIO ())
parseCmdModify
        forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"drop" ParserInfo (NIO ())
parseCmdDrop
    )

parsePackageName :: Opts.Parser PackageName
parsePackageName :: Parser PackageName
parsePackageName =
  Text -> PackageName
PackageName
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. ReadM a -> Mod ArgumentFields a -> Parser a
Opts.argument forall s. IsString s => ReadM s
Opts.str (forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"PACKAGE")

parsePackage :: Opts.Parser (PackageName, PackageSpec)
parsePackage :: Parser (PackageName, PackageSpec)
parsePackage = (,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser PackageName
parsePackageName forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Cmd -> Parser PackageSpec
parsePackageSpec Cmd
githubCmd)

-------------------------------------------------------------------------------
-- INIT
-------------------------------------------------------------------------------

-- | Whether or not to fetch nixpkgs
data FetchNixpkgs
  = NoNixpkgs
  | NixpkgsFast -- Pull latest known nixpkgs
  | NixpkgsCustom T.Text Nixpkgs -- branch, nixpkgs
  deriving (Int -> FetchNixpkgs -> ShowS
[FetchNixpkgs] -> ShowS
FetchNixpkgs -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FetchNixpkgs] -> ShowS
$cshowList :: [FetchNixpkgs] -> ShowS
show :: FetchNixpkgs -> String
$cshow :: FetchNixpkgs -> String
showsPrec :: Int -> FetchNixpkgs -> ShowS
$cshowsPrec :: Int -> FetchNixpkgs -> ShowS
Show)

data Nixpkgs = Nixpkgs T.Text T.Text -- owner, repo

instance Show Nixpkgs where
  show :: Nixpkgs -> String
show (Nixpkgs Text
o Text
r) = Text -> String
T.unpack Text
o forall a. Semigroup a => a -> a -> a
<> String
"/" forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
r

parseCmdInit :: Opts.ParserInfo (NIO ())
parseCmdInit :: ParserInfo (NIO ())
parseCmdInit = forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info (FetchNixpkgs -> NIO ()
cmdInit forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser FetchNixpkgs
parseNixpkgs forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper) forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall {a}. [InfoMod a]
desc
  where
    desc :: [InfoMod a]
desc =
      [ forall a. InfoMod a
Opts.fullDesc,
        forall a. String -> InfoMod a
Opts.progDesc
          String
"Initialize a Nix project. Existing files won't be modified."
      ]

parseNixpkgs :: Opts.Parser FetchNixpkgs
parseNixpkgs :: Parser FetchNixpkgs
parseNixpkgs = Parser FetchNixpkgs
parseNixpkgsFast forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser FetchNixpkgs
parseNixpkgsLatest forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser FetchNixpkgs
parseNixpkgsCustom forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser FetchNixpkgs
parseNoNixpkgs forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (f :: * -> *) a. Applicative f => a -> f a
pure FetchNixpkgs
NixpkgsFast
  where
    parseNixpkgsFast :: Parser FetchNixpkgs
parseNixpkgsFast =
      forall a. a -> Mod FlagFields a -> Parser a
Opts.flag'
        FetchNixpkgs
NixpkgsFast
        ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"fast"
            forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Use the latest nixpkgs cached at 'https://github.com/nmattia/niv/blob/master/data/nixpkgs.json'. This is the default."
        )
    parseNixpkgsLatest :: Parser FetchNixpkgs
parseNixpkgsLatest =
      forall a. a -> Mod FlagFields a -> Parser a
Opts.flag'
        (Text -> Nixpkgs -> FetchNixpkgs
NixpkgsCustom Text
"master" (Text -> Text -> Nixpkgs
Nixpkgs Text
"NixOS" Text
"nixpkgs"))
        ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"latest"
            forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Pull the latest unstable nixpkgs from NixOS/nixpkgs."
        )
    parseNixpkgsCustom :: Parser FetchNixpkgs
parseNixpkgsCustom =
      (forall a b c. (a -> b -> c) -> b -> a -> c
flip Text -> Nixpkgs -> FetchNixpkgs
NixpkgsCustom)
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ( forall a. ReadM a -> Mod OptionFields a -> Parser a
Opts.option
                ReadM Nixpkgs
customNixpkgsReader
                ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"nixpkgs"
                    forall a. Semigroup a => a -> a -> a
<> forall a (f :: * -> *). Show a => Mod f a
Opts.showDefault
                    forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Use a custom nixpkgs repository from GitHub."
                    forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"OWNER/REPO"
                )
            )
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ( forall s. IsString s => Mod OptionFields s -> Parser s
Opts.strOption
                ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"nixpkgs-branch"
                    forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opts.short Char
'b'
                    forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"The nixpkgs branch when using --nixpkgs ...."
                    forall a. Semigroup a => a -> a -> a
<> forall a (f :: * -> *). Show a => Mod f a
Opts.showDefault
                )
            )
    parseNoNixpkgs :: Parser FetchNixpkgs
parseNoNixpkgs =
      forall a. a -> Mod FlagFields a -> Parser a
Opts.flag'
        FetchNixpkgs
NoNixpkgs
        ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"no-nixpkgs"
            forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Don't add a nixpkgs entry to sources.json."
        )
    customNixpkgsReader :: ReadM Nixpkgs
customNixpkgsReader = forall a. (String -> Maybe a) -> ReadM a
Opts.maybeReader forall a b. (a -> b) -> a -> b
$ \(String -> Text
T.pack -> Text
repo) -> case Text -> Text -> [Text]
T.splitOn Text
"/" Text
repo of
      [Text
owner, Text
reponame] -> forall a. a -> Maybe a
Just (Text -> Text -> Nixpkgs
Nixpkgs Text
owner Text
reponame)
      [Text]
_ -> forall a. Maybe a
Nothing

cmdInit :: FetchNixpkgs -> NIO ()
cmdInit :: FetchNixpkgs -> NIO ()
cmdInit FetchNixpkgs
nixpkgs = do
  forall (io :: * -> *).
(MonadUnliftIO io, MonadIO io) =>
String -> io () -> io ()
job String
"Initializing" forall a b. (a -> b) -> a -> b
$ do
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    -- Writes all the default files
    -- a path, a "create" function and an update function for each file.
    forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_
      [ ( String
pathNixSourcesNix,
          (String -> ByteString -> NIO ()
`createFile` ByteString
initNixSourcesNixContent),
          \String
path ByteString
content -> do
            if ByteString -> Bool
shouldUpdateNixSourcesNix ByteString
content
              then do
                forall (io :: * -> *). MonadIO io => String -> io ()
say String
"Updating sources.nix"
                forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ String -> ByteString -> IO ()
B.writeFile String
path ByteString
initNixSourcesNixContent
              else forall (io :: * -> *). MonadIO io => String -> io ()
say String
"Not updating sources.nix"
        ),
        ( FindSourcesJson -> String
pathNixSourcesJson FindSourcesJson
fsj,
          \String
path -> do
            String -> ByteString -> NIO ()
createFile String
path ByteString
initNixSourcesJsonContent

            -- Import nixpkgs, if necessary
            FetchNixpkgs -> NIO ()
initNixpkgs FetchNixpkgs
nixpkgs,
          \String
path ByteString
_content -> String -> NIO ()
dontCreateFile String
path
        )
      ]
      forall a b. (a -> b) -> a -> b
$ \(String
path, String -> NIO ()
onCreate, String -> ByteString -> NIO ()
onUpdate) -> do
        Bool
exists <- forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ String -> IO Bool
Dir.doesFileExist String
path
        if Bool
exists then forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (String -> IO ByteString
B.readFile String
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> ByteString -> NIO ()
onUpdate String
path else String -> NIO ()
onCreate String
path
    case FindSourcesJson
fsj of
      FindSourcesJson
Auto -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      AtPath String
fp ->
        forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$
          [Text] -> Text
T.unlines
            [ [Text] -> Text
T.unwords
                [ T
tbold forall a b. (a -> b) -> a -> b
$ T
tblue Text
"INFO:",
                  Text
"You are using a custom path for sources.json."
                ],
              Text
"  You need to configure the sources.nix to use " forall a. Semigroup a => a -> a -> a
<> T
tbold (String -> Text
T.pack String
fp) forall a. Semigroup a => a -> a -> a
<> Text
":",
              T
tbold Text
"      import sources.nix { sourcesFile = PATH ; }; ",
              [Text] -> Text
T.unwords
                [ Text
"  where",
                  T
tbold Text
"PATH",
                  Text
"is the relative path from sources.nix to",
                  T
tbold (String -> Text
T.pack String
fp) forall a. Semigroup a => a -> a -> a
<> Text
"."
                ]
            ]
  where
    createFile :: FilePath -> B.ByteString -> NIO ()
    createFile :: String -> ByteString -> NIO ()
createFile String
path ByteString
content = forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ do
      let dir :: String
dir = ShowS
takeDirectory String
path
      Bool -> String -> IO ()
Dir.createDirectoryIfMissing Bool
True String
dir
      forall (io :: * -> *). MonadIO io => String -> io ()
say forall a b. (a -> b) -> a -> b
$ String
"Creating " forall a. Semigroup a => a -> a -> a
<> String
path
      String -> ByteString -> IO ()
B.writeFile String
path ByteString
content
    dontCreateFile :: FilePath -> NIO ()
    dontCreateFile :: String -> NIO ()
dontCreateFile String
path = forall (io :: * -> *). MonadIO io => String -> io ()
say forall a b. (a -> b) -> a -> b
$ String
"Not creating " forall a. Semigroup a => a -> a -> a
<> String
path

initNixpkgs :: FetchNixpkgs -> NIO ()
initNixpkgs :: FetchNixpkgs -> NIO ()
initNixpkgs FetchNixpkgs
nixpkgs =
  case FetchNixpkgs
nixpkgs of
    FetchNixpkgs
NoNixpkgs -> forall (io :: * -> *). MonadIO io => String -> io ()
say String
"Not importing 'nixpkgs'."
    FetchNixpkgs
NixpkgsFast -> do
      forall (io :: * -> *). MonadIO io => String -> io ()
say String
"Using known 'nixpkgs' ..."
      PackageSpec
packageSpec <- forall a. Response a -> a
HTTP.getResponseBody forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
(MonadIO m, FromJSON a) =>
Request -> m (Response a)
HTTP.httpJSON Request
"https://raw.githubusercontent.com/nmattia/niv/master/data/nixpkgs.json"
      Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd
        Cmd
githubCmd
        (Text -> PackageName
PackageName Text
"nixpkgs")
        (PackageSpec -> Attrs
specToLockedAttrs PackageSpec
packageSpec)
      forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    NixpkgsCustom Text
branch Nixpkgs
nixpkgs' -> do
      forall (io :: * -> *). MonadIO io => String -> io ()
say String
"Importing 'nixpkgs' ..."
      let (Text
owner, Text
repo) = case Nixpkgs
nixpkgs' of
            Nixpkgs Text
o Text
r -> (Text
o, Text
r)
      Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd
        Cmd
githubCmd
        (Text -> PackageName
PackageName Text
"nixpkgs")
        ( PackageSpec -> Attrs
specToFreeAttrs forall a b. (a -> b) -> a -> b
$
            Object -> PackageSpec
PackageSpec forall a b. (a -> b) -> a -> b
$
              forall v. [(Key, v)] -> KeyMap v
KM.fromList
                [ Key
"owner" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
owner,
                  Key
"repo" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
repo,
                  Key
"branch" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
branch
                ]
        )

-------------------------------------------------------------------------------
-- ADD
-------------------------------------------------------------------------------

parseCmdAdd :: Opts.ParserInfo (NIO ())
parseCmdAdd :: ParserInfo (NIO ())
parseCmdAdd =
  forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info
    ((Parser (NIO ())
parseCommands forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (NIO ())
parseShortcuts) forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper)
    forall a b. (a -> b) -> a -> b
$ (Cmd -> forall a. InfoMod a
description Cmd
githubCmd)
  where
    -- XXX: this should parse many shortcuts (github, git). Right now we only
    -- parse GitHub because the git interface is still experimental.  note to
    -- implementer: it'll be tricky to have the correct arguments show up
    -- without repeating "PACKAGE PACKAGE PACKAGE" for every package type.
    parseShortcuts :: Parser (NIO ())
parseShortcuts = Cmd -> Parser (NIO ())
parseShortcut Cmd
githubCmd
    parseShortcut :: Cmd -> Parser (NIO ())
parseShortcut Cmd
cmd = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd Cmd
cmd) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Cmd -> Parser (PackageName, Attrs)
parseShortcutArgs Cmd
cmd)
    parseCmd :: Cmd -> Parser (NIO ())
parseCmd Cmd
cmd = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd Cmd
cmd) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Cmd -> Parser (PackageName, Attrs)
parseCmdArgs Cmd
cmd)
    parseCmdAddGit :: ParserInfo (NIO ())
parseCmdAddGit =
      forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info (Cmd -> Parser (NIO ())
parseCmd Cmd
gitCmd forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper) (Cmd -> forall a. InfoMod a
description Cmd
gitCmd)
    parseCmdAddLocal :: ParserInfo (NIO ())
parseCmdAddLocal =
      forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info (Cmd -> Parser (NIO ())
parseCmd Cmd
localCmd forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper) (Cmd -> forall a. InfoMod a
description Cmd
localCmd)
    parseCmdAddGitHub :: ParserInfo (NIO ())
parseCmdAddGitHub =
      forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info (Cmd -> Parser (NIO ())
parseCmd Cmd
githubCmd forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper) (Cmd -> forall a. InfoMod a
description Cmd
githubCmd)
    parseCommands :: Parser (NIO ())
parseCommands =
      forall a. Mod CommandFields a -> Parser a
Opts.subparser
        ( forall (f :: * -> *) a. Mod f a
Opts.hidden
            forall a. Semigroup a => a -> a -> a
<> forall a. String -> Mod CommandFields a
Opts.commandGroup String
"Experimental commands:"
            forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"git" ParserInfo (NIO ())
parseCmdAddGit
            forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"github" ParserInfo (NIO ())
parseCmdAddGitHub
            forall a. Semigroup a => a -> a -> a
<> forall a. String -> ParserInfo a -> Mod CommandFields a
Opts.command String
"local" ParserInfo (NIO ())
parseCmdAddLocal
        )

-- | only used in shortcuts (niv add foo/bar ...) because PACKAGE is NOT
-- optional
parseShortcutArgs :: Cmd -> Opts.Parser (PackageName, Attrs)
parseShortcutArgs :: Cmd -> Parser (PackageName, Attrs)
parseShortcutArgs Cmd
cmd = forall {a}. ((a, Object), Maybe a) -> PackageSpec -> (a, Attrs)
collapse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ((PackageName, Object), Maybe PackageName)
parseNameAndShortcut forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Cmd -> Parser PackageSpec
parsePackageSpec Cmd
cmd
  where
    collapse :: ((a, Object), Maybe a) -> PackageSpec -> (a, Attrs)
collapse ((a, Object), Maybe a)
specAndName PackageSpec
pspec = (a
pname, PackageSpec -> Attrs
specToLockedAttrs forall a b. (a -> b) -> a -> b
$ PackageSpec
pspec forall a. Semigroup a => a -> a -> a
<> PackageSpec
baseSpec)
      where
        (a
pname, PackageSpec
baseSpec) = case ((a, Object), Maybe a)
specAndName of
          ((a
_, Object
spec), Just a
pname') -> (a
pname', Object -> PackageSpec
PackageSpec Object
spec)
          ((a
pname', Object
spec), Maybe a
Nothing) -> (a
pname', Object -> PackageSpec
PackageSpec Object
spec)
    parseNameAndShortcut :: Parser ((PackageName, Object), Maybe PackageName)
parseNameAndShortcut =
      (,)
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. ReadM a -> Mod ArgumentFields a -> Parser a
Opts.argument
          (forall a. (String -> Maybe a) -> ReadM a
Opts.maybeReader (Cmd -> Text -> Maybe (PackageName, Object)
parseCmdShortcut Cmd
cmd forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack))
          (forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"PACKAGE")
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe PackageName)
optName
    optName :: Parser (Maybe PackageName)
optName =
      forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional forall a b. (a -> b) -> a -> b
$
        Text -> PackageName
PackageName
          forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s. IsString s => Mod OptionFields s -> Parser s
Opts.strOption
            ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"name"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opts.short Char
'n'
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"NAME"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Set the package name to <NAME>"
            )

-- | only used in command (niv add <cmd> ...) because PACKAGE is optional
parseCmdArgs :: Cmd -> Opts.Parser (PackageName, Attrs)
parseCmdArgs :: Cmd -> Parser (PackageName, Attrs)
parseCmdArgs Cmd
cmd = (Maybe (PackageName, Object), Maybe PackageName)
-> PackageSpec -> (PackageName, Attrs)
collapse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Maybe (PackageName, Object), Maybe PackageName)
parseNameAndShortcut forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Cmd -> Parser PackageSpec
parsePackageSpec Cmd
cmd
  where
    collapse :: (Maybe (PackageName, Object), Maybe PackageName)
-> PackageSpec -> (PackageName, Attrs)
collapse (Maybe (PackageName, Object), Maybe PackageName)
specAndName PackageSpec
pspec = (PackageName
pname, PackageSpec -> Attrs
specToLockedAttrs forall a b. (a -> b) -> a -> b
$ PackageSpec
pspec forall a. Semigroup a => a -> a -> a
<> PackageSpec
baseSpec)
      where
        (PackageName
pname, PackageSpec
baseSpec) = case (Maybe (PackageName, Object), Maybe PackageName)
specAndName of
          (Just (PackageName
_, Object
spec), Just PackageName
pname') -> (PackageName
pname', Object -> PackageSpec
PackageSpec Object
spec)
          (Just (PackageName
pname', Object
spec), Maybe PackageName
Nothing) -> (PackageName
pname', Object -> PackageSpec
PackageSpec Object
spec)
          (Maybe (PackageName, Object)
Nothing, Just PackageName
pname') -> (PackageName
pname', Object -> PackageSpec
PackageSpec forall v. KeyMap v
KM.empty)
          (Maybe (PackageName, Object)
Nothing, Maybe PackageName
Nothing) -> (Text -> PackageName
PackageName Text
"unnamed", Object -> PackageSpec
PackageSpec forall v. KeyMap v
KM.empty)
    parseNameAndShortcut :: Parser (Maybe (PackageName, Object), Maybe PackageName)
parseNameAndShortcut =
      (,)
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional
          ( forall a. ReadM a -> Mod ArgumentFields a -> Parser a
Opts.argument
              (forall a. (String -> Maybe a) -> ReadM a
Opts.maybeReader (Cmd -> Text -> Maybe (PackageName, Object)
parseCmdShortcut Cmd
cmd forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack))
              (forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"PACKAGE")
          )
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe PackageName)
optName
    optName :: Parser (Maybe PackageName)
optName =
      forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional forall a b. (a -> b) -> a -> b
$
        Text -> PackageName
PackageName
          forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s. IsString s => Mod OptionFields s -> Parser s
Opts.strOption
            ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"name"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opts.short Char
'n'
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"NAME"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Set the package name to <NAME>"
            )

cmdAdd :: Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd :: Cmd -> PackageName -> Attrs -> NIO ()
cmdAdd Cmd
cmd PackageName
packageName Attrs
attrs = do
  forall (io :: * -> *).
(MonadUnliftIO io, MonadIO io) =>
String -> io () -> io ()
job (String
"Adding package " forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack (PackageName -> Text
unPackageName PackageName
packageName)) forall a b. (a -> b) -> a -> b
$ do
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HMS.member PackageName
packageName HashMap PackageName PackageSpec
sources) forall a b. (a -> b) -> a -> b
$
      forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
        forall a. PackageName -> IO a
abortCannotAddPackageExists PackageName
packageName
    Either SomeException PackageSpec
eFinalSpec <- forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Attrs -> PackageSpec
attrsToSpec forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (Attrs -> Cmd -> IO (Either SomeException Attrs)
doUpdate Attrs
attrs Cmd
cmd)
    case Either SomeException PackageSpec
eFinalSpec of
      Left SomeException
e -> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (forall a. [(PackageName, SomeException)] -> IO a
abortUpdateFailed [(PackageName
packageName, SomeException
e)])
      Right PackageSpec
finalSpec -> do
        forall (io :: * -> *). MonadIO io => String -> io ()
say forall a b. (a -> b) -> a -> b
$ String
"Writing new sources file"
        forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
          FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$
            HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$
              forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert PackageName
packageName PackageSpec
finalSpec HashMap PackageName PackageSpec
sources

-------------------------------------------------------------------------------
-- SHOW
-------------------------------------------------------------------------------

parseCmdShow :: Opts.ParserInfo (NIO ())
parseCmdShow :: ParserInfo (NIO ())
parseCmdShow =
  forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info
    ((Maybe PackageName -> NIO ()
cmdShow forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional Parser PackageName
parsePackageName) forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper)
    forall a. InfoMod a
Opts.fullDesc

-- TODO: nicer output
cmdShow :: Maybe PackageName -> NIO ()
cmdShow :: Maybe PackageName -> NIO ()
cmdShow = \case
  Just PackageName
packageName -> do
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    case forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HMS.lookup PackageName
packageName HashMap PackageName PackageSpec
sources of
      Just PackageSpec
pspec -> forall (io :: * -> *).
MonadIO io =>
PackageName -> PackageSpec -> io ()
showPackage PackageName
packageName PackageSpec
pspec
      Maybe PackageSpec
Nothing -> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ forall a. PackageName -> IO a
abortCannotShowNoSuchPackage PackageName
packageName
  Maybe PackageName
Nothing -> do
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    forall k (m :: * -> *) v1.
(Eq k, Hashable k, Monad m) =>
HashMap k v1 -> (k -> v1 -> m ()) -> m ()
forWithKeyM_ HashMap PackageName PackageSpec
sources forall a b. (a -> b) -> a -> b
$ forall (io :: * -> *).
MonadIO io =>
PackageName -> PackageSpec -> io ()
showPackage

showPackage :: MonadIO io => PackageName -> PackageSpec -> io ()
showPackage :: forall (io :: * -> *).
MonadIO io =>
PackageName -> PackageSpec -> io ()
showPackage (PackageName Text
pname) (PackageSpec Object
spec) = do
  forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ T
tbold Text
pname
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall v. KeyMap v -> [(Key, v)]
KM.toList Object
spec) forall a b. (a -> b) -> a -> b
$ \(Key
attrName, Value
attrValValue) -> do
    let attrValue :: Text
attrValue = case Value
attrValValue of
          Aeson.String Text
str -> Text
str
          Value
_ -> T
tfaint Text
"<barabajagal>"
    forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"  " forall a. Semigroup a => a -> a -> a
<> Key -> Text
K.toText Key
attrName forall a. Semigroup a => a -> a -> a
<> Text
": " forall a. Semigroup a => a -> a -> a
<> Text
attrValue

-------------------------------------------------------------------------------
-- UPDATE
-------------------------------------------------------------------------------

parseCmdUpdate :: Opts.ParserInfo (NIO ())
parseCmdUpdate :: ParserInfo (NIO ())
parseCmdUpdate =
  forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info
    ((Maybe (PackageName, PackageSpec) -> NIO ()
cmdUpdate forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional Parser (PackageName, PackageSpec)
parsePackage) forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper)
    forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall {a}. [InfoMod a]
desc
  where
    desc :: [InfoMod a]
desc =
      [ forall a. InfoMod a
Opts.fullDesc,
        forall a. String -> InfoMod a
Opts.progDesc String
"Update dependencies",
        forall a. Maybe Doc -> InfoMod a
Opts.headerDoc forall a b. (a -> b) -> a -> b
$
          forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
            Int -> Doc -> Doc
Opts.nest Int
2 forall a b. (a -> b) -> a -> b
$
              Doc
"Examples:"
                Doc -> Doc -> Doc
Opts.<$$> Doc
""
                Doc -> Doc -> Doc
Opts.<$$> [Doc] -> Doc
Opts.vcat
                  [ Int -> Doc -> Doc
Opts.fill Int
30 Doc
"niv update" Doc -> Doc -> Doc
Opts.<+> Doc
"# update all packages",
                    Int -> Doc -> Doc
Opts.fill Int
30 Doc
"niv update nixpkgs" Doc -> Doc -> Doc
Opts.<+> Doc
"# update nixpkgs",
                    Int -> Doc -> Doc
Opts.fill Int
30 Doc
"niv update my-package -v beta-0.2" Doc -> Doc -> Doc
Opts.<+> Doc
"# update my-package to version \"beta-0.2\""
                  ]
      ]

specToFreeAttrs :: PackageSpec -> Attrs
specToFreeAttrs :: PackageSpec -> Attrs
specToFreeAttrs = forall v. KeyMap v -> HashMap Text v
KM.toHashMapText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Freedom
Free,) forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageSpec -> Object
unPackageSpec

specToLockedAttrs :: PackageSpec -> Attrs
specToLockedAttrs :: PackageSpec -> Attrs
specToLockedAttrs = forall v. KeyMap v -> HashMap Text v
KM.toHashMapText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Freedom
Locked,) forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageSpec -> Object
unPackageSpec

cmdUpdate :: Maybe (PackageName, PackageSpec) -> NIO ()
cmdUpdate :: Maybe (PackageName, PackageSpec) -> NIO ()
cmdUpdate = \case
  Just (PackageName
packageName, PackageSpec
cliSpec) ->
    forall (io :: * -> *).
(MonadUnliftIO io, MonadIO io) =>
String -> io () -> io ()
job (String
"Update " forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack (PackageName -> Text
unPackageName PackageName
packageName)) forall a b. (a -> b) -> a -> b
$ do
      FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
      HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
      Either SomeException PackageSpec
eFinalSpec <- case forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HMS.lookup PackageName
packageName HashMap PackageName PackageSpec
sources of
        Just PackageSpec
defaultSpec -> do
          -- lookup the "type" to find a Cmd to run, defaulting to legacy
          -- github
          let cmd :: Cmd
cmd = case forall v. Key -> KeyMap v -> Maybe v
KM.lookup Key
"type" (PackageSpec -> Object
unPackageSpec PackageSpec
defaultSpec) of
                Just Value
"git" -> Cmd
gitCmd
                Just Value
"local" -> Cmd
localCmd
                Maybe Value
_ -> Cmd
githubCmd
              spec :: Attrs
spec = PackageSpec -> Attrs
specToLockedAttrs PackageSpec
cliSpec forall a. Semigroup a => a -> a -> a
<> PackageSpec -> Attrs
specToFreeAttrs PackageSpec
defaultSpec
          forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Attrs -> PackageSpec
attrsToSpec forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (Attrs -> Cmd -> IO (Either SomeException Attrs)
doUpdate Attrs
spec Cmd
cmd)
        Maybe PackageSpec
Nothing -> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ forall a. PackageName -> IO a
abortCannotUpdateNoSuchPackage PackageName
packageName
      case Either SomeException PackageSpec
eFinalSpec of
        Left SomeException
e -> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ forall a. [(PackageName, SomeException)] -> IO a
abortUpdateFailed [(PackageName
packageName, SomeException
e)]
        Right PackageSpec
finalSpec ->
          forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
            FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$
              HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$
                forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert PackageName
packageName PackageSpec
finalSpec HashMap PackageName PackageSpec
sources
  Maybe (PackageName, PackageSpec)
Nothing -> forall (io :: * -> *).
(MonadUnliftIO io, MonadIO io) =>
String -> io () -> io ()
job String
"Updating all packages" forall a b. (a -> b) -> a -> b
$ do
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    HashMap PackageName (Either SomeException PackageSpec)
esources' <- forall k (m :: * -> *) v1 v2.
(Eq k, Hashable k, Monad m) =>
HashMap k v1 -> (k -> v1 -> m v2) -> m (HashMap k v2)
forWithKeyM HashMap PackageName PackageSpec
sources forall a b. (a -> b) -> a -> b
$
      \PackageName
packageName PackageSpec
defaultSpec -> do
        forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"Package: " forall a. Semigroup a => a -> a -> a
<> PackageName -> Text
unPackageName PackageName
packageName
        let initialSpec :: Attrs
initialSpec = PackageSpec -> Attrs
specToFreeAttrs PackageSpec
defaultSpec
        -- lookup the "type" to find a Cmd to run, defaulting to legacy
        -- github
        let cmd :: Cmd
cmd = case forall v. Key -> KeyMap v -> Maybe v
KM.lookup Key
"type" (PackageSpec -> Object
unPackageSpec PackageSpec
defaultSpec) of
              Just Value
"git" -> Cmd
gitCmd
              Just Value
"local" -> Cmd
localCmd
              Maybe Value
_ -> Cmd
githubCmd
        Either SomeException PackageSpec
finalSpec <- forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Attrs -> PackageSpec
attrsToSpec forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (Attrs -> Cmd -> IO (Either SomeException Attrs)
doUpdate Attrs
initialSpec Cmd
cmd)
        forall (f :: * -> *) a. Applicative f => a -> f a
pure Either SomeException PackageSpec
finalSpec
    let (HashMap PackageName SomeException
failed, HashMap PackageName PackageSpec
sources') = forall k a b.
(Eq k, Hashable k) =>
HashMap k (Either a b) -> (HashMap k a, HashMap k b)
partitionEithersHMS HashMap PackageName (Either SomeException PackageSpec)
esources'
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall k v. HashMap k v -> Bool
HMS.null HashMap PackageName SomeException
failed) forall a b. (a -> b) -> a -> b
$
      forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
        forall a. [(PackageName, SomeException)] -> IO a
abortUpdateFailed (forall k v. HashMap k v -> [(k, v)]
HMS.toList HashMap PackageName SomeException
failed)
    forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$ HashMap PackageName PackageSpec -> Sources
Sources HashMap PackageName PackageSpec
sources'

-- | pretty much tryEvalUpdate but we might issue some warnings first
doUpdate :: Attrs -> Cmd -> IO (Either SomeException Attrs)
doUpdate :: Attrs -> Cmd -> IO (Either SomeException Attrs)
doUpdate Attrs
attrs Cmd
cmd = do
  forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Cmd -> Attrs -> [Text]
extraLogs Cmd
cmd Attrs
attrs) forall a b. (a -> b) -> a -> b
$ forall (io :: * -> *). MonadIO io => Text -> io ()
tsay
  forall a. Attrs -> Update () a -> IO (Either SomeException Attrs)
tryEvalUpdate Attrs
attrs (Cmd -> Update () ()
updateCmd Cmd
cmd)

partitionEithersHMS ::
  (Eq k, Hashable k) =>
  HMS.HashMap k (Either a b) ->
  (HMS.HashMap k a, HMS.HashMap k b)
partitionEithersHMS :: forall k a b.
(Eq k, Hashable k) =>
HashMap k (Either a b) -> (HashMap k a, HashMap k b)
partitionEithersHMS =
  forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a k v. (a -> k -> v -> a) -> a -> HashMap k v -> a
HMS.foldlWithKey' (forall k v. HashMap k v
HMS.empty, forall k v. HashMap k v
HMS.empty) forall a b. (a -> b) -> a -> b
$ \(HashMap k a
ls, HashMap k b
rs) k
k -> \case
    Left a
l -> (forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert k
k a
l HashMap k a
ls, HashMap k b
rs)
    Right b
r -> (HashMap k a
ls, forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert k
k b
r HashMap k b
rs)

-------------------------------------------------------------------------------
-- MODIFY
-------------------------------------------------------------------------------

parseCmdModify :: Opts.ParserInfo (NIO ())
parseCmdModify :: ParserInfo (NIO ())
parseCmdModify =
  forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info
    ((PackageName -> Maybe PackageName -> PackageSpec -> NIO ()
cmdModify forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser PackageName
parsePackageName forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe PackageName)
optName forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Cmd -> Parser PackageSpec
parsePackageSpec Cmd
githubCmd) forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper)
    forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall {a}. [InfoMod a]
desc
  where
    desc :: [InfoMod a]
desc =
      [ forall a. InfoMod a
Opts.fullDesc,
        forall a. String -> InfoMod a
Opts.progDesc String
"Modify dependency attributes without performing an update",
        forall a. Maybe Doc -> InfoMod a
Opts.headerDoc forall a b. (a -> b) -> a -> b
$
          forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
            Doc
"Examples:"
              Doc -> Doc -> Doc
Opts.<$$> Doc
""
              Doc -> Doc -> Doc
Opts.<$$> Doc
"  niv modify nixpkgs -v beta-0.2"
              Doc -> Doc -> Doc
Opts.<$$> Doc
"  niv modify nixpkgs -a branch=nixpkgs-unstable"
      ]
    optName :: Parser (Maybe PackageName)
optName =
      forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Opts.optional forall a b. (a -> b) -> a -> b
$
        Text -> PackageName
PackageName
          forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s. IsString s => Mod OptionFields s -> Parser s
Opts.strOption
            ( forall (f :: * -> *) a. HasName f => String -> Mod f a
Opts.long String
"name"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opts.short Char
'n'
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"NAME"
                forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. String -> Mod f a
Opts.help String
"Set the package name to <NAME>"
            )

cmdModify :: PackageName -> Maybe PackageName -> PackageSpec -> NIO ()
cmdModify :: PackageName -> Maybe PackageName -> PackageSpec -> NIO ()
cmdModify PackageName
packageName Maybe PackageName
mNewName PackageSpec
cliSpec = do
  forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"Modifying package: " forall a. Semigroup a => a -> a -> a
<> PackageName -> Text
unPackageName PackageName
packageName
  FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
  HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
  PackageSpec
finalSpec <- case forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HMS.lookup PackageName
packageName HashMap PackageName PackageSpec
sources of
    Just PackageSpec
defaultSpec -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Attrs -> PackageSpec
attrsToSpec (PackageSpec -> Attrs
specToLockedAttrs PackageSpec
cliSpec forall a. Semigroup a => a -> a -> a
<> PackageSpec -> Attrs
specToFreeAttrs PackageSpec
defaultSpec)
    Maybe PackageSpec
Nothing -> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ forall a. PackageName -> IO a
abortCannotModifyNoSuchPackage PackageName
packageName
  case Maybe PackageName
mNewName of
    Just PackageName
newName -> do
      forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HMS.member PackageName
newName HashMap PackageName PackageSpec
sources) forall a b. (a -> b) -> a -> b
$
        forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
          forall a. PackageName -> IO a
abortCannotAddPackageExists PackageName
newName
      forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$ HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$ forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert PackageName
newName PackageSpec
finalSpec forall a b. (a -> b) -> a -> b
$ forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
HMS.delete PackageName
packageName HashMap PackageName PackageSpec
sources
    Maybe PackageName
Nothing ->
      forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$ HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$ forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert PackageName
packageName PackageSpec
finalSpec HashMap PackageName PackageSpec
sources

-------------------------------------------------------------------------------
-- DROP
-------------------------------------------------------------------------------

parseCmdDrop :: Opts.ParserInfo (NIO ())
parseCmdDrop :: ParserInfo (NIO ())
parseCmdDrop =
  forall a. Parser a -> InfoMod a -> ParserInfo a
Opts.info
    ( (PackageName -> [Text] -> NIO ()
cmdDrop forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser PackageName
parsePackageName forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser [Text]
parseDropAttributes)
        forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> forall a. Parser (a -> a)
Opts.helper
    )
    forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall {a}. [InfoMod a]
desc
  where
    desc :: [InfoMod a]
desc =
      [ forall a. InfoMod a
Opts.fullDesc,
        forall a. String -> InfoMod a
Opts.progDesc String
"Drop dependency",
        forall a. Maybe Doc -> InfoMod a
Opts.headerDoc forall a b. (a -> b) -> a -> b
$
          forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
            Doc
"Examples:"
              Doc -> Doc -> Doc
Opts.<$$> Doc
""
              Doc -> Doc -> Doc
Opts.<$$> Doc
"  niv drop jq"
              Doc -> Doc -> Doc
Opts.<$$> Doc
"  niv drop my-package version"
      ]
    parseDropAttributes :: Opts.Parser [T.Text]
    parseDropAttributes :: Parser [Text]
parseDropAttributes =
      forall (f :: * -> *) a. Alternative f => f a -> f [a]
many forall a b. (a -> b) -> a -> b
$
        forall a. ReadM a -> Mod ArgumentFields a -> Parser a
Opts.argument forall s. IsString s => ReadM s
Opts.str (forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
Opts.metavar String
"ATTRIBUTE")

cmdDrop :: PackageName -> [T.Text] -> NIO ()
cmdDrop :: PackageName -> [Text] -> NIO ()
cmdDrop PackageName
packageName = \case
  [] -> do
    forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"Dropping package: " forall a. Semigroup a => a -> a -> a
<> PackageName -> Text
unPackageName PackageName
packageName
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HMS.member PackageName
packageName HashMap PackageName PackageSpec
sources) forall a b. (a -> b) -> a -> b
$
      forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
        forall a. PackageName -> IO a
abortCannotDropNoSuchPackage PackageName
packageName
    forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
      FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$
        HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$
          forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
HMS.delete PackageName
packageName HashMap PackageName PackageSpec
sources
  [Text]
attrs -> do
    forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"Dropping attributes: " forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
" " [Text]
attrs
    forall (io :: * -> *). MonadIO io => Text -> io ()
tsay forall a b. (a -> b) -> a -> b
$ Text
"In package: " forall a. Semigroup a => a -> a -> a
<> PackageName -> Text
unPackageName PackageName
packageName
    FindSourcesJson
fsj <- NIO FindSourcesJson
getFindSourcesJson
    HashMap PackageName PackageSpec
sources <- Sources -> HashMap PackageName PackageSpec
unSources forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (io :: * -> *) a. MonadIO io => IO a -> io a
li (FindSourcesJson -> IO Sources
getSources FindSourcesJson
fsj)
    PackageSpec
packageSpec <- case forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HMS.lookup PackageName
packageName HashMap PackageName PackageSpec
sources of
      Maybe PackageSpec
Nothing ->
        forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$ forall a. PackageName -> IO a
abortCannotAttributesDropNoSuchPackage PackageName
packageName
      Just (PackageSpec Object
packageSpec) ->
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
          Object -> PackageSpec
PackageSpec forall a b. (a -> b) -> a -> b
$
            forall v u. (Key -> v -> Maybe u) -> KeyMap v -> KeyMap u
KM.mapMaybeWithKey
              (\Key
k Value
v -> if Key -> Text
K.toText Key
k forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
attrs then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just Value
v)
              Object
packageSpec
    forall (io :: * -> *) a. MonadIO io => IO a -> io a
li forall a b. (a -> b) -> a -> b
$
      FindSourcesJson -> Sources -> IO ()
setSources FindSourcesJson
fsj forall a b. (a -> b) -> a -> b
$
        HashMap PackageName PackageSpec -> Sources
Sources forall a b. (a -> b) -> a -> b
$
          forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HMS.insert PackageName
packageName PackageSpec
packageSpec HashMap PackageName PackageSpec
sources

-------------------------------------------------------------------------------
-- Files and their content
-------------------------------------------------------------------------------

-- | Checks if content is different than default and if it does /not/ contain
-- a comment line with @niv: no_update@
shouldUpdateNixSourcesNix :: B.ByteString -> Bool
shouldUpdateNixSourcesNix :: ByteString -> Bool
shouldUpdateNixSourcesNix ByteString
content =
  ByteString
content forall a. Eq a => a -> a -> Bool
/= ByteString
initNixSourcesNixContent
    Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ByteString -> Bool
lineForbids (ByteString -> [ByteString]
B8.lines ByteString
content))
  where
    lineForbids :: B8.ByteString -> Bool
    lineForbids :: ByteString -> Bool
lineForbids ByteString
str =
      case ByteString -> Maybe (Char, ByteString)
B8.uncons ((Char -> Bool) -> ByteString -> ByteString
B8.dropWhile Char -> Bool
isSpace ByteString
str) of
        Just (Char
'#', ByteString
rest) -> case ByteString -> ByteString -> Maybe ByteString
B8.stripPrefix ByteString
"niv:" ((Char -> Bool) -> ByteString -> ByteString
B8.dropWhile Char -> Bool
isSpace ByteString
rest) of
          Just ByteString
rest' -> case ByteString -> ByteString -> Maybe ByteString
B8.stripPrefix ByteString
"no_update" ((Char -> Bool) -> ByteString -> ByteString
B8.dropWhile Char -> Bool
isSpace ByteString
rest') of
            Just {} -> Bool
True
            Maybe ByteString
_ -> Bool
False
          Maybe ByteString
_ -> Bool
False
        Maybe (Char, ByteString)
_ -> Bool
False

-------------------------------------------------------------------------------
-- Abort
-------------------------------------------------------------------------------

abortCannotAddPackageExists :: PackageName -> IO a
abortCannotAddPackageExists :: forall a. PackageName -> IO a
abortCannotAddPackageExists (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot add package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package already exists. Use",
        Text
"  niv drop " forall a. Semigroup a => a -> a -> a
<> Text
n,
        Text
"and then re-add the package. Alternatively use",
        Text
"  niv update " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
" --attribute foo=bar",
        Text
"to update the package's attributes."
      ]

abortCannotUpdateNoSuchPackage :: PackageName -> IO a
abortCannotUpdateNoSuchPackage :: forall a. PackageName -> IO a
abortCannotUpdateNoSuchPackage (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot update package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package doesn't exist. Use",
        Text
"  niv add " forall a. Semigroup a => a -> a -> a
<> Text
n,
        Text
"to add the package."
      ]

abortCannotModifyNoSuchPackage :: PackageName -> IO a
abortCannotModifyNoSuchPackage :: forall a. PackageName -> IO a
abortCannotModifyNoSuchPackage (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot modify package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package doesn't exist. Use",
        Text
"  niv add " forall a. Semigroup a => a -> a -> a
<> Text
n,
        Text
"to add the package."
      ]

abortCannotDropNoSuchPackage :: PackageName -> IO a
abortCannotDropNoSuchPackage :: forall a. PackageName -> IO a
abortCannotDropNoSuchPackage (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot drop package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package doesn't exist."
      ]

abortCannotShowNoSuchPackage :: PackageName -> IO a
abortCannotShowNoSuchPackage :: forall a. PackageName -> IO a
abortCannotShowNoSuchPackage (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot show package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package doesn't exist."
      ]

abortCannotAttributesDropNoSuchPackage :: PackageName -> IO a
abortCannotAttributesDropNoSuchPackage :: forall a. PackageName -> IO a
abortCannotAttributesDropNoSuchPackage (PackageName Text
n) =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines
      [ Text
"Cannot drop attributes of package " forall a. Semigroup a => a -> a -> a
<> Text
n forall a. Semigroup a => a -> a -> a
<> Text
".",
        Text
"The package doesn't exist."
      ]

abortUpdateFailed :: [(PackageName, SomeException)] -> IO a
abortUpdateFailed :: forall a. [(PackageName, SomeException)] -> IO a
abortUpdateFailed [(PackageName, SomeException)]
errs =
  forall (io :: * -> *) a. MonadIO io => Text -> io a
abort forall a b. (a -> b) -> a -> b
$
    [Text] -> Text
T.unlines forall a b. (a -> b) -> a -> b
$
      [Text
"One or more packages failed to update:"]
        forall a. Semigroup a => a -> a -> a
<> forall a b. (a -> b) -> [a] -> [b]
map
          ( \(PackageName Text
pname, SomeException
e) ->
              Text
pname forall a. Semigroup a => a -> a -> a
<> Text
": " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
tshow SomeException
e
          )
          [(PackageName, SomeException)]
errs