nix-thunk 0.2.0.3 → 0.3.0.0
raw patch · 4 files changed
+48/−45 lines, 4 files
Files
- CHANGELOG.md +5/−0
- README.md +8/−0
- nix-thunk.cabal +1/−1
- src/Nix/Thunk.hs +34/−44
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for nix-thunk +## 0.3.0.0++* Fix readThunk when thunk is checked out [#4](https://github.com/obsidiansystems/nix-thunk/pull/4)+* Fix removal of .git from default destination [#10](https://github.com/obsidiansystems/nix-thunk/pull/10)+ ## 0.2.0.3 * Default to GHC 8.8.4 and update dependency bounds
README.md view
@@ -65,6 +65,14 @@ }; ``` +You can also represent in nix all the thunks of a given directory+```nix+let sources = nix-thunk.mapSubdirectories nix-thunk.thunkSource ./dep;+```+```nix+{ which = self.callCabal2nix "which" sources.which {}; }+```+ ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. See the [contribution guide](CONTRIBUTING.md) for more details.
nix-thunk.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: nix-thunk-version: 0.2.0.3+version: 0.3.0.0 license: BSD3 license-file: LICENSE copyright: Obsidian Systems LLC 2020
src/Nix/Thunk.hs view
@@ -73,11 +73,9 @@ import Data.Data (Data) import Data.Default import Data.Either.Combinators (fromRight', rightToMaybe)-import Data.Foldable (toList)+import Data.Foldable (for_, toList) import Data.Function-import Data.Functor ((<&>)) import qualified Data.List as L-import Data.List (stripPrefix) import Data.List.NonEmpty (NonEmpty(..), nonEmpty) import qualified Data.List.NonEmpty as NonEmpty import Data.Map (Map)@@ -326,35 +324,38 @@ -> Set FilePath -- ^ Set of file paths relative to the given directory -> m ThunkData matchThunkSpecToDir thunkSpec dir dirFiles = do- case nonEmpty (toList $ dirFiles `Set.difference` expectedPaths) of- Just fs -> throwError $ ReadThunkError_UnrecognizedPaths $ (dir </>) <$> fs- Nothing -> pure ()- case nonEmpty (toList $ requiredPaths `Set.difference` dirFiles) of- Just fs -> throwError $ ReadThunkError_MissingPaths $ (dir </>) <$> fs- Nothing -> pure ()- datas <- fmap toList $ flip Map.traverseMaybeWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case- ThunkFileSpec_AttrCache -> Nothing <$ dirMayExist expectedPath- ThunkFileSpec_CheckoutIndicator -> liftIO (doesDirectoryExist (dir </> expectedPath)) <&> \case- False -> Nothing- True -> Just ThunkData_Checkout- ThunkFileSpec_FileMatches expectedContents -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do- actualContents <- liftIO (T.readFile $ dir </> expectedPath)- case T.strip expectedContents == T.strip actualContents of- True -> pure Nothing- False -> throwError $ ReadThunkError_FileDoesNotMatch (dir </> expectedPath) expectedContents- ThunkFileSpec_Ptr parser -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do- let path = dir </> expectedPath- liftIO (doesFileExist path) >>= \case- False -> pure Nothing- True -> do- actualContents <- liftIO $ LBS.readFile path- case parser actualContents of- Right v -> pure $ Just (ThunkData_Packed thunkSpec v)- Left e -> throwError $ ReadThunkError_UnparseablePtr (dir </> expectedPath) e+ isCheckout <- fmap or $ flip Map.traverseWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case+ ThunkFileSpec_CheckoutIndicator -> liftIO (doesDirectoryExist (dir </> expectedPath))+ _ -> pure False+ case isCheckout of+ True -> pure ThunkData_Checkout+ False -> do+ for_ (nonEmpty (toList $ dirFiles `Set.difference` expectedPaths)) $ \fs ->+ throwError $ ReadThunkError_UnrecognizedPaths $ (dir </>) <$> fs+ for_ (nonEmpty (toList $ requiredPaths `Set.difference` dirFiles)) $ \fs ->+ throwError $ ReadThunkError_MissingPaths $ (dir </>) <$> fs+ datas <- fmap toList $ flip Map.traverseMaybeWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case+ ThunkFileSpec_AttrCache -> Nothing <$ dirMayExist expectedPath+ ThunkFileSpec_CheckoutIndicator -> pure Nothing -- Handled above+ ThunkFileSpec_FileMatches expectedContents -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do+ actualContents <- liftIO (T.readFile $ dir </> expectedPath)+ case T.strip expectedContents == T.strip actualContents of+ True -> pure Nothing+ False -> throwError $ ReadThunkError_FileDoesNotMatch (dir </> expectedPath) expectedContents+ ThunkFileSpec_Ptr parser -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do+ let path = dir </> expectedPath+ liftIO (doesFileExist path) >>= \case+ False -> pure Nothing+ True -> do+ actualContents <- liftIO $ LBS.readFile path+ case parser actualContents of+ Right v -> pure $ Just (thunkSpec, v)+ Left e -> throwError $ ReadThunkError_UnparseablePtr (dir </> expectedPath) e - case nonEmpty datas of- Nothing -> throwError ReadThunkError_UnrecognizedThunk- Just xs -> fold1WithM xs $ \a b -> either throwError pure (mergeThunkData a b)+ uncurry ThunkData_Packed <$> case nonEmpty datas of+ Nothing -> throwError ReadThunkError_UnrecognizedThunk+ Just xs -> fold1WithM xs $ \a@(_, ptrA) (_, ptrB) ->+ if ptrA == ptrB then pure a else throwError $ ReadThunkError_AmbiguousPackedState ptrA ptrB where rootPathsOnly = Set.fromList . mapMaybe takeRootDir . Map.keys takeRootDir = fmap NonEmpty.head . nonEmpty . splitPath@@ -370,15 +371,6 @@ True -> throwError $ ReadThunkError_UnrecognizedPaths $ expectedPath :| [] False -> pure () - -- Combine 'ThunkData' from different files, preferring "Checkout" over "Packed"- mergeThunkData ThunkData_Checkout ThunkData_Checkout = Right ThunkData_Checkout- mergeThunkData ThunkData_Checkout ThunkData_Packed{} = Left bothPackedAndUnpacked- mergeThunkData ThunkData_Packed{} ThunkData_Checkout = Left bothPackedAndUnpacked- mergeThunkData a@(ThunkData_Packed _ ptrA) (ThunkData_Packed _ ptrB) =- if ptrA == ptrB then Right a else Left $ ReadThunkError_AmbiguousPackedState ptrA ptrB-- bothPackedAndUnpacked = ReadThunkError_UnrecognizedState "Both packed data and checkout present"- fold1WithM (x :| xs) f = foldM f x xs readThunkWith@@ -393,8 +385,7 @@ Left e -> putLog Debug [i|Thunk specification ${_thunkSpec_name spec} did not match ${dir}: ${e}|] *> loop rest x@(Right _) -> x <$ putLog Debug [i|Thunk specification ${_thunkSpec_name spec} matched ${dir}|] --- | Read a thunk and validate that it is exactly a packed thunk.--- If additional data is present, fail.+-- | Read a packed or unpacked thunk based on predefined thunk specifications. readThunk :: (MonadNixThunk m) => FilePath -> m (Either ReadThunkError ThunkData) readThunk = readThunkWith thunkSpecTypes @@ -506,9 +497,8 @@ (untagName <$> _thunkCreateConfig_branch config) (T.pack . show <$> _thunkCreateConfig_rev config) let trailingDirectoryName = reverse . takeWhile (/= '/') . dropWhile (=='/') . reverse- stripSuffix s = fmap reverse . stripPrefix s . reverse dropDotGit :: FilePath -> FilePath- dropDotGit origName = fromMaybe origName $ stripSuffix ".git" origName+ dropDotGit origName = fromMaybe origName $ stripExtension "git" origName defaultDestinationForGitUri :: GitUri -> FilePath defaultDestinationForGitUri = dropDotGit . trailingDirectoryName . T.unpack . URI.render . unGitUri destination = fromMaybe (defaultDestinationForGitUri $ _thunkCreateConfig_uri config) $ _thunkCreateConfig_destination config