Skip to content

Commit d7f7854

Browse files
committed
Fix force-version implementation.
Now the tarballs are downloaded only once but now each package name and version is unpacked independently in its own directory. Then patches are applied there.
1 parent 4e333ef commit d7f7854

File tree

7 files changed

+161
-144
lines changed

7 files changed

+161
-144
lines changed

app/Foliage/CmdBuild.hs

Lines changed: 81 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
{-# LANGUAGE NamedFieldPuns #-}
21
{-# OPTIONS_GHC -Wno-name-shadowing #-}
32

43
module Foliage.CmdBuild (cmdBuild) where
@@ -8,8 +7,9 @@ import Codec.Archive.Tar.Entry qualified as Tar
87
import Codec.Compression.GZip qualified as GZip
98
import Control.Monad (unless, when)
109
import Data.ByteString.Lazy qualified as BSL
10+
import Data.Char (isAlpha)
1111
import Data.Foldable (for_)
12-
import Data.List (isPrefixOf, sortOn)
12+
import Data.List (dropWhileEnd, isPrefixOf, sortOn)
1313
import Data.Maybe (fromMaybe)
1414
import Data.Traversable (for)
1515
import Development.Shake
@@ -21,8 +21,8 @@ import Foliage.Package
2121
import Foliage.Shake
2222
import Foliage.Shake.Oracle
2323
import Foliage.Time qualified as Time
24-
import Foliage.Utils
2524
import System.Directory qualified as IO
25+
import System.FilePath.Posix qualified as Posix
2626

2727
cmdBuild :: BuildOptions -> IO ()
2828
cmdBuild
@@ -66,27 +66,51 @@ cmdBuild
6666
putInfo $ "🕐 Expiry time set to " <> Time.iso8601Show t <> " (a year from now)."
6767
return t
6868

69-
getSourceMeta <- addOracle $ \(GetSourceMeta PackageId {pkgName, pkgVersion}) ->
70-
readSourceMeta' $ inputDir </> pkgName </> pkgVersion </> "meta.toml"
69+
getPackageMeta <- addOracle $ \(GetPackageMeta PackageId {pkgName, pkgVersion}) ->
70+
readPackageMeta' $ inputDir </> pkgName </> pkgVersion </> "meta.toml"
7171

72-
getSourceDir <- addOracle $ \(GetSourceDir pkgId) -> do
73-
SourceMeta {sourceUrl, sourceSubdir, sourceForceVersion} <- getSourceMeta (GetSourceMeta pkgId)
74-
let urlDir = "_cache" </> urlToFileName sourceUrl
72+
preparePackageSource <- addOracle $ \(PreparePackageSource pkgId@PackageId {pkgName, pkgVersion}) -> do
73+
PackageMeta {packageSource, packageForceVersion} <- getPackageMeta (GetPackageMeta pkgId)
7574

76-
need [urlDir </> ".downloaded"]
77-
-- FIXME Without this, sometimes the download doesn't trigger
78-
putInfo $ "👀 " <> sourceUrl
75+
let srcDir = "_cache" </> "packages" </> pkgName </> pkgVersion
7976

80-
projectFiles <- liftIO $ filter ("cabal.project" `isPrefixOf`) <$> IO.getDirectoryContents urlDir
81-
unless (null projectFiles) $ do
82-
putWarn $ "⚠️ Deleting cabal project files from " ++ urlDir
83-
liftIO $ for_ projectFiles $ IO.removeFile . (urlDir </>)
77+
-- FIXME too much rework?
78+
-- this action only depends on the tarball and the package metadata
79+
80+
-- delete everything inside the package source tree
81+
liftIO $ do
82+
-- FIXME this should only delete inside srcDir but apparently
83+
-- also deletes srcDir itself
84+
removeFiles srcDir ["//*"]
85+
IO.createDirectoryIfMissing True srcDir
86+
87+
case packageSource of
88+
TarballSource url mSubdir -> do
89+
tarballPath <- fetchUrl url
90+
91+
withTempDir $ \tmpDir -> do
92+
cmd_ ["tar", "xzf", tarballPath, "-C", tmpDir]
8493

85-
let srcDir = case sourceSubdir of
86-
Just s -> urlDir </> s
87-
Nothing -> urlDir
94+
-- Special treatment of top-level directory: we remove it
95+
--
96+
-- Note: Don't let shake look into tmpDir! it will cause
97+
-- unnecessary rework because tmpDir is always new
98+
ls <- liftIO $ IO.getDirectoryContents tmpDir
99+
let ls' = filter (not . all (== '.')) ls
100+
101+
let fix1 = case ls' of [l] -> (</> l); _ -> id
102+
fix2 = case mSubdir of Just s -> (</> s); _ -> id
103+
tdir = fix2 $ fix1 tmpDir
104+
105+
cmd_ ["cp", "--recursive", "--no-target-directory", "--dereference", tdir, srcDir]
106+
107+
-- Delete cabal.project files if present
108+
projectFiles <- liftIO $ filter ("cabal.project" `isPrefixOf`) <$> IO.getDirectoryContents srcDir
109+
unless (null projectFiles) $ do
110+
putWarn $ "⚠️ Deleting cabal project files from " ++ srcDir
111+
liftIO $ for_ projectFiles $ IO.removeFile . (srcDir </>)
88112

89-
when sourceForceVersion $
113+
when packageForceVersion $
90114
forcePackageVersion srcDir pkgId
91115

92116
applyPatches inputDir srcDir pkgId
@@ -257,29 +281,29 @@ cmdBuild
257281
fmap concat $
258282
for pkgIds $ \pkgId -> do
259283
let PackageId {pkgName, pkgVersion} = pkgId
260-
SourceMeta {sourceTimestamp, sourceRevisions} <- getSourceMeta (GetSourceMeta pkgId)
284+
PackageMeta {packageTimestamp, packageRevisions} <- getPackageMeta (GetPackageMeta pkgId)
261285

262-
srcDir <- getSourceDir (GetSourceDir pkgId)
286+
srcDir <- preparePackageSource $ PreparePackageSource pkgId
263287
now <- getCurrentTime GetCurrentTime
264288

265289
sequence $
266290
[ -- original cabal file
267291
mkTarEntry
268292
(srcDir </> pkgName <.> "cabal")
269293
(pkgName </> pkgVersion </> pkgName <.> "cabal")
270-
(fromMaybe now sourceTimestamp),
294+
(fromMaybe now packageTimestamp),
271295
-- package.json
272296
mkTarEntry
273297
(outputDir </> "index" </> pkgName </> pkgVersion </> "package.json")
274298
(pkgName </> pkgVersion </> "package.json")
275-
(fromMaybe now sourceTimestamp)
299+
(fromMaybe now packageTimestamp)
276300
]
277301
++ [ -- revised cabal files
278302
mkTarEntry
279303
(inputDir </> pkgName </> pkgVersion </> "revisions" </> show revNum <.> "cabal")
280304
(pkgName </> pkgVersion </> pkgName <.> "cabal")
281305
(fromMaybe now revTimestamp)
282-
| RevisionMeta revTimestamp revNum <- sourceRevisions
306+
| RevisionMeta revTimestamp revNum <- packageRevisions
283307
]
284308

285309
liftIO $ BSL.writeFile path $ Tar.write (sortOn Tar.entryTime entries)
@@ -295,23 +319,24 @@ cmdBuild
295319
putInfo $ "✅ Written " <> path
296320

297321
--
298-
-- index cabal files (latest revision)
322+
-- index cabal files
323+
--
324+
-- these come either from the package source or the revision files
299325
--
300326

301327
outputDir </> "index/*/*/*.cabal" %> \path -> do
302328
let [_, _, pkgName, pkgVersion, _] = splitDirectories path
303329
let pkgId = PackageId pkgName pkgVersion
304330

305-
-- Figure out where to get it from
306-
meta <- getSourceMeta $ GetSourceMeta pkgId
331+
meta <- getPackageMeta $ GetPackageMeta pkgId
307332

308333
case latestRevisionNumber meta of
309334
Nothing -> do
310-
srcDir <- getSourceDir (GetSourceDir pkgId)
335+
srcDir <- preparePackageSource $ PreparePackageSource pkgId
311336
copyFileChanged (srcDir </> pkgName <.> "cabal") path
312337
Just revNum -> do
313-
let revisionCabal = inputDir </> pkgName </> pkgVersion </> "revisions" </> show revNum <.> "cabal"
314-
copyFileChanged revisionCabal path
338+
let revisionFile = inputDir </> pkgName </> pkgVersion </> "revisions" </> show revNum <.> "cabal"
339+
copyFileChanged revisionFile path
315340

316341
putInfo $ "✅ Written " <> path
317342

@@ -343,17 +368,19 @@ cmdBuild
343368
putInfo $ "✅ Written " <> path
344369

345370
--
346-
-- source distributions
371+
-- source distributions, including patching
347372
--
348373

349374
outputDir </> "package/*.tar.gz" %> \path -> do
350375
let [_, _, filename] = splitDirectories path
351376
let Just pkgId = parsePkgId <$> stripExtension "tar.gz" filename
352377

353-
srcDir <- getSourceDir (GetSourceDir pkgId)
378+
srcDir <- preparePackageSource $ PreparePackageSource pkgId
379+
putInfo srcDir
354380

355381
withTempDir $ \tmpDir -> do
356-
putInfo $ " Creating source distribution for " <> pkgIdToString pkgId
382+
putInfo $ "Creating source distribution for " <> pkgIdToString pkgId
383+
357384
cmd_ Shell (Cwd srcDir) (FileStdout path) ("cabal sdist --ignore-project --output-directory " <> tmpDir)
358385

359386
-- check cabal sdist has produced a single tarball with the
@@ -373,34 +400,25 @@ cmdBuild
373400
putInfo $ "✅ Written " <> path
374401

375402
--
376-
-- source tree downloads
403+
-- tarball downloads
377404
--
378405

379-
"_cache/*/.downloaded" %> \path -> do
380-
let [_, hashedUrl, _] = splitDirectories path
381-
let url = fileNameToUrl hashedUrl
382-
let srcDir = takeDirectory path
383-
384-
withTempDir $ \tmpDir -> do
385-
-- Download and extract tarball
386-
putInfo $ "🐢 Downloading " <> url
387-
cmd_ Shell $ "curl --silent -L " <> url <> " | tar xz -C " <> tmpDir
388-
389-
-- Special treatment of top-level directory: we remove it
390-
--
391-
-- Note: Don't let shake look into tmpDir! it will cause
392-
-- unnecessary rework because tmpDir is always new
393-
ls <- liftIO $ IO.getDirectoryContents tmpDir
394-
let ls' = filter (not . all (== '.')) ls
395-
case ls' of
396-
[l] -> cmd_ Shell ["mv", "-T", tmpDir </> l, srcDir]
397-
_ -> cmd_ Shell ["mv", "-T", tmpDir, srcDir]
398-
399-
-- Touch the trigger file
400-
writeFile' path ""
406+
"_cache/downloads/**" %> \path -> do
407+
let scheme : rest = drop 2 $ splitDirectories path
408+
let url = scheme <> "://" <> Posix.joinPath rest
409+
putInfo $ "🐢 Downloading " <> url
410+
cmd_ Shell (FileStdout path) $ "curl --silent -L " <> url
401411

402412
putStrLn $ "💥 All done. The repository is now available in " <> outputDir <> "."
403413

414+
fetchUrl :: String -> Action FilePath
415+
fetchUrl url = do
416+
let scheme : rest = Posix.splitPath url
417+
scheme' = dropWhileEnd (not . isAlpha) scheme
418+
urlPath = "_cache" </> "downloads" </> joinPath (scheme' : rest)
419+
need [urlPath]
420+
return urlPath
421+
404422
mkTarEntry :: FilePath -> [Char] -> UTCTime -> Action Tar.Entry
405423
mkTarEntry filePath indexPath timestamp = do
406424
let Right tarPath = Tar.toTarPath False indexPath
@@ -417,17 +435,16 @@ mkTarEntry filePath indexPath timestamp = do
417435
}
418436
}
419437

420-
applyPatches :: FilePath -> FilePath -> PackageId -> Action ()
438+
applyPatches :: [Char] -> FilePath -> PackageId -> Action ()
421439
applyPatches inputDir srcDir PackageId {pkgName, pkgVersion} = do
422440
let patchesDir = inputDir </> pkgName </> pkgVersion </> "patches"
423441
hasPatches <- doesDirectoryExist patchesDir
424442

425443
when hasPatches $ do
426-
patches <- getDirectoryFiles (inputDir </> pkgName </> pkgVersion </> "patches") ["*.patch"]
427-
for_ patches $ \patch -> do
428-
let patchfile = inputDir </> pkgName </> pkgVersion </> "patches" </> patch
429-
putInfo $ "Applying patch: " <> patch
430-
cmd_ Shell (Cwd srcDir) (FileStdin patchfile) "patch --backup -p1"
444+
patchfiles <- getDirectoryFiles patchesDir ["*.patch"]
445+
for_ patchfiles $ \patchfile -> do
446+
let patch = patchesDir </> patchfile
447+
cmd_ Shell (Cwd srcDir) (FileStdin patch) "patch -p1"
431448

432449
forcePackageVersion :: FilePath -> PackageId -> Action ()
433450
forcePackageVersion srcDir PackageId {pkgName, pkgVersion} = do
@@ -442,7 +459,7 @@ replaceVersion version = unlines . map f . lines
442459
| "version" `isPrefixOf` line =
443460
unlines
444461
[ "-- version field replaced by foliage",
445-
"--" <> line,
446-
"version:\t" ++ version
462+
"-- " <> line,
463+
"version: " ++ version
447464
]
448465
f line = line

app/Foliage/CmdImportHackage.hs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ importIndex ::
4040
Show e =>
4141
(PackageId -> Bool) ->
4242
Tar.Entries e ->
43-
Map PackageId SourceMeta ->
44-
IO (Map PackageId SourceMeta)
43+
Map PackageId PackageMeta ->
44+
IO (Map PackageId PackageMeta)
4545
importIndex f (Tar.Next e es) m =
4646
case isCabalFile e of
4747
Just (pkgId, contents, time)
@@ -55,19 +55,18 @@ importIndex f (Tar.Next e es) m =
5555
Nothing ->
5656
pure $
5757
Just $
58-
SourceMeta
59-
{ sourceUrl = pkgIdToHackageUrl pkgId,
60-
sourceTimestamp = Just time,
61-
sourceSubdir = Nothing,
62-
sourceRevisions = [],
63-
sourceForceVersion = False
58+
PackageMeta
59+
{ packageSource = TarballSource (pkgIdToHackageUrl pkgId) Nothing,
60+
packageTimestamp = Just time,
61+
packageRevisions = [],
62+
packageForceVersion = False
6463
}
6564
-- Existing package, new revision
6665
Just sm -> do
6766
let revnum = 1 + fromMaybe 0 (latestRevisionNumber sm)
6867
newRevision = RevisionMeta {revisionNumber = revnum, revisionTimestamp = Just time}
6968
-- bad performance here but I don't care
70-
let sm' = sm {sourceRevisions = sourceRevisions sm ++ [newRevision]}
69+
let sm' = sm {packageRevisions = packageRevisions sm ++ [newRevision]}
7170
let PackageId pkgName pkgVersion = pkgId
7271
let outDir = "_sources" </> pkgName </> pkgVersion </> "revisions"
7372
IO.createDirectoryIfMissing True outDir
@@ -85,12 +84,12 @@ importIndex _f (Tar.Fail e) _ =
8584

8685
finalise ::
8786
PackageId ->
88-
SourceMeta ->
87+
PackageMeta ->
8988
IO ()
9089
finalise PackageId {pkgName, pkgVersion} meta = do
9190
let dir = "_sources" </> pkgName </> pkgVersion
9291
IO.createDirectoryIfMissing True dir
93-
writeSourceMeta (dir </> "meta.toml") meta
92+
writePackageMeta (dir </> "meta.toml") meta
9493

9594
isCabalFile ::
9695
Tar.Entry ->

0 commit comments

Comments
 (0)