{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
module NvFetcher.FetchRustGitDeps
(
FetchRustGitDepsQ (..),
fetchRustGitDepsRule,
fetchRustGitDeps,
)
where
import Control.Monad (void)
import Control.Monad.Extra (fromMaybeM)
import Data.Binary.Instances ()
import Data.Coerce (coerce)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HMap
import Data.List.Extra (nubOrdOn)
import Data.Maybe (maybeToList)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Development.Shake
import Development.Shake.FilePath ((</>))
import NvFetcher.ExtractSrc
import NvFetcher.NixFetcher
import NvFetcher.Types
import NvFetcher.Types.ShakeExtras (getBuildDir)
import Prettyprinter (pretty, (<+>))
import qualified TOML as Toml
import Text.Parsec
import Text.Parsec.Text
getExtractedLock :: HashMap FilePath FilePath -> Action (FilePath, Text)
HashMap String String
result = case HashMap String String -> [(String, String)]
forall k v. HashMap k v -> [(k, v)]
HMap.toList HashMap String String
result of
[(String
s, String
fp)] -> do
buildDir <- Action String
getBuildDir
content <- liftIO $ T.readFile (buildDir </> fp)
pure (s, content)
[(String, String)]
_ -> String -> Action (String, PackageName)
forall a. String -> Action a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Failed to extract cargo lock content. The size of extracted file is not 1."
fetchRustGitDepsRule :: Rules ()
fetchRustGitDepsRule :: Rules ()
fetchRustGitDepsRule = Rules (FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Rules (FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules ())
-> Rules
(FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules ()
forall a b. (a -> b) -> a -> b
$
(FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules
(FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
forall q a.
(RuleResult q ~ a, ShakeValue q, ShakeValue a, Partial) =>
(q -> Action a) -> Rules (q -> Action a)
addOracleCache ((FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules
(FetchRustGitDepsQ -> Action (HashMap PackageName Checksum)))
-> (FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> Rules
(FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
forall a b. (a -> b) -> a -> b
$ \key :: FetchRustGitDepsQ
key@(FetchRustGitDepsQ NixFetcher 'Fetched
fetcher String
lockPath) -> do
String -> Action ()
putInfo (String -> Action ())
-> (Doc (ZonkAny 0) -> String) -> Doc (ZonkAny 0) -> Action ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc (ZonkAny 0) -> String
forall a. Show a => a -> String
show (Doc (ZonkAny 0) -> Action ()) -> Doc (ZonkAny 0) -> Action ()
forall a b. (a -> b) -> a -> b
$ Doc (ZonkAny 0)
"#" Doc (ZonkAny 0) -> Doc (ZonkAny 0) -> Doc (ZonkAny 0)
forall ann. Doc ann -> Doc ann -> Doc ann
<+> FetchRustGitDepsQ -> Doc (ZonkAny 0)
forall a ann. Pretty a => a -> Doc ann
forall ann. FetchRustGitDepsQ -> Doc ann
pretty FetchRustGitDepsQ
key
(s, cargoLock) <- NixFetcher 'Fetched -> Glob -> Action (HashMap String String)
extractSrc NixFetcher 'Fetched
fetcher (String -> Glob
Glob String
lockPath) Action (HashMap String String)
-> (HashMap String String -> Action (String, PackageName))
-> Action (String, PackageName)
forall a b. Action a -> (a -> Action b) -> Action b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HashMap String String -> Action (String, PackageName)
getExtractedLock
deps <- case Toml.decodeWith (Toml.getFieldWith (Toml.getArrayOf rustDepDecoder) "package") cargoLock of
Right [RustDep]
r -> [RustDep] -> Action [RustDep]
forall a. a -> Action a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([RustDep] -> Action [RustDep]) -> [RustDep] -> Action [RustDep]
forall a b. (a -> b) -> a -> b
$ (RustDep -> Maybe PackageName) -> [RustDep] -> [RustDep]
forall b a. Ord b => (a -> b) -> [a] -> [a]
nubOrdOn RustDep -> Maybe PackageName
rrawSrc [RustDep]
r
Left TOMLError
err -> String -> Action [RustDep]
forall a. String -> Action a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Action [RustDep]) -> String -> Action [RustDep]
forall a b. (a -> b) -> a -> b
$ String
"Failed to parse Cargo lock file " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> PackageName -> String
T.unpack (TOMLError -> PackageName
Toml.renderTOMLError TOMLError
err)
r <-
parallel
[ case parse gitSrcParser s src of
Right ParsedGitSrc {PackageName
Version
pgurl :: PackageName
pgsha :: Version
pgsha :: ParsedGitSrc -> Version
pgurl :: ParsedGitSrc -> PackageName
..} -> do
(_sha256 -> sha256) <- Action (NixFetcher 'Fetched)
-> Action (Maybe (NixFetcher 'Fetched))
-> Action (NixFetcher 'Fetched)
forall (m :: * -> *) a. Monad m => m a -> m (Maybe a) -> m a
fromMaybeM (String -> Action (NixFetcher 'Fetched)
forall a. String -> Action a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Action (NixFetcher 'Fetched))
-> String -> Action (NixFetcher 'Fetched)
forall a b. (a -> b) -> a -> b
$ String
"Prefetch failed for " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> PackageName -> String
T.unpack PackageName
pgurl) (Action (Maybe (NixFetcher 'Fetched))
-> Action (NixFetcher 'Fetched))
-> Action (Maybe (NixFetcher 'Fetched))
-> Action (NixFetcher 'Fetched)
forall a b. (a -> b) -> a -> b
$ NixFetcher 'Fresh
-> ForceFetch -> Action (Maybe (NixFetcher 'Fetched))
prefetch (PackageName -> PackageFetcher
gitFetcher PackageName
pgurl Version
pgsha) ForceFetch
NoForceFetch
pure (rname <> "-" <> coerce rversion, sha256)
Left ParseError
err -> String -> Action (PackageName, Checksum)
forall a. String -> Action a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Action (PackageName, Checksum))
-> String -> Action (PackageName, Checksum)
forall a b. (a -> b) -> a -> b
$ String
"Failed to parse git source in Cargo lock file: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ParseError -> String
forall a. Show a => a -> String
show ParseError
err
| RustDep {..} <- deps,
src <- maybeToList rrawSrc,
"git+" `T.isPrefixOf` src
]
pure $ HMap.fromList r
fetchRustGitDeps ::
NixFetcher Fetched ->
FilePath ->
Action (HashMap Text Checksum)
fetchRustGitDeps :: NixFetcher 'Fetched
-> String -> Action (HashMap PackageName Checksum)
fetchRustGitDeps NixFetcher 'Fetched
fetcher String
lockPath = FetchRustGitDepsQ -> Action (HashMap PackageName Checksum)
forall q a.
(RuleResult q ~ a, ShakeValue q, ShakeValue a) =>
q -> Action a
askOracle (FetchRustGitDepsQ -> Action (HashMap PackageName Checksum))
-> FetchRustGitDepsQ -> Action (HashMap PackageName Checksum)
forall a b. (a -> b) -> a -> b
$ NixFetcher 'Fetched -> String -> FetchRustGitDepsQ
FetchRustGitDepsQ NixFetcher 'Fetched
fetcher String
lockPath
data ParsedGitSrc = ParsedGitSrc
{
ParsedGitSrc -> PackageName
pgurl :: Text,
ParsedGitSrc -> Version
pgsha :: Version
}
deriving (Int -> ParsedGitSrc -> String -> String
[ParsedGitSrc] -> String -> String
ParsedGitSrc -> String
(Int -> ParsedGitSrc -> String -> String)
-> (ParsedGitSrc -> String)
-> ([ParsedGitSrc] -> String -> String)
-> Show ParsedGitSrc
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> ParsedGitSrc -> String -> String
showsPrec :: Int -> ParsedGitSrc -> String -> String
$cshow :: ParsedGitSrc -> String
show :: ParsedGitSrc -> String
$cshowList :: [ParsedGitSrc] -> String -> String
showList :: [ParsedGitSrc] -> String -> String
Show, ParsedGitSrc -> ParsedGitSrc -> Bool
(ParsedGitSrc -> ParsedGitSrc -> Bool)
-> (ParsedGitSrc -> ParsedGitSrc -> Bool) -> Eq ParsedGitSrc
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ParsedGitSrc -> ParsedGitSrc -> Bool
== :: ParsedGitSrc -> ParsedGitSrc -> Bool
$c/= :: ParsedGitSrc -> ParsedGitSrc -> Bool
/= :: ParsedGitSrc -> ParsedGitSrc -> Bool
Eq, Eq ParsedGitSrc
Eq ParsedGitSrc =>
(ParsedGitSrc -> ParsedGitSrc -> Ordering)
-> (ParsedGitSrc -> ParsedGitSrc -> Bool)
-> (ParsedGitSrc -> ParsedGitSrc -> Bool)
-> (ParsedGitSrc -> ParsedGitSrc -> Bool)
-> (ParsedGitSrc -> ParsedGitSrc -> Bool)
-> (ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc)
-> (ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc)
-> Ord ParsedGitSrc
ParsedGitSrc -> ParsedGitSrc -> Bool
ParsedGitSrc -> ParsedGitSrc -> Ordering
ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ParsedGitSrc -> ParsedGitSrc -> Ordering
compare :: ParsedGitSrc -> ParsedGitSrc -> Ordering
$c< :: ParsedGitSrc -> ParsedGitSrc -> Bool
< :: ParsedGitSrc -> ParsedGitSrc -> Bool
$c<= :: ParsedGitSrc -> ParsedGitSrc -> Bool
<= :: ParsedGitSrc -> ParsedGitSrc -> Bool
$c> :: ParsedGitSrc -> ParsedGitSrc -> Bool
> :: ParsedGitSrc -> ParsedGitSrc -> Bool
$c>= :: ParsedGitSrc -> ParsedGitSrc -> Bool
>= :: ParsedGitSrc -> ParsedGitSrc -> Bool
$cmax :: ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc
max :: ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc
$cmin :: ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc
min :: ParsedGitSrc -> ParsedGitSrc -> ParsedGitSrc
Ord)
gitSrcParser :: Parser ParsedGitSrc
gitSrcParser :: Parsec PackageName () ParsedGitSrc
gitSrcParser = do
_ <- String -> ParsecT PackageName () Identity String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"git+"
pgurl <- many1 $ noneOf ['?', '#']
skipMany (noneOf ['#'])
_ <- char '#'
pgsha <- manyTill anyChar eof
pure $ ParsedGitSrc (T.pack pgurl) (coerce $ T.pack pgsha)
data RustDep = RustDep
{ RustDep -> PackageName
rname :: PackageName,
RustDep -> Version
rversion :: Version,
RustDep -> Maybe PackageName
rrawSrc :: Maybe Text
}
deriving (Int -> RustDep -> String -> String
[RustDep] -> String -> String
RustDep -> String
(Int -> RustDep -> String -> String)
-> (RustDep -> String)
-> ([RustDep] -> String -> String)
-> Show RustDep
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> RustDep -> String -> String
showsPrec :: Int -> RustDep -> String -> String
$cshow :: RustDep -> String
show :: RustDep -> String
$cshowList :: [RustDep] -> String -> String
showList :: [RustDep] -> String -> String
Show, RustDep -> RustDep -> Bool
(RustDep -> RustDep -> Bool)
-> (RustDep -> RustDep -> Bool) -> Eq RustDep
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RustDep -> RustDep -> Bool
== :: RustDep -> RustDep -> Bool
$c/= :: RustDep -> RustDep -> Bool
/= :: RustDep -> RustDep -> Bool
Eq, Eq RustDep
Eq RustDep =>
(RustDep -> RustDep -> Ordering)
-> (RustDep -> RustDep -> Bool)
-> (RustDep -> RustDep -> Bool)
-> (RustDep -> RustDep -> Bool)
-> (RustDep -> RustDep -> Bool)
-> (RustDep -> RustDep -> RustDep)
-> (RustDep -> RustDep -> RustDep)
-> Ord RustDep
RustDep -> RustDep -> Bool
RustDep -> RustDep -> Ordering
RustDep -> RustDep -> RustDep
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: RustDep -> RustDep -> Ordering
compare :: RustDep -> RustDep -> Ordering
$c< :: RustDep -> RustDep -> Bool
< :: RustDep -> RustDep -> Bool
$c<= :: RustDep -> RustDep -> Bool
<= :: RustDep -> RustDep -> Bool
$c> :: RustDep -> RustDep -> Bool
> :: RustDep -> RustDep -> Bool
$c>= :: RustDep -> RustDep -> Bool
>= :: RustDep -> RustDep -> Bool
$cmax :: RustDep -> RustDep -> RustDep
max :: RustDep -> RustDep -> RustDep
$cmin :: RustDep -> RustDep -> RustDep
min :: RustDep -> RustDep -> RustDep
Ord)
rustDepDecoder :: Toml.Decoder RustDep
rustDepDecoder :: Decoder RustDep
rustDepDecoder =
PackageName -> Version -> Maybe PackageName -> RustDep
RustDep
(PackageName -> Version -> Maybe PackageName -> RustDep)
-> Decoder PackageName
-> Decoder (Version -> Maybe PackageName -> RustDep)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PackageName -> Decoder PackageName
forall a. DecodeTOML a => PackageName -> Decoder a
Toml.getField PackageName
"name"
Decoder (Version -> Maybe PackageName -> RustDep)
-> Decoder Version -> Decoder (Maybe PackageName -> RustDep)
forall a b. Decoder (a -> b) -> Decoder a -> Decoder b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (forall a b. Coercible a b => a -> b
forall a b. Coercible a b => a -> b
coerce @Text (PackageName -> Version) -> Decoder PackageName -> Decoder Version
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PackageName -> Decoder PackageName
forall a. DecodeTOML a => PackageName -> Decoder a
Toml.getField PackageName
"version")
Decoder (Maybe PackageName -> RustDep)
-> Decoder (Maybe PackageName) -> Decoder RustDep
forall a b. Decoder (a -> b) -> Decoder a -> Decoder b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> PackageName -> Decoder (Maybe PackageName)
forall a. DecodeTOML a => PackageName -> Decoder (Maybe a)
Toml.getFieldOpt PackageName
"source"