nix-tree 0.3.3 → 0.4.0
raw patch · 5 files changed
+113/−24 lines, 5 filesdep +dot
Dependencies added: dot
Files
- CHANGELOG.md +8/−0
- README.md +34/−10
- nix-tree.cabal +2/−1
- src/NixTree/Main.hs +21/−3
- src/NixTree/StorePath.hs +48/−10
CHANGELOG.md view
@@ -1,5 +1,13 @@ # Changelog +## 0.4.0 - 2024-01-21:++* feat: Allow passing `--store` for alternative nix store (e.g. remote binary cache) (thanks @bryango, PR: [#79][])+* feat: Graphviz export via `--dot` flag (thanks @SomeoneSerge, issue: [#59][])++[#79]: https://github.com/utdemir/nix-tree/pull/79+[#59]: https://github.com/utdemir/nix-tree/issues/59+ ## 0.3.3 - 2024-01-17: * chore: Update 'brick' & 'optparse-applicative' library to work with the newer Stackage snapshot (thanks @ncfavier, PR: [#78][])
README.md view
@@ -12,9 +12,15 @@ `nix-tree` is on `nixpkgs` since `20.09`, so just use your preferred method for adding packages to your system, eg: ```-nix-env -i nix-tree+nix-env -iA nix-tree ``` +Or, for flake enabled systems:++```+nix profile install 'nixpkgs#nix-tree'+```+ To run the current development version: ```@@ -23,17 +29,21 @@ ## Usage -```+```console $ nix-tree --help-Usage: nix-tree [--version] [--derivation] [INSTALLABLE]+Usage: nix-tree [INSTALLABLE] [--store STORE] [--version] [--derivation] [--impure] [--dot]+ Interactively browse dependency graphs of Nix derivations. Available options:- --version Show the nix-tree version.- --derivation Operate on the store derivation rather than its- outputs.- INSTALLABLE A store path or a flake reference. Paths default to- "~/.nix-profile" and "/var/run/current-system".+ INSTALLABLE A store path or a flake reference.+ Paths default to "~/.nix-profile" and "/var/run/current-system"+ --store STORE The URL of the Nix store, e.g. "daemon" or "https://cache.nixos.org"+ See "nix help-stores" for supported store types and settings.+ --version Show the nix-tree version+ --derivation Operate on the store derivation rather than its outputs+ --impure Allow access to mutable paths and repositories+ --dot Print the dependency graph in dot format -h,--help Show this help text Keybindings:@@ -66,12 +76,12 @@ nix-build . --no-out-link | xargs -o nix-tree # Build time dependencies (passing a `.drv` path)-nix-instantiate -r | xargs -o nix-tree --derivation+nix-instantiate . | xargs -o nix-tree --derivation # Dependencies from shell.nix nix-build shell.nix -A inputDerivation | xargs -o nix-tree -# All outputs of a derivation in nixpkgs:+# All outputs of a derivation in nixpkgs nix-build '<nixpkgs>' -A openssl.all --no-out-link | xargs -o nix-tree ``` @@ -89,6 +99,20 @@ ```bash nix-tree /nix/var/nix/profiles/system+```++Query the binary cache before download, with the `--store` option:++```bash+# Query the runtime dependency of `stellarium` (2 GiB closure) without download+nix eval --raw 'nixpkgs#stellarium.outPath' | xargs -o nix-tree --store https://cache.nixos.org+```++For valid `--store` options, see [`nix help-stores`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-help-stores). For example,++```bash+# Build in a temporary chroot store and examine the output+nix build --store /tmp/chroot-store 'nixpkgs#hello' --print-out-paths | xargs -o nix-tree --store /tmp/chroot-store ``` ## Contributing
nix-tree.cabal view
@@ -3,7 +3,7 @@ name: nix-tree synopsis: Interactively browse a Nix store paths dependencies description: A terminal curses application to browse a Nix store paths dependencies-version: 0.3.3+version: 0.4.0 homepage: https://github.com/utdemir/nix-tree license: BSD-3-Clause license-file: LICENSE@@ -61,6 +61,7 @@ , directory , optparse-applicative , microlens+ , dot executable nix-tree import: common-options
src/NixTree/Main.hs view
@@ -19,9 +19,11 @@ data Opts = Opts { oInstallables :: [Installable],+ oStore :: String, oVersion :: Bool, oDerivation :: Bool,- oImpure :: Bool+ oImpure :: Bool,+ oDot :: Bool } optsParser :: Opts.ParserInfo Opts@@ -49,9 +51,22 @@ ) ) )+ <*> Opts.strOption+ ( Opts.long "store"+ <> Opts.metavar "STORE"+ <> Opts.value "auto"+ <> Opts.helpDoc+ ( Just $+ Opts.vsep+ [ "The URL of the Nix store, e.g. \"daemon\" or \"https://cache.nixos.org\"",+ "See \"nix help-stores\" for supported store types and settings."+ ]+ )+ ) <*> Opts.switch (Opts.long "version" <> Opts.help "Show the nix-tree version") <*> Opts.switch (Opts.long "derivation" <> Opts.help "Operate on the store derivation rather than its outputs") <*> Opts.switch (Opts.long "impure" <> Opts.help "Allow access to mutable paths and repositories")+ <*> Opts.switch (Opts.long "dot" <> Opts.help "Print the dependency graph in dot format") keybindingsHelp :: Opts.Doc keybindingsHelp =@@ -96,7 +111,8 @@ let seo = StoreEnvOptions { seoIsDerivation = opts & oDerivation,- seoIsImpure = opts & oImpure+ seoIsImpure = opts & oImpure,+ seoStoreURL = opts & oStore } withStoreEnv seo installables $ \env' -> do@@ -109,7 +125,9 @@ & chunks 50 & mapConcurrently_ (mapM_ (\p -> evaluate (rnf p) >> incProgress bar 1)) - run env+ if opts & oDot+ then putTextLn $ storeEnvToDot env+ else run env chunks :: Int -> [a] -> [[a]] chunks _ [] = []
src/NixTree/StorePath.hs view
@@ -14,8 +14,8 @@ seGetRoots, seBottomUp, seFetchRefs,- getNixStore, mkStoreName,+ storeEnvToDot, ) where @@ -26,7 +26,9 @@ import qualified Data.ByteString.Lazy as BL import qualified Data.HashMap.Strict as HM import qualified Data.HashSet as HS+import qualified Data.Set as Set import qualified Data.Text as T+import qualified Dot import System.FilePath.Posix (addTrailingPathSeparator, splitDirectories, (</>)) import System.IO (hPutStrLn) import System.Process.Typed (proc, readProcessStdout_)@@ -48,10 +50,10 @@ unNixStore NixStore = "/nix/store/" unNixStore (NixStoreCustom fp) = fp -getNixStore :: IO NixStore-getNixStore = do+getStoreDir :: FilePath -> IO NixStore+getStoreDir seoNixStore = do let prog = "nix-instantiate"- args = ["--eval", "--expr", "(builtins.storeDir)", "--json"]+ args = ["--eval", "--expr", "(builtins.storeDir)", "--json", "--option", "store", seoNixStore] out <- readProcessStdout_ (proc prog args) <&> fmap mkNixStore@@ -146,7 +148,8 @@ data PathInfoOptions = PathInfoOptions { pioIsRecursive :: Bool, pioIsDerivation :: Bool,- pioIsImpure :: Bool+ pioIsImpure :: Bool,+ pioStoreURL :: FilePath } getPathInfo :: NixStore -> NixVersion -> PathInfoOptions -> NonEmpty Installable -> IO (NonEmpty (StorePath s (StoreName s) ()))@@ -160,6 +163,7 @@ ++ ["--impure" | options & pioIsImpure] ++ ["--recursive" | options & pioIsRecursive] ++ ["--derivation" | (options & pioIsDerivation) && nixVersion >= Nix2_4]+ ++ ["--store", options & pioStoreURL] ++ (if nixVersion >= Nix2_4 then ["--extra-experimental-features", "nix-command flakes"] else []) ++ map (toString . installableToText) (toList names) )@@ -200,7 +204,8 @@ data StoreEnvOptions = StoreEnvOptions { seoIsDerivation :: Bool,- seoIsImpure :: Bool+ seoIsImpure :: Bool,+ seoStoreURL :: String } withStoreEnv ::@@ -210,8 +215,8 @@ NonEmpty Installable -> (forall s. StoreEnv s () -> m a) -> m a-withStoreEnv StoreEnvOptions {seoIsDerivation, seoIsImpure} names cb = do- nixStore <- liftIO getNixStore+withStoreEnv StoreEnvOptions {seoIsDerivation, seoIsImpure, seoStoreURL} names cb = do+ nixStore <- liftIO $ getStoreDir seoStoreURL -- See: https://github.com/utdemir/nix-tree/issues/12 nixVersion <- liftIO getNixVersion@@ -225,7 +230,7 @@ getPathInfo nixStore nixVersion- (PathInfoOptions {pioIsDerivation = seoIsDerivation, pioIsRecursive = False, pioIsImpure = seoIsImpure})+ (PathInfoOptions {pioIsDerivation = seoIsDerivation, pioIsRecursive = False, pioIsImpure = seoIsImpure, pioStoreURL = seoStoreURL}) names paths <-@@ -233,7 +238,7 @@ getPathInfo nixStore nixVersion- (PathInfoOptions {pioIsDerivation = seoIsDerivation, pioIsRecursive = True, pioIsImpure = seoIsImpure})+ (PathInfoOptions {pioIsDerivation = seoIsDerivation, pioIsRecursive = True, pioIsImpure = seoIsImpure, pioStoreURL = seoStoreURL}) (Installable . toText . storeNameToPath . spName <$> roots) let env =@@ -314,6 +319,39 @@ let new = sp {spPayload = f sp {spRefs = refs}} modify $ bimap (HM.delete spName) (HM.insert spName new) return new++--------------------------------------------------------------------------------++storeEnvToDot :: StoreEnv s a -> Text+storeEnvToDot env =+ seBottomUp go env+ & seGetRoots+ & toList+ & map spPayload+ & mconcat+ & render+ where+ go sp =+ fromList [Set.singleton (spName sp, spName ref) <> spPayload ref | ref <- spRefs sp]+ & mconcat++ render :: Set (StoreName s, StoreName s) -> Text+ render edges =+ Dot.DotGraph+ Dot.Strict+ Dot.Directed+ Nothing+ [ Dot.StatementEdge+ ( Dot.EdgeStatement+ (Dot.ListTwo (Dot.EdgeNode (mkNodeId from)) (Dot.EdgeNode (mkNodeId to)) [])+ []+ )+ | (from, to) <- toList edges+ ]+ & Dot.encode++ mkNodeId :: StoreName s -> Dot.NodeId+ mkNodeId = fromString . toString . storeNameToShortText --------------------------------------------------------------------------------