1- {-# LANGUAGE NamedFieldPuns #-}
21{-# OPTIONS_GHC -Wno-name-shadowing #-}
32
43module Foliage.CmdBuild (cmdBuild ) where
@@ -8,8 +7,9 @@ import Codec.Archive.Tar.Entry qualified as Tar
87import Codec.Compression.GZip qualified as GZip
98import Control.Monad (unless , when )
109import Data.ByteString.Lazy qualified as BSL
10+ import Data.Char (isAlpha )
1111import Data.Foldable (for_ )
12- import Data.List (isPrefixOf , sortOn )
12+ import Data.List (dropWhileEnd , isPrefixOf , sortOn )
1313import Data.Maybe (fromMaybe )
1414import Data.Traversable (for )
1515import Development.Shake
@@ -21,8 +21,8 @@ import Foliage.Package
2121import Foliage.Shake
2222import Foliage.Shake.Oracle
2323import Foliage.Time qualified as Time
24- import Foliage.Utils
2524import System.Directory qualified as IO
25+ import System.FilePath.Posix qualified as Posix
2626
2727cmdBuild :: BuildOptions -> IO ()
2828cmdBuild
@@ -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+
404422mkTarEntry :: FilePath -> [Char ] -> UTCTime -> Action Tar. Entry
405423mkTarEntry 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 ()
421439applyPatches 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
432449forcePackageVersion :: FilePath -> PackageId -> Action ()
433450forcePackageVersion 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
0 commit comments