Merge branch 'main' into dont-autogenerate-keys

This commit is contained in:
Ben Gamari 2023-03-21 15:32:52 -04:00 committed by GitHub
commit add45abbb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1031 additions and 344 deletions

View File

@ -12,18 +12,16 @@ jobs:
- ubuntu-latest - ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: cachix/install-nix-action@v17 - uses: cachix/install-nix-action@v20
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
substituters = https://cache.iog.io https://cache.nixos.org
- uses: cachix/cachix-action@v10 - uses: cachix/cachix-action@v12
with: with:
name: foliage name: foliage
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- run: nix build - run: nix build --accept-flake-config

27
.github/workflows/update-flake-lock.yml vendored Normal file
View File

@ -0,0 +1,27 @@
name: update-flake-lock
on:
workflow_dispatch: # allows manual triggering
schedule:
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
jobs:
lockfile:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Nix
uses: cachix/install-nix-action@v19
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v16
with:
pr-title: "Update flake.lock" # Title of PR to be created
pr-labels: | # Labels to be set on the PR
dependencies
automated
- name: Print PR number
run: echo Opened pull request ${{ steps.update.outputs.pull-request-number }}.

View File

@ -273,6 +273,18 @@ metadata file `<package>/<version>/meta.toml` includes the option
`force-version = true`, then the version in the package cabal file will be `force-version = true`, then the version in the package cabal file will be
overwritten with `<version>`. Notice this is done after applying patches. overwritten with `<version>`. Notice this is done after applying patches.
# Accessing private repositories
Foliage uses curl to fetch remote assets. If you need to access private
repositories you can use one of the following methods.
- You can instruct curl to use a netrc file.
- Add netrc-optional to ~/.curlrc (see [here](https://curl.se/docs/manpage.html#-K) for the places curl looks in).
- Add the relevant credentials to ~/.netrc
- You can also add the credentials directly to curl's configuration, e.g.
- Add `user = "USERNAME:PASSWORD"` to .curlrc in the current directly
- Set `CURL_HOME=$PWD`
## Author ## Author
- Andrea Bedini (@andreabedini) - Andrea Bedini (@andreabedini)

View File

@ -18,7 +18,7 @@ module Distribution.PackageDescription.FieldGrammar.Copy
where where
import Distribution.CabalSpecVersion import Distribution.CabalSpecVersion
import qualified Distribution.Compat.CharParsing as P import Distribution.Compat.CharParsing qualified as P
import Distribution.Compat.Newtype (Newtype, pack', unpack') import Distribution.Compat.Newtype (Newtype, pack', unpack')
import Distribution.Compat.Prelude import Distribution.Compat.Prelude
import Distribution.Compiler (CompilerFlavor (..)) import Distribution.Compiler (CompilerFlavor (..))
@ -29,8 +29,8 @@ import Distribution.PackageDescription
import Distribution.PackageDescription.FieldGrammar hiding (packageDescriptionFieldGrammar) import Distribution.PackageDescription.FieldGrammar hiding (packageDescriptionFieldGrammar)
import Distribution.Parsec import Distribution.Parsec
import Distribution.Pretty (Pretty (..), showToken) import Distribution.Pretty (Pretty (..), showToken)
import qualified Distribution.SPDX as SPDX import Distribution.SPDX qualified as SPDX
import qualified Distribution.Types.Lens as L import Distribution.Types.Lens qualified as L
import Distribution.Utils.Path import Distribution.Utils.Path
import Distribution.Version (Version, VersionRange) import Distribution.Version (Version, VersionRange)
import Prelude () import Prelude ()

View File

@ -2,14 +2,14 @@
module Distribution.Types.Orphans where module Distribution.Types.Orphans where
import Data.Aeson (ToJSON (toJSON))
import Development.Shake.Classes (Hashable) import Development.Shake.Classes (Hashable)
import Distribution.Pretty (prettyShow)
import Distribution.Types.PackageId (PackageIdentifier) import Distribution.Types.PackageId (PackageIdentifier)
import Distribution.Types.PackageName (PackageName) import Distribution.Types.PackageName (PackageName)
import Distribution.Types.Version (Version) import Distribution.Types.Version (Version)
import Distribution.Types.VersionRange (VersionRange) import Distribution.Types.VersionRange (VersionRange)
import Distribution.Utils.ShortText (ShortText) import Distribution.Utils.ShortText (ShortText)
import Data.Aeson (ToJSON (toJSON))
import Distribution.Pretty (prettyShow)
instance ToJSON PackageIdentifier where instance ToJSON PackageIdentifier where
toJSON = toJSON . prettyShow toJSON = toJSON . prettyShow

View File

@ -6,29 +6,32 @@ module Foliage.CmdBuild (cmdBuild) where
import Codec.Archive.Tar qualified as Tar import Codec.Archive.Tar qualified as Tar
import Codec.Archive.Tar.Entry qualified as Tar import Codec.Archive.Tar.Entry qualified as Tar
import Codec.Compression.GZip qualified as GZip import Codec.Compression.GZip qualified as GZip
import Control.Monad (unless, when) import Control.Monad (unless, void, when)
import Data.Aeson qualified as Aeson
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BL import Data.ByteString.Lazy qualified as BL
import Data.ByteString.Lazy qualified as BSL
import Data.Foldable (for_)
import Data.List (sortOn) import Data.List (sortOn)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Text qualified as T
import Data.Traversable (for) import Data.Traversable (for)
import Development.Shake import Development.Shake
import Development.Shake.FilePath import Development.Shake.FilePath
import Distribution.Package import Distribution.Package
import Distribution.Parsec (simpleParsec)
import Distribution.Pretty (prettyShow) import Distribution.Pretty (prettyShow)
import Foliage.HackageSecurity hiding (ToJSON, toJSON) import Foliage.HackageSecurity hiding (ToJSON, toJSON)
import Foliage.Meta import Foliage.Meta
import Foliage.Meta.Aeson () import Foliage.Meta.Aeson ()
import Foliage.Options import Foliage.Options
import Foliage.Pages import Foliage.Pages
import Foliage.PrepareSdist import Foliage.PreparePackageVersion (PreparedPackageVersion (..), preparePackageVersion)
import Foliage.PrepareSource (addPrepareSourceRule, prepareSource) import Foliage.PrepareSdist (addPrepareSdistRule)
import Foliage.PrepareSource (addPrepareSourceRule)
import Foliage.RemoteAsset (addFetchRemoteAssetRule) import Foliage.RemoteAsset (addFetchRemoteAssetRule)
import Foliage.Shake import Foliage.Shake
import Foliage.Time qualified as Time import Foliage.Time qualified as Time
import Hackage.Security.Util.Path (castRoot, toFilePath) import Hackage.Security.Util.Path (castRoot, toFilePath)
import Network.URI (URI (uriPath, uriQuery, uriScheme), nullURI)
import System.Directory (createDirectoryIfMissing)
cmdBuild :: BuildOptions -> IO () cmdBuild :: BuildOptions -> IO ()
cmdBuild buildOptions = do cmdBuild buildOptions = do
@ -45,7 +48,8 @@ cmdBuild buildOptions = do
opts = opts =
shakeOptions shakeOptions
{ shakeFiles = cacheDir, { shakeFiles = cacheDir,
shakeVerbosity = Verbose shakeVerbosity = Verbose,
shakeThreads = buildOptsNumThreads buildOptions
} }
buildAction :: BuildOptions -> Action () buildAction :: BuildOptions -> Action ()
@ -55,7 +59,8 @@ buildAction
buildOptsCurrentTime = mCurrentTime, buildOptsCurrentTime = mCurrentTime,
buildOptsExpireSignaturesOn = mExpireSignaturesOn, buildOptsExpireSignaturesOn = mExpireSignaturesOn,
buildOptsInputDir = inputDir, buildOptsInputDir = inputDir,
buildOptsOutputDir = outputDir buildOptsOutputDir = outputDir,
buildOptsWriteMetadata = doWritePackageMeta
} = do } = do
outputDirRoot <- liftIO $ makeAbsolute (fromFilePath outputDir) outputDirRoot <- liftIO $ makeAbsolute (fromFilePath outputDir)
@ -94,54 +99,47 @@ buildAction
makeAllPackageVersionsPage currentTime outputDir packageVersions makeAllPackageVersionsPage currentTime outputDir packageVersions
for_ packageVersions $ makePackageVersionPage inputDir outputDir when doWritePackageMeta $
makeMetadataFile outputDir packageVersions
for_ packageVersions $ \pkgMeta@PackageVersionMeta {pkgId} -> do void $ forP packageVersions $ makePackageVersionPage outputDir
void $ forP packageVersions $ \PreparedPackageVersion {pkgId, cabalFilePath} -> do
let PackageIdentifier {pkgName, pkgVersion} = pkgId let PackageIdentifier {pkgName, pkgVersion} = pkgId
cabalFilePath <- maybe (originalCabalFile pkgMeta) pure (revisedCabalFile inputDir pkgMeta)
copyFileChanged cabalFilePath (outputDir </> "index" </> prettyShow pkgName </> prettyShow pkgVersion </> prettyShow pkgName <.> "cabal") copyFileChanged cabalFilePath (outputDir </> "index" </> prettyShow pkgName </> prettyShow pkgVersion </> prettyShow pkgName <.> "cabal")
cabalEntries <- cabalEntries <-
foldMap foldMap
( \pkgMeta@PackageVersionMeta {pkgId, pkgSpec} -> do ( \PreparedPackageVersion {pkgId, pkgTimestamp, originalCabalFilePath, cabalFileRevisions} -> do
let PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions} = pkgSpec
-- original cabal file, with its timestamp (if specified) -- original cabal file, with its timestamp (if specified)
cabalFilePath <- originalCabalFile pkgMeta let cabalFileTimestamp = fromMaybe currentTime pkgTimestamp
let cabalFileTimestamp = fromMaybe currentTime packageVersionTimestamp cf <- prepareIndexPkgCabal pkgId cabalFileTimestamp originalCabalFilePath
cf <- prepareIndexPkgCabal pkgId cabalFileTimestamp cabalFilePath
-- all revised cabal files, with their timestamp -- all revised cabal files, with their timestamp
revcf <- revcf <- for cabalFileRevisions $ uncurry (prepareIndexPkgCabal pkgId)
for packageVersionRevisions $
\RevisionSpec {revisionTimestamp, revisionNumber} ->
prepareIndexPkgCabal
pkgId
revisionTimestamp
(cabalFileRevisionPath inputDir pkgId revisionNumber)
return $ cf : revcf return $ cf : revcf
) )
packageVersions packageVersions
targetKeys <- maybeReadKeysAt "target" targetKeys <- maybeReadKeysAt "target"
metadataEntries <- metadataEntries <-
for packageVersions $ \pkg@PackageVersionMeta {pkgId, pkgSpec} -> do forP packageVersions $ \ppv@PreparedPackageVersion {pkgId, pkgTimestamp} -> do
let PackageIdentifier {pkgName, pkgVersion} = pkgId let PackageIdentifier {pkgName, pkgVersion} = pkgId
let PackageVersionSpec {packageVersionTimestamp} = pkgSpec targets <- prepareIndexPkgMetadata expiryTime ppv
targets <- prepareIndexPkgMetadata expiryTime pkg
let path = outputDir </> "index" </> prettyShow pkgName </> prettyShow pkgVersion </> "package.json" let path = outputDir </> "index" </> prettyShow pkgName </> prettyShow pkgVersion </> "package.json"
liftIO $ BL.writeFile path $ renderSignedJSON targetKeys targets liftIO $ BL.writeFile path $ renderSignedJSON targetKeys targets
return $ pure $
mkTarEntry mkTarEntry
(renderSignedJSON targetKeys targets) (renderSignedJSON targetKeys targets)
(IndexPkgMetadata pkgId) (IndexPkgMetadata pkgId)
(fromMaybe currentTime packageVersionTimestamp) (fromMaybe currentTime pkgTimestamp)
let tarContents = Tar.write $ sortOn Tar.entryTime (cabalEntries ++ metadataEntries) let tarContents = Tar.write $ sortOn Tar.entryTime (cabalEntries ++ metadataEntries)
traced "Writing index" $ do traced "Writing index" $ do
BSL.writeFile (anchorPath outputDirRoot repoLayoutIndexTar) tarContents BL.writeFile (anchorPath outputDirRoot repoLayoutIndexTar) tarContents
BSL.writeFile (anchorPath outputDirRoot repoLayoutIndexTarGz) $ GZip.compress tarContents BL.writeFile (anchorPath outputDirRoot repoLayoutIndexTarGz) $ GZip.compress tarContents
privateKeysRoot <- maybeReadKeysAt "root" privateKeysRoot <- maybeReadKeysAt "root"
privateKeysTarget <- maybeReadKeysAt "target" privateKeysTarget <- maybeReadKeysAt "target"
@ -226,58 +224,66 @@ buildAction
timestampInfoSnapshot = snapshotInfo timestampInfoSnapshot = snapshotInfo
} }
getPackageVersions :: FilePath -> Action [PackageVersionMeta] makeMetadataFile :: FilePath -> [PreparedPackageVersion] -> Action ()
makeMetadataFile outputDir packageVersions = traced "writing metadata" $ do
createDirectoryIfMissing True (outputDir </> "foliage")
Aeson.encodeFile
(outputDir </> "foliage" </> "packages.json")
(map encodePackageVersion packageVersions)
where
encodePackageVersion
PreparedPackageVersion
{ pkgId = PackageIdentifier {pkgName, pkgVersion},
pkgTimestamp,
pkgVersionForce,
pkgVersionSource
} =
Aeson.object
( [ "pkg-name" Aeson..= pkgName,
"pkg-version" Aeson..= pkgVersion,
"url" Aeson..= sourceUrl pkgVersionSource
]
++ ["forced-version" Aeson..= True | pkgVersionForce]
++ (case pkgTimestamp of Nothing -> []; Just t -> ["timestamp" Aeson..= t])
)
sourceUrl :: PackageVersionSource -> URI
sourceUrl (TarballSource uri Nothing) = uri
sourceUrl (TarballSource uri (Just subdir)) = uri {uriQuery = "?dir=" ++ subdir}
sourceUrl (GitHubSource repo rev Nothing) =
nullURI
{ uriScheme = "github:",
uriPath = T.unpack (unGitHubRepo repo) </> T.unpack (unGitHubRev rev)
}
sourceUrl (GitHubSource repo rev (Just subdir)) =
nullURI
{ uriScheme = "github:",
uriPath = T.unpack (unGitHubRepo repo) </> T.unpack (unGitHubRev rev),
uriQuery = "?dir=" ++ subdir
}
getPackageVersions :: FilePath -> Action [PreparedPackageVersion]
getPackageVersions inputDir = do getPackageVersions inputDir = do
metaFiles <- getDirectoryFiles inputDir ["*/*/meta.toml"] metaFiles <- getDirectoryFiles inputDir ["*/*/meta.toml"]
when (null metaFiles) $ do when (null metaFiles) $ do
putError $ error $
unlines unlines
[ "We could not find any package metadata file (i.e. _sources/<name>/<version>/meta.toml)", [ "We could not find any package metadata file (i.e. _sources/<name>/<version>/meta.toml)",
"Make sure you are passing the right input directory. The default input directory is _sources" "Make sure you are passing the right input directory. The default input directory is _sources"
] ]
fail "no package metadata found"
for metaFiles $ \metaFile -> do forP metaFiles $ preparePackageVersion inputDir
let [pkgName, pkgVersion, _] = splitDirectories metaFile
let Just name = simpleParsec pkgName
let Just version = simpleParsec pkgVersion
let pkgId = PackageIdentifier name version
pkgSpec <-
readPackageVersionSpec' (inputDir </> metaFile) >>= \case
PackageVersionSpec {packageVersionRevisions, packageVersionTimestamp = Nothing}
| not (null packageVersionRevisions) -> do
putError $
unlines
[ inputDir </> metaFile <> " has cabal file revisions but the original package has no timestamp.",
"This combination doesn't make sense. Either add a timestamp on the original package or remove the revisions"
]
fail "invalid package metadata"
PackageVersionSpec {packageVersionRevisions, packageVersionTimestamp = Just pkgTs}
| any ((< pkgTs) . revisionTimestamp) packageVersionRevisions -> do
putError $
unlines
[ inputDir </> metaFile <> " has a revision with timestamp earlier than the package itself.",
"Adjust the timestamps so that all revisions come after the original package"
]
fail "invalid package metadata"
meta ->
return meta
return $ PackageVersionMeta pkgId pkgSpec
prepareIndexPkgCabal :: PackageId -> UTCTime -> FilePath -> Action Tar.Entry prepareIndexPkgCabal :: PackageId -> UTCTime -> FilePath -> Action Tar.Entry
prepareIndexPkgCabal pkgId timestamp filePath = do prepareIndexPkgCabal pkgId timestamp filePath = do
need [filePath] need [filePath]
contents <- liftIO $ BSL.readFile filePath contents <- liftIO $ BS.readFile filePath
return $ mkTarEntry contents (IndexPkgCabal pkgId) timestamp pure $ mkTarEntry (BL.fromStrict contents) (IndexPkgCabal pkgId) timestamp
prepareIndexPkgMetadata :: Maybe UTCTime -> PackageVersionMeta -> Action Targets prepareIndexPkgMetadata :: Maybe UTCTime -> PreparedPackageVersion -> Action Targets
prepareIndexPkgMetadata expiryTime PackageVersionMeta {pkgId, pkgSpec} = do prepareIndexPkgMetadata expiryTime PreparedPackageVersion {pkgId, sdistPath} = do
srcDir <- prepareSource pkgId pkgSpec targetFileInfo <- liftIO $ computeFileInfoSimple sdistPath
sdist <- prepareSdist srcDir
targetFileInfo <- computeFileInfoSimple' sdist
let packagePath = repoLayoutPkgTarGz hackageRepoLayout pkgId let packagePath = repoLayoutPkgTarGz hackageRepoLayout pkgId
return return
Targets Targets
@ -287,7 +293,7 @@ prepareIndexPkgMetadata expiryTime PackageVersionMeta {pkgId, pkgSpec} = do
targetsDelegations = Nothing targetsDelegations = Nothing
} }
mkTarEntry :: BSL.ByteString -> IndexFile dec -> UTCTime -> Tar.Entry mkTarEntry :: BL.ByteString -> IndexFile dec -> UTCTime -> Tar.Entry
mkTarEntry contents indexFile timestamp = mkTarEntry contents indexFile timestamp =
(Tar.fileEntry tarPath contents) (Tar.fileEntry tarPath contents)
{ Tar.entryTime = floor $ Time.utcTimeToPOSIXSeconds timestamp, { Tar.entryTime = floor $ Time.utcTimeToPOSIXSeconds timestamp,
@ -300,8 +306,11 @@ mkTarEntry contents indexFile timestamp =
} }
} }
where where
tarPath = case Tar.toTarPath False indexPath of
Left e -> error $ "Invalid tar path " ++ indexPath ++ "(" ++ e ++ ")"
Right tp -> tp
indexPath = toFilePath $ castRoot $ indexFileToPath hackageIndexLayout indexFile indexPath = toFilePath $ castRoot $ indexFileToPath hackageIndexLayout indexFile
Right tarPath = Tar.toTarPath False indexPath
anchorPath :: Path Absolute -> (RepoLayout -> RepoPath) -> FilePath anchorPath :: Path Absolute -> (RepoLayout -> RepoPath) -> FilePath
anchorPath outputDirRoot p = anchorPath outputDirRoot p =

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
module Foliage.CmdImportIndex module Foliage.CmdImportIndex
( cmdImportIndex, ( cmdImportIndex,
) )
@ -48,31 +50,31 @@ importIndex f (Tar.Next e es) m =
case isCabalFile e of case isCabalFile e of
Just (pkgId, contents, time) Just (pkgId, contents, time)
| f pkgId -> | f pkgId ->
do do
putStrLn $ "Found cabal file " ++ prettyShow pkgId ++ " with timestamp " ++ show time putStrLn $ "Found cabal file " ++ prettyShow pkgId ++ " with timestamp " ++ show time
let -- new package let -- new package
go Nothing = go Nothing =
pure $ pure $
Just $ Just $
PackageVersionSpec PackageVersionSpec
{ packageVersionSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing, { packageVersionSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing,
packageVersionTimestamp = Just time, packageVersionTimestamp = Just time,
packageVersionRevisions = [], packageVersionRevisions = [],
packageVersionForce = False packageVersionForce = False
} }
-- Existing package, new revision -- Existing package, new revision
go (Just sm) = do go (Just sm) = do
let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm) let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm)
newRevision = RevisionSpec {revisionNumber = revnum, revisionTimestamp = time} newRevision = RevisionSpec {revisionNumber = revnum, revisionTimestamp = time}
-- Repeatedly adding at the end of a list is bad performance but good for the moment. -- Repeatedly adding at the end of a list is bad performance but good for the moment.
let sm' = sm {packageVersionRevisions = packageVersionRevisions sm ++ [newRevision]} let sm' = sm {packageVersionRevisions = packageVersionRevisions sm ++ [newRevision]}
let PackageIdentifier pkgName pkgVersion = pkgId let PackageIdentifier pkgName pkgVersion = pkgId
let outDir = "_sources" </> unPackageName pkgName </> prettyShow pkgVersion </> "revisions" let outDir = "_sources" </> unPackageName pkgName </> prettyShow pkgVersion </> "revisions"
createDirectoryIfMissing True outDir createDirectoryIfMissing True outDir
BSL.writeFile (outDir </> show revnum <.> "cabal") contents BSL.writeFile (outDir </> show revnum <.> "cabal") contents
return $ Just sm' return $ Just sm'
m' <- M.alterF go pkgId m m' <- M.alterF go pkgId m
importIndex f es m' importIndex f es m'
_ -> importIndex f es m _ -> importIndex f es m
importIndex _f Tar.Done m = importIndex _f Tar.Done m =
return m return m
@ -106,9 +108,9 @@ isCabalFile
Tar.entryTime = posixSecondsToUTCTime . fromIntegral -> time Tar.entryTime = posixSecondsToUTCTime . fromIntegral -> time
} }
| ".cabal" `isSuffixOf` path = | ".cabal" `isSuffixOf` path =
let [pkgName, pkgVersion, _] = splitDirectories path let [pkgName, pkgVersion, _] = splitDirectories path
Just name = simpleParsec pkgName Just name = simpleParsec pkgName
Just version = simpleParsec pkgVersion Just version = simpleParsec pkgVersion
packageId = PackageIdentifier name version packageId = PackageIdentifier name version
in Just (packageId, contents, time) in Just (packageId, contents, time)
isCabalFile _ = Nothing isCabalFile _ = Nothing

View File

@ -13,7 +13,6 @@ module Foliage.Meta
packageMetaEntryTimestamp, packageMetaEntryTimestamp,
readPackageMeta, readPackageMeta,
writePackageMeta, writePackageMeta,
PackageVersionMeta (PackageVersionMeta, pkgId, pkgSpec),
packageVersionTimestamp, packageVersionTimestamp,
packageVersionSource, packageVersionSource,
packageVersionRevisions, packageVersionRevisions,
@ -32,8 +31,6 @@ module Foliage.Meta
UTCTime, UTCTime,
latestRevisionNumber, latestRevisionNumber,
consolidateRanges, consolidateRanges,
cabalFileRevisionPath,
revisedCabalFile,
) )
where where
@ -50,8 +47,6 @@ import Distribution.Aeson ()
import Distribution.Parsec (simpleParsec) import Distribution.Parsec (simpleParsec)
import Distribution.Pretty (prettyShow) import Distribution.Pretty (prettyShow)
import Distribution.Types.Orphans () import Distribution.Types.Orphans ()
import Distribution.Types.PackageId (PackageIdentifier (..))
import Distribution.Types.PackageName (unPackageName)
import Distribution.Types.Version (Version) import Distribution.Types.Version (Version)
import Distribution.Types.VersionRange (VersionRange, anyVersion, intersectVersionRanges, notThisVersion) import Distribution.Types.VersionRange (VersionRange, anyVersion, intersectVersionRanges, notThisVersion)
import Distribution.Version (isAnyVersion, isNoVersion, simplifyVersionRange) import Distribution.Version (isAnyVersion, isNoVersion, simplifyVersionRange)
@ -59,7 +54,6 @@ import Foliage.Time (UTCTime)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Network.URI (URI, parseURI) import Network.URI (URI, parseURI)
import Network.URI.Orphans () import Network.URI.Orphans ()
import System.FilePath ((<.>), (</>))
import Toml (TomlCodec, (.=)) import Toml (TomlCodec, (.=))
import Toml qualified import Toml qualified
@ -86,14 +80,18 @@ writePackageMeta fp a = void $ Toml.encodeToFile packageMetaCodec fp a
packageMetaCodec :: TomlCodec PackageMeta packageMetaCodec :: TomlCodec PackageMeta
packageMetaCodec = packageMetaCodec =
PackageMeta PackageMeta
<$> Toml.list packageMetaEntryCodec "entries" .= packageMetaEntries <$> Toml.list packageMetaEntryCodec "entries"
.= packageMetaEntries
packageMetaEntryCodec :: TomlCodec PackageMetaEntry packageMetaEntryCodec :: TomlCodec PackageMetaEntry
packageMetaEntryCodec = packageMetaEntryCodec =
PackageMetaEntry PackageMetaEntry
<$> timeCodec "timestamp" .= packageMetaEntryTimestamp <$> timeCodec "timestamp"
<*> Toml.arrayOf _VersionRange "preferred-versions" .= packageMetaEntryPreferred .= packageMetaEntryTimestamp
<*> Toml.arrayOf _Version "deprecated-versions" .= packageMetaEntryDeprecated <*> Toml.arrayOf _VersionRange "preferred-versions"
.= packageMetaEntryPreferred
<*> Toml.arrayOf _Version "deprecated-versions"
.= packageMetaEntryDeprecated
_Version :: Toml.TomlBiMap Version Toml.AnyValue _Version :: Toml.TomlBiMap Version Toml.AnyValue
_Version = Toml._TextBy showVersion parseVersion _Version = Toml._TextBy showVersion parseVersion
@ -185,10 +183,14 @@ data PackageVersionSpec = PackageVersionSpec
sourceMetaCodec :: TomlCodec PackageVersionSpec sourceMetaCodec :: TomlCodec PackageVersionSpec
sourceMetaCodec = sourceMetaCodec =
PackageVersionSpec PackageVersionSpec
<$> Toml.dioptional (timeCodec "timestamp") .= packageVersionTimestamp <$> Toml.dioptional (timeCodec "timestamp")
<*> packageSourceCodec .= packageVersionSource .= packageVersionTimestamp
<*> Toml.list revisionMetaCodec "revisions" .= packageVersionRevisions <*> packageSourceCodec
<*> withDefault False (Toml.bool "force-version") .= packageVersionForce .= packageVersionSource
<*> Toml.list revisionMetaCodec "revisions"
.= packageVersionRevisions
<*> withDefault False (Toml.bool "force-version")
.= packageVersionForce
readPackageVersionSpec :: FilePath -> IO PackageVersionSpec readPackageVersionSpec :: FilePath -> IO PackageVersionSpec
readPackageVersionSpec = Toml.decodeFile sourceMetaCodec readPackageVersionSpec = Toml.decodeFile sourceMetaCodec
@ -206,8 +208,10 @@ data RevisionSpec = RevisionSpec
revisionMetaCodec :: TomlCodec RevisionSpec revisionMetaCodec :: TomlCodec RevisionSpec
revisionMetaCodec = revisionMetaCodec =
RevisionSpec RevisionSpec
<$> timeCodec "timestamp" .= revisionTimestamp <$> timeCodec "timestamp"
<*> Toml.int "number" .= revisionNumber .= revisionTimestamp
<*> Toml.int "number"
.= revisionNumber
timeCodec :: Toml.Key -> TomlCodec UTCTime timeCodec :: Toml.Key -> TomlCodec UTCTime
timeCodec key = Toml.dimap (utcToZonedTime utc) zonedTimeToUTC $ Toml.zonedTime key timeCodec key = Toml.dimap (utcToZonedTime utc) zonedTimeToUTC $ Toml.zonedTime key
@ -231,18 +235,3 @@ consolidateRanges PackageMetaEntry {packageMetaEntryPreferred, packageMetaEntryD
range = range =
simplifyVersionRange $ simplifyVersionRange $
foldr intersectVersionRanges anyVersion (map notThisVersion packageMetaEntryDeprecated ++ packageMetaEntryPreferred) foldr intersectVersionRanges anyVersion (map notThisVersion packageMetaEntryDeprecated ++ packageMetaEntryPreferred)
data PackageVersionMeta = PackageVersionMeta
{ pkgId :: PackageIdentifier,
pkgSpec :: PackageVersionSpec
}
deriving (Show, Eq)
deriving (Generic)
cabalFileRevisionPath :: FilePath -> PackageIdentifier -> Int -> FilePath
cabalFileRevisionPath inputDir PackageIdentifier {pkgName, pkgVersion} revisionNumber =
inputDir </> unPackageName pkgName </> prettyShow pkgVersion </> "revisions" </> show revisionNumber <.> "cabal"
revisedCabalFile :: FilePath -> PackageVersionMeta -> Maybe FilePath
revisedCabalFile inputDir PackageVersionMeta {pkgId, pkgSpec} = do
cabalFileRevisionPath inputDir pkgId <$> latestRevisionNumber pkgSpec

View File

@ -1,13 +1,13 @@
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE InstanceSigs #-}
module Foliage.Meta.Aeson where module Foliage.Meta.Aeson where
import Distribution.Types.Orphans ()
import Data.Aeson import Data.Aeson
import Data.Text import Data.Text
import Distribution.Types.Orphans ()
import Foliage.Meta import Foliage.Meta
import Foliage.Utils.Aeson import Foliage.Utils.Aeson
import Network.URI (URI) import Network.URI (URI)
@ -20,8 +20,6 @@ deriving via MyAesonEncoding RevisionSpec instance ToJSON RevisionSpec
deriving via MyAesonEncoding PackageVersionSpec instance ToJSON PackageVersionSpec deriving via MyAesonEncoding PackageVersionSpec instance ToJSON PackageVersionSpec
deriving via MyAesonEncoding PackageVersionMeta instance ToJSON PackageVersionMeta
deriving via Text instance ToJSON GitHubRepo deriving via Text instance ToJSON GitHubRepo
deriving via Text instance ToJSON GitHubRev deriving via Text instance ToJSON GitHubRev
@ -30,8 +28,8 @@ instance ToJSON PackageVersionSource where
toJSON = toJSON =
genericToJSON genericToJSON
defaultOptions defaultOptions
{ sumEncoding = ObjectWithSingleField { sumEncoding = ObjectWithSingleField,
, omitNothingFields = True omitNothingFields = True
} }
instance ToJSON URI where instance ToJSON URI where

View File

@ -51,7 +51,9 @@ data BuildOptions = BuildOptions
buildOptsCurrentTime :: Maybe UTCTime, buildOptsCurrentTime :: Maybe UTCTime,
buildOptsExpireSignaturesOn :: Maybe UTCTime, buildOptsExpireSignaturesOn :: Maybe UTCTime,
buildOptsInputDir :: FilePath, buildOptsInputDir :: FilePath,
buildOptsOutputDir :: FilePath buildOptsOutputDir :: FilePath,
buildOptsNumThreads :: Int,
buildOptsWriteMetadata :: Bool
} }
buildCommand :: Parser Command buildCommand :: Parser Command
@ -90,6 +92,20 @@ buildCommand =
<> showDefault <> showDefault
<> value "_repo" <> value "_repo"
) )
<*> option
auto
( long "num-jobs"
<> short 'j'
<> metavar "JOBS"
<> help "Number of jobs to run in parallel, 0 is 'all available cores'"
<> showDefault
<> value 1
)
<*> switch
( long "write-metadata"
<> help "Write metadata in the output-directory"
<> showDefault
)
) )
where where
signOpts = signOpts =

View File

@ -15,10 +15,11 @@ module Foliage.Pages
where where
import Data.Aeson (KeyValue ((.=)), ToJSON, object) import Data.Aeson (KeyValue ((.=)), ToJSON, object)
import Data.Function (on) import Data.Function (on, (&))
import Data.List (groupBy, sortOn) import Data.List (sortOn)
import Data.List.NonEmpty qualified as NE
import Data.Maybe (fromMaybe, listToMaybe) import Data.Maybe (fromMaybe, listToMaybe)
import Data.Ord (Down (Down)) import Data.Ord (Down (Down), comparing)
import Data.Text.Lazy.IO.Utf8 qualified as TL import Data.Text.Lazy.IO.Utf8 qualified as TL
import Data.Time (UTCTime) import Data.Time (UTCTime)
import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds) import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds)
@ -26,9 +27,9 @@ import Development.Shake (Action, traced)
import Distribution.Aeson (jsonGenericPackageDescription) import Distribution.Aeson (jsonGenericPackageDescription)
import Distribution.Package (PackageIdentifier (pkgName, pkgVersion)) import Distribution.Package (PackageIdentifier (pkgName, pkgVersion))
import Distribution.Pretty (prettyShow) import Distribution.Pretty (prettyShow)
import Foliage.Meta (PackageVersionMeta (..), PackageVersionSource, PackageVersionSpec (PackageVersionSpec, packageVersionRevisions, packageVersionSource, packageVersionTimestamp), RevisionSpec (RevisionSpec, revisionTimestamp), revisedCabalFile) import Foliage.Meta (PackageVersionSource)
import Foliage.Meta.Aeson () import Foliage.Meta.Aeson ()
import Foliage.Shake (originalCabalFile, readGenericPackageDescription') import Foliage.PreparePackageVersion (PreparedPackageVersion (..))
import Foliage.Utils.Aeson (MyAesonEncoding (..)) import Foliage.Utils.Aeson (MyAesonEncoding (..))
import GHC.Generics (Generic) import GHC.Generics (Generic)
import System.Directory qualified as IO import System.Directory qualified as IO
@ -50,34 +51,44 @@ data AllPackagesPageEntry = AllPackagesPageEntry
allPackagesPageEntryTimestamp :: UTCTime, allPackagesPageEntryTimestamp :: UTCTime,
allPackagesPageEntryTimestampPosix :: POSIXTime, allPackagesPageEntryTimestampPosix :: POSIXTime,
allPackagesPageEntrySource :: PackageVersionSource, allPackagesPageEntrySource :: PackageVersionSource,
allPackagesPageEntryRevision :: Maybe RevisionSpec allPackagesPageEntryLatestRevisionTimestamp :: Maybe UTCTime
} }
deriving stock (Generic) deriving stock (Generic)
deriving (ToJSON) via MyAesonEncoding AllPackagesPageEntry deriving (ToJSON) via MyAesonEncoding AllPackagesPageEntry
makeAllPackagesPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action () makeAllPackagesPage :: UTCTime -> FilePath -> [PreparedPackageVersion] -> Action ()
makeAllPackagesPage currentTime outputDir packageVersions = do makeAllPackagesPage currentTime outputDir packageVersions =
let packages =
sortOn allPackagesPageEntryPkgId $
map
( ( \PackageVersionMeta {pkgId, pkgSpec = PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions, packageVersionSource}} ->
AllPackagesPageEntry
{ allPackagesPageEntryPkgId = pkgId,
allPackagesPageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
allPackagesPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
allPackagesPageEntrySource = packageVersionSource,
allPackagesPageEntryRevision = listToMaybe packageVersionRevisions
}
)
. head
. sortOn (Down . pkgVersion . pkgId)
)
$ groupBy ((==) `on` (pkgName . pkgId)) packageVersions
traced "webpages / all-packages" $ do traced "webpages / all-packages" $ do
IO.createDirectoryIfMissing True (outputDir </> "all-packages") IO.createDirectoryIfMissing True (outputDir </> "all-packages")
TL.writeFile (outputDir </> "all-packages" </> "index.html") $ TL.writeFile (outputDir </> "all-packages" </> "index.html") $
renderMustache allPackagesPageTemplate $ renderMustache allPackagesPageTemplate $
object ["packages" .= packages] object ["packages" .= packages]
where
packages =
packageVersions
-- group package versions by package name
& NE.groupBy ((==) `on` (pkgName . pkgId))
-- for each package name pick the most recent version
& map
( \group ->
group
-- sort them from the most recent version to the least recent
& NE.sortBy (comparing $ Down . pkgVersion . pkgId)
-- pick the most recent version
& NE.head
-- turn it into the template data
& ( \(PreparedPackageVersion {pkgId, pkgTimestamp, cabalFileRevisions, pkgVersionSource}) ->
AllPackagesPageEntry
{ allPackagesPageEntryPkgId = pkgId,
allPackagesPageEntryTimestamp = fromMaybe currentTime pkgTimestamp,
allPackagesPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime pkgTimestamp),
allPackagesPageEntrySource = pkgVersionSource,
allPackagesPageEntryLatestRevisionTimestamp = fst <$> listToMaybe cabalFileRevisions
}
)
)
-- sort packages by pkgId
& sortOn allPackagesPageEntryPkgId
data AllPackageVersionsPageEntry data AllPackageVersionsPageEntry
= AllPackageVersionsPageEntryPackage = AllPackageVersionsPageEntryPackage
@ -94,47 +105,49 @@ data AllPackageVersionsPageEntry
deriving stock (Generic) deriving stock (Generic)
deriving (ToJSON) via MyAesonEncoding AllPackageVersionsPageEntry deriving (ToJSON) via MyAesonEncoding AllPackageVersionsPageEntry
makeAllPackageVersionsPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action () makeAllPackageVersionsPage :: UTCTime -> FilePath -> [PreparedPackageVersion] -> Action ()
makeAllPackageVersionsPage currentTime outputDir packageVersions = do makeAllPackageVersionsPage currentTime outputDir packageVersions =
let entries =
sortOn (Down . allPackageVersionsPageEntryTimestamp) $
foldMap
( \PackageVersionMeta {pkgId, pkgSpec = PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions, packageVersionSource}} ->
AllPackageVersionsPageEntryPackage
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = fromMaybe currentTime packageVersionTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime packageVersionTimestamp),
allPackageVersionsPageEntrySource = packageVersionSource
} :
map
( \RevisionSpec {revisionTimestamp} ->
AllPackageVersionsPageEntryRevision
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = revisionTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds revisionTimestamp
}
)
packageVersionRevisions
)
packageVersions
traced "webpages / all-package-versions" $ do traced "webpages / all-package-versions" $ do
IO.createDirectoryIfMissing True (outputDir </> "all-package-versions") IO.createDirectoryIfMissing True (outputDir </> "all-package-versions")
TL.writeFile (outputDir </> "all-package-versions" </> "index.html") $ TL.writeFile (outputDir </> "all-package-versions" </> "index.html") $
renderMustache allPackageVersionsPageTemplate $ renderMustache allPackageVersionsPageTemplate $
object ["entries" .= entries] object ["entries" .= entries]
where
entries =
-- collect all cabal file revisions including the original cabal file
foldMap
( \PreparedPackageVersion {pkgId, pkgTimestamp, pkgVersionSource, cabalFileRevisions} ->
-- original cabal file
AllPackageVersionsPageEntryPackage
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = fromMaybe currentTime pkgTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds (fromMaybe currentTime pkgTimestamp),
allPackageVersionsPageEntrySource = pkgVersionSource
}
-- list of revisions
: [ AllPackageVersionsPageEntryRevision
{ allPackageVersionsPageEntryPkgId = pkgId,
allPackageVersionsPageEntryTimestamp = revisionTimestamp,
allPackageVersionsPageEntryTimestampPosix = utcTimeToPOSIXSeconds revisionTimestamp
}
| (revisionTimestamp, _) <- cabalFileRevisions
]
)
packageVersions
-- sort them by timestamp
& sortOn (Down . allPackageVersionsPageEntryTimestamp)
makePackageVersionPage :: FilePath -> FilePath -> PackageVersionMeta -> Action () makePackageVersionPage :: FilePath -> PreparedPackageVersion -> Action ()
makePackageVersionPage inputDir outputDir pkgMeta@PackageVersionMeta {pkgId, pkgSpec} = do makePackageVersionPage outputDir PreparedPackageVersion {pkgId, pkgTimestamp, pkgVersionSource, pkgDesc, cabalFileRevisions} = do
cabalFilePath <- maybe (originalCabalFile pkgMeta) pure (revisedCabalFile inputDir pkgMeta)
pkgDesc <- readGenericPackageDescription' cabalFilePath
traced ("webpages / package / " ++ prettyShow pkgId) $ do traced ("webpages / package / " ++ prettyShow pkgId) $ do
IO.createDirectoryIfMissing True (outputDir </> "package" </> prettyShow pkgId) IO.createDirectoryIfMissing True (outputDir </> "package" </> prettyShow pkgId)
TL.writeFile (outputDir </> "package" </> prettyShow pkgId </> "index.html") $ TL.writeFile (outputDir </> "package" </> prettyShow pkgId </> "index.html") $
renderMustache packageVersionPageTemplate $ renderMustache packageVersionPageTemplate $
object object
[ "pkgSpec" .= pkgSpec, [ "pkgVersionSource" .= pkgVersionSource,
"pkgDesc" .= jsonGenericPackageDescription pkgDesc "cabalFileRevisions" .= map fst cabalFileRevisions,
"pkgDesc" .= jsonGenericPackageDescription pkgDesc,
"pkgTimestamp" .= pkgTimestamp
] ]
indexPageTemplate :: Template indexPageTemplate :: Template

View File

@ -0,0 +1,132 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
module Foliage.PreparePackageVersion
( PreparedPackageVersion
( pkgId,
pkgTimestamp,
pkgVersionSource,
pkgVersionForce,
pkgDesc,
sdistPath,
cabalFilePath,
originalCabalFilePath,
cabalFileRevisions
),
pattern PreparedPackageVersion,
preparePackageVersion,
)
where
import Control.Monad (unless)
import Data.List (sortOn)
import Data.Ord (Down (Down))
import Development.Shake (Action)
import Development.Shake.FilePath (joinPath, splitDirectories)
import Distribution.Client.Compat.Prelude (fromMaybe, prettyShow)
import Distribution.Parsec (simpleParsec)
import Distribution.Types.GenericPackageDescription (GenericPackageDescription (packageDescription))
import Distribution.Types.PackageDescription (PackageDescription (package))
import Distribution.Types.PackageId
import Foliage.Meta (PackageVersionSource, PackageVersionSpec (..), RevisionSpec (..), UTCTime, latestRevisionNumber)
import Foliage.PrepareSdist (prepareSdist)
import Foliage.PrepareSource (prepareSource)
import Foliage.Shake (readGenericPackageDescription', readPackageVersionSpec')
import System.FilePath (takeBaseName, takeFileName, (<.>), (</>))
data PreparedPackageVersion = PreparedPackageVersion
{ pkgId :: PackageId,
pkgTimestamp :: Maybe UTCTime,
pkgVersionSource :: PackageVersionSource,
pkgVersionForce :: Bool,
pkgDesc :: GenericPackageDescription,
sdistPath :: FilePath,
cabalFilePath :: FilePath,
originalCabalFilePath :: FilePath,
cabalFileRevisions :: [(UTCTime, FilePath)]
}
preparePackageVersion :: FilePath -> FilePath -> Action PreparedPackageVersion
preparePackageVersion inputDir metaFile = do
let (name, version) = case splitDirectories metaFile of
[n, v, _] -> (n, v)
_else -> error $ "internal error: I should not be looking at " ++ metaFile
let pkgName = fromMaybe (error $ "invalid package name: " ++ name) $ simpleParsec name
let pkgVersion = fromMaybe (error $ "invalid package version: " ++ version) $ simpleParsec version
let pkgId = PackageIdentifier pkgName pkgVersion
pkgSpec <-
readPackageVersionSpec' (inputDir </> metaFile) >>= \case
PackageVersionSpec {packageVersionRevisions, packageVersionTimestamp = Nothing}
| not (null packageVersionRevisions) -> do
error $
unlines
[ inputDir </> metaFile <> " has cabal file revisions but the original package has no timestamp.",
"This combination doesn't make sense. Either add a timestamp on the original package or remove the revisions"
]
PackageVersionSpec {packageVersionRevisions, packageVersionTimestamp = Just pkgTs}
| any ((< pkgTs) . revisionTimestamp) packageVersionRevisions -> do
error $
unlines
[ inputDir </> metaFile <> " has a revision with timestamp earlier than the package itself.",
"Adjust the timestamps so that all revisions come after the original package"
]
meta ->
return meta
srcDir <- prepareSource pkgId pkgSpec
let originalCabalFilePath = srcDir </> prettyShow pkgName <.> "cabal"
cabalFileRevisionPath revisionNumber =
joinPath
[ inputDir,
prettyShow pkgName,
prettyShow pkgVersion,
"revisions",
show revisionNumber
]
<.> "cabal"
let cabalFilePath =
maybe
originalCabalFilePath
cabalFileRevisionPath
(latestRevisionNumber pkgSpec)
pkgDesc <- readGenericPackageDescription' cabalFilePath
sdistPath <- prepareSdist srcDir
let expectedSdistName = prettyShow pkgId <.> "tar.gz"
unless (takeFileName sdistPath == expectedSdistName) $ do
error $
unlines
[ "creating a source distribution for " ++ prettyShow pkgId ++ " has failed because",
"cabal has produced a source distribtion that does not match the expected file name:",
"actual: " ++ takeBaseName sdistPath,
"expected: " ++ expectedSdistName,
"possible cause: the package name and/or version implied by the metadata file path does not match what is contained in the cabal file",
"metadata file: " ++ metaFile,
"version in cabal file: " ++ prettyShow (Distribution.Types.PackageId.pkgVersion $ package $ packageDescription pkgDesc)
]
let cabalFileRevisions =
sortOn
(Down . fst)
[ (revisionTimestamp, cabalFileRevisionPath revisionNumber)
| RevisionSpec {revisionTimestamp, revisionNumber} <- packageVersionRevisions pkgSpec
]
return
PreparedPackageVersion
{ pkgId,
pkgTimestamp = packageVersionTimestamp pkgSpec,
pkgVersionSource = packageVersionSource pkgSpec,
pkgVersionForce = packageVersionForce pkgSpec,
pkgDesc,
sdistPath,
cabalFilePath,
originalCabalFilePath,
cabalFileRevisions
}

View File

@ -1,7 +1,6 @@
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
module Foliage.PrepareSdist module Foliage.PrepareSdist
@ -53,7 +52,7 @@ addPrepareSdistRule outputDirRoot = addBuiltinRule noLint noIdentity run
case ehvExisting of case ehvExisting of
Right hvExisting Right hvExisting
| hvExisting == hvExpected -> | hvExisting == hvExpected ->
return RunResult {runChanged = ChangedNothing, runStore = old, runValue = path} return RunResult {runChanged = ChangedNothing, runStore = old, runValue = path}
Right hvExisting -> do Right hvExisting -> do
putWarn $ "Changed " ++ path ++ " (expecting hash " ++ showHashValue hvExpected ++ " found " ++ showHashValue hvExisting ++ "). I will rebuild it." putWarn $ "Changed " ++ path ++ " (expecting hash " ++ showHashValue hvExpected ++ " found " ++ showHashValue hvExisting ++ "). I will rebuild it."
run (PrepareSdistRule srcDir) (Just old) RunDependenciesChanged run (PrepareSdistRule srcDir) (Just old) RunDependenciesChanged
@ -71,18 +70,24 @@ addPrepareSdistRule outputDirRoot = addBuiltinRule noLint noIdentity run
_differentOrMissing -> ChangedRecomputeDiff _differentOrMissing -> ChangedRecomputeDiff
when (changed == ChangedRecomputeSame) $ when (changed == ChangedRecomputeSame) $
putInfo $ "Wrote " ++ path ++ " (same hash " ++ showHashValue hv ++ ")" putInfo ("Wrote " ++ path ++ " (same hash " ++ showHashValue hv ++ ")")
when (changed == ChangedRecomputeDiff) $ when (changed == ChangedRecomputeDiff) $
putInfo $ "Wrote " ++ path ++ " (new hash " ++ showHashValue hv ++ ")" putInfo ("Wrote " ++ path ++ " (new hash " ++ showHashValue hv ++ ")")
return $ RunResult {runChanged = changed, runStore = new, runValue = path} return $ RunResult {runChanged = changed, runStore = new, runValue = path}
makeSdist srcDir = do makeSdist srcDir = do
cabalFile <- do cabalFiles <- getDirectoryFiles srcDir ["*.cabal"]
getDirectoryFiles srcDir ["*.cabal"] >>= \case let cabalFile = case cabalFiles of
[f] -> pure f [f] -> f
fs -> fail $ "Invalid srcDir: " ++ srcDir ++ ". It contains multiple cabal files: " ++ unwords fs fs ->
error $
unlines
[ "Invalid source directory: " ++ srcDir,
"It contains multiple cabal files, while only one is allowed",
unwords fs
]
traced "cabal sdist" $ do traced "cabal sdist" $ do
gpd <- readGenericPackageDescription Verbosity.normal (srcDir </> cabalFile) gpd <- readGenericPackageDescription Verbosity.normal (srcDir </> cabalFile)

View File

@ -8,7 +8,6 @@ module Foliage.PrepareSource where
import Control.Monad (when) import Control.Monad (when)
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
import Data.Foldable (for_) import Data.Foldable (for_)
import Data.Text qualified as T
import Development.Shake import Development.Shake
import Development.Shake.Classes import Development.Shake.Classes
import Development.Shake.Rule import Development.Shake.Rule
@ -18,8 +17,8 @@ import Distribution.Types.PackageName (unPackageName)
import Foliage.Meta import Foliage.Meta
import Foliage.RemoteAsset (fetchRemoteAsset) import Foliage.RemoteAsset (fetchRemoteAsset)
import Foliage.UpdateCabalFile (rewritePackageVersion) import Foliage.UpdateCabalFile (rewritePackageVersion)
import Foliage.Utils.GitHub (githubRepoTarballUrl)
import GHC.Generics import GHC.Generics
import Network.URI (URI (..), URIAuth (..), nullURI, nullURIAuth)
import System.Directory qualified as IO import System.Directory qualified as IO
import System.FilePath ((<.>), (</>)) import System.FilePath ((<.>), (</>))
@ -79,12 +78,7 @@ addPrepareSourceRule inputDir cacheDir = addBuiltinRule noLint noIdentity run
-- metadata. -- metadata.
-- --
GitHubSource repo rev mSubdir -> do GitHubSource repo rev mSubdir -> do
let url = let url = githubRepoTarballUrl repo rev
nullURI
{ uriScheme = "https:",
uriAuthority = Just nullURIAuth {uriRegName = "github.com"},
uriPath = "/" </> T.unpack (unGitHubRepo repo) </> "tarball" </> T.unpack (unGitHubRev rev)
}
tarballPath <- fetchRemoteAsset url tarballPath <- fetchRemoteAsset url

View File

@ -35,14 +35,16 @@ addFetchRemoteAssetRule cacheDir = addBuiltinRule noLint noIdentity run
run :: BuiltinRun RemoteAsset FilePath run :: BuiltinRun RemoteAsset FilePath
run (RemoteAsset uri) old _mode = do run (RemoteAsset uri) old _mode = do
unless (uriQuery uri == "") $ unless (uriQuery uri == "") $
fail $ "Query elements in URI are not supported: " <> show uri error ("Query elements in URI are not supported: " <> show uri)
unless (uriFragment uri == "") $ unless (uriFragment uri == "") $
fail $ "Fragments in URI are not supported: " <> show uri error ("Fragments in URI are not supported: " <> show uri)
let scheme = dropWhileEnd (not . isAlpha) $ uriScheme uri let scheme = dropWhileEnd (not . isAlpha) $ uriScheme uri
Just host = uriRegName <$> uriAuthority uri
path = cacheDir </> joinPath (scheme : host : pathSegments uri) let host = maybe (error $ "invalid uri " ++ show uri) uriRegName (uriAuthority uri)
let path = cacheDir </> joinPath (scheme : host : pathSegments uri)
-- parse etag from store -- parse etag from store
let oldETag = fromMaybe BS.empty old let oldETag = fromMaybe BS.empty old

View File

@ -3,7 +3,6 @@ module Foliage.Shake
readKeysAt, readKeysAt,
readPackageVersionSpec', readPackageVersionSpec',
readGenericPackageDescription', readGenericPackageDescription',
originalCabalFile,
) )
where where
@ -12,12 +11,9 @@ import Development.Shake
import Development.Shake.FilePath import Development.Shake.FilePath
import Distribution.Simple.PackageDescription import Distribution.Simple.PackageDescription
import Distribution.Types.GenericPackageDescription import Distribution.Types.GenericPackageDescription
import Distribution.Types.PackageId
import Distribution.Types.PackageName
import Distribution.Verbosity qualified as Verbosity import Distribution.Verbosity qualified as Verbosity
import Foliage.HackageSecurity import Foliage.HackageSecurity
import Foliage.Meta import Foliage.Meta
import Foliage.PrepareSource
computeFileInfoSimple' :: FilePath -> Action FileInfo computeFileInfoSimple' :: FilePath -> Action FileInfo
computeFileInfoSimple' fp = do computeFileInfoSimple' fp = do
@ -41,8 +37,3 @@ readGenericPackageDescription' :: FilePath -> Action GenericPackageDescription
readGenericPackageDescription' fp = do readGenericPackageDescription' fp = do
need [fp] need [fp]
liftIO $ readGenericPackageDescription Verbosity.silent fp liftIO $ readGenericPackageDescription Verbosity.silent fp
originalCabalFile :: PackageVersionMeta -> Action FilePath
originalCabalFile PackageVersionMeta {pkgId, pkgSpec} = do
srcDir <- prepareSource pkgId pkgSpec
return $ srcDir </> unPackageName (pkgName pkgId) <.> "cabal"

View File

@ -2,22 +2,23 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
module Foliage.Utils.Aeson where module Foliage.Utils.Aeson where
import Data.Aeson import Data.Aeson
import GHC.Generics
import Data.Coerce import Data.Coerce
import GHC.Generics
newtype MyAesonEncoding a = MyAesonEncoding a newtype MyAesonEncoding a = MyAesonEncoding a
deriving Generic deriving (Generic)
myOptions :: Options myOptions :: Options
myOptions = myOptions =
defaultOptions defaultOptions
{ sumEncoding = ObjectWithSingleField { sumEncoding = ObjectWithSingleField,
, omitNothingFields = True omitNothingFields = True
} }
instance (Generic a, GToJSON' Value Zero (Rep a), GToJSON' Encoding Zero (Rep a)) => ToJSON (MyAesonEncoding a) where instance (Generic a, GToJSON' Value Zero (Rep a), GToJSON' Encoding Zero (Rep a)) => ToJSON (MyAesonEncoding a) where
toJSON = coerce (genericToJSON myOptions :: a -> Value) toJSON = coerce (genericToJSON myOptions :: a -> Value)
toEncoding = coerce (genericToEncoding myOptions :: a -> Encoding) toEncoding = coerce (genericToEncoding myOptions :: a -> Encoding)

View File

@ -0,0 +1,17 @@
module Foliage.Utils.GitHub
( githubRepoTarballUrl,
)
where
import Data.Text qualified as T
import Foliage.Meta (GitHubRepo (unGitHubRepo), GitHubRev (unGitHubRev))
import Network.URI (URI (..), URIAuth (..), nullURI, nullURIAuth)
import System.FilePath ((</>))
githubRepoTarballUrl :: GitHubRepo -> GitHubRev -> URI
githubRepoTarballUrl repo rev =
nullURI
{ uriScheme = "https:",
uriAuthority = Just nullURIAuth {uriRegName = "github.com"},
uriPath = "/" </> T.unpack (unGitHubRepo repo) </> "tarball" </> T.unpack (unGitHubRev rev)
}

View File

@ -1,3 +1,5 @@
{-# LANGUAGE LambdaCase #-}
module Main where module Main where
import Foliage.CmdBuild import Foliage.CmdBuild

View File

@ -1,3 +1,6 @@
packages: . packages: .
index-state: 2022-08-29T00:00:00Z index-state: 2023-03-01T00:00:00Z
with-compiler: ghc-8.10.7 with-compiler: ghc-9.2.6
allow-newer:
, tomland:base
, tomland:text

View File

@ -16,6 +16,21 @@
"type": "github" "type": "github"
} }
}, },
"blank": {
"locked": {
"lastModified": 1625557891,
"narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=",
"owner": "divnix",
"repo": "blank",
"rev": "5a5d2684073d9f563072ed07c871d577a6c614a8",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "blank",
"type": "github"
}
},
"cabal-32": { "cabal-32": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -36,11 +51,11 @@
"cabal-34": { "cabal-34": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1640353650, "lastModified": 1645834128,
"narHash": "sha256-N1t6M3/wqj90AEdRkeC8i923gQYUpzSr8b40qVOZ1Rk=", "narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=",
"owner": "haskell", "owner": "haskell",
"repo": "cabal", "repo": "cabal",
"rev": "942639c18c0cd8ec53e0a6f8d120091af35312cd", "rev": "5ff598c67f53f7c4f48e31d722ba37172230c462",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -53,11 +68,11 @@
"cabal-36": { "cabal-36": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1641652457, "lastModified": 1669081697,
"narHash": "sha256-BlFPKP4C4HRUJeAbdembX1Rms1LD380q9s0qVDeoAak=", "narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=",
"owner": "haskell", "owner": "haskell",
"repo": "cabal", "repo": "cabal",
"rev": "f27667f8ec360c475027dcaee0138c937477b070", "rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -83,13 +98,104 @@
"type": "github" "type": "github"
} }
}, },
"devshell": {
"inputs": {
"flake-utils": [
"haskell-nix",
"tullia",
"std",
"flake-utils"
],
"nixpkgs": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1663445644,
"narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=",
"owner": "numtide",
"repo": "devshell",
"rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"dmerge": {
"inputs": {
"nixlib": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
],
"yants": [
"haskell-nix",
"tullia",
"std",
"yants"
]
},
"locked": {
"lastModified": 1659548052,
"narHash": "sha256-fzI2gp1skGA8mQo/FBFrUAtY0GQkAIAaV/V127TJPyY=",
"owner": "divnix",
"repo": "data-merge",
"rev": "d160d18ce7b1a45b88344aa3f13ed1163954b497",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "data-merge",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1672831974,
"narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=",
"owner": "input-output-hk",
"repo": "flake-compat",
"rev": "45f2638735f8cdc40fe302742b79f248d23eb368",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"ref": "hkm/gitlab-fix",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1650374568,
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1667395993,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -100,11 +206,26 @@
}, },
"flake-utils_2": { "flake-utils_2": {
"locked": { "locked": {
"lastModified": 1644229661, "lastModified": 1653893745,
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -130,14 +251,33 @@
"type": "github" "type": "github"
} }
}, },
"gomod2nix": {
"inputs": {
"nixpkgs": "nixpkgs_2",
"utils": "utils"
},
"locked": {
"lastModified": 1655245309,
"narHash": "sha256-d/YPoQ/vFn1+GTmSdvbSBSTOai61FONxB4+Lt6w/IVI=",
"owner": "tweag",
"repo": "gomod2nix",
"rev": "40d32f82fc60d66402eb0972e6e368aeab3faf58",
"type": "github"
},
"original": {
"owner": "tweag",
"repo": "gomod2nix",
"type": "github"
}
},
"hackage": { "hackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1661735830, "lastModified": 1677809131,
"narHash": "sha256-xJpfFmpzJVci+fM9mjTKyIbkUpJf5XkZMygY+YRKzwU=", "narHash": "sha256-MQ+ybbu5VFA6ERvh8mXcYEVlBCTte4BDxRaILSwBdAk=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "hackage.nix", "repo": "hackage.nix",
"rev": "9b22f61f50b19bf401ab104ff0e239f8ada87547", "rev": "4ea4b12737ea42e47eb5c6a7e4a3eafe9da2fc52",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -153,12 +293,13 @@
"cabal-34": "cabal-34", "cabal-34": "cabal-34",
"cabal-36": "cabal-36", "cabal-36": "cabal-36",
"cardano-shell": "cardano-shell", "cardano-shell": "cardano-shell",
"flake-utils": "flake-utils_2", "flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"ghc-8.6.5-iohk": "ghc-8.6.5-iohk", "ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
"hackage": "hackage", "hackage": "hackage",
"hpc-coveralls": "hpc-coveralls", "hpc-coveralls": "hpc-coveralls",
"hydra": "hydra", "hydra": "hydra",
"nix-tools": "nix-tools", "iserv-proxy": "iserv-proxy",
"nixpkgs": [ "nixpkgs": [
"haskell-nix", "haskell-nix",
"nixpkgs-unstable" "nixpkgs-unstable"
@ -167,16 +308,18 @@
"nixpkgs-2105": "nixpkgs-2105", "nixpkgs-2105": "nixpkgs-2105",
"nixpkgs-2111": "nixpkgs-2111", "nixpkgs-2111": "nixpkgs-2111",
"nixpkgs-2205": "nixpkgs-2205", "nixpkgs-2205": "nixpkgs-2205",
"nixpkgs-2211": "nixpkgs-2211",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix", "old-ghc-nix": "old-ghc-nix",
"stackage": "stackage" "stackage": "stackage",
"tullia": "tullia"
}, },
"locked": { "locked": {
"lastModified": 1661940924, "lastModified": 1677809260,
"narHash": "sha256-aXmYSdeDjSWpJPtNAtvAKabKUyOOiJXzZ7EEYYKNrYI=", "narHash": "sha256-RSiv9/LP8/+sf15B305z4DYaj7IiAVjPBkqPfByxAp4=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "haskell.nix", "repo": "haskell.nix",
"rev": "c83b33f4198fd8ba62748feb5024ece2b5329a8e", "rev": "02a5acdfc937129e51e41de0eafd0c44f29896b4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -212,11 +355,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1646878427, "lastModified": 1671755331,
"narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=", "narHash": "sha256-hXsgJj0Cy0ZiCiYdW2OdBz5WmFyOMKuw4zyxKpgUKm4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "hydra", "repo": "hydra",
"rev": "28b682b85b7efc5cf7974065792a1f22203a5927", "rev": "f48f00ee6d5727ae3e488cbf9ce157460853fea8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -224,6 +367,46 @@
"type": "indirect" "type": "indirect"
} }
}, },
"incl": {
"inputs": {
"nixlib": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1669263024,
"narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=",
"owner": "divnix",
"repo": "incl",
"rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "incl",
"type": "github"
}
},
"iserv-proxy": {
"flake": false,
"locked": {
"lastModified": 1670983692,
"narHash": "sha256-avLo34JnI9HNyOuauK5R69usJm+GfW3MlyGlYxZhTgY=",
"ref": "hkm/remote-iserv",
"rev": "50d0abb3317ac439a4e7495b185a64af9b7b9300",
"revCount": 10,
"type": "git",
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
},
"original": {
"ref": "hkm/remote-iserv",
"type": "git",
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
}
},
"lowdown-src": { "lowdown-src": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -240,6 +423,35 @@
"type": "github" "type": "github"
} }
}, },
"n2c": {
"inputs": {
"flake-utils": [
"haskell-nix",
"tullia",
"std",
"flake-utils"
],
"nixpkgs": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1665039323,
"narHash": "sha256-SAh3ZjFGsaCI8FRzXQyp56qcGdAqgKEfJWPCQ0Sr7tQ=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "b008fe329ffb59b67bf9e7b08ede6ee792f2741a",
"type": "github"
},
"original": {
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
"nix": { "nix": {
"inputs": { "inputs": {
"lowdown-src": "lowdown-src", "lowdown-src": "lowdown-src",
@ -247,49 +459,123 @@
"nixpkgs-regression": "nixpkgs-regression" "nixpkgs-regression": "nixpkgs-regression"
}, },
"locked": { "locked": {
"lastModified": 1643066034, "lastModified": 1661606874,
"narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=", "narHash": "sha256-9+rpYzI+SmxJn+EbYxjGv68Ucp22bdFUSy/4LkHkkDQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nix", "repo": "nix",
"rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62", "rev": "11e45768b34fdafdcf019ddbd337afa16127ff0f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "2.6.0", "ref": "2.11.0",
"repo": "nix", "repo": "nix",
"type": "github" "type": "github"
} }
}, },
"nix-tools": { "nix-nomad": {
"flake": false, "inputs": {
"flake-compat": "flake-compat_2",
"flake-utils": [
"haskell-nix",
"tullia",
"nix2container",
"flake-utils"
],
"gomod2nix": "gomod2nix",
"nixpkgs": [
"haskell-nix",
"tullia",
"nixpkgs"
],
"nixpkgs-lib": [
"haskell-nix",
"tullia",
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1659569011, "lastModified": 1658277770,
"narHash": "sha256-wHS0H5+TERmDnPCfzH4A+rSR5TvjYMWus9BNeNAMyUM=", "narHash": "sha256-T/PgG3wUn8Z2rnzfxf2VqlR1CBjInPE0l1yVzXxPnt0=",
"owner": "input-output-hk", "owner": "tristanpemble",
"repo": "nix-tools", "repo": "nix-nomad",
"rev": "555d57e1ea81b79945f2608aa261df20f6b602a5", "rev": "054adcbdd0a836ae1c20951b67ed549131fd2d70",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "input-output-hk", "owner": "tristanpemble",
"repo": "nix-tools", "repo": "nix-nomad",
"type": "github"
}
},
"nix2container": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1658567952,
"narHash": "sha256-XZ4ETYAMU7XcpEeAFP3NOl9yDXNuZAen/aIJ84G+VgA=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "60bb43d405991c1378baf15a40b5811a53e32ffa",
"type": "github"
},
"original": {
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
"nixago": {
"inputs": {
"flake-utils": [
"haskell-nix",
"tullia",
"std",
"flake-utils"
],
"nixago-exts": [
"haskell-nix",
"tullia",
"std",
"blank"
],
"nixpkgs": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1661824785,
"narHash": "sha256-/PnwdWoO/JugJZHtDUioQp3uRiWeXHUdgvoyNbXesz8=",
"owner": "nix-community",
"repo": "nixago",
"rev": "8c1f9e5f1578d4b2ea989f618588d62a335083c3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixago",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1632864508, "lastModified": 1657693803,
"narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=", "narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "82891b5e2c2359d7e58d08849e4c89511ab94234", "rev": "365e1b3a859281cf11b94f87231adeabbdd878a2",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "NixOS",
"ref": "nixos-21.05-small", "ref": "nixos-22.05-small",
"type": "indirect" "repo": "nixpkgs",
"type": "github"
} }
}, },
"nixpkgs-2003": { "nixpkgs-2003": {
@ -310,11 +596,11 @@
}, },
"nixpkgs-2105": { "nixpkgs-2105": {
"locked": { "locked": {
"lastModified": 1655034179, "lastModified": 1659914493,
"narHash": "sha256-rf1/7AbzuYDw6+8Xvvf3PtEOygymLBrFsFxvext5ZjI=", "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "046ee4af7a9f016a364f8f78eeaa356ba524ac31", "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -326,11 +612,11 @@
}, },
"nixpkgs-2111": { "nixpkgs-2111": {
"locked": { "locked": {
"lastModified": 1656782578, "lastModified": 1659446231,
"narHash": "sha256-1eMCBEqJplPotTo/SZ/t5HU6Sf2I8qKlZi9MX7jv9fw=", "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "573603b7fdb9feb0eb8efc16ee18a015c667ab1b", "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -342,11 +628,11 @@
}, },
"nixpkgs-2205": { "nixpkgs-2205": {
"locked": { "locked": {
"lastModified": 1657876628, "lastModified": 1672580127,
"narHash": "sha256-URmf0O2cQ/3heg2DJOeLyU/JmfVMqG4X5t9crQXMaeY=", "narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "549d82bdd40f760a438c3c3497c1c61160f3de55", "rev": "0874168639713f547c05947c76124f78441ea46c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -356,6 +642,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-2211": {
"locked": {
"lastModified": 1675730325,
"narHash": "sha256-uNvD7fzO5hNlltNQUAFBPlcEjNG5Gkbhl/ROiX+GZU4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b7ce17b1ebf600a72178f6302c77b6382d09323f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-22.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": { "nixpkgs-regression": {
"locked": { "locked": {
"lastModified": 1643052045, "lastModified": 1643052045,
@ -366,18 +668,19 @@
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "indirect" "type": "github"
} }
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1657888067, "lastModified": 1675758091,
"narHash": "sha256-GnwJoFBTPfW3+mz7QEeJEEQ9OMHZOiIJ/qDhZxrlKh8=", "narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "65fae659e31098ca4ac825a6fef26d890aaf3f4e", "rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -387,6 +690,68 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": {
"locked": {
"lastModified": 1653581809,
"narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "83658b28fe638a170a19b8933aa008b30640fbd1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1654807842,
"narHash": "sha256-ADymZpr6LuTEBXcy6RtFHcUZdjKTBRTMYwu19WOx17E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fc909087cc3386955f21b4665731dbdaceefb1d8",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1665087388,
"narHash": "sha256-FZFPuW9NWHJteATOf79rZfwfRn5fE0wi9kRzvGfDHPA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "95fda953f6db2e9496d2682c4fc7b82f959878f7",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nosys": {
"locked": {
"lastModified": 1667881534,
"narHash": "sha256-FhwJ15uPLRsvaxtt/bNuqE/ykMpNAPF0upozFKhTtXM=",
"owner": "divnix",
"repo": "nosys",
"rev": "2d0d5207f6a230e9d0f660903f8db9807b54814f",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "nosys",
"type": "github"
}
},
"old-ghc-nix": { "old-ghc-nix": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -406,7 +771,10 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": [
"haskell-nix",
"flake-utils"
],
"haskell-nix": "haskell-nix", "haskell-nix": "haskell-nix",
"nixpkgs": [ "nixpkgs": [
"haskell-nix", "haskell-nix",
@ -417,11 +785,11 @@
"stackage": { "stackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1661925696, "lastModified": 1677543037,
"narHash": "sha256-eMM1dhdSv0AlLtD2cULJsLhJF4ZWdvpqRcCOw9DbXLI=", "narHash": "sha256-7CPQZZafTQiw7YL+a2KCamb9a3PU0do9iZKy1AaRkBo=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "stackage.nix", "repo": "stackage.nix",
"rev": "575039e5410ef653e302d53938aa6df403e5a8b1", "rev": "f4d29fa4403f45541d9f3993523df6027c21fe90",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -429,6 +797,113 @@
"repo": "stackage.nix", "repo": "stackage.nix",
"type": "github" "type": "github"
} }
},
"std": {
"inputs": {
"arion": [
"haskell-nix",
"tullia",
"std",
"blank"
],
"blank": "blank",
"devshell": "devshell",
"dmerge": "dmerge",
"flake-utils": "flake-utils_3",
"incl": "incl",
"makes": [
"haskell-nix",
"tullia",
"std",
"blank"
],
"microvm": [
"haskell-nix",
"tullia",
"std",
"blank"
],
"n2c": "n2c",
"nixago": "nixago",
"nixpkgs": "nixpkgs_4",
"nosys": "nosys",
"yants": "yants"
},
"locked": {
"lastModified": 1674526466,
"narHash": "sha256-tMTaS0bqLx6VJ+K+ZT6xqsXNpzvSXJTmogkraBGzymg=",
"owner": "divnix",
"repo": "std",
"rev": "516387e3d8d059b50e742a2ff1909ed3c8f82826",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "std",
"type": "github"
}
},
"tullia": {
"inputs": {
"nix-nomad": "nix-nomad",
"nix2container": "nix2container",
"nixpkgs": [
"haskell-nix",
"nixpkgs"
],
"std": "std"
},
"locked": {
"lastModified": 1675695930,
"narHash": "sha256-B7rEZ/DBUMlK1AcJ9ajnAPPxqXY6zW2SBX+51bZV0Ac=",
"owner": "input-output-hk",
"repo": "tullia",
"rev": "621365f2c725608f381b3ad5b57afef389fd4c31",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "tullia",
"type": "github"
}
},
"utils": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"yants": {
"inputs": {
"nixpkgs": [
"haskell-nix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1667096281,
"narHash": "sha256-wRRec6ze0gJHmGn6m57/zhz/Kdvp9HS4Nl5fkQ+uIuA=",
"owner": "divnix",
"repo": "yants",
"rev": "d18f356ec25cb94dc9c275870c3a7927a10f8c3c",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "yants",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@ -1,50 +1,52 @@
{ {
description = "Foliage is a tool to create custom Haskell package repositories, in a fully reproducible way."; description =
"Foliage is a tool to create custom Haskell package repositories, in a fully reproducible way.";
inputs = { inputs = {
nixpkgs.follows = "haskell-nix/nixpkgs-unstable"; nixpkgs.follows = "haskell-nix/nixpkgs-unstable";
haskell-nix.url = "github:input-output-hk/haskell.nix"; haskell-nix.url = "github:input-output-hk/haskell.nix";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.follows = "haskell-nix/flake-utils";
}; };
outputs = { self, nixpkgs, flake-utils, haskell-nix }: outputs = { self, nixpkgs, flake-utils, haskell-nix }:
flake-utils.lib.eachDefaultSystem (system:
let flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
pkgs = import nixpkgs { inherit system; inherit (haskell-nix) config; overlays = [haskell-nix.overlay]; }; let
project = pkgs.haskell-nix.cabalProject { pkgs = import nixpkgs {
src = ./.; inherit system;
compiler-nix-name = "ghc8107"; inherit (haskell-nix) config;
shell.tools = { overlays = [ haskell-nix.overlay ];
cabal = {};
hlint = {};
haskell-language-server = {};
}; };
shell.buildInputs = with pkgs; [
nixpkgs-fmt pkgs-static-where-possible =
fsatrace if pkgs.stdenv.hostPlatform.isLinux then
]; if pkgs.stdenv.hostPlatform.isAarch64 then
modules = [{ pkgs.pkgsCross.aarch64-multiplatform-musl
packages.foliage.components.exes.foliage.dontStrip = false; else
}]; pkgs.pkgsCross.musl64
}; else
in { pkgs;
packages.default = project.foliage.components.exes.foliage;
devShell = pkgs.mkShell { project = pkgs-static-where-possible.haskell-nix.cabalProject' {
name = "foliage-dev-shell"; src = ./.;
buildInputs = with pkgs; [ compiler-nix-name = "ghc926";
fsatrace };
];
}; flake = project.flake { };
});
in
flake // { packages.default = flake.packages."foliage:exe:foliage"; });
nixConfig = { nixConfig = {
extra-substituters = [ extra-substituters = [
"https://cache.iog.io" "https://cache.iog.io"
"https://foliage.cachix.org" "https://foliage.cachix.org"
"https://cache.zw3rk.com"
]; ];
extra-trusted-public-keys = [ extra-trusted-public-keys = [
"hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="
"foliage.cachix.org-1:kAFyYLnk8JcRURWReWZCatM9v3Rk24F5wNMpEj14Q/g=" "foliage.cachix.org-1:kAFyYLnk8JcRURWReWZCatM9v3Rk24F5wNMpEj14Q/g="
"loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk="
]; ];
}; };
} }

View File

@ -27,6 +27,7 @@ executable foliage
Foliage.Meta.Aeson Foliage.Meta.Aeson
Foliage.Options Foliage.Options
Foliage.Pages Foliage.Pages
Foliage.PreparePackageVersion
Foliage.PrepareSource Foliage.PrepareSource
Foliage.PrepareSdist Foliage.PrepareSdist
Foliage.RemoteAsset Foliage.RemoteAsset
@ -34,13 +35,13 @@ executable foliage
Foliage.Time Foliage.Time
Foliage.UpdateCabalFile Foliage.UpdateCabalFile
Foliage.Utils.Aeson Foliage.Utils.Aeson
Foliage.Utils.GitHub
Network.URI.Orphans Network.URI.Orphans
default-language: Haskell2010 default-language: GHC2021
default-extensions:
ImportQualifiedPost LambdaCase NamedFieldPuns ViewPatterns
ghc-options: -Wall ghc-options: -Wall
ghc-options: -threaded
build-depends: build-depends:
base >=4.14.3.0 && <4.18, base >=4.14.3.0 && <4.18,
aeson >=2.0.3.0 && <2.2, aeson >=2.0.3.0 && <2.2,

View File

@ -42,28 +42,26 @@
<dt class="col-sm-3">License</dt> <dt class="col-sm-3">License</dt>
<dd class="col-sm-9"><p>{{license}}</p></dd> <dd class="col-sm-9"><p>{{license}}</p></dd>
{{/pkgDesc}} {{/pkgDesc}}
{{#pkgSpec}} {{#pkgVersionSource}}
{{#packageVersionSource}}
<dt class="col-sm-3">Source</dt> <dt class="col-sm-3">Source</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
<dl class="row"> <dl class="row">
{{> packageVersionSource}} {{> packageVersionSource}}
</dl> </dl>
</dd> </dd>
{{/packageVersionSource}} {{/pkgVersionSource}}
<dt class="col-sm-3">Timestamp</dt> <dt class="col-sm-3">Timestamp</dt>
<dd class="col-sm-9"><p>{{packageVersionTimestamp}}</p></dd> <dd class="col-sm-9"><p>{{pkgTimestamp}}</p></dd>
<dt class="col-sm-3">Revisions</dt> <dt class="col-sm-3">Revisions</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
{{#packageVersionRevisions}} {{#cabalFileRevisions}}
<p>{{revisionTimestamp}}</p> <p>{{.}}</p>
{{/packageVersionRevisions}} {{/cabalFileRevisions}}
{{^packageVersionRevisions}} {{^cabalFileRevisions}}
<p>None</p> <p>None</p>
{{/packageVersionRevisions}} {{/cabalFileRevisions}}
</dd> </dd>
</dl> </dl>
</div> </div>
{{/pkgSpec}}
</body> </body>
</html> </html>