1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-17 11:51:42 +03:00
juvix/app/Commands/Init.hs
Paul Cadman 46ab163ca7
Update stackage resolver to LTS 21.6 (#2275)
Stack LTS 21.6 uses GHC 9.4.5, binaries for HLS are available via ghcup.

Changes required:

1. Fix warnings about type level `:` and `[]` used without backticks.
2. Fix warnings about deprecation of builtin `~` - replaced with `import
Data.Type.Equality ( type (~) )` in the Prelude
3. SemVer is no longer a monoid
4. `path-io` now contains the `AnyPath` instances we were defining
(thanks to Jan) so they can be removed.
5. Added `aeson-better-errors-0.9.1.1` as an extra-dep. The reason it is
not part of the resolver is only because it has a strict bound on base
which is not compatible with ghc 9.4.5. To work around this I've set:

    ```
    allow-newer: true
    allow-newer-deps:
      - aeson-better-errors
    ```
which relaxed the upper constraint bounds for `aeson-better-errors`
only. When the base constraints have been updated we can remove this
workaround.

6. Use stack2cabal to generate the cabal.project file and to freeze
dependency versions.

    https://www.stackage.org/lts-21.6/cabal.config now contains the
constraint `haskeline installed`, which means that the version of
haskeline that is globally installed with GHC 9.4.5 will be used, see:
    * https://github.com/commercialhaskell/stackage/issues/7002
GHC 9.4.5 comes with haskeline 0.8.2 preinstalled but our configuration
contains the source-repository-package for haskeline 0.8.2.1 (required
because we're using a fork) so if you try to run` cabal build` you get a
conflict.

Constraints from cabal imports cannot yet be overridden so it's not
possible to get rid of this conflict using the import method. So we need
to use stack2cabal with an explicit freeze file instead.

7. Remove `runTempFilePure` as this is unused and depends on
`Polysemy.Fresh` in `polysemy-zoo` which is not available in the
resolver. It turns out that it's not possible to use the `Fresh` effect
in a pure context anyway, so it was not possible to use
`runTempFilePure` for its original purpose.

8. We now use https://github.com/benz0li/ghc-musl as the base container
for static linux builds, this means we don't need to maintain our own
Docker container for this purpose.

9. The PR for the nightly builds is ready
https://github.com/anoma/juvix-nightly-builds/pull/2, it should be
merged as soon as this PR is merged.

Thanks to @benz0li for maintaining https://github.com/benz0li/ghc-musl
and (along with @TravisCardwell) for help with building the static
binary.

* Closes https://github.com/anoma/juvix/issues/2166
2023-08-11 11:49:33 +02:00

138 lines
4.0 KiB
Haskell

module Commands.Init where
import Data.Text qualified as Text
import Data.Versions
import Data.Yaml (encodeFile)
import Juvix.Compiler.Pipeline.Package
import Juvix.Data.Effect.Fail.Extra qualified as Fail
import Juvix.Extra.Paths
import Juvix.Prelude
import Juvix.Prelude.Pretty
import Text.Megaparsec (Parsec)
import Text.Megaparsec qualified as P
import Text.Megaparsec.Char qualified as P
type Err = Text
parse :: Parsec Void Text a -> Text -> Either Err a
parse p t = mapLeft ppErr (P.runParser p "<stdin>" t)
ppErr :: P.ParseErrorBundle Text Void -> Text
ppErr = pack . errorBundlePretty
init :: forall r. (Members '[Embed IO] r) => Sem r ()
init = do
checkNotInProject
say "✨ Your next Juvix adventure is about to begin! ✨"
say "I will help you set it up"
pkg <- getPackage
say ("creating " <> pack (toFilePath juvixYamlFile))
embed (encodeFile (toFilePath juvixYamlFile) (rawPackage pkg))
say "you are all set"
checkNotInProject :: forall r. (Members '[Embed IO] r) => Sem r ()
checkNotInProject =
whenM (doesFileExist juvixYamlFile) err
where
err :: Sem r ()
err = do
say "You are already in a Juvix project"
embed exitFailure
getPackage :: forall r. Members '[Embed IO] r => Sem r Package
getPackage = do
tproj <- getProjName
say "Write the version of your project [leave empty for 0.0.0]"
tversion :: SemVer <- getVersion
return
Package
{ _packageName = tproj,
_packageVersion = tversion,
_packageBuildDir = Nothing,
_packageMain = Nothing,
_packageDependencies = [defaultStdlibDep DefaultBuildDir]
}
getProjName :: forall r. (Members '[Embed IO] r) => Sem r Text
getProjName = do
d <- getDefault
let defMsg :: Text
defMsg = case d of
Nothing -> mempty
Just d' -> " [leave empty for '" <> d' <> "']"
say
( "Write the name of your project"
<> defMsg
<> " (lower case letters, numbers and dashes are allowed): "
)
readName d
where
getDefault :: Sem r (Maybe Text)
getDefault = runFail $ do
dir <- map toLower . dropTrailingPathSeparator . toFilePath . dirname <$> getCurrentDir
Fail.fromRight (parse projectNameParser (pack dir))
readName :: Maybe Text -> Sem r Text
readName def = go
where
go :: Sem r Text
go = do
txt <- embed getLine
if
| Text.null txt, Just def' <- def -> return def'
| otherwise ->
case parse projectNameParser txt of
Right p
| Text.length p <= projextNameMaxLength -> return p
| otherwise -> do
say ("The project name cannot exceed " <> prettyText projextNameMaxLength <> " characters")
retry
Left err -> do
say err
retry
where
retry :: Sem r Text
retry = do
tryAgain
go
say :: (Members '[Embed IO] r) => Text -> Sem r ()
say = embed . putStrLn
tryAgain :: (Members '[Embed IO] r) => Sem r ()
tryAgain = say "Please, try again:"
getVersion :: forall r. (Members '[Embed IO] r) => Sem r SemVer
getVersion = do
txt <- embed getLine
if
| Text.null txt -> return defaultVersion
| otherwise -> case parse semver' txt of
Right r -> return r
Left err -> do
say err
say "The version must follow the 'Semantic Versioning 2.0.0' specification"
retry
where
retry :: Sem r SemVer
retry = do
tryAgain
getVersion
projextNameMaxLength :: Int
projextNameMaxLength = 100
projectNameParser :: Parsec Void Text Text
projectNameParser = do
h <- P.satisfy validFirstChar
t <- P.takeWhileP (Just "project name character") validChar
P.hspace
P.eof
return (Text.cons h t)
where
validFirstChar :: Char -> Bool
validFirstChar c =
isAscii c
&& (isLower c || isNumber c)
validChar :: Char -> Bool
validChar c = c == '-' || validFirstChar c