diff --git a/bin/spago.yaml b/bin/spago.yaml index 287b882f7..17712c3d7 100644 --- a/bin/spago.yaml +++ b/bin/spago.yaml @@ -3,9 +3,11 @@ package: publish: version: 0.93.19 license: BSD-3-Clause + build: + censor_project_warnings: + - WildcardInferredType dependencies: - aff - - optparse - arrays - codec-argonaut - console @@ -14,6 +16,7 @@ package: - node-fs - node-path - node-process + - optparse - ordered-collections - record - refs diff --git a/bin/src/Flags.purs b/bin/src/Flags.purs index 077f77006..1fad6f760 100644 --- a/bin/src/Flags.purs +++ b/bin/src/Flags.purs @@ -164,6 +164,13 @@ transitive = <> O.help "Include transitive dependencies" ) +pure :: Parser Boolean +pure = + O.switch + ( O.long "pure" + <> O.help "Use the package information from the current lockfile, even if it is out of date" + ) + pedanticPackages :: Parser Boolean pedanticPackages = O.switch diff --git a/bin/src/Main.purs b/bin/src/Main.purs index dcefd18f7..be4989e3d 100644 --- a/bin/src/Main.purs +++ b/bin/src/Main.purs @@ -10,11 +10,11 @@ import Data.Array.NonEmpty as NonEmptyArray import Data.Codec.Argonaut.Common as CA.Common import Data.Foldable as Foldable import Data.List as List -import Data.Map as Map import Data.Maybe as Maybe import Data.Set as Set import Data.String as String import Effect.Aff as Aff +import Effect.Aff.AVar as AVar import Effect.Now as Now import Node.Path as Path import Node.Process as Process @@ -22,16 +22,11 @@ import Options.Applicative (CommandFields, Mod, Parser, ParserPrefs(..)) import Options.Applicative as O import Optparse as Optparse import Record as Record -import Registry.Constants as Registry.Constants -import Registry.ManifestIndex as ManifestIndex -import Registry.Metadata as Metadata import Registry.PackageName as PackageName -import Registry.Version as Version import Spago.Bin.Flags as Flags import Spago.Command.Build as Build import Spago.Command.Bundle as Bundle import Spago.Command.Docs as Docs -import Spago.Command.Uninstall as Uninstall import Spago.Command.Fetch as Fetch import Spago.Command.Graph (GraphModulesArgs, GraphPackagesArgs) import Spago.Command.Graph as Graph @@ -45,6 +40,7 @@ import Spago.Command.Repl as Repl import Spago.Command.Run as Run import Spago.Command.Sources as Sources import Spago.Command.Test as Test +import Spago.Command.Uninstall as Uninstall import Spago.Command.Upgrade as Upgrade import Spago.Config (BundleConfig, BundlePlatform(..), BundleType(..), PackageMap, RunConfig, TestConfig) import Spago.Config as Config @@ -75,12 +71,16 @@ type InitArgs = , useSolver :: Boolean } -type FetchArgs = - { packages :: List String +type FetchArgsRow a = + ( packages :: List String , selectedPackage :: Maybe String , ensureRanges :: Boolean , testDeps :: Boolean - } + , pure :: Boolean + | a + ) + +type FetchArgs a = Record (FetchArgsRow a) type InstallArgs = { packages :: List String @@ -91,6 +91,7 @@ type InstallArgs = , pedanticPackages :: Boolean , ensureRanges :: Boolean , testDeps :: Boolean + , pure :: Boolean } type UninstallArgs = @@ -109,6 +110,7 @@ type BuildArgs a = , jsonErrors :: Boolean , strict :: Maybe Boolean , statVerbosity :: Maybe Core.StatVerbosity + , pure :: Boolean | a } @@ -136,6 +138,7 @@ type RunArgs = , ensureRanges :: Boolean , strict :: Maybe Boolean , statVerbosity :: Maybe Core.StatVerbosity + , pure :: Boolean } type TestArgs = @@ -147,6 +150,7 @@ type TestArgs = , execArgs :: Maybe (Array String) , strict :: Maybe Boolean , statVerbosity :: Maybe Core.StatVerbosity + , pure :: Boolean } type SourcesArgs = @@ -170,6 +174,7 @@ type BundleArgs = , ensureRanges :: Boolean , strict :: Maybe Boolean , statVerbosity :: Maybe Core.StatVerbosity + , pure :: Boolean } type PublishArgs = @@ -184,7 +189,7 @@ data Command a = Build (BuildArgs a) | Bundle BundleArgs | Docs DocsArgs - | Fetch FetchArgs + | Fetch (FetchArgs a) | Init InitArgs | Install InstallArgs | Uninstall UninstallArgs @@ -287,13 +292,14 @@ initArgsParser = , useSolver: Flags.useSolver } -fetchArgsParser :: Parser FetchArgs +fetchArgsParser :: Parser (FetchArgs ()) fetchArgsParser = Optparse.fromRecord { packages: Flags.packages , selectedPackage: Flags.selectedPackage , ensureRanges: Flags.ensureRanges , testDeps: Flags.testDeps + , pure: Flags.pure } sourcesArgsParser :: Parser SourcesArgs @@ -314,6 +320,7 @@ installArgsParser = , pedanticPackages: Flags.pedanticPackages , ensureRanges: Flags.ensureRanges , testDeps: Flags.testDeps + , pure: Flags.pure } uninstallArgsParser :: Parser UninstallArgs @@ -335,6 +342,7 @@ buildArgsParser = Optparse.fromRecord , jsonErrors: Flags.jsonErrors , strict: Flags.strict , statVerbosity: Flags.statVerbosity + , pure: Flags.pure } replArgsParser :: Parser ReplArgs @@ -356,6 +364,7 @@ runArgsParser = Optparse.fromRecord , ensureRanges: Flags.ensureRanges , strict: Flags.strict , statVerbosity: Flags.statVerbosity + , pure: Flags.pure } testArgsParser :: Parser TestArgs @@ -368,6 +377,7 @@ testArgsParser = Optparse.fromRecord , pedanticPackages: Flags.pedanticPackages , strict: Flags.strict , statVerbosity: Flags.statVerbosity + , pure: Flags.pure } bundleArgsParser :: Parser BundleArgs @@ -388,6 +398,7 @@ bundleArgsParser = , ensureRanges: Flags.ensureRanges , strict: Flags.strict , statVerbosity: Flags.statVerbosity + , pure: Flags.pure } publishArgsParser :: Parser PublishArgs @@ -463,6 +474,7 @@ lsPathsArgsParser = Optparse.fromRecord lsPackagesArgsParser :: Parser LsPackagesArgs lsPackagesArgsParser = Optparse.fromRecord { json: Flags.json + , pure: Flags.pure } lsDepsArgsParser :: Parser LsDepsArgs @@ -470,6 +482,7 @@ lsDepsArgsParser = Optparse.fromRecord { json: Flags.json , transitive: Flags.transitive , selectedPackage: Flags.selectedPackage + , pure: Flags.pure } data Cmd a = Cmd'SpagoCmd (SpagoCmd a) | Cmd'VersionCmd Boolean @@ -487,7 +500,10 @@ parseArgs = do ( O.info ( O.helper <*> ( (Cmd'SpagoCmd <$> argParser) <|> - (Cmd'VersionCmd <$> (O.switch (O.long "version" <> O.short 'v' <> O.help "Show the current version"))) + ( Cmd'VersionCmd <$> + ( O.flag' true (O.long "version" <> O.short 'v' <> O.help "Show the current version") + ) + ) ) ) (O.progDesc "PureScript package manager and build tool") @@ -508,6 +524,8 @@ main = do , selectedPackage: args.selectedPackage , ensureRanges: false , testDeps: false + , isRepl: false + , pure: false } void $ runSpago env (Sources.run { json: args.json }) Init args@{ useSolver } -> do @@ -528,7 +546,7 @@ main = do logInfo "Set up a new Spago project." logInfo "Try running `spago run`" Fetch args -> do - { env, fetchOpts } <- mkFetchEnv offline args + { env, fetchOpts } <- mkFetchEnv offline (Record.merge { isRepl: false } args) void $ runSpago env (Fetch.run fetchOpts) RegistrySearch args -> do env <- mkRegistryEnv offline @@ -539,8 +557,8 @@ main = do RegistryPackageSets args -> do env <- mkRegistryEnv offline void $ runSpago env (RegistryCmd.packageSets args) - Install args@{ packages, selectedPackage, ensureRanges, testDeps } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages, selectedPackage, ensureRanges, testDeps } + Install args -> do + { env, fetchOpts } <- mkFetchEnv offline (Record.merge args { isRepl: false }) dependencies <- runSpago env (Fetch.run fetchOpts) let buildArgs = Record.merge @@ -552,17 +570,17 @@ main = do let options = { depsOnly: true, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false } runSpago env' (Build.run options) Uninstall { packagesToRemove, selectedPackage, testDeps } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: packagesToRemove, selectedPackage, ensureRanges: false, testDeps: false } + { env, fetchOpts } <- mkFetchEnv offline { packages: packagesToRemove, selectedPackage, ensureRanges: false, testDeps: false, isRepl: false, pure: false } let options = { testDeps, dependenciesToRemove: Set.fromFoldable fetchOpts.packages } - runSpago { workspace: env.workspace, logOptions: env.logOptions } (Uninstall.run options) - Build args@{ selectedPackage, ensureRanges, jsonErrors } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, testDeps: false } + runSpago env (Uninstall.run options) + Build args@{ selectedPackage, ensureRanges, jsonErrors, pure } -> do + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, pure, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) buildEnv <- runSpago env (mkBuildEnv args dependencies) let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors } runSpago buildEnv (Build.run options) Publish { selectedPackage } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false } + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false, isRepl: false, pure: false } dependencies <- runSpago env (Fetch.run fetchOpts) publishEnv <- runSpago env (mkPublishEnv dependencies) void $ runSpago publishEnv (Publish.publish {}) @@ -592,30 +610,32 @@ main = do , selectedPackage , ensureRanges: false , testDeps: false + , isRepl: true + , pure: false } dependencies <- runSpago env (Fetch.run fetchOpts) supportPackages <- runSpago env (SpagoRepl.supportPackage env.workspace.packageSet) replEnv <- runSpago env (mkReplEnv args dependencies supportPackages) void $ runSpago replEnv Repl.run - Bundle args@{ selectedPackage, ensureRanges } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, testDeps: false } + Bundle args@{ selectedPackage, ensureRanges, pure } -> do + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, pure, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) buildEnv <- runSpago env (mkBuildEnv args dependencies) let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false } runSpago buildEnv (Build.run options) bundleEnv <- runSpago env (mkBundleEnv args) runSpago bundleEnv Bundle.run - Run args@{ selectedPackage, ensureRanges } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, testDeps: false } + Run args@{ selectedPackage, ensureRanges, pure } -> do + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges, pure, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) buildEnv <- runSpago env (mkBuildEnv args dependencies) let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false } runSpago buildEnv (Build.run options) runEnv <- runSpago env (mkRunEnv args buildEnv) runSpago runEnv Run.run - Test args@{ selectedPackage } -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false } + Test args@{ selectedPackage, pure } -> do + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage, pure, ensureRanges: false, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) buildEnv <- runSpago env (mkBuildEnv (Record.union args { ensureRanges: false }) dependencies) let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false } @@ -624,34 +644,34 @@ main = do runSpago testEnv Test.run LsPaths args -> do runSpago { logOptions } $ Ls.listPaths args - LsPackages args -> do - let fetchArgs = { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: false } + LsPackages args@{ pure } -> do + let fetchArgs = { packages: mempty, selectedPackage: Nothing, pure, ensureRanges: false, testDeps: false, isRepl: false } { env: env@{ workspace }, fetchOpts } <- mkFetchEnv offline fetchArgs dependencies <- runSpago env (Fetch.run fetchOpts) let lsEnv = { workspace, dependencies, logOptions } runSpago lsEnv (Ls.listPackageSet args) - LsDeps { selectedPackage, json, transitive } -> do - let fetchArgs = { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false } + LsDeps { selectedPackage, json, transitive, pure } -> do + let fetchArgs = { packages: mempty, selectedPackage, pure, ensureRanges: false, testDeps: false, isRepl: false } { env, fetchOpts } <- mkFetchEnv offline fetchArgs dependencies <- runSpago env (Fetch.run fetchOpts) lsEnv <- runSpago env (mkLsEnv dependencies) runSpago lsEnv (Ls.listPackages { json, transitive }) Docs args -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: true } + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, pure: false, selectedPackage: Nothing, ensureRanges: false, testDeps: true, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) docsEnv <- runSpago env (mkDocsEnv args dependencies) runSpago docsEnv Docs.run Upgrade _args -> do - { env } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: false } + { env } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, pure: false, ensureRanges: false, testDeps: false, isRepl: false } runSpago env Upgrade.run -- TODO: add selected to graph commands GraphModules args -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: false } + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, pure: false, ensureRanges: false, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) purs <- Purs.getPurs runSpago { dependencies, logOptions, purs, workspace: env.workspace } (Graph.graphModules args) GraphPackages args -> do - { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: false } + { env, fetchOpts } <- mkFetchEnv offline { packages: mempty, selectedPackage: Nothing, pure: false, ensureRanges: false, testDeps: false, isRepl: false } dependencies <- runSpago env (Fetch.run fetchOpts) purs <- Purs.getPurs runSpago { dependencies, logOptions, purs, workspace: env.workspace } (Graph.graphPackages args) @@ -891,7 +911,7 @@ mkReplEnv replArgs dependencies supportPackage = do , selected } -mkFetchEnv :: forall a. OnlineStatus -> FetchArgs -> Spago (LogEnv a) { env :: Fetch.FetchEnv (), fetchOpts :: Fetch.FetchOpts } +mkFetchEnv :: forall a b. OnlineStatus -> { isRepl :: Boolean | FetchArgsRow b } -> Spago (LogEnv a) { env :: Fetch.FetchEnv (), fetchOpts :: Fetch.FetchOpts } mkFetchEnv offline args = do let parsePackageName p = case PackageName.parse p of @@ -906,8 +926,8 @@ mkFetchEnv offline args = do Left _err -> die $ "Failed to parse selected package name, was: " <> show args.selectedPackage env <- mkRegistryEnv offline - workspace <- runSpago env (Config.readWorkspace maybeSelectedPackage) - let fetchOpts = { packages: packageNames, ensureRanges: args.ensureRanges, isTest: args.testDeps } + workspace <- runSpago env (Config.readWorkspace { maybeSelectedPackage, pureBuild: args.pure }) + let fetchOpts = { packages: packageNames, ensureRanges: args.ensureRanges, isTest: args.testDeps, isRepl: args.isRepl } pure { fetchOpts, env: Record.union { workspace } env } mkRegistryEnv :: forall a. OnlineStatus -> Spago (LogEnv a) (Registry.RegistryEnv ()) @@ -925,84 +945,15 @@ mkRegistryEnv offline = do git <- Git.getGit purs <- Purs.getPurs { logOptions } <- ask - - -- Connect to the database - we need it to keep track of when to pull the Registry, - -- so we don't do it too often db <- liftEffect $ Db.connect { database: Paths.databasePath , logger: \str -> Reader.runReaderT (logDebug $ "DB: " <> str) { logOptions } } - - -- we keep track of how old the latest pull was - if the last pull was recent enough - -- we just move on, otherwise run the fibers - fetchingFreshRegistry <- Registry.shouldFetchRegistryRepos db - when fetchingFreshRegistry do - -- clone the registry and index repo, or update them - logInfo "Refreshing the Registry Index..." - runSpago { logOptions, git, offline } $ parallelise - [ Git.fetchRepo { git: "https://github.com/purescript/registry-index.git", ref: "main" } Paths.registryIndexPath >>= case _ of - Right _ -> pure unit - Left _err -> logWarn "Couldn't refresh the registry-index, will proceed anyways" - , Git.fetchRepo { git: "https://github.com/purescript/registry.git", ref: "main" } Paths.registryPath >>= case _ of - Right _ -> pure unit - Left _err -> logWarn "Couldn't refresh the registry, will proceed anyways" - ] - - -- Now that we are up to date with the Registry we init/refresh the database - Registry.updatePackageSetsDb db - - -- Prepare the functions to read the manifests and metadata - here we memoize as much - -- as we can in the DB, so we don't have to read the files every time - let - -- Manifests are immutable so we can just lookup in the DB or read from file if not there - getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) - getManifestFromIndex name version = do - liftEffect (Db.getManifest db name version) >>= case _ of - Just manifest -> pure (Just manifest) - Nothing -> do - -- if we don't have it we need to read it from file - -- (note that we have all the versions of a package in the same file) - logDebug $ "Reading package from Index: " <> PackageName.print name - maybeManifests <- liftAff $ ManifestIndex.readEntryFile Paths.registryIndexPath name - manifests <- map (map (\m@(Manifest m') -> Tuple m'.version m)) case maybeManifests of - Right ms -> pure $ NonEmptyArray.toUnfoldable ms - Left err -> do - logWarn $ "Could not read package manifests from index, proceeding anyways. Error: " <> err - pure [] - let versions = Map.fromFoldable manifests - -- and memoize it - for_ manifests \(Tuple _ manifest@(Manifest m)) -> do - logDebug $ "Inserting manifest in DB: " <> PackageName.print name <> " v" <> Version.print m.version - liftEffect $ Db.insertManifest db name m.version manifest - pure (Map.lookup version versions) - - -- Metadata can change over time (unpublished packages, and new packages), so we need - -- to read it from file every time we have a fresh Registry - let - metadataFromFile name = do - let metadataFilePath = Path.concat [ Paths.registryPath, Registry.Constants.metadataDirectory, PackageName.print name <> ".json" ] - logDebug $ "Reading metadata from file: " <> metadataFilePath - liftAff (FS.readJsonFile Metadata.codec metadataFilePath) - - getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata) - getMetadata name = do - -- we first try reading it from the DB - liftEffect (Db.getMetadata db name) >>= case _ of - Just metadata | not fetchingFreshRegistry -> do - logDebug $ "Got metadata from DB: " <> PackageName.print name - pure (Right metadata) - _ -> do - -- if we don't have it we try reading it from file - metadataFromFile name >>= case _ of - Left e -> pure (Left e) - Right m -> do - -- and memoize it - liftEffect (Db.insertMetadata db name m) - pure (Right m) + registryBox <- liftAff $ AVar.empty + registryLock <- liftAff $ AVar.new unit pure - { getManifestFromIndex - , getMetadata + { getRegistry: Registry.getRegistryFns registryBox registryLock , logOptions , offline , purs @@ -1030,7 +981,7 @@ mkLsEnv dependencies = do ] pure { logOptions, workspace, dependencies, selected } -mkDocsEnv :: forall a. DocsArgs -> Fetch.PackageTransitiveDeps -> Spago (Fetch.FetchEnv a) Docs.DocsEnv +mkDocsEnv :: DocsArgs -> Fetch.PackageTransitiveDeps -> Spago (Fetch.FetchEnv _) (Docs.DocsEnv _) mkDocsEnv args dependencies = do { logOptions, workspace } <- ask purs <- Purs.getPurs diff --git a/core/src/Config.purs b/core/src/Config.purs index 3229998cb..b7128912c 100644 --- a/core/src/Config.purs +++ b/core/src/Config.purs @@ -288,12 +288,10 @@ type WorkspaceConfig = , extra_packages :: Maybe (Map PackageName ExtraPackage) , backend :: Maybe BackendConfig , build_opts :: Maybe WorkspaceBuildOptionsInput - , lock :: Maybe Boolean } workspaceConfigCodec :: JsonCodec WorkspaceConfig workspaceConfigCodec = CA.object "WorkspaceConfig" - $ CA.recordPropOptional (Proxy :: _ "lock") CA.boolean $ CA.recordPropOptional (Proxy :: _ "package_set") setAddressCodec $ CA.recordPropOptional (Proxy :: _ "backend") backendConfigCodec $ CA.recordPropOptional (Proxy :: _ "build_opts") buildOptionsCodec diff --git a/core/src/Prelude.purs b/core/src/Prelude.purs index 2ed332564..b3d365b96 100644 --- a/core/src/Prelude.purs +++ b/core/src/Prelude.purs @@ -10,8 +10,8 @@ import Prelude import Control.Alt ((<|>)) as Extra import Control.Monad.Error.Class (class MonadError, class MonadThrow, try, catchError) as Extra -import Control.Monad.Reader (ask, asks) as Extra -import Control.Monad.Reader (class MonadAsk, ReaderT, runReaderT) +import Control.Monad.Reader (ask, asks, local) as Extra +import Control.Monad.Reader (class MonadAsk, class MonadReader, ReaderT, runReaderT) import Control.Monad.State (StateT) as Extra import Data.Array ((..)) as Extra import Data.Array.NonEmpty (NonEmptyArray) as Extra @@ -65,6 +65,7 @@ derive newtype instance Extra.MonadAff (Spago env) derive newtype instance Extra.MonadThrow Extra.Error (Spago env) derive newtype instance Extra.MonadError Extra.Error (Spago env) derive newtype instance MonadAsk env (Spago env) +derive newtype instance MonadReader env (Spago env) runSpago' :: forall a env. env -> Spago env a -> Extra.Aff a runSpago' env (Spago m) = runReaderT m env diff --git a/flake.lock b/flake.lock index d312da095..e73afa6dc 100644 --- a/flake.lock +++ b/flake.lock @@ -1,15 +1,31 @@ { "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -20,11 +36,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1697851979, - "narHash": "sha256-lJ8k4qkkwdvi+t/Xc6Fn74kUuobpu9ynPGxNZR6OwoA=", + "lastModified": 1701805708, + "narHash": "sha256-hh0S14E816Img0tPaNQSEKFvSscSIrvu1ypubtfh6M4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5550a85a087c04ddcace7f892b0bdc9d8bb080c8", + "rev": "0561103cedb11e7554cf34cea81e5f5d578a4753", "type": "github" }, "original": { @@ -36,17 +52,18 @@ }, "purescript-overlay": { "inputs": { + "flake-compat": "flake-compat", "nixpkgs": [ "nixpkgs" ], "slimlock": "slimlock" }, "locked": { - "lastModified": 1697766752, - "narHash": "sha256-jTGJhKuv/KPsMOnfIUSqoTckf4jo3e+9e0XY2cvXbD4=", + "lastModified": 1702248387, + "narHash": "sha256-v8BnqXzdX971kS7kFj/MgJ2YQ4Xhe6KF9ohLQ8s9ZTo=", "owner": "thomashoneyman", "repo": "purescript-overlay", - "rev": "1a6676b94f064113980b142454e3eefeecce5dcc", + "rev": "5880ccd7d35f24f91322ee76912785f7190fc3bb", "type": "github" }, "original": { diff --git a/spago.lock b/spago.lock index 4f9ccea9d..1cd972691 100644 --- a/spago.lock +++ b/spago.lock @@ -36,6 +36,107 @@ workspace: - web-storage - web-uievents test_dependencies: [] + build_plan: + - aff + - aff-promise + - argonaut-core + - arrays + - avar + - bifunctors + - catenable-lists + - codec + - codec-argonaut + - colors + - console + - const + - contravariant + - control + - css + - datetime + - distributive + - docs-search-common + - dom-indexed + - effect + - either + - enums + - exceptions + - exists + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - fork + - formatters + - free + - freeap + - functions + - functors + - gen + - halogen + - halogen-css + - halogen-subscriptions + - halogen-vdom + - html-parser-halogen + - identity + - integers + - invariant + - js-date + - js-promise + - js-uri + - json-codecs + - language-purescript + - lazy + - lcg + - lists + - markdown-it + - markdown-it-halogen + - maybe + - media-types + - newtype + - nonempty + - now + - nullable + - numbers + - options + - ordered-collections + - orders + - parallel + - parsing + - partial + - prelude + - profunctor + - profunctor-lenses + - quickcheck + - quickcheck-laws + - random + - record + - refs + - safe-coerce + - search-trie + - st + - string-parsers + - strings + - tailrec + - these + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - unsafe-reference + - variant + - versions + - web-clipboard + - web-dom + - web-events + - web-file + - web-html + - web-pointerevents + - web-storage + - web-touchevents + - web-uievents docs-search-common: path: docs-search/common dependencies: @@ -66,6 +167,75 @@ workspace: - tuples - variant test_dependencies: [] + build_plan: + - aff + - aff-promise + - argonaut-core + - arrays + - bifunctors + - codec + - codec-argonaut + - console + - const + - contravariant + - control + - datetime + - distributive + - effect + - either + - enums + - exceptions + - exists + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - formatters + - functions + - functors + - gen + - identity + - integers + - invariant + - json-codecs + - language-purescript + - lazy + - lcg + - lists + - maybe + - newtype + - nonempty + - nullable + - numbers + - ordered-collections + - orders + - parallel + - parsing + - partial + - prelude + - profunctor + - profunctor-lenses + - quickcheck + - quickcheck-laws + - random + - record + - refs + - safe-coerce + - search-trie + - st + - string-parsers + - strings + - tailrec + - these + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - variant + - versions docs-search-index: path: docs-search/index dependencies: @@ -99,6 +269,94 @@ workspace: test_dependencies: - exceptions - spec + build_plan: + - aff + - aff-promise + - ansi + - argonaut-core + - arraybuffer-types + - arrays + - avar + - bifunctors + - catenable-lists + - codec + - codec-argonaut + - console + - const + - contravariant + - control + - datetime + - distributive + - docs-search-common + - effect + - either + - enums + - exceptions + - exists + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - fork + - formatters + - free + - functions + - functors + - gen + - identity + - integers + - invariant + - js-date + - json-codecs + - language-purescript + - lazy + - lcg + - lists + - maybe + - mmorph + - newtype + - node-buffer + - node-fs + - node-fs-aff + - node-path + - node-process + - node-streams + - nonempty + - now + - nullable + - numbers + - ordered-collections + - orders + - parallel + - parsing + - partial + - pipes + - posix-types + - prelude + - profunctor + - profunctor-lenses + - quickcheck + - quickcheck-laws + - random + - record + - refs + - safe-coerce + - search-trie + - spec + - st + - string-parsers + - strings + - tailrec + - these + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - variant + - versions spago: path: ./ dependencies: @@ -144,6 +402,131 @@ workspace: - unsafe-coerce test_dependencies: - spec + build_plan: + - aff + - aff-promise + - affjax + - affjax-node + - ansi + - argonaut-core + - arraybuffer-types + - arrays + - assert + - avar + - b64 + - bifunctors + - catenable-lists + - codec + - codec-argonaut + - console + - const + - contravariant + - control + - convertable-options + - datetime + - distributive + - docs-search-common + - docs-search-index + - dodo-printer + - effect + - either + - encoding + - enums + - exceptions + - exists + - fetch + - fetch-core + - filterable + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - fork + - form-urlencoded + - formatters + - free + - functions + - functors + - gen + - graphs + - http-methods + - identity + - integers + - invariant + - js-date + - js-timers + - js-uri + - json-codecs + - language-cst-parser + - language-purescript + - lazy + - lcg + - lists + - maybe + - media-types + - minibench + - mmorph + - newtype + - node-buffer + - node-child-process + - node-event-emitter + - node-execa + - node-fs + - node-fs-aff + - node-human-signals + - node-path + - node-process + - node-streams + - nonempty + - now + - nullable + - numbers + - ordered-collections + - orders + - parallel + - parsing + - partial + - pipes + - posix-types + - prelude + - profunctor + - profunctor-lenses + - quickcheck + - quickcheck-laws + - random + - record + - refs + - registry-foreign + - registry-lib + - routing-duplex + - safe-coerce + - search-trie + - spago-core + - spec + - st + - string-parsers + - strings + - stringutils + - tailrec + - these + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - unsafe-reference + - variant + - versions + - web-dom + - web-events + - web-file + - web-html + - web-promise + - web-storage + - web-streams + - web-xhr spago-bin: path: bin dependencies: @@ -165,6 +548,136 @@ workspace: - spago-core - unsafe-coerce test_dependencies: [] + build_plan: + - aff + - aff-promise + - affjax + - affjax-node + - ansi + - argonaut-core + - arraybuffer-types + - arrays + - assert + - avar + - b64 + - bifunctors + - catenable-lists + - codec + - codec-argonaut + - console + - const + - contravariant + - control + - convertable-options + - datetime + - distributive + - docs-search-common + - docs-search-index + - dodo-printer + - effect + - either + - encoding + - enums + - exceptions + - exists + - exitcodes + - fetch + - fetch-core + - filterable + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - fork + - form-urlencoded + - formatters + - free + - functions + - functors + - gen + - graphs + - http-methods + - identity + - integers + - invariant + - js-date + - js-timers + - js-uri + - json-codecs + - language-cst-parser + - language-purescript + - lazy + - lcg + - lists + - maybe + - media-types + - minibench + - mmorph + - newtype + - node-buffer + - node-child-process + - node-event-emitter + - node-execa + - node-fs + - node-fs-aff + - node-human-signals + - node-path + - node-process + - node-streams + - nonempty + - now + - nullable + - numbers + - open-memoize + - optparse + - ordered-collections + - orders + - parallel + - parsing + - partial + - pipes + - posix-types + - prelude + - profunctor + - profunctor-lenses + - psci-support + - quickcheck + - quickcheck-laws + - random + - record + - refs + - registry-foreign + - registry-lib + - routing-duplex + - safe-coerce + - search-trie + - spago + - spago-core + - spec + - st + - string-parsers + - strings + - stringutils + - tailrec + - these + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - unsafe-reference + - variant + - versions + - web-dom + - web-events + - web-file + - web-html + - web-promise + - web-storage + - web-streams + - web-xhr spago-core: path: core dependencies: @@ -202,8 +715,546 @@ workspace: - transformers - tuples test_dependencies: [] + build_plan: + - aff + - ansi + - argonaut-core + - arraybuffer-types + - arrays + - assert + - avar + - bifunctors + - catenable-lists + - codec + - codec-argonaut + - console + - const + - contravariant + - control + - datetime + - distributive + - dodo-printer + - effect + - either + - enums + - exceptions + - exists + - filterable + - fixed-points + - foldable-traversable + - foreign + - foreign-object + - formatters + - free + - functions + - functors + - gen + - graphs + - identity + - integers + - invariant + - js-date + - js-uri + - language-cst-parser + - lazy + - lcg + - lists + - maybe + - minibench + - newtype + - node-buffer + - node-child-process + - node-fs + - node-fs-aff + - node-path + - node-process + - node-streams + - nonempty + - now + - nullable + - numbers + - ordered-collections + - orders + - parallel + - parsing + - partial + - posix-types + - prelude + - profunctor + - profunctor-lenses + - quickcheck + - random + - record + - refs + - registry-lib + - routing-duplex + - safe-coerce + - st + - strings + - tailrec + - transformers + - tuples + - type-equality + - typelevel-prelude + - unfoldable + - unicode + - unsafe-coerce + - variant package_set: - registry: 20.0.1 + address: + registry: 20.0.1 + compiler: ">=0.15.7 <0.16.0" + content: + abc-parser: 2.0.0 + ace: 9.1.0 + aff: 7.1.0 + aff-bus: 6.0.0 + aff-coroutines: 9.0.0 + aff-promise: 4.0.0 + aff-retry: 2.0.0 + affjax: 13.0.0 + affjax-node: 1.0.0 + affjax-web: 1.0.0 + ansi: 7.0.0 + argonaut: 9.0.0 + argonaut-aeson-generic: 0.4.1 + argonaut-codecs: 9.1.0 + argonaut-core: 7.0.0 + argonaut-generic: 8.0.0 + argonaut-traversals: 10.0.0 + argparse-basic: 2.0.0 + array-builder: 0.1.2 + array-search: 0.5.6 + arraybuffer: 13.2.0 + arraybuffer-builder: 3.1.0 + arraybuffer-types: 3.0.2 + arrays: 7.2.0 + arrays-zipper: 2.0.1 + ask: 1.0.0 + assert: 6.0.0 + assert-multiple: 0.3.4 + avar: 5.0.0 + b64: 0.0.8 + barbies: 1.0.1 + barlow-lens: 0.9.0 + basic-auth: 3.0.1 + bifunctors: 6.0.0 + bigints: 7.0.1 + bolson: 0.3.2 + bower-json: 3.0.0 + bucketchain: 1.0.1 + bucketchain-basic-auth: 1.0.1 + bucketchain-conditional: 1.0.1 + bucketchain-cors: 1.0.1 + bucketchain-csrf: 1.0.1 + bucketchain-header-utils: 1.0.1 + bucketchain-health: 1.0.1 + bucketchain-history-api-fallback: 1.0.1 + bucketchain-logger: 1.0.1 + bucketchain-secure: 1.0.1 + bucketchain-simple-api: 5.0.1 + bucketchain-sslify: 1.0.1 + bucketchain-static: 1.0.1 + call-by-name: 4.0.1 + canvas: 6.0.0 + canvas-action: 9.0.0 + cartesian: 1.0.6 + catenable-lists: 7.0.0 + channel: 1.0.0 + checked-exceptions: 3.1.1 + classless: 0.1.1 + classless-arbitrary: 0.1.1 + classless-decode-json: 0.1.1 + classless-encode-json: 0.1.3 + classnames: 2.0.0 + codec: 6.0.0 + codec-argonaut: 10.0.0 + colors: 7.0.1 + concur-core: 0.5.0 + concur-react: 0.5.0 + concurrent-queues: 3.0.0 + console: 6.0.0 + const: 6.0.0 + contravariant: 6.0.0 + control: 6.0.0 + convertable-options: 1.0.0 + coroutines: 7.0.0 + crypto: 5.0.1 + css: 6.0.0 + datetime: 6.1.0 + datetime-parsing: 0.2.0 + debug: 6.0.2 + decimals: 7.1.0 + default-values: 1.0.1 + deku: 0.9.18 + deno: 0.0.5 + dissect: 1.0.0 + distributive: 6.0.0 + dodo-printer: 2.2.1 + dom-filereader: 7.0.0 + dom-indexed: 11.0.0 + dotenv: 4.0.0 + droplet: 0.6.0 + dts: 0.1.3 + dynamic-buffer: 3.0.1 + echarts-simple: 0.0.1 + effect: 4.0.0 + either: 6.1.0 + elmish: 0.9.3 + elmish-enzyme: 0.1.1 + elmish-hooks: 0.9.1 + elmish-html: 0.8.1 + elmish-testing-library: 0.3.1 + email-validate: 7.0.0 + encoding: 0.0.8 + enums: 6.0.1 + env-names: 0.3.4 + error: 2.0.0 + exceptions: 6.0.0 + exists: 6.0.0 + exitcodes: 4.0.0 + expect-inferred: 3.0.0 + fahrtwind: 2.0.0 + fallback: 0.1.0 + fast-vect: 1.1.0 + fetch: 1.1.4 + fetch-argonaut: 1.0.0 + fetch-core: 4.0.4 + fetch-yoga-json: 1.1.0 + filterable: 5.0.0 + fixed-points: 7.0.0 + fixed-precision: 5.0.0 + flame: 1.3.0 + float32: 2.0.0 + foldable-traversable: 6.0.0 + foreign: 7.0.0 + foreign-object: 4.1.0 + foreign-readwrite: 3.4.0 + fork: 6.0.0 + form-urlencoded: 7.0.0 + formatters: 7.0.0 + framer-motion: 1.0.1 + free: 7.0.0 + freeap: 7.0.0 + freer-free: 0.0.1 + freet: 7.0.0 + functions: 6.0.0 + functor1: 3.0.0 + functors: 5.0.0 + fuzzy: 0.4.0 + gen: 4.0.0 + generate-values: 1.0.1 + generic-router: 0.0.1 + geojson: 0.0.2 + geometry-plane: 1.0.3 + github-actions-toolkit: 0.5.0 + grain: 3.0.0 + grain-router: 3.0.0 + grain-virtualized: 3.0.0 + graphql-client: 9.3.2 + graphs: 8.1.0 + group: 4.1.1 + halogen: 7.0.0 + halogen-bootstrap5: 2.1.0 + halogen-css: 10.0.0 + halogen-echarts-simple: 0.0.4 + halogen-formless: 4.0.2 + halogen-helix: 1.0.0 + halogen-hooks: 0.6.3 + halogen-hooks-extra: 0.9.0 + halogen-store: 0.5.4 + halogen-storybook: 2.0.0 + halogen-subscriptions: 2.0.0 + halogen-svg-elems: 7.0.0 + halogen-vdom: 8.0.0 + halogen-vdom-string-renderer: 0.5.0 + heckin: 2.0.1 + heterogeneous: 0.6.0 + homogeneous: 0.4.0 + http-methods: 6.0.0 + httpure: 0.16.0 + httpurple: 3.0.1 + httpurple-argonaut: 1.0.1 + httpurple-yoga-json: 1.0.0 + humdrum: 0.0.1 + hyrule: 2.3.7 + identity: 6.0.0 + identy: 4.0.1 + indexed-db: 1.0.0 + indexed-monad: 3.0.0 + int64: 3.0.0 + integers: 6.0.0 + interpolate: 5.0.2 + invariant: 6.0.0 + jarilo: 1.0.1 + jelly: 0.10.0 + jelly-router: 0.3.0 + jelly-signal: 0.4.0 + jest: 1.0.0 + js-abort-controller: 1.0.0 + js-bigints: 2.0.0 + js-date: 8.0.0 + js-fileio: 3.0.0 + js-promise: 1.0.0 + js-promise-aff: 1.0.0 + js-timers: 6.1.0 + js-uri: 3.1.0 + json-codecs: 3.0.0 + justifill: 0.5.0 + jwt: 0.0.9 + language-cst-parser: 0.12.3 + lazy: 6.0.0 + lazy-joe: 1.0.0 + lcg: 4.0.0 + leibniz: 5.0.0 + liminal: 1.0.1 + linalg: 5.1.0 + lists: 7.0.0 + literals: 1.0.2 + logging: 3.0.0 + logging-journald: 0.4.0 + machines: 7.0.0 + maps-eager: 0.4.1 + marionette: 1.0.0 + marionette-commander: 0.1.1 + marionette-react-basic-hooks: 0.1.1 + matrices: 5.0.1 + matryoshka: 1.0.0 + maybe: 6.0.0 + mdast-util-from-markdown: 0.2.1 + media-types: 6.0.0 + midi: 4.0.0 + milkis: 9.0.0 + minibench: 4.0.1 + mmorph: 7.0.0 + monad-control: 5.0.0 + monad-logger: 1.3.1 + monad-loops: 0.5.0 + monad-unlift: 1.0.1 + monoid-extras: 0.0.1 + monoidal: 0.16.0 + morello: 0.4.0 + mote: 3.0.0 + motsunabe: 2.0.0 + mysql: 6.0.1 + n3: 0.1.0 + nano-id: 1.1.0 + naturals: 3.0.0 + nested-functor: 0.2.1 + newtype: 5.0.0 + nextjs: 0.1.1 + nextui: 0.2.0 + node-buffer: 8.0.0 + node-buffer-blob: 1.0.0 + node-child-process: 9.0.0 + node-event-emitter: 1.0.1 + node-execa: 1.3.2 + node-fs: 8.2.0 + node-fs-aff: 9.2.0 + node-http: 8.0.0 + node-human-signals: 1.0.0 + node-net: 4.0.0 + node-path: 5.0.0 + node-process: 10.0.0 + node-readline: 7.0.0 + node-sqlite3: 8.0.0 + node-streams: 7.0.0 + node-streams-aff: 5.0.0 + node-url: 6.0.0 + nodemailer: 4.0.1 + nonempty: 7.0.0 + now: 6.0.0 + npm-package-json: 2.0.0 + nullable: 6.0.0 + numberfield: 0.1.0 + numbers: 9.0.1 + object-maps: 0.1.1 + ocarina: 1.5.2 + open-folds: 6.3.0 + open-memoize: 6.1.0 + open-pairing: 6.1.0 + options: 7.0.0 + optparse: 5.0.0 + ordered-collections: 3.0.0 + ordered-set: 0.4.0 + orders: 6.0.0 + pairs: 9.0.0 + parallel: 6.0.0 + parsing: 10.2.0 + parsing-dataview: 3.2.4 + partial: 4.0.0 + pathy: 9.0.0 + pha: 0.9.1 + phaser: 0.7.0 + pipes: 8.0.0 + pirates-charm: 0.0.1 + point-free: 1.0.0 + pointed-list: 0.5.1 + polymorphic-vectors: 4.0.0 + posix-types: 6.0.0 + precise: 6.0.0 + precise-datetime: 7.0.0 + prelude: 6.0.1 + prettier-printer: 3.0.0 + profunctor: 6.0.0 + profunctor-lenses: 8.0.0 + protobuf: 4.3.0 + ps-cst: 1.2.0 + psa-utils: 8.0.0 + psc-ide: 19.0.0 + psci-support: 6.0.0 + qualified-do: 2.2.0 + quantities: 12.1.0 + quickcheck: 8.0.1 + quickcheck-combinators: 0.1.3 + quickcheck-laws: 7.0.0 + quickcheck-utf8: 0.0.0 + random: 6.0.0 + rationals: 5.0.1 + rdf: 0.1.0 + react: 11.0.0 + react-aria: 0.2.0 + react-basic: 17.0.0 + react-basic-classic: 3.0.0 + react-basic-dnd: 10.1.0 + react-basic-dom: 6.1.0 + react-basic-emotion: 7.1.0 + react-basic-hooks: 8.1.2 + react-basic-storybook: 2.0.0 + react-dom: 8.0.0 + react-halo: 3.0.0 + react-icons: 1.1.1 + react-markdown: 0.1.0 + react-testing-library: 4.0.1 + react-virtuoso: 1.0.0 + read: 1.0.1 + recharts: 1.1.0 + record: 4.0.0 + record-extra: 5.0.1 + record-studio: 1.0.4 + refs: 6.0.0 + remotedata: 5.0.0 + resource: 2.0.1 + resourcet: 1.0.0 + result: 1.0.3 + return: 0.2.0 + ring-modules: 5.0.1 + rito: 0.3.2 + routing: 11.0.0 + routing-duplex: 0.7.0 + run: 5.0.0 + safe-coerce: 2.0.0 + safely: 4.0.1 + school-of-music: 1.3.0 + selection-foldable: 0.2.0 + semirings: 7.0.0 + signal: 13.0.0 + simple-emitter: 3.0.1 + simple-i18n: 2.0.1 + simple-json: 9.0.0 + simple-jwt: 4.0.1 + simple-ulid: 3.0.0 + sized-matrices: 1.0.0 + sized-vectors: 5.0.2 + slug: 3.0.8 + small-ffi: 4.0.1 + soundfonts: 4.1.0 + sparse-matrices: 1.3.0 + sparse-polynomials: 2.0.3 + spec: 7.3.0 + spec-discovery: 8.0.1 + spec-quickcheck: 5.0.0 + splitmix: 2.1.0 + ssrs: 1.0.0 + st: 6.2.0 + statistics: 0.3.2 + strictlypositiveint: 1.0.1 + string-parsers: 8.0.0 + strings: 6.0.1 + strings-extra: 4.0.0 + stringutils: 0.0.12 + substitute: 0.2.3 + sunde: 3.0.0 + supply: 0.2.0 + svg-parser: 3.0.0 + systemd-journald: 0.3.0 + tagged: 4.0.2 + tailrec: 6.1.0 + tecton: 0.1.6 + tecton-halogen: 0.1.3 + test-unit: 17.0.0 + thermite: 6.3.1 + thermite-dom: 0.3.1 + these: 6.0.0 + toppokki: 4.0.0 + transformation-matrix: 1.0.1 + transformers: 6.0.0 + tree-rose: 4.0.2 + ts-bridge: 2.0.3 + tuples: 7.0.0 + two-or-more: 1.0.0 + type-equality: 4.0.1 + typedenv: 2.0.1 + typelevel: 6.0.0 + typelevel-lists: 2.1.0 + typelevel-peano: 1.0.1 + typelevel-prelude: 7.0.0 + typelevel-rows: 0.1.0 + uint: 7.0.0 + ulid: 3.0.1 + uncurried-transformers: 1.1.0 + undefined: 2.0.0 + undefined-is-not-a-problem: 1.1.0 + unfoldable: 6.0.0 + unicode: 6.0.0 + unique: 0.6.1 + unlift: 1.0.1 + unordered-collections: 3.0.1 + unsafe-coerce: 6.0.0 + unsafe-reference: 5.0.0 + untagged-to-tagged: 0.1.4 + untagged-union: 1.0.0 + uri: 9.0.0 + uuid: 9.0.0 + uuidv4: 1.0.0 + validation: 6.0.0 + variant: 8.0.0 + vectorfield: 1.0.1 + vectors: 2.1.0 + versions: 7.0.0 + visx: 0.0.2 + web-clipboard: 5.0.0 + web-cssom: 2.0.0 + web-cssom-view: 0.1.0 + web-dom: 6.0.0 + web-dom-parser: 8.0.0 + web-dom-xpath: 3.0.0 + web-encoding: 3.0.0 + web-events: 4.0.0 + web-fetch: 3.0.0 + web-file: 4.0.0 + web-geometry: 0.1.0 + web-html: 4.1.0 + web-pointerevents: 1.0.0 + web-proletarian: 1.0.0 + web-promise: 3.1.0 + web-resize-observer: 2.0.0 + web-router: 1.0.0 + web-socket: 4.0.0 + web-storage: 5.0.0 + web-streams: 3.0.0 + web-touchevents: 4.0.0 + web-uievents: 4.0.0 + web-url: 2.0.0 + web-workers: 1.1.0 + web-xhr: 5.0.1 + webextension-polyfill: 0.1.0 + which: 2.0.0 + yoga-fetch: 1.0.1 + yoga-json: 5.1.0 + yoga-om: 0.1.0 + yoga-postgres: 6.0.0 + yoga-tree: 1.0.0 extra_packages: html-parser-halogen: git: https://github.com/rnons/purescript-html-parser-halogen.git @@ -220,7 +1271,6 @@ workspace: - effect - foldable-traversable - prelude - - psci-support json-codecs: 4.0.0 language-cst-parser: git: https://github.com/natefaubion/purescript-language-cst-parser.git diff --git a/spago.yaml b/spago.yaml index 07f980691..61cafb893 100644 --- a/spago.yaml +++ b/spago.yaml @@ -6,6 +6,11 @@ package: location: githubOwner: purescript githubRepo: spago + build: + strict: true + censor_project_warnings: + - WildcardInferredType + - ImplicitQualifiedImportReExport dependencies: - aff - affjax @@ -49,16 +54,11 @@ package: - unsafe-coerce test: main: Test.Spago + censor_test_warnings: + - ImplicitQualifiedImportReExport dependencies: - spec workspace: - build_opts: - strict: false - censor_warnings: project - censor_codes: - - ImplicitQualifiedImportReExport - - ImplicitQualifiedImport - lock: true package_set: registry: 20.0.1 extra_packages: @@ -83,7 +83,6 @@ workspace: - effect - foldable-traversable - prelude - - psci-support git: https://github.com/nonbili/purescript-jest.git ref: caf2032f2e5828337e897a99f5359c00e91cb0ee language-purescript: diff --git a/src/Spago/Command/Build.purs b/src/Spago/Command/Build.purs index dd1f23bfd..527870e4d 100644 --- a/src/Spago/Command/Build.purs +++ b/src/Spago/Command/Build.purs @@ -42,7 +42,7 @@ type BuildOptions = , jsonErrors :: Boolean } -run :: forall a. BuildOptions -> Spago (BuildEnv a) Unit +run :: BuildOptions -> Spago (BuildEnv _) Unit run opts = do logInfo "Building..." { dependencies diff --git a/src/Spago/Command/Docs.purs b/src/Spago/Command/Docs.purs index c20fd1956..541ac2434 100644 --- a/src/Spago/Command/Docs.purs +++ b/src/Spago/Command/Docs.purs @@ -18,7 +18,7 @@ import Spago.Config as Config import Spago.Purs (Purs, DocsFormat(..)) import Spago.Purs as Purs -type DocsEnv = +type DocsEnv a = { purs :: Purs , workspace :: Workspace , dependencies :: Fetch.PackageTransitiveDeps @@ -26,9 +26,10 @@ type DocsEnv = , docsFormat :: DocsFormat , depsOnly :: Boolean , open :: Boolean + | a } -run :: Spago DocsEnv Unit +run :: Spago (DocsEnv _) Unit run = do logDebug "Running `spago docs`" logInfo "Generating documentation for the project. This might take a while..." diff --git a/src/Spago/Command/Fetch.purs b/src/Spago/Command/Fetch.purs index 5dec62b3b..b9e064483 100644 --- a/src/Spago/Command/Fetch.purs +++ b/src/Spago/Command/Fetch.purs @@ -8,6 +8,7 @@ module Spago.Command.Fetch , getTransitiveDeps , getTransitiveDepsFromRegistry , run + , writeNewLockfile ) where import Spago.Prelude @@ -17,12 +18,16 @@ import Affjax.ResponseFormat as Response import Affjax.StatusCode (StatusCode(..)) import Control.Monad.State as State import Data.Array as Array +import Data.Array.NonEmpty as NEA import Data.Codec.Argonaut as CA +import Data.Codec.Argonaut.Common as CA.Common import Data.Either as Either import Data.HTTP.Method as Method import Data.Int as Int import Data.Map as Map +import Data.Newtype (wrap) import Data.Set as Set +import Data.Traversable (sequence) import Effect.Ref as Ref import Node.Buffer as Buffer import Node.Encoding as Encoding @@ -35,7 +40,7 @@ import Registry.Sha256 as Sha256 import Registry.Solver as Registry.Solver import Registry.Version as Registry.Version import Registry.Version as Version -import Spago.Config (Dependencies(..), GitPackage, LockfileSettings(..), Package(..), PackageMap, PackageSet(..), Workspace, WorkspacePackage) +import Spago.Config (BuildType(..), Dependencies(..), GitPackage, Package(..), PackageMap, Workspace, WorkspacePackage) import Spago.Config as Config import Spago.Db as Db import Spago.FS as FS @@ -44,14 +49,14 @@ import Spago.Lock (LockEntry(..)) import Spago.Lock as Lock import Spago.Paths as Paths import Spago.Purs as Purs +import Spago.Registry as Registry import Spago.Repl as Repl import Spago.Tar as Tar type PackageTransitiveDeps = Map PackageName PackageMap type FetchEnvRow a = - ( getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) - , getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata) + ( getRegistry :: Spago (Registry.PreRegistryEnv ()) Registry.RegistryFunctions , workspace :: Workspace , logOptions :: LogOptions , offline :: OnlineStatus @@ -67,216 +72,265 @@ type FetchOpts = { packages :: Array PackageName , ensureRanges :: Boolean , isTest :: Boolean + , isRepl :: Boolean } -run - :: forall a - . FetchOpts - -> Spago (FetchEnv a) PackageTransitiveDeps -run { packages: packagesToInstall, ensureRanges, isTest } = do - logDebug $ "Requested to install these packages: " <> printJson (CA.array PackageName.codec) packagesToInstall +run :: forall a. FetchOpts -> Spago (FetchEnv a) PackageTransitiveDeps +run { packages: packagesRequestedToInstall, ensureRanges, isTest, isRepl } = do + logDebug $ "Requested to install these packages: " <> printJson (CA.array PackageName.codec) packagesRequestedToInstall - { getMetadata, logOptions, workspace, offline } <- ask - - let - installingPackages = not $ Array.null packagesToInstall - - getSelectedPackageTransitiveDeps :: WorkspacePackage -> Spago (FetchEnv a) PackageMap - getSelectedPackageTransitiveDeps selected = - getTransitiveDeps $ getWorkspacePackageDeps selected <> Dependencies (Map.fromFoldable $ map (_ /\ Nothing) packagesToInstall) - - -- lookup the dependencies in the package set, so we get their version numbers. - { dependencies, transitiveDeps } <- case workspace.selected of - Just (selected :: WorkspacePackage) -> do - transitiveDeps <- getSelectedPackageTransitiveDeps selected - pure - { dependencies: Map.singleton selected.package.name transitiveDeps - , transitiveDeps - } - Nothing -> do - dependencies <- traverse getTransitiveDeps - $ Map.fromFoldable - $ map (\p -> Tuple p.package.name (getWorkspacePackageDeps p)) - $ Config.getWorkspacePackages workspace.packageSet - pure - { dependencies - , transitiveDeps: toAllDependencies dependencies - } + { workspace: currentWorkspace, offline } <- ask let getPackageConfigPath errorMessageEnd = do - case workspace.selected of + case currentWorkspace.selected of Just { path, doc, package } -> pure { configPath: Path.concat [ path, "spago.yaml" ], yamlDoc: doc, package } - Nothing -> case workspace.rootPackage of - Just rootPackage -> do pure { configPath: "spago.yaml", yamlDoc: workspace.doc, package: rootPackage } + Nothing -> case currentWorkspace.rootPackage of + Just rootPackage -> do pure { configPath: "spago.yaml", yamlDoc: currentWorkspace.doc, package: rootPackage } Nothing -> die [ "No package found in the root configuration." , "Please use the `-p` flag to select a package " <> errorMessageEnd ] - -- write to the config file if we are adding new packages - when installingPackages do - { configPath, package, yamlDoc } <- getPackageConfigPath "to install your packages in." - let packageDependencies = Map.keys $ unwrap package.dependencies - -- Prevent users from installing a circular dependency - let packages = Array.filter (\p -> p /= package.name) packagesToInstall - let overlappingPackages = Set.intersection packageDependencies (Set.fromFoldable packages) - unless (Set.isEmpty overlappingPackages) do - logWarn - $ [ toDoc "You tried to install some packages that are already present in the configuration, proceeding anyways:" ] - <> map (indent <<< toDoc <<< append "- " <<< PackageName.print) (Array.fromFoldable overlappingPackages) - logInfo $ "Adding " <> show (Array.length packages) <> " packages to the config in " <> configPath - liftEffect $ Config.addPackagesToConfig yamlDoc isTest packages - liftAff $ FS.writeYamlDocFile configPath yamlDoc - - -- if the flag is selected, we kick off the process of adding ranges to the config - when ensureRanges do - { configPath, package, yamlDoc } <- getPackageConfigPath "in which to add ranges." - logInfo $ "Adding ranges to dependencies to the config in " <> configPath - packageDeps <- (Map.lookup package.name dependencies) `justOrDieWith` - "Impossible: package dependencies must be in dependencies map" - let rangeMap = map getRangeFromPackage packageDeps - liftEffect $ Config.addRangesToConfig yamlDoc rangeMap - liftAff $ FS.writeYamlDocFile configPath yamlDoc - - -- TODO: need to be careful about what happens when we select a single package vs the whole workspace - -- because otherwise the lockfile will be partial. - -- Most likely we'll want to first figure out if we want a new lockfile at all, - -- then possibly resolve all the packages anyways, then resolve the ones for a single package - -- (which comes for free at that point since the cache is already populated) - lockfile <- do - let - fromWorkspacePackage :: WorkspacePackage -> Tuple PackageName Lock.WorkspaceLockPackage - fromWorkspacePackage { path, package } = Tuple package.name - { path - , dependencies: package.dependencies - , test_dependencies: foldMap _.dependencies package.test - } + installingPackagesData <- do + case Array.null packagesRequestedToInstall of + true -> pure Nothing + false -> do + { configPath, package, yamlDoc } <- getPackageConfigPath "to install your packages in." + currentWorkspacePackage <- NEA.find (\p -> p.package.name == package.name) (Config.getWorkspacePackages currentWorkspace.packageSet) `justOrDieWith` "Impossible: package must be in workspace packages" + let + packageDependencies = Map.keys $ case isTest of + false -> unwrap package.dependencies + true -> unwrap $ maybe mempty _.dependencies package.test + -- Prevent users from installing a circular dependency + packages = Array.filter (\p -> p /= package.name) packagesRequestedToInstall + overlappingPackages = Set.intersection packageDependencies (Set.fromFoldable packages) + actualPackagesToInstall = Array.filter (\p -> not $ Set.member p overlappingPackages) packages + newPackageDependencies = wrap $ Map.fromFoldable $ map (\p -> Tuple p Nothing) actualPackagesToInstall + newWorkspacePackage = case isTest of + false -> currentWorkspacePackage { package { dependencies = package.dependencies <> newPackageDependencies } } + true -> currentWorkspacePackage { package { test = package.test # map (\t -> t { dependencies = t.dependencies <> newPackageDependencies }) } } + logDebug $ "Overlapping packages: " <> printJson (CA.Common.set PackageName.codec) overlappingPackages + logDebug $ "Actual packages to install: " <> printJson (CA.array PackageName.codec) actualPackagesToInstall + -- If we are installing new packages, we need to add them to the config + -- We also warn the user if they are already present in the config + unless (Set.isEmpty overlappingPackages) do + logWarn + $ [ toDoc "You tried to install some packages that are already present in the configuration, proceeding anyways:" ] + <> map (indent <<< toDoc <<< append "- " <<< PackageName.print) (Array.fromFoldable overlappingPackages) + case Array.null actualPackagesToInstall of + true -> pure Nothing + false -> do + logDebug $ "Packages to install: " <> printJson (CA.array PackageName.codec) actualPackagesToInstall + pure $ Just { configPath, yamlDoc, actualPackagesToInstall, newWorkspacePackage } - lockfileWorkspace :: Lock.WorkspaceLock - lockfileWorkspace = - { package_set: workspace.workspaceConfig.package_set - , packages: Map.fromFoldable - $ map fromWorkspacePackage (Config.getWorkspacePackages workspace.packageSet) - , extra_packages: fromMaybe Map.empty workspace.workspaceConfig.extra_packages + let + -- If we need to install new packages then we need to zero the current lockfile, we're going to need a new one + workspace = case installingPackagesData of + Nothing -> currentWorkspace + Just { newWorkspacePackage } -> currentWorkspace + { packageSet = currentWorkspace.packageSet + { lockfile = Left "Lockfile is out of date (installing new packages)" + -- If we are installing packages, we need to add the new deps to the selected package + , buildType = case currentWorkspace.packageSet.buildType of + RegistrySolverBuild packageMap -> RegistrySolverBuild $ Map.insert newWorkspacePackage.package.name (WorkspacePackage newWorkspacePackage) packageMap + PackageSetBuild info packageMap -> PackageSetBuild info $ Map.insert newWorkspacePackage.package.name (WorkspacePackage newWorkspacePackage) packageMap + } + , selected = Just newWorkspacePackage } - (lockfilePackages :: Map PackageName Lock.LockEntry) <- Map.catMaybes <$> - forWithIndex transitiveDeps \packageName package -> do - (packageDependencies :: Array PackageName) <- (Array.fromFoldable <<< Map.keys <<< fromMaybe Map.empty) - <$> getPackageDependencies packageName package - case package of - GitPackage gitPackage -> do - let packageLocation = Config.getPackageLocation packageName package - Git.getRef (Just packageLocation) >>= case _ of - Left err -> die err - Right rev -> pure $ Just $ FromGit { rev, dependencies: packageDependencies, url: gitPackage.git, subdir: gitPackage.subdir } - RegistryVersion version -> do - metadata <- runSpago { logOptions } $ getMetadata packageName - registryVersion <- case (metadata >>= (\(Metadata meta) -> Either.note "Didn't find version in the metadata file" $ Map.lookup version meta.published)) of - Left err -> die $ "Couldn't read metadata, reason:\n " <> err - Right { hash: integrity } -> - pure { version, integrity, dependencies: packageDependencies } - pure $ Just $ FromRegistry registryVersion - LocalPackage { path } -> pure $ Just (FromPath { path, dependencies: packageDependencies }) - WorkspacePackage _ -> pure $ Nothing - - pure { workspace: lockfileWorkspace, packages: lockfilePackages } + local (_ { workspace = workspace }) do + -- We compute the transitive deps for all the packages in the workspace, but keep them + -- split by package - we need all of them so we can stash them in the lockfile, but we + -- are going to only download the ones that we need to, if e.g. there's a package selected + dependencies <- traverse getTransitiveDeps + $ Map.fromFoldable + $ map (\p -> Tuple p.package.name p) + $ Config.getWorkspacePackages workspace.packageSet + + case installingPackagesData of + Nothing -> pure unit + Just { configPath, yamlDoc, actualPackagesToInstall } -> do + let + countString = case Array.length actualPackagesToInstall of + 1 -> "1 package" + n -> show n <> " packages" + logInfo $ "Adding " <> countString <> " to the config in " <> configPath + liftAff $ Config.addPackagesToConfig configPath yamlDoc isTest actualPackagesToInstall + + -- if the flag is selected, we kick off the process of adding ranges to the config + when ensureRanges do + { configPath, package, yamlDoc } <- getPackageConfigPath "in which to add ranges." + logInfo $ "Adding ranges to dependencies to the config in " <> configPath + packageDeps <- (Map.lookup package.name dependencies) `justOrDieWith` + "Impossible: package dependencies must be in dependencies map" + let rangeMap = map getRangeFromPackage packageDeps + liftEffect $ Config.addRangesToConfig yamlDoc rangeMap + liftAff $ FS.writeYamlDocFile configPath yamlDoc + + -- the repl needs a support package, so we add it here as a sidecar + supportPackage <- Repl.supportPackage workspace.packageSet + let + allTransitiveDeps = case isRepl of + false -> dependencies + true -> map (\packageMap -> Map.union packageMap supportPackage) dependencies + depsToFetch <- case workspace.selected of + Nothing -> pure (toAllDependencies allTransitiveDeps) + -- If there's a package selected, we only fetch the transitive deps for that one + Just p -> case Map.lookup p.package.name dependencies of + Nothing -> die "Impossible: package dependencies must be in dependencies map" + Just deps -> pure $ Map.union deps if isRepl then supportPackage else Map.empty + + case workspace.packageSet.lockfile of + Right _lockfile -> pure unit + Left reason -> writeNewLockfile reason allTransitiveDeps + + -- then for every package we have we try to download it, and copy it in the local cache + logInfo "Downloading dependencies..." + + parallelise $ (flip map) (Map.toUnfoldable depsToFetch :: Array (Tuple PackageName Package)) \(Tuple name package) -> do + let localPackageLocation = Config.getPackageLocation name package + -- first of all, we check if we have the package in the local cache. If so, we don't even do the work + unlessM (FS.exists localPackageLocation) case package of + GitPackage gitPackage -> getGitPackageInLocalCache name gitPackage + RegistryVersion v -> do + -- if the version comes from the registry then we have a longer list of things to do + let versionString = Registry.Version.print v + let packageVersion = PackageName.print name <> "@" <> versionString + -- get the metadata for the package, so we have access to the hash and other info + metadata <- Registry.getMetadata name + case (metadata >>= (\(Metadata meta) -> Either.note "Didn't find version in the metadata file" $ Map.lookup v meta.published)) of + Left err -> die $ "Couldn't read metadata, reason:\n " <> err + Right versionMetadata -> do + logDebug $ "Metadata read: " <> printJson Metadata.publishedMetadataCodec versionMetadata + -- then check if we have a tarball cached. If not, download it + let globalCachePackagePath = Path.concat [ Paths.globalCachePath, "packages", PackageName.print name ] + let archivePath = Path.concat [ globalCachePackagePath, versionString <> ".tar.gz" ] + FS.mkdirp globalCachePackagePath + -- We need to see if the tarball is there, and if we can decompress it. + -- This is because if Spago is killed while it's writing the tar, then it might leave it corrupted. + -- By checking that it's broken we can try to redownload it here. + tarExists <- FS.exists archivePath + -- unpack the tars in a temp folder, then move to local cache + let tarInnerFolder = PackageName.print name <> "-" <> Version.print v + tempDir <- mkTemp + FS.mkdirp tempDir + tarIsGood <- + if tarExists then do + logDebug $ "Trying to unpack archive to temp folder: " <> tempDir + map (either (const false) (const true)) $ liftEffect $ Tar.extract { filename: archivePath, cwd: tempDir } + else + pure false + case tarExists, tarIsGood, offline of + true, true, _ -> pure unit -- Tar exists and is good, and we already unpacked it. Happy days! + _, _, Offline -> die $ "Package " <> packageVersion <> " is not in the local cache, and Spago is running in offline mode - can't make progress." + _, _, Online -> do + let packageUrl = "https://packages.registry.purescript.org/" <> PackageName.print name <> "/" <> versionString <> ".tar.gz" + logInfo $ "Fetching package " <> packageVersion + response <- liftAff $ withBackoff' $ Http.request + ( Http.defaultRequest + { method = Left Method.GET + , responseFormat = Response.arrayBuffer + , url = packageUrl + } + ) + case response of + Nothing -> die $ "Couldn't reach the registry at " <> packageUrl + Just (Left err) -> die $ "Couldn't fetch package " <> packageVersion <> ":\n " <> Http.printError err + Just (Right { status, body }) | status /= StatusCode 200 -> do + (buf :: Buffer) <- liftEffect $ Buffer.fromArrayBuffer body + bodyString <- liftEffect $ Buffer.toString Encoding.UTF8 buf + die $ "Couldn't fetch package " <> packageVersion <> ", status was not ok " <> show status <> ", got answer:\n " <> bodyString + Just (Right r@{ body: archiveArrayBuffer }) -> do + logDebug $ "Got status: " <> show r.status + -- check the size and hash of the tar against the metadata + archiveBuffer <- liftEffect $ Buffer.fromArrayBuffer archiveArrayBuffer + archiveSize <- liftEffect $ Buffer.size archiveBuffer + archiveSha <- liftEffect $ Sha256.hashBuffer archiveBuffer + unless (Int.toNumber archiveSize == versionMetadata.bytes) do + die $ "Archive fetched for " <> packageVersion <> " has a different size (" <> show archiveSize <> ") than expected (" <> show versionMetadata.bytes <> ")" + unless (archiveSha == versionMetadata.hash) do + die $ "Archive fetched for " <> packageVersion <> " has a different hash (" <> Sha256.print archiveSha <> ") than expected (" <> Sha256.print versionMetadata.hash <> ")" + -- if everything's alright we stash the tar in the global cache + logDebug $ "Fetched archive for " <> packageVersion <> ", saving it in the global cache: " <> archivePath + FS.writeFile archivePath archiveBuffer + logDebug $ "Unpacking archive to temp folder: " <> tempDir + (liftEffect $ Tar.extract { filename: archivePath, cwd: tempDir }) >>= case _ of + Right _ -> pure unit + Left err -> die [ "Failed to decode downloaded package " <> packageVersion <> ", error:", show err ] + logDebug $ "Moving extracted file to local cache:" <> localPackageLocation + FS.moveSync { src: (Path.concat [ tempDir, tarInnerFolder ]), dst: localPackageLocation } + -- Local package, no work to be done + LocalPackage _ -> pure unit + WorkspacePackage _ -> pure unit + + pure dependencies + +type LockfileBuilderResult = + { workspacePackages :: Map PackageName Lock.WorkspaceLockPackage + , packages :: Map PackageName Lock.LockEntry + } + +writeNewLockfile :: forall a. String -> PackageTransitiveDeps -> Spago (FetchEnv a) Unit +writeNewLockfile reason allTransitiveDeps = do + logInfo $ reason <> ", generating it..." + { workspace } <- ask + let + processPackage :: LockfileBuilderResult -> Tuple PackageName (Tuple PackageName Package) -> Spago (FetchEnv a) LockfileBuilderResult + processPackage result (Tuple workspacePackageName (Tuple dependencyName dependencyPackage)) = do + (packageDependencies :: Array PackageName) <- (Array.fromFoldable <<< Map.keys <<< fromMaybe Map.empty) + <$> getPackageDependencies dependencyName dependencyPackage + let + updatePackage r package = (updateWorkspacePackage r) + { packages = Map.insert dependencyName package r.packages } + updateWorkspacePackage r = r + { workspacePackages = Map.alter + ( case _ of + Nothing -> Nothing + Just pkg -> Just $ pkg { build_plan = Set.insert dependencyName (pkg.build_plan) } + ) + workspacePackageName + r.workspacePackages + } + + case dependencyPackage of + WorkspacePackage _pkg -> pure $ updateWorkspacePackage result + GitPackage gitPackage -> do + let packageLocation = Config.getPackageLocation dependencyName dependencyPackage + Git.getRef (Just packageLocation) >>= case _ of + Left err -> die err -- TODO maybe not die here? + Right rev -> pure $ updatePackage result $ FromGit { rev, dependencies: packageDependencies, url: gitPackage.git, subdir: gitPackage.subdir } + RegistryVersion version -> do + metadata <- Registry.getMetadata dependencyName + registryVersion <- case (metadata >>= (\(Metadata meta) -> Either.note "Didn't find version in the metadata file" $ Map.lookup version meta.published)) of + Left err -> die $ "Couldn't read metadata, reason:\n " <> err + Right { hash: integrity } -> + pure { version, integrity, dependencies: packageDependencies } + pure $ updatePackage result $ FromRegistry registryVersion + LocalPackage { path } -> do + pure $ updatePackage result $ FromPath { path, dependencies: packageDependencies } let - shouldWriteLockFile = case workspace.selected, workspace.lockfile of - Nothing, GenerateLockfile -> true - Nothing, (UseLockfile _) -> true - _, _ -> false - - when shouldWriteLockFile do - logInfo "Writing a new lockfile" - liftAff $ FS.writeYamlFile Lock.lockfileCodec "spago.lock" lockfile - - -- then for every package we have we try to download it, and copy it in the local cache - logInfo "Downloading dependencies..." - - -- the repl needs a support package, so we fetch it here as a sidecar - supportPackage <- Repl.supportPackage workspace.packageSet - let transitiveDeps' = Map.union transitiveDeps supportPackage - - parallelise $ (flip map) (Map.toUnfoldable transitiveDeps' :: Array (Tuple PackageName Package)) \(Tuple name package) -> do - let localPackageLocation = Config.getPackageLocation name package - -- first of all, we check if we have the package in the local cache. If so, we don't even do the work - unlessM (FS.exists localPackageLocation) case package of - GitPackage gitPackage -> getGitPackageInLocalCache name gitPackage - RegistryVersion v -> do - -- if the version comes from the registry then we have a longer list of things to do - let versionString = Registry.Version.print v - let packageVersion = PackageName.print name <> "@" <> versionString - -- get the metadata for the package, so we have access to the hash and other info - metadata <- runSpago { logOptions } $ getMetadata name - case (metadata >>= (\(Metadata meta) -> Either.note "Didn't find version in the metadata file" $ Map.lookup v meta.published)) of - Left err -> die $ "Couldn't read metadata, reason:\n " <> err - Right versionMetadata -> do - logDebug $ "Metadata read: " <> printJson Metadata.publishedMetadataCodec versionMetadata - -- then check if we have a tarball cached. If not, download it - let globalCachePackagePath = Path.concat [ Paths.globalCachePath, "packages", PackageName.print name ] - let archivePath = Path.concat [ globalCachePackagePath, versionString <> ".tar.gz" ] - FS.mkdirp globalCachePackagePath - -- We need to see if the tarball is there, and if we can decompress it. - -- This is because if Spago is killed while it's writing the tar, then it might leave it corrupted. - -- By checking that it's broken we can try to redownload it here. - tarExists <- FS.exists archivePath - -- unpack the tars in a temp folder, then move to local cache - let tarInnerFolder = PackageName.print name <> "-" <> Version.print v - tempDir <- mkTemp - FS.mkdirp tempDir - tarIsGood <- - if tarExists then do - logDebug $ "Trying to unpack archive to temp folder: " <> tempDir - map (either (const false) (const true)) $ liftEffect $ Tar.extract { filename: archivePath, cwd: tempDir } - else - pure false - case tarExists, tarIsGood, offline of - true, true, _ -> pure unit -- Tar exists and is good, and we already unpacked it. Happy days! - _, _, Offline -> die $ "Package " <> packageVersion <> " is not in the local cache, and Spago is running in offline mode - can't make progress." - _, _, Online -> do - let packageUrl = "https://packages.registry.purescript.org/" <> PackageName.print name <> "/" <> versionString <> ".tar.gz" - logInfo $ "Fetching package " <> packageVersion - response <- liftAff $ withBackoff' $ Http.request - ( Http.defaultRequest - { method = Left Method.GET - , responseFormat = Response.arrayBuffer - , url = packageUrl - } - ) - case response of - Nothing -> die $ "Couldn't reach the registry at " <> packageUrl - Just (Left err) -> die $ "Couldn't fetch package " <> packageVersion <> ":\n " <> Http.printError err - Just (Right { status, body }) | status /= StatusCode 200 -> do - (buf :: Buffer) <- liftEffect $ Buffer.fromArrayBuffer body - bodyString <- liftEffect $ Buffer.toString Encoding.UTF8 buf - die $ "Couldn't fetch package " <> packageVersion <> ", status was not ok " <> show status <> ", got answer:\n " <> bodyString - Just (Right r@{ body: archiveArrayBuffer }) -> do - logDebug $ "Got status: " <> show r.status - -- check the size and hash of the tar against the metadata - archiveBuffer <- liftEffect $ Buffer.fromArrayBuffer archiveArrayBuffer - archiveSize <- liftEffect $ Buffer.size archiveBuffer - archiveSha <- liftEffect $ Sha256.hashBuffer archiveBuffer - unless (Int.toNumber archiveSize == versionMetadata.bytes) do - die $ "Archive fetched for " <> packageVersion <> " has a different size (" <> show archiveSize <> ") than expected (" <> show versionMetadata.bytes <> ")" - unless (archiveSha == versionMetadata.hash) do - die $ "Archive fetched for " <> packageVersion <> " has a different hash (" <> Sha256.print archiveSha <> ") than expected (" <> Sha256.print versionMetadata.hash <> ")" - -- if everything's alright we stash the tar in the global cache - logDebug $ "Fetched archive for " <> packageVersion <> ", saving it in the global cache: " <> archivePath - FS.writeFile archivePath archiveBuffer - logDebug $ "Unpacking archive to temp folder: " <> tempDir - (liftEffect $ Tar.extract { filename: archivePath, cwd: tempDir }) >>= case _ of - Right _ -> pure unit - Left err -> die [ "Failed to decode downloaded package " <> packageVersion <> ", error:", show err ] - logDebug $ "Moving extracted file to local cache:" <> localPackageLocation - FS.moveSync { src: (Path.concat [ tempDir, tarInnerFolder ]), dst: localPackageLocation } - -- Local package, no work to be done - LocalPackage _ -> pure unit - WorkspacePackage _ -> pure unit - - pure dependencies + toArray :: forall k v. Map k v -> Array (Tuple k v) + toArray = Map.toUnfoldable + ({ packages, workspacePackages } :: LockfileBuilderResult) <- + Array.foldM processPackage + { workspacePackages: Map.fromFoldable $ map Config.workspacePackageToLockfilePackage (Config.getWorkspacePackages workspace.packageSet), packages: Map.empty } + (foldMap sequence $ toArray $ map toArray allTransitiveDeps) + + let + lockfile = + { packages + , workspace: + { package_set: case workspace.packageSet.buildType of + RegistrySolverBuild _ -> Nothing + PackageSetBuild info _ -> Just info + , packages: workspacePackages + , extra_packages: fromMaybe Map.empty workspace.workspaceConfig.extra_packages + } + } + liftAff $ FS.writeYamlFile Lock.lockfileCodec "spago.lock" lockfile + logInfo "Lockfile written to spago.lock. Please commit this file." toAllDependencies :: PackageTransitiveDeps -> PackageMap toAllDependencies = foldl (Map.unionWith (\l _ -> l)) Map.empty @@ -296,8 +350,7 @@ getGitPackageInLocalCache name package = do getPackageDependencies :: forall a. PackageName -> Package -> Spago (FetchEnv a) (Maybe (Map PackageName Range)) getPackageDependencies packageName package = case package of RegistryVersion v -> do - { getManifestFromIndex, logOptions } <- ask - maybeManifest <- runSpago { logOptions } $ getManifestFromIndex packageName v + maybeManifest <- Registry.getManifestFromIndex packageName v pure $ map (_.dependencies <<< unwrap) maybeManifest GitPackage p -> do -- Note: we get the package in local cache nonetheless, @@ -341,20 +394,53 @@ type TransitiveDepsResult = } } -getTransitiveDeps :: forall a. Dependencies -> Spago (FetchEnv a) PackageMap -getTransitiveDeps (Dependencies deps) = do - let depsRanges = map (fromMaybe Config.widestRange) deps +getTransitiveDeps :: forall a. Config.WorkspacePackage -> Spago (FetchEnv a) PackageMap +getTransitiveDeps workspacePackage = do + let depsRanges = map (fromMaybe Config.widestRange) (unwrap $ getWorkspacePackageDeps workspacePackage) { workspace } <- ask - case workspace.packageSet of - Registry extraPackages -> do - plan <- getTransitiveDepsFromRegistry depsRanges extraPackages - logDebug $ "Got a plan from the Solver: " <> printJson (Internal.Codec.packageMap Version.codec) plan - pure (map RegistryVersion plan) - PackageSet set -> getTransitiveDepsFromPackageSet set (Array.fromFoldable $ Map.keys depsRanges) + case workspace.packageSet.lockfile of + -- If we have a lockfile we can just use that - we don't need build a plan, since we store it for every workspace + -- package, so we can just filter out the packages we need. + Right lockfile -> do + case Map.lookup workspacePackage.package.name lockfile.workspace.packages of + Nothing -> die $ "Package " <> PackageName.print workspacePackage.package.name <> " not found in lockfile" + Just { build_plan } -> do + let + allWorkspacePackages = Map.fromFoldable $ map (\p -> Tuple p.package.name (WorkspacePackage p)) (Config.getWorkspacePackages workspace.packageSet) + + isInBuildPlan :: forall v. PackageName -> v -> Boolean + isInBuildPlan name _package = Set.member name build_plan + + workspacePackagesWeNeed = Map.filterWithKey isInBuildPlan allWorkspacePackages + otherPackages = map fromLockEntry $ Map.filterWithKey isInBuildPlan lockfile.packages + + pure $ Map.union otherPackages workspacePackagesWeNeed + + -- No lockfile, we need to build a plan from scratch, and hit the Registry and so on + Left _ -> case workspace.packageSet.buildType of + RegistrySolverBuild extraPackages -> do + plan <- getTransitiveDepsFromRegistry depsRanges extraPackages + logDebug $ "Got a plan from the Solver: " <> printJson (Internal.Codec.packageMap Version.codec) plan + pure (map RegistryVersion plan) + PackageSetBuild _info set -> getTransitiveDepsFromPackageSet set (Array.fromFoldable $ Map.keys depsRanges) + + where + -- Note: here we can safely discard the dependencies because we don't need to bother about building a build plan, + -- we already built it when the lockfile was put together in the first place. All the dependency info is there so + -- that other things can use it (e.g. Nix), but Spago is not going to need it at this point. + fromLockEntry :: LockEntry -> Package + fromLockEntry = case _ of + FromPath { path } -> LocalPackage { path } + FromRegistry { version } -> RegistryVersion version + FromGit { rev, dependencies, url, subdir } -> GitPackage + { ref: rev + , dependencies: Just $ wrap $ Map.fromFoldable $ map (\p -> Tuple p Nothing) dependencies + , git: url + , subdir + } getTransitiveDepsFromRegistry :: forall a. Map PackageName Range -> PackageMap -> Spago (FetchEnv a) (Map PackageName Version) getTransitiveDepsFromRegistry depsRanges extraPackages = do - { logOptions, getMetadata, getManifestFromIndex } <- ask let loader :: PackageName -> Spago (FetchEnv a) (Map Version (Map PackageName Range)) loader packageName = do @@ -362,13 +448,13 @@ getTransitiveDepsFromRegistry depsRanges extraPackages = do case Map.lookup packageName extraPackages of Just p -> map (Map.singleton (getVersionFromPackage p) <<< fromMaybe Map.empty) $ getPackageDependencies packageName p Nothing -> do - maybeMetadata <- runSpago { logOptions } (getMetadata packageName) + maybeMetadata <- Registry.getMetadata packageName let versions = case maybeMetadata of Right (Metadata metadata) -> Array.fromFoldable $ Map.keys metadata.published Left _err -> [] map (Map.fromFoldable :: Array _ -> Map _ _) $ for versions \v -> do - maybeManifest <- runSpago { logOptions } $ getManifestFromIndex packageName v + maybeManifest <- Registry.getManifestFromIndex packageName v let deps = fromMaybe Map.empty $ map (_.dependencies <<< unwrap) maybeManifest pure (Tuple v deps) maybePlan <- Registry.Solver.loadAndSolve loader depsRanges @@ -384,7 +470,6 @@ getTransitiveDepsFromRegistry depsRanges extraPackages = do getTransitiveDepsFromPackageSet :: forall a. PackageMap -> Array PackageName -> Spago (FetchEnv a) PackageMap getTransitiveDepsFromPackageSet packageSet deps = do logDebug "Getting transitive deps" - -- { workspace } <- ask packageDependenciesCache <- liftEffect $ Ref.new Map.empty let memoisedGetPackageDependencies :: PackageName -> Package -> Spago (FetchEnv a) (Maybe (Map PackageName Range)) diff --git a/src/Spago/Command/Init.purs b/src/Spago/Command/Init.purs index 5cc2adeb1..0743af4d8 100644 --- a/src/Spago/Command/Init.purs +++ b/src/Spago/Command/Init.purs @@ -31,7 +31,7 @@ type InitOptions = -- TODO run git init? Is that desirable? -run :: forall a. InitOptions -> Spago (RegistryEnv a) Config +run :: InitOptions -> Spago (RegistryEnv _) Config run opts = do logInfo "Initializing a new project..." @@ -175,7 +175,6 @@ defaultConfig' opts = , package_set: setVersion # map \set -> SetFromRegistry { registry: set } , build_opts: Nothing , backend: Nothing - , lock: Nothing } } where diff --git a/src/Spago/Command/Ls.purs b/src/Spago/Command/Ls.purs index 3439b053f..10893ed1b 100644 --- a/src/Spago/Command/Ls.purs +++ b/src/Spago/Command/Ls.purs @@ -13,7 +13,7 @@ import Spago.Prelude import Data.Codec.Argonaut as CA import Data.Codec.Argonaut.Common as CAC import Data.Codec.Argonaut.Record as CAR -import Data.Foldable (elem, traverse_) +import Data.Foldable (elem) import Data.Map (filterKeys) import Data.Map as Map import Data.Tuple.Nested (type (/\)) @@ -22,19 +22,21 @@ import Registry.Internal.Codec (packageMap) import Registry.PackageName as PackageName import Registry.Version as Version import Spago.Command.Fetch as Fetch -import Spago.Config (Package(..), PackageSet(..), Workspace, WorkspacePackage) +import Spago.Config (BuildType(..), Package(..), Workspace, WorkspacePackage) import Spago.Config as Config import Spago.Paths as Paths import Type.Proxy (Proxy(..)) type LsPackagesArgs = { json :: Boolean + , pure :: Boolean } type LsDepsArgs = { json :: Boolean , transitive :: Boolean , selectedPackage :: Maybe String + , pure :: Boolean } type LsDepsOpts = @@ -87,9 +89,9 @@ listPackageSet :: LsPackagesArgs -> Spago LsSetEnv Unit listPackageSet { json } = do logDebug "Running `listPackageSet`" { workspace } <- ask - case workspace.packageSet of - Registry _extraPackages -> die "Cannot list the packages in the package set, as none is configured for the project." - PackageSet packageSet -> do + case workspace.packageSet.buildType of + RegistrySolverBuild _extraPackages -> die "Cannot list the packages in the package set, as none is configured for the project." + PackageSetBuild _info packageSet -> do let packages = Map.toUnfoldable packageSet case json of true -> formatPackagesJson packages diff --git a/src/Spago/Command/Publish.purs b/src/Spago/Command/Publish.purs index 5fda39365..15ab7a09d 100644 --- a/src/Spago/Command/Publish.purs +++ b/src/Spago/Command/Publish.purs @@ -29,6 +29,7 @@ import Registry.Operation.Validation as Operation.Validation import Registry.PackageName as PackageName import Registry.Version as Version import Routing.Duplex as Duplex +import Spago.Command.Build (BuildEnv) import Spago.Command.Build as Build import Spago.Command.Fetch as Fetch import Spago.Config (Package(..), Workspace, WorkspacePackage) @@ -42,6 +43,8 @@ import Spago.Log (LogVerbosity(..)) import Spago.Log as Log import Spago.Purs (Purs) import Spago.Purs.Graph as Graph +import Spago.Registry (PreRegistryEnv) +import Spago.Registry as Registry type PublishData = { name :: PackageName @@ -52,8 +55,7 @@ type PublishData = } type PublishEnv a = - { getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) - , getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata) + { getRegistry :: Spago (PreRegistryEnv ()) Registry.RegistryFunctions , workspace :: Workspace , logOptions :: LogOptions , offline :: OnlineStatus @@ -89,13 +91,7 @@ publish _args = do ) resultRef - env@ - { selected: selected' - , purs - , dependencies - , logOptions - , getMetadata - } <- ask + env@{ selected: selected', purs, dependencies } <- ask let (selected :: WorkspacePackage) = selected' { hasTests = false } let name = selected.package.name let strName = PackageName.print name @@ -103,22 +99,7 @@ publish _args = do logDebug $ "Publishing package " <> strName -- As first thing we run a build to make sure the package compiles at all - runSpago - -- We explicitly list the env fields because `Record.merge` didn't compile. - { getManifestFromIndex: env.getManifestFromIndex - , getMetadata: env.getMetadata - , workspace: env.workspace { selected = Just selected } - , logOptions: env.logOptions - , git: env.git - , purs: env.purs - , selected - , dependencies: env.dependencies - , psaCliFlags: - { statVerbosity: (Nothing :: Maybe Core.StatVerbosity) - , strict: (Nothing :: Maybe Boolean) - } - , pedanticPackages: false - } + runBuild { selected, dependencies: env.dependencies } ( Build.run { depsOnly: false , pursArgs: [] @@ -169,7 +150,7 @@ publish _args = do -- Get the metadata file for this package. -- It will exist if the package has been published at some point, it will not if the package is new. -- We make a new one if that's the case. - metadata <- runSpago { logOptions } (getMetadata name) >>= case _ of + metadata <- Registry.getMetadata name >>= case _ of Right (Metadata metadata) -> pure metadata Left err -> do logDebug $ "Got error while reading metadata file: " <> err @@ -341,8 +322,8 @@ publish _args = do <> Log.break die' $ Array.fromFoldable errors Right { expectedVersion, publishingData: publishingData@{ resolutions } } -> do - logInfo "Passed preliminary checks. " - -- This requires login credentials. + logInfo "Passed preliminary checks." + -- This requires login credentials. Git.pushTag Nothing expectedVersion >>= case _ of Left err -> die $ toDoc [ err @@ -356,22 +337,7 @@ publish _args = do -- from the solver (this is because the build might terminate the process, and we shall output the errors first) logInfo "Building again with the build plan from the solver..." let buildPlanDependencies = map Config.RegistryVersion resolutions - runSpago - -- We explicitly list the env fields because `Record.merge` didn't compile. - { getManifestFromIndex: env.getManifestFromIndex - , getMetadata: env.getMetadata - , workspace: env.workspace { selected = Just selected } - , logOptions: env.logOptions - , git: env.git - , purs: env.purs - , selected: env.selected - , dependencies: Map.singleton selected.package.name buildPlanDependencies - , psaCliFlags: - { statVerbosity: (Nothing :: Maybe Core.StatVerbosity) - , strict: (Nothing :: Maybe Boolean) - } - , pedanticPackages: false - } + runBuild { selected, dependencies: Map.singleton selected.package.name buildPlanDependencies } ( Build.run { depsOnly: false , pursArgs: [] @@ -391,6 +357,25 @@ publish _args = do waitForJobFinish jobId pure newPublishingData + where + -- If you are reading this and think that you can make it look nicer with + -- a `Record.merge` then please, be my guest + runBuild :: _ -> Spago (BuildEnv _) _ -> Spago (PublishEnv _) _ + runBuild { selected, dependencies } action = do + env <- ask + runSpago + { purs: env.purs + , git: env.git + , dependencies: dependencies + , logOptions: env.logOptions + , workspace: env.workspace { selected = Just selected } + , psaCliFlags: + { statVerbosity: (Nothing :: Maybe Core.StatVerbosity) + , strict: (Nothing :: Maybe Boolean) + } + , pedanticPackages: false + } + action callRegistry :: forall env a b. String -> JsonCodec b -> Maybe { codec :: JsonCodec a, data :: a } -> Spago (PublishEnv env) b callRegistry url outputCodec maybeInput = handleError do diff --git a/src/Spago/Command/Registry.purs b/src/Spago/Command/Registry.purs index 1694ec1a4..81caba8c8 100644 --- a/src/Spago/Command/Registry.purs +++ b/src/Spago/Command/Registry.purs @@ -10,7 +10,6 @@ import Data.Formatter.DateTime as DateTime import Data.Map as Map import Data.String (Pattern(..)) import Data.String as String -import Node.Path as Path import Registry.Internal.Codec as Internal import Registry.Internal.Codec as Internal.Codec import Registry.Internal.Format as Internal.Format @@ -18,9 +17,8 @@ import Registry.Metadata as Metadata import Registry.PackageName as PackageName import Registry.Version as Version import Spago.Db as Db -import Spago.FS as FS -import Spago.Paths as Paths import Spago.Registry (RegistryEnv) +import Spago.Registry as Registry type RegistrySearchArgs = { package :: String @@ -28,10 +26,10 @@ type RegistrySearchArgs = } -- TODO: I guess we could also search in (1) the tags and (2) the description -search :: forall a. RegistrySearchArgs -> Spago (RegistryEnv a) Unit +search :: RegistrySearchArgs -> Spago (RegistryEnv _) Unit search { package: searchString, json } = do logInfo $ "Searching for " <> show searchString <> " in the Registry package names..." - metadataFiles <- FS.ls $ Path.concat [ Paths.registryPath, "metadata" ] + metadataFiles <- Registry.listMetadataFiles let matches = Array.filter (String.contains (Pattern searchString)) (Array.mapMaybe (String.stripSuffix (Pattern ".json")) metadataFiles) @@ -39,12 +37,11 @@ search { package: searchString, json } = do logError "Did not find any packages matching the search string." else do -- We have only the match names, at least we get the time of the last release to be even a little useful - { getMetadata, logOptions } <- ask infos <- map (Map.fromFoldable <<< Array.catMaybes) $ for matches \match -> case PackageName.parse match of Left err -> do logWarn $ "Couldn't parse package name: " <> err pure Nothing - Right packageName -> runSpago { logOptions } (getMetadata packageName) >>= case _ of + Right packageName -> Registry.getMetadata packageName >>= case _ of Left err -> do logWarn $ "Couldn't read metadata for pacakge " <> PackageName.print packageName <> ", error: " <> err pure Nothing @@ -77,14 +74,13 @@ type RegistryInfoArgs = , json :: Boolean } -info :: forall a. RegistryInfoArgs -> Spago (RegistryEnv a) Unit +info :: RegistryInfoArgs -> Spago (RegistryEnv _) Unit info { package, json } = do packageName <- case PackageName.parse package of Left err -> die [ toDoc "Could not parse package name, error:", indent (toDoc $ show err) ] Right name -> pure name - { getMetadata, logOptions } <- ask - runSpago { logOptions } (getMetadata packageName) >>= case _ of + Registry.getMetadata packageName >>= case _ of Left err -> do logDebug err die $ "Could not find package " <> PackageName.print packageName @@ -99,7 +95,7 @@ type RegistryPackageSetsArgs = , json :: Boolean } -packageSets :: forall a. RegistryPackageSetsArgs -> Spago (RegistryEnv a) Unit +packageSets :: RegistryPackageSetsArgs -> Spago (RegistryEnv _) Unit packageSets { latest, json } = do { db } <- ask availableSets <- liftEffect $ Db.selectPackageSets db diff --git a/src/Spago/Command/Repl.purs b/src/Spago/Command/Repl.purs index d3ab77bce..8d5553300 100644 --- a/src/Spago/Command/Repl.purs +++ b/src/Spago/Command/Repl.purs @@ -23,9 +23,9 @@ type ReplEnv a = | a } -run :: forall a. Spago (ReplEnv a) Unit +run :: Spago (ReplEnv _) Unit run = do - { dependencies, purs, logOptions, pursArgs, selected, depsOnly, supportPackage } <- ask + { dependencies, pursArgs, selected, depsOnly, supportPackage } <- ask let allDependencies = Map.unionWith (\l _ -> l) supportPackage $ Fetch.toAllDependencies dependencies @@ -35,4 +35,4 @@ run = do , depsOnly , withTests: true } - void $ runSpago { purs, logOptions } $ Purs.repl globs pursArgs + void $ Purs.repl globs pursArgs diff --git a/src/Spago/Command/Script.purs b/src/Spago/Command/Script.purs index 84fb9babd..9d579a2b4 100644 --- a/src/Spago/Command/Script.purs +++ b/src/Spago/Command/Script.purs @@ -1,3 +1 @@ module Spago.Command.Script where - -import Prelude diff --git a/src/Spago/Command/Sources.purs b/src/Spago/Command/Sources.purs index 240e84cb4..d3ee23a90 100644 --- a/src/Spago/Command/Sources.purs +++ b/src/Spago/Command/Sources.purs @@ -22,11 +22,11 @@ run { json } = do Just selected -> NEA.singleton selected Nothing -> Config.getWorkspacePackages workspace.packageSet - deps = foldMap Fetch.getWorkspacePackageDeps selectedPackages + transitiveDeps <- traverse Fetch.getTransitiveDeps + $ Map.fromFoldable + $ map (\p -> Tuple p.package.name p) selectedPackages - transitiveDeps <- Fetch.getTransitiveDeps deps - - let transitivePackages = Map.union (Map.fromFoldable (map (\p -> Tuple (p.package.name) (WorkspacePackage p)) selectedPackages)) transitiveDeps + let transitivePackages = Map.union (Map.fromFoldable (map (\p -> Tuple (p.package.name) (WorkspacePackage p)) selectedPackages)) (Fetch.toAllDependencies transitiveDeps) let globs = Array.foldMap diff --git a/src/Spago/Command/Uninstall.purs b/src/Spago/Command/Uninstall.purs index 4abae7023..4e06e3da1 100644 --- a/src/Spago/Command/Uninstall.purs +++ b/src/Spago/Command/Uninstall.purs @@ -1,6 +1,5 @@ module Spago.Command.Uninstall ( run - , UninstallEnv , UninstallArgs ) where @@ -8,12 +7,17 @@ import Spago.Prelude import Data.Array as Array import Data.Array.NonEmpty as NEA -import Data.FoldableWithIndex (foldlWithIndex) import Data.Map as Map +import Data.Newtype (wrap) +import Data.Set as Set import Data.Set.NonEmpty as NonEmptySet +import Data.String as String import Node.Path as Path +import Node.Process as Process import Registry.PackageName as PackageName -import Spago.Config (Dependencies, PackageConfig, Workspace) +import Spago.Command.Fetch (FetchEnv) +import Spago.Command.Fetch as Fetch +import Spago.Config (BuildType(..), Dependencies, Package(..), PackageConfig) import Spago.Config as Config import Spago.Config as Core import Spago.FS as FS @@ -23,98 +27,101 @@ type UninstallArgs = , testDeps :: Boolean } -type UninstallEnv = - { workspace :: Workspace - , logOptions :: LogOptions - } - -run :: UninstallArgs -> Spago UninstallEnv Unit +run :: UninstallArgs -> Spago (FetchEnv _) Unit run args = do logDebug "Running `spago uninstall`" { workspace } <- ask + + { sourceOrTestString, deps, configPath, yamlDoc, name } <- case workspace.selected, workspace.rootPackage of + Just p, _ -> toContext (Path.concat [ p.path, "spago.yaml" ]) p.doc p.package + Nothing, Just rootPackage -> toContext "spago.yaml" workspace.doc rootPackage + Nothing, Nothing -> die "No package was selected. Please select a package." let - modifyConfig - :: FilePath - -> YamlDoc Core.Config - -> String - -> NonEmptyArray PackageName - -> Spago UninstallEnv Unit - modifyConfig configPath yamlDoc sourceOrTestString = \removedPackages -> do - logInfo - [ "Removing the following " <> sourceOrTestString <> " dependencies:" - , " " <> intercalateMap ", " PackageName.print removedPackages - ] - logDebug $ "Editing config file at path: " <> configPath - liftEffect $ Config.removePackagesFromConfig yamlDoc args.testDeps $ NonEmptySet.fromFoldable1 removedPackages - liftAff $ FS.writeYamlDocFile configPath yamlDoc - where - intercalateMap sep f = _.val <<< foldl go { init: true, val: "" } - where - go acc next = { init: false, val: if acc.init then f next else acc.val <> sep <> f next } + { warn, removed: removedSet } = separate deps + warnAbout = NEA.fromFoldable warn + removed = NEA.fromFoldable removedSet + newDeps = wrap $ Map.filterKeys (not <<< flip Set.member removedSet) $ unwrap deps + modifyDoc = modifyConfig configPath yamlDoc sourceOrTestString - toContext - :: FilePath - -> YamlDoc Core.Config - -> PackageConfig - -> Either - PackageName - { name :: PackageName - , deps :: Dependencies - , sourceOrTestString :: String - , modifyDoc :: NonEmptyArray PackageName -> Spago UninstallEnv Unit - } - toContext configPath yamlDoc pkgConfig - | args.testDeps = case pkgConfig.test of - Nothing -> - Left pkgConfig.name - Just { dependencies } -> do - let sourceOrTestString = "test" - Right - { name: pkgConfig.name - , deps: dependencies - , sourceOrTestString - , modifyDoc: modifyConfig configPath yamlDoc sourceOrTestString - } - | otherwise = do - let sourceOrTestString = "source" - Right - { name: pkgConfig.name - , deps: pkgConfig.dependencies - , sourceOrTestString - , modifyDoc: modifyConfig configPath yamlDoc sourceOrTestString - } - missingTestConfigOrContext <- case workspace.selected of - Just p -> - pure $ toContext (Path.concat [ p.path, "spago.yaml" ]) p.doc p.package + logDebug $ "Existing " <> sourceOrTestString <> " dependencies are: " <> (String.joinWith ", " $ map PackageName.print $ Array.fromFoldable $ Map.keys $ unwrap deps) + for_ warnAbout \undeclaredPkgs -> + logWarn + [ toDoc $ "The following packages cannot be uninstalled because they are not declared in the package's " <> sourceOrTestString <> " dependencies:" + , indent2 $ toDoc $ String.joinWith ", " $ Array.fromFoldable $ map PackageName.print undeclaredPkgs + ] + + case removed of Nothing -> do - case workspace.rootPackage of - Nothing -> - die "No package was selected. Please select a package." - Just p -> - pure $ toContext "spago.yaml" workspace.doc p - case missingTestConfigOrContext of - Left pkgName -> - logWarn $ "Could not uninstall test dependencies for " <> PackageName.print pkgName <> " because it does not have a test configuration." - Right context -> do - logDebug $ "Existing " <> context.sourceOrTestString <> " dependencies are: " <> (Array.intercalate ", " $ foldlWithIndex (\k a _ -> Array.snoc a $ PackageName.print k) [] $ unwrap context.deps) + logWarn $ "The package config for " <> PackageName.print name <> " was not updated." + -- We might be in a place where the config file is untouched, but we still need to update the lockfile + case workspace.packageSet.lockfile of + Right _ -> pure unit + Left reason -> writeNewLockfile reason + Just removed' -> do + modifyDoc removed' + + currentWorkspacePackage <- NEA.find (\p -> p.package.name == name) (Config.getWorkspacePackages workspace.packageSet) `justOrDieWith` "Impossible: package must be in workspace packages" let - { warn, removed } = foldl separate init args.dependenciesToRemove - where - init = { warn: [], removed: [] } + newWorkspacePackage = case args.testDeps of + false -> currentWorkspacePackage { package { dependencies = newDeps } } + true -> currentWorkspacePackage { package { test = currentWorkspacePackage.package.test # map (\t -> t { dependencies = newDeps }) } } + + newWorkspace = workspace + { packageSet = workspace.packageSet + { lockfile = Left "Lockfile is out of date (installing new packages)" + -- If we are installing packages, we need to add the new deps to the selected package + , buildType = case workspace.packageSet.buildType of + RegistrySolverBuild packageMap -> RegistrySolverBuild $ Map.insert newWorkspacePackage.package.name (WorkspacePackage newWorkspacePackage) packageMap + PackageSetBuild info packageMap -> PackageSetBuild info $ Map.insert newWorkspacePackage.package.name (WorkspacePackage newWorkspacePackage) packageMap + } + , selected = Just newWorkspacePackage + } + + local (_ { workspace = newWorkspace }) do + writeNewLockfile "Lockfile is out of date (uninstalled packages)" + + where + writeNewLockfile reason = do + { workspace } <- ask + dependencies <- traverse Fetch.getTransitiveDeps + $ Map.fromFoldable + $ map (\p -> Tuple p.package.name p) + $ Config.getWorkspacePackages workspace.packageSet + Fetch.writeNewLockfile reason dependencies - separate :: _ -> PackageName -> _ - separate acc next - | Map.member next $ unwrap context.deps = acc { removed = Array.snoc acc.removed next } - | otherwise = acc { warn = Array.snoc acc.warn next } - for_ (NEA.fromArray warn) \undeclaredPkgs -> - logWarn - [ "The following packages cannot be uninstalled because they are not declared in the package's " <> context.sourceOrTestString <> " dependencies:" - , " " <> NEA.intercalate ", " (map PackageName.print undeclaredPkgs) - ] + toContext :: FilePath -> YamlDoc Core.Config -> PackageConfig -> Spago _ (_ _) + toContext configPath yamlDoc pkgConfig = case args.testDeps of + true -> case pkgConfig.test of + Nothing -> do + logWarn $ "Could not uninstall test dependencies for " <> PackageName.print pkgConfig.name <> " because it does not have a test configuration." + liftEffect $ Process.exit 0 + Just { dependencies } -> pure + { name: pkgConfig.name + , deps: dependencies + , sourceOrTestString: "test" + , yamlDoc + , configPath + } + false -> pure + { name: pkgConfig.name + , deps: pkgConfig.dependencies + , sourceOrTestString: "source" + , yamlDoc + , configPath + } - case NEA.fromArray removed of - Nothing -> - logInfo $ "The package config for " <> PackageName.print context.name <> " was not updated." - Just removed' -> - context.modifyDoc removed' + separate :: Dependencies -> { warn :: Set PackageName, removed :: Set PackageName } + separate deps = foldl f { warn: mempty, removed: mempty } args.dependenciesToRemove + where + f :: _ -> PackageName -> _ + f acc next = case Map.member next (unwrap deps) of + true -> acc { removed = Set.insert next acc.removed } + false -> acc { warn = Set.insert next acc.warn } + modifyConfig :: FilePath -> YamlDoc Core.Config -> String -> NonEmptyArray PackageName -> Spago (FetchEnv _) Unit + modifyConfig configPath yamlDoc sourceOrTestString = \removedPackages -> do + logInfo $ "Removing the following " <> sourceOrTestString <> " dependencies: " + <> (String.joinWith ", " $ map PackageName.print $ Array.fromFoldable removedPackages) + logDebug $ "Editing config file at path: " <> configPath + liftEffect $ Config.removePackagesFromConfig yamlDoc args.testDeps $ NonEmptySet.fromFoldable1 removedPackages + liftAff $ FS.writeYamlDocFile configPath yamlDoc diff --git a/src/Spago/Config.js b/src/Spago/Config.js index 408f5210a..b9cd9122a 100644 --- a/src/Spago/Config.js +++ b/src/Spago/Config.js @@ -63,8 +63,8 @@ export function removePackagesFromConfigImpl(doc, isTest, shouldRemove) { let newItems = []; for (const el of deps.items) { if ( - (Yaml.isScalar(el) && shouldRemove(el.value)) || - (Yaml.isMap(el) && shouldRemove(el.items[0].key)) + (Yaml.isScalar(el) && shouldRemove(el.value)) || + (Yaml.isMap(el) && shouldRemove(el.items[0].key)) ) { continue; } @@ -99,7 +99,3 @@ export function addRangesToConfigImpl(doc, rangesMap) { export function setPackageSetVersionInConfigImpl(doc, version) { doc.setIn(["workspace", "package_set", "registry"], version); } - -export function updatePackageSetHashInConfigImpl(doc, sha) { - doc.setIn(["workspace", "package_set", "hash"], sha); -} diff --git a/src/Spago/Config.purs b/src/Spago/Config.purs index 817c81355..2a6d8b0d0 100644 --- a/src/Spago/Config.purs +++ b/src/Spago/Config.purs @@ -1,6 +1,6 @@ module Spago.Config ( BuildOptions - , LockfileSettings(..) + , BuildType(..) , Package(..) , PackageSet(..) , PackageMap @@ -19,6 +19,7 @@ module Spago.Config , readWorkspace , sourceGlob , setPackageSetVersionInConfig + , workspacePackageToLockfilePackage ) where import Spago.Prelude @@ -49,15 +50,16 @@ import Record as Record import Registry.Foreign.FastGlob as Glob import Registry.Internal.Codec as Internal.Codec import Registry.PackageName as PackageName +import Registry.PackageSet as Registry.PackageSet import Registry.Range as Range -import Registry.Sha256 as Sha256 import Registry.Version as Version import Spago.Core.Config as Core import Spago.FS as FS import Spago.Git as Git -import Spago.Lock (Lockfile) +import Spago.Lock (Lockfile, PackageSetInfo) import Spago.Lock as Lock import Spago.Paths as Paths +import Spago.Registry as Registry import Type.Proxy (Proxy(..)) type Workspace = @@ -69,7 +71,6 @@ type Workspace = , doc :: YamlDoc Core.Config , workspaceConfig :: Core.WorkspaceConfig , rootPackage :: Maybe Core.PackageConfig - , lockfile :: LockfileSettings } type BuildOptions = @@ -78,13 +79,6 @@ type BuildOptions = , statVerbosity :: Maybe Core.StatVerbosity } -data LockfileSettings - = UseLockfile Lockfile - | GenerateLockfile - | SkipLockfile - -derive instance Eq LockfileSettings - fromExtraPackage :: Core.ExtraPackage -> Package fromExtraPackage = case _ of Core.ExtraLocalPackage lp -> LocalPackage lp @@ -130,9 +124,14 @@ derive newtype instance Eq RemotePackageSet type PackageMap = Map PackageName Package -data PackageSet - = PackageSet PackageMap - | Registry PackageMap +data BuildType + = RegistrySolverBuild PackageMap + | PackageSetBuild PackageSetInfo PackageMap + +type PackageSet = + { buildType :: BuildType + , lockfile :: Either String Lockfile + } type WorkspacePackage = { path :: FilePath @@ -149,8 +148,8 @@ data Package -- | Reads all the configurations in the tree and builds up the Map of local -- | packages to be integrated in the package set -readWorkspace :: forall a. Maybe PackageName -> Spago (Git.GitEnv a) Workspace -readWorkspace maybeSelectedPackage = do +readWorkspace :: { maybeSelectedPackage :: Maybe PackageName, pureBuild :: Boolean } -> Spago (Registry.RegistryEnv _) Workspace +readWorkspace { maybeSelectedPackage, pureBuild } = do logInfo "Reading Spago workspace configuration..." -- First try to read the config in the root. It _has_ to contain a workspace @@ -163,27 +162,6 @@ readWorkspace maybeSelectedPackage = do ] Right { yaml: { workspace: Just workspace, package }, doc } -> pure { workspace, package, workspaceDoc: doc } - lockfile <- FS.exists "spago.lock" >>= case _ of - true -> liftAff (FS.readYamlFile Lock.lockfileCodec "spago.lock") >>= case _ of - Left error -> die $ "Your project contains a spago.lock file, but it cannot be decoded:\n" <> error - Right contents - | workspace.lock == Just false -> die "Your workspace specifies 'lock: false', but there is a spago.lock file in the workspace." - | otherwise -> do - -- TODO: here figure out if the lockfile is still valid by checking if: - -- - the package set section of the workspace is the same - -- - the dependencies of each package are the same - pure (UseLockfile contents) - false - -- If the user specifies lock: true then we always create a lockfile. - | workspace.lock == Just true -> pure GenerateLockfile - -- If the user specifies lock: false then we always skip the lockfile. - | workspace.lock == Just false -> pure SkipLockfile - -- If the user does not set the 'lock' field then we defer to whether or - -- not they are using a package set. - | otherwise -> case workspace.package_set of - Nothing -> pure GenerateLockfile - Just _ -> pure SkipLockfile - -- Then gather all the spago other configs in the tree. { succeeded: otherConfigPaths, failed, ignored } <- do result <- liftAff $ Glob.match' Paths.cwd [ "**/spago.yaml" ] { ignore: [ ".spago", "spago.yaml" ] } @@ -261,40 +239,66 @@ readWorkspace maybeSelectedPackage = do pkgs -> [ toDoc "Available packages:", indent (toDoc pkgs) ] Just p -> pure (Just p) + maybeLockfileContents <- FS.exists "spago.lock" >>= case _ of + false -> pure (Left "No lockfile found") + true -> liftAff (FS.readYamlFile Lock.lockfileCodec "spago.lock") >>= case _ of + Left error -> do + logWarn + [ "Your project contains a spago.lock file, but it cannot be decoded. Spago will generate a new one." + , "Error was: " <> error + ] + pure (Left "Could not decode lockfile") + -- Here we figure out if the lockfile is still up to date by having a quick look at the configurations: + -- if they changed since the last write, then we need to regenerate the lockfile + -- Unless! the user is passing the --pure flag, in which case we just use the lockfile + Right contents -> case pureBuild, shouldComputeNewLockfile { workspace, workspacePackages } contents.workspace of + true, _ -> do + logDebug "Using lockfile because of --pure flag" + pure (Right contents) + false, true -> pure (Left "Lockfile is out of date") + false, false -> do + logDebug "Lockfile is up to date, using it" + pure (Right contents) + -- Read in the package database { offline } <- ask - { compatibleCompiler, remotePackageSet } <- case workspace.package_set of - Nothing -> do + packageSetInfo <- case maybeLockfileContents, workspace.package_set of + _, Nothing -> do logDebug "Did not find a package set in your config, using Registry solver" - pure - { compatibleCompiler: Core.widestRange - , remotePackageSet: Nothing - } - Just (Core.SetFromRegistry { registry: v }) -> do + pure Nothing + + -- If there's a lockfile we don't attempt to fetch the package set from the registry + -- repo nor from the internet, since we already have the whole set right there + Right lockfile, _ -> do + logDebug "Found lockfile, using the package set from there" + pure lockfile.workspace.package_set + + Left _, Just address@(Core.SetFromRegistry { registry: v }) -> do logDebug "Reading the package set from the Registry repo..." - let packageSetPath = Path.concat [ Paths.registryPath, "package-sets", Version.print v <> ".json" ] - liftAff (FS.readJsonFile remotePackageSetCodec packageSetPath) >>= case _ of - Left err -> die $ "Couldn't read the package set: " <> err - Right (RemotePackageSet registryPackageSet) -> do - logInfo "Read the package set from the registry" - pure - { compatibleCompiler: Range.caret registryPackageSet.compiler - , remotePackageSet: Just registryPackageSet.packages - } - Just (Core.SetFromPath { path }) -> do + (Registry.PackageSet.PackageSet registryPackageSet) <- Registry.readPackageSet v + logDebug "Read the package set from the Registry repo" + pure $ Just + { content: map Core.RemoteRegistryVersion registryPackageSet.packages + , address + , compiler: Range.caret registryPackageSet.compiler + } + + Left _, Just address@(Core.SetFromPath { path }) -> do logDebug $ "Reading the package set from local path: " <> path liftAff (FS.readJsonFile remotePackageSetCodec path) >>= case _ of Left err -> die $ "Couldn't read the package set: " <> err Right (RemotePackageSet localPackageSet) -> do logInfo "Read the package set from local path" - pure - { compatibleCompiler: Range.caret localPackageSet.compiler - , remotePackageSet: Just localPackageSet.packages + pure $ Just + { content: localPackageSet.packages + , address + , compiler: Range.caret localPackageSet.compiler } - Just (Core.SetFromUrl { url: rawUrl, hash: maybeHash }) -> do - -- If there is a hash then we look up in the CAS, if not we fetch stuff, compute a hash and store it there - let - fetchPackageSet' = do + + Left _, Just address@(Core.SetFromUrl { url: rawUrl }) -> do + result <- case offline of + Offline -> die "You are offline, but the package set is not cached locally. Please connect to the internet and try again." + Online -> do logDebug $ "Reading the package set from URL: " <> rawUrl url <- case parseUrl rawUrl of Left err -> die $ "Could not parse URL for the package set, error: " <> show err @@ -320,24 +324,10 @@ readWorkspace maybeSelectedPackage = do Just { version } -> pure (unsafeFromRight (parseLenientVersion version)) Nothing -> die $ "Couldn't find 'metadata' package in legacy package set." pure { compiler: version, remotePackageSet: map Core.RemoteLegacyPackage set } - fetchPackageSet = case offline of - Online -> fetchPackageSet' - Offline -> die "You are offline, but the package set is not cached locally. Please connect to the internet and try again." - result <- case maybeHash of - Just hash -> readPackageSetFromHash hash >>= case _ of - Left err -> do - logDebug $ show err - fetchPackageSet - Right r -> pure r - Nothing -> do - logWarn $ "Did not find a hash for your package set import, adding it to your config..." - fetchPackageSet - newHash <- writePackageSetToHash result - logDebug $ "Package set hash: " <> Sha256.print newHash - updatePackageSetHashInConfig workspaceDoc newHash - pure - { compatibleCompiler: Range.caret result.compiler - , remotePackageSet: Just result.remotePackageSet + pure $ Just + { content: result.remotePackageSet + , compiler: Range.caret result.compiler + , address } -- Mix in the package set (a) the workspace packages, and (b) the extra_packages @@ -351,13 +341,14 @@ readWorkspace maybeSelectedPackage = do let extraPackages = map fromExtraPackage (fromMaybe Map.empty workspace.extra_packages) localPackagesOverlap = Set.intersection (Map.keys workspacePackages) (Map.keys extraPackages) - packageSet = + buildType = let localPackages = Map.union (map WorkspacePackage workspacePackages) extraPackages in - case remotePackageSet of - Nothing -> Registry localPackages - Just set -> PackageSet $ Map.union localPackages (map fromRemotePackage set) + case packageSetInfo of + Nothing -> RegistrySolverBuild localPackages + Just info -> PackageSetBuild info $ Map.union localPackages (map fromRemotePackage info.content) + packageSet = { buildType, lockfile: maybeLockfileContents } -- Note again: we only try to prevent collisions between workspace packages and local overrides. -- We otherwise want local packages to override _remote_ ones, e.g. in the case where you are @@ -392,13 +383,12 @@ readWorkspace maybeSelectedPackage = do pure { selected: maybeSelected , packageSet - , compatibleCompiler + , compatibleCompiler: fromMaybe Core.widestRange $ map _.compiler packageSetInfo , backend: workspace.backend , buildOptions , doc: workspaceDoc , workspaceConfig: workspace , rootPackage: maybePackage - , lockfile } rootPackageToWorkspacePackage @@ -410,6 +400,23 @@ rootPackageToWorkspacePackage { rootPackage, workspaceDoc } = do hasTests <- liftEffect $ FS.exists "test" pure { path: "./", doc: workspaceDoc, package: rootPackage, hasTests } +workspacePackageToLockfilePackage :: WorkspacePackage -> Tuple PackageName Lock.WorkspaceLockPackage +workspacePackageToLockfilePackage { path, package } = Tuple package.name + { path + , dependencies: package.dependencies + , test_dependencies: foldMap _.dependencies package.test + , build_plan: mempty -- Note: this is filled in later + } + +shouldComputeNewLockfile :: { workspace :: Core.WorkspaceConfig, workspacePackages :: Map PackageName WorkspacePackage } -> Lock.WorkspaceLock -> Boolean +shouldComputeNewLockfile { workspace, workspacePackages } workspaceLock = + -- the workspace packages should exactly match, except for the needed_by field, which is filled in during build plan construction + (map (workspacePackageToLockfilePackage >>> snd) workspacePackages /= (map (_ { build_plan = mempty }) workspaceLock.packages)) + -- and the extra packages should exactly match + || (fromMaybe Map.empty workspace.extra_packages /= workspaceLock.extra_packages) + -- and the package set address needs to match - we have no way to match the package set contents at this point, so we let it be + || (workspace.package_set /= map _.address workspaceLock.package_set) + getPackageLocation :: PackageName -> Package -> FilePath getPackageLocation name = Paths.mkRelative <<< case _ of RegistryVersion v -> Path.concat [ Paths.localCachePackagesPath, PackageName.print name <> "-" <> Version.print v ] @@ -464,10 +471,11 @@ testGlob = "test/**/*.purs" -- We can afford an unsafe here, if it's empty we have bigger problems getWorkspacePackages :: PackageSet -> NonEmptyArray WorkspacePackage -getWorkspacePackages = unsafeFromJust <<< NEA.fromFoldable <<< Array.mapMaybe extractWorkspacePackage <<< Map.toUnfoldable <<< case _ of - PackageSet m -> m - Registry m -> m +getWorkspacePackages = unsafeFromJust <<< NEA.fromFoldable <<< Array.mapMaybe extractWorkspacePackage <<< Map.toUnfoldable <<< extractSet <<< _.buildType where + extractSet = case _ of + PackageSetBuild _info m -> m + RegistrySolverBuild m -> m extractWorkspacePackage = case _ of Tuple _ (WorkspacePackage p) -> Just p _ -> Nothing @@ -487,45 +495,6 @@ getTopologicallySortedWorkspacePackages packageSet = do type PackageSetResult = { compiler :: Version, remotePackageSet :: Map PackageName Core.RemotePackage } -packageSetResultCodec :: JsonCodec PackageSetResult -packageSetResultCodec = CAR.object "PackageSetResult" - { compiler: Version.codec - , remotePackageSet: Internal.Codec.packageMap Core.remotePackageCodec - } - -readPackageSetFromHash :: forall a. Sha256 -> Spago (LogEnv a) (Either String PackageSetResult) -readPackageSetFromHash hash = do - hex <- liftEffect (shaToHex hash) - let path = packageSetCachePath hex - logDebug $ "Reading cached package set entry from " <> path - FS.exists path >>= case _ of - false -> pure $ Left $ "Did not find a package set cached with hash " <> Sha256.print hash - true -> (liftAff $ FS.readJsonFile packageSetResultCodec path) >>= case _ of - Left err -> pure $ Left $ "Error while reading cached package set " <> Sha256.print hash <> ": " <> err - Right res -> pure $ Right res - -writePackageSetToHash :: forall a. PackageSetResult -> Spago (LogEnv a) Sha256 -writePackageSetToHash result = do - let serialised = printJson packageSetResultCodec result - hash <- liftEffect $ Sha256.hashString serialised - hex <- liftEffect (shaToHex hash) - FS.mkdirp packageSetsCachePath - FS.writeTextFile (packageSetCachePath hex) serialised - pure hash - -packageSetsCachePath :: FilePath -packageSetsCachePath = Path.concat [ Paths.globalCachePath, "setsCAS" ] - -packageSetCachePath :: HexString → String -packageSetCachePath (HexString hash) = Path.concat [ packageSetsCachePath, hash ] - -foreign import updatePackageSetHashInConfigImpl :: EffectFn2 (YamlDoc Core.Config) String Unit - -updatePackageSetHashInConfig :: forall m. MonadAff m => MonadEffect m => YamlDoc Core.Config -> Sha256 -> m Unit -updatePackageSetHashInConfig doc sha = do - liftEffect $ runEffectFn2 updatePackageSetHashInConfigImpl doc (Sha256.print sha) - liftAff $ FS.writeYamlDocFile "spago.yaml" doc - foreign import setPackageSetVersionInConfigImpl :: EffectFn2 (YamlDoc Core.Config) String Unit setPackageSetVersionInConfig :: forall m. MonadAff m => MonadEffect m => YamlDoc Core.Config -> Version -> m Unit @@ -535,8 +504,10 @@ setPackageSetVersionInConfig doc version = do foreign import addPackagesToConfigImpl :: EffectFn3 (YamlDoc Core.Config) Boolean (Array String) Unit -addPackagesToConfig :: YamlDoc Core.Config -> Boolean -> Array PackageName -> Effect Unit -addPackagesToConfig doc isTest pkgs = runEffectFn3 addPackagesToConfigImpl doc isTest (map PackageName.print pkgs) +addPackagesToConfig :: forall m. MonadAff m => FilePath -> YamlDoc Core.Config -> Boolean -> Array PackageName -> m Unit +addPackagesToConfig configPath doc isTest pkgs = do + liftEffect $ runEffectFn3 addPackagesToConfigImpl doc isTest (map PackageName.print pkgs) + liftAff $ FS.writeYamlDocFile configPath doc foreign import removePackagesFromConfigImpl :: EffectFn3 (YamlDoc Core.Config) Boolean (PackageName -> Boolean) Unit diff --git a/src/Spago/Db.purs b/src/Spago/Db.purs index ba6bfaaab..82276e271 100644 --- a/src/Spago/Db.purs +++ b/src/Spago/Db.purs @@ -65,6 +65,10 @@ selectLatestPackageSetByCompiler db compiler = do maybePackageSet <- Nullable.toMaybe <$> Uncurried.runEffectFn2 selectLatestPackageSetByCompilerImpl db (Version.print compiler) pure $ packageSetFromJs =<< maybePackageSet +{- + +We'll need these when implementing a command for "show me what's in this package set" + selectPackageSetEntriesBySet :: Db -> Version -> Effect (Array PackageSetEntry) selectPackageSetEntriesBySet db packageSetVersion = do packageSetEntries <- Uncurried.runEffectFn2 selectPackageSetEntriesBySetImpl db (Version.print packageSetVersion) @@ -74,6 +78,7 @@ selectPackageSetEntriesByPackage :: Db -> PackageName -> Version -> Effect (Arra selectPackageSetEntriesByPackage db packageName version = do packageSetEntries <- Uncurried.runEffectFn3 selectPackageSetEntriesByPackageImpl db (PackageName.print packageName) (Version.print version) pure $ Array.mapMaybe packageSetEntryFromJs packageSetEntries +-} getLastPull :: Db -> String -> Effect (Maybe DateTime) getLastPull db key = do @@ -172,6 +177,8 @@ packageSetEntryToJs { packageSetVersion, packageName, packageVersion } = , packageVersion: Version.print packageVersion } +{- + packageSetEntryFromJs :: PackageSetEntryJs -> Maybe PackageSetEntry packageSetEntryFromJs p = hush do packageSetVersion <- Version.parse p.packageSetVersion @@ -179,6 +186,8 @@ packageSetEntryFromJs p = hush do packageVersion <- Version.parse p.packageVersion pure $ { packageSetVersion, packageName, packageVersion } +-} + -------------------------------------------------------------------------------- -- Codecs diff --git a/src/Spago/Git.purs b/src/Spago/Git.purs index 8f2afc2f6..bc4cc14ea 100644 --- a/src/Spago/Git.purs +++ b/src/Spago/Git.purs @@ -58,22 +58,27 @@ fetchRepo { git, ref } path = do Except.runExceptT $ runGit_ [ "clone", "--filter=tree:0", git, path ] Nothing result <- Except.runExceptT do Except.ExceptT $ pure cloneOrFetchResult + logDebug $ "Checking out the requested ref for " <> git <> " : " <> ref _ <- runGit [ "checkout", ref ] (Just path) -- if we are on a branch and not on a detached head, then we need to pull -- the following command will fail if on a detached head, and succeed if on a branch Except.mapExceptT ( \a -> a >>= case _ of Left _err -> pure (Right unit) - Right _ -> Except.runExceptT $ runGit_ [ "pull", "--rebase", "--autostash" ] (Just path) + Right _ -> do + logDebug "Pulling the latest changes" + Except.runExceptT $ runGit_ [ "pull", "--rebase", "--autostash" ] (Just path) ) (runGit_ [ "symbolic-ref", "-q", "HEAD" ] (Just path)) - pure case result of - Left err -> Left + case result of + Left err -> pure $ Left [ "Error while fetching the repo '" <> git <> "' at ref '" <> ref <> "':" , " " <> err ] - Right _ -> Right unit + Right _ -> do + logDebug $ "Successfully fetched the repo '" <> git <> "' at ref '" <> ref <> "'" + pure $ Right unit listTags :: forall a. Maybe FilePath -> Spago (GitEnv a) (Either Docc (Array String)) listTags cwd = do diff --git a/src/Spago/Lock.purs b/src/Spago/Lock.purs index 6920eca89..3edca3a17 100644 --- a/src/Spago/Lock.purs +++ b/src/Spago/Lock.purs @@ -5,6 +5,7 @@ module Spago.Lock , lockEntryCodec , PathLock , GitLock + , PackageSetInfo , RegistryLock , WorkspaceLock , WorkspaceLockPackage @@ -13,31 +14,47 @@ module Spago.Lock import Spago.Prelude import Data.Codec.Argonaut as CA +import Data.Codec.Argonaut.Common as CA.Common import Data.Profunctor as Profunctor import Record as Record import Registry.Internal.Codec as Registry.Codec import Registry.PackageName as PackageName +import Registry.Range as Range import Registry.Sha256 as Sha256 import Registry.Version as Version -import Spago.Core.Config (Dependencies, ExtraPackage, SetAddress) import Spago.Core.Config as Config +import Spago.Core.Config as Core import Type.Proxy (Proxy(..)) +type Lockfile = + { workspace :: WorkspaceLock + , packages :: Map PackageName LockEntry + } + +data LockEntry + = FromPath PathLock + | FromGit GitLock + | FromRegistry RegistryLock + +derive instance Eq LockEntry + type WorkspaceLock = - { package_set :: Maybe SetAddress + { package_set :: Maybe PackageSetInfo , packages :: Map PackageName WorkspaceLockPackage - , extra_packages :: Map PackageName ExtraPackage + , extra_packages :: Map PackageName Core.ExtraPackage } -type WorkspaceLockPackage = - { dependencies :: Dependencies - , test_dependencies :: Dependencies - , path :: FilePath +type PackageSetInfo = + { address :: Core.SetAddress + , content :: Map PackageName Core.RemotePackage + , compiler :: Range } -type Lockfile = - { workspace :: WorkspaceLock - , packages :: Map PackageName LockEntry +type WorkspaceLockPackage = + { dependencies :: Core.Dependencies + , test_dependencies :: Core.Dependencies + , path :: FilePath + , build_plan :: Set PackageName } lockfileCodec :: JsonCodec Lockfile @@ -49,7 +66,7 @@ lockfileCodec = CA.object "Lockfile" workspaceLockCodec :: JsonCodec WorkspaceLock workspaceLockCodec = CA.object "WorkspaceLock" $ CA.recordProp (Proxy :: _ "packages") (Registry.Codec.packageMap dependenciesCodec) - $ CA.recordPropOptional (Proxy :: _ "package_set") Config.setAddressCodec + $ CA.recordPropOptional (Proxy :: _ "package_set") packageSetCodec $ CA.recordProp (Proxy :: _ "extra_packages") (Registry.Codec.packageMap Config.extraPackageCodec) $ CA.record where @@ -57,14 +74,15 @@ workspaceLockCodec = CA.object "WorkspaceLock" $ CA.recordProp (Proxy :: _ "path") CA.string $ CA.recordProp (Proxy :: _ "dependencies") Config.dependenciesCodec $ CA.recordProp (Proxy :: _ "test_dependencies") Config.dependenciesCodec + $ CA.recordProp (Proxy :: _ "build_plan") (CA.Common.set PackageName.codec) $ CA.record -data LockEntry - = FromPath PathLock - | FromGit GitLock - | FromRegistry RegistryLock - -derive instance Eq LockEntry +packageSetCodec :: JsonCodec PackageSetInfo +packageSetCodec = CA.object "PackageSetInfo" + $ CA.recordProp (Proxy :: _ "address") Config.setAddressCodec + $ CA.recordProp (Proxy :: _ "compiler") Range.codec + $ CA.recordProp (Proxy :: _ "content") (Registry.Codec.packageMap Core.remotePackageCodec) + $ CA.record lockEntryCodec :: JsonCodec LockEntry lockEntryCodec = CA.codec' decode encode diff --git a/src/Spago/Purs.purs b/src/Spago/Purs.purs index bb7df255e..d21c62185 100644 --- a/src/Spago/Purs.purs +++ b/src/Spago/Purs.purs @@ -54,7 +54,6 @@ compile globs pursArgs = do { pipeStdout = false } repl :: forall a. Set FilePath -> Array String -> Spago (PursEnv a) (Either Cmd.ExecError Cmd.ExecResult) - repl globs pursArgs = do { purs } <- ask let args = [ "repl" ] <> pursArgs <> Set.toUnfoldable globs diff --git a/src/Spago/Registry.purs b/src/Spago/Registry.purs index d723baf19..0da4c4a87 100644 --- a/src/Spago/Registry.purs +++ b/src/Spago/Registry.purs @@ -1,16 +1,35 @@ -module Spago.Registry where +module Spago.Registry + ( PreRegistryEnv + , PreRegistryEnvRow + , RegistryEnv + , RegistryEnvRow + , RegistryFunctions + , findPackageSet + , getManifestFromIndex + , getMetadata + , getRegistryFns + , listMetadataFiles + , readPackageSet + ) where import Spago.Prelude import Data.Array as Array +import Data.Array.NonEmpty as NonEmptyArray import Data.DateTime as DateTime import Data.Map as Map import Data.Set as Set import Data.String (Pattern(..)) import Data.String as String import Data.Time.Duration (Minutes(..)) +import Effect.AVar (AVar) +import Effect.Aff.AVar as AVar import Effect.Now as Now import Node.Path as Path +import Registry.Constants as Registry.Constants +import Registry.ManifestIndex as ManifestIndex +import Registry.Metadata as Metadata +import Registry.PackageName as PackageName import Registry.PackageSet (PackageSet(..)) import Registry.PackageSet as PackageSet import Registry.Version as Version @@ -21,60 +40,201 @@ import Spago.Git as Git import Spago.Paths as Paths import Spago.Purs as Purs -type RegistryEnv a = - { getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) - , getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata) - , offline :: OnlineStatus +type PreRegistryEnvRow a = + ( offline :: OnlineStatus , logOptions :: LogOptions , purs :: Purs.Purs , git :: Git.Git , db :: Db.Db | a + ) + +type PreRegistryEnv a = Record (PreRegistryEnvRow a) + +type RegistryEnvRow a = PreRegistryEnvRow + ( getRegistry :: Spago (PreRegistryEnv ()) RegistryFunctions + | a + ) + +type RegistryEnv a = Record (RegistryEnvRow a) + +type RegistryFunctions = + { getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) + , getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata) + , findPackageSet :: Maybe Version -> Spago (PreRegistryEnv ()) Version + , listMetadataFiles :: Spago (LogEnv ()) (Array String) + , readPackageSet :: Version -> Spago (LogEnv ()) PackageSet } --- | Update the database with the latest package sets -updatePackageSetsDb :: forall a. Db -> Spago (LogEnv a) Unit -updatePackageSetsDb db = do - setsAvailable <- map Set.fromFoldable getAvailablePackageSets - setsInDb <- map (Set.fromFoldable <<< map _.version) (liftEffect $ Db.selectPackageSets db) - let setsToInsert = Set.difference setsAvailable setsInDb - - unless (Set.isEmpty setsToInsert) do - for_ (Set.toUnfoldable setsToInsert :: Array _) \setVersion -> do - PackageSet set <- readPackageSet setVersion - -- First insert the package set - logDebug $ "Inserting package set in DB: " <> Version.print setVersion - liftEffect $ Db.insertPackageSet db { compiler: set.compiler, date: set.published, version: set.version } - -- Then we insert every entry separately - for_ (Map.toUnfoldable set.packages :: Array _) \(Tuple name version) -> do - liftEffect $ Db.insertPackageSetEntry db { packageName: name, packageVersion: version, packageSetVersion: set.version } - --- | List all the package sets versions available in the Registry repo -getAvailablePackageSets :: forall a. Spago (LogEnv a) (Array Version) -getAvailablePackageSets = do - { success: setVersions, fail: parseFailures } <- map (partitionEithers <<< map parseSetVersion) $ FS.ls Paths.packageSetsPath - - unless (Array.null parseFailures) do - logDebug $ [ toDoc "Failed to parse some package-sets versions:" ] <> map (indent <<< toDoc <<< show) parseFailures - - pure setVersions +getMetadata :: PackageName -> Spago (RegistryEnv _) _ +getMetadata packageName = do + { getRegistry, logOptions, db, git, purs, offline } <- ask + { getMetadata: fn } <- runSpago { logOptions, db, git, purs, offline } getRegistry + runSpago { logOptions } (fn packageName) + +getManifestFromIndex :: PackageName -> Version -> Spago (RegistryEnv _) _ +getManifestFromIndex packageName version = do + { getRegistry, logOptions, db, git, purs, offline } <- ask + { getManifestFromIndex: fn } <- runSpago { logOptions, db, git, purs, offline } getRegistry + runSpago { logOptions } (fn packageName version) + +findPackageSet :: Maybe Version -> Spago (RegistryEnv _) _ +findPackageSet version = do + { getRegistry, logOptions, db, git, purs, offline } <- ask + { findPackageSet: fn } <- runSpago { logOptions, db, git, purs, offline } getRegistry + runSpago { logOptions, db, git, purs, offline } (fn version) + +listMetadataFiles :: Spago (RegistryEnv _) _ +listMetadataFiles = do + { getRegistry, logOptions, db, git, purs, offline } <- ask + { listMetadataFiles: fn } <- runSpago { logOptions, db, git, purs, offline } getRegistry + runSpago { logOptions } fn + +readPackageSet :: Version -> Spago (RegistryEnv _) _ +readPackageSet version = do + { getRegistry, logOptions, db, git, purs, offline } <- ask + { readPackageSet: fn } <- runSpago { logOptions, db, git, purs, offline } getRegistry + runSpago { logOptions } (fn version) + +getRegistryFns :: AVar RegistryFunctions -> AVar Unit -> Spago (PreRegistryEnv _) RegistryFunctions +getRegistryFns registryBox registryLock = do + -- The Box AVar will be empty until the first time we fetch the Registry, then + -- we can just use the value that is cached. + -- The Lock AVar is used to make sure + -- that only one fiber is fetching the Registry at a time, and that all the other + -- fibers will wait for it to finish and then use the cached value. + { db } <- ask + liftAff $ AVar.take registryLock + liftAff (AVar.tryRead registryBox) >>= case _ of + Just registry -> do + liftAff $ AVar.put unit registryLock + pure registry + Nothing -> do + fetchingFreshRegistry <- fetchRegistry + let + registryFns = + { getManifestFromIndex: getManifestFromIndexImpl db + , getMetadata: getMetadataImpl db fetchingFreshRegistry + , listMetadataFiles: FS.ls (Path.concat [ Paths.registryPath, Registry.Constants.metadataDirectory ]) + , findPackageSet: findPackageSetImpl + , readPackageSet: readPackageSetImpl + } + liftAff $ AVar.put registryFns registryBox + liftAff $ AVar.put unit registryLock + pure registryFns + + where + fetchRegistry :: Spago (PreRegistryEnv _) Boolean + fetchRegistry = do + -- we keep track of how old the latest pull was - if the last pull was recent enough + -- we just move on, otherwise run the fibers + { db } <- ask + fetchingFreshRegistry <- shouldFetchRegistryRepos db + when fetchingFreshRegistry do + -- clone the registry and index repo, or update them + logInfo "Refreshing the Registry Index..." + parallelise + [ Git.fetchRepo { git: "https://github.com/purescript/registry-index.git", ref: "main" } Paths.registryIndexPath >>= case _ of + Right _ -> pure unit + Left _err -> logWarn "Couldn't refresh the registry-index, will proceed anyways" + , Git.fetchRepo { git: "https://github.com/purescript/registry.git", ref: "main" } Paths.registryPath >>= case _ of + Right _ -> pure unit + Left _err -> logWarn "Couldn't refresh the registry, will proceed anyways" + ] + + -- Now that we are up to date with the Registry we init/refresh the database + updatePackageSetsDb db + pure fetchingFreshRegistry + + -- | Update the database with the latest package sets + updatePackageSetsDb :: Db -> Spago (LogEnv _) Unit + updatePackageSetsDb db = do + { logOptions } <- ask + setsAvailable <- map Set.fromFoldable getAvailablePackageSets + setsInDb <- map (Set.fromFoldable <<< map _.version) (liftEffect $ Db.selectPackageSets db) + let setsToInsert = Set.difference setsAvailable setsInDb + + unless (Set.isEmpty setsToInsert) do + for_ (Set.toUnfoldable setsToInsert :: Array _) \setVersion -> do + PackageSet set <- runSpago { logOptions } (readPackageSetImpl setVersion) + -- First insert the package set + logDebug $ "Inserting package set in DB: " <> Version.print setVersion + liftEffect $ Db.insertPackageSet db { compiler: set.compiler, date: set.published, version: set.version } + -- Then we insert every entry separately + for_ (Map.toUnfoldable set.packages :: Array _) \(Tuple name version) -> do + liftEffect $ Db.insertPackageSetEntry db { packageName: name, packageVersion: version, packageSetVersion: set.version } + + -- | List all the package sets versions available in the Registry repo + getAvailablePackageSets :: Spago (LogEnv _) (Array Version) + getAvailablePackageSets = do + { success: setVersions, fail: parseFailures } <- map (partitionEithers <<< map parseSetVersion) $ FS.ls Paths.packageSetsPath + + unless (Array.null parseFailures) do + logDebug $ [ toDoc "Failed to parse some package-sets versions:" ] <> map (indent <<< toDoc <<< show) parseFailures + + pure setVersions + where + parseSetVersion str = Version.parse case String.stripSuffix (Pattern ".json") str of + Nothing -> str + Just v -> v + + readPackageSetImpl :: Version -> Spago (LogEnv ()) PackageSet + readPackageSetImpl setVersion = do + logDebug "Reading the package set from the Registry repo..." + let packageSetPath = Path.concat [ Paths.packageSetsPath, Version.print setVersion <> ".json" ] + liftAff (FS.readJsonFile PackageSet.codec packageSetPath) >>= case _ of + Left err -> die $ "Couldn't read the package set: " <> err + Right registryPackageSet -> do + logDebug $ "Read the package set " <> Version.print setVersion <> " from the registry" + pure registryPackageSet + +-- Metadata can change over time (unpublished packages, and new packages), so we need +-- to read it from file every time we have a fresh Registry +getMetadataImpl :: Db -> Boolean -> PackageName -> Spago (LogEnv ()) (Either String Metadata) +getMetadataImpl db fetchingFreshRegistry name = do + -- we first try reading it from the DB + liftEffect (Db.getMetadata db name) >>= case _ of + Just metadata | not fetchingFreshRegistry -> do + logDebug $ "Got metadata from DB: " <> PackageName.print name + pure (Right metadata) + _ -> do + -- if we don't have it we try reading it from file + metadataFromFile name >>= case _ of + Left e -> pure (Left e) + Right m -> do + -- and memoize it + liftEffect (Db.insertMetadata db name m) + pure (Right m) where - parseSetVersion str = Version.parse case String.stripSuffix (Pattern ".json") str of - Nothing -> str - Just v -> v - -readPackageSet :: forall a. Version -> Spago (LogEnv a) PackageSet -readPackageSet setVersion = do - logDebug "Reading the package set from the Registry repo..." - let packageSetPath = Path.concat [ Paths.packageSetsPath, Version.print setVersion <> ".json" ] - liftAff (FS.readJsonFile PackageSet.codec packageSetPath) >>= case _ of - Left err -> die $ "Couldn't read the package set: " <> err - Right registryPackageSet -> do - logDebug $ "Read the package set " <> Version.print setVersion <> " from the registry" - pure registryPackageSet - -findPackageSet :: forall a. Maybe Version -> Spago (RegistryEnv a) Version -findPackageSet maybeSet = do + metadataFromFile pkgName = do + let metadataFilePath = Path.concat [ Paths.registryPath, Registry.Constants.metadataDirectory, PackageName.print pkgName <> ".json" ] + logDebug $ "Reading metadata from file: " <> metadataFilePath + liftAff (FS.readJsonFile Metadata.codec metadataFilePath) + +-- Manifests are immutable so we can just lookup in the DB or read from file if not there +getManifestFromIndexImpl :: Db -> PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest) +getManifestFromIndexImpl db name version = do + liftEffect (Db.getManifest db name version) >>= case _ of + Just manifest -> pure (Just manifest) + Nothing -> do + -- if we don't have it we need to read it from file + -- (note that we have all the versions of a package in the same file) + logDebug $ "Reading package from Index: " <> PackageName.print name + maybeManifests <- liftAff $ ManifestIndex.readEntryFile Paths.registryIndexPath name + manifests <- map (map (\m@(Manifest m') -> Tuple m'.version m)) case maybeManifests of + Right ms -> pure $ NonEmptyArray.toUnfoldable ms + Left err -> do + logWarn $ "Could not read package manifests from index, proceeding anyways. Error: " <> err + pure [] + let versions = Map.fromFoldable manifests + -- and memoize it + for_ manifests \(Tuple _ manifest@(Manifest m)) -> do + logDebug $ "Inserting manifest in DB: " <> PackageName.print name <> " v" <> Version.print m.version + liftEffect $ Db.insertManifest db name m.version manifest + pure (Map.lookup version versions) + +findPackageSetImpl :: forall a. Maybe Version -> Spago (PreRegistryEnv a) Version +findPackageSetImpl maybeSet = do { db, purs } <- ask availableSets <- liftEffect $ Db.selectPackageSets db let availableVersions = map _.version availableSets @@ -139,10 +299,11 @@ shouldFetchRegistryRepos db = do let staleAfter = Minutes 15.0 let (timeDiff :: Minutes) = DateTime.diff now lastRegistryFetch let isOldEnough = timeDiff > staleAfter - if isOldEnough then do + -- We check if it's old, but also if we have it at all + registryExists <- FS.exists Paths.registryPath + if isOldEnough || not registryExists then do logDebug "Registry is old, refreshing" liftEffect $ Db.updateLastPull db registryKey now pure true else do - logDebug "Registry is fresh enough, moving on..." pure false diff --git a/src/Spago/Repl.purs b/src/Spago/Repl.purs index e95fc4694..ae2c0a233 100644 --- a/src/Spago/Repl.purs +++ b/src/Spago/Repl.purs @@ -6,21 +6,21 @@ import Spago.Prelude import Data.Map as Map import Registry.PackageName as PackageName +import Spago.Config (BuildType(..), Package(..), PackageMap, PackageSet) import Spago.Registry (RegistryEnv) -import Spago.Config (Package(..), PackageMap, PackageSet(..)) +import Spago.Registry as Registry -- TODO I guess this should be configurable supportPackageName :: PackageName supportPackageName = unsafeFromRight $ PackageName.parse "psci-support" -supportPackage :: forall a. PackageSet -> Spago (RegistryEnv a) PackageMap +supportPackage :: PackageSet -> Spago (RegistryEnv _) PackageMap supportPackage packageSet = do - { getMetadata, logOptions } <- ask - case packageSet of - PackageSet packages -> pure $ Map.filterWithKey (\k _v -> k == supportPackageName) packages + case packageSet.buildType of + PackageSetBuild _info packages -> pure $ Map.filterWithKey (\k _v -> k == supportPackageName) packages -- TODO: we should look in the "other" packages first - Registry _other -> do - maybeMetadata <- runSpago { logOptions } (getMetadata supportPackageName) + RegistrySolverBuild _other -> do + maybeMetadata <- Registry.getMetadata supportPackageName pure case maybeMetadata of Right (Metadata metadata) -> case Map.findMax metadata.published of Nothing -> Map.empty diff --git a/test-fixtures/alternate-backend-output.txt b/test-fixtures/alternate-backend-output.txt index 964766865..a9b0aaa6e 100644 --- a/test-fixtures/alternate-backend-output.txt +++ b/test-fixtures/alternate-backend-output.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: subpackage diff --git a/test-fixtures/circular-dependencies.txt b/test-fixtures/circular-dependencies.txt index 3e504c114..ce0ed29ec 100644 --- a/test-fixtures/circular-dependencies.txt +++ b/test-fixtures/circular-dependencies.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: bbb diff --git a/test-fixtures/codegen-opt.txt b/test-fixtures/codegen-opt.txt index 2617921c4..7bc602b11 100644 --- a/test-fixtures/codegen-opt.txt +++ b/test-fixtures/codegen-opt.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: 7368613235362d68766258694c614d517a3667747a58725778 diff --git a/test-fixtures/list-packages-registry.txt b/test-fixtures/list-packages-registry.txt index 7e5d1f6f7..b5084c682 100644 --- a/test-fixtures/list-packages-registry.txt +++ b/test-fixtures/list-packages-registry.txt @@ -2,6 +2,8 @@ Reading Spago workspace configuration... ✅ Selecting package to build: aaa +No lockfile found, generating it... +Lockfile written to spago.lock. Please commit this file. Downloading dependencies... ❌ Cannot list the packages in the package set, as none is configured for the project. diff --git a/test-fixtures/missing-dependencies.txt b/test-fixtures/missing-dependencies.txt index 14e9b30c8..9f39f39bb 100644 --- a/test-fixtures/missing-dependencies.txt +++ b/test-fixtures/missing-dependencies.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaaa diff --git a/test-fixtures/offline.txt b/test-fixtures/offline.txt index 7e627ecfd..f8483c153 100644 --- a/test-fixtures/offline.txt +++ b/test-fixtures/offline.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: eee diff --git a/test-fixtures/pedantic/check-direct-import-transitive-dependency-both.txt b/test-fixtures/pedantic/check-direct-import-transitive-dependency-both.txt index 1cd258a4d..df914fbf7 100644 --- a/test-fixtures/pedantic/check-direct-import-transitive-dependency-both.txt +++ b/test-fixtures/pedantic/check-direct-import-transitive-dependency-both.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -27,4 +26,4 @@ Tests for package 'pedantic' import the following transitive dependencies - plea These errors can be fixed by running the below command(s): spago install -p pedantic maybe -spago install -p pedantic --test-deps control \ No newline at end of file +spago install -p pedantic --test-deps control diff --git a/test-fixtures/pedantic/check-direct-import-transitive-dependency-test.txt b/test-fixtures/pedantic/check-direct-import-transitive-dependency-test.txt index c8c545d74..85109de44 100644 --- a/test-fixtures/pedantic/check-direct-import-transitive-dependency-test.txt +++ b/test-fixtures/pedantic/check-direct-import-transitive-dependency-test.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -21,4 +20,4 @@ Tests for package 'pedantic' import the following transitive dependencies - plea Control.Alt These errors can be fixed by running the below command(s): -spago install -p pedantic --test-deps control \ No newline at end of file +spago install -p pedantic --test-deps control diff --git a/test-fixtures/pedantic/check-direct-import-transitive-dependency.txt b/test-fixtures/pedantic/check-direct-import-transitive-dependency.txt index c894aa26c..728284054 100644 --- a/test-fixtures/pedantic/check-direct-import-transitive-dependency.txt +++ b/test-fixtures/pedantic/check-direct-import-transitive-dependency.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -21,4 +20,4 @@ Sources for package 'pedantic' import the following transitive dependencies - pl Control.Alt These errors can be fixed by running the below command(s): -spago install -p pedantic control \ No newline at end of file +spago install -p pedantic control diff --git a/test-fixtures/pedantic/check-pedantic-packages.txt b/test-fixtures/pedantic/check-pedantic-packages.txt index d1c73545f..3748bc6b5 100644 --- a/test-fixtures/pedantic/check-pedantic-packages.txt +++ b/test-fixtures/pedantic/check-pedantic-packages.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -37,4 +36,4 @@ These errors can be fixed by running the below command(s): spago uninstall -p pedantic console effect either spago install -p pedantic newtype spago uninstall -p pedantic --test-deps tuples -spago install -p pedantic --test-deps either \ No newline at end of file +spago install -p pedantic --test-deps either diff --git a/test-fixtures/pedantic/check-unused-dependency-in-source.txt b/test-fixtures/pedantic/check-unused-dependency-in-source.txt index 085e1d343..7316f743e 100644 --- a/test-fixtures/pedantic/check-unused-dependency-in-source.txt +++ b/test-fixtures/pedantic/check-unused-dependency-in-source.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -29,4 +28,4 @@ Tests for package 'pedantic' import the following transitive dependencies - plea These errors can be fixed by running the below command(s): spago uninstall -p pedantic console effect -spago install -p pedantic --test-deps console effect \ No newline at end of file +spago install -p pedantic --test-deps console effect diff --git a/test-fixtures/pedantic/check-unused-dependency.txt b/test-fixtures/pedantic/check-unused-dependency.txt index df9ff5275..a74358caf 100644 --- a/test-fixtures/pedantic/check-unused-dependency.txt +++ b/test-fixtures/pedantic/check-unused-dependency.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -20,4 +19,4 @@ Sources for package 'pedantic' declares unused dependencies - please remove them - effect These errors can be fixed by running the below command(s): -spago uninstall -p pedantic console effect \ No newline at end of file +spago uninstall -p pedantic console effect diff --git a/test-fixtures/pedantic/check-unused-source-and-test-dependency.txt b/test-fixtures/pedantic/check-unused-source-and-test-dependency.txt index 3ea9f4603..387b4b2f2 100644 --- a/test-fixtures/pedantic/check-unused-source-and-test-dependency.txt +++ b/test-fixtures/pedantic/check-unused-source-and-test-dependency.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -25,4 +24,4 @@ Tests for package 'pedantic' declares unused dependencies - please remove them f These errors can be fixed by running the below command(s): spago uninstall -p pedantic console effect -spago uninstall -p pedantic --test-deps console effect \ No newline at end of file +spago uninstall -p pedantic --test-deps console effect diff --git a/test-fixtures/pedantic/check-unused-test-dependency.txt b/test-fixtures/pedantic/check-unused-test-dependency.txt index 302d8e2b5..2cd0d7efe 100644 --- a/test-fixtures/pedantic/check-unused-test-dependency.txt +++ b/test-fixtures/pedantic/check-unused-test-dependency.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -19,4 +18,4 @@ Tests for package 'pedantic' declares unused dependencies - please remove them f - newtype These errors can be fixed by running the below command(s): -spago uninstall -p pedantic --test-deps newtype \ No newline at end of file +spago uninstall -p pedantic --test-deps newtype diff --git a/test-fixtures/pedantic/pedantic-instructions-initial-failure.txt b/test-fixtures/pedantic/pedantic-instructions-initial-failure.txt index 318771bda..b68c36af6 100644 --- a/test-fixtures/pedantic/pedantic-instructions-initial-failure.txt +++ b/test-fixtures/pedantic/pedantic-instructions-initial-failure.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic @@ -21,4 +20,4 @@ Sources for package 'pedantic' import the following transitive dependencies - pl Effect These errors can be fixed by running the below command(s): -spago install -p pedantic effect \ No newline at end of file +spago install -p pedantic effect diff --git a/test-fixtures/pedantic/pedantic-instructions-installation-result.txt b/test-fixtures/pedantic/pedantic-instructions-installation-result.txt index 9953c0d53..6ac115bef 100644 --- a/test-fixtures/pedantic/pedantic-instructions-installation-result.txt +++ b/test-fixtures/pedantic/pedantic-instructions-installation-result.txt @@ -1,13 +1,14 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: pedantic -Adding 1 packages to the config in spago.yaml +Adding 1 package to the config in spago.yaml +Lockfile is out of date (installing new packages), generating it... +Lockfile written to spago.lock. Please commit this file. Downloading dependencies... Building... Src Lib All Warnings 0 0 0 Errors 0 0 0 -✅ Build succeeded. \ No newline at end of file +✅ Build succeeded. diff --git a/test-fixtures/polyrepo.lock b/test-fixtures/polyrepo.lock new file mode 100644 index 000000000..5fd05e893 --- /dev/null +++ b/test-fixtures/polyrepo.lock @@ -0,0 +1,427 @@ +workspace: + packages: + package-a: + path: package-a + dependencies: + - package-b + - package-c + - prelude + test_dependencies: + - console + - effect + - prelude + build_plan: + - console + - effect + - package-b + - package-c + - prelude + package-b: + path: package-b + dependencies: + - package-c + - prelude + test_dependencies: + - console + - effect + - prelude + build_plan: + - console + - effect + - package-c + - prelude + package-c: + path: package-c + dependencies: + - prelude + test_dependencies: + - console + - effect + - prelude + build_plan: + - console + - effect + - prelude + package_set: + address: + registry: 0.0.1 + compiler: ">=0.15.4 <0.16.0" + content: + ace: 9.0.0 + aff: 7.1.0 + aff-bus: 6.0.0 + aff-coroutines: 9.0.0 + aff-promise: 4.0.0 + aff-retry: 2.0.0 + affjax: 13.0.0 + affjax-node: 1.0.0 + affjax-web: 1.0.0 + ansi: 7.0.0 + argonaut: 9.0.0 + argonaut-codecs: 9.1.0 + argonaut-core: 7.0.0 + argonaut-generic: 8.0.0 + argonaut-traversals: 10.0.0 + argparse-basic: 2.0.0 + array-builder: 0.1.2 + arraybuffer: 13.0.0 + arraybuffer-builder: 3.0.1 + arraybuffer-types: 3.0.2 + arrays: 7.1.0 + arrays-zipper: 2.0.1 + ask: 1.0.0 + assert: 6.0.0 + avar: 5.0.0 + b64: 0.0.8 + barbies: 1.0.1 + barlow-lens: 0.9.0 + bifunctors: 6.0.0 + bigints: 7.0.1 + bolson: 0.1.1 + bower-json: 3.0.0 + call-by-name: 4.0.1 + canvas: 6.0.0 + canvas-action: 9.0.0 + cartesian: 1.0.6 + catenable-lists: 7.0.0 + channel: 1.0.0 + checked-exceptions: 3.1.1 + classnames: 2.0.0 + codec: 5.0.0 + codec-argonaut: 9.0.0 + colors: 7.0.1 + concur-core: 0.5.0 + concur-react: 0.5.0 + concurrent-queues: 3.0.0 + console: 6.0.0 + const: 6.0.0 + contravariant: 6.0.0 + control: 6.0.0 + convertable-options: 1.0.0 + coroutines: 7.0.0 + css: 6.0.0 + datetime: 6.1.0 + datetime-parsing: 0.2.0 + debug: 6.0.2 + decimals: 7.1.0 + deku: 0.6.1 + deno: 0.0.5 + dissect: 1.0.0 + distributive: 6.0.0 + dodo-printer: 2.2.1 + dom-filereader: 7.0.0 + dom-indexed: 11.0.0 + dotenv: 3.0.0 + droplet: 0.5.0 + dynamic-buffer: 3.0.1 + effect: 4.0.0 + either: 6.1.0 + elmish: 0.8.3 + elmish-enzyme: 0.1.1 + elmish-hooks: 0.8.2 + elmish-html: 0.7.2 + elmish-testing-library: 0.2.0 + email-validate: 7.0.0 + encoding: 0.0.8 + enums: 6.0.1 + error: 2.0.0 + exceptions: 6.0.0 + exists: 6.0.0 + exitcodes: 4.0.0 + expect-inferred: 3.0.0 + fallback: 0.1.0 + fast-vect: 0.7.0 + fetch: 1.1.4 + fetch-argonaut: 1.0.0 + fetch-core: 4.0.4 + fetch-yoga-json: 1.1.0 + filterable: 5.0.0 + fixed-points: 7.0.0 + fixed-precision: 5.0.0 + flame: 1.2.0 + float32: 2.0.0 + foldable-traversable: 6.0.0 + foreign: 7.0.0 + foreign-object: 4.0.0 + foreign-readwrite: 3.0.0 + fork: 6.0.0 + form-urlencoded: 7.0.0 + formatters: 7.0.0 + free: 7.0.0 + freeap: 7.0.0 + freer-free: 0.0.1 + freet: 7.0.0 + functions: 6.0.0 + functor1: 3.0.0 + functors: 5.0.0 + fuzzy: 0.4.0 + gen: 4.0.0 + generate-values: 1.0.1 + generic-router: 0.0.1 + geometry-plane: 1.0.3 + github-actions-toolkit: 0.5.0 + graphql-client: 9.2.2 + graphs: 8.1.0 + group: 4.1.1 + halogen: 7.0.0 + halogen-css: 10.0.0 + halogen-formless: 4.0.2 + halogen-hooks: 0.6.1 + halogen-hooks-extra: 0.9.0 + halogen-store: 0.5.4 + halogen-storybook: 2.0.0 + halogen-subscriptions: 2.0.0 + halogen-svg-elems: 6.0.0 + halogen-vdom: 8.0.0 + halogen-vdom-string-renderer: 0.5.0 + heckin: 2.0.1 + heterogeneous: 0.6.0 + heterogeneous-extrablatt: 0.2.1 + homogeneous: 0.4.0 + http-methods: 6.0.0 + httpure: 0.15.0 + httpurple: 3.0.0 + httpurple-argonaut: 1.0.1 + httpurple-yoga-json: 1.0.0 + hyrule: 2.1.0 + identity: 6.0.0 + indexed-monad: 2.1.0 + int64: 2.0.0 + integers: 6.0.0 + interpolate: 5.0.0 + invariant: 6.0.0 + jarilo: 1.0.1 + jelly: 0.4.1 + jest: 1.0.0 + js-date: 8.0.0 + js-fileio: 3.0.0 + js-promise: 1.0.0 + js-timers: 6.1.0 + js-uri: 3.1.0 + justifill: 0.5.0 + jwt: 0.0.9 + language-cst-parser: 0.12.1 + lazy: 6.0.0 + lazy-joe: 1.0.0 + lcg: 4.0.0 + leibniz: 5.0.0 + linalg: 5.1.0 + lists: 7.0.0 + literals: 1.0.2 + logging: 3.0.0 + logging-journald: 0.4.0 + machines: 7.0.0 + matrices: 5.0.1 + matryoshka: 1.0.0 + maybe: 6.0.0 + mdast-util-from-markdown: 0.2.1 + media-types: 6.0.0 + midi: 4.0.0 + milkis: 9.0.0 + minibench: 4.0.0 + mmorph: 7.0.0 + monad-control: 5.0.0 + monad-logger: 1.3.1 + monad-loops: 0.5.0 + monad-unlift: 1.0.1 + monoid-extras: 0.0.1 + monoidal: 0.16.0 + morello: 0.3.2 + mote: 3.0.0 + motsunabe: 2.0.0 + nano-id: 1.1.0 + naturals: 3.0.0 + nested-functor: 0.2.1 + newtype: 5.0.0 + node-buffer: 8.0.0 + node-buffer-blob: 1.0.0 + node-child-process: 9.0.0 + node-fs: 8.1.0 + node-fs-aff: 9.1.0 + node-http: 8.0.0 + node-net: 4.0.0 + node-path: 5.0.0 + node-process: 10.0.0 + node-readline: 7.0.0 + node-sqlite3: 8.0.0 + node-streams: 7.0.0 + node-streams-aff: 4.0.0 + node-url: 6.0.0 + nonempty: 7.0.0 + now: 6.0.0 + npm-package-json: 2.0.0 + nullable: 6.0.0 + numbers: 9.0.0 + ocarina: 1.3.0 + open-folds: 6.3.0 + open-memoize: 6.1.0 + open-pairing: 6.1.0 + options: 7.0.0 + optparse: 5.0.0 + ordered-collections: 3.0.0 + ordered-set: 0.4.0 + orders: 6.0.0 + pairs: 9.0.0 + parallel: 6.0.0 + parsing: 10.0.0 + parsing-dataview: 3.1.0 + partial: 4.0.0 + pathy: 9.0.0 + pha: 0.9.0 + phaser: 0.6.0 + pipes: 8.0.0 + point-free: 1.0.0 + pointed-list: 0.5.1 + polymorphic-vectors: 4.0.0 + posix-types: 6.0.0 + precise: 6.0.0 + precise-datetime: 7.0.0 + prelude: 6.0.1 + prettier-printer: 3.0.0 + profunctor: 6.0.0 + profunctor-lenses: 8.0.0 + protobuf: 4.0.0 + ps-cst: 1.2.0 + psa-utils: 8.0.0 + psc-ide: 19.0.0 + psci-support: 6.0.0 + qualified-do: 2.2.0 + quantities: 12.1.0 + quickcheck: 8.0.1 + quickcheck-combinators: 0.1.3 + quickcheck-laws: 7.0.0 + quickcheck-utf8: 0.0.0 + random: 6.0.0 + rationals: 5.0.0 + react: 10.0.1 + react-basic: 17.0.0 + react-basic-classic: 3.0.0 + react-basic-dnd: 10.1.0 + react-basic-dom: 6.0.0 + react-basic-emotion: 7.0.0 + react-basic-hooks: 8.0.0 + react-dom: 8.0.0 + react-halo: 3.0.0 + react-icons: 1.0.8 + react-testing-library: 4.0.1 + read: 1.0.1 + record: 4.0.0 + refs: 6.0.0 + remotedata: 5.0.0 + resource: 2.0.1 + resourcet: 1.0.0 + result: 1.0.3 + return: 0.2.0 + ring-modules: 5.0.1 + rito: 0.1.0 + routing: 11.0.0 + routing-duplex: 0.6.0 + run: 5.0.0 + safe-coerce: 2.0.0 + safely: 4.0.1 + selection-foldable: 0.2.0 + semirings: 7.0.0 + signal: 13.0.0 + simple-emitter: 2.0.0 + simple-json: 9.0.0 + sized-matrices: 1.0.0 + sized-vectors: 5.0.2 + slug: 3.0.8 + soundfonts: 4.1.0 + sparse-matrices: 1.2.1 + sparse-polynomials: 1.0.5 + spec: 7.0.0 + spec-discovery: 8.0.1 + spec-quickcheck: 5.0.0 + splitmix: 2.1.0 + ssrs: 1.0.0 + st: 6.0.0 + strictlypositiveint: 1.0.1 + string-parsers: 8.0.0 + strings: 6.0.1 + strings-extra: 4.0.0 + stringutils: 0.0.12 + substitute: 0.2.3 + sunde: 3.0.0 + supply: 0.2.0 + svg-parser: 3.0.0 + systemd-journald: 0.3.0 + tailrec: 6.1.0 + test-unit: 17.0.0 + thermite: 6.3.1 + thermite-dom: 0.3.1 + these: 6.0.0 + toppokki: 4.0.0 + transformers: 6.0.0 + tree-rose: 4.0.2 + tuples: 7.0.0 + two-or-more: 1.0.0 + type-equality: 4.0.1 + typelevel: 6.0.0 + typelevel-lists: 2.1.0 + typelevel-peano: 1.0.1 + typelevel-prelude: 7.0.0 + typelevel-rows: 0.1.0 + uint: 7.0.0 + ulid: 3.0.1 + uncurried-transformers: 1.1.0 + undefined: 2.0.0 + undefined-is-not-a-problem: 1.1.0 + unfoldable: 6.0.0 + unicode: 6.0.0 + unlift: 1.0.1 + unordered-collections: 3.0.1 + unsafe-coerce: 6.0.0 + unsafe-reference: 5.0.0 + untagged-union: 1.0.0 + uri: 9.0.0 + uuid: 9.0.0 + validation: 6.0.0 + variant: 8.0.0 + vectorfield: 1.0.1 + versions: 7.0.0 + web-clipboard: 4.1.0 + web-cssom: 2.0.0 + web-dom: 6.0.0 + web-dom-parser: 8.0.0 + web-dom-xpath: 3.0.0 + web-encoding: 3.0.0 + web-events: 4.0.0 + web-fetch: 3.0.0 + web-file: 4.0.0 + web-html: 4.1.0 + web-pointerevents: 1.0.0 + web-promise: 3.1.0 + web-router: 1.0.0 + web-socket: 4.0.0 + web-storage: 5.0.0 + web-streams: 3.0.0 + web-touchevents: 4.0.0 + web-uievents: 4.0.0 + web-url: 2.0.0 + web-workers: 1.1.0 + web-xhr: 5.0.0 + which: 2.0.0 + yoga-fetch: 1.0.1 + yoga-json: 3.0.2 + yoga-postgres: 6.0.0 + extra_packages: {} +packages: + console: + type: registry + version: 6.0.0 + integrity: sha256-gJpJ53fCDAL8BiCiJXH0HNAJ9K3gJtLo8GDaCK6hA5U= + dependencies: + - effect + - prelude + effect: + type: registry + version: 4.0.0 + integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M= + dependencies: + - prelude + prelude: + type: registry + version: 6.0.1 + integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= + dependencies: [] diff --git a/test-fixtures/publish-main-win.txt b/test-fixtures/publish-main-win.txt index bf80c6f98..55aa1f248 100644 --- a/test-fixtures/publish-main-win.txt +++ b/test-fixtures/publish-main-win.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaa diff --git a/test-fixtures/publish-main.txt b/test-fixtures/publish-main.txt index ddb7fde8c..8461f8e94 100644 --- a/test-fixtures/publish-main.txt +++ b/test-fixtures/publish-main.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaa @@ -18,4 +17,4 @@ Your package "aaa" is not ready for publishing yet, encountered 1 error: in its `src` directory. All package sources must be in the `src` directory, with any additional sources indicated by the `files` key in your manifest. - - src/Main.purs: Module name is Main but PureScript libraries cannot publish modules named: Main, Test.Main \ No newline at end of file + - src/Main.purs: Module name is Main but PureScript libraries cannot publish modules named: Main, Test.Main diff --git a/test-fixtures/publish-no-bounds.txt b/test-fixtures/publish-no-bounds.txt index 24389ce3b..6452f6e72 100644 --- a/test-fixtures/publish-no-bounds.txt +++ b/test-fixtures/publish-no-bounds.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaaa @@ -21,4 +20,4 @@ See the configuration file's documentation: https://github.com/purescript/spago# ❌ The configuration is missing version bounds for some packages. Run `spago fetch --ensure-ranges` to add them: - console - effect - - prelude \ No newline at end of file + - prelude diff --git a/test-fixtures/publish-no-config.txt b/test-fixtures/publish-no-config.txt index 02f20fc98..bb509b943 100644 --- a/test-fixtures/publish-no-config.txt +++ b/test-fixtures/publish-no-config.txt @@ -1,8 +1,9 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaaa +Lockfile is out of date, generating it... +Lockfile written to spago.lock. Please commit this file. Downloading dependencies... Building... Src Lib All @@ -15,4 +16,4 @@ Your package "aaaa" is not ready for publishing yet, encountered 1 error: ❌ Did not find publishing config: add a valid one in `package.publish`. -See the configuration file's documentation: https://github.com/purescript/spago#the-configuration-file \ No newline at end of file +See the configuration file's documentation: https://github.com/purescript/spago#the-configuration-file diff --git a/test-fixtures/publish-no-git.txt b/test-fixtures/publish-no-git.txt index 24eda5666..b5636ca1d 100644 --- a/test-fixtures/publish-no-git.txt +++ b/test-fixtures/publish-no-git.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaa @@ -15,4 +14,4 @@ Errors 0 0 0 ❌ Could not verify whether the git tree is clean due to the below error: Could not run `git status`. Error: Command failed with exit code 128: git status --porcelain -fatal: not a git repository (or any of the parent directories): .git \ No newline at end of file +fatal: not a git repository (or any of the parent directories): .git diff --git a/test-fixtures/publish.txt b/test-fixtures/publish.txt index 540a1cc6a..00e3e6d0b 100644 --- a/test-fixtures/publish.txt +++ b/test-fixtures/publish.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: aaa @@ -11,7 +10,7 @@ Errors 0 0 0 ✅ Build succeeded. -Passed preliminary checks. +Passed preliminary checks. ⚠️ Spago is in offline mode - not pushing the git tag v0.0.1 Building again with the build plan from the solver... Building... @@ -25,4 +24,4 @@ Errors 0 0 0 ✅ Ready for publishing. Calling the registry.. -❌ Spago is offline - not able to call the Registry. \ No newline at end of file +❌ Spago is offline - not able to call the Registry. diff --git a/test-fixtures/spago-install-existing-dep-stderr.txt b/test-fixtures/spago-install-existing-dep-stderr.txt index ecb78e248..d1feb9487 100644 --- a/test-fixtures/spago-install-existing-dep-stderr.txt +++ b/test-fixtures/spago-install-existing-dep-stderr.txt @@ -1,9 +1,7 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: 7368613235362d50744f44764f717435586c685938735a5154 ⚠️ You tried to install some packages that are already present in the configuration, proceeding anyways: - effect -Adding 1 packages to the config in spago.yaml Downloading dependencies... diff --git a/test-fixtures/spago-with-hash.yaml b/test-fixtures/spago-with-hash.yaml deleted file mode 100644 index 99cc7d074..000000000 --- a/test-fixtures/spago-with-hash.yaml +++ /dev/null @@ -1,14 +0,0 @@ -package: - name: aaa - dependencies: - - console - - effect - - prelude - test: - main: Test.Main - dependencies: [] -workspace: - package_set: - url: https://raw.githubusercontent.com/purescript/registry/main/package-sets/29.3.0.json - hash: sha256-LJoXQjRcY0IkP1YJMwvhKAtb4NpxoJW5A6DxapTI+as= - extra_packages: {} diff --git a/test-fixtures/spago-with-maybe.lock b/test-fixtures/spago-with-maybe.lock new file mode 100644 index 000000000..fb7085d92 --- /dev/null +++ b/test-fixtures/spago-with-maybe.lock @@ -0,0 +1,562 @@ +workspace: + packages: + aaa: + path: ./ + dependencies: + - console + - effect + - maybe + - prelude + test_dependencies: [] + build_plan: + - console + - control + - effect + - invariant + - maybe + - newtype + - prelude + - safe-coerce + - unsafe-coerce + package_set: + address: + registry: 33.0.0 + compiler: ">=0.15.10 <0.16.0" + content: + ace: 9.1.0 + aff: 7.1.0 + aff-bus: 6.0.0 + aff-coroutines: 9.0.0 + aff-promise: 4.0.0 + aff-retry: 2.0.0 + affjax: 13.0.0 + affjax-node: 1.0.0 + affjax-web: 1.0.0 + ansi: 7.0.0 + argonaut: 9.0.0 + argonaut-aeson-generic: 0.4.1 + argonaut-codecs: 9.1.0 + argonaut-core: 7.0.0 + argonaut-generic: 8.0.0 + argonaut-traversals: 10.0.0 + argparse-basic: 2.0.0 + array-builder: 0.1.2 + array-search: 0.5.6 + arraybuffer: 13.2.0 + arraybuffer-builder: 3.1.0 + arraybuffer-types: 3.0.2 + arrays: 7.2.1 + arrays-zipper: 2.0.1 + ask: 1.0.0 + assert: 6.0.0 + assert-multiple: 0.3.4 + avar: 5.0.0 + b64: 0.0.8 + barbies: 1.0.1 + barlow-lens: 0.9.0 + basic-auth: 3.0.1 + bifunctors: 6.0.0 + bigints: 7.0.1 + bolson: 0.3.9 + bookhound: 0.1.3 + bower-json: 3.0.0 + bucketchain: 1.0.1 + bucketchain-basic-auth: 1.0.1 + bucketchain-conditional: 1.0.1 + bucketchain-cors: 1.0.1 + bucketchain-csrf: 1.0.1 + bucketchain-header-utils: 1.0.1 + bucketchain-health: 1.0.1 + bucketchain-history-api-fallback: 1.0.1 + bucketchain-logger: 1.0.1 + bucketchain-secure: 1.0.1 + bucketchain-simple-api: 5.0.1 + bucketchain-sslify: 1.0.1 + bucketchain-static: 1.0.1 + call-by-name: 4.0.1 + canvas: 6.0.0 + canvas-action: 9.0.0 + cartesian: 1.0.6 + catenable-lists: 7.0.0 + chameleon: 0.0.5 + chameleon-halogen: 0.0.5 + chameleon-react-basic: 0.1.0 + chameleon-styled: 0.1.0 + chameleon-transformers: 0.1.0 + channel: 1.0.0 + checked-exceptions: 3.1.1 + classless: 0.1.1 + classless-arbitrary: 0.1.1 + classless-decode-json: 0.1.1 + classless-encode-json: 0.1.3 + classnames: 2.0.0 + codec: 6.0.0 + codec-argonaut: 10.0.0 + colors: 7.0.1 + concur-core: 0.5.0 + concur-react: 0.5.0 + concurrent-queues: 3.0.0 + console: 6.0.0 + const: 6.0.0 + contravariant: 6.0.0 + control: 6.0.0 + convertable-options: 1.0.0 + coroutines: 7.0.0 + crypto: 5.0.1 + css: 6.0.0 + css-frameworks: 1.0.1 + data-mvc: 0.0.2 + datetime: 6.1.0 + datetime-parsing: 0.2.0 + debug: 6.0.2 + decimals: 7.1.0 + default-values: 1.0.1 + deku: 0.9.23 + deno: 0.0.5 + dissect: 1.0.0 + distributive: 6.0.0 + dodo-printer: 2.2.1 + dom-filereader: 7.0.0 + dom-indexed: 11.0.0 + dotenv: 4.0.0 + droplet: 0.6.0 + dts: 0.2.0 + dynamic-buffer: 3.0.1 + echarts-simple: 0.0.1 + effect: 4.0.0 + either: 6.1.0 + elmish: 0.10.0 + elmish-enzyme: 0.1.1 + elmish-hooks: 0.9.1 + elmish-html: 0.8.1 + elmish-testing-library: 0.3.1 + email-validate: 7.0.0 + encoding: 0.0.8 + enums: 6.0.1 + env-names: 0.3.4 + error: 2.0.0 + exceptions: 6.0.0 + exists: 6.0.0 + exitcodes: 4.0.0 + expect-inferred: 3.0.0 + fahrtwind: 2.0.0 + fallback: 0.1.0 + fast-vect: 1.1.0 + fetch-argonaut: 1.0.1 + fetch-yoga-json: 1.1.0 + filterable: 5.0.0 + fixed-points: 7.0.0 + fixed-precision: 5.0.0 + flame: 1.3.0 + float32: 2.0.0 + foldable-traversable: 6.0.0 + foreign: 7.0.0 + foreign-object: 4.1.0 + foreign-readwrite: 3.4.0 + forgetmenot: 0.1.0 + fork: 6.0.0 + form-urlencoded: 7.0.0 + formatters: 7.0.0 + framer-motion: 1.0.1 + free: 7.0.0 + freeap: 7.0.0 + freer-free: 0.0.1 + freet: 7.0.0 + functions: 6.0.0 + functor1: 3.0.0 + functors: 5.0.0 + fuzzy: 0.4.0 + gen: 4.0.0 + generate-values: 1.0.1 + generic-router: 0.0.1 + geojson: 0.0.3 + geometry-plane: 1.0.3 + github-actions-toolkit: 0.5.0 + grain: 3.0.0 + grain-router: 3.0.0 + grain-virtualized: 3.0.0 + graphql-client: 9.3.2 + graphs: 8.1.0 + group: 4.1.1 + halogen: 7.0.0 + halogen-bootstrap5: 2.2.0 + halogen-css: 10.0.0 + halogen-echarts-simple: 0.0.4 + halogen-formless: 4.0.3 + halogen-helix: 1.0.0 + halogen-hooks: 0.6.3 + halogen-hooks-extra: 0.9.0 + halogen-store: 0.5.4 + halogen-storybook: 2.0.0 + halogen-subscriptions: 2.0.0 + halogen-svg-elems: 8.0.0 + halogen-typewriter: 1.0.2 + halogen-vdom: 8.0.0 + halogen-vdom-string-renderer: 0.5.0 + heckin: 2.0.1 + heterogeneous: 0.6.0 + homogeneous: 0.4.0 + http-methods: 6.0.0 + httpure: 0.16.0 + httpurple: 3.0.1 + httpurple-argonaut: 1.0.1 + httpurple-yoga-json: 1.0.0 + humdrum: 0.0.1 + hyrule: 2.3.8 + identity: 6.0.0 + identy: 4.0.1 + indexed-db: 1.0.0 + indexed-monad: 3.0.0 + int64: 3.0.0 + integers: 6.0.0 + interactive-data: 0.3.0 + interpolate: 5.0.2 + invariant: 6.0.0 + jarilo: 1.0.1 + jelly: 0.10.0 + jelly-router: 0.3.0 + jelly-signal: 0.4.0 + jest: 1.0.0 + js-abort-controller: 1.0.0 + js-bigints: 2.1.0 + js-date: 8.0.0 + js-fileio: 3.0.0 + js-iterators: 0.1.1 + js-maps: 0.1.2 + js-promise: 1.0.0 + js-promise-aff: 1.0.0 + js-timers: 6.1.0 + js-uri: 3.1.0 + json-codecs: 3.0.0 + justifill: 0.5.0 + jwt: 0.0.9 + labeled-data: 0.2.0 + language-cst-parser: 0.13.0 + lazy: 6.0.0 + lazy-joe: 1.0.0 + lcg: 4.0.0 + leibniz: 5.0.0 + liminal: 1.0.1 + linalg: 6.0.0 + lists: 7.0.0 + literals: 1.0.2 + logging: 3.0.0 + logging-journald: 0.4.0 + machines: 7.0.0 + maps-eager: 0.4.1 + marionette: 1.0.0 + marionette-commander: 0.1.1 + marionette-react-basic-hooks: 0.1.1 + matrices: 5.0.1 + matryoshka: 1.0.0 + maybe: 6.0.0 + mdast-util-from-markdown: 0.2.1 + media-types: 6.0.0 + midi: 4.0.0 + milkis: 9.0.0 + minibench: 4.0.1 + mmorph: 7.0.0 + monad-control: 5.0.0 + monad-logger: 1.3.1 + monad-loops: 0.5.0 + monad-unlift: 1.0.1 + monoid-extras: 0.0.1 + monoidal: 0.16.0 + morello: 0.4.0 + mote: 3.0.0 + motsunabe: 2.0.0 + mvc: 0.0.1 + mysql: 6.0.1 + n3: 0.1.0 + nano-id: 1.1.0 + nanoid: 0.1.0 + naturals: 3.0.0 + nested-functor: 0.2.1 + newtype: 5.0.0 + nextjs: 0.1.1 + nextui: 0.2.0 + node-buffer: 8.0.0 + node-buffer-blob: 1.0.0 + node-child-process: 9.0.0 + node-env-paths: 1.0.0 + node-event-emitter: 3.0.0 + node-execa: 3.0.0 + node-fs: 8.2.0 + node-fs-aff: 9.2.0 + node-http: 8.0.0 + node-human-signals: 1.0.0 + node-net: 4.0.0 + node-os: 5.1.0 + node-path: 5.0.0 + node-process: 10.0.0 + node-readline: 7.0.0 + node-sqlite3: 8.0.0 + node-streams: 7.0.0 + node-streams-aff: 5.0.0 + node-url: 6.0.0 + node-zlib: 0.4.0 + nodemailer: 4.0.1 + nonempty: 7.0.0 + now: 6.0.0 + npm-package-json: 2.0.0 + nullable: 6.0.0 + numberfield: 0.1.0 + numbers: 9.0.1 + oak: 3.1.1 + oak-debug: 1.2.2 + object-maps: 0.3.0 + ocarina: 1.5.4 + open-folds: 6.3.0 + open-memoize: 6.1.0 + open-pairing: 6.1.0 + options: 7.0.0 + optparse: 5.0.0 + ordered-collections: 3.0.0 + ordered-set: 0.4.0 + orders: 6.0.0 + pairs: 9.0.1 + parallel: 6.0.0 + parsing: 10.2.0 + parsing-dataview: 3.2.4 + partial: 4.0.0 + pathy: 9.0.0 + pha: 0.11.0 + phaser: 0.7.0 + phylio: 1.1.2 + pipes: 8.0.0 + pirates-charm: 0.0.1 + pmock: 0.4.0 + point-free: 1.0.0 + pointed-list: 0.5.1 + polymorphic-vectors: 4.0.0 + posix-types: 6.0.0 + precise: 6.0.0 + precise-datetime: 7.0.0 + prelude: 6.0.1 + prettier-printer: 3.0.0 + profunctor: 6.0.0 + profunctor-lenses: 8.0.0 + protobuf: 4.3.0 + ps-cst: 1.2.0 + psa-utils: 8.0.0 + psc-ide: 19.0.0 + psci-support: 6.0.0 + qualified-do: 2.2.0 + quantities: 12.2.0 + quickcheck: 8.0.1 + quickcheck-combinators: 0.1.3 + quickcheck-laws: 7.0.0 + quickcheck-utf8: 0.0.0 + random: 6.0.0 + rationals: 6.0.0 + rdf: 0.1.0 + react: 11.0.0 + react-aria: 0.2.0 + react-basic: 17.0.0 + react-basic-classic: 3.0.0 + react-basic-dnd: 10.1.0 + react-basic-dom: 6.1.0 + react-basic-emotion: 7.1.0 + react-basic-hooks: 8.2.0 + react-basic-storybook: 2.0.0 + react-dom: 8.0.0 + react-halo: 3.0.0 + react-icons: 1.1.1 + react-markdown: 0.1.0 + react-testing-library: 4.0.1 + react-virtuoso: 1.0.0 + read: 1.0.1 + recharts: 1.1.0 + record: 4.0.0 + record-extra: 5.0.1 + record-studio: 1.0.4 + refs: 6.0.0 + remotedata: 5.0.0 + resource: 2.0.1 + resourcet: 1.0.0 + result: 1.0.3 + return: 0.2.0 + ring-modules: 5.0.1 + rito: 0.3.4 + routing: 11.0.0 + routing-duplex: 0.7.0 + run: 5.0.0 + safe-coerce: 2.0.0 + safely: 4.0.1 + school-of-music: 1.3.0 + selection-foldable: 0.2.0 + semirings: 7.0.0 + signal: 13.0.0 + simple-emitter: 3.0.1 + simple-i18n: 2.0.1 + simple-json: 9.0.0 + simple-jwt: 4.0.1 + simple-ulid: 3.0.0 + sized-matrices: 1.0.0 + sized-vectors: 5.0.2 + slug: 3.0.8 + small-ffi: 4.0.1 + soundfonts: 4.1.0 + sparse-matrices: 1.3.0 + sparse-polynomials: 2.0.5 + spec: 7.5.4 + spec-discovery: 8.0.1 + spec-golden: 1.0.0 + spec-mocha: 5.0.0 + spec-quickcheck: 5.0.0 + spec-reporter-xunit: 0.6.1 + splitmix: 2.1.0 + ssrs: 1.0.0 + st: 6.2.0 + statistics: 0.3.2 + strictlypositiveint: 1.0.1 + string-parsers: 8.0.0 + strings: 6.0.1 + strings-extra: 4.0.0 + stringutils: 0.0.12 + substitute: 0.2.3 + sunde: 3.0.0 + supply: 0.2.0 + svg-parser: 3.0.0 + systemd-journald: 0.3.0 + tagged: 4.0.2 + tailrec: 6.1.0 + tecton: 0.2.1 + tecton-halogen: 0.2.0 + test-unit: 17.0.0 + thermite: 6.3.1 + thermite-dom: 0.3.1 + these: 6.0.0 + toppokki: 4.0.0 + transformation-matrix: 1.0.1 + transformers: 6.0.0 + tree-rose: 4.0.2 + ts-bridge: 2.1.2 + tuples: 7.0.0 + two-or-more: 1.0.0 + type-equality: 4.0.1 + typedenv: 2.0.1 + typelevel: 6.0.0 + typelevel-lists: 2.1.0 + typelevel-peano: 1.0.1 + typelevel-prelude: 7.0.0 + typelevel-rows: 0.1.0 + uint: 7.0.0 + ulid: 3.0.1 + uncurried-transformers: 1.1.0 + undefined: 2.0.0 + undefined-is-not-a-problem: 1.1.0 + unfoldable: 6.0.0 + unicode: 6.0.0 + unique: 0.6.1 + unlift: 1.0.1 + unordered-collections: 3.0.1 + unsafe-coerce: 6.0.0 + unsafe-reference: 5.0.0 + untagged-to-tagged: 0.1.4 + untagged-union: 1.0.0 + uri: 9.0.0 + uuid: 9.0.0 + uuidv4: 1.0.0 + validation: 6.0.0 + variant: 8.0.0 + variant-encodings: 2.0.0 + vectorfield: 1.0.1 + vectors: 2.1.0 + versions: 7.0.0 + visx: 0.0.2 + web-clipboard: 5.0.0 + web-cssom: 2.0.0 + web-cssom-view: 0.1.0 + web-dom: 6.0.0 + web-dom-parser: 8.0.0 + web-dom-xpath: 3.0.0 + web-encoding: 3.0.0 + web-events: 4.0.0 + web-fetch: 4.0.1 + web-file: 4.0.0 + web-geometry: 0.1.0 + web-html: 4.1.0 + web-intl: 0.4.0 + web-pointerevents: 1.0.0 + web-proletarian: 1.0.0 + web-resize-observer: 2.0.0 + web-router: 1.0.0 + web-socket: 4.0.0 + web-storage: 5.0.0 + web-streams: 4.0.0 + web-touchevents: 4.0.0 + web-uievents: 4.0.0 + web-url: 2.0.0 + web-workers: 1.1.0 + web-xhr: 5.0.1 + webextension-polyfill: 0.1.0 + webgpu: 0.0.1 + which: 2.0.0 + yoga-fetch: 1.0.1 + yoga-json: 5.1.0 + yoga-om: 0.1.0 + yoga-postgres: 6.0.0 + yoga-tree: 1.0.0 + z3: 0.0.2 + extra_packages: {} +packages: + console: + type: registry + version: 6.0.0 + integrity: sha256-gJpJ53fCDAL8BiCiJXH0HNAJ9K3gJtLo8GDaCK6hA5U= + dependencies: + - effect + - prelude + control: + type: registry + version: 6.0.0 + integrity: sha256-sH7Pg9E96JCPF9PIA6oQ8+BjTyO/BH1ZuE/bOcyj4Jk= + dependencies: + - newtype + - prelude + effect: + type: registry + version: 4.0.0 + integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M= + dependencies: + - prelude + invariant: + type: registry + version: 6.0.0 + integrity: sha256-RGWWyYrz0Hs1KjPDA+87Kia67ZFBhfJ5lMGOMCEFoLo= + dependencies: + - control + - prelude + maybe: + type: registry + version: 6.0.0 + integrity: sha256-5cCIb0wPwbat2PRkQhUeZO0jcAmf8jCt2qE0wbC3v2Q= + dependencies: + - control + - invariant + - newtype + - prelude + newtype: + type: registry + version: 5.0.0 + integrity: sha256-gdrQu8oGe9eZE6L3wOI8ql/igOg+zEGB5ITh2g+uttw= + dependencies: + - prelude + - safe-coerce + prelude: + type: registry + version: 6.0.1 + integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= + dependencies: [] + safe-coerce: + type: registry + version: 2.0.0 + integrity: sha256-a1ibQkiUcbODbLE/WAq7Ttbbh9ex+x33VCQ7GngKudU= + dependencies: + - unsafe-coerce + unsafe-coerce: + type: registry + version: 6.0.0 + integrity: sha256-IqIYW4Vkevn8sI+6aUwRGvd87tVL36BBeOr0cGAE7t0= + dependencies: [] diff --git a/test-fixtures/spago.lock b/test-fixtures/spago.lock new file mode 100644 index 000000000..ec80c9f3d --- /dev/null +++ b/test-fixtures/spago.lock @@ -0,0 +1,514 @@ +workspace: + packages: + aaa: + path: ./ + dependencies: + - console + - effect + - prelude + test_dependencies: [] + build_plan: + - console + - effect + - prelude + package_set: + address: + registry: 33.0.0 + compiler: ">=0.15.10 <0.16.0" + content: + ace: 9.1.0 + aff: 7.1.0 + aff-bus: 6.0.0 + aff-coroutines: 9.0.0 + aff-promise: 4.0.0 + aff-retry: 2.0.0 + affjax: 13.0.0 + affjax-node: 1.0.0 + affjax-web: 1.0.0 + ansi: 7.0.0 + argonaut: 9.0.0 + argonaut-aeson-generic: 0.4.1 + argonaut-codecs: 9.1.0 + argonaut-core: 7.0.0 + argonaut-generic: 8.0.0 + argonaut-traversals: 10.0.0 + argparse-basic: 2.0.0 + array-builder: 0.1.2 + array-search: 0.5.6 + arraybuffer: 13.2.0 + arraybuffer-builder: 3.1.0 + arraybuffer-types: 3.0.2 + arrays: 7.2.1 + arrays-zipper: 2.0.1 + ask: 1.0.0 + assert: 6.0.0 + assert-multiple: 0.3.4 + avar: 5.0.0 + b64: 0.0.8 + barbies: 1.0.1 + barlow-lens: 0.9.0 + basic-auth: 3.0.1 + bifunctors: 6.0.0 + bigints: 7.0.1 + bolson: 0.3.9 + bookhound: 0.1.3 + bower-json: 3.0.0 + bucketchain: 1.0.1 + bucketchain-basic-auth: 1.0.1 + bucketchain-conditional: 1.0.1 + bucketchain-cors: 1.0.1 + bucketchain-csrf: 1.0.1 + bucketchain-header-utils: 1.0.1 + bucketchain-health: 1.0.1 + bucketchain-history-api-fallback: 1.0.1 + bucketchain-logger: 1.0.1 + bucketchain-secure: 1.0.1 + bucketchain-simple-api: 5.0.1 + bucketchain-sslify: 1.0.1 + bucketchain-static: 1.0.1 + call-by-name: 4.0.1 + canvas: 6.0.0 + canvas-action: 9.0.0 + cartesian: 1.0.6 + catenable-lists: 7.0.0 + chameleon: 0.0.5 + chameleon-halogen: 0.0.5 + chameleon-react-basic: 0.1.0 + chameleon-styled: 0.1.0 + chameleon-transformers: 0.1.0 + channel: 1.0.0 + checked-exceptions: 3.1.1 + classless: 0.1.1 + classless-arbitrary: 0.1.1 + classless-decode-json: 0.1.1 + classless-encode-json: 0.1.3 + classnames: 2.0.0 + codec: 6.0.0 + codec-argonaut: 10.0.0 + colors: 7.0.1 + concur-core: 0.5.0 + concur-react: 0.5.0 + concurrent-queues: 3.0.0 + console: 6.0.0 + const: 6.0.0 + contravariant: 6.0.0 + control: 6.0.0 + convertable-options: 1.0.0 + coroutines: 7.0.0 + crypto: 5.0.1 + css: 6.0.0 + css-frameworks: 1.0.1 + data-mvc: 0.0.2 + datetime: 6.1.0 + datetime-parsing: 0.2.0 + debug: 6.0.2 + decimals: 7.1.0 + default-values: 1.0.1 + deku: 0.9.23 + deno: 0.0.5 + dissect: 1.0.0 + distributive: 6.0.0 + dodo-printer: 2.2.1 + dom-filereader: 7.0.0 + dom-indexed: 11.0.0 + dotenv: 4.0.0 + droplet: 0.6.0 + dts: 0.2.0 + dynamic-buffer: 3.0.1 + echarts-simple: 0.0.1 + effect: 4.0.0 + either: 6.1.0 + elmish: 0.10.0 + elmish-enzyme: 0.1.1 + elmish-hooks: 0.9.1 + elmish-html: 0.8.1 + elmish-testing-library: 0.3.1 + email-validate: 7.0.0 + encoding: 0.0.8 + enums: 6.0.1 + env-names: 0.3.4 + error: 2.0.0 + exceptions: 6.0.0 + exists: 6.0.0 + exitcodes: 4.0.0 + expect-inferred: 3.0.0 + fahrtwind: 2.0.0 + fallback: 0.1.0 + fast-vect: 1.1.0 + fetch-argonaut: 1.0.1 + fetch-yoga-json: 1.1.0 + filterable: 5.0.0 + fixed-points: 7.0.0 + fixed-precision: 5.0.0 + flame: 1.3.0 + float32: 2.0.0 + foldable-traversable: 6.0.0 + foreign: 7.0.0 + foreign-object: 4.1.0 + foreign-readwrite: 3.4.0 + forgetmenot: 0.1.0 + fork: 6.0.0 + form-urlencoded: 7.0.0 + formatters: 7.0.0 + framer-motion: 1.0.1 + free: 7.0.0 + freeap: 7.0.0 + freer-free: 0.0.1 + freet: 7.0.0 + functions: 6.0.0 + functor1: 3.0.0 + functors: 5.0.0 + fuzzy: 0.4.0 + gen: 4.0.0 + generate-values: 1.0.1 + generic-router: 0.0.1 + geojson: 0.0.3 + geometry-plane: 1.0.3 + github-actions-toolkit: 0.5.0 + grain: 3.0.0 + grain-router: 3.0.0 + grain-virtualized: 3.0.0 + graphql-client: 9.3.2 + graphs: 8.1.0 + group: 4.1.1 + halogen: 7.0.0 + halogen-bootstrap5: 2.2.0 + halogen-css: 10.0.0 + halogen-echarts-simple: 0.0.4 + halogen-formless: 4.0.3 + halogen-helix: 1.0.0 + halogen-hooks: 0.6.3 + halogen-hooks-extra: 0.9.0 + halogen-store: 0.5.4 + halogen-storybook: 2.0.0 + halogen-subscriptions: 2.0.0 + halogen-svg-elems: 8.0.0 + halogen-typewriter: 1.0.2 + halogen-vdom: 8.0.0 + halogen-vdom-string-renderer: 0.5.0 + heckin: 2.0.1 + heterogeneous: 0.6.0 + homogeneous: 0.4.0 + http-methods: 6.0.0 + httpure: 0.16.0 + httpurple: 3.0.1 + httpurple-argonaut: 1.0.1 + httpurple-yoga-json: 1.0.0 + humdrum: 0.0.1 + hyrule: 2.3.8 + identity: 6.0.0 + identy: 4.0.1 + indexed-db: 1.0.0 + indexed-monad: 3.0.0 + int64: 3.0.0 + integers: 6.0.0 + interactive-data: 0.3.0 + interpolate: 5.0.2 + invariant: 6.0.0 + jarilo: 1.0.1 + jelly: 0.10.0 + jelly-router: 0.3.0 + jelly-signal: 0.4.0 + jest: 1.0.0 + js-abort-controller: 1.0.0 + js-bigints: 2.1.0 + js-date: 8.0.0 + js-fileio: 3.0.0 + js-iterators: 0.1.1 + js-maps: 0.1.2 + js-promise: 1.0.0 + js-promise-aff: 1.0.0 + js-timers: 6.1.0 + js-uri: 3.1.0 + json-codecs: 3.0.0 + justifill: 0.5.0 + jwt: 0.0.9 + labeled-data: 0.2.0 + language-cst-parser: 0.13.0 + lazy: 6.0.0 + lazy-joe: 1.0.0 + lcg: 4.0.0 + leibniz: 5.0.0 + liminal: 1.0.1 + linalg: 6.0.0 + lists: 7.0.0 + literals: 1.0.2 + logging: 3.0.0 + logging-journald: 0.4.0 + machines: 7.0.0 + maps-eager: 0.4.1 + marionette: 1.0.0 + marionette-commander: 0.1.1 + marionette-react-basic-hooks: 0.1.1 + matrices: 5.0.1 + matryoshka: 1.0.0 + maybe: 6.0.0 + mdast-util-from-markdown: 0.2.1 + media-types: 6.0.0 + midi: 4.0.0 + milkis: 9.0.0 + minibench: 4.0.1 + mmorph: 7.0.0 + monad-control: 5.0.0 + monad-logger: 1.3.1 + monad-loops: 0.5.0 + monad-unlift: 1.0.1 + monoid-extras: 0.0.1 + monoidal: 0.16.0 + morello: 0.4.0 + mote: 3.0.0 + motsunabe: 2.0.0 + mvc: 0.0.1 + mysql: 6.0.1 + n3: 0.1.0 + nano-id: 1.1.0 + nanoid: 0.1.0 + naturals: 3.0.0 + nested-functor: 0.2.1 + newtype: 5.0.0 + nextjs: 0.1.1 + nextui: 0.2.0 + node-buffer: 8.0.0 + node-buffer-blob: 1.0.0 + node-child-process: 9.0.0 + node-env-paths: 1.0.0 + node-event-emitter: 3.0.0 + node-execa: 3.0.0 + node-fs: 8.2.0 + node-fs-aff: 9.2.0 + node-http: 8.0.0 + node-human-signals: 1.0.0 + node-net: 4.0.0 + node-os: 5.1.0 + node-path: 5.0.0 + node-process: 10.0.0 + node-readline: 7.0.0 + node-sqlite3: 8.0.0 + node-streams: 7.0.0 + node-streams-aff: 5.0.0 + node-url: 6.0.0 + node-zlib: 0.4.0 + nodemailer: 4.0.1 + nonempty: 7.0.0 + now: 6.0.0 + npm-package-json: 2.0.0 + nullable: 6.0.0 + numberfield: 0.1.0 + numbers: 9.0.1 + oak: 3.1.1 + oak-debug: 1.2.2 + object-maps: 0.3.0 + ocarina: 1.5.4 + open-folds: 6.3.0 + open-memoize: 6.1.0 + open-pairing: 6.1.0 + options: 7.0.0 + optparse: 5.0.0 + ordered-collections: 3.0.0 + ordered-set: 0.4.0 + orders: 6.0.0 + pairs: 9.0.1 + parallel: 6.0.0 + parsing: 10.2.0 + parsing-dataview: 3.2.4 + partial: 4.0.0 + pathy: 9.0.0 + pha: 0.11.0 + phaser: 0.7.0 + phylio: 1.1.2 + pipes: 8.0.0 + pirates-charm: 0.0.1 + pmock: 0.4.0 + point-free: 1.0.0 + pointed-list: 0.5.1 + polymorphic-vectors: 4.0.0 + posix-types: 6.0.0 + precise: 6.0.0 + precise-datetime: 7.0.0 + prelude: 6.0.1 + prettier-printer: 3.0.0 + profunctor: 6.0.0 + profunctor-lenses: 8.0.0 + protobuf: 4.3.0 + ps-cst: 1.2.0 + psa-utils: 8.0.0 + psc-ide: 19.0.0 + psci-support: 6.0.0 + qualified-do: 2.2.0 + quantities: 12.2.0 + quickcheck: 8.0.1 + quickcheck-combinators: 0.1.3 + quickcheck-laws: 7.0.0 + quickcheck-utf8: 0.0.0 + random: 6.0.0 + rationals: 6.0.0 + rdf: 0.1.0 + react: 11.0.0 + react-aria: 0.2.0 + react-basic: 17.0.0 + react-basic-classic: 3.0.0 + react-basic-dnd: 10.1.0 + react-basic-dom: 6.1.0 + react-basic-emotion: 7.1.0 + react-basic-hooks: 8.2.0 + react-basic-storybook: 2.0.0 + react-dom: 8.0.0 + react-halo: 3.0.0 + react-icons: 1.1.1 + react-markdown: 0.1.0 + react-testing-library: 4.0.1 + react-virtuoso: 1.0.0 + read: 1.0.1 + recharts: 1.1.0 + record: 4.0.0 + record-extra: 5.0.1 + record-studio: 1.0.4 + refs: 6.0.0 + remotedata: 5.0.0 + resource: 2.0.1 + resourcet: 1.0.0 + result: 1.0.3 + return: 0.2.0 + ring-modules: 5.0.1 + rito: 0.3.4 + routing: 11.0.0 + routing-duplex: 0.7.0 + run: 5.0.0 + safe-coerce: 2.0.0 + safely: 4.0.1 + school-of-music: 1.3.0 + selection-foldable: 0.2.0 + semirings: 7.0.0 + signal: 13.0.0 + simple-emitter: 3.0.1 + simple-i18n: 2.0.1 + simple-json: 9.0.0 + simple-jwt: 4.0.1 + simple-ulid: 3.0.0 + sized-matrices: 1.0.0 + sized-vectors: 5.0.2 + slug: 3.0.8 + small-ffi: 4.0.1 + soundfonts: 4.1.0 + sparse-matrices: 1.3.0 + sparse-polynomials: 2.0.5 + spec: 7.5.4 + spec-discovery: 8.0.1 + spec-golden: 1.0.0 + spec-mocha: 5.0.0 + spec-quickcheck: 5.0.0 + spec-reporter-xunit: 0.6.1 + splitmix: 2.1.0 + ssrs: 1.0.0 + st: 6.2.0 + statistics: 0.3.2 + strictlypositiveint: 1.0.1 + string-parsers: 8.0.0 + strings: 6.0.1 + strings-extra: 4.0.0 + stringutils: 0.0.12 + substitute: 0.2.3 + sunde: 3.0.0 + supply: 0.2.0 + svg-parser: 3.0.0 + systemd-journald: 0.3.0 + tagged: 4.0.2 + tailrec: 6.1.0 + tecton: 0.2.1 + tecton-halogen: 0.2.0 + test-unit: 17.0.0 + thermite: 6.3.1 + thermite-dom: 0.3.1 + these: 6.0.0 + toppokki: 4.0.0 + transformation-matrix: 1.0.1 + transformers: 6.0.0 + tree-rose: 4.0.2 + ts-bridge: 2.1.2 + tuples: 7.0.0 + two-or-more: 1.0.0 + type-equality: 4.0.1 + typedenv: 2.0.1 + typelevel: 6.0.0 + typelevel-lists: 2.1.0 + typelevel-peano: 1.0.1 + typelevel-prelude: 7.0.0 + typelevel-rows: 0.1.0 + uint: 7.0.0 + ulid: 3.0.1 + uncurried-transformers: 1.1.0 + undefined: 2.0.0 + undefined-is-not-a-problem: 1.1.0 + unfoldable: 6.0.0 + unicode: 6.0.0 + unique: 0.6.1 + unlift: 1.0.1 + unordered-collections: 3.0.1 + unsafe-coerce: 6.0.0 + unsafe-reference: 5.0.0 + untagged-to-tagged: 0.1.4 + untagged-union: 1.0.0 + uri: 9.0.0 + uuid: 9.0.0 + uuidv4: 1.0.0 + validation: 6.0.0 + variant: 8.0.0 + variant-encodings: 2.0.0 + vectorfield: 1.0.1 + vectors: 2.1.0 + versions: 7.0.0 + visx: 0.0.2 + web-clipboard: 5.0.0 + web-cssom: 2.0.0 + web-cssom-view: 0.1.0 + web-dom: 6.0.0 + web-dom-parser: 8.0.0 + web-dom-xpath: 3.0.0 + web-encoding: 3.0.0 + web-events: 4.0.0 + web-fetch: 4.0.1 + web-file: 4.0.0 + web-geometry: 0.1.0 + web-html: 4.1.0 + web-intl: 0.4.0 + web-pointerevents: 1.0.0 + web-proletarian: 1.0.0 + web-resize-observer: 2.0.0 + web-router: 1.0.0 + web-socket: 4.0.0 + web-storage: 5.0.0 + web-streams: 4.0.0 + web-touchevents: 4.0.0 + web-uievents: 4.0.0 + web-url: 2.0.0 + web-workers: 1.1.0 + web-xhr: 5.0.1 + webextension-polyfill: 0.1.0 + webgpu: 0.0.1 + which: 2.0.0 + yoga-fetch: 1.0.1 + yoga-json: 5.1.0 + yoga-om: 0.1.0 + yoga-postgres: 6.0.0 + yoga-tree: 1.0.0 + z3: 0.0.2 + extra_packages: {} +packages: + console: + type: registry + version: 6.0.0 + integrity: sha256-gJpJ53fCDAL8BiCiJXH0HNAJ9K3gJtLo8GDaCK6hA5U= + dependencies: + - effect + - prelude + effect: + type: registry + version: 4.0.0 + integrity: sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M= + dependencies: + - prelude + prelude: + type: registry + version: 6.0.1 + integrity: sha256-o8p6SLYmVPqzXZhQFd2hGAWEwBoXl1swxLG/scpJ0V0= + dependencies: [] diff --git a/test-fixtures/test-missing-module.txt b/test-fixtures/test-missing-module.txt index 41ac0250f..48118579c 100644 --- a/test-fixtures/test-missing-module.txt +++ b/test-fixtures/test-missing-module.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: 7368613235362d6a336156536c675a7033334e7659556c6d38 diff --git a/test-fixtures/test-output-stderr.txt b/test-fixtures/test-output-stderr.txt index f2da8ecc5..6c8684e9f 100644 --- a/test-fixtures/test-output-stderr.txt +++ b/test-fixtures/test-output-stderr.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: 7368613235362d6a336156536c675a7033334e7659556c6d38 diff --git a/test-fixtures/uninstall-deps-undeclared-src-deps.txt b/test-fixtures/uninstall-deps-undeclared-src-deps.txt index 7c5846b9e..adc618e10 100644 --- a/test-fixtures/uninstall-deps-undeclared-src-deps.txt +++ b/test-fixtures/uninstall-deps-undeclared-src-deps.txt @@ -1,8 +1,9 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: uninstall-tests ⚠️ The following packages cannot be uninstalled because they are not declared in the package's source dependencies: - either -The package config for uninstall-tests was not updated. + either +⚠️ The package config for uninstall-tests was not updated. +No lockfile found, generating it... +Lockfile written to spago.lock. Please commit this file. diff --git a/test-fixtures/uninstall-deps-undeclared-test-deps.txt b/test-fixtures/uninstall-deps-undeclared-test-deps.txt index a98c42f1a..f7b3d8654 100644 --- a/test-fixtures/uninstall-deps-undeclared-test-deps.txt +++ b/test-fixtures/uninstall-deps-undeclared-test-deps.txt @@ -1,8 +1,9 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: uninstall-tests ⚠️ The following packages cannot be uninstalled because they are not declared in the package's test dependencies: - either -The package config for uninstall-tests was not updated. + either +⚠️ The package config for uninstall-tests was not updated. +No lockfile found, generating it... +Lockfile written to spago.lock. Please commit this file. diff --git a/test-fixtures/uninstall-no-package-selection.txt b/test-fixtures/uninstall-no-package-selection.txt index e1f326301..cfa2801c2 100644 --- a/test-fixtures/uninstall-no-package-selection.txt +++ b/test-fixtures/uninstall-no-package-selection.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting 2 packages to build: bar diff --git a/test-fixtures/uninstall-no-test-config.txt b/test-fixtures/uninstall-no-test-config.txt index db33dfcc4..28eb91468 100644 --- a/test-fixtures/uninstall-no-test-config.txt +++ b/test-fixtures/uninstall-no-test-config.txt @@ -1,5 +1,4 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: uninstall-tests diff --git a/test-fixtures/uninstall-remove-src-deps.txt b/test-fixtures/uninstall-remove-src-deps.txt index 23d474152..891850a33 100644 --- a/test-fixtures/uninstall-remove-src-deps.txt +++ b/test-fixtures/uninstall-remove-src-deps.txt @@ -1,7 +1,7 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: uninstall-tests -Removing the following source dependencies: - either +Removing the following source dependencies: either +Lockfile is out of date (uninstalled packages), generating it... +Lockfile written to spago.lock. Please commit this file. diff --git a/test-fixtures/uninstall-remove-test-deps.txt b/test-fixtures/uninstall-remove-test-deps.txt index 70b7e7271..525d292dc 100644 --- a/test-fixtures/uninstall-remove-test-deps.txt +++ b/test-fixtures/uninstall-remove-test-deps.txt @@ -1,7 +1,7 @@ Reading Spago workspace configuration... -Read the package set from the registry ✅ Selecting package to build: uninstall-tests -Removing the following test dependencies: - either +Removing the following test dependencies: either +Lockfile is out of date (uninstalled packages), generating it... +Lockfile written to spago.lock. Please commit this file. diff --git a/test/Prelude.purs b/test/Prelude.purs index 6cc6a4078..65c5b5efc 100644 --- a/test/Prelude.purs +++ b/test/Prelude.purs @@ -177,10 +177,10 @@ checkOutputs checkers execResult = do Console.log $ "Overwriting fixture at path: " <> fixtureFileExpected let parentDir = dirname fixtureFileExpected unlessM (FS.exists parentDir) $ FS.mkdirp parentDir - FS.writeTextFile fixtureFileExpected actual + FS.writeTextFile fixtureFileExpected (actual <> "\n") else do expected <- String.trim <$> FS.readTextFile fixtureFileExpected - actual `Assert.shouldEqual` expected + actual `shouldEqualStr` expected check { stdout: checkOrOverwrite checkers.stdoutFile , stderr: checkOrOverwrite checkers.stderrFile diff --git a/test/Spago/Build.purs b/test/Spago/Build.purs index b1e411a01..33a23aa0a 100644 --- a/test/Spago/Build.purs +++ b/test/Spago/Build.purs @@ -8,9 +8,10 @@ import Node.Process as Process import Spago.Command.Init as Init import Spago.Core.Config as Config import Spago.FS as FS +import Spago.Paths as Paths +import Test.Spago.Build.BuildInfo as BuildInfo import Test.Spago.Build.Pedantic as Pedantic import Test.Spago.Build.Polyrepo as BuildPolyrepo -import Test.Spago.Build.BuildInfo as BuildInfo import Test.Spec (Spec) import Test.Spec as Spec import Test.Spec.Assertions as Assert @@ -106,6 +107,36 @@ spec = Spec.around withTempDir do } spago [ "build" ] >>= shouldBeFailure + Spec.it "building with a lockfile doesn't need the Registry repo" \{ spago, fixture } -> do + spago [ "init", "--name", "aaa", "--package-set", "33.0.0" ] >>= shouldBeSuccess + spago [ "build" ] >>= shouldBeSuccess + -- Check that we have written the lockfile + checkFixture "spago.lock" (fixture "spago.lock") + -- Then remove the registry repo + FSA.rm' Paths.registryPath { force: true, recursive: true, retryDelay: 0, maxRetries: 0 } + -- And check that we can still build + spago [ "build" ] >>= shouldBeSuccess + -- And that we still don't have the registry + FS.exists Paths.registryPath `Assert.shouldReturn` false + + Spec.it "using the --pure flag does not refresh the lockfile" \{ spago, fixture } -> do + spago [ "init", "--name", "aaa", "--package-set", "33.0.0" ] >>= shouldBeSuccess + spago [ "build" ] >>= shouldBeSuccess + -- Check that we have written the lockfile + checkFixture "spago.lock" (fixture "spago.lock") + -- Update the config + let + conf = Init.defaultConfig + { name: mkPackageName "aaa" + , testModuleName: "Test.Main" + , withWorkspace: Just { setVersion: Just $ mkVersion "33.0.0" } + } + FS.writeYamlFile Config.configCodec "spago.yaml" + (conf { package = conf.package # map (\pkg -> pkg { dependencies = pkg.dependencies <> mkDependencies [ "maybe" ] }) }) + -- Check that building with --pure does not refresh the lockfile + spago [ "build", "--pure" ] >>= shouldBeSuccess + checkFixture "spago.lock" (fixture "spago.lock") + Spec.it "compiles with the specified backend" \{ spago, fixture } -> do spago [ "init" ] >>= shouldBeSuccess let diff --git a/test/Spago/Build/Polyrepo.purs b/test/Spago/Build/Polyrepo.purs index fd74561f1..cae181797 100644 --- a/test/Spago/Build/Polyrepo.purs +++ b/test/Spago/Build/Polyrepo.purs @@ -170,12 +170,13 @@ spec = Spec.describe "polyrepo" do end ``` -} - Spec.it "Case 3 (dependencies: A&B -> C; A -> B) builds" \{ spago } -> do + Spec.it "Case 3 (dependencies: A&B -> C; A -> B) builds" \{ spago, fixture } -> do writeWorkspaceOnlySpagoYamlFile pkgC <- setupPackageWithDeps { packageName: "package-c", hasTest: false, deps: [] } pkgB <- setupPackageWithDeps { packageName: "package-b", hasTest: true, deps: [ pkgC ] } void $ setupPackageWithDeps { packageName: "package-a", hasTest: true, deps: [ pkgC, pkgB ] } spago [ "build" ] >>= shouldBeSuccess + checkFixture "spago.lock" (fixture "polyrepo.lock") {- ```mermaid diff --git a/test/Spago/Install.purs b/test/Spago/Install.purs index 529e86104..f902c9807 100644 --- a/test/Spago/Install.purs +++ b/test/Spago/Install.purs @@ -22,7 +22,7 @@ spec :: Spec Unit spec = Spec.around withTempDir do Spec.describe "install" do - Spec.it "warns that config was not changed when trying to install a package already present in project dependencies" \{ spago, fixture } -> do + Spec.it "warns that the config was not changed when trying to install a package already present in project dependencies" \{ spago, fixture } -> do spago [ "init", "--name", "7368613235362d50744f44764f717435586c685938735a5154" ] >>= shouldBeSuccess spago [ "install" ] >>= shouldBeSuccess spago [ "fetch", "effect" ] >>= shouldBeSuccessErr (fixture "spago-install-existing-dep-stderr.txt") @@ -211,32 +211,6 @@ spec = Spec.around withTempDir do spago [ "install", "-p", "subpackage", "either" ] >>= shouldBeSuccess checkFixture "subpackage/spago.yaml" (fixture "spago-subpackage-install-success.yaml") - Spec.it "adds a hash to the package set when importing it from a URL" \{ spago, fixture } -> do - spago [ "init" ] >>= shouldBeSuccess - let - conf = Init.defaultConfig - { name: mkPackageName "aaa" - , withWorkspace: Just - { setVersion: Just $ unsafeFromRight $ Version.parse "0.0.1" } - , testModuleName: "Test.Main" - } - FS.writeYamlFile Config.configCodec "spago.yaml" - ( conf - { workspace = conf.workspace # map - ( _ - { package_set = Just - ( Config.SetFromUrl - { hash: Nothing - , url: "https://raw.githubusercontent.com/purescript/registry/main/package-sets/29.3.0.json" - } - ) - } - ) - } - ) - spago [ "install" ] >>= shouldBeSuccess - checkFixture "spago.yaml" (fixture "spago-with-hash.yaml") - Spec.it "can build with a newer (but still compatible) compiler than the one in the package set" \{ spago } -> do spago [ "init", "--package-set", "10.0.0" ] >>= shouldBeSuccess startingTime <- liftEffect $ Now.now @@ -247,6 +221,18 @@ spec = Spec.around withTempDir do false -> Assert.fail $ "Expected purs version to be newer than 0.15.4, but it was " <> Version.print purs.version spago [ "install" ] >>= shouldBeSuccess + Spec.it "can refresh the lockfile, and uninstall restores it" \{ spago, fixture } -> do + spago [ "init", "--name", "aaa", "--package-set", "33.0.0" ] >>= shouldBeSuccess + spago [ "build" ] >>= shouldBeSuccess + -- Check that we have written the lockfile + checkFixture "spago.lock" (fixture "spago.lock") + spago [ "install", "maybe" ] >>= shouldBeSuccess + -- Check that the new lockfile includes maybe + checkFixture "spago.lock" (fixture "spago-with-maybe.lock") + spago [ "uninstall", "maybe" ] >>= shouldBeSuccess + -- Check that the lockfile is back to the original + checkFixture "spago.lock" (fixture "spago.lock") + writeConfigWithEither :: Aff Unit writeConfigWithEither = do -- The commit for `either` is for the `v6.1.0` release diff --git a/test/Spago/Lock.purs b/test/Spago/Lock.purs index c184b1819..31cd15be3 100644 --- a/test/Spago/Lock.purs +++ b/test/Spago/Lock.purs @@ -4,11 +4,13 @@ import Test.Prelude import Data.Codec.Argonaut as CA import Data.Map as Map +import Data.Set as Set import Registry.Range as Range import Registry.Sha256 as Sha256 import Registry.Version as Version import Spago.Core.Config (Dependencies(..), ExtraPackage(..), RemotePackage(..), SetAddress(..)) import Spago.Core.Config as Config +import Spago.Core.Config as Core import Spago.Lock (LockEntry(..), Lockfile) import Spago.Lock as Lock import Test.Spec (Spec) @@ -37,14 +39,29 @@ validLockfile = ] , test_dependencies: Dependencies Map.empty , path: "my-app" + , build_plan: Set.fromFoldable + [ mkPackageName "my-library" + , mkPackageName "effect" + , mkPackageName "prelude" + ] } , packageTuple "my-library" { dependencies: Dependencies $ Map.fromFoldable [ packageTuple "prelude" Nothing ] , test_dependencies: Dependencies $ Map.fromFoldable [ packageTuple "console" (Just Config.widestRange) ] , path: "my-library" + , build_plan: Set.fromFoldable [ mkPackageName "prelude" ] } ] - , package_set: Just $ SetFromRegistry { registry: unsafeFromRight (Version.parse "22.1.1") } + , package_set: Just + { address: SetFromRegistry { registry: unsafeFromRight (Version.parse "22.1.1") } + , compiler: unsafeFromRight (Range.parse ">=0.13.8 <0.14.0") + -- This is not actually the content of the package set, but you get the idea + , content: Map.fromFoldable + [ Tuple (mkPackageName "effect") (Core.RemoteRegistryVersion $ mkVersion "4.0.0") + , Tuple (mkPackageName "prelude") (Core.RemoteRegistryVersion $ mkVersion "4.0.0") + , Tuple (mkPackageName "console") (Core.RemoteRegistryVersion $ mkVersion "4.0.0") + ] + } , extra_packages: Map.fromFoldable [ packageTuple "console" $ ExtraRemotePackage $ RemoteGitPackage { git: "https://github.com/purescript/purescript-console.git" @@ -62,23 +79,26 @@ validLockfile = } , packages: Map.fromFoldable - [ packageTuple "console" $ FromGit - { url: "https://github.com/purescript/purescript-console.git" - , rev: "3b83d7b792d03872afeea5e62b4f686ab0f09842" - , subdir: Nothing - , dependencies: [ prelude ] - } - , packageTuple "effect" $ FromRegistry - { version: unsafeFromRight (Version.parse "4.0.0") - , integrity: unsafeFromRight (Sha256.parse "sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M=") - , dependencies: [ prelude ] - } - , packageTuple "prelude" $ FromGit - { url: "https://github.com/purescript/purescript-libraries.git" - , rev: "3b83d7b792d03872afeea5e62b4f686ab0f09842" - , subdir: Just "prelude" - , dependencies: [] - } + [ packageTuple "console" $ + FromGit + { url: "https://github.com/purescript/purescript-console.git" + , rev: "3b83d7b792d03872afeea5e62b4f686ab0f09842" + , subdir: Nothing + , dependencies: [ prelude ] + } + , packageTuple "effect" $ + FromRegistry + { version: unsafeFromRight (Version.parse "4.0.0") + , integrity: unsafeFromRight (Sha256.parse "sha256-eBtZu+HZcMa5HilvI6kaDyVX3ji8p0W9MGKy2K4T6+M=") + , dependencies: [ prelude ] + } + , packageTuple "prelude" $ + FromGit + { url: "https://github.com/purescript/purescript-libraries.git" + , rev: "3b83d7b792d03872afeea5e62b4f686ab0f09842" + , subdir: Just "prelude" + , dependencies: [] + } ] } where @@ -95,6 +115,10 @@ workspace: packages: my-app: path: my-app + build_plan: + - effect + - my-library + - prelude dependencies: - effect: ">=1.0.0 <5.0.0" - my-library @@ -102,14 +126,21 @@ workspace: my-library: path: my-library + build_plan: + - prelude dependencies: - prelude test_dependencies: - console: "*" package_set: - registry: 22.1.1 - + address: + registry: 22.1.1 + compiler: ">=0.13.8 <0.14.0" + content: + console: 4.0.0 + effect: 4.0.0 + prelude: 4.0.0 extra_packages: console: git: https://github.com/purescript/purescript-console.git diff --git a/test/Spago/Publish.purs b/test/Spago/Publish.purs index f5c47c4e8..5fdd88286 100644 --- a/test/Spago/Publish.purs +++ b/test/Spago/Publish.purs @@ -33,7 +33,7 @@ spec = Spec.around withTempDir do spago [ "build" ] >>= shouldBeSuccess spago [ "publish", "--offline" ] >>= shouldBeFailureErr (fixture "publish-no-git.txt") - Spec.it "fails the module is called Main" \{ spago, fixture } -> do + Spec.it "fails if the module is called Main" \{ spago, fixture } -> do spago [ "init", "--name", "aaaa" ] >>= shouldBeSuccess FSA.unlink "spago.yaml" FS.copyFile { src: fixture "spago-publish.yaml", dst: "spago.yaml" }