nix-thunk 0.4.0.0 → 0.5.0.0
raw patch · 6 files changed
+109/−45 lines, 6 filesdep +processdep +template-haskelldep ~cli-extrasdep ~cli-git
Dependencies added: process, template-haskell
Dependency ranges changed: cli-extras, cli-git
Files
- CHANGELOG.md +7/−1
- README.md +2/−0
- nix-thunk.cabal +6/−4
- src-bin/nix-thunk.hs +24/−10
- src/Nix/Thunk.hs +69/−29
- src/Nix/Thunk/Command.hs +1/−1
CHANGELOG.md view
@@ -1,8 +1,14 @@ # Revision history for nix-thunk +## 0.5.0.0++* Fix a critical bug where v6 thunks can not be used to fetch non-GitHub repositories. Please update all your thunks to use the new v7 thunk spec.+ Updating your thunk can be done by running `nix-thunk unpack $path; nix-thunk pack $path`.+* Building a functional `nix-thunk` _must_ be done using the included Nix derivation.+ ## 0.4.0.0 -* The default thunk specification ("v6") now uses a pinned version of nixpkgsk, rather than the magic `<nixpkgs>`, for fetching thunks. This ensures that thunks can be fetched even in an environment where `NIX_PATH` is unset.+* The default thunk specification ("v6") now uses a pinned version of nixpkgs, rather than the magic `<nixpkgs>`, for fetching thunks. This ensures that thunks can be fetched even in an environment where `NIX_PATH` is unset. ## 0.3.0.0
README.md view
@@ -21,6 +21,8 @@ nix-env -f https://github.com/obsidiansystems/nix-thunk/archive/master.tar.gz -iA command ``` +**WARNING**: It is _not_ possible to compile `nix-thunk` without Nix. To ensure that packed thunks are buildable even in environments where diamond paths are unavailable (specifically `<nixpkgs>`), `nix-thunk` _must_ be built with knowledge of a known-good nixpkgs, _and_ for `nix-thunk` to be able to manipulate these thunks, it must _always_ be the same version of nixpkgs.+ ## Command Usage ### Create a dependency
nix-thunk.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: nix-thunk-version: 0.4.0.0+version: 0.5.0.0 license: BSD3 license-file: LICENSE copyright: Obsidian Systems LLC 2020-2022@@ -34,8 +34,8 @@ , aeson-pretty >=0.8.7 && <0.9 , base >=4.12.0.0 && <4.15 , bytestring >=0.10.8.2 && <0.11- , cli-extras >=0.1.0.1 && <0.2- , cli-git >=0.1.0.1 && <0.2+ , cli-extras >=0.2.1.0 && <0.3+ , cli-git >=0.2.0.0 && <0.3 , cli-nix >=0.1.0.1 && <0.2 , containers >=0.6.0.1 && <0.7 , cryptonite >=0.25 && <0.30@@ -61,13 +61,15 @@ , unix >=2.7.2.2 && <2.8 , which >=0.2 && <0.3 , yaml >=0.11.1.2 && <0.12+ , process >=1.6.0.0 && <1.7+ , template-haskell >=2.14.0.0 && <2.19 executable nix-thunk main-is: src-bin/nix-thunk.hs default-language: Haskell2010 build-depends: base >=4.12.0.0 && <4.15- , cli-extras >=0.1.0.1 && <0.2+ , cli-extras >=0.2.1.0 && <0.3 , nix-thunk , optparse-applicative >=0.14.3.0 && <0.17 , text >=1.2.3.1 && <1.3
src-bin/nix-thunk.hs view
@@ -7,6 +7,8 @@ import qualified Data.Text.IO as T import System.Environment import System.Exit+import System.IO+import Data.List import Data.Void data Args = Args@@ -35,13 +37,25 @@ { prefShowHelpOnEmpty = True } -main :: IO Void-main = do- args <- getArgs- args' <- handleParseResult $ execParserPure parserPrefs argsInfo args- cliConf <- mkDefaultCliConfig args- runCli cliConf (runThunkCommand (_args_command args')) >>= \case- Right () -> exitWith ExitSuccess- Left e -> do- T.putStrLn $ prettyNixThunkError e- exitWith $ ExitFailure 2+main :: IO ()+main =+ do+ args <- getArgs+ args' <- handleParseResult $ execParserPure parserPrefs argsInfo args+ let logLevel = if _args_verbose args' then Debug else Notice+ notInteractive <- not <$> isInteractiveTerm args+ cliConf <- newCliConfig logLevel notInteractive notInteractive (\e -> (prettyNixThunkError e, ExitFailure 1))+ runCli cliConf (runThunkCommand (_args_command args'))+ where+ isInteractiveTerm args = do+ isTerm <- hIsTerminalDevice stdout+ -- Running in bash/fish/zsh completion+ let inShellCompletion = isInfixOf "completion" $ unwords args++ -- Respect the user’s TERM environment variable. Dumb terminals+ -- like Eshell cannot handle lots of control sequences that the+ -- spinner uses.+ termEnv <- lookupEnv "TERM"+ let isDumb = termEnv == Just "dumb"++ return $ isTerm && not inShellCompletion && not isDumb
src/Nix/Thunk.hs view
@@ -30,6 +30,7 @@ , ThunkPackConfig (..) , ThunkConfig (..) , updateThunkToLatest+ , updateThunk , ThunkUpdateConfig (..) , unpackThunk , ThunkSpec (..)@@ -102,6 +103,8 @@ import System.IO.Temp import System.Posix.Files import qualified Text.URI as URI+import Language.Haskell.TH (Exp(LitE), Lit(StringL), runIO)+import qualified System.Process as P -------------------------------------------------------------------------------- -- Hacks@@ -109,7 +112,7 @@ type MonadInfallibleNixThunk m = ( CliLog m- , HasCliConfig m+ , HasCliConfig NixThunkError m , MonadIO m , MonadMask m )@@ -126,7 +129,8 @@ prettyNixThunkError :: NixThunkError -> Text prettyNixThunkError = \case- NixThunkError_ProcessFailure pf -> prettyProcessFailure pf+ NixThunkError_ProcessFailure (ProcessFailure p code) ->+ "Process exited with code " <> T.pack (show code) <> "; " <> reconstructCommand p NixThunkError_Unstructured msg -> msg makePrisms ''NixThunkError@@ -248,11 +252,6 @@ , _gitSource_private = _gitHubSource_private s } -getThunkGitBranch :: ThunkPtr -> Maybe Text-getThunkGitBranch (ThunkPtr _ src) = fmap untagName $ case src of- ThunkSource_GitHub s -> _gitHubSource_branch s- ThunkSource_Git s -> _gitSource_branch s- commitNameToRef :: Name Commit -> Ref SHA1 commitNameToRef (N c) = refFromHex $ encodeUtf8 c @@ -300,6 +299,17 @@ attrCacheFileName :: FilePath attrCacheFileName = ".attr-cache" +-- | A path from which our known-good nixpkgs can be fetched.+-- @print-nixpkgs-path@ is a shell script whose only purpose is to print+-- that path. It is generated and included in the build dependencies of+-- nix-thunk by our default.nix.+pinnedNixpkgsPath :: FilePath+pinnedNixpkgsPath =+ $(do+ p <- fmap init . runIO $ P.readCreateProcess (P.shell "print-nixpkgs-path") ""+ pure $ LitE $ StringL $ p+ )+ -- | Specification for how a file in a thunk version works. data ThunkFileSpec = ThunkFileSpec_Ptr (LBS.ByteString -> Either String ThunkPtr) -- ^ This file specifies 'ThunkPtr' data@@ -520,14 +530,6 @@ liftIO $ createDirectoryIfMissing True $ takeDirectory fullPath f fullPath -createThunkWithLatest :: MonadNixThunk m => FilePath -> ThunkSource -> m ()-createThunkWithLatest target s = do- rev <- getLatestRev s- createThunk target $ Right $ ThunkPtr- { _thunkPtr_source = s- , _thunkPtr_rev = rev- }- updateThunkToLatest :: MonadNixThunk m => ThunkUpdateConfig -> FilePath -> m () updateThunkToLatest (ThunkUpdateConfig mBranch thunkConfig) target = do withSpinner' ("Updating thunk " <> T.pack target <> " to latest") (pure $ const $ "Thunk " <> T.pack target <> " updated to latest") $ do@@ -562,8 +564,9 @@ -- This tool will only ever produce the newest one when it writes a thunk. gitHubThunkSpecs :: NonEmpty ThunkSpec gitHubThunkSpecs =- gitHubThunkSpecV6 :|- [ gitHubThunkSpecV5+ gitHubThunkSpecV7 :|+ [ gitHubThunkSpecV6+ , gitHubThunkSpecV5 , gitHubThunkSpecV4 , gitHubThunkSpecV3 , gitHubThunkSpecV2@@ -638,10 +641,11 @@ in fetch json |] --- | Specification for GitHub thunks which use a specific, pinned--- version of nixpkgs for fetching, rather than using @<nixpkgs>@ from--- @NIX_PATH@. The "v6" specs ensure that thunks can be fetched even--- when @NIX_PATH@ is unset.+-- | See 'gitHubThunkSpecV7'.+--+-- __NOTE__: v6 spec thunks are broken! They import the pinned nixpkgs+-- in an incorrect way. GitHub thunks for public repositories with no+-- submodules will still work, but update as soon as possible. gitHubThunkSpecV6 :: ThunkSpec gitHubThunkSpecV6 = mkThunkSpec "github-v6" "github.json" parseGitHubJsonBytes [here| # DO NOT HAND-EDIT THIS FILE@@ -658,14 +662,30 @@ in fetch json |] +-- | Specification for GitHub thunks which use a specific, pinned+-- version of nixpkgs for fetching, rather than using @<nixpkgs>@ from+-- @NIX_PATH@. The "v7" specs ensure that thunks can be fetched even+-- when @NIX_PATH@ is unset.+gitHubThunkSpecV7 :: ThunkSpec+gitHubThunkSpecV7 = mkThunkSpec "github-v7" "github.json" parseGitHubJsonBytes [i|# DO NOT HAND-EDIT THIS FILE+let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:+ if !fetchSubmodules && !private then builtins.fetchTarball {+ url = "https://github.com/\${owner}/\${repo}/archive/\${rev}.tar.gz"; inherit sha256;+ } else (import ${pinnedNixpkgsPath} {}).fetchFromGitHub {+ inherit owner repo rev sha256 fetchSubmodules private;+ };+ json = builtins.fromJSON (builtins.readFile ./github.json);+in fetch json|]+ parseGitHubJsonBytes :: LBS.ByteString -> Either String ThunkPtr parseGitHubJsonBytes = parseJsonObject $ parseThunkPtr $ \v -> ThunkSource_GitHub <$> parseGitHubSource v <|> ThunkSource_Git <$> parseGitSource v gitThunkSpecs :: NonEmpty ThunkSpec gitThunkSpecs =- gitThunkSpecV6 :|- [ gitThunkSpecV5+ gitThunkSpecV7 :|+ [ gitThunkSpecV6+ , gitThunkSpecV5 , gitThunkSpecV4 , gitThunkSpecV3 , gitThunkSpecV2@@ -751,10 +771,10 @@ in fetch json |] --- | Specification for Git thunks which use a specific, pinned version--- of nixpkgs for fetching, rather than using @<nixpkgs>@ from--- @NIX_PATH@. The "v6" specs ensure that thunks can be fetched even--- when @NIX_PATH@ is unset.+-- | See 'gitThunkSpecV7'.+-- __NOTE__: v6 spec thunks are broken! They import the pinned nixpkgs+-- in an incorrect way. GitHub thunks for public repositories with no+-- submodules will still work, but update as soon as possible. gitThunkSpecV6 :: ThunkSpec gitThunkSpecV6 = mkThunkSpec "git-v6" "git.json" parseGitJsonBytes [here| # DO NOT HAND-EDIT THIS FILE@@ -776,6 +796,26 @@ in fetch json |] +-- | Specification for Git thunks which use a specific, pinned version+-- of nixpkgs for fetching, rather than using @<nixpkgs>@ from+-- @NIX_PATH@. The "v7" specs ensure that thunks can be fetched even+-- when @NIX_PATH@ is unset.+gitThunkSpecV7 :: ThunkSpec+gitThunkSpecV7 = mkThunkSpec "git-v7" "git.json" parseGitJsonBytes [i|# DO NOT HAND-EDIT THIS FILE+let fetch = {url, rev, branch ? null, sha256 ? null, fetchSubmodules ? false, private ? false, ...}:+ let realUrl = let firstChar = builtins.substring 0 1 url; in+ if firstChar == "/" then /. + url+ else if firstChar == "." then ./. + url+ else url;+ in if !fetchSubmodules && private then builtins.fetchGit {+ url = realUrl; inherit rev;+ \${if branch == null then null else "ref"} = branch;+ } else (import ${pinnedNixpkgsPath} {}).fetchgit {+ url = realUrl; inherit rev sha256;+ };+ json = builtins.fromJSON (builtins.readFile ./git.json);+in fetch json|]+ parseGitJsonBytes :: LBS.ByteString -> Either String ThunkPtr parseGitJsonBytes = parseJsonObject $ parseThunkPtr $ fmap ThunkSource_Git . parseGitSource @@ -804,7 +844,7 @@ nixBuildThunkAttrWithCache :: ( MonadIO m , MonadLog Output m- , HasCliConfig m+ , HasCliConfig NixThunkError m , MonadMask m , MonadError NixThunkError m , MonadFail m@@ -856,7 +896,7 @@ -- | Build a nix attribute, and cache the result if possible nixBuildAttrWithCache :: ( MonadLog Output m- , HasCliConfig m+ , HasCliConfig NixThunkError m , MonadIO m , MonadMask m , MonadError NixThunkError m
src/Nix/Thunk/Command.hs view
@@ -64,7 +64,7 @@ runThunkCommand :: ( MonadLog Output m- , HasCliConfig m+ , HasCliConfig NixThunkError m , MonadIO m , MonadMask m , MonadError NixThunkError m