stack-all 0.3 → 0.3.1
raw patch · 6 files changed
+99/−102 lines, 6 filesdep +cached-json-filedep −bytestringdep −timedep −xdg-basedir
Dependencies added: cached-json-file
Dependencies removed: bytestring, time, xdg-basedir
Files
- ChangeLog.md +6/−0
- README.md +33/−27
- src/Main.hs +50/−35
- src/MajorVer.hs +2/−2
- src/Snapshots.hs +4/−32
- stack-all.cabal +4/−6
ChangeLog.md view
@@ -1,5 +1,11 @@ # Release history for stack-all +## 0.3.1 (2021-09-06)+- newest LTS for a project can now be configured+- use cached-json-file for snapshots.json+- add --keep-going+- exclude lts17 now by default+ ## 0.3 (2021-06-26) - use hackage.stackage.org/snapshots.json: - to determine the latest LTS major version
README.md view
@@ -2,13 +2,13 @@ A CLI tool for building Haskell projects easily over Stackage major versions. -This is how I do my Haskell "build ci" now locally.+This is how I do my Haskell build CI for projects locally with stack. ## Usage `stack-all` by default runs `stack build` over recent Stackage LTS major versions and Nightly-(current default is nightly, lts-18, lts-17, lts-16, lts-14,... , lts-11)+(current default is nightly & LTS 18, 16, 14, 13, 12, 11) corresponding to latest major ghc minor versions, using the stack's `--resolver` option. @@ -19,24 +19,42 @@ ### Overriding stack.yaml `stack-all` can use `stack-ltsXX.yaml` files to override the default `stack.yaml`-file for particular lts major versions. Note that a `stack-ltsXX.yaml` file-will also be used for older lts major versions until+file for particular LTS major versions. Note that a `stack-ltsXX.yaml` file+will also be used for older LTS major versions until another `stack-ltsYY.yaml` file is found. For example if you have `stack-lts14.yaml` and `stack-lts12.yaml` files in your project,-then `stack.yaml` will be used as normal to build nightly, lts-17 and lts-16,+then `stack.yaml` will be used as normal to build nightly, lts-18 and lts-16, but `stack-lts14.yaml` will be used for building lts-14 and lts-13, and `stack-lts12.yaml` will be used for lts-12, lts-11 (and older). Since `stack-all` overrides the resolver with `--resolver lts-XX`-the exact minor lts version specified in the `stack*.yaml` files+the exact minor LTS version specified in the `stack*.yaml` files doesn't actually matter: `stack-all` always uses the latest minor release of-the lts major version according to Stackage.+the LTS major version according to Stackage. +`stack-ltsXX.yaml` files can be easily prepared using+`stack-all --make-lts ltsXX` (or `-s ltsXX` for short).+ (Other versioned stack.yaml filenames like stack-ghc-8.8.yaml are not currently supported.) -### Configuring the oldest lts to build+### Specifying LTS versions+You can abbreviate `lts-XX` args to `ltsXX` on the commandline.++There are `--oldest` and `--newest` options to specify the range of+lts versions to build over:++You can specify the oldest major LTS to build for with eg `stack-all -o lts13`.+Otherwise if not configured the default oldest LTS is currently `lts-11`.++Similarly you can specify the newest LTS version to build from with+eg `stack-all -n lts16`. (The default is to build from nightly.)++Alternatively, one can give one or more explicit LTS major versions to build for+as arguments: eg `stack-all lts14` if you only wish to build that version.++### Configuring the oldest and/or newest LTS to build You can configure the oldest working LTS major version for your project by running for example `stack-all -c -o lts-13` which generates a `.stack-all` project config file like this:@@ -45,28 +63,16 @@ # lts-12 too old oldest = lts-13 ```-(the comment line can be used to document why the older lts doesn't work).-This specifies that the oldest lts version to build for is lts-13.--### Specifying lts versions-You can abbreviate `lts-XX` args to `ltsXX` on the commandline.--There are `--oldest` and `--newest` options to specify the range of-lts versions to build over:--You can specify the oldest major lts to build for with eg `stack-all -o lts13`.-Otherwise if not configured the default oldest lts is currently `lts-11`.--Similarly you can specify the newest lts version to build from with-`stack-all -n lts16`. (The default is to build from nightly.)+(the comment line can be used to document why the older LTS doesn't work).+This specifies that the oldest LTS version to build for is lts-13. -Alternatively, one can give one or more explicit lts major versions to build for-as arguments: eg `stack-all lts14` if you only wish to build that version.+The newest LTS to build with stack-all can similarly be configured:+`stack-all -c -n lts18` or setting `newest = lts-18`. ### Running other stack commands-By default `stack-all` just runs the stack `build` command over lts versions.+By default `stack-all` just runs the stack `build` command over LTS versions. -You can also specify the stack command to run and its options on the commandline:+You can also specify a stack command to run with options on the commandline: eg ``` $ stack-all test --no-rerun-tests@@ -78,7 +84,7 @@ ## Install The project is released on Hackage. -You can also build from source with `stack install` or `cabal install`.+You can also build from git source with `stack install` or `cabal install`. ## Collaboration The project is hosted at https://github.com/juhp/stack-all under a BSD license.
src/Main.hs view
@@ -19,8 +19,8 @@ import Paths_stack_all (version) import Snapshots -defaultOldest :: MajorVer-defaultOldest = LTS 11+defaultOldestLTS :: MajorVer+defaultOldestLTS = LTS 11 data VersionLimit = DefaultLimit | Oldest MajorVer | AllVersions @@ -34,20 +34,22 @@ run <$> (flagWith' CreateConfig 'c' "create-config" "Create a project .stack-all file" <|> flagWith DefaultRun MakeStackLTS 's' "make-lts" "Create a stack-ltsXX.yaml file") <*>+ switchWith 'k' "keep-going" "Keep going even if an LTS fails" <*> switchWith 'd' "debug" "Verbose stack build output on error" <*> optional (readMajor <$> strOptionWith 'n' "newest" "MAJOR" "Newest LTS release to build from") <*> (Oldest . readMajor <$> strOptionWith 'o' "oldest" "MAJOR" "Oldest compatible LTS release" <|> flagWith DefaultLimit AllVersions 'a' "all-lts" "Try to build back to LTS 1 even") <*> many (strArg "MAJORVER... [COMMAND...]") -run :: Command -> Bool -> Maybe MajorVer -> VersionLimit -> [String] -> IO ()-run command debug mnewest verlimit verscmd = do+run :: Command -> Bool ->Bool -> Maybe MajorVer -> VersionLimit -> [String]+ -> IO ()+run command keepgoing debug mnewest verlimit verscmd = do findStackProjectDir Nothing case command of CreateConfig -> case verlimit of- Oldest oldest -> createStackAll oldest- _ -> error' "creating .stack-all requires --oldest LTS"+ Oldest oldest -> createStackAll (Just oldest) mnewest+ _ -> createStackAll Nothing mnewest MakeStackLTS -> do (versions, _) <- getVersionsCmd if null versions@@ -57,7 +59,7 @@ (versions, cargs) <- getVersionsCmd configs <- mapMaybe readStackConf <$> listDirectory "." let newestFilter = maybe id (filter . (>=)) mnewest- mapM_ (stackBuild configs debug cargs) (newestFilter versions)+ mapM_ (stackBuild configs keepgoing debug cargs) (newestFilter versions) where findStackProjectDir :: Maybe FilePath -> IO () findStackProjectDir mcwd = do@@ -79,7 +81,7 @@ -- FIXME stack init content too verbose unlessM (cmdBool "stack" ["init"]) $ -- FIXME determine latest stable snapshot automatically- writeFile "stack.yaml" "resolver: lts-17.15\n"+ writeFile "stack.yaml" "resolver: lts-18.8\n" else error' "no package/project found" getVersionsCmd :: IO ([MajorVer],[String])@@ -91,17 +93,20 @@ if null verlist then case verlimit of DefaultLimit -> do- oldest <- fromMaybeM (return defaultOldest) readOldestLTS+ (newestLTS, oldestLTS) <- readNewestOldestLTS return $ case mnewest of Just newest ->- if newest < oldest- then filter (newest >=) allMajors- else filter (\ s -> s >= oldest && newest >= s) allMajors- Nothing -> filter (>= oldest) allMajors+ if newest < oldestLTS+ then filter (inRange newest (LTS 1)) allMajors+ else filter (inRange newest oldestLTS) allMajors+ Nothing -> filter (inRange newestLTS oldestLTS) allMajors AllVersions -> return allMajors- Oldest ver -> return $ filter (>= ver) allMajors+ Oldest ver -> return $ filter (inRange Nightly ver) allMajors else return verlist return (versions,if null cmds then ["build"] else cmds)+ where+ inRange :: MajorVer -> MajorVer -> MajorVer -> Bool+ inRange newest oldest v = v >= oldest && v <= newest readStackConf :: FilePath -> Maybe MajorVer readStackConf "stack-lts.yaml" = error' "unversioned stack-lts.yaml is unsupported"@@ -111,34 +116,44 @@ stackAllFile :: FilePath stackAllFile = ".stack-all" -createStackAll :: MajorVer -> IO ()-createStackAll ver = do+createStackAll :: Maybe MajorVer -> Maybe MajorVer -> IO ()+createStackAll Nothing Nothing =+ error' "creating .stack-all requires --oldest LTS and/or --newest LTS"+createStackAll moldest mnewest = do exists <- doesFileExist stackAllFile if exists then error' $ stackAllFile ++ " already exists" else do allMajors <- getMajorVers- let older =- let molder = listToMaybe $ dropWhile (>= ver) allMajors- in maybe "" (\s -> showMajor s ++ " too old") molder writeFile stackAllFile $- "[versions]\n# " ++ older ++ "\noldest = " ++ showMajor ver ++ "\n"+ "[versions]\n" +++ case mnewest of+ Nothing -> ""+ Just newest ->+ "newest = " ++ showMajor newest ++ "\n"+ +++ case moldest of+ Nothing -> ""+ Just oldest ->+ let older =+ let molder = listToMaybe $ dropWhile (>= oldest) allMajors+ in maybe "" (\s -> showMajor s ++ " too old") molder+ in "# " ++ older ++ "\noldest = " ++ showMajor oldest ++ "\n" -readOldestLTS :: IO (Maybe MajorVer)-readOldestLTS = do+readNewestOldestLTS :: IO (MajorVer,MajorVer)+readNewestOldestLTS = do haveConfig <- doesFileExist stackAllFile if haveConfig then- Just . readMajor <$> readIniConfig stackAllFile rcParser id- else return Nothing+ readIniConfig stackAllFile $+ section "versions" $ do+ mnewest <- fmap readMajor <$> fieldMbOf "newest" string+ moldest <- fmap readMajor <$> fieldMbOf "oldest" string+ return (fromMaybe Nightly mnewest, fromMaybe defaultOldestLTS moldest)+ else return (Nightly, defaultOldestLTS) where- rcParser :: IniParser String- rcParser =- section "versions" $- fieldOf "oldest" string-- readIniConfig :: FilePath -> IniParser a -> (a -> b) -> IO b- readIniConfig inifile iniparser fn = do+ readIniConfig :: FilePath -> IniParser a -> IO a+ readIniConfig inifile iniparser = do ini <- T.readFile inifile- return $ either error fn $ parseIniFile ini iniparser+ return $ either error id $ parseIniFile ini iniparser makeStackLTS :: [MajorVer] -> IO () makeStackLTS vers = do@@ -162,8 +177,8 @@ compactMajor Nightly = "nightly" compactMajor (LTS ver) = "lts" ++ show ver -stackBuild :: [MajorVer] -> Bool -> [String] -> MajorVer -> IO ()-stackBuild configs debug command ver = do+stackBuild :: [MajorVer] -> Bool -> Bool -> [String] -> MajorVer -> IO ()+stackBuild configs keepgoing debug command ver = do let config = case sort (filter (ver <=) configs) of [] -> []@@ -178,7 +193,7 @@ then debugBuild $ opts ++ command else do ok <- cmdBool "stack" $ opts ++ command- unless ok $ do+ unless (ok || keepgoing) $ do putStr "\nsnapshot-pkg-db: " cmd_ "stack" $ "--silent" : opts ++ ["path", "--snapshot-pkg-db"] error' $ "failed for " ++ showMajor ver
src/MajorVer.hs view
@@ -34,7 +34,7 @@ case maybeReadMajor ver of Just s -> s Nothing ->- error' $ "couldn't parse " ++ ver ++ " (expected lts-XX or ltsXX)"+ error' $! "couldn't parse " ++ ver ++ " (expected lts-XX or ltsXX)" -- readCompactMajor "lts16" readCompactMajor :: String -> Maybe MajorVer@@ -43,7 +43,7 @@ if "lts" `isPrefixOf` ver then case readMaybe (dropPrefix "lts" ver) of Just major -> Just (LTS major)- Nothing -> error' $ "couldn't parse compact " ++ ver ++ " (expected ltsXX)"+ Nothing -> error' $! "couldn't parse compact " ++ ver ++ " (expected ltsXX)" else Nothing eitherReadMajor :: String -> Either String MajorVer
src/Snapshots.hs view
@@ -6,23 +6,17 @@ ) where -import Control.Monad import Data.Aeson-import qualified Data.ByteString.Lazy.Char8 as B import Data.List.Extra import qualified Data.HashMap.Strict as H import qualified Data.Text as T-import Data.Time.Clock (diffUTCTime, getCurrentTime) import Network.HTTP.Query-import SimpleCmd (error')-import System.Directory-import System.Environment.XDG.BaseDir-import System.FilePath+import System.Cached.JSON import MajorVer excludedMajors :: [MajorVer]-excludedMajors = [LTS 15, LTS 7, LTS 3, LTS 0]+excludedMajors = [LTS 17, LTS 15, LTS 7, LTS 3, LTS 0] getMajorVers :: IO [MajorVer] getMajorVers = do@@ -33,28 +27,6 @@ latestSnapshot ver = do lookupKey (T.pack (showMajor ver)) <$> getSnapshots --- FIXME handle network failure getSnapshots :: IO Object-getSnapshots = do- file <- getUserCacheFile "stack-all" "snapshots.json"- exists <- doesFileExist file- unless exists $ do- putStrLn $ "Creating " ++ file ++ " ..."- createDirectoryIfMissing True (takeDirectory file)- recent <- do- if exists then do- ts <- getModificationTime file- t <- getCurrentTime- -- < 3 hours- return $ diffUTCTime t ts < 10000- else return False- if recent- then do- eobj <- eitherDecode <$> B.readFile file- case eobj of- Left err -> error' err- Right obj -> return obj- else do- obj <- webAPIQuery "http://haddock.stackage.org/snapshots.json" []- B.writeFile file $ encode obj- return obj+getSnapshots =+ getCachedJSON "stackage-snapshots" "snapshots.json" "http://haddock.stackage.org/snapshots.json" 200
stack-all.cabal view
@@ -1,5 +1,5 @@ name: stack-all-version: 0.3+version: 0.3.1 synopsis: CLI tool for building across Stackage major versions description: Build your Haskell project over Stackage major LTS versions.@@ -16,7 +16,7 @@ ChangeLog.md cabal-version: 1.18 tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,- GHC == 8.8.4, GHC == 8.10.4, GHC == 9.0.1+ GHC == 8.8.4, GHC == 8.10.5, GHC == 9.0.1 source-repository head type: git@@ -30,7 +30,7 @@ hs-source-dirs: src build-depends: base < 5, aeson,- bytestring,+ cached-json-file, config-ini, directory >= 1.2.5, extra >= 1.6.15,@@ -40,9 +40,7 @@ simple-cmd >= 0.1.4, simple-cmd-args, text,- time,- unordered-containers,- xdg-basedir+ unordered-containers default-language: Haskell2010 ghc-options: -Wall if impl(ghc >= 8.0)