diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c7c4cac0..2af2f670c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -95,7 +95,7 @@ jobs: $HOME\AppData\Local\Programs\stack\x86_64-windows key: ${{ runner.os }}-${{ hashFiles('stack.yaml') }}-1 - - run: npm install -g purescript@0.14.0 psc-package@3.0.1 bower@1.8.8 + - run: npm install -g purescript@0.14.0 psc-package@3.0.1 bower@1.8.8 esbuild@0.14.28 - name: Install dependencies run: | @@ -112,6 +112,13 @@ jobs: run: ./scripts/fix-home stack install shell: bash - - name: Run tests + - name: Run tests (PureScript < 0.15.0) run: ./scripts/fix-home stack test shell: bash + + - name: Install PureScript 0.15.0 + run: npm install -g purescript@next + + - name: Run tests (PureScript >= 0.15.0) + shell: bash + run: ./scripts/fix-home stack test --ta "--match purs-0.15" diff --git a/CHANGELOG.md b/CHANGELOG.md index cd2e7c33e..4d9755b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ Features: - Support Glibc versions >= `2.24` - Retry git clone up to two times (#834, #873) +Bugfixes +- Fix `spago run` and `spago test` to accept command line arguments correctly, by writing a JS file to run (#865, #866) +- Remove support for node versions older than 12.0.0 as they do not work with es modules (#866) + ## [0.20.7] - 2022-02-12 Bugfixes diff --git a/spago.cabal b/spago.cabal index 54cc29255..d3a73144e 100644 --- a/spago.cabal +++ b/spago.cabal @@ -87,6 +87,7 @@ library Spago.Bower Spago.Build Spago.CLI + Spago.Cmd Spago.Command.Init Spago.Command.Ls Spago.Command.Path diff --git a/src/Spago/Build.hs b/src/Spago/Build.hs index 3bab378bf..b4ef1b073 100644 --- a/src/Spago/Build.hs +++ b/src/Spago/Build.hs @@ -17,6 +17,7 @@ import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as Text +import qualified Data.Versions as Version import System.Directory (getCurrentDirectory) import System.FilePath (splitDirectories) import qualified System.FilePath.Glob as Glob @@ -36,6 +37,7 @@ import qualified Spago.Packages as Packages import qualified Spago.Purs as Purs import qualified Spago.Templates as Templates import qualified Spago.Watch as Watch +import qualified Spago.Cmd as Cmd prepareBundleDefaults @@ -50,7 +52,7 @@ prepareBundleDefaults maybeModuleName maybeTargetPath maybePlatform = (moduleNam platform = fromMaybe Browser maybePlatform -- eventually running some other action after the build -build :: HasBuildEnv env => Maybe (RIO Env ()) -> RIO env () +build :: HasBuildEnv env => Maybe (RIO env ()) -> RIO env () build maybePostBuild = do logDebug "Running `spago build`" BuildOptions{..} <- view (the @BuildOptions) @@ -143,8 +145,7 @@ build maybePostBuild = do checkImports buildAction globs = do - env <- Run.getEnv - let action = buildBackend globs >> (runRIO env $ fromMaybe (pure ()) maybePostBuild) + let action = buildBackend globs >> (fromMaybe (pure ()) maybePostBuild) runCommands "Before" beforeCommands action `onException` (runCommands "Else" elseCommands) runCommands "Then" thenCommands @@ -309,6 +310,22 @@ script modulePath tag packageDeps opts = do data RunDirectories = RunDirectories { sourceDir :: FilePath, executeDir :: FilePath } +data NodeEsSupport = Unsupported Version.SemVer | Experimental | Supported + +hasNodeEsSupport :: (HasLogFunc env) => RIO env NodeEsSupport +hasNodeEsSupport = do + nodeVersion <- Cmd.getCmdVersion "node" + case nodeVersion of + Left err -> do + logDebug $ display $ "Unable to get Node.js version: " <> displayShow err + pure Supported + Right nv@Version.SemVer{} | Version._svMajor nv < 12 -> + pure $ Unsupported nv + Right nv@Version.SemVer{} | Version._svMajor nv >= 12 && Version._svMajor nv < 13 -> + pure Experimental + _ -> pure Supported + + -- | Run the project with node (or the chosen alternate backend): -- compile and run the provided ModuleName runBackend @@ -323,15 +340,17 @@ runBackend runBackend maybeBackend RunDirectories{ sourceDir, executeDir } moduleName maybeSuccessMessage failureMessage extraArgs = do logDebug $ display $ "Running with backend: " <> fromMaybe "nodejs" maybeBackend BuildOptions{ pursArgs } <- view (the @BuildOptions) - isES <- Purs.hasMinPursVersion "0.15.0" - let postBuild = maybe (nodeAction isES $ Path.getOutputPath pursArgs) backendAction maybeBackend + let + postBuild = maybe (nodeAction $ Path.getOutputPath pursArgs) backendAction maybeBackend build (Just postBuild) where fromFilePath = Text.pack . Turtle.encodeString + runJsSource = fromFilePath (sourceDir Turtle. ".spago/run.js") + packageJson = fromFilePath (sourceDir Turtle. ".spago/package.json") nodeArgs = Text.intercalate " " $ map unBackendArg extraArgs esContents outputPath' = fold - [ "import { main } from '" + [ "import { main } from 'file://" , Text.replace "\\" "/" (fromFilePath sourceDir) , "/" , Text.pack outputPath' @@ -352,19 +371,36 @@ runBackend maybeBackend RunDirectories{ sourceDir, executeDir } moduleName maybe , unModuleName moduleName , "').main()" ] - nodeCmd isES outputPath'= - if isES then - "node --input-type=module -e \"" <> esContents outputPath' <> "\" -- " <> nodeArgs - else - "node -e \"" <> cjsContents outputPath' <> "\" -- " <> nodeArgs - - nodeAction isES outputPath' = do + nodeContents isES outputPath' = + if isES then esContents outputPath' + else cjsContents outputPath' + + packageJsonContents = "{\"type\":\"module\" }" + + nodeCmd isES Experimental | isES = "node --experimental-modules \"" <> runJsSource <> "\" " <> nodeArgs + nodeCmd _ _ = "node \"" <> runJsSource <> "\" " <> nodeArgs + + nodeAction outputPath' = do + isES <- Purs.hasMinPursVersion "0.15.0-alpha-01" + nodeVersion <- hasNodeEsSupport + case (isES, nodeVersion) of + (True, Unsupported nv) -> + die [ "Unsupported Node.js version: " <> display (Version.prettySemVer nv), "Required Node.js version >=12." ] + _ -> + pure () + logDebug $ "Writing " <> displayShow @Text runJsSource + writeTextFile runJsSource (nodeContents isES outputPath') + void $ chmod executable $ pathFromText runJsSource + if isES then do + logDebug $ "Writing " <> displayShow @Text packageJson + writeTextFile packageJson packageJsonContents + else pure () -- cd to executeDir in case it isn't the same as sourceDir logDebug $ "Executing from: " <> displayShow @FilePath executeDir Turtle.cd executeDir -- We build a process by hand here because we need to forward the stdin to the backend process - logDebug $ "Running node command: `" <> display (nodeCmd isES outputPath') <> "`" - let processWithStdin = (Process.shell (Text.unpack $ nodeCmd isES outputPath')) { Process.std_in = Process.Inherit } + logDebug $ "Running node command: `" <> display (nodeCmd isES nodeVersion) <> "`" + let processWithStdin = (Process.shell (Text.unpack $ nodeCmd isES nodeVersion)) { Process.std_in = Process.Inherit } Turtle.system processWithStdin empty >>= \case ExitSuccess -> maybe (pure ()) (logInfo . display) maybeSuccessMessage ExitFailure n -> die [ display failureMessage <> "exit code: " <> repr n ] @@ -376,26 +412,28 @@ runBackend maybeBackend RunDirectories{ sourceDir, executeDir } moduleName maybe ExitFailure n -> die [ display failureMessage <> "Backend " <> displayShow backend <> " exited with error:" <> repr n ] -bundleWithEsbuild :: HasLogFunc env => WithMain -> ModuleName -> TargetPath -> Platform -> Minify -> RIO env () -bundleWithEsbuild withMain (ModuleName moduleName) (TargetPath targetPath) platform minify = do +bundleWithEsbuild :: HasLogFunc env => WithMain -> WithSrcMap -> ModuleName -> TargetPath -> Platform -> Minify -> RIO env () +bundleWithEsbuild withMain srcMap (ModuleName moduleName) (TargetPath targetPath) platform minify = do esbuild <- getESBuild let platformOpt = case platform of - Browser -> "browser" - Node -> "node" + Browser -> ["--platform=browser"] + Node -> ["--platform=node"] minifyOpt = case minify of - NoMinify -> "" - Minify -> " --minify" - cmd = case withMain of - WithMain -> - "echo \"import { main } from './output/" <> moduleName <> "/index.js'\nmain()\" | " - <> esbuild <> " --platform=" <> platformOpt <> minifyOpt <> " --bundle " - <> " --outfile=" <> targetPath + NoMinify -> [] + Minify -> ["--minify"] + srcMapOpt = case srcMap of + WithSrcMap -> ["--sourcemap"] + WithoutSrcMap -> [] + esbuildBase = platformOpt <> minifyOpt <> srcMapOpt <> ["--format=esm", "--bundle", "--outfile=" <> targetPath] + (input, cmd) = case withMain of + WithMain -> do + let + echoLine = "import { main } from './output/" <> moduleName <> "/index.js'; main();" + (Turtle.textToLine echoLine, esbuild :| esbuildBase) WithoutMain -> - esbuild <> " --platform=" <> platformOpt <> minifyOpt <> " --bundle " - <> "output/" <> moduleName <> "/index.js" - <> " --outfile=" <> targetPath - runWithOutput cmd + (Nothing, esbuild :| esbuildBase <> ["output/" <> moduleName <> "/index.js"]) + runProcessWithOutput cmd input ("Bundle succeeded and output file to " <> targetPath) "Bundle failed." where @@ -414,12 +452,12 @@ bundleModule -> UsePsa -> RIO env () bundleModule withMain BundleOptions { maybeModuleName, maybeTargetPath, maybePlatform, minify, noBuild } buildOpts usePsa = do - isES <- Purs.hasMinPursVersion "0.15.0" + isES <- Purs.hasMinPursVersion "0.15.0-alpha-01" let (moduleName, targetPath, platform) = prepareBundleDefaults maybeModuleName maybeTargetPath maybePlatform bundleAction = if isES then - bundleWithEsbuild withMain moduleName targetPath platform minify + bundleWithEsbuild withMain (withSourceMap buildOpts) moduleName targetPath platform minify else case withMain of WithMain -> Purs.bundle WithMain (withSourceMap buildOpts) moduleName targetPath WithoutMain -> @@ -437,7 +475,7 @@ bundleModule withMain BundleOptions { maybeModuleName, maybeTargetPath, maybePla Left (n :: SomeException) -> die [ "Make module failed: " <> repr n ] case noBuild of DoBuild -> Run.withBuildEnv usePsa buildOpts $ build (Just bundleAction) - NoBuild -> Run.getEnv >>= (flip runRIO) bundleAction + NoBuild -> Run.withBuildEnv usePsa buildOpts bundleAction docsSearchTemplate :: (HasType LogFunc env, HasType PursCmd env) => RIO env Text docsSearchTemplate = ifM (Purs.hasMinPursVersion "0.14.0") diff --git a/src/Spago/Cmd.hs b/src/Spago/Cmd.hs new file mode 100644 index 000000000..620508a18 --- /dev/null +++ b/src/Spago/Cmd.hs @@ -0,0 +1,26 @@ +module Spago.Cmd (getCmdVersion) where + +import qualified Spago.Messages as Messages +import qualified Turtle.Bytes +import Spago.Prelude +import qualified Data.Text as Text +import qualified Data.Text.Encoding as Text.Encoding +import qualified Data.Text.Encoding.Error as Text.Encoding +import qualified Data.Versions as Version + +-- | Get the semantic version of a command, e.g. purs --version +getCmdVersion :: forall io. MonadIO io => Text -> io (Either Text Version.SemVer) +getCmdVersion cmd = + Turtle.Bytes.shellStrictWithErr (cmd <> " --version") empty >>= \case + (ExitSuccess, out, _err) -> do + let versionText = headMay $ Text.split (== ' ') (Text.strip $ Text.Encoding.decodeUtf8With lenientDecode out) + parsed = versionText >>= (\vt -> Text.stripPrefix "v" vt <|> Just vt) >>= (hush . Version.semver) + + pure $ case parsed of + Nothing -> + Left $ + Messages.failedToParseCommandOutput + (cmd <> " --version") + (Text.Encoding.decodeUtf8With Text.Encoding.lenientDecode out) + Just p -> Right p + (_, _out, _err) -> pure $ Left $ "Failed to run '" <> cmd <> " --version'" diff --git a/src/Spago/Prelude.hs b/src/Spago/Prelude.hs index daf32765a..79c93bc30 100644 --- a/src/Spago/Prelude.hs +++ b/src/Spago/Prelude.hs @@ -67,6 +67,7 @@ module Spago.Prelude , findExecutableOrDie , findExecutable , runWithOutput + , runProcessWithOutput -- * Other , Dhall.Core.throws , repr @@ -108,7 +109,7 @@ import RIO as X hiding (FilePath, fi import RIO.Orphans as X import Safe (headMay, lastMay) import System.FilePath (isAbsolute, pathSeparator, ()) -import Turtle (FilePath, appendonly, chmod, +import Turtle (FilePath, Line, appendonly, chmod, executable, mktree, repr, shell, shellStrict, shellStrictWithErr, systemStrictWithErr, testdir) @@ -271,6 +272,14 @@ runWithOutput command success failure = do ExitSuccess -> logInfo $ display success ExitFailure _ -> die [ display failure ] +-- | Run the given command. +runProcessWithOutput :: HasLogFunc env => NonEmpty Text -> Maybe Line -> Text -> Text -> RIO env () +runProcessWithOutput (command :| arguments) input success failure = do + logDebug $ "Running command: `" <> display (Text.intercalate " " $ command : arguments) <> "`" + Turtle.proc command arguments (Turtle.select input) >>= \case + ExitSuccess -> logInfo $ display success + ExitFailure _ -> die [ display failure ] + -- | Return the full path of the executable we're trying to call, -- or die trying findExecutableOrDie :: HasLogFunc env => String -> RIO env Text diff --git a/src/Spago/Purs.hs b/src/Spago/Purs.hs index 2dbe8a3b6..0d98ba9b5 100644 --- a/src/Spago/Purs.hs +++ b/src/Spago/Purs.hs @@ -19,12 +19,11 @@ import Spago.Env import qualified Data.ByteString.Lazy as BSL import qualified Data.Text as Text import qualified Data.Text.Encoding as Text.Encoding -import qualified Data.Text.Encoding.Error as Text.Encoding import qualified Data.Versions as Version import qualified Spago.Messages as Messages import qualified Turtle.Bytes - +import qualified Spago.Cmd as Cmd compile :: (HasPurs env, HasLogFunc env) @@ -130,19 +129,7 @@ docs format sourcePaths = do "Docs generation failed." pursVersion :: RIO env (Either Text Version.SemVer) -pursVersion = Turtle.Bytes.shellStrictWithErr (purs <> " --version") empty >>= \case - (ExitSuccess, out, _err) -> do - let versionText = headMay $ Text.split (== ' ') (Text.strip $ Text.Encoding.decodeUtf8With lenientDecode out) - parsed = versionText >>= (hush . Version.semver) - - pure $ case parsed of - Nothing -> Left $ Messages.failedToParseCommandOutput - (purs <> " --version") - (Text.Encoding.decodeUtf8With Text.Encoding.lenientDecode out) - Just p -> Right p - (_, _out, _err) -> pure $ Left $ "Failed to run '" <> purs <> " --version'" - where - purs = "purs" +pursVersion = Cmd.getCmdVersion "purs" hasMinPursVersion :: (HasLogFunc env, HasPurs env) => Text -> RIO env Bool hasMinPursVersion maybeMinVersion = do diff --git a/test/SpagoSpec.hs b/test/SpagoSpec.hs index 43fe17418..c5e5bb505 100644 --- a/test/SpagoSpec.hs +++ b/test/SpagoSpec.hs @@ -5,25 +5,53 @@ import qualified Data.Text as Text import Prelude hiding (FilePath) import qualified System.IO.Temp as Temp import Test.Hspec (Spec, around_, describe, it, shouldBe, shouldNotSatisfy, - shouldNotBe, shouldReturn, shouldSatisfy) + shouldNotBe, shouldReturn, shouldSatisfy, runIO) import Turtle (ExitCode (..), cd, cp, decodeString, empty, encodeString, mkdir, mktree, mv, pwd, readTextFile, rm, shell, - shellStrictWithErr, testdir, writeTextFile, ()) + shellStrictWithErr, testdir, writeTextFile, (), die, when) import Utils (checkFileHasInfix, checkFixture, checkFileExist, outputShouldEqual, readFixture, runFor, shouldBeFailure, shouldBeFailureInfix, shouldBeFailureStderr, shouldBeSuccess, shouldBeSuccessOutput, shouldBeSuccessOutputWithErr, shouldBeSuccessStderr, spago, - withCwd, withEnvVar) + withCwd, withEnvVar, dhall, cpFixture) +import qualified Spago.Cmd as Cmd +import qualified Data.Versions as Version +import System.Directory.Extra (getCurrentDirectory) -setup :: IO () -> IO () -setup cmd = do - Temp.withTempDirectory "test/" "spago-test" $ \temp -> do +setup :: String -> IO () -> IO () +setup dir cmd = do + Temp.withTempDirectory "test/" dir $ \temp -> do -- print ("Running in " <> temp) withCwd (decodeString temp) cmd +setup' :: String -> IO () -> IO () +setup' dir cmd = do + currentDir <- getCurrentDirectory + setup (currentDir <> "/" <> dir) cmd + +-- | This label is used to describe +-- tests that can be run on an +-- alpha release of PureScript @0.15.0@. +purs0_15_0TestMsg :: String +purs0_15_0TestMsg = "purs-0.15" + +fixPackagesDhall :: Bool -> IO () +fixPackagesDhall usingEsModules = when usingEsModules $ do + -- The prepare-0.15 package set's contents can change. + -- So, we copy an unfrozen one into the directory + -- and then freeze it before running `spago init`. + cpFixture "packages-prepare-0-15.dhall" "packages.dhall" + dhall ["freeze", "packages.dhall"] >>= shouldBeSuccess + +getUsingEsModules :: IO Bool +getUsingEsModules = do + pursVersion <- Cmd.getCmdVersion "purs" >>= either die pure + esmVersion <- either (const $ die "Failed to parse `0.15.0` static version") pure $ Version.semver "0.15.0-alpha-02" + pure $ pursVersion >= esmVersion + spec :: Spec -spec = around_ setup $ do +spec = runIO getUsingEsModules >>= \usingEsModules -> around_ (setup "spago-test") $ do describe "spago init" $ do @@ -580,22 +608,25 @@ spec = around_ setup $ do , "--else", "exit 1" ] >>= shouldBeFailure - describe "spago test" $ do + describe "spago test" $ describe purs0_15_0TestMsg $ around_ (setup' "spago test") $ do it "Spago should test successfully" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess spago ["--no-psa", "test"] >>= shouldBeSuccessOutputWithErr "test-output-stdout.txt" "test-output-stderr.txt" it "Spago should fail nicely when the test module is not found" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess mv "test" "test2" spago ["test"] >>= shouldBeFailureInfix "Module 'Test.Main' not found! Are you including it in your build?" it "Spago should test in custom output folder" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["test", "--purs-args", "-o", "--purs-args", "myOutput"] >>= shouldBeSuccess testdir "myOutput" `shouldReturn` True @@ -605,12 +636,14 @@ spec = around_ setup $ do -- Create root-level packages.dhall mkdir "monorepo" cd "monorepo" + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess rm "spago.dhall" -- Create local 'lib-a' package that uses packages.dhall on top level (but also has it's own one to confuse things) mkdir "lib-a" cd "lib-a" + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess rm "spago.dhall" writeTextFile "spago.dhall" $ "{ name = \"lib-1\", dependencies = [\"console\", \"effect\", \"prelude\"], packages = ./packages.dhall }" @@ -675,10 +708,11 @@ spec = around_ setup $ do packageSetUrl `shouldBe` originalPackageSetUrl - describe "spago run" $ do + describe "spago run" $ describe purs0_15_0TestMsg $ around_ (setup' "spago test") $ do it "Spago should run successfully" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess @@ -688,30 +722,34 @@ spec = around_ setup $ do it "Spago should be able to not use `psa`" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["--no-psa", "build"] >>= shouldBeSuccess spago ["-v", "--no-psa", "run"] >>= shouldBeSuccessOutput "run-output.txt" it "Spago should pass stdin to the child process" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - cp "../fixtures/spago-run-stdin.purs" "src/Main.purs" + cpFixture "spago-run-stdin.purs" "src/Main.purs" spago ["install", "node-buffer", "node-streams", "node-process"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess shellStrictWithErr "echo wut| spago run" empty >>= shouldBeSuccessOutput "spago-run-passthrough.txt" it "Spago should use exec-args" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - cp "../fixtures/spago-run-args.purs" "src/Main.purs" + cpFixture "spago-run-args.purs" "src/Main.purs" spago ["install", "node-process", "arrays"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess spago ["run", "--exec-args", "hello world"] >>= shouldBeSuccessOutput "run-args-output.txt" it "Spago should use node-args" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - cp "../fixtures/spago-run-args.purs" "src/Main.purs" + cpFixture "spago-run-args.purs" "src/Main.purs" spago ["install", "node-process", "arrays"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess spago ["run", "--node-args", "hello world"] >>= shouldBeSuccessOutput "run-args-output.txt" @@ -719,8 +757,9 @@ spec = around_ setup $ do it "Spago should prefer exec-args" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - cp "../fixtures/spago-run-args.purs" "src/Main.purs" + cpFixture "spago-run-args.purs" "src/Main.purs" spago ["install", "node-process", "arrays"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess spago ["run", "--exec-args", "hello world", "--node-args", "hallo welt"] >>= shouldBeSuccessOutput "run-args-combined-output.txt" @@ -741,20 +780,31 @@ spec = around_ setup $ do spago ["bundle", "--to", "bundle.js"] >>= shouldBeFailureStderr "bundle-stderr.txt" - describe "spago bundle-app" $ do + describe "spago bundle-app" $ describe purs0_15_0TestMsg $ do it "Spago should bundle successfully" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - spago ["bundle-app", "--to", "bundle-app.js"] >>= shouldBeSuccess - checkFixture "bundle-app.js" + if usingEsModules then do + spago [ "-V", "bundle-app", "--to", "bundle-app-esm.js"] >>= shouldBeSuccess + checkFixture "bundle-app-esm.js" + else do + spago ["bundle-app", "--to", "bundle-app.js"] >>= shouldBeSuccess + checkFixture "bundle-app.js" it "Spago should bundle successfully with source map" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess - spago ["bundle-app", "--to", "bundle-app-src-map.js", "--source-maps"] >>= shouldBeSuccess - checkFixture "bundle-app-src-map.js" - checkFileExist "bundle-app-src-map.js.map" + if usingEsModules then do + spago ["-V", "bundle-app", "--to", "bundle-app-src-map-esm.js", "--source-maps"] >>= shouldBeSuccess + checkFixture "bundle-app-src-map-esm.js" + checkFileExist "bundle-app-src-map-esm.js.map" + else do + spago ["bundle-app", "--to", "bundle-app-src-map.js", "--source-maps"] >>= shouldBeSuccess + checkFixture "bundle-app-src-map.js" + checkFileExist "bundle-app-src-map.js.map" describe "spago make-module" $ do @@ -763,26 +813,37 @@ spec = around_ setup $ do spago ["make-module", "--to", "make-module.js"] >>= shouldBeFailureStderr "make-module-stderr.txt" - describe "spago bundle-module" $ do + describe "spago bundle-module" $ describe purs0_15_0TestMsg $ do it "Spago should successfully make a module" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess -- Now we don't remove the output folder, but we pass the `--no-build` -- flag to skip rebuilding (i.e. we are counting on the previous command -- to have built stuff for us) - spago ["bundle-module", "--to", "bundle-module.js", "--no-build"] >>= shouldBeSuccess - checkFixture "bundle-module.js" + if usingEsModules then do + spago ["bundle-module", "--to", "bundle-module-esm.js", "--no-build"] >>= shouldBeSuccess + checkFixture "bundle-module-esm.js" + else do + spago ["bundle-module", "--to", "bundle-module.js", "--no-build"] >>= shouldBeSuccess + checkFixture "bundle-module.js" it "Spago should successfully make a module with source map" $ do + fixPackagesDhall usingEsModules spago ["init"] >>= shouldBeSuccess spago ["build"] >>= shouldBeSuccess - spago ["bundle-module", "--to", "bundle-module-src-map.js", "--no-build", "--source-maps"] >>= shouldBeSuccess - checkFixture "bundle-module-src-map.js" - checkFileExist "bundle-module-src-map.js.map" + if usingEsModules then do + spago ["bundle-module", "--to", "bundle-module-src-map-esm.js", "--no-build", "--source-maps"] >>= shouldBeSuccess + checkFixture "bundle-module-src-map-esm.js" + checkFileExist "bundle-module-src-map-esm.js.map" + else do + spago ["bundle-module", "--to", "bundle-module-src-map.js", "--no-build", "--source-maps"] >>= shouldBeSuccess + checkFixture "bundle-module-src-map.js" + checkFileExist "bundle-module-src-map.js.map" describe "spago ls packages" $ do diff --git a/test/Utils.hs b/test/Utils.hs index 6dba28a12..4cf86cde5 100644 --- a/test/Utils.hs +++ b/test/Utils.hs @@ -2,7 +2,9 @@ module Utils ( checkFixture , checkFileHasInfix , checkFileExist + , getFixturesDir , readFixture + , cpFixture , getHighestTag , git , outputShouldEqual @@ -19,9 +21,9 @@ module Utils , shouldBeFailureStderr , shouldBeEmptySuccess , spago + , dhall , withCwd - , withEnvVar - ) where + , withEnvVar) where import qualified Control.Concurrent as Concurrent import qualified Control.Exception as Exception @@ -34,7 +36,7 @@ import System.Directory (removePathForcibly, doesFileExist) import qualified System.Process as Process import Test.Hspec (HasCallStack, shouldBe, shouldSatisfy) import Turtle (ExitCode (..), FilePath, Text, cd, empty, encodeString, export, - inproc, limit, need, pwd, readTextFile, strict) + inproc, limit, need, pwd, readTextFile, strict, testdir, (), parent, cp) import qualified Turtle.Bytes @@ -59,6 +61,9 @@ proc cmd args = do (c, out, err) <- Turtle.Bytes.procStrictWithErr cmd args empty pure (c, b2t out, b2t err) +dhall :: [Text] -> IO (ExitCode, Text, Text) +dhall = proc "dhall" + spago :: [Text] -> IO (ExitCode, Text, Text) spago = proc "spago" @@ -132,9 +137,24 @@ shouldBeFailureInfix :: HasCallStack => Text -> (ExitCode, Text, Text) -> IO () shouldBeFailureInfix expected result = do result `shouldSatisfy` (\(code, _stdout, stderr) -> code == ExitFailure 1 && Text.isInfixOf expected stderr) +getFixturesDir :: IO FilePath +getFixturesDir = pwd >>= go + where + fixturesDirName = "fixtures" + go accumPath = do + let fixturesDir = accumPath fixturesDirName + hasFixturesDir <- testdir fixturesDir + if hasFixturesDir + then pure fixturesDir + else go (parent accumPath) + readFixture :: FilePath -> IO Text -readFixture path = - readTextFile $ "../fixtures/" <> path +readFixture filePath = getFixturesDir >>= \fixturesDir -> readTextFile $ fixturesDir filePath + +cpFixture :: FilePath -> FilePath -> IO () +cpFixture fixture path = do + fixturesDir <- getFixturesDir + cp (fixturesDir fixture) path checkFixture :: HasCallStack => FilePath -> IO () checkFixture path = do diff --git a/test/fixtures/bundle-app-esm.js b/test/fixtures/bundle-app-esm.js new file mode 100644 index 000000000..0c581ab56 --- /dev/null +++ b/test/fixtures/bundle-app-esm.js @@ -0,0 +1,12 @@ +// output/Effect.Console/foreign.js +var log = function(s) { + return function() { + console.log(s); + }; +}; + +// output/Main/index.js +var main = /* @__PURE__ */ log("\u{1F35D}"); + +// +main(); diff --git a/test/fixtures/bundle-app-src-map-esm.js b/test/fixtures/bundle-app-src-map-esm.js new file mode 100644 index 000000000..0c26d4716 --- /dev/null +++ b/test/fixtures/bundle-app-src-map-esm.js @@ -0,0 +1,13 @@ +// output/Effect.Console/foreign.js +var log = function(s) { + return function() { + console.log(s); + }; +}; + +// output/Main/index.js +var main = /* @__PURE__ */ log("\u{1F35D}"); + +// +main(); +//# sourceMappingURL=bundle-app-src-map-esm.js.map diff --git a/test/fixtures/bundle-module-esm.js b/test/fixtures/bundle-module-esm.js new file mode 100644 index 000000000..3319b6f83 --- /dev/null +++ b/test/fixtures/bundle-module-esm.js @@ -0,0 +1,12 @@ +// output/Effect.Console/foreign.js +var log = function(s) { + return function() { + console.log(s); + }; +}; + +// output/Main/index.js +var main = /* @__PURE__ */ log("\u{1F35D}"); +export { + main +}; diff --git a/test/fixtures/bundle-module-src-map-esm.js b/test/fixtures/bundle-module-src-map-esm.js new file mode 100644 index 000000000..cca2194c7 --- /dev/null +++ b/test/fixtures/bundle-module-src-map-esm.js @@ -0,0 +1,13 @@ +// output/Effect.Console/foreign.js +var log = function(s) { + return function() { + console.log(s); + }; +}; + +// output/Main/index.js +var main = /* @__PURE__ */ log("\u{1F35D}"); +export { + main +}; +//# sourceMappingURL=bundle-module-src-map-esm.js.map diff --git a/test/fixtures/packages-prepare-0-15.dhall b/test/fixtures/packages-prepare-0-15.dhall new file mode 100644 index 000000000..aa940d7fe --- /dev/null +++ b/test/fixtures/packages-prepare-0-15.dhall @@ -0,0 +1,4 @@ +let upstream = + https://github.com/JordanMartinez/package-sets/releases/download/psc-0.15.0-20220329/packages.dhall + +in upstream \ No newline at end of file diff --git a/test/fixtures/spago-run-args.purs b/test/fixtures/spago-run-args.purs index aaa57155b..447a70bc6 100644 --- a/test/fixtures/spago-run-args.purs +++ b/test/fixtures/spago-run-args.purs @@ -10,5 +10,5 @@ import Data.Show (show) main :: Effect Unit main = do args <- argv - -- dropping the first arg, node path to make test stable - log $ show $ drop 1 args + -- dropping the first two args, node path and script name, to make test stable + log $ show $ drop 2 args