1
1
mirror of https://github.com/nmattia/niv.git synced 2024-09-20 20:07:38 +03:00

Merge pull request #67 from nmattia/nm-cleanup

Light cleanup
This commit is contained in:
Nicolas Mattia 2019-06-09 19:07:09 +02:00 committed by GitHub
commit 65786ee156
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 78 deletions

View File

@ -11,7 +11,7 @@ import Control.Applicative
import Control.Monad import Control.Monad
import Control.Monad.State import Control.Monad.State
import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey) import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
import Data.Char (isSpace, toUpper) import Data.Char (isSpace)
import Data.FileEmbed (embedFile) import Data.FileEmbed (embedFile)
import Data.Functor ((<&>)) import Data.Functor ((<&>))
import Data.Hashable (Hashable) import Data.Hashable (Hashable)
@ -27,8 +27,9 @@ import qualified Data.Aeson.Encode.Pretty as AesonPretty
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8 import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.HashMap.Strict as HMap import qualified Data.HashMap.Strict as HMS
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified GitHub as GH import qualified GitHub as GH
import qualified GitHub.Data.Name as GH import qualified GitHub.Data.Name as GH
import qualified Options.Applicative as Opts import qualified Options.Applicative as Opts
@ -53,7 +54,7 @@ parseCommand = Opts.subparser (
Opts.command "drop" parseCmdDrop ) Opts.command "drop" parseCmdDrop )
newtype Sources = Sources newtype Sources = Sources
{ unSources :: HMap.HashMap PackageName PackageSpec } { unSources :: HMS.HashMap PackageName PackageSpec }
deriving newtype (FromJSON, ToJSON) deriving newtype (FromJSON, ToJSON)
getSources :: IO Sources getSources :: IO Sources
@ -67,19 +68,18 @@ getSources = do
decodeFileStrict pathNixSourcesJson >>= \case decodeFileStrict pathNixSourcesJson >>= \case
Just (Aeson.Object obj) -> Just (Aeson.Object obj) ->
fmap (Sources . mconcat) $ fmap (Sources . mconcat) $
forM (HMap.toList obj) $ \(k, v) -> forM (HMS.toList obj) $ \(k, v) ->
case v of case v of
Aeson.Object v' -> Aeson.Object v' ->
pure $ HMap.singleton (PackageName (T.unpack k)) (PackageSpec v') pure $ HMS.singleton (PackageName k) (PackageSpec v')
_ -> abortAttributeIsntAMap _ -> abortAttributeIsntAMap
Just _ -> abortSourcesIsntAMap Just _ -> abortSourcesIsntAMap
Nothing -> abortSourcesIsntJSON Nothing -> abortSourcesIsntJSON
-- TODO: pretty
setSources :: Sources -> IO () setSources :: Sources -> IO ()
setSources sources = encodeFile pathNixSourcesJson sources setSources sources = encodeFile pathNixSourcesJson sources
newtype PackageName = PackageName { unPackageName :: String } newtype PackageName = PackageName { unPackageName :: T.Text }
deriving newtype (Eq, Hashable, FromJSONKey, ToJSONKey, Show) deriving newtype (Eq, Hashable, FromJSONKey, ToJSONKey, Show)
parsePackageName :: Opts.Parser PackageName parsePackageName :: Opts.Parser PackageName
@ -91,10 +91,10 @@ newtype PackageSpec = PackageSpec { _unPackageSpec :: Aeson.Object }
parsePackageSpec :: Opts.Parser PackageSpec parsePackageSpec :: Opts.Parser PackageSpec
parsePackageSpec = parsePackageSpec =
(PackageSpec . HMap.fromList . fmap fixupAttributes) <$> (PackageSpec . HMS.fromList . fmap fixupAttributes) <$>
many parseAttribute many parseAttribute
where where
parseAttribute :: Opts.Parser (String, String) parseAttribute :: Opts.Parser (T.Text, T.Text)
parseAttribute = parseAttribute =
Opts.option (Opts.maybeReader parseKeyVal) Opts.option (Opts.maybeReader parseKeyVal)
( Opts.long "attribute" <> ( Opts.long "attribute" <>
@ -116,32 +116,32 @@ parsePackageSpec =
)) ))
-- Parse "key=val" into ("key", "val") -- Parse "key=val" into ("key", "val")
parseKeyVal :: String -> Maybe (String, String) parseKeyVal :: String -> Maybe (T.Text, T.Text)
parseKeyVal str = case span (/= '=') str of parseKeyVal str = case span (/= '=') str of
(key, '=':val) -> Just (key, val) (key, '=':val) -> Just (T.pack key, T.pack val)
_ -> Nothing _ -> Nothing
-- Shortcuts for common attributes -- Shortcuts for common attributes
shortcutAttributes :: Opts.Parser (String, String) shortcutAttributes :: Opts.Parser (T.Text, T.Text)
shortcutAttributes = foldr (<|>) empty $ mkShortcutAttribute <$> shortcutAttributes = foldr (<|>) empty $ mkShortcutAttribute <$>
[ "branch", "owner", "repo", "version" ] [ "branch", "owner", "repo", "version" ]
mkShortcutAttribute :: String -> Opts.Parser (String, String) mkShortcutAttribute :: T.Text -> Opts.Parser (T.Text, T.Text)
mkShortcutAttribute = \case mkShortcutAttribute = \case
attr@(c:_) -> (attr,) <$> Opts.strOption attr@(T.uncons -> Just (c,_)) -> (attr,) <$> Opts.strOption
( Opts.long attr <> ( Opts.long (T.unpack attr) <>
Opts.short c <> Opts.short c <>
Opts.metavar (toUpper <$> attr) <> Opts.metavar (T.unpack $ T.toUpper attr) <>
Opts.help Opts.help
( ( T.unpack $
"Equivalent to --attribute " <> "Equivalent to --attribute " <>
attr <> "=<" <> (toUpper <$> attr) <> ">" attr <> "=<" <> (T.toUpper attr) <> ">"
) )
) )
_ -> empty _ -> empty
fixupAttributes :: (String, String) -> (T.Text, Aeson.Value) fixupAttributes :: (T.Text, T.Text) -> (T.Text, Aeson.Value)
fixupAttributes (k, v) = (T.pack k, Aeson.String (T.pack v)) fixupAttributes (k, v) = (k, Aeson.String v)
parsePackage :: Opts.Parser (PackageName, PackageSpec) parsePackage :: Opts.Parser (PackageName, PackageSpec)
parsePackage = (,) <$> parsePackageName <*> parsePackageSpec parsePackage = (,) <$> parsePackageName <*> parsePackageSpec
@ -251,10 +251,10 @@ completePackageSpec = execStateT $ do
whenNotSet "url_template" $ whenNotSet "url_template" $
setPackageSpecAttr setPackageSpecAttr
"url_template" "url_template"
(Aeson.String $ T.pack githubURLTemplate) (Aeson.String githubURLTemplate)
where where
githubURLTemplate :: String githubURLTemplate :: T.Text
githubURLTemplate = githubURLTemplate =
"https://github.com/<owner>/<repo>/archive/<rev>.tar.gz" "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
@ -283,18 +283,18 @@ getPackageSpecAttr
-> StateT PackageSpec IO (Maybe Aeson.Value) -> StateT PackageSpec IO (Maybe Aeson.Value)
getPackageSpecAttr attrName = do getPackageSpecAttr attrName = do
PackageSpec obj <- get PackageSpec obj <- get
pure $ HMap.lookup attrName obj pure $ HMS.lookup attrName obj
setPackageSpecAttr setPackageSpecAttr
:: T.Text -> Aeson.Value :: T.Text -> Aeson.Value
-> StateT PackageSpec IO () -> StateT PackageSpec IO ()
setPackageSpecAttr attrName attrValue = do setPackageSpecAttr attrName attrValue = do
PackageSpec obj <- get PackageSpec obj <- get
let obj' = HMap.insert attrName attrValue obj let obj' = HMS.insert attrName attrValue obj
put (PackageSpec obj') put (PackageSpec obj')
packageSpecStringValues :: PackageSpec -> [(String, String)] packageSpecStringValues :: PackageSpec -> [(String, String)]
packageSpecStringValues (PackageSpec m) = mapMaybe toVal (HMap.toList m) packageSpecStringValues (PackageSpec m) = mapMaybe toVal (HMS.toList m)
where where
toVal :: (T.Text, Aeson.Value) -> Maybe (String, String) toVal :: (T.Text, Aeson.Value) -> Maybe (String, String)
toVal = \case toVal = \case
@ -334,12 +334,12 @@ cmdInit = do
createFile path initNixSourcesJsonContent createFile path initNixSourcesJsonContent
-- Imports @niv@ and @nixpkgs@ (18.09) -- Imports @niv@ and @nixpkgs@ (18.09)
putStrLn "Importing 'niv' ..." putStrLn "Importing 'niv' ..."
cmdAdd Nothing (PackageName "nmattia/niv", PackageSpec HMap.empty) cmdAdd Nothing (PackageName "nmattia/niv", PackageSpec HMS.empty)
putStrLn "Importing 'nixpkgs' ..." putStrLn "Importing 'nixpkgs' ..."
cmdAdd cmdAdd
(Just (PackageName "nixpkgs")) (Just (PackageName "nixpkgs"))
( PackageName "NixOS/nixpkgs-channels" ( PackageName "NixOS/nixpkgs-channels"
, PackageSpec (HMap.singleton "branch" "nixos-18.09")) , PackageSpec (HMS.singleton "branch" "nixos-18.09"))
, \path _content -> dontCreateFile path) , \path _content -> dontCreateFile path)
] $ \(path, onCreate, onUpdate) -> do ] $ \(path, onCreate, onUpdate) -> do
exists <- Dir.doesFileExist path exists <- Dir.doesFileExist path
@ -385,12 +385,13 @@ cmdAdd :: Maybe PackageName -> (PackageName, PackageSpec) -> IO ()
cmdAdd mPackageName (PackageName str, spec) = do cmdAdd mPackageName (PackageName str, spec) = do
-- Figures out the owner and repo -- Figures out the owner and repo
(packageName, spec') <- flip runStateT spec $ case span (/= '/') str of (packageName, spec') <- flip runStateT spec $ case T.span (/= '/') str of
(owner@(_:_), '/':repo@(_:_)) -> do ( owner@(T.null -> False)
, T.uncons -> Just ('/', repo@(T.null -> False))) -> do
whenNotSet "owner" $ whenNotSet "owner" $
setPackageSpecAttr "owner" (Aeson.String $ T.pack owner) setPackageSpecAttr "owner" (Aeson.String owner)
whenNotSet "repo" $ do whenNotSet "repo" $ do
setPackageSpecAttr "repo" (Aeson.String $ T.pack repo) setPackageSpecAttr "repo" (Aeson.String repo)
pure (PackageName repo) pure (PackageName repo)
_ -> pure (PackageName str) _ -> pure (PackageName str)
@ -398,14 +399,14 @@ cmdAdd mPackageName (PackageName str, spec) = do
let packageName' = fromMaybe packageName mPackageName let packageName' = fromMaybe packageName mPackageName
when (HMap.member packageName' sources) $ when (HMS.member packageName' sources) $
abortCannotAddPackageExists packageName' abortCannotAddPackageExists packageName'
spec'' <- updatePackageSpec =<< completePackageSpec spec' spec'' <- updatePackageSpec =<< completePackageSpec spec'
putStrLn $ "Writing new sources file" putStrLn $ "Writing new sources file"
setSources $ Sources $ setSources $ Sources $
HMap.insert packageName' spec'' sources HMS.insert packageName' spec'' sources
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- SHOW -- SHOW
@ -421,8 +422,8 @@ cmdShow = do
sources <- unSources <$> getSources sources <- unSources <$> getSources
forWithKeyM_ sources $ \key (PackageSpec spec) -> do forWithKeyM_ sources $ \key (PackageSpec spec) -> do
putStrLn $ "Package: " <> unPackageName key T.putStrLn $ "Package: " <> unPackageName key
forM_ (HMap.toList spec) $ \(attrName, attrValValue) -> do forM_ (HMS.toList spec) $ \(attrName, attrValValue) -> do
let attrValue = case attrValValue of let attrValue = case attrValValue of
Aeson.String str -> str Aeson.String str -> str
_ -> "<barabajagal>" _ -> "<barabajagal>"
@ -452,10 +453,10 @@ parseCmdUpdate =
cmdUpdate :: Maybe (PackageName, PackageSpec) -> IO () cmdUpdate :: Maybe (PackageName, PackageSpec) -> IO ()
cmdUpdate = \case cmdUpdate = \case
Just (packageName, packageSpec) -> do Just (packageName, packageSpec) -> do
putStrLn $ "Updating single package: " <> unPackageName packageName T.putStrLn $ "Updating single package: " <> unPackageName packageName
sources <- unSources <$> getSources sources <- unSources <$> getSources
packageSpec' <- case HMap.lookup packageName sources of packageSpec' <- case HMS.lookup packageName sources of
Just packageSpec' -> do Just packageSpec' -> do
-- TODO: something fishy happening here -- TODO: something fishy happening here
@ -465,14 +466,14 @@ cmdUpdate = \case
Nothing -> abortCannotUpdateNoSuchPackage packageName Nothing -> abortCannotUpdateNoSuchPackage packageName
setSources $ Sources $ setSources $ Sources $
HMap.insert packageName packageSpec' sources HMS.insert packageName packageSpec' sources
Nothing -> do Nothing -> do
sources <- unSources <$> getSources sources <- unSources <$> getSources
sources' <- forWithKeyM sources $ sources' <- forWithKeyM sources $
\packageName packageSpec -> do \packageName packageSpec -> do
putStrLn $ "Package: " <> unPackageName packageName T.putStrLn $ "Package: " <> unPackageName packageName
updatePackageSpec =<< completePackageSpec packageSpec updatePackageSpec =<< completePackageSpec packageSpec
setSources $ Sources sources' setSources $ Sources sources'
@ -504,29 +505,29 @@ parseCmdDrop =
cmdDrop :: PackageName -> [T.Text] -> IO () cmdDrop :: PackageName -> [T.Text] -> IO ()
cmdDrop packageName = \case cmdDrop packageName = \case
[] -> do [] -> do
putStrLn $ "Dropping package: " <> unPackageName packageName T.putStrLn $ "Dropping package: " <> unPackageName packageName
sources <- unSources <$> getSources sources <- unSources <$> getSources
when (not $ HMap.member packageName sources) $ when (not $ HMS.member packageName sources) $
abortCannotDropNoSuchPackage packageName abortCannotDropNoSuchPackage packageName
setSources $ Sources $ setSources $ Sources $
HMap.delete packageName sources HMS.delete packageName sources
attrs -> do attrs -> do
putStrLn $ "Dropping attributes :" <> putStrLn $ "Dropping attributes :" <>
(T.unpack (T.intercalate " " attrs)) (T.unpack (T.intercalate " " attrs))
putStrLn $ "In package: " <> unPackageName packageName T.putStrLn $ "In package: " <> unPackageName packageName
sources <- unSources <$> getSources sources <- unSources <$> getSources
packageSpec <- case HMap.lookup packageName sources of packageSpec <- case HMS.lookup packageName sources of
Nothing -> Nothing ->
abortCannotAttributesDropNoSuchPackage packageName abortCannotAttributesDropNoSuchPackage packageName
Just (PackageSpec packageSpec) -> pure $ PackageSpec $ Just (PackageSpec packageSpec) -> pure $ PackageSpec $
HMap.mapMaybeWithKey HMS.mapMaybeWithKey
(\k v -> if k `elem` attrs then Nothing else Just v) packageSpec (\k v -> if k `elem` attrs then Nothing else Just v) packageSpec
setSources $ Sources $ setSources $ Sources $
HMap.insert packageName packageSpec sources HMS.insert packageName packageSpec sources
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Aux -- Aux
@ -556,14 +557,14 @@ encodeFile fp = L.writeFile fp . AesonPretty.encodePretty' config
forWithKeyM forWithKeyM
:: (Eq k, Hashable k, Monad m) :: (Eq k, Hashable k, Monad m)
=> HMap.HashMap k v1 => HMS.HashMap k v1
-> (k -> v1 -> m v2) -> (k -> v1 -> m v2)
-> m (HMap.HashMap k v2) -> m (HMS.HashMap k v2)
forWithKeyM = flip mapWithKeyM forWithKeyM = flip mapWithKeyM
forWithKeyM_ forWithKeyM_
:: (Eq k, Hashable k, Monad m) :: (Eq k, Hashable k, Monad m)
=> HMap.HashMap k v1 => HMS.HashMap k v1
-> (k -> v1 -> m ()) -> (k -> v1 -> m ())
-> m () -> m ()
forWithKeyM_ = flip mapWithKeyM_ forWithKeyM_ = flip mapWithKeyM_
@ -571,20 +572,20 @@ forWithKeyM_ = flip mapWithKeyM_
mapWithKeyM mapWithKeyM
:: (Eq k, Hashable k, Monad m) :: (Eq k, Hashable k, Monad m)
=> (k -> v1 -> m v2) => (k -> v1 -> m v2)
-> HMap.HashMap k v1 -> HMS.HashMap k v1
-> m (HMap.HashMap k v2) -> m (HMS.HashMap k v2)
mapWithKeyM f m = do mapWithKeyM f m = do
fmap mconcat $ forM (HMap.toList m) $ \(k, v) -> fmap mconcat $ forM (HMS.toList m) $ \(k, v) ->
HMap.singleton k <$> f k v HMS.singleton k <$> f k v
mapWithKeyM_ mapWithKeyM_
:: (Eq k, Hashable k, Monad m) :: (Eq k, Hashable k, Monad m)
=> (k -> v1 -> m ()) => (k -> v1 -> m ())
-> HMap.HashMap k v1 -> HMS.HashMap k v1
-> m () -> m ()
mapWithKeyM_ f m = do mapWithKeyM_ f m = do
forM_ (HMap.toList m) $ \(k, v) -> forM_ (HMS.toList m) $ \(k, v) ->
HMap.singleton k <$> f k v HMS.singleton k <$> f k v
-- | Renders the template. Returns 'Nothing' if some of the attributes are -- | Renders the template. Returns 'Nothing' if some of the attributes are
-- missing. -- missing.
@ -601,9 +602,9 @@ renderTemplate vals = \case
c:str -> (c:) <$> renderTemplate vals str c:str -> (c:) <$> renderTemplate vals str
[] -> Just [] [] -> Just []
abort :: String -> IO a abort :: T.Text -> IO a
abort msg = do abort msg = do
putStrLn msg T.putStrLn msg
exitFailure exitFailure
nixPrefetchURL :: Bool -> String -> IO String nixPrefetchURL :: Bool -> String -> IO String
@ -638,18 +639,18 @@ shouldUpdateNixSourcesNix content =
warnIfOutdated :: IO () warnIfOutdated :: IO ()
warnIfOutdated = do warnIfOutdated = do
tryAny (B.readFile pathNixSourcesNix) >>= \case tryAny (B.readFile pathNixSourcesNix) >>= \case
Left e -> putStrLn $ unlines Left e -> T.putStrLn $ T.unlines
[ "Could not read " <> pathNixSourcesNix [ "Could not read " <> T.pack pathNixSourcesNix
, "Error: " <> show e , "Error: " <> tshow e
] ]
Right content -> Right content ->
if shouldUpdateNixSourcesNix content if shouldUpdateNixSourcesNix content
then then
putStrLn $ unlines T.putStrLn $ T.unlines
[ "WARNING: " <> pathNixSourcesNix <> " is out of date." [ "WARNING: " <> T.pack pathNixSourcesNix <> " is out of date."
, "Please run" , "Please run"
, " niv init" , " niv init"
, "or add the following line in the " <> pathNixSourcesNix <> " file:" , "or add the following line in the " <> T.pack pathNixSourcesNix <> " file:"
, " # niv: no_update" , " # niv: no_update"
] ]
else pure () else pure ()
@ -700,17 +701,17 @@ Make sure the repository exists.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
abortSourcesDoesntExist :: IO a abortSourcesDoesntExist :: IO a
abortSourcesDoesntExist = abort $ unlines [ line1, line2 ] abortSourcesDoesntExist = abort $ T.unlines [ line1, line2 ]
where where
line1 = "Cannot use " <> pathNixSourcesJson line1 = "Cannot use " <> T.pack pathNixSourcesJson
line2 = [s| line2 = [s|
The sources file does not exist! You may need to run 'niv init'. The sources file does not exist! You may need to run 'niv init'.
|] |]
abortSourcesIsntAMap :: IO a abortSourcesIsntAMap :: IO a
abortSourcesIsntAMap = abort $ unlines [ line1, line2 ] abortSourcesIsntAMap = abort $ T.unlines [ line1, line2 ]
where where
line1 = "Cannot use " <> pathNixSourcesJson line1 = "Cannot use " <> T.pack pathNixSourcesJson
line2 = [s| line2 = [s|
The sources file should be a JSON map from package name to package The sources file should be a JSON map from package name to package
specification, e.g.: specification, e.g.:
@ -718,9 +719,9 @@ specification, e.g.:
|] |]
abortAttributeIsntAMap :: IO a abortAttributeIsntAMap :: IO a
abortAttributeIsntAMap = abort $ unlines [ line1, line2 ] abortAttributeIsntAMap = abort $ T.unlines [ line1, line2 ]
where where
line1 = "Cannot use " <> pathNixSourcesJson line1 = "Cannot use " <> T.pack pathNixSourcesJson
line2 = [s| line2 = [s|
The package specifications in the sources file should be JSON maps from The package specifications in the sources file should be JSON maps from
attribute name to attribute value, e.g.: attribute name to attribute value, e.g.:
@ -728,13 +729,13 @@ attribute name to attribute value, e.g.:
|] |]
abortSourcesIsntJSON :: IO a abortSourcesIsntJSON :: IO a
abortSourcesIsntJSON = abort $ unlines [ line1, line2 ] abortSourcesIsntJSON = abort $ T.unlines [ line1, line2 ]
where where
line1 = "Cannot use " <> pathNixSourcesJson line1 = "Cannot use " <> T.pack pathNixSourcesJson
line2 = "The sources file should be JSON." line2 = "The sources file should be JSON."
abortCannotAddPackageExists :: PackageName -> IO a abortCannotAddPackageExists :: PackageName -> IO a
abortCannotAddPackageExists (PackageName n) = abort $ unlines abortCannotAddPackageExists (PackageName n) = abort $ T.unlines
[ "Cannot add package " <> n <> "." [ "Cannot add package " <> n <> "."
, "The package already exists. Use" , "The package already exists. Use"
, " niv drop " <> n , " niv drop " <> n
@ -744,7 +745,7 @@ abortCannotAddPackageExists (PackageName n) = abort $ unlines
] ]
abortCannotUpdateNoSuchPackage :: PackageName -> IO a abortCannotUpdateNoSuchPackage :: PackageName -> IO a
abortCannotUpdateNoSuchPackage (PackageName n) = abort $ unlines abortCannotUpdateNoSuchPackage (PackageName n) = abort $ T.unlines
[ "Cannot update package " <> n <> "." [ "Cannot update package " <> n <> "."
, "The package doesn't exist. Use" , "The package doesn't exist. Use"
, " niv add " <> n , " niv add " <> n
@ -752,13 +753,13 @@ abortCannotUpdateNoSuchPackage (PackageName n) = abort $ unlines
] ]
abortCannotDropNoSuchPackage :: PackageName -> IO a abortCannotDropNoSuchPackage :: PackageName -> IO a
abortCannotDropNoSuchPackage (PackageName n) = abort $ unlines abortCannotDropNoSuchPackage (PackageName n) = abort $ T.unlines
[ "Cannot drop package " <> n <> "." [ "Cannot drop package " <> n <> "."
, "The package doesn't exist." , "The package doesn't exist."
] ]
abortCannotAttributesDropNoSuchPackage :: PackageName -> IO a abortCannotAttributesDropNoSuchPackage :: PackageName -> IO a
abortCannotAttributesDropNoSuchPackage (PackageName n) = abort $ unlines abortCannotAttributesDropNoSuchPackage (PackageName n) = abort $ T.unlines
[ "Cannot drop attributes of package " <> n <> "." [ "Cannot drop attributes of package " <> n <> "."
, "The package doesn't exist." , "The package doesn't exist."
] ]
@ -772,3 +773,6 @@ ticket:
Thanks! I'll buy you a beer. Thanks! I'll buy you a beer.
|] |]
tshow :: Show a => a -> T.Text
tshow = T.pack . show

View File

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="1f2ba40b461bae96af1073b4f3fbfdf2" baseProfile="full" viewBox="0 0 703 523" width="703" version="1.1"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="e7be124f4eec8170d74afbc28a4a5f02" baseProfile="full" viewBox="0 0 703 523" width="703" version="1.1">
<defs> <defs>
<termtosvg:template_settings xmlns:termtosvg="https://github.com/nbedos/termtosvg"> <termtosvg:template_settings xmlns:termtosvg="https://github.com/nbedos/termtosvg">
<termtosvg:screen_geometry columns="82" rows="26"/> <termtosvg:screen_geometry columns="82" rows="26"/>
@ -44,5 +44,5 @@
<circle cx="44" cy="23" r="7" class="color3"/> <circle cx="44" cy="23" r="7" class="color3"/>
<circle cx="64" cy="23" r="7" class="color2"/> <circle cx="64" cy="23" r="7" class="color2"/>
<svg id="screen" width="656" x="23" y="50" viewBox="0 0 656 442" preserveAspectRatio="xMidYMin meet"> <svg id="screen" width="656" x="23" y="50" viewBox="0 0 656 442" preserveAspectRatio="xMidYMin meet">
<rect class="background" height="100%" width="100%" x="0" y="0"/><g display="none"><rect class="foreground" height="17" width="8" x="0" y="85"/><use y="85" xlink:href="#g1"/><animate attributeName="display" begin="0ms; anim_last.end" dur="1500ms" from="inline" to="inline"/></g><g display="none"><rect class="foreground" height="17" width="8" x="0" y="187"/><use y="187" xlink:href="#g1"/><animate attributeName="display" begin="1500ms; anim_last.end+1500ms" dur="1500ms" from="inline" to="inline"/></g><g display="none"><rect class="foreground" height="17" width="8" x="0" y="306"/><use y="306" xlink:href="#g1"/><animate attributeName="display" begin="3000ms; anim_last.end+3000ms" dur="1500ms" from="inline" to="inline"/></g><g display="none"><use y="0" xlink:href="#g2"/><use y="17" xlink:href="#g3"/><use y="34" xlink:href="#g4"/><use y="51" xlink:href="#g5"/><use y="68" xlink:href="#g6"/><animate attributeName="display" begin="0ms; anim_last.end" dur="5500ms" from="inline" to="inline"/></g><g display="none"><use y="85" xlink:href="#g7"/><use y="102" xlink:href="#g8"/><use y="119" xlink:href="#g9"/><use y="136" xlink:href="#g10"/><use y="153" xlink:href="#g11"/><use y="170" xlink:href="#g6"/><animate attributeName="display" begin="1500ms; anim_last.end+1500ms" dur="4000ms" from="inline" to="inline"/></g><g display="none"><use y="272" xlink:href="#g12"/><use y="289" xlink:href="#g6"/><use y="187" xlink:href="#g7"/><use y="204" xlink:href="#g13"/><use y="221" xlink:href="#g14"/><use y="238" xlink:href="#g10"/><animate attributeName="display" begin="3000ms; anim_last.end+3000ms" dur="2500ms" from="inline" to="inline"/></g><g display="none"><use y="306" xlink:href="#g7"/><use y="323" xlink:href="#g15"/><use y="340" xlink:href="#g16"/><use y="357" xlink:href="#g10"/><rect class="foreground" height="17" width="8" x="0" y="374"/><use y="374" xlink:href="#g1"/><animate attributeName="display" begin="4500ms; anim_last.end+4500ms" dur="1000ms" from="inline" to="inline" id="anim_last"/></g><defs><g id="g1"><text class="background" textLength="8" x="0"> </text></g><g id="g2"><text class="foreground" textLength="80" x="0">$ niv init</text></g><g id="g3"><text class="foreground" textLength="192" x="0">Creating nix/sources.nix</text></g><g id="g4"><text class="foreground" textLength="200" x="0">Creating nix/sources.json</text></g><g id="g5"><text class="foreground" textLength="152" x="0">Importing 'niv' ...</text></g><g id="g6"><text class="foreground" textLength="160" x="0">Reading sources file</text></g><g id="g7"><text class="foreground" textLength="96" x="0">unpacking...</text></g><g id="g8"><text class="foreground" textLength="656" x="0">path is '/nix/store/d2ibkfdbsqkr6avllvkqcwdyj771qmvv-30f55f14e1580325f65dd2bd0be4e</text></g><g id="g9"><text class="foreground" textLength="152" x="0">bd0797a8c83.tar.gz'</text></g><g id="g10"><text class="foreground" textLength="192" x="0">Writing new sources file</text></g><g id="g11"><text class="foreground" textLength="184" x="0">Importing 'nixpkgs' ...</text></g><g id="g12"><text class="foreground" textLength="168" x="0">$ niv add stedolan/jq</text></g><g id="g13"><text class="foreground" textLength="656" x="0">path is '/nix/store/qbzbhgq78m94j4dm026y7mi7nkd4lgh4-a7e559a5504572008567383c3dc8e</text></g><g id="g14"><text class="foreground" textLength="152" x="0">142fa7a8633.tar.gz'</text></g><g id="g15"><text class="foreground" textLength="656" x="0">path is '/nix/store/yjz2v8kfk2jkzc0w7lh43hfmcafpqs33-ad9fc9f559e78a764aac20f669f23</text></g><g id="g16"><text class="foreground" textLength="152" x="0">cdd020cd943.tar.gz'</text></g></defs></svg> <rect class="background" height="100%" width="100%" x="0" y="0"/><g display="none"><rect class="foreground" height="17" width="8" x="0" y="85"/><use y="85" xlink:href="#g1"/><animate attributeName="display" begin="0ms; anim_last.end" dur="1500ms" from="inline" to="inline"/></g><g display="none"><rect class="foreground" height="17" width="8" x="0" y="187"/><use y="187" xlink:href="#g1"/><animate attributeName="display" begin="1500ms; anim_last.end+1500ms" dur="1500ms" from="inline" to="inline"/></g><g display="none"><rect class="foreground" height="17" width="8" x="0" y="306"/><use y="306" xlink:href="#g1"/><animate attributeName="display" begin="3000ms; anim_last.end+3000ms" dur="1500ms" from="inline" to="inline"/></g><g display="none"><use y="0" xlink:href="#g2"/><use y="17" xlink:href="#g3"/><use y="34" xlink:href="#g4"/><use y="51" xlink:href="#g5"/><use y="68" xlink:href="#g6"/><animate attributeName="display" begin="0ms; anim_last.end" dur="5500ms" from="inline" to="inline"/></g><g display="none"><use y="85" xlink:href="#g7"/><use y="102" xlink:href="#g8"/><use y="119" xlink:href="#g9"/><use y="136" xlink:href="#g10"/><use y="153" xlink:href="#g11"/><use y="170" xlink:href="#g6"/><animate attributeName="display" begin="1500ms; anim_last.end+1500ms" dur="4000ms" from="inline" to="inline"/></g><g display="none"><use y="272" xlink:href="#g12"/><use y="289" xlink:href="#g6"/><use y="187" xlink:href="#g7"/><use y="204" xlink:href="#g13"/><use y="221" xlink:href="#g14"/><use y="238" xlink:href="#g10"/><animate attributeName="display" begin="3000ms; anim_last.end+3000ms" dur="2500ms" from="inline" to="inline"/></g><g display="none"><use y="306" xlink:href="#g7"/><use y="323" xlink:href="#g15"/><use y="340" xlink:href="#g16"/><use y="357" xlink:href="#g10"/><rect class="foreground" height="17" width="8" x="0" y="374"/><use y="374" xlink:href="#g1"/><animate attributeName="display" begin="4500ms; anim_last.end+4500ms" dur="1000ms" from="inline" to="inline" id="anim_last"/></g><defs><g id="g1"><text class="background" textLength="8" x="0"> </text></g><g id="g2"><text class="foreground" textLength="80" x="0">$ niv init</text></g><g id="g3"><text class="foreground" textLength="192" x="0">Creating nix/sources.nix</text></g><g id="g4"><text class="foreground" textLength="200" x="0">Creating nix/sources.json</text></g><g id="g5"><text class="foreground" textLength="152" x="0">Importing 'niv' ...</text></g><g id="g6"><text class="foreground" textLength="160" x="0">Reading sources file</text></g><g id="g7"><text class="foreground" textLength="96" x="0">unpacking...</text></g><g id="g8"><text class="foreground" textLength="656" x="0">path is '/nix/store/bypafdfyf7q6fg1m1xxps4gv4adwwlxb-2f95c55006d6138aafe44e452350c</text></g><g id="g9"><text class="foreground" textLength="152" x="0">e7fa3211dfd.tar.gz'</text></g><g id="g10"><text class="foreground" textLength="192" x="0">Writing new sources file</text></g><g id="g11"><text class="foreground" textLength="184" x="0">Importing 'nixpkgs' ...</text></g><g id="g12"><text class="foreground" textLength="168" x="0">$ niv add stedolan/jq</text></g><g id="g13"><text class="foreground" textLength="656" x="0">path is '/nix/store/qbzbhgq78m94j4dm026y7mi7nkd4lgh4-a7e559a5504572008567383c3dc8e</text></g><g id="g14"><text class="foreground" textLength="152" x="0">142fa7a8633.tar.gz'</text></g><g id="g15"><text class="foreground" textLength="656" x="0">path is '/nix/store/yjz2v8kfk2jkzc0w7lh43hfmcafpqs33-ad9fc9f559e78a764aac20f669f23</text></g><g id="g16"><text class="foreground" textLength="152" x="0">cdd020cd943.tar.gz'</text></g></defs></svg>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB