nvfetcher 0.7.0.0 → 0.8.0.0
raw patch · 26 files changed
+509/−220 lines, 26 filesdep +Globdep +timePVP ok
version bump matches the API change (PVP)
Dependencies added: Glob, time
API changes (from Hackage documentation)
- NvFetcher.Config: instance Data.Default.Class.Default NvFetcher.Config.Config
- NvFetcher.GetGitCommitDate: DateFormat :: Maybe Text -> DateFormat
- NvFetcher.GetGitCommitDate: newtype DateFormat
- NvFetcher.PackageSet: hasCargoLocks :: Attach PackageCargoLockFiles [FilePath]
- NvFetcher.PackageSet: type AttachMany xs arg = forall r. PackageSet (Prod r) -> arg -> PackageSet (Prod (Append xs r))
- NvFetcher.Types: DateFormat :: Maybe Text -> DateFormat
- NvFetcher.Types: [_pgitdateformat] :: Package -> DateFormat
- NvFetcher.Types: instance Control.DeepSeq.NFData NvFetcher.Types.DateFormat
- NvFetcher.Types: instance Data.Binary.Class.Binary NvFetcher.Types.DateFormat
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.Branch
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.DateFormat
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.ForceFetch
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.ListOptions
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.NvcheckerOptions
- NvFetcher.Types: instance Data.Default.Class.Default NvFetcher.Types.VersionSortMethod
- NvFetcher.Types: instance Data.Hashable.Class.Hashable NvFetcher.Types.DateFormat
- NvFetcher.Types: instance GHC.Classes.Eq NvFetcher.Types.DateFormat
- NvFetcher.Types: instance GHC.Classes.Ord NvFetcher.Types.DateFormat
- NvFetcher.Types: instance GHC.Generics.Generic NvFetcher.Types.DateFormat
- NvFetcher.Types: instance GHC.Show.Show NvFetcher.Types.DateFormat
- NvFetcher.Types: instance Prettyprinter.Internal.Pretty NvFetcher.Types.DateFormat
- NvFetcher.Types: newtype DateFormat
- NvFetcher.Types.Lens: pgitdateformat :: Lens' Package DateFormat
+ NvFetcher.Config: instance Data.Default.Internal.Default NvFetcher.Config.Config
+ NvFetcher.ExtractSrc: Glob :: FilePath -> Glob
+ NvFetcher.ExtractSrc: newtype Glob
+ NvFetcher.GetGitCommitDate: GitDateFormat :: Maybe Text -> GitDateFormat
+ NvFetcher.GetGitCommitDate: GitTimeZone :: Maybe Text -> GitTimeZone
+ NvFetcher.GetGitCommitDate: newtype GitDateFormat
+ NvFetcher.GetGitCommitDate: newtype GitTimeZone
+ NvFetcher.Nvchecker: AwesomeVersion :: VersionSortMethod
+ NvFetcher.PackageSet: gitTimeZone :: Attach GitTimeZone (Maybe Text)
+ NvFetcher.PackageSet: hasCargoLock :: Attach PackageCargoLockFiles [Glob]
+ NvFetcher.Types: AwesomeVersion :: VersionSortMethod
+ NvFetcher.Types: GitDateFormat :: Maybe Text -> GitDateFormat
+ NvFetcher.Types: GitTimeZone :: Maybe Text -> GitTimeZone
+ NvFetcher.Types: Glob :: FilePath -> Glob
+ NvFetcher.Types: [_pgitdate] :: Package -> (GitDateFormat, GitTimeZone)
+ NvFetcher.Types: instance Control.DeepSeq.NFData NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance Control.DeepSeq.NFData NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance Control.DeepSeq.NFData NvFetcher.Types.Glob
+ NvFetcher.Types: instance Data.Binary.Class.Binary NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance Data.Binary.Class.Binary NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance Data.Binary.Class.Binary NvFetcher.Types.Glob
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.Branch
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.ForceFetch
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.ListOptions
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.NvcheckerOptions
+ NvFetcher.Types: instance Data.Default.Internal.Default NvFetcher.Types.VersionSortMethod
+ NvFetcher.Types: instance Data.Hashable.Class.Hashable NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance Data.Hashable.Class.Hashable NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance Data.Hashable.Class.Hashable NvFetcher.Types.Glob
+ NvFetcher.Types: instance Data.String.IsString NvFetcher.Types.Glob
+ NvFetcher.Types: instance GHC.Classes.Eq NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance GHC.Classes.Eq NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance GHC.Classes.Eq NvFetcher.Types.Glob
+ NvFetcher.Types: instance GHC.Classes.Ord NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance GHC.Classes.Ord NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance GHC.Classes.Ord NvFetcher.Types.Glob
+ NvFetcher.Types: instance GHC.Generics.Generic NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance GHC.Generics.Generic NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance GHC.Generics.Generic NvFetcher.Types.Glob
+ NvFetcher.Types: instance GHC.Show.Show NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance GHC.Show.Show NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance GHC.Show.Show NvFetcher.Types.Glob
+ NvFetcher.Types: instance GHC.TypeLits.KnownSymbol d => GHC.Show.Show (NvFetcher.Types.DefaultableText d)
+ NvFetcher.Types: instance GHC.TypeLits.KnownSymbol d => Prettyprinter.Internal.Pretty (NvFetcher.Types.DefaultableText d)
+ NvFetcher.Types: instance Prettyprinter.Internal.Pretty NvFetcher.Types.GitDateFormat
+ NvFetcher.Types: instance Prettyprinter.Internal.Pretty NvFetcher.Types.GitTimeZone
+ NvFetcher.Types: instance Prettyprinter.Internal.Pretty NvFetcher.Types.Glob
+ NvFetcher.Types: newtype GitDateFormat
+ NvFetcher.Types: newtype GitTimeZone
+ NvFetcher.Types: newtype Glob
+ NvFetcher.Types.Lens: pgitdate :: Lens' Package (GitDateFormat, GitTimeZone)
- NvFetcher.ExtractSrc: ExtractSrcQ :: NixFetcher Fetched -> NonEmpty FilePath -> ExtractSrcQ
+ NvFetcher.ExtractSrc: ExtractSrcQ :: NixFetcher 'Fetched -> NonEmpty Glob -> ExtractSrcQ
- NvFetcher.ExtractSrc: extractSrc :: NixFetcher Fetched -> FilePath -> Action (HashMap FilePath Text)
+ NvFetcher.ExtractSrc: extractSrc :: NixFetcher 'Fetched -> Glob -> Action (HashMap FilePath FilePath)
- NvFetcher.ExtractSrc: extractSrcs :: NixFetcher Fetched -> NonEmpty FilePath -> Action (HashMap FilePath Text)
+ NvFetcher.ExtractSrc: extractSrcs :: NixFetcher 'Fetched -> NonEmpty Glob -> Action (HashMap FilePath FilePath)
- NvFetcher.FetchRustGitDeps: FetchRustGitDepsQ :: NixFetcher Fetched -> FilePath -> FetchRustGitDepsQ
+ NvFetcher.FetchRustGitDeps: FetchRustGitDepsQ :: NixFetcher 'Fetched -> FilePath -> FetchRustGitDepsQ
- NvFetcher.FetchRustGitDeps: fetchRustGitDeps :: NixFetcher Fetched -> FilePath -> Action (HashMap Text Checksum)
+ NvFetcher.FetchRustGitDeps: fetchRustGitDeps :: NixFetcher 'Fetched -> FilePath -> Action (HashMap Text Checksum)
- NvFetcher.GetGitCommitDate: GetGitCommitDate :: Text -> Text -> DateFormat -> GetGitCommitDate
+ NvFetcher.GetGitCommitDate: GetGitCommitDate :: Text -> Text -> (GitDateFormat, GitTimeZone) -> GetGitCommitDate
- NvFetcher.GetGitCommitDate: [_gformat] :: GetGitCommitDate -> DateFormat
+ NvFetcher.GetGitCommitDate: [_gformat] :: GetGitCommitDate -> (GitDateFormat, GitTimeZone)
- NvFetcher.GetGitCommitDate: getGitCommitDate :: Text -> Text -> DateFormat -> Action Text
+ NvFetcher.GetGitCommitDate: getGitCommitDate :: Text -> Text -> (GitDateFormat, GitTimeZone) -> Action Text
- NvFetcher.NixExpr: fetcherToDrv :: NixFetcher Fetched -> Text -> NixExpr
+ NvFetcher.NixExpr: fetcherToDrv :: NixFetcher 'Fetched -> Text -> NixExpr
- NvFetcher.NixFetcher: RunFetch :: ForceFetch -> NixFetcher Fresh -> RunFetch
+ NvFetcher.NixFetcher: RunFetch :: ForceFetch -> NixFetcher 'Fresh -> RunFetch
- NvFetcher.NixFetcher: prefetch :: NixFetcher Fresh -> ForceFetch -> Action (Maybe (NixFetcher Fetched))
+ NvFetcher.NixFetcher: prefetch :: NixFetcher 'Fresh -> ForceFetch -> Action (Maybe (NixFetcher 'Fetched))
- NvFetcher.NixFetcher: tarballFetcher :: Text -> NixFetcher Fresh
+ NvFetcher.NixFetcher: tarballFetcher :: Text -> NixFetcher 'Fresh
- NvFetcher.NixFetcher: urlFetcher :: Text -> NixFetcher Fresh
+ NvFetcher.NixFetcher: urlFetcher :: Text -> NixFetcher 'Fresh
- NvFetcher.NixFetcher: urlFetcher' :: Text -> Maybe Text -> NixFetcher Fresh
+ NvFetcher.NixFetcher: urlFetcher' :: Text -> Maybe Text -> NixFetcher 'Fresh
- NvFetcher.PackageSet: andThen :: PkgDSL f => f (Prod r) -> f a -> f (Prod (a ': r))
+ NvFetcher.PackageSet: andThen :: forall (r :: [Type]) a. PkgDSL f => f (Prod r) -> f a -> f (Prod (a ': r))
- NvFetcher.PackageSet: class Member (a :: Type) (r :: [Type])
+ NvFetcher.PackageSet: class Member a (r :: [Type])
- NvFetcher.PackageSet: class OptionalMember (a :: Type) (r :: [Type])
+ NvFetcher.PackageSet: class OptionalMember a (r :: [Type])
- NvFetcher.PackageSet: class PkgDSL f
+ NvFetcher.PackageSet: class PkgDSL (f :: Type -> Type)
- NvFetcher.PackageSet: coerce :: forall {k :: RuntimeRep} (a :: TYPE k) (b :: TYPE k). Coercible a b => a -> b
+ NvFetcher.PackageSet: coerce :: Coercible a b => a -> b
- NvFetcher.PackageSet: define :: (Members '[PackageName, VersionSource, PackageFetcher] r, OptionalMembers '[PackageExtractSrc, PackageCargoLockFiles, PackagePassthru, NvcheckerOptions, UseStaleVersion, DateFormat, ForceFetch] r) => PackageSet (Prod r) -> PackageSet ()
+ NvFetcher.PackageSet: define :: forall (r :: [Type]). (Members '[PackageName, VersionSource, PackageFetcher] r, OptionalMembers '[PackageExtractSrc, PackageCargoLockFiles, PackagePassthru, NvcheckerOptions, UseStaleVersion, GitDateFormat, GitTimeZone, ForceFetch] r) => PackageSet (Prod r) -> PackageSet ()
- NvFetcher.PackageSet: end :: (PkgDSL f, Members '[PackageName, VersionSource, PackageFetcher] r, OptionalMembers '[PackageExtractSrc, PackageCargoLockFiles, NvcheckerOptions, PackagePassthru, UseStaleVersion, DateFormat, ForceFetch] r) => f (Prod r) -> f ()
+ NvFetcher.PackageSet: end :: forall (r :: [Type]). (PkgDSL f, Members '[PackageName, VersionSource, PackageFetcher] r, OptionalMembers '[PackageExtractSrc, PackageCargoLockFiles, NvcheckerOptions, PackagePassthru, UseStaleVersion, GitDateFormat, GitTimeZone, ForceFetch] r) => f (Prod r) -> f ()
- NvFetcher.PackageSet: extractSource :: Attach PackageExtractSrc [FilePath]
+ NvFetcher.PackageSet: extractSource :: Attach PackageExtractSrc [Glob]
- NvFetcher.PackageSet: fetchGit' :: Attach PackageFetcher (Text, NixFetcher Fresh -> NixFetcher Fresh)
+ NvFetcher.PackageSet: fetchGit' :: Attach PackageFetcher (Text, NixFetcher 'Fresh -> NixFetcher 'Fresh)
- NvFetcher.PackageSet: fetchGitHub' :: Attach PackageFetcher (Text, Text, NixFetcher Fresh -> NixFetcher Fresh)
+ NvFetcher.PackageSet: fetchGitHub' :: Attach PackageFetcher (Text, Text, NixFetcher 'Fresh -> NixFetcher 'Fresh)
- NvFetcher.PackageSet: forceFetch :: PackageSet (Prod r) -> PackageSet (Prod (ForceFetch : r))
+ NvFetcher.PackageSet: forceFetch :: forall (r :: [Type]). PackageSet (Prod r) -> PackageSet (Prod (ForceFetch ': r))
- NvFetcher.PackageSet: fromGitHub' :: AttachMany '[PackageFetcher, VersionSource] (Text, Text, NixFetcher Fresh -> NixFetcher Fresh)
+ NvFetcher.PackageSet: fromGitHub' :: AttachMany '[PackageFetcher, VersionSource] (Text, Text, NixFetcher 'Fresh -> NixFetcher 'Fresh)
- NvFetcher.PackageSet: fromGitHubTag' :: AttachMany '[PackageFetcher, VersionSource] (Text, Text, ListOptions -> ListOptions, NixFetcher Fresh -> NixFetcher Fresh)
+ NvFetcher.PackageSet: fromGitHubTag' :: AttachMany '[PackageFetcher, VersionSource] (Text, Text, ListOptions -> ListOptions, NixFetcher 'Fresh -> NixFetcher 'Fresh)
- NvFetcher.PackageSet: gitDateFormat :: Attach DateFormat (Maybe Text)
+ NvFetcher.PackageSet: gitDateFormat :: Attach GitDateFormat (Maybe Text)
- NvFetcher.PackageSet: newPackage :: PackageName -> CheckVersion -> PackageFetcher -> Maybe PackageExtractSrc -> Maybe PackageCargoLockFiles -> PackagePassthru -> UseStaleVersion -> DateFormat -> ForceFetch -> PackageSet ()
+ NvFetcher.PackageSet: newPackage :: PackageName -> CheckVersion -> PackageFetcher -> Maybe PackageExtractSrc -> Maybe PackageCargoLockFiles -> PackagePassthru -> UseStaleVersion -> (GitDateFormat, GitTimeZone) -> ForceFetch -> PackageSet ()
- NvFetcher.PackageSet: pinned :: PackageSet (Prod r) -> PackageSet (Prod (UseStaleVersion : r))
+ NvFetcher.PackageSet: pinned :: forall (r :: [Type]). PackageSet (Prod r) -> PackageSet (Prod (UseStaleVersion ': r))
- NvFetcher.PackageSet: type PackageSet = Free PackageSetF
+ NvFetcher.PackageSet: type AttachMany (xs :: [Type]) arg = forall (r :: [Type]). () => PackageSet Prod r -> arg -> PackageSet Prod Append xs r
- NvFetcher.PackageSet: type family OptionalMembers xs r :: Constraint
+ NvFetcher.PackageSet: type family OptionalMembers (xs :: [Type]) (r :: [Type])
- NvFetcher.Types: ExtractSrcQ :: NixFetcher Fetched -> NonEmpty FilePath -> ExtractSrcQ
+ NvFetcher.Types: ExtractSrcQ :: NixFetcher 'Fetched -> NonEmpty Glob -> ExtractSrcQ
- NvFetcher.Types: FetchRustGitDepsQ :: NixFetcher Fetched -> FilePath -> FetchRustGitDepsQ
+ NvFetcher.Types: FetchRustGitDepsQ :: NixFetcher 'Fetched -> FilePath -> FetchRustGitDepsQ
- NvFetcher.Types: GetGitCommitDate :: Text -> Text -> DateFormat -> GetGitCommitDate
+ NvFetcher.Types: GetGitCommitDate :: Text -> Text -> (GitDateFormat, GitTimeZone) -> GetGitCommitDate
- NvFetcher.Types: Package :: PackageName -> CheckVersion -> PackageFetcher -> Maybe PackageExtractSrc -> Maybe PackageCargoLockFiles -> PackagePassthru -> UseStaleVersion -> DateFormat -> ForceFetch -> Package
+ NvFetcher.Types: Package :: PackageName -> CheckVersion -> PackageFetcher -> Maybe PackageExtractSrc -> Maybe PackageCargoLockFiles -> PackagePassthru -> UseStaleVersion -> (GitDateFormat, GitTimeZone) -> ForceFetch -> Package
- NvFetcher.Types: PackageCargoLockFiles :: NonEmpty FilePath -> PackageCargoLockFiles
+ NvFetcher.Types: PackageCargoLockFiles :: NonEmpty Glob -> PackageCargoLockFiles
- NvFetcher.Types: PackageExtractSrc :: NonEmpty FilePath -> PackageExtractSrc
+ NvFetcher.Types: PackageExtractSrc :: NonEmpty Glob -> PackageExtractSrc
- NvFetcher.Types: PackageResult :: PackageName -> NvcheckerResult -> NixFetcher 'Fetched -> Maybe (HashMap Text Text) -> Maybe (HashMap FilePath NixExpr) -> Maybe (HashMap FilePath (NixExpr, HashMap Text Checksum)) -> UseStaleVersion -> Maybe Text -> PackageResult
+ NvFetcher.Types: PackageResult :: PackageName -> NvcheckerResult -> NixFetcher 'Fetched -> Maybe (HashMap Text Text) -> Maybe (HashMap FilePath FilePath) -> Maybe (HashMap FilePath (FilePath, HashMap Text Checksum)) -> UseStaleVersion -> Maybe Text -> PackageResult
- NvFetcher.Types: RunFetch :: ForceFetch -> NixFetcher Fresh -> RunFetch
+ NvFetcher.Types: RunFetch :: ForceFetch -> NixFetcher 'Fresh -> RunFetch
- NvFetcher.Types: [_gformat] :: GetGitCommitDate -> DateFormat
+ NvFetcher.Types: [_gformat] :: GetGitCommitDate -> (GitDateFormat, GitTimeZone)
- NvFetcher.Types: [_prcargolock] :: PackageResult -> Maybe (HashMap FilePath (NixExpr, HashMap Text Checksum))
+ NvFetcher.Types: [_prcargolock] :: PackageResult -> Maybe (HashMap FilePath (FilePath, HashMap Text Checksum))
- NvFetcher.Types: [_prextract] :: PackageResult -> Maybe (HashMap FilePath NixExpr)
+ NvFetcher.Types: [_prextract] :: PackageResult -> Maybe (HashMap FilePath FilePath)
- NvFetcher.Types: type PackageFetcher = Version -> NixFetcher Fresh
+ NvFetcher.Types: type PackageFetcher = Version -> NixFetcher 'Fresh
- NvFetcher.Types.Lens: deepClone :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Bool
+ NvFetcher.Types.Lens: deepClone :: forall (k :: FetchStatus) f. Applicative f => (Bool -> f Bool) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: farch :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Text)
+ NvFetcher.Types.Lens: farch :: forall (k :: FetchStatus) f. Applicative f => (Maybe Text -> f (Maybe Text)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: fetchSubmodules :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Bool
+ NvFetcher.Types.Lens: fetchSubmodules :: forall (k :: FetchStatus) f. Applicative f => (Bool -> f Bool) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: finalImageName :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Text)
+ NvFetcher.Types.Lens: finalImageName :: forall (k :: FetchStatus) f. Applicative f => (Maybe Text -> f (Maybe Text)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: finalImageTag :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Text)
+ NvFetcher.Types.Lens: finalImageTag :: forall (k :: FetchStatus) f. Applicative f => (Maybe Text -> f (Maybe Text)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: fos :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Text)
+ NvFetcher.Types.Lens: fos :: forall (k :: FetchStatus) f. Applicative f => (Maybe Text -> f (Maybe Text)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: fowner :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Text
+ NvFetcher.Types.Lens: fowner :: forall (k :: FetchStatus) f. Applicative f => (Text -> f Text) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: frepo :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Text
+ NvFetcher.Types.Lens: frepo :: forall (k :: FetchStatus) f. Applicative f => (Text -> f Text) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: furl :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Text
+ NvFetcher.Types.Lens: furl :: forall (k :: FetchStatus) f. Applicative f => (Text -> f Text) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: imageDigest :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (FetchResult ContainerDigest k_iTBS)
+ NvFetcher.Types.Lens: imageDigest :: forall (k :: FetchStatus) f. Applicative f => (FetchResult ContainerDigest k -> f (FetchResult ContainerDigest k)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: imageName :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Text
+ NvFetcher.Types.Lens: imageName :: forall (k :: FetchStatus) f. Applicative f => (Text -> f Text) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: imageTag :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Text
+ NvFetcher.Types.Lens: imageTag :: forall (k :: FetchStatus) f. Applicative f => (Text -> f Text) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: leaveDotGit :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Bool
+ NvFetcher.Types.Lens: leaveDotGit :: forall (k :: FetchStatus) f. Applicative f => (Bool -> f Bool) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: name :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Text)
+ NvFetcher.Types.Lens: name :: forall (k :: FetchStatus) f. Applicative f => (Maybe Text -> f (Maybe Text)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: rev :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) Version
+ NvFetcher.Types.Lens: rev :: forall (k :: FetchStatus) f. Applicative f => (Version -> f Version) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: sha256 :: forall k_iTBS. Lens' (NixFetcher k_iTBS) (FetchResult Checksum k_iTBS)
+ NvFetcher.Types.Lens: sha256 :: forall (k :: FetchStatus) f. Functor f => (FetchResult Checksum k -> f (FetchResult Checksum k)) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: sparseCheckout :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) [Text]
+ NvFetcher.Types.Lens: sparseCheckout :: forall (k :: FetchStatus) f. Applicative f => ([Text] -> f [Text]) -> NixFetcher k -> f (NixFetcher k)
- NvFetcher.Types.Lens: tlsVerify :: forall k_iTBS. Traversal' (NixFetcher k_iTBS) (Maybe Bool)
+ NvFetcher.Types.Lens: tlsVerify :: forall (k :: FetchStatus) f. Applicative f => (Maybe Bool -> f (Maybe Bool)) -> NixFetcher k -> f (NixFetcher k)
Files
- CHANGELOG.md +16/−0
- Main_example.hs +2/−2
- README.md +92/−44
- app/Config.hs +9/−5
- app/Config/VersionSource.hs +1/−0
- nvfetcher.cabal +9/−6
- src/NvFetcher.hs +16/−9
- src/NvFetcher/Config.hs +1/−1
- src/NvFetcher/Core.hs +9/−34
- src/NvFetcher/ExtractSrc.hs +50/−28
- src/NvFetcher/FetchRustGitDeps.hs +17/−5
- src/NvFetcher/GetGitCommitDate.hs +18/−6
- src/NvFetcher/NixExpr.hs +20/−11
- src/NvFetcher/NixFetcher.hs +11/−4
- src/NvFetcher/Nvchecker.hs +3/−3
- src/NvFetcher/Options.hs +1/−1
- src/NvFetcher/PackageSet.hs +22/−13
- src/NvFetcher/Types.hs +77/−31
- src/NvFetcher/Types/Lens.hs +1/−1
- src/NvFetcher/Types/ShakeExtras.hs +1/−1
- src/NvFetcher/Utils.hs +18/−5
- test/CheckVersionSpec.hs +3/−3
- test/ExtractSpec.hs +73/−0
- test/GetGitCommitDateSpec.hs +31/−3
- test/PrefetchSpec.hs +3/−3
- test/Utils.hs +5/−1
CHANGELOG.md view
@@ -1,5 +1,21 @@ # Revision history for nvfetcher +## 0.8.0.0++There is a major rework on Source File Extract, which is a *breaking change* and requires users to update their configuration files and the usage of generated Nix expressions.++1. Now both `extract` and `cargo_lock` (renamed from `cargo_locks`) options accept a list of zsh style globs.+2. `ExtractSrc` rule now copies all matched files to the output directory and generates a mapping between relative paths in the output directory and original paths in the source repository, rather than loading them into memory as text files. This makes extracting binary files possible.+3. There are several structural changes in generated Nix expressions. See https://github.com/berberman/nvfetcher/pull/139 for details.++Other changes:+* Add option `git.date_tz` to specify the time zone for `GetGitCommitDate` rule.+* Add `awesomeversion` sort_version_key for nvchecker. Thanks to @auscyber.+* Generate `hash` for Docker fetcher. Thanks to @amesgen.+* Fix binary packaging issue on aarch64-darwin. Thanks to @truelecter.+* Make generated Nix file satisfy nixfmt-rfc-style. Thanks to @zzzsyyy.++ ## 0.7.0.0 Now nvfetcher removes all files *except* `generated.json` and `generated.nix` in `_sources` before each run. If you do want to keep those files, you can use the new CLI option `--keep-old`. In addition, a new target `purge` is introduced for resetting the state of nvfetcher by deleting the shake database saved in XDG directory.
Main_example.hs view
@@ -36,7 +36,7 @@ package "rust-git-dependency-example" `sourceManual` "8a5f37a8f80a3b05290707febf57e88661cee442" `fetchGit` "https://gist.github.com/NickCao/6c4dbc4e15db5da107de6cdb89578375"- `hasCargoLocks` ["Cargo.lock"]+ `hasCargoLock` ["Cargo.lock"] define $ package "vscode-LiveServer" `fromOpenVsx` ("ritwickdey", "LiveServer") @@ -44,4 +44,4 @@ package "revda" `sourceGit` "https://github.com/THMonster/Revda" `fetchGitHub'` ("THMonster", "Revda", fetchSubmodules .~ True)- `hasCargoLocks` ["dmlive/Cargo.lock", "dmlive/tars-stream/Cargo.lock"]+ `hasCargoLock` ["dmlive/Cargo.lock", "dmlive/tars-stream/Cargo.lock"]
README.md view
@@ -4,71 +4,106 @@ [](LICENSE) [](https://github.com/berberman/nvfetcher/actions/workflows/nix.yml) -nvfetcher is a tool to automate nix package updates. It's built on top of [shake](https://www.shakebuild.com/),+`nvfetcher` is a tool to automate nix package updates. It's built on top of [shake](https://www.shakebuild.com/), integrating [nvchecker](https://github.com/lilydjwg/nvchecker).-nvfetcher cli program accepts a TOML file as config, which defines a set of package sources to run.+`nvfetcher` CLI program accepts a TOML file as config, which defines a set of package sources to run. ## Overview -For example, feeding the following configuration to`nvfetcher`:+For example, feeding the following configuration to `nvfetcher`: ```toml # nvfetcher.toml-[feeluown]-src.pypi = "feeluown"-fetch.pypi = "feeluown"+[rustdeck]+src.github = "rustdesk/rustdesk"+fetch.github = "rustdesk/rustdesk"+# Compute outputHashes for git dependencies in cargo lock+cargo_lock = ["Cargo.lock"] ``` -it will create `_sources/generated.nix`:+You would get `_sources/generated.nix`: ```nix-{ fetchgit, fetchurl, fetchFromGitHub }:+# This file was generated by nvfetcher, please do not modify it manually. {- feeluown = {- pname = "feeluown";- version = "3.8.2";- src = fetchurl {- url = "https://pypi.io/packages/source/f/feeluown/feeluown-3.8.2.tar.gz";- sha256 = "sha256-V2yzpkmjRkipZOvQGB2mYRhiiEly6QPrTOMJ7BmyWBQ=";+ fetchgit,+ fetchurl,+ fetchFromGitHub,+ dockerTools,+}:+{+ rustdesk = {+ pname = "rustdesk";+ version = "1.4.2";+ src = fetchFromGitHub {+ owner = "rustdesk";+ repo = "rustdesk";+ rev = "1.4.2";+ fetchSubmodules = false;+ sha256 = "sha256-b/KuWECsmEcz9nPiuPqCcGQ1p+GdbaELScaIXnUTGv8="; };+ cargoLock."Cargo.lock" = {+ lockFile = ./. + "/sha256-b_KuWECsmEcz9nPiuPqCcGQ1p+GdbaELScaIXnUTGv8=/Cargo.lock";+ outputHashes = {+ "filedescriptor-0.8.2" = "sha256-zXTt9eHAVdCPipWAMFeiqk1JteX+7IZcXZ7uvxkzDjQ=";+ # ...+ };+ }; }; }++ ``` and `_sources/generated.json`: ```json {- "feeluown": {- "pinned": false,- "cargoLocks": null,- "name": "feeluown-core",- "version": "3.8.2",- "passthru": null,- "src": {- "url": "https://pypi.io/packages/source/f/feeluown/feeluown-3.8.2.tar.gz",- "name": null,- "type": "url",- "sha256": "sha256-V2yzpkmjRkipZOvQGB2mYRhiiEly6QPrTOMJ7BmyWBQ="- },- "extract": null,- "rustGitDeps": null- }+ "rustdesk": {+ "cargoLock": {+ "Cargo.lock": [+ "sha256-b_KuWECsmEcz9nPiuPqCcGQ1p+GdbaELScaIXnUTGv8=/Cargo.lock",+ {+ "android-wakelock-0.1.0": "sha256-09EH/U1BBs3l4galQOrTKmPUYBgryUjfc/rqPZhdYc4=",+ // ...+ }+ ]+ },+ "date": null,+ "extract": null,+ "name": "rustdesk",+ "passthru": null,+ "pinned": false,+ "src": {+ "deepClone": false,+ "fetchSubmodules": false,+ "leaveDotGit": false,+ "name": null,+ "owner": "rustdesk",+ "repo": "rustdesk",+ "rev": "1.4.2",+ "sha256": "sha256-b/KuWECsmEcz9nPiuPqCcGQ1p+GdbaELScaIXnUTGv8=",+ "sparseCheckout": [],+ "type": "github"+ },+ "version": "1.4.2"+ } } ``` -We tell nvfetcher how to get the latest version number of packages and how to fetch their sources given version numbers,-and nvfetcher will help us keep their version and prefetched SHA256 sums up-to-date, producing ready-to-use nix expressions in `_sources/generated.nix`.-Nvfetcher reads `generated.json` to produce version change message, such as `feeluown: 3.8.1 → 3.8.2`.-We always check versions of packages during each run, but only do prefetch and further operations when needed.+We tell `nvfetcher` how to get the latest version number of packages and how to fetch their sources given version numbers,+and `nvfetcher` will help us keep their version and prefetched SHA256 sums up-to-date, producing ready-to-use nix expressions in `_sources/generated.nix`. +`nvfetcher` reads `generated.json` to produce version change messages, such as `feeluown: 3.8.1 → 3.8.2`.+Versions of packages are always checked during each run, but only do prefetch and further operations when needed.+ ### Live examples How to use the generated sources file? Here are several examples: - My [flakes repo](https://github.com/berberman/flakes) -- Nick Cao's [flakes repo](https://gitlab.com/NickCao/flakes/-/tree/master/pkgs)+**Add your own flakes repo here if you want to share it with others!** ## Installation @@ -80,14 +115,14 @@ This repo also has flakes support: -```+```sh $ nix run github:berberman/nvfetcher ``` To use it as a Haskell library, the package is available on [Hackage](https://hackage.haskell.org/package/nvfetcher). If you want to use the Haskell library from flakes, there is also a shell `ghcWithNvfetcher`: -```+```sh $ nix develop github:berberman/nvfetcher#ghcWithNvfetcher $ runghc Main.hs ```@@ -96,11 +131,11 @@ ## Usage -Basically, there are two ways to use nvfetcher, where the difference is how we provide package sources definitions to it.+Basically, there are two ways to use `nvfetcher`, where the difference is how we provide package sources definitions to it. ### CLI -To run nvfetcher as a CLI program, you'll need to provide package sources defined in TOML.+To run `nvfetcher` as a CLI program, you'll need to provide package sources defined in TOML. ``` Usage: nvfetcher [--version] [--help] [-o|--build-dir DIR] [--commit-changes] @@ -136,13 +171,13 @@ (default: "nvfetcher.toml") ``` -Each _package_ corresponds to a TOML table, whose name is encoded as table key, with+Each package corresponds to a TOML table: name is encoded as table key, with two required fields and three optional fields in each table. You can find an example of the configuration file, see [`nvfetcher_example.toml`](nvfetcher_example.toml). ### Keyfile -You can specify nvchecker keyfile via command line option.+You can specify `nvchecker` keyfile via command line option. For the format of this file, please refer to [nvchecker documentation](https://nvchecker.readthedocs.io/en/latest/usage.html#configuration-table). #### Nvchecker@@ -212,12 +247,20 @@ - `docker.finalImageTag` - `docker.tlsVerify` -#### Extract src+#### Extract source files -Optional _extract src_ config, files are extracted into build directory, and then read by `readFile` in generated nix expr.+Optional source extracting config, files are extracted into build directory. -- `extract = [ "file_1", "file_2", ...]` - file paths are relative to the source root+- `extract = [ "glob_1", "glob_2", ...]` - globs are relative to the source root +Each glob will be resolved to a list of files matching the pattern.+For each matching file, `nvfetcher` copies it to the build directory, and generates `extract.<file_name> = ./. + "<path>"` entry in the nix expr.++Recursive globs are supported, e.g. one can write `extract = [ "**/*" ]` to pull all files in a package to build directory. +See [Glob](https://hackage.haskell.org/package/Glob-0.10.2/docs/System-FilePath-Glob.html#v:compile) for details.++Note: Directories are ignored.+ #### Rust support `rustPlatform.buildRustPackage` now accepts an attribute [`cargoLock`](https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/rust.section.md#importing-a-cargolock-file) to vendor dependencies from `Cargo.lock`,@@ -225,8 +268,10 @@ extracting the lock file to build and calculating `cargoLock.outputHashes`, as long as you set the config. There can be many lock files in one source. -- `cargo_locks = [ "cargo_lock_path_1", "cargo_lock_path_2", ...]` - relative to the source root+- `cargo_lock = [ "cargo_lock_glob_1", "cargo_lock_glob_2", ...]` - globs are relative to the source root +Similar to extract, cargo locks will be pulled into build directory.+ #### Passthru _passthru_ config, an additional set of attrs to be generated.@@ -247,6 +292,9 @@ in the format of `%Y-%m-%d` by default. You can provide your own [`strftime`](https://strftime.org/) format: - `git.date_format = "strftime_format"`+- `git.date_tz = "timezone"`++You can use the `git.date_tz` option to specify the time zone for the commit date. Accepts IANA time zone names, e.g. `git.date_tz = "America/New_York"`. Plus, you can use `git.date_tz = "local"` to refer to the local time zone. #### Force fetching
app/Config.hs view
@@ -11,6 +11,7 @@ import Control.Monad.Trans.Except import qualified Data.HashMap.Strict as HMap import Data.List (foldl', intersect)+import qualified Data.List.NonEmpty as NE import qualified Data.Map.Strict as Map import Data.Text (Text) import qualified Data.Text as T@@ -110,16 +111,16 @@ <*> cargoLockPathDecoder <*> passthruDecoder <*> pinnedDecoder- <*> gitDateFormatDecoder+ <*> ((,) <$> gitDateFormatDecoder <*> gitTimeZoneDecoder) <*> forceFetchDecoder -------------------------------------------------------------------------------- extractFilesDecoder :: Decoder (Maybe PackageExtractSrc)-extractFilesDecoder = fmap PackageExtractSrc <$> getFieldOpt "extract"+extractFilesDecoder = fmap (PackageExtractSrc . fmap Glob) <$> getFieldOpt @(NE.NonEmpty String) "extract" cargoLockPathDecoder :: Decoder (Maybe PackageCargoLockFiles)-cargoLockPathDecoder = fmap PackageCargoLockFiles <$> getFieldOpt "cargo_locks"+cargoLockPathDecoder = fmap (PackageCargoLockFiles . fmap Glob) <$> getFieldOpt @(NE.NonEmpty String) "cargo_lock" nvcheckerOptionsDecoder :: Decoder NvcheckerOptions nvcheckerOptionsDecoder =@@ -149,8 +150,11 @@ maybe NoStale (\x -> if x then PermanentStale else NoStale) <$> getFieldOpt "pinned" -gitDateFormatDecoder :: Decoder DateFormat-gitDateFormatDecoder = DateFormat <$> getFieldsOpt ["git", "date_format"]+gitDateFormatDecoder :: Decoder GitDateFormat+gitDateFormatDecoder = GitDateFormat <$> getFieldsOpt ["git", "date_format"]++gitTimeZoneDecoder :: Decoder GitTimeZone+gitTimeZoneDecoder = GitTimeZone <$> getFieldsOpt ["git", "date_tz"] forceFetchDecoder :: Decoder ForceFetch forceFetchDecoder =
app/Config/VersionSource.hs view
@@ -67,6 +67,7 @@ <$> getFieldOpt "include_regex" <*> getFieldOpt "exclude_regex" <*> ( getFieldOpt @Text "sort_version_key" >>= \case+ Just "awesomeversion" -> pure $ Just AwesomeVersion Just "parse_version" -> pure $ Just ParseVersion Just "vercmp" -> pure $ Just Vercmp Just _ -> makeDecoder $ invalidValue "unexpected sort_version_key: it should be either parse_version or vercmp"
nvfetcher.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: nvfetcher-version: 0.7.0.0+version: 0.8.0.0 synopsis: Generate nix sources expr for the latest version of packages @@ -13,7 +13,7 @@ license-file: LICENSE author: berberman maintainer: berberman <berberman.yandex.com>-copyright: 2021-2023 berberman+copyright: 2021-2025 berberman category: Nix build-type: Simple extra-doc-files:@@ -33,19 +33,20 @@ , binary-instances ^>=1.0 , bytestring , containers- , data-default ^>=0.7.1- , extra ^>=1.7+ , data-default ^>=0.7 || ^>=0.8+ , extra ^>=1.7 || ^>=1.8 , free >=5.1 && <5.3+ , Glob ^>=0.10 , microlens , microlens-th , neat-interpolation ^>=0.5.1 , optparse-simple ^>=0.1.1 , parsec , prettyprinter- , regex-tdfa ^>=1.3.1+ , regex-tdfa ^>=1.3 , shake ^>=0.19 , text- , toml-reader ^>=0.2+ , toml-reader ^>=0.2 || ^>=0.3 , transformers , unordered-containers @@ -114,6 +115,7 @@ main-is: Spec.hs other-modules: CheckVersionSpec+ ExtractSpec FetchRustGitDepsSpec GetGitCommitDateSpec NixExprSpec@@ -127,6 +129,7 @@ , hspec , nvfetcher , stm+ , time , unliftio build-tool-depends: hspec-discover:hspec-discover
src/NvFetcher.hs view
@@ -6,7 +6,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -164,6 +164,15 @@ -- Set shakeExtra let shakeOptions2 = shakeOptions1 {shakeExtra = addShakeExtra shakeExtras (shakeExtra shakeConfig)} rules = mainRules config++ -- Remove all files in build dir except generated nix and json+ -- Since core rule has always rerun, any file not generated in this run will be removed+ -- Put it here to avoid removing files generated in this run+ unless (keepOldFiles || (target /= Build)) $+ whenM (D.doesDirectoryExist buildDir) $ do+ oldFiles <- (\\ [generatedJsonFileName, generatedNixFileName]) <$> D.listDirectory buildDir+ putStrLn $ "Removing old files: " <> show oldFiles+ liftIO $ removeFiles buildDir oldFiles shake shakeOptions2 $ want [show target] >> rules where -- Don't touch already pinned packages@@ -192,13 +201,6 @@ removeFilesAfter shakeDir ["//*"] "build" ~> do- -- remove all files in build dir except generated nix and json- -- since core rule has always rerun, any file not generated in this run will be removed- unless keepOldFiles $- whenM (liftIO $ D.doesDirectoryExist buildDir) $ do- oldFiles <- (\\ [generatedJsonFileName, generatedNixFileName]) <$> liftIO (D.listDirectory buildDir)- putVerbose $ "Removing old files: " <> show oldFiles- liftIO $ removeFiles buildDir oldFiles allKeys <- getAllPackageKeys results <- fmap (zip allKeys) $ parallel $ runPackage <$> allKeys let (fmap (fromJust . snd) -> successResults, fmap fst -> failureKeys) = partition (isJust . snd) results@@ -229,7 +231,12 @@ srouces body = [trimming| # This file was generated by nvfetcher, please do not modify it manually.- { fetchgit, fetchurl, fetchFromGitHub, dockerTools }:+ {+ fetchgit,+ fetchurl,+ fetchFromGitHub,+ dockerTools,+ }: { $body }
src/NvFetcher/Config.hs view
@@ -1,4 +1,4 @@--- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental
src/NvFetcher/Core.hs view
@@ -3,7 +3,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -17,9 +17,7 @@ import Data.Coerce (coerce) import qualified Data.HashMap.Strict as HMap-import qualified Data.Text as T import Development.Shake-import Development.Shake.FilePath import Development.Shake.Rule import NvFetcher.ExtractSrc import NvFetcher.FetchRustGitDeps@@ -39,8 +37,8 @@ fetchRustGitDepsRule getGitCommitDateRule addBuiltinRule noLint noIdentity $ \(WithPackageKey (Core, pkg)) _ _ -> do- -- it's important to always rerun- -- since the package definition is not tracked at all+ -- It's important to always rerun since the package definition is not tracked at all+ -- Also we generate new files in the build directory alwaysRerun lookupPackage pkg >>= \case Nothing -> fail $ "Unknown package key: " <> show pkg@@ -55,27 +53,12 @@ -- If we fail to prefetch, we should fail on this package case _prfetched of Just _prfetched -> do- buildDir <- getBuildDir -- extract src _prextract <- case _pextract of Just (PackageExtractSrc extract) -> do- result <- HMap.toList <$> extractSrcs _prfetched extract- Just . HMap.fromList- <$> sequence- [ do- -- write extracted files to build dir- -- and read them in nix using 'builtins.readFile'- writeFile' (buildDir </> path) (T.unpack v)- pure (k, T.pack path)- | (k, v) <- result,- let path =- "./"- <> T.unpack _pname- <> "-"- <> T.unpack (coerce version)- </> k- ]+ result <- extractSrcs _prfetched extract+ pure $ Just result _ -> pure Nothing -- cargo locks _prcargolock <-@@ -83,23 +66,15 @@ Just (PackageCargoLockFiles lockPath) -> do lockFiles <- HMap.toList <$> extractSrcs _prfetched lockPath result <- parallel $- flip fmap lockFiles $ \(lockPath, lockData) -> do- result <- fetchRustGitDeps _prfetched lockPath- let lockPath' =- T.unpack _pname- <> "-"- <> T.unpack (coerce version)- </> lockPath- lockPathNix = "./" <> T.pack lockPath'- -- similar to extract src, write lock file to build dir- writeFile' (buildDir </> lockPath') $ T.unpack lockData- pure (lockPath, (lockPathNix, result))+ flip fmap lockFiles $ \(srcLockPath, dstLockPath) -> do+ result <- fetchRustGitDeps _prfetched srcLockPath+ pure (srcLockPath, (dstLockPath, result)) pure . Just $ HMap.fromList result _ -> pure Nothing -- Only git version source supports git commit date _prgitdate <- case versionSource of- Git {..} -> Just <$> getGitCommitDate _vurl (coerce version) _pgitdateformat+ Git {..} -> Just <$> getGitCommitDate _vurl (coerce version) _pgitdate _ -> pure Nothing -- update changelog
src/NvFetcher/ExtractSrc.hs view
@@ -1,21 +1,19 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental -- Portability: portable ----- This module provides function that extracs files contents from package sources.--- It uses [IFD](https://nixos.wiki/wiki/Import_From_Derivation) under the hood,--- pulling /textual/ files from source drv.+-- This module provides function that extracts files contents from package sources. -- Because we use @nix-instantiate@ to build drv, so @<nixpkgs>@ (@NIX_PATH@) is required. module NvFetcher.ExtractSrc ( -- * Types ExtractSrcQ (..),+ Glob (..), -- * Rules extractSrcRule,@@ -26,52 +24,76 @@ ) where -import Control.Monad (void)+import Control.Monad (filterM, forM, join, void, when) import Control.Monad.Extra (unlessM) import Data.Binary.Instances ()+import Data.Coerce (coerce) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM+import Data.List (intercalate) import qualified Data.List.NonEmpty as NE-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 Development.Shake.FilePath (makeRelative, (</>)) import NvFetcher.NixExpr import NvFetcher.Types import NvFetcher.Types.ShakeExtras+import NvFetcher.Utils (compileGlob) import Prettyprinter (pretty, (<+>))+import qualified System.Directory.Extra as IO+import System.FilePath.Glob (globDir1) -- | Rules of extract source extractSrcRule :: Rules () extractSrcRule = void $- addOracle $ \q@(ExtractSrcQ fetcher files) -> withTempFile $ \fp -> withRetry $ do- putInfo . show $ "#" <+> pretty q- let nixExpr = T.unpack $ fetcherToDrv fetcher "nvfetcher-extract"- putVerbose $ "Generated nix expr:\n" <> nixExpr- writeFile' fp nixExpr- (CmdTime t, StdoutTrim out, CmdLine c, Stdouterr err) <- quietly $ cmd $ "nix-build --no-out-link " <> fp- putVerbose $ "Finishing running " <> c <> ", took " <> show t <> "s"- putVerbose $ "Output from stdout: " <> out- putVerbose $ "Output from stderr: " <> err- unlessM (doesDirectoryExist out) $- fail $ "nix-build output is not a directory: " <> out- HM.fromList <$> sequence [(f,) <$> liftIO (T.readFile $ out </> f) | f <- NE.toList files]+ addOracle $ \q@(ExtractSrcQ fetcher files) -> do+ withTempFile $ \fp -> withRetry $ do+ putInfo . show $ "#" <+> pretty q+ let nixExpr = T.unpack $ fetcherToDrv fetcher "nvfetcher-extract"+ putVerbose $ "Generated nix expr:\n" <> nixExpr+ writeFile' fp nixExpr+ (CmdTime t, StdoutTrim out, CmdLine c, Stdouterr err) <- quietly $ cmd $ "nix-build --no-out-link " <> fp+ putVerbose $ "Finishing running " <> c <> ", took " <> show t <> "s"+ putVerbose $ "Output from stdout: " <> out+ putVerbose $ "Output from stderr: " <> err+ unlessM (liftIO $ IO.doesDirectoryExist out) $+ fail $+ "nix-build output is not a directory: " <> out+ buildDir <- getBuildDir+ HM.fromList+ <$> fmap+ join+ ( sequence+ [ do+ let compiled = compileGlob glob+ -- Find all matching files+ paths <- liftIO $ fmap (makeRelative out) <$> (liftIO (globDir1 compiled out) >>= filterM IO.doesFileExist)+ putVerbose $ "From glob: " <> coerce glob <> ", found file(s): " <> intercalate ", " paths+ when (null paths) $ fail $ "No files matched glob: " <> coerce glob+ forM paths $ \file -> do+ -- Copy the file to the build directory under the hash of the fetcher+ -- Also replace slashes in the hash with underscores+ let dst = (T.unpack . T.replace "/" "_" . coerce $ _sha256 fetcher) </> file+ copyFile' (out </> file) (buildDir </> dst)+ pure (file, dst)+ | glob <- NE.toList files+ ]+ ) -- | Run extract source with many sources extractSrcs :: -- | prefetched source NixFetcher Fetched ->- -- | relative file paths to extract- NE.NonEmpty FilePath ->- Action (HashMap FilePath Text)+ -- | glob patterns+ NE.NonEmpty Glob ->+ Action (HashMap FilePath FilePath) extractSrcs fetcher xs = askOracle (ExtractSrcQ fetcher xs) -- | Run extract source extractSrc :: -- | prefetched source NixFetcher Fetched ->- -- | relative file path to extract- FilePath ->- Action (HashMap FilePath Text)-extractSrc fetcher fp = extractSrcs fetcher $ NE.fromList [fp]+ -- | glob pattern+ Glob ->+ Action (HashMap FilePath FilePath)+extractSrc fetcher glob = extractSrcs fetcher $ NE.fromList [glob]
src/NvFetcher/FetchRustGitDeps.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -33,32 +33,44 @@ 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 +-- | Read extracted cargo lock content+getExtractedLock :: HashMap FilePath FilePath -> Action (FilePath, Text)+getExtractedLock result = case HMap.toList result of+ [(s, fp)] -> do+ buildDir <- getBuildDir+ content <- liftIO $ T.readFile (buildDir </> fp)+ pure (s, content)+ _ -> fail "Failed to extract cargo lock content. The size of extracted file is not 1."+ -- | Rules of fetch rust git dependencies fetchRustGitDepsRule :: Rules () fetchRustGitDepsRule = void $ addOracleCache $ \key@(FetchRustGitDepsQ fetcher lockPath) -> do putInfo . show $ "#" <+> pretty key- cargoLock <- head . HMap.elems <$> extractSrc fetcher lockPath+ (s, cargoLock) <- extractSrc fetcher (Glob lockPath) >>= getExtractedLock deps <- case Toml.decodeWith (Toml.getFieldWith (Toml.getArrayOf rustDepDecoder) "package") cargoLock of Right r -> pure $ nubOrdOn rrawSrc r- Left err -> fail $ "Failed to parse Cargo.lock: " <> T.unpack (Toml.renderTOMLError err)+ Left err -> fail $ "Failed to parse Cargo lock file " <> s <> ": " <> T.unpack (Toml.renderTOMLError err) r <- parallel- [ case parse gitSrcParser (T.unpack rname) src of+ [ case parse gitSrcParser s src of Right ParsedGitSrc {..} -> do (_sha256 -> sha256) <- fromMaybeM (fail $ "Prefetch failed for " <> T.unpack pgurl) $ prefetch (gitFetcher pgurl pgsha) NoForceFetch -- @${name}-${version}@ -> sha256 pure (rname <> "-" <> coerce rversion, sha256)- Left err -> fail $ "Failed to parse git source in Cargo.lock: " <> show err+ Left err -> fail $ "Failed to parse git source in Cargo lock file: " <> show err | RustDep {..} <- deps, -- it's a dependency src <- maybeToList rrawSrc,
src/NvFetcher/GetGitCommitDate.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -11,8 +11,9 @@ -- The cloned repo will not be preserved. module NvFetcher.GetGitCommitDate ( -- * Types- DateFormat (..),+ GitDateFormat (..), GetGitCommitDate (..),+ GitTimeZone (..), -- * Rules getGitCommitDateRule,@@ -33,15 +34,26 @@ getGitCommitDateRule :: Rules () getGitCommitDateRule = void $ do- addOracleCache $ \q@(GetGitCommitDate (T.unpack -> url) (T.unpack -> rev) format) -> withTempDir $ \repo -> do+ addOracleCache $ \q@(GetGitCommitDate (T.unpack -> url) (T.unpack -> rev) (coerce -> format, coerce -> tz)) -> withTempDir $ \repo -> do putInfo . show $ "#" <+> pretty q (StdoutTrim out) <- quietly $ do cmd_ [Cwd repo, EchoStderr False, EchoStdout False] ("git init" :: String) cmd_ [Cwd repo, EchoStderr False] $ "git remote add origin " <> url cmd_ [Cwd repo, EchoStderr False] $ "git fetch --depth 1 origin " <> rev cmd_ [Cwd repo, EchoStderr False] ("git checkout FETCH_HEAD" :: String)- cmd [Cwd repo, Shell] $ "git --no-pager log -1 --format=%cd --date=format:\"" <> T.unpack (fromMaybe "%Y-%m-%d" $ coerce format) <> "\""+ cmd+ ( [Cwd repo, Shell]+ -- If the time zone is not local, set it in the environment+ <> [AddEnv "TZ" tz' | Just (T.unpack -> tz') <- [tz], tz' /= "local"]+ )+ $ "git --no-pager log -1 "+ <> "--format=%cd --date=format"+ -- Use --date-local instead of --date if a time zone is specified+ <> maybe "" (const "-local") tz+ <> ":\""+ <> T.unpack (fromMaybe "%Y-%m-%d" format)+ <> "\"" pure $ T.pack out -getGitCommitDate :: Text -> Text -> DateFormat -> Action Text-getGitCommitDate url rev format = askOracle $ GetGitCommitDate url rev format+getGitCommitDate :: Text -> Text -> (GitDateFormat, GitTimeZone) -> Action Text+getGitCommitDate url rev = askOracle . GetGitCommitDate url rev
src/NvFetcher/NixExpr.hs view
@@ -7,7 +7,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -44,10 +44,10 @@ toNixExpr True = "true" toNixExpr False = "false" -instance ToNixExpr a => ToNixExpr [a] where+instance (ToNixExpr a) => ToNixExpr [a] where toNixExpr xs = foldl (\acc x -> acc <> " " <> toNixExpr x) "[" xs <> " ]" -instance ToNixExpr a => ToNixExpr (NE.NonEmpty a) where+instance (ToNixExpr a) => ToNixExpr (NE.NonEmpty a) where toNixExpr = toNixExpr . NE.toList instance {-# OVERLAPS #-} ToNixExpr String where@@ -207,14 +207,23 @@ "" ( \ex -> T.unlines- [ quoteIfNeeds (T.pack name)- <> " = builtins.readFile "- <> fp+ [ quoteIfNeeds (T.pack src)+ <> " = ./. + "+ <> quote ("/" <> T.pack dst) <> ";"- | (name, fp) <- HMap.toList ex+ | (src, dst) <- HMap.toList ex ] ) _prextract+ extracted' =+ if T.null extract+ then ""+ else+ [trimming|+ extract = {+ $extract+ };+ |] cargo = fromMaybe "" $ do cargoLocks <- _prcargolock let depsSnippet (deps :: HashMap Text Checksum) =@@ -225,11 +234,11 @@ <> ";" | (name, sum) <- HMap.toList deps ]- lockSnippet ((T.pack -> fp) :: FilePath, (nixFP :: NixExpr, deps :: HashMap Text Checksum)) =+ lockSnippet ((T.pack -> src) :: FilePath, ((T.pack -> dst) :: FilePath, deps :: HashMap Text Checksum)) = let hashes = depsSnippet deps in [trimming|- cargoLock."$fp" = {- lockFile = $nixFP;+ cargoLock."$src" = {+ lockFile = ./. + "/$dst"; outputHashes = { $hashes };@@ -250,5 +259,5 @@ ) _prpassthru date = maybe "" (\d -> "date = " <> quote d <> ";") _prgitdate- joined = extract <> cargo <> passthru <> date+ joined = extracted' <> cargo <> passthru <> date appending = if T.null joined then "" else "\n" <> joined
src/NvFetcher/NixFetcher.hs view
@@ -11,7 +11,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -55,6 +55,7 @@ ) where +import Control.Applicative ((<|>)) import Control.Exception (ErrorCall) import Control.Monad (void, when) import qualified Data.Aeson as A@@ -147,15 +148,21 @@ putVerbose $ "Finishing running " <> c <> ", took " <> show t <> "s" case A.eitherDecode out of Right FetchedContainer {..} -> do- sri <- sha256ToSri sha256+ sri <- sha256ToSri hash pure FetchDocker {_sha256 = sri, _imageDigest = imageDigest, ..} Left e -> fail $ "Failed to parse output from nix-prefetch-docker as JSON: " <> e data FetchedContainer = FetchedContainer { imageDigest :: ContainerDigest,- sha256 :: Text+ hash :: Text }- deriving (Show, Generic, A.FromJSON)+ deriving (Show, Generic)++instance A.FromJSON FetchedContainer where+ parseJSON = A.withObject "FetchedContainer" $ \o -> do+ imageDigest <- o A..: "imageDigest"+ hash <- o A..: "sha256" <|> o A..: "hash"+ pure FetchedContainer {..} pypiUrl :: Text -> Version -> Text pypiUrl pypi (coerce -> ver) =
src/NvFetcher/Nvchecker.hs view
@@ -3,7 +3,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -105,7 +105,7 @@ runNvchecker pkg options versionSource = withTempFile $ \config -> withRetry $ do mKeyfile <- getKeyfilePath let nvcheckerConfig = T.unpack $ T.unlines $ execWriter $ genNvConfig pkg options mKeyfile versionSource- putVerbose $ "Generated nvchecker config for " <> show pkg <> ":" <> nvcheckerConfig+ putVerbose $ "Generated nvchecker config for " <> show pkg <> ":\n" <> nvcheckerConfig writeFile' config nvcheckerConfig (CmdTime t, Stdout out, CmdLine c) <- quietly . cmd $ "nvchecker --logger json -c " <> config putVerbose $ "Finishing running " <> c <> ", took " <> show t <> "s"@@ -131,7 +131,7 @@ genOptions options ) where- key =: x = tell [key <> " = " <> quote x]+ key =: x = tell [key <> " = " <> quoteAndEscape x] key =:? (Just x) = key =: x _ =:? _ = pure () table t m = tell ["[" <> quote t <> "]"] >> m >> tell [""]
src/NvFetcher/Options.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TemplateHaskell #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental
src/NvFetcher/PackageSet.hs view
@@ -13,7 +13,7 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -82,11 +82,12 @@ -- * Addons extractSource,- hasCargoLocks,+ hasCargoLock, tweakVersion, passthru, pinned, gitDateFormat,+ gitTimeZone, forceFetch, -- ** Miscellaneous@@ -160,11 +161,11 @@ Maybe PackageCargoLockFiles -> PackagePassthru -> UseStaleVersion ->- DateFormat ->+ (GitDateFormat, GitTimeZone) -> ForceFetch -> PackageSet ()-newPackage name source fetcher extract cargo pasthru useStale format force =- liftF $ NewPackage (Package name source fetcher extract cargo pasthru useStale format force) ()+newPackage name source fetcher extract cargo pasthru useStale (format, tz) force =+ liftF $ NewPackage (Package name source fetcher extract cargo pasthru useStale (format, tz) force) () -- | Add a list of packages into package set purePackageSet :: [Package] -> PackageSet ()@@ -263,7 +264,8 @@ NvcheckerOptions, PackagePassthru, UseStaleVersion,- DateFormat,+ GitDateFormat,+ GitTimeZone, ForceFetch ] r@@ -289,7 +291,7 @@ (projMaybe p) (fromMaybe mempty (projMaybe p)) (fromMaybe NoStale (projMaybe p))- (fromMaybe (DateFormat Nothing) (projMaybe p))+ (fromMaybe (GitDateFormat Nothing) (projMaybe p), fromMaybe (GitTimeZone Nothing) (projMaybe p)) (fromMaybe NoForceFetch (projMaybe p)) -- | 'PkgDSL' version of 'newPackage'@@ -312,7 +314,8 @@ PackagePassthru, NvcheckerOptions, UseStaleVersion,- DateFormat,+ GitDateFormat,+ GitTimeZone, ForceFetch ] r@@ -543,14 +546,14 @@ -------------------------------------------------------------------------------- -- | Extract files from fetched package source-extractSource :: Attach PackageExtractSrc [FilePath]+extractSource :: Attach PackageExtractSrc [Glob] extractSource = (. pure . PackageExtractSrc . NE.fromList) . andThen -- | Run 'FetchRustGitDependencies' given the path to @Cargo.lock@ files -- -- The lock files will be extracted as well.-hasCargoLocks :: Attach PackageCargoLockFiles [FilePath]-hasCargoLocks = (. pure . PackageCargoLockFiles . NE.fromList) . andThen+hasCargoLock :: Attach PackageCargoLockFiles [Glob]+hasCargoLock = (. pure . PackageCargoLockFiles . NE.fromList) . andThen -- | Set 'NvcheckerOptions' for a package, which can tweak the version number we obtain tweakVersion :: Attach NvcheckerOptions (NvcheckerOptions -> NvcheckerOptions)@@ -571,8 +574,14 @@ -- | Specify the date format for getting git commit date -- -- Available only for git version source-gitDateFormat :: Attach DateFormat (Maybe Text)-gitDateFormat = (. pure . DateFormat) . andThen+gitDateFormat :: Attach GitDateFormat (Maybe Text)+gitDateFormat = (. pure . GitDateFormat) . andThen++-- | Specify the time zone for getting git commit date+--+-- Available only for git version source+gitTimeZone :: Attach GitTimeZone (Maybe Text)+gitTimeZone = (. pure . GitTimeZone) . andThen -- | Set always fetching regardless of the version changing forceFetch :: PackageSet (Prod r) -> PackageSet (Prod (ForceFetch : r))
src/NvFetcher/Types.hs view
@@ -2,21 +2,23 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableSuperClasses #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -32,6 +34,7 @@ NixExpr, VersionChange (..), WithPackageKey (..),+ Glob (..), -- * Nvchecker types VersionSortMethod (..),@@ -57,8 +60,9 @@ FetchRustGitDepsQ (..), -- * GetGitCommitDate types- DateFormat (..),+ GitDateFormat (..), GetGitCommitDate (..),+ GitTimeZone (..), -- * Core types Core (..),@@ -81,16 +85,30 @@ import Data.HashMap.Strict (HashMap) import qualified Data.List.NonEmpty as NE import Data.Maybe (fromMaybe, isNothing)+import Data.Proxy (Proxy (..)) import Data.String (IsString) import Data.Text (Text) import qualified Data.Text as T import Development.Shake import Development.Shake.Classes import GHC.Generics (Generic)+import GHC.TypeLits (KnownSymbol, Symbol, symbolVal) import Prettyprinter -------------------------------------------------------------------------------- +-- | Helper type for generating 'Show' and 'Pretty' instances+-- Type level string @d@ denotes the string used for the default value 'Nothing'+newtype DefaultableText (d :: Symbol) = DefaultableText (Maybe Text)++instance (KnownSymbol d) => Show (DefaultableText d) where+ show (DefaultableText Nothing) = "default (" <> symbolVal (Proxy :: Proxy d) <> ")"+ show (DefaultableText x) = show x++instance (KnownSymbol d) => Pretty (DefaultableText d) where+ pretty (DefaultableText Nothing) = pretty $ "default (" <> symbolVal (Proxy :: Proxy d) <> ")"+ pretty (DefaultableText (Just x)) = pretty x+ -- | Package version newtype Version = Version Text deriving newtype (Eq, Show, Ord, IsString, Semigroup, Monoid, A.FromJSON, A.ToJSON, Pretty)@@ -111,9 +129,10 @@ -- | Git branch ('Nothing': master) newtype Branch = Branch (Maybe Text)- deriving newtype (Show, Eq, Ord, Default, Pretty)+ deriving newtype (Eq, Ord, Default) deriving stock (Typeable, Generic) deriving anyclass (Hashable, Binary, NFData)+ deriving (Pretty, Show) via DefaultableText "master" -- | Version change of a package --@@ -138,17 +157,19 @@ -------------------------------------------------------------------------------- -data VersionSortMethod = ParseVersion | Vercmp+data VersionSortMethod = ParseVersion | Vercmp | AwesomeVersion deriving (Typeable, Eq, Ord, Enum, Generic, Hashable, Binary, NFData) instance Show VersionSortMethod where show = \case ParseVersion -> "parse_version" Vercmp -> "vercmp"+ AwesomeVersion -> "awesomeversion" instance Pretty VersionSortMethod where pretty ParseVersion = "ParseVersion" pretty Vercmp = "Vercmp"+ pretty AwesomeVersion = "AwesomeVersion" instance Default VersionSortMethod where def = ParseVersion@@ -213,7 +234,7 @@ ] ) -ppField :: Pretty a => Doc ann -> Maybe a -> [Doc ann]+ppField :: (Pretty a) => Doc ann -> Maybe a -> [Doc ann] ppField _ Nothing = [] ppField s (Just x) = [s <> colon <+> pretty x] @@ -435,17 +456,17 @@ instance (c (FetchResult Checksum k), c (FetchResult ContainerDigest k)) => ForFetchResult c k -deriving instance Show `ForFetchResult` k => Show (NixFetcher k)+deriving instance (Show `ForFetchResult` k) => Show (NixFetcher k) -deriving instance Eq `ForFetchResult` k => Eq (NixFetcher k)+deriving instance (Eq `ForFetchResult` k) => Eq (NixFetcher k) -deriving instance Ord `ForFetchResult` k => Ord (NixFetcher k)+deriving instance (Ord `ForFetchResult` k) => Ord (NixFetcher k) -deriving instance Hashable `ForFetchResult` k => Hashable (NixFetcher k)+deriving instance (Hashable `ForFetchResult` k) => Hashable (NixFetcher k) -deriving instance Binary `ForFetchResult` k => Binary (NixFetcher k)+deriving instance (Binary `ForFetchResult` k) => Binary (NixFetcher k) -deriving instance NFData `ForFetchResult` k => NFData (NixFetcher k)+deriving instance (NFData `ForFetchResult` k) => NFData (NixFetcher k) -- | Fetch status data FetchStatus = Fresh | Fetched@@ -568,12 +589,24 @@ -------------------------------------------------------------------------------- +-- | Zsh style glob pattern+-- Notably, recursive wildcards like @**/@ are supported.+newtype Glob = Glob FilePath+ deriving newtype (Show, Eq, Ord, IsString, Pretty)+ deriving stock (Typeable, Generic)+ deriving anyclass (Hashable, Binary, NFData)+ -- | Extract file contents from package source--- e.g. @Cargo.lock@-data ExtractSrcQ = ExtractSrcQ (NixFetcher Fetched) (NE.NonEmpty FilePath)+-- Matched files will be copied to build dir.+-- All matched directories are ignored. Only files will be processed.+data ExtractSrcQ = ExtractSrcQ (NixFetcher Fetched) (NE.NonEmpty Glob) deriving (Show, Eq, Ord, Hashable, NFData, Binary, Typeable, Generic) -type instance RuleResult ExtractSrcQ = HashMap FilePath Text+-- | Rule result for extracting source files. 'Text' is the file contents,+-- only available if the second element of the tuple in 'ExtractSrcQ' is @True@.+-- The key of the result map is the file path relative to the package source,+-- and the value is the file path relative to the build directory.+type instance RuleResult ExtractSrcQ = HashMap FilePath FilePath instance Pretty ExtractSrcQ where pretty (ExtractSrcQ f n) =@@ -613,18 +646,31 @@ -------------------------------------------------------------------------------- -- | @strftime@ format------ Nothing defaults to @%Y-%m-%d@-newtype DateFormat = DateFormat (Maybe Text)- deriving newtype (Show, Eq, Ord, Default, Pretty)+-- Defaults to @%Y-%m-%d@+newtype GitDateFormat = GitDateFormat (Maybe Text)+ deriving newtype (Eq, Ord, Default) deriving stock (Typeable, Generic) deriving anyclass (Hashable, Binary, NFData)+ deriving (Pretty, Show) via DefaultableText "%Y-%m-%d" +-- | Defaults to commit's time zone.+-- When set to @local@, current local time zone is used.+-- Only used in 'GetGitCommitDate'.+newtype GitTimeZone = GitTimeZone (Maybe Text)+ deriving newtype (Eq, Ord, Default)+ deriving stock (Typeable, Generic)+ deriving anyclass (Hashable, Binary, NFData)+ deriving (Pretty, Show) via DefaultableText "commit's time zone"+ -- | Get the commit date by using shallow clone -- -- @_gformat@ is in. -- Note: Requires git >= 2.5-data GetGitCommitDate = GetGitCommitDate {_gurl :: Text, _grev :: Text, _gformat :: DateFormat}+data GetGitCommitDate = GetGitCommitDate+ { _gurl :: Text,+ _grev :: Text,+ _gformat :: (GitDateFormat, GitTimeZone)+ } deriving (Show, Eq, Ord, Hashable, NFData, Binary, Typeable, Generic) type instance RuleResult GetGitCommitDate = Text@@ -650,9 +696,9 @@ -- | How to create package source fetcher given a version type PackageFetcher = Version -> NixFetcher Fresh -newtype PackageExtractSrc = PackageExtractSrc (NE.NonEmpty FilePath)+newtype PackageExtractSrc = PackageExtractSrc (NE.NonEmpty Glob) -newtype PackageCargoLockFiles = PackageCargoLockFiles (NE.NonEmpty FilePath)+newtype PackageCargoLockFiles = PackageCargoLockFiles (NE.NonEmpty Glob) newtype PackagePassthru = PackagePassthru (HashMap Text Text) deriving newtype (Semigroup, Monoid)@@ -676,10 +722,10 @@ -- 2. how to track its version -- 3. how to fetch it as we have the version -- 4. optional file paths to extract (dump to build dir)--- 5. optional @Cargo.lock@ path (if it's a rust package)+-- 5. optional @Cargo.lock@ paths (if it's a rust package) -- 6. an optional pass through map -- 7. if the package version was pinned--- 8. optional git date format (if the version source is git)+-- 8. optional git date format with time zone (if the version source is git) -- 9. whether to always fetch a package regardless of the version changing -- /INVARIANT: 'Version' passed to 'PackageFetcher' MUST be used textually,/ -- /i.e. can only be concatenated with other strings,/@@ -692,7 +738,7 @@ _pcargo :: Maybe PackageCargoLockFiles, _ppassthru :: PackagePassthru, _ppinned :: UseStaleVersion,- _pgitdateformat :: DateFormat,+ _pgitdate :: (GitDateFormat, GitTimeZone), _pforcefetch :: ForceFetch } @@ -716,7 +762,7 @@ newtype WithPackageKey k = WithPackageKey (k, PackageKey) deriving newtype (Eq, Hashable, Binary, NFData) -instance Show k => Show (WithPackageKey k) where+instance (Show k) => Show (WithPackageKey k) where show (WithPackageKey (k, n)) = show k <> " (" <> show n <> ")" type instance RuleResult (WithPackageKey k) = RuleResult k@@ -727,10 +773,10 @@ _prversion :: NvcheckerResult, _prfetched :: NixFetcher 'Fetched, _prpassthru :: Maybe (HashMap Text Text),- -- | extracted file name -> file path in build dir- _prextract :: Maybe (HashMap FilePath NixExpr),- -- | cargo lock file path in build dir -> (file path in nix, git dependencies)- _prcargolock :: Maybe (HashMap FilePath (NixExpr, HashMap Text Checksum)),+ -- | file path relative to package source -> file path relative to build dir+ _prextract :: Maybe (HashMap FilePath FilePath),+ -- | cargo lock file path relative to package source -> (lock file path relative to build dir, git dependencies)+ _prcargolock :: Maybe (HashMap FilePath (FilePath, HashMap Text Checksum)), _prpinned :: UseStaleVersion, _prgitdate :: Maybe Text }@@ -744,7 +790,7 @@ "src" A..= _prfetched, "extract" A..= _prextract, "passthru" A..= _prpassthru,- "cargoLocks" A..= _prcargolock,+ "cargoLock" A..= _prcargolock, "pinned" A..= case _prpinned of PermanentStale -> True _ -> False,
src/NvFetcher/Types/Lens.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE TemplateHaskell #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental
src/NvFetcher/Types/ShakeExtras.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeApplications #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental
src/NvFetcher/Utils.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} --- | Copyright: (c) 2021-2022 berberman+-- | Copyright: (c) 2021-2025 berberman -- SPDX-License-Identifier: MIT -- Maintainer: berberman <berberman@yandex.com> -- Stability: experimental@@ -12,21 +12,29 @@ import qualified Data.ByteString.Lazy as LBS import Data.Text (Text) import qualified Data.Text as T-import System.Directory.Extra (XdgDirectory (XdgData), getXdgDirectory)+import NvFetcher.Types+import System.Directory.Extra (XdgDirectory (..), getXdgDirectory)+import System.FilePath.Glob (Pattern, compile) import Text.Regex.TDFA ((=~))+ #if MIN_VERSION_aeson(2,0,0) import qualified Data.Aeson.Key as A #endif -encode' :: Binary a => a -> BS.ByteString+encode' :: (Binary a) => a -> BS.ByteString encode' = BS.concat . LBS.toChunks . encode -decode' :: Binary a => BS.ByteString -> a+decode' :: (Binary a) => BS.ByteString -> a decode' = decode . LBS.fromChunks . pure quote :: Text -> Text-quote = T.pack . show+quote x = T.concat [q, x, q]+ where+ q = T.pack "\"" +quoteAndEscape :: Text -> Text+quoteAndEscape = T.pack . show+ isLegalNixId :: Text -> Bool isLegalNixId x = x =~ "^[a-zA-Z_][a-zA-Z0-9_'-]*$" @@ -37,6 +45,11 @@ getDataDir :: IO FilePath getDataDir = getXdgDirectory XdgData "nvfetcher"++-- | Compile a 'Glob' pattern into a 'Pattern'.+-- See <https://hackage.haskell.org/package/Glob/docs/System-FilePath-Glob.html#v:compile> for details.+compileGlob :: Glob -> Pattern+compileGlob (Glob txt) = compile txt #if MIN_VERSION_aeson(2,0,0) aesonKey :: Text -> A.Key
test/CheckVersionSpec.hs view
@@ -30,7 +30,7 @@ runNvcheckerRule (Pypi "example") `shouldReturnJust` Version "0.1.0" specifyChan "archpkg" $- runNvcheckerRule (ArchLinux "lib32-libva-vdpau-driver") `shouldReturnJust` Version "0.7.4"+ runNvcheckerRule (ArchLinux "xfce4-artwork") `shouldReturnJust` Version "0.1.1a_git20110420" specifyChan "aur" $ runNvcheckerRule (Aur "ssed") `shouldReturnJust` Version "3.62"@@ -76,7 +76,7 @@ runNvcheckerRule (Cmd "echo Meow") `shouldReturnJust` Version "Meow" specifyChan "container" $- runNvcheckerRule (Container "testcontainers/helloworld" def) `shouldReturnJust` Version "1.1.0"+ runNvcheckerRule (Container "testcontainers/helloworld" def) `shouldReturnJust` Version "1.3.0" -------------------------------------------------------------------------------- @@ -136,7 +136,7 @@ _pextract = undefined, _ppassthru = undefined, _ppinned = NoStale,- _pgitdateformat = undefined,+ _pgitdate = undefined, _pforcefetch = undefined }
+ test/ExtractSpec.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}++module ExtractSpec where++import Control.Monad.Trans.Reader+import qualified Data.HashMap.Strict as HMap+import qualified Data.List.NonEmpty as NE+import Data.Maybe (fromJust)+import Development.Shake (liftIO)+import Development.Shake.FilePath ((</>))+import FetchRustGitDepsSpec (runPrefetchRule)+import NvFetcher (getBuildDir)+import NvFetcher.ExtractSrc+import NvFetcher.NixFetcher+import NvFetcher.Types+import qualified System.Directory.Extra as IO+import Test.Hspec+import Utils++spec :: Spec+spec = aroundShake $ do+ describe "extract" $ do+ let fetcher = gitHubFetcher ("berberman", "nvfetcher") $ Version "0.7.0"+ srcSha256 = "sha256-GVjVivAz2AW7WNqpWTA5Uy9vN8Wh_3pjuZRFhsGVk24="+ mkExpectedMap files = HMap.fromList [(f, srcSha256 </> f) | f <- files]+ mkExpectedPaths buildDir files = [buildDir </> srcSha256 </> f | f <- files]+ allExist = mapM_ shouldExist+ specifyChan "extracts single file" $ do+ prefetched <- runPrefetchRule fetcher+ shouldBeJust prefetched+ let expectedFiles = ["Setup.hs"]+ runExtractSrcsRule (fromJust prefetched) (NE.singleton "Setup.hs")+ `shouldReturnJust` mkExpectedMap expectedFiles+ (fromJust -> buildDir) <- runActionChan getBuildDir+ allExist $ mkExpectedPaths buildDir expectedFiles+ specifyChan "extracts files" $ do+ prefetched <- runPrefetchRule fetcher+ shouldBeJust prefetched+ let expectedFiles =+ [ "default.nix",+ "CHANGELOG.md",+ "README.md",+ "flake.nix",+ "nix/default.nix"+ ]+ runExtractSrcsRule (fromJust prefetched) (NE.fromList ["**/*.nix", "*.md"])+ `shouldReturnJust` mkExpectedMap expectedFiles+ (fromJust -> buildDir) <- runActionChan getBuildDir+ allExist $ mkExpectedPaths buildDir expectedFiles+ specifyChan "extracts rerun" $ do+ prefetched <- runPrefetchRule fetcher+ shouldBeJust prefetched+ let expectedFiles = ["Setup.hs"]+ runExtractSrcsRule (fromJust prefetched) (NE.singleton "Setup.hs")+ `shouldReturnJust` mkExpectedMap expectedFiles+ (fromJust -> buildDir) <- runActionChan getBuildDir+ let path = case mkExpectedPaths buildDir expectedFiles of+ [] -> error "Impossible"+ (p : _) -> p+ allExist [path]+ -- Delete this generated file and rerun the rule+ -- We should see the file being regenerated+ liftIO $ IO.removeFile path+ -- Run again+ runExtractSrcsRule (fromJust prefetched) (NE.singleton "Setup.hs")+ `shouldReturnJust` mkExpectedMap expectedFiles+ -- Check that the file has been regenerated+ allExist [path]++runExtractSrcsRule :: NixFetcher Fetched -> NE.NonEmpty Glob -> ReaderT ActionQueue IO (Maybe (HMap.HashMap FilePath FilePath))+runExtractSrcsRule fetcher globs = runActionChan $ extractSrcs fetcher globs
test/GetGitCommitDateSpec.hs view
@@ -1,10 +1,15 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} module GetGitCommitDateSpec where +import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Reader import Data.Default (def)+import Data.Maybe (fromJust) import Data.Text (Text)+import qualified Data.Text as T+import Data.Time (UTCTime, defaultTimeLocale, formatTime, getCurrentTimeZone, parseTimeM, utcToLocalTime) import NvFetcher.GetGitCommitDate import Test.Hspec import Utils@@ -17,14 +22,37 @@ runGetGitCommitDateRule repo rev def `shouldReturnJust` "2021-05-31" specifyChan "custom format" $- runGetGitCommitDateRule repo rev (DateFormat $ Just "%Y-%m-%d %H:%M:%S")+ runGetGitCommitDateRule repo rev (GitDateFormat $ Just "%Y-%m-%d %H:%M:%S", def) `shouldReturnJust` "2021-05-31 18:43:48"+ specifyChan "UTC time zone" $+ runGetGitCommitDateRule repo rev (GitDateFormat $ Just "%H:%M:%S", GitTimeZone $ Just "UTC")+ -- The commit was made at UTC+8; hence we expect the time to be 8 hours earlier+ `shouldReturnJust` "10:43:48" + -- TODO+ -- Test commented out as this logic does not work:+ -- The git command with --date=local returns DST time zone if the commit time falls within DST, + -- but our conversion always uses current local time zone, which may not match git's output.+ -- It's not clear how to check whether DST applies for a given time zone at a specific date/time in Haskell.+ --+ -- specifyChan "local time zone" $ do+ -- -- Get the current time zone+ -- tz <- liftIO getCurrentTimeZone+ -- -- Get commit time at UTC+ -- rawCommitTime <- runGetGitCommitDateRule repo rev (GitDateFormat $ Just "%Y-%m-%d %H:%M:%S", GitTimeZone $ Just "UTC")+ -- shouldBeJust rawCommitTime+ -- parsedCommitTime :: UTCTime <- parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M:%S" . T.unpack . fromJust $ rawCommitTime+ -- -- Convert UTC time to local time+ -- let localTimeStr = T.pack $ formatTime defaultTimeLocale "%H:%M:%S" $ utcToLocalTime tz parsedCommitTime+ -- -- Rule should return the same result as we computed+ -- runGetGitCommitDateRule repo rev (GitDateFormat $ Just "%H:%M:%S", GitTimeZone $ Just "local")+ -- `shouldReturnJust` localTimeStr+ repo :: Text repo = "https://gist.github.com/NickCao/6c4dbc4e15db5da107de6cdb89578375" rev :: Text rev = "8a5f37a8f80a3b05290707febf57e88661cee442" -runGetGitCommitDateRule :: Text -> Text -> DateFormat -> ReaderT ActionQueue IO (Maybe Text)-runGetGitCommitDateRule url rev format = runActionChan $ getGitCommitDate url rev format+runGetGitCommitDateRule :: Text -> Text -> (GitDateFormat, GitTimeZone) -> ReaderT ActionQueue IO (Maybe Text)+runGetGitCommitDateRule url rev (format, tz) = runActionChan $ getGitCommitDate url rev (format, tz)
test/PrefetchSpec.hs view
@@ -47,10 +47,10 @@ specifyChan "url with name" $ runPrefetchRule ( urlFetcher'- "https://files.yande.re/image/3fc51f6a2fb10c96b73dd0fce6ddb9c8/yande.re%201048717%20dress%20garter%20lolita_fashion%20ruo_gan_zhua.jpg"- (Just "foo.jpg")+ "https://whatthecommit.com/6f7a23353b95ca5981bf7b685c278d47.txt"+ (Just "foo.txt") )- `shouldReturnJust` Checksum "sha256-wkiXDN6vPFtx88krcQ4szK6dJNjtrDxrsNa3ZvHlfMQ="+ `shouldReturnJust` Checksum "sha256-jFxm3Zts3ZkgwEJmpHk3cocszzVm2umfhRJCFNam2GA=" testDockerFetcher :: NixFetcher Fresh testDockerFetcher =
test/Utils.hs view
@@ -21,6 +21,7 @@ import NvFetcher.Core (coreRules) import NvFetcher.Types import NvFetcher.Types.ShakeExtras+import qualified System.Directory.Extra as Extra import qualified System.IO.Extra as Extra import System.Time.Extra import Test.Hspec@@ -82,7 +83,10 @@ shouldBeJust :: (MonadIO m, Show a) => Maybe a -> m () shouldBeJust x = liftIO $ x `shouldSatisfy` isJust -specifyChan :: HasCallStack => String -> ReaderT ActionQueue IO () -> SpecWith ActionQueue+shouldExist :: (MonadIO m) => FilePath -> m ()+shouldExist path = liftIO $ Extra.doesFileExist path `shouldReturn` True++specifyChan :: (HasCallStack) => String -> ReaderT ActionQueue IO () -> SpecWith ActionQueue specifyChan s m = specify s $ \r -> runReaderT m r runActionChan :: Action a -> ReaderT ActionQueue IO (Maybe a)