-
Notifications
You must be signed in to change notification settings - Fork 25
Bit too late #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bit too late #35
Changes from all commits
2957ce1
50f1329
4d58821
68f5a5d
9482161
9ffdd9c
b608733
1fe1237
df62048
1364c81
aa58adb
e534a85
db71e6b
325975a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| {-# LANGUAGE RecordWildCards #-} | ||
| {-| | ||
| Description : Build related types | ||
| Maintainer : srk <[email protected]> | ||
| |-} | ||
| module System.Nix.Build ( | ||
| BuildMode(..) | ||
| , BuildStatus(..) | ||
| , BuildResult(..) | ||
| , buildSuccess | ||
| ) where | ||
|
|
||
| import Data.Time (UTCTime) | ||
| import Data.Text (Text) | ||
| import Data.HashSet (HashSet) | ||
|
|
||
| -- keep the order of these Enums to match enums from reference implementations | ||
| -- src/libstore/store-api.hh | ||
| data BuildMode = Normal | Repair | Check | ||
| deriving (Eq, Ord, Enum, Show) | ||
|
|
||
| data BuildStatus = | ||
| Built | ||
| | Substituted | ||
| | AlreadyValid | ||
| | PermanentFailure | ||
| | InputRejected | ||
| | OutputRejected | ||
| | TransientFailure -- possibly transient | ||
| | CachedFailure -- no longer used | ||
| | TimedOut | ||
| | MiscFailure | ||
| | DependencyFailed | ||
| | LogLimitExceeded | ||
| | NotDeterministic | ||
| deriving (Eq, Ord, Enum, Show) | ||
|
|
||
|
|
||
| -- | Result of the build | ||
| data BuildResult = BuildResult | ||
| { -- | build status, MiscFailure should be default | ||
| status :: !BuildStatus | ||
| , -- | possible build error message | ||
| errorMessage :: !(Maybe Text) | ||
| , -- | How many times this build was performed | ||
| timesBuilt :: !Integer | ||
| , -- | If timesBuilt > 1, whether some builds did not produce the same result | ||
| isNonDeterministic :: !Bool | ||
| , -- Start time of this build | ||
| startTime :: !UTCTime | ||
| , -- Stop time of this build | ||
| stopTime :: !UTCTime | ||
| } deriving (Eq, Ord, Show) | ||
|
|
||
| buildSuccess BuildResult{..} = status == Built || status == Substituted || status == AlreadyValid |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| {-# LANGUAGE OverloadedStrings #-} | ||
| {-# LANGUAGE DataKinds #-} | ||
| {-# LANGUAGE TypeApplications #-} | ||
|
|
||
| {-| | ||
| Description : Internal path utilities | ||
| Maintainer : srk <[email protected]> | ||
| |-} | ||
| module System.Nix.Internal.Path where | ||
|
|
||
| import Control.Monad | ||
| import qualified Data.ByteString.Lazy as BSL | ||
| import qualified Data.ByteString.Char8 as BSC | ||
| import Data.Text (Text) | ||
| import qualified Data.Text as T | ||
| import System.FilePath.Posix (takeBaseName, takeDirectory) | ||
| import System.Nix.Path (Path(..), PathName(..), pathName, PathHashAlgo) | ||
| import System.Nix.Internal.Hash (Digest(..), HashAlgorithm'( SHA256 )) | ||
| import System.Nix.Hash (HasDigest, printAsBase16, printAsBase32, printHashAlgo) | ||
| import qualified System.Nix.Hash | ||
|
|
||
| -- | Parse store location | ||
| parseStore :: BSL.ByteString -> T.Text | ||
| parseStore = T.pack . takeDirectory . BSC.unpack . BSL.toStrict | ||
|
|
||
| -- | Parse path from string | ||
| -- | ||
| -- in form <storeDir>/<hash>-<pathName> | ||
| -- into (Just (Path <hash> (PathName <pathName>))) | ||
| -- or Nothing on error | ||
| -- | ||
| -- XXX: should check for @PathHashAlgo length | ||
| parsePath :: BSL.ByteString -> Maybe Path | ||
| parsePath p = case name of | ||
| Nothing -> Nothing | ||
| Just n -> Just $ Path digest n | ||
| where | ||
| base = T.pack . takeBaseName . BSC.unpack . BSL.toStrict $ p | ||
| parts = T.breakOn "-" base | ||
| digest = Digest . BSC.pack . T.unpack . fst $ parts | ||
| name = pathName . T.drop 1 . snd $ parts | ||
|
|
||
|
|
||
| -- experimental | ||
| -- Directory of the store | ||
| type StoreDir = Text | ||
| type Stored a = (StoreDir, a) | ||
|
|
||
| -- wrap StoreDir and Path into tuple | ||
| makeStored :: StoreDir -> Path -> Stored Path | ||
| makeStored sl p = (sl, p) | ||
|
|
||
| type PathType = Text | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we create a new datatype for this? I think it would be: or |
||
| -- "text:<r1>:<r2>:...<rN>" | ||
| -- "source" | ||
| -- "output:<id>" | ||
| -- <id> is the name of the output (usually, "out"). | ||
|
|
||
| -- store settings | ||
| data Settings = Settings { | ||
| storeDir :: StoreDir -- settings.nixStore | ||
| } deriving (Eq, Show) | ||
|
|
||
| -- build a store path in the following form: | ||
| -- <storeDir>/<hash>-<pathName> | ||
| storedToText :: Stored Path -> Text | ||
| storedToText (storeLoc, (Path digest pName)) = T.concat | ||
| [ storeLoc | ||
| , "/" | ||
| , printAsBase32 @PathHashAlgo digest | ||
| , "-" | ||
| , pathNameContents pName | ||
| ] | ||
|
|
||
| makeStorePath :: (HasDigest a) => PathType -> PathName -> Digest a -> Settings -> Text | ||
| makeStorePath typ pName digest settings = T.concat | ||
| [ storeDir settings | ||
| , "/" | ||
| , printAsBase32 @PathHashAlgo $ pathHash typ pName digest (storeDir settings) | ||
| , "-" | ||
| , pathNameContents pName | ||
| ] | ||
|
|
||
| makeStorePath' :: (HasDigest a) => PathType -> PathName -> Digest a -> StoreDir -> Path | ||
| makeStorePath' typ pName digest storeLoc = snd $ makeStoredPath typ pName digest storeLoc | ||
|
|
||
| -- | build Stored Path from the type of the path, path name and a digest stored at StoreDir | ||
| -- As StoreDir is part of the path hashing process we need to take it into account | ||
| -- when building Path(s) | ||
| makeStoredPath :: (HasDigest a) => PathType -> PathName -> Digest a -> StoreDir -> Stored Path | ||
| makeStoredPath typ pName digest storeLoc = makeStored storeLoc $ Path (pathHash typ pName digest storeLoc) pName | ||
|
|
||
| -- build <h> string which is a truncated base32 formatted SHA256 hash of <s> | ||
| pathHash :: (HasDigest a) => PathType -> PathName -> Digest a -> StoreDir -> Digest PathHashAlgo | ||
| pathHash typ pName digest storeLoc = System.Nix.Hash.hash . BSC.pack . T.unpack $ | ||
| makePathDigestString typ pName digest storeLoc | ||
|
|
||
| -- build <s> string which is hashed and used in makeStorePath | ||
| -- <s> = "<pathType>:<hash_algo>:<base16_hash>:<storeDir>:<pathName>" | ||
| -- (exposed for testing purposes only) | ||
| makePathDigestString :: (HasDigest a) => PathType -> PathName -> Digest a -> StoreDir -> Text | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this function is only used in |
||
| makePathDigestString typ pName digest storeLoc = T.intercalate (T.pack ":") | ||
| [ typ | ||
| , printHashAlgo digest | ||
| , printAsBase16 digest | ||
| , storeLoc | ||
| , pathNameContents pName | ||
| ] | ||
|
|
||
| -- make output path from `PathName` digest and outputId which typically is "out" | ||
| makeOutputPath :: (HasDigest a) => PathName -> Digest a -> T.Text -> Settings -> Text | ||
| makeOutputPath pName digest outputId settings = | ||
| makeStorePath typ (adjustName pName) digest settings | ||
| where | ||
| typ = T.concat [ "output:", outputId ] | ||
| adjustName n | outputId == "out" = n | ||
| adjustName (PathName name) | otherwise = PathName $ T.concat [ name, T.pack "-", outputId ] | ||
|
|
||
| type Recursive = Bool | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still being broken up into manageable chunks,but see 974a944#diff-d6eea410e6c564641deccfa88ae99d1fR101 |
||
| -- make fixed output path from `PathName` and Recursive option | ||
| makeFixedOutputPath :: (HasDigest a) => PathName -> Digest a -> Recursive -> Settings -> Text | ||
| makeFixedOutputPath pName digest True settings = -- XXX: this needs be restricted to @a == @SHA256 | ||
| makeStorePath ("source") pName digest settings | ||
| makeFixedOutputPath pName digest recursive settings = | ||
| makeStorePath ("output:out") pName digest' settings | ||
| where | ||
| rec True = "r:" | ||
| rec False = T.empty | ||
| digest' = System.Nix.Hash.hash @SHA256 $ BSC.pack . T.unpack . T.concat $ | ||
| [ "fixed:out:" | ||
| , rec recursive | ||
| , printHashAlgo digest | ||
| , printAsBase16 digest | ||
| , ":" | ||
| ] | ||
|
|
||
| -- references should be PathSet not [T.Text] | ||
| -- but how to turn PathSet into store paths (texts) again | ||
| -- when we don't have PathType | ||
| type References = [T.Text] | ||
|
|
||
| makeTextPath :: (HasDigest a) => PathName -> Digest a -> References-> Settings -> Text | ||
| makeTextPath pName digest references settings = | ||
| makeStorePath typ pName digest settings | ||
| where typ = T.concat $ [ "text" ] ++ (map (T.cons ':') references) | ||
|
|
||
| storePathForText :: PathName -> T.Text -> References -> Settings -> Text | ||
| storePathForText pName contents references settings = | ||
| makeTextPath pName hashOfContents references settings | ||
| where hashOfContents = System.Nix.Hash.hash @SHA256 (BSC.pack . T.unpack $ contents) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| {-| | ||
| Description : Types and effects for interacting with the Nix store. | ||
| Maintainer : Shea Levy <[email protected]> | ||
| -} | ||
| {-# LANGUAGE DataKinds #-} | ||
| {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
| module System.Nix.ValidPath | ||
| ( ValidPath(..) | ||
| ) where | ||
|
|
||
| import System.Nix.Hash (Digest(..)) | ||
| import System.Nix.StorePath (StorePath(..), StorePathSet, KnownStoreDir) | ||
| import qualified Data.ByteString as BS | ||
| import qualified Data.ByteString.Char8 as BSC | ||
| import Data.Hashable (Hashable (..), hashPtrWithSalt) | ||
| import Data.HashMap.Strict (HashMap) | ||
| import Data.HashSet (HashSet) | ||
| import Data.Map.Strict (Map) | ||
| import Data.Text (Text) | ||
| import Data.Time (UTCTime) | ||
| import qualified Data.Text as T | ||
| import System.IO.Unsafe (unsafeDupablePerformIO) | ||
| import Text.Regex.Base.RegexLike (makeRegex, matchTest) | ||
| import Text.Regex.TDFA.Text (Regex) | ||
|
|
||
| -- | Information about @Path@ | ||
| data (KnownStoreDir a) => ValidPath a = ValidPath | ||
| { -- | Path itself | ||
| path :: !(StorePath a) | ||
| , -- | The .drv which led to this 'Path'. | ||
| deriver :: !(Maybe (StorePath a)) | ||
| , -- | NAR hash | ||
| narHash :: !Text | ||
| , -- | The references of the 'Path' | ||
| references :: !(StorePathSet a) | ||
| , -- | Registration time | ||
| registrationTime :: !UTCTime | ||
| , -- | The size of the uncompressed NAR serialization of this | ||
| -- 'Path'. | ||
| narSize :: !Integer | ||
| , -- | Whether the path is ultimately trusted, that is, it's a | ||
| -- derivation output that was built locally. | ||
| ultimate :: !Bool | ||
| , -- | Signatures | ||
| sigs :: ![Text] | ||
| , -- | Content-addressed | ||
| -- Store path is computed from a cryptographic hash | ||
| -- of the contents of the path, plus some other bits of data like | ||
| -- the "name" part of the path. | ||
| -- | ||
| -- ‘ca’ has one of the following forms: | ||
| -- * ‘text:sha256:<sha256 hash of file contents>’ (paths by makeTextPath() / addTextToStore()) | ||
| -- * ‘fixed:<r?>:<ht>:<h>’ (paths by makeFixedOutputPath() / addToStore()) | ||
| ca :: !Text | ||
| } deriving (Eq, Ord) -- , Show) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| {-# LANGUAGE DataKinds #-} | ||
| {-# LANGUAGE OverloadedStrings #-} | ||
| {-# LANGUAGE ScopedTypeVariables #-} | ||
| {-# LANGUAGE TypeApplications #-} | ||
|
|
||
| module Path where | ||
|
|
||
| import Control.Monad.IO.Class (liftIO) | ||
| import Control.Exception (bracket) | ||
| import qualified Data.ByteString as BS | ||
| import qualified Data.ByteString.Base64.Lazy as B64 | ||
| import qualified Data.ByteString.Lazy as BSL | ||
| import Data.Monoid ((<>)) | ||
| import qualified Data.Text as T | ||
| import System.Directory (removeFile) | ||
| import System.IO.Temp (withSystemTempFile, writeSystemTempFile) | ||
| import qualified System.IO as IO -- (hGetContents, hPutStr, openFile) | ||
| import qualified System.Process as P | ||
| import Test.Tasty as T | ||
| import Test.Tasty.Hspec | ||
| import qualified Test.Tasty.HUnit as HU | ||
| import Test.Tasty.QuickCheck | ||
| import Text.Read (readMaybe) | ||
|
|
||
| import System.Nix.Hash | ||
| import System.Nix.Internal.Hash | ||
| import NarFormat -- TODO: Move the fixtures into a common module | ||
|
|
||
| spec_path :: Spec | ||
| spec_path = do | ||
| return () | ||
|
|
||
| {- | ||
| describe "path operations" $ do | ||
|
|
||
| it "makeStorePath hashes correctly" $ | ||
| makeStorePath "text" (PathName "lal") (hash @MD5 "Hello World") (Settings "/nix/store") `shouldBe` "/nix/store/vsfi9phi6a2hvvvihyh48jn8xh9ld5ax-lal" | ||
|
|
||
| it "store path for text matches real world test scenario" $ | ||
| storePathForText (PathName "lal") ("Hello World") [] (Settings "/run/user/1000/test-nix-store-a256230bc88fe520/store") `shouldBe` "/run/user/1000/test-nix-store-a256230bc88fe520/store/3v0g8si7h0as1nqdanymv2zh2gagbl4f-lal" | ||
|
|
||
| it "parses valid path" $ | ||
| parsePath "/nix/store/vsfi9phi6a2hvvvihyh48jn8xh9ld5ax-lal" `shouldBe` (Just (Path (Digest "vsfi9phi6a2hvvvihyh48jn8xh9ld5ax") (PathName "lal"))) | ||
|
|
||
| it "fails on invalid name" $ | ||
| parsePath "/st/hash-$%^^#" `shouldBe` Nothing | ||
|
|
||
| it "parses store" $ | ||
| parseStore "/nix/store/vsfi9phi6a2hvvvihyh48jn8xh9ld5ax-lal" `shouldBe` "/nix/store" | ||
| -} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is incorrect and needs #34