packages feed

nix-thunk 0.2.0.3 → 0.3.0.0

raw patch · 4 files changed

+48/−45 lines, 4 files

Files

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