diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index e4f2d82..ef627f8 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -12,18 +12,16 @@ jobs: - ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v17 + - uses: cachix/install-nix-action@v20 with: extra_nix_config: | 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: name: foliage authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - run: nix build + - run: nix build --accept-flake-config diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml new file mode 100644 index 0000000..d51e30e --- /dev/null +++ b/.github/workflows/update-flake-lock.yml @@ -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 }}. diff --git a/README.md b/README.md index 2a1a12f..5cd1eed 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,18 @@ metadata file `//meta.toml` includes the option `force-version = true`, then the version in the package cabal file will be overwritten with ``. 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 - Andrea Bedini (@andreabedini) diff --git a/app/Distribution/PackageDescription/FieldGrammar/Copy.hs b/app/Distribution/PackageDescription/FieldGrammar/Copy.hs index 212484c..6f6eba3 100644 --- a/app/Distribution/PackageDescription/FieldGrammar/Copy.hs +++ b/app/Distribution/PackageDescription/FieldGrammar/Copy.hs @@ -18,7 +18,7 @@ module Distribution.PackageDescription.FieldGrammar.Copy where 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.Prelude import Distribution.Compiler (CompilerFlavor (..)) @@ -29,8 +29,8 @@ import Distribution.PackageDescription import Distribution.PackageDescription.FieldGrammar hiding (packageDescriptionFieldGrammar) import Distribution.Parsec import Distribution.Pretty (Pretty (..), showToken) -import qualified Distribution.SPDX as SPDX -import qualified Distribution.Types.Lens as L +import Distribution.SPDX qualified as SPDX +import Distribution.Types.Lens qualified as L import Distribution.Utils.Path import Distribution.Version (Version, VersionRange) import Prelude () diff --git a/app/Distribution/Types/Orphans.hs b/app/Distribution/Types/Orphans.hs index 3af7a11..ba3a784 100644 --- a/app/Distribution/Types/Orphans.hs +++ b/app/Distribution/Types/Orphans.hs @@ -2,14 +2,14 @@ module Distribution.Types.Orphans where +import Data.Aeson (ToJSON (toJSON)) import Development.Shake.Classes (Hashable) +import Distribution.Pretty (prettyShow) import Distribution.Types.PackageId (PackageIdentifier) import Distribution.Types.PackageName (PackageName) import Distribution.Types.Version (Version) import Distribution.Types.VersionRange (VersionRange) import Distribution.Utils.ShortText (ShortText) -import Data.Aeson (ToJSON (toJSON)) -import Distribution.Pretty (prettyShow) instance ToJSON PackageIdentifier where toJSON = toJSON . prettyShow diff --git a/app/Foliage/CmdBuild.hs b/app/Foliage/CmdBuild.hs index aa69558..832495c 100644 --- a/app/Foliage/CmdBuild.hs +++ b/app/Foliage/CmdBuild.hs @@ -6,29 +6,32 @@ module Foliage.CmdBuild (cmdBuild) where import Codec.Archive.Tar qualified as Tar import Codec.Archive.Tar.Entry qualified as Tar 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 BSL -import Data.Foldable (for_) import Data.List (sortOn) import Data.Maybe (fromMaybe) +import Data.Text qualified as T import Data.Traversable (for) import Development.Shake import Development.Shake.FilePath import Distribution.Package -import Distribution.Parsec (simpleParsec) import Distribution.Pretty (prettyShow) import Foliage.HackageSecurity hiding (ToJSON, toJSON) import Foliage.Meta import Foliage.Meta.Aeson () import Foliage.Options import Foliage.Pages -import Foliage.PrepareSdist -import Foliage.PrepareSource (addPrepareSourceRule, prepareSource) +import Foliage.PreparePackageVersion (PreparedPackageVersion (..), preparePackageVersion) +import Foliage.PrepareSdist (addPrepareSdistRule) +import Foliage.PrepareSource (addPrepareSourceRule) import Foliage.RemoteAsset (addFetchRemoteAssetRule) import Foliage.Shake import Foliage.Time qualified as Time import Hackage.Security.Util.Path (castRoot, toFilePath) +import Network.URI (URI (uriPath, uriQuery, uriScheme), nullURI) +import System.Directory (createDirectoryIfMissing) cmdBuild :: BuildOptions -> IO () cmdBuild buildOptions = do @@ -45,7 +48,8 @@ cmdBuild buildOptions = do opts = shakeOptions { shakeFiles = cacheDir, - shakeVerbosity = Verbose + shakeVerbosity = Verbose, + shakeThreads = buildOptsNumThreads buildOptions } buildAction :: BuildOptions -> Action () @@ -55,7 +59,8 @@ buildAction buildOptsCurrentTime = mCurrentTime, buildOptsExpireSignaturesOn = mExpireSignaturesOn, buildOptsInputDir = inputDir, - buildOptsOutputDir = outputDir + buildOptsOutputDir = outputDir, + buildOptsWriteMetadata = doWritePackageMeta } = do outputDirRoot <- liftIO $ makeAbsolute (fromFilePath outputDir) @@ -94,54 +99,47 @@ buildAction 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 - cabalFilePath <- maybe (originalCabalFile pkgMeta) pure (revisedCabalFile inputDir pkgMeta) copyFileChanged cabalFilePath (outputDir "index" prettyShow pkgName prettyShow pkgVersion prettyShow pkgName <.> "cabal") cabalEntries <- foldMap - ( \pkgMeta@PackageVersionMeta {pkgId, pkgSpec} -> do - let PackageVersionSpec {packageVersionTimestamp, packageVersionRevisions} = pkgSpec - + ( \PreparedPackageVersion {pkgId, pkgTimestamp, originalCabalFilePath, cabalFileRevisions} -> do -- original cabal file, with its timestamp (if specified) - cabalFilePath <- originalCabalFile pkgMeta - let cabalFileTimestamp = fromMaybe currentTime packageVersionTimestamp - cf <- prepareIndexPkgCabal pkgId cabalFileTimestamp cabalFilePath + let cabalFileTimestamp = fromMaybe currentTime pkgTimestamp + cf <- prepareIndexPkgCabal pkgId cabalFileTimestamp originalCabalFilePath -- all revised cabal files, with their timestamp - revcf <- - for packageVersionRevisions $ - \RevisionSpec {revisionTimestamp, revisionNumber} -> - prepareIndexPkgCabal - pkgId - revisionTimestamp - (cabalFileRevisionPath inputDir pkgId revisionNumber) + revcf <- for cabalFileRevisions $ uncurry (prepareIndexPkgCabal pkgId) return $ cf : revcf ) packageVersions targetKeys <- maybeReadKeysAt "target" + metadataEntries <- - for packageVersions $ \pkg@PackageVersionMeta {pkgId, pkgSpec} -> do + forP packageVersions $ \ppv@PreparedPackageVersion {pkgId, pkgTimestamp} -> do let PackageIdentifier {pkgName, pkgVersion} = pkgId - let PackageVersionSpec {packageVersionTimestamp} = pkgSpec - targets <- prepareIndexPkgMetadata expiryTime pkg + targets <- prepareIndexPkgMetadata expiryTime ppv let path = outputDir "index" prettyShow pkgName prettyShow pkgVersion "package.json" liftIO $ BL.writeFile path $ renderSignedJSON targetKeys targets - return $ + pure $ mkTarEntry (renderSignedJSON targetKeys targets) (IndexPkgMetadata pkgId) - (fromMaybe currentTime packageVersionTimestamp) + (fromMaybe currentTime pkgTimestamp) let tarContents = Tar.write $ sortOn Tar.entryTime (cabalEntries ++ metadataEntries) traced "Writing index" $ do - BSL.writeFile (anchorPath outputDirRoot repoLayoutIndexTar) tarContents - BSL.writeFile (anchorPath outputDirRoot repoLayoutIndexTarGz) $ GZip.compress tarContents + BL.writeFile (anchorPath outputDirRoot repoLayoutIndexTar) tarContents + BL.writeFile (anchorPath outputDirRoot repoLayoutIndexTarGz) $ GZip.compress tarContents privateKeysRoot <- maybeReadKeysAt "root" privateKeysTarget <- maybeReadKeysAt "target" @@ -226,58 +224,66 @@ buildAction 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 metaFiles <- getDirectoryFiles inputDir ["*/*/meta.toml"] when (null metaFiles) $ do - putError $ + error $ unlines [ "We could not find any package metadata file (i.e. _sources///meta.toml)", "Make sure you are passing the right input directory. The default input directory is _sources" ] - fail "no package metadata found" - for metaFiles $ \metaFile -> do - 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 + forP metaFiles $ preparePackageVersion inputDir prepareIndexPkgCabal :: PackageId -> UTCTime -> FilePath -> Action Tar.Entry prepareIndexPkgCabal pkgId timestamp filePath = do need [filePath] - contents <- liftIO $ BSL.readFile filePath - return $ mkTarEntry contents (IndexPkgCabal pkgId) timestamp + contents <- liftIO $ BS.readFile filePath + pure $ mkTarEntry (BL.fromStrict contents) (IndexPkgCabal pkgId) timestamp -prepareIndexPkgMetadata :: Maybe UTCTime -> PackageVersionMeta -> Action Targets -prepareIndexPkgMetadata expiryTime PackageVersionMeta {pkgId, pkgSpec} = do - srcDir <- prepareSource pkgId pkgSpec - sdist <- prepareSdist srcDir - targetFileInfo <- computeFileInfoSimple' sdist +prepareIndexPkgMetadata :: Maybe UTCTime -> PreparedPackageVersion -> Action Targets +prepareIndexPkgMetadata expiryTime PreparedPackageVersion {pkgId, sdistPath} = do + targetFileInfo <- liftIO $ computeFileInfoSimple sdistPath let packagePath = repoLayoutPkgTarGz hackageRepoLayout pkgId return Targets @@ -287,7 +293,7 @@ prepareIndexPkgMetadata expiryTime PackageVersionMeta {pkgId, pkgSpec} = do targetsDelegations = Nothing } -mkTarEntry :: BSL.ByteString -> IndexFile dec -> UTCTime -> Tar.Entry +mkTarEntry :: BL.ByteString -> IndexFile dec -> UTCTime -> Tar.Entry mkTarEntry contents indexFile timestamp = (Tar.fileEntry tarPath contents) { Tar.entryTime = floor $ Time.utcTimeToPOSIXSeconds timestamp, @@ -300,8 +306,11 @@ mkTarEntry contents indexFile timestamp = } } 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 - Right tarPath = Tar.toTarPath False indexPath anchorPath :: Path Absolute -> (RepoLayout -> RepoPath) -> FilePath anchorPath outputDirRoot p = diff --git a/app/Foliage/CmdImportIndex.hs b/app/Foliage/CmdImportIndex.hs index e4d601c..25ec972 100644 --- a/app/Foliage/CmdImportIndex.hs +++ b/app/Foliage/CmdImportIndex.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE ViewPatterns #-} + module Foliage.CmdImportIndex ( cmdImportIndex, ) @@ -48,31 +50,31 @@ importIndex f (Tar.Next e es) m = case isCabalFile e of Just (pkgId, contents, time) | f pkgId -> - do - putStrLn $ "Found cabal file " ++ prettyShow pkgId ++ " with timestamp " ++ show time - let -- new package - go Nothing = - pure $ - Just $ - PackageVersionSpec - { packageVersionSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing, - packageVersionTimestamp = Just time, - packageVersionRevisions = [], - packageVersionForce = False - } - -- Existing package, new revision - go (Just sm) = do - let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm) - newRevision = RevisionSpec {revisionNumber = revnum, revisionTimestamp = time} - -- Repeatedly adding at the end of a list is bad performance but good for the moment. - let sm' = sm {packageVersionRevisions = packageVersionRevisions sm ++ [newRevision]} - let PackageIdentifier pkgName pkgVersion = pkgId - let outDir = "_sources" unPackageName pkgName prettyShow pkgVersion "revisions" - createDirectoryIfMissing True outDir - BSL.writeFile (outDir show revnum <.> "cabal") contents - return $ Just sm' - m' <- M.alterF go pkgId m - importIndex f es m' + do + putStrLn $ "Found cabal file " ++ prettyShow pkgId ++ " with timestamp " ++ show time + let -- new package + go Nothing = + pure $ + Just $ + PackageVersionSpec + { packageVersionSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing, + packageVersionTimestamp = Just time, + packageVersionRevisions = [], + packageVersionForce = False + } + -- Existing package, new revision + go (Just sm) = do + let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm) + newRevision = RevisionSpec {revisionNumber = revnum, revisionTimestamp = time} + -- Repeatedly adding at the end of a list is bad performance but good for the moment. + let sm' = sm {packageVersionRevisions = packageVersionRevisions sm ++ [newRevision]} + let PackageIdentifier pkgName pkgVersion = pkgId + let outDir = "_sources" unPackageName pkgName prettyShow pkgVersion "revisions" + createDirectoryIfMissing True outDir + BSL.writeFile (outDir show revnum <.> "cabal") contents + return $ Just sm' + m' <- M.alterF go pkgId m + importIndex f es m' _ -> importIndex f es m importIndex _f Tar.Done m = return m @@ -106,9 +108,9 @@ isCabalFile Tar.entryTime = posixSecondsToUTCTime . fromIntegral -> time } | ".cabal" `isSuffixOf` path = - let [pkgName, pkgVersion, _] = splitDirectories path - Just name = simpleParsec pkgName - Just version = simpleParsec pkgVersion - packageId = PackageIdentifier name version - in Just (packageId, contents, time) + let [pkgName, pkgVersion, _] = splitDirectories path + Just name = simpleParsec pkgName + Just version = simpleParsec pkgVersion + packageId = PackageIdentifier name version + in Just (packageId, contents, time) isCabalFile _ = Nothing diff --git a/app/Foliage/Meta.hs b/app/Foliage/Meta.hs index 12662b8..7130367 100644 --- a/app/Foliage/Meta.hs +++ b/app/Foliage/Meta.hs @@ -13,7 +13,6 @@ module Foliage.Meta packageMetaEntryTimestamp, readPackageMeta, writePackageMeta, - PackageVersionMeta (PackageVersionMeta, pkgId, pkgSpec), packageVersionTimestamp, packageVersionSource, packageVersionRevisions, @@ -32,8 +31,6 @@ module Foliage.Meta UTCTime, latestRevisionNumber, consolidateRanges, - cabalFileRevisionPath, - revisedCabalFile, ) where @@ -50,8 +47,6 @@ import Distribution.Aeson () import Distribution.Parsec (simpleParsec) import Distribution.Pretty (prettyShow) import Distribution.Types.Orphans () -import Distribution.Types.PackageId (PackageIdentifier (..)) -import Distribution.Types.PackageName (unPackageName) import Distribution.Types.Version (Version) import Distribution.Types.VersionRange (VersionRange, anyVersion, intersectVersionRanges, notThisVersion) import Distribution.Version (isAnyVersion, isNoVersion, simplifyVersionRange) @@ -59,7 +54,6 @@ import Foliage.Time (UTCTime) import GHC.Generics (Generic) import Network.URI (URI, parseURI) import Network.URI.Orphans () -import System.FilePath ((<.>), ()) import Toml (TomlCodec, (.=)) import Toml qualified @@ -86,14 +80,18 @@ writePackageMeta fp a = void $ Toml.encodeToFile packageMetaCodec fp a packageMetaCodec :: TomlCodec PackageMeta packageMetaCodec = PackageMeta - <$> Toml.list packageMetaEntryCodec "entries" .= packageMetaEntries + <$> Toml.list packageMetaEntryCodec "entries" + .= packageMetaEntries packageMetaEntryCodec :: TomlCodec PackageMetaEntry packageMetaEntryCodec = PackageMetaEntry - <$> timeCodec "timestamp" .= packageMetaEntryTimestamp - <*> Toml.arrayOf _VersionRange "preferred-versions" .= packageMetaEntryPreferred - <*> Toml.arrayOf _Version "deprecated-versions" .= packageMetaEntryDeprecated + <$> timeCodec "timestamp" + .= packageMetaEntryTimestamp + <*> Toml.arrayOf _VersionRange "preferred-versions" + .= packageMetaEntryPreferred + <*> Toml.arrayOf _Version "deprecated-versions" + .= packageMetaEntryDeprecated _Version :: Toml.TomlBiMap Version Toml.AnyValue _Version = Toml._TextBy showVersion parseVersion @@ -185,10 +183,14 @@ data PackageVersionSpec = PackageVersionSpec sourceMetaCodec :: TomlCodec PackageVersionSpec sourceMetaCodec = PackageVersionSpec - <$> Toml.dioptional (timeCodec "timestamp") .= packageVersionTimestamp - <*> packageSourceCodec .= packageVersionSource - <*> Toml.list revisionMetaCodec "revisions" .= packageVersionRevisions - <*> withDefault False (Toml.bool "force-version") .= packageVersionForce + <$> Toml.dioptional (timeCodec "timestamp") + .= packageVersionTimestamp + <*> packageSourceCodec + .= packageVersionSource + <*> Toml.list revisionMetaCodec "revisions" + .= packageVersionRevisions + <*> withDefault False (Toml.bool "force-version") + .= packageVersionForce readPackageVersionSpec :: FilePath -> IO PackageVersionSpec readPackageVersionSpec = Toml.decodeFile sourceMetaCodec @@ -206,8 +208,10 @@ data RevisionSpec = RevisionSpec revisionMetaCodec :: TomlCodec RevisionSpec revisionMetaCodec = RevisionSpec - <$> timeCodec "timestamp" .= revisionTimestamp - <*> Toml.int "number" .= revisionNumber + <$> timeCodec "timestamp" + .= revisionTimestamp + <*> Toml.int "number" + .= revisionNumber timeCodec :: Toml.Key -> TomlCodec UTCTime timeCodec key = Toml.dimap (utcToZonedTime utc) zonedTimeToUTC $ Toml.zonedTime key @@ -231,18 +235,3 @@ consolidateRanges PackageMetaEntry {packageMetaEntryPreferred, packageMetaEntryD range = simplifyVersionRange $ 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 diff --git a/app/Foliage/Meta/Aeson.hs b/app/Foliage/Meta/Aeson.hs index 54f1aa6..339b39c 100644 --- a/app/Foliage/Meta/Aeson.hs +++ b/app/Foliage/Meta/Aeson.hs @@ -1,13 +1,13 @@ {-# LANGUAGE DerivingVia #-} +{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE StandaloneDeriving #-} {-# OPTIONS_GHC -Wno-orphans #-} -{-# LANGUAGE InstanceSigs #-} module Foliage.Meta.Aeson where -import Distribution.Types.Orphans () import Data.Aeson import Data.Text +import Distribution.Types.Orphans () import Foliage.Meta import Foliage.Utils.Aeson 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 PackageVersionMeta instance ToJSON PackageVersionMeta - deriving via Text instance ToJSON GitHubRepo deriving via Text instance ToJSON GitHubRev @@ -30,8 +28,8 @@ instance ToJSON PackageVersionSource where toJSON = genericToJSON defaultOptions - { sumEncoding = ObjectWithSingleField - , omitNothingFields = True + { sumEncoding = ObjectWithSingleField, + omitNothingFields = True } instance ToJSON URI where diff --git a/app/Foliage/Options.hs b/app/Foliage/Options.hs index 58813f3..607f484 100644 --- a/app/Foliage/Options.hs +++ b/app/Foliage/Options.hs @@ -51,7 +51,9 @@ data BuildOptions = BuildOptions buildOptsCurrentTime :: Maybe UTCTime, buildOptsExpireSignaturesOn :: Maybe UTCTime, buildOptsInputDir :: FilePath, - buildOptsOutputDir :: FilePath + buildOptsOutputDir :: FilePath, + buildOptsNumThreads :: Int, + buildOptsWriteMetadata :: Bool } buildCommand :: Parser Command @@ -90,6 +92,20 @@ buildCommand = <> showDefault <> 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 signOpts = diff --git a/app/Foliage/Pages.hs b/app/Foliage/Pages.hs index 7b79dfe..9df7777 100644 --- a/app/Foliage/Pages.hs +++ b/app/Foliage/Pages.hs @@ -15,10 +15,11 @@ module Foliage.Pages where import Data.Aeson (KeyValue ((.=)), ToJSON, object) -import Data.Function (on) -import Data.List (groupBy, sortOn) +import Data.Function (on, (&)) +import Data.List (sortOn) +import Data.List.NonEmpty qualified as NE 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.Time (UTCTime) import Data.Time.Clock.POSIX (POSIXTime, utcTimeToPOSIXSeconds) @@ -26,9 +27,9 @@ import Development.Shake (Action, traced) import Distribution.Aeson (jsonGenericPackageDescription) import Distribution.Package (PackageIdentifier (pkgName, pkgVersion)) 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.Shake (originalCabalFile, readGenericPackageDescription') +import Foliage.PreparePackageVersion (PreparedPackageVersion (..)) import Foliage.Utils.Aeson (MyAesonEncoding (..)) import GHC.Generics (Generic) import System.Directory qualified as IO @@ -50,34 +51,44 @@ data AllPackagesPageEntry = AllPackagesPageEntry allPackagesPageEntryTimestamp :: UTCTime, allPackagesPageEntryTimestampPosix :: POSIXTime, allPackagesPageEntrySource :: PackageVersionSource, - allPackagesPageEntryRevision :: Maybe RevisionSpec + allPackagesPageEntryLatestRevisionTimestamp :: Maybe UTCTime } deriving stock (Generic) deriving (ToJSON) via MyAesonEncoding AllPackagesPageEntry -makeAllPackagesPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action () -makeAllPackagesPage currentTime outputDir packageVersions = do - 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 +makeAllPackagesPage :: UTCTime -> FilePath -> [PreparedPackageVersion] -> Action () +makeAllPackagesPage currentTime outputDir packageVersions = traced "webpages / all-packages" $ do IO.createDirectoryIfMissing True (outputDir "all-packages") TL.writeFile (outputDir "all-packages" "index.html") $ renderMustache allPackagesPageTemplate $ 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 = AllPackageVersionsPageEntryPackage @@ -94,47 +105,49 @@ data AllPackageVersionsPageEntry deriving stock (Generic) deriving (ToJSON) via MyAesonEncoding AllPackageVersionsPageEntry -makeAllPackageVersionsPage :: UTCTime -> FilePath -> [PackageVersionMeta] -> Action () -makeAllPackageVersionsPage currentTime outputDir packageVersions = do - 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 - +makeAllPackageVersionsPage :: UTCTime -> FilePath -> [PreparedPackageVersion] -> Action () +makeAllPackageVersionsPage currentTime outputDir packageVersions = traced "webpages / all-package-versions" $ do IO.createDirectoryIfMissing True (outputDir "all-package-versions") TL.writeFile (outputDir "all-package-versions" "index.html") $ renderMustache allPackageVersionsPageTemplate $ 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 inputDir outputDir pkgMeta@PackageVersionMeta {pkgId, pkgSpec} = do - cabalFilePath <- maybe (originalCabalFile pkgMeta) pure (revisedCabalFile inputDir pkgMeta) - pkgDesc <- readGenericPackageDescription' cabalFilePath +makePackageVersionPage :: FilePath -> PreparedPackageVersion -> Action () +makePackageVersionPage outputDir PreparedPackageVersion {pkgId, pkgTimestamp, pkgVersionSource, pkgDesc, cabalFileRevisions} = do traced ("webpages / package / " ++ prettyShow pkgId) $ do IO.createDirectoryIfMissing True (outputDir "package" prettyShow pkgId) TL.writeFile (outputDir "package" prettyShow pkgId "index.html") $ renderMustache packageVersionPageTemplate $ object - [ "pkgSpec" .= pkgSpec, - "pkgDesc" .= jsonGenericPackageDescription pkgDesc + [ "pkgVersionSource" .= pkgVersionSource, + "cabalFileRevisions" .= map fst cabalFileRevisions, + "pkgDesc" .= jsonGenericPackageDescription pkgDesc, + "pkgTimestamp" .= pkgTimestamp ] indexPageTemplate :: Template diff --git a/app/Foliage/PreparePackageVersion.hs b/app/Foliage/PreparePackageVersion.hs new file mode 100644 index 0000000..854bdda --- /dev/null +++ b/app/Foliage/PreparePackageVersion.hs @@ -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 + } diff --git a/app/Foliage/PrepareSdist.hs b/app/Foliage/PrepareSdist.hs index 6ccaca6..e41a2e7 100644 --- a/app/Foliage/PrepareSdist.hs +++ b/app/Foliage/PrepareSdist.hs @@ -1,7 +1,6 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeFamilies #-} module Foliage.PrepareSdist @@ -53,7 +52,7 @@ addPrepareSdistRule outputDirRoot = addBuiltinRule noLint noIdentity run case ehvExisting of Right hvExisting | hvExisting == hvExpected -> - return RunResult {runChanged = ChangedNothing, runStore = old, runValue = path} + return RunResult {runChanged = ChangedNothing, runStore = old, runValue = path} Right hvExisting -> do putWarn $ "Changed " ++ path ++ " (expecting hash " ++ showHashValue hvExpected ++ " found " ++ showHashValue hvExisting ++ "). I will rebuild it." run (PrepareSdistRule srcDir) (Just old) RunDependenciesChanged @@ -71,18 +70,24 @@ addPrepareSdistRule outputDirRoot = addBuiltinRule noLint noIdentity run _differentOrMissing -> ChangedRecomputeDiff when (changed == ChangedRecomputeSame) $ - putInfo $ "Wrote " ++ path ++ " (same hash " ++ showHashValue hv ++ ")" + putInfo ("Wrote " ++ path ++ " (same hash " ++ showHashValue hv ++ ")") 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} makeSdist srcDir = do - cabalFile <- do - getDirectoryFiles srcDir ["*.cabal"] >>= \case - [f] -> pure f - fs -> fail $ "Invalid srcDir: " ++ srcDir ++ ". It contains multiple cabal files: " ++ unwords fs + cabalFiles <- getDirectoryFiles srcDir ["*.cabal"] + let cabalFile = case cabalFiles of + [f] -> f + fs -> + error $ + unlines + [ "Invalid source directory: " ++ srcDir, + "It contains multiple cabal files, while only one is allowed", + unwords fs + ] traced "cabal sdist" $ do gpd <- readGenericPackageDescription Verbosity.normal (srcDir cabalFile) diff --git a/app/Foliage/PrepareSource.hs b/app/Foliage/PrepareSource.hs index dfa989e..34443a6 100644 --- a/app/Foliage/PrepareSource.hs +++ b/app/Foliage/PrepareSource.hs @@ -8,7 +8,6 @@ module Foliage.PrepareSource where import Control.Monad (when) import Data.ByteString qualified as BS import Data.Foldable (for_) -import Data.Text qualified as T import Development.Shake import Development.Shake.Classes import Development.Shake.Rule @@ -18,8 +17,8 @@ import Distribution.Types.PackageName (unPackageName) import Foliage.Meta import Foliage.RemoteAsset (fetchRemoteAsset) import Foliage.UpdateCabalFile (rewritePackageVersion) +import Foliage.Utils.GitHub (githubRepoTarballUrl) import GHC.Generics -import Network.URI (URI (..), URIAuth (..), nullURI, nullURIAuth) import System.Directory qualified as IO import System.FilePath ((<.>), ()) @@ -79,12 +78,7 @@ addPrepareSourceRule inputDir cacheDir = addBuiltinRule noLint noIdentity run -- metadata. -- GitHubSource repo rev mSubdir -> do - let url = - nullURI - { uriScheme = "https:", - uriAuthority = Just nullURIAuth {uriRegName = "github.com"}, - uriPath = "/" T.unpack (unGitHubRepo repo) "tarball" T.unpack (unGitHubRev rev) - } + let url = githubRepoTarballUrl repo rev tarballPath <- fetchRemoteAsset url diff --git a/app/Foliage/RemoteAsset.hs b/app/Foliage/RemoteAsset.hs index 90fee7d..f054256 100644 --- a/app/Foliage/RemoteAsset.hs +++ b/app/Foliage/RemoteAsset.hs @@ -35,14 +35,16 @@ addFetchRemoteAssetRule cacheDir = addBuiltinRule noLint noIdentity run run :: BuiltinRun RemoteAsset FilePath run (RemoteAsset uri) old _mode = do 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 == "") $ - 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 - 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 let oldETag = fromMaybe BS.empty old diff --git a/app/Foliage/Shake.hs b/app/Foliage/Shake.hs index 0885b7e..a28883a 100644 --- a/app/Foliage/Shake.hs +++ b/app/Foliage/Shake.hs @@ -3,7 +3,6 @@ module Foliage.Shake readKeysAt, readPackageVersionSpec', readGenericPackageDescription', - originalCabalFile, ) where @@ -12,12 +11,9 @@ import Development.Shake import Development.Shake.FilePath import Distribution.Simple.PackageDescription import Distribution.Types.GenericPackageDescription -import Distribution.Types.PackageId -import Distribution.Types.PackageName import Distribution.Verbosity qualified as Verbosity import Foliage.HackageSecurity import Foliage.Meta -import Foliage.PrepareSource computeFileInfoSimple' :: FilePath -> Action FileInfo computeFileInfoSimple' fp = do @@ -41,8 +37,3 @@ readGenericPackageDescription' :: FilePath -> Action GenericPackageDescription readGenericPackageDescription' fp = do need [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" diff --git a/app/Foliage/Utils/Aeson.hs b/app/Foliage/Utils/Aeson.hs index dfbf42d..220cb25 100644 --- a/app/Foliage/Utils/Aeson.hs +++ b/app/Foliage/Utils/Aeson.hs @@ -2,22 +2,23 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} + module Foliage.Utils.Aeson where import Data.Aeson -import GHC.Generics import Data.Coerce +import GHC.Generics newtype MyAesonEncoding a = MyAesonEncoding a - deriving Generic + deriving (Generic) myOptions :: Options myOptions = defaultOptions - { sumEncoding = ObjectWithSingleField - , omitNothingFields = True + { sumEncoding = ObjectWithSingleField, + omitNothingFields = True } 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) diff --git a/app/Foliage/Utils/GitHub.hs b/app/Foliage/Utils/GitHub.hs new file mode 100644 index 0000000..96c1461 --- /dev/null +++ b/app/Foliage/Utils/GitHub.hs @@ -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) + } diff --git a/app/Main.hs b/app/Main.hs index 323d271..baca0ad 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE LambdaCase #-} + module Main where import Foliage.CmdBuild diff --git a/cabal.project b/cabal.project index b16303c..5ccaf65 100644 --- a/cabal.project +++ b/cabal.project @@ -1,3 +1,6 @@ packages: . -index-state: 2022-08-29T00:00:00Z -with-compiler: ghc-8.10.7 +index-state: 2023-03-01T00:00:00Z +with-compiler: ghc-9.2.6 +allow-newer: + , tomland:base + , tomland:text diff --git a/flake.lock b/flake.lock index fb6135d..de46b90 100644 --- a/flake.lock +++ b/flake.lock @@ -16,6 +16,21 @@ "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": { "flake": false, "locked": { @@ -36,11 +51,11 @@ "cabal-34": { "flake": false, "locked": { - "lastModified": 1640353650, - "narHash": "sha256-N1t6M3/wqj90AEdRkeC8i923gQYUpzSr8b40qVOZ1Rk=", + "lastModified": 1645834128, + "narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=", "owner": "haskell", "repo": "cabal", - "rev": "942639c18c0cd8ec53e0a6f8d120091af35312cd", + "rev": "5ff598c67f53f7c4f48e31d722ba37172230c462", "type": "github" }, "original": { @@ -53,11 +68,11 @@ "cabal-36": { "flake": false, "locked": { - "lastModified": 1641652457, - "narHash": "sha256-BlFPKP4C4HRUJeAbdembX1Rms1LD380q9s0qVDeoAak=", + "lastModified": 1669081697, + "narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=", "owner": "haskell", "repo": "cabal", - "rev": "f27667f8ec360c475027dcaee0138c937477b070", + "rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144", "type": "github" }, "original": { @@ -83,13 +98,104 @@ "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": { "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -100,11 +206,26 @@ }, "flake-utils_2": { "locked": { - "lastModified": 1644229661, - "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", "owner": "numtide", "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" }, "original": { @@ -130,14 +251,33 @@ "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": { "flake": false, "locked": { - "lastModified": 1661735830, - "narHash": "sha256-xJpfFmpzJVci+fM9mjTKyIbkUpJf5XkZMygY+YRKzwU=", + "lastModified": 1677809131, + "narHash": "sha256-MQ+ybbu5VFA6ERvh8mXcYEVlBCTte4BDxRaILSwBdAk=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "9b22f61f50b19bf401ab104ff0e239f8ada87547", + "rev": "4ea4b12737ea42e47eb5c6a7e4a3eafe9da2fc52", "type": "github" }, "original": { @@ -153,12 +293,13 @@ "cabal-34": "cabal-34", "cabal-36": "cabal-36", "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", "hackage": "hackage", "hpc-coveralls": "hpc-coveralls", "hydra": "hydra", - "nix-tools": "nix-tools", + "iserv-proxy": "iserv-proxy", "nixpkgs": [ "haskell-nix", "nixpkgs-unstable" @@ -167,16 +308,18 @@ "nixpkgs-2105": "nixpkgs-2105", "nixpkgs-2111": "nixpkgs-2111", "nixpkgs-2205": "nixpkgs-2205", + "nixpkgs-2211": "nixpkgs-2211", "nixpkgs-unstable": "nixpkgs-unstable", "old-ghc-nix": "old-ghc-nix", - "stackage": "stackage" + "stackage": "stackage", + "tullia": "tullia" }, "locked": { - "lastModified": 1661940924, - "narHash": "sha256-aXmYSdeDjSWpJPtNAtvAKabKUyOOiJXzZ7EEYYKNrYI=", + "lastModified": 1677809260, + "narHash": "sha256-RSiv9/LP8/+sf15B305z4DYaj7IiAVjPBkqPfByxAp4=", "owner": "input-output-hk", "repo": "haskell.nix", - "rev": "c83b33f4198fd8ba62748feb5024ece2b5329a8e", + "rev": "02a5acdfc937129e51e41de0eafd0c44f29896b4", "type": "github" }, "original": { @@ -212,11 +355,11 @@ ] }, "locked": { - "lastModified": 1646878427, - "narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=", + "lastModified": 1671755331, + "narHash": "sha256-hXsgJj0Cy0ZiCiYdW2OdBz5WmFyOMKuw4zyxKpgUKm4=", "owner": "NixOS", "repo": "hydra", - "rev": "28b682b85b7efc5cf7974065792a1f22203a5927", + "rev": "f48f00ee6d5727ae3e488cbf9ce157460853fea8", "type": "github" }, "original": { @@ -224,6 +367,46 @@ "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": { "flake": false, "locked": { @@ -240,6 +423,35 @@ "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": { "inputs": { "lowdown-src": "lowdown-src", @@ -247,49 +459,123 @@ "nixpkgs-regression": "nixpkgs-regression" }, "locked": { - "lastModified": 1643066034, - "narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=", + "lastModified": 1661606874, + "narHash": "sha256-9+rpYzI+SmxJn+EbYxjGv68Ucp22bdFUSy/4LkHkkDQ=", "owner": "NixOS", "repo": "nix", - "rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62", + "rev": "11e45768b34fdafdcf019ddbd337afa16127ff0f", "type": "github" }, "original": { "owner": "NixOS", - "ref": "2.6.0", + "ref": "2.11.0", "repo": "nix", "type": "github" } }, - "nix-tools": { - "flake": false, + "nix-nomad": { + "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": { - "lastModified": 1659569011, - "narHash": "sha256-wHS0H5+TERmDnPCfzH4A+rSR5TvjYMWus9BNeNAMyUM=", - "owner": "input-output-hk", - "repo": "nix-tools", - "rev": "555d57e1ea81b79945f2608aa261df20f6b602a5", + "lastModified": 1658277770, + "narHash": "sha256-T/PgG3wUn8Z2rnzfxf2VqlR1CBjInPE0l1yVzXxPnt0=", + "owner": "tristanpemble", + "repo": "nix-nomad", + "rev": "054adcbdd0a836ae1c20951b67ed549131fd2d70", "type": "github" }, "original": { - "owner": "input-output-hk", - "repo": "nix-tools", + "owner": "tristanpemble", + "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" } }, "nixpkgs": { "locked": { - "lastModified": 1632864508, - "narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=", + "lastModified": 1657693803, + "narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "82891b5e2c2359d7e58d08849e4c89511ab94234", + "rev": "365e1b3a859281cf11b94f87231adeabbdd878a2", "type": "github" }, "original": { - "id": "nixpkgs", - "ref": "nixos-21.05-small", - "type": "indirect" + "owner": "NixOS", + "ref": "nixos-22.05-small", + "repo": "nixpkgs", + "type": "github" } }, "nixpkgs-2003": { @@ -310,11 +596,11 @@ }, "nixpkgs-2105": { "locked": { - "lastModified": 1655034179, - "narHash": "sha256-rf1/7AbzuYDw6+8Xvvf3PtEOygymLBrFsFxvext5ZjI=", + "lastModified": 1659914493, + "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "046ee4af7a9f016a364f8f78eeaa356ba524ac31", + "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf", "type": "github" }, "original": { @@ -326,11 +612,11 @@ }, "nixpkgs-2111": { "locked": { - "lastModified": 1656782578, - "narHash": "sha256-1eMCBEqJplPotTo/SZ/t5HU6Sf2I8qKlZi9MX7jv9fw=", + "lastModified": 1659446231, + "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "573603b7fdb9feb0eb8efc16ee18a015c667ab1b", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", "type": "github" }, "original": { @@ -342,11 +628,11 @@ }, "nixpkgs-2205": { "locked": { - "lastModified": 1657876628, - "narHash": "sha256-URmf0O2cQ/3heg2DJOeLyU/JmfVMqG4X5t9crQXMaeY=", + "lastModified": 1672580127, + "narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "549d82bdd40f760a438c3c3497c1c61160f3de55", + "rev": "0874168639713f547c05947c76124f78441ea46c", "type": "github" }, "original": { @@ -356,6 +642,22 @@ "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": { "locked": { "lastModified": 1643052045, @@ -366,18 +668,19 @@ "type": "github" }, "original": { - "id": "nixpkgs", + "owner": "NixOS", + "repo": "nixpkgs", "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "indirect" + "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1657888067, - "narHash": "sha256-GnwJoFBTPfW3+mz7QEeJEEQ9OMHZOiIJ/qDhZxrlKh8=", + "lastModified": 1675758091, + "narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "65fae659e31098ca4ac825a6fef26d890aaf3f4e", + "rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87", "type": "github" }, "original": { @@ -387,6 +690,68 @@ "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": { "flake": false, "locked": { @@ -406,7 +771,10 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": [ + "haskell-nix", + "flake-utils" + ], "haskell-nix": "haskell-nix", "nixpkgs": [ "haskell-nix", @@ -417,11 +785,11 @@ "stackage": { "flake": false, "locked": { - "lastModified": 1661925696, - "narHash": "sha256-eMM1dhdSv0AlLtD2cULJsLhJF4ZWdvpqRcCOw9DbXLI=", + "lastModified": 1677543037, + "narHash": "sha256-7CPQZZafTQiw7YL+a2KCamb9a3PU0do9iZKy1AaRkBo=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "575039e5410ef653e302d53938aa6df403e5a8b1", + "rev": "f4d29fa4403f45541d9f3993523df6027c21fe90", "type": "github" }, "original": { @@ -429,6 +797,113 @@ "repo": "stackage.nix", "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", diff --git a/flake.nix b/flake.nix index fba06a9..9a29da5 100644 --- a/flake.nix +++ b/flake.nix @@ -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 = { nixpkgs.follows = "haskell-nix/nixpkgs-unstable"; 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 }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; inherit (haskell-nix) config; overlays = [haskell-nix.overlay]; }; - project = pkgs.haskell-nix.cabalProject { - src = ./.; - compiler-nix-name = "ghc8107"; - shell.tools = { - cabal = {}; - hlint = {}; - haskell-language-server = {}; + + flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: + let + pkgs = import nixpkgs { + inherit system; + inherit (haskell-nix) config; + overlays = [ haskell-nix.overlay ]; }; - shell.buildInputs = with pkgs; [ - nixpkgs-fmt - fsatrace - ]; - modules = [{ - packages.foliage.components.exes.foliage.dontStrip = false; - }]; - }; - in { - packages.default = project.foliage.components.exes.foliage; - devShell = pkgs.mkShell { - name = "foliage-dev-shell"; - buildInputs = with pkgs; [ - fsatrace - ]; - }; - }); + + pkgs-static-where-possible = + if pkgs.stdenv.hostPlatform.isLinux then + if pkgs.stdenv.hostPlatform.isAarch64 then + pkgs.pkgsCross.aarch64-multiplatform-musl + else + pkgs.pkgsCross.musl64 + else + pkgs; + + project = pkgs-static-where-possible.haskell-nix.cabalProject' { + src = ./.; + compiler-nix-name = "ghc926"; + }; + + flake = project.flake { }; + + in + flake // { packages.default = flake.packages."foliage:exe:foliage"; }); nixConfig = { extra-substituters = [ "https://cache.iog.io" "https://foliage.cachix.org" + "https://cache.zw3rk.com" ]; extra-trusted-public-keys = [ "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" "foliage.cachix.org-1:kAFyYLnk8JcRURWReWZCatM9v3Rk24F5wNMpEj14Q/g=" + "loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk=" ]; }; } diff --git a/foliage.cabal b/foliage.cabal index 7715b4f..c89401c 100644 --- a/foliage.cabal +++ b/foliage.cabal @@ -27,6 +27,7 @@ executable foliage Foliage.Meta.Aeson Foliage.Options Foliage.Pages + Foliage.PreparePackageVersion Foliage.PrepareSource Foliage.PrepareSdist Foliage.RemoteAsset @@ -34,13 +35,13 @@ executable foliage Foliage.Time Foliage.UpdateCabalFile Foliage.Utils.Aeson + Foliage.Utils.GitHub Network.URI.Orphans - default-language: Haskell2010 - default-extensions: - ImportQualifiedPost LambdaCase NamedFieldPuns ViewPatterns + default-language: GHC2021 ghc-options: -Wall + ghc-options: -threaded build-depends: base >=4.14.3.0 && <4.18, aeson >=2.0.3.0 && <2.2, diff --git a/templates/packageVersion.mustache b/templates/packageVersion.mustache index a25ea9a..91b95e6 100644 --- a/templates/packageVersion.mustache +++ b/templates/packageVersion.mustache @@ -42,28 +42,26 @@
License

{{license}}

{{/pkgDesc}} - {{#pkgSpec}} - {{#packageVersionSource}} + {{#pkgVersionSource}}
Source
{{> packageVersionSource}}
- {{/packageVersionSource}} + {{/pkgVersionSource}}
Timestamp
-

{{packageVersionTimestamp}}

+

{{pkgTimestamp}}

Revisions
- {{#packageVersionRevisions}} -

{{revisionTimestamp}}

- {{/packageVersionRevisions}} - {{^packageVersionRevisions}} + {{#cabalFileRevisions}} +

{{.}}

+ {{/cabalFileRevisions}} + {{^cabalFileRevisions}}

None

- {{/packageVersionRevisions}} + {{/cabalFileRevisions}}
- {{/pkgSpec}}