mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-11-23 19:29:17 +03:00
Merge commit resolutions I ommited commiting by accident.
This commit is contained in:
parent
8b6fdc7b6e
commit
6d4a39a976
@ -45,6 +45,10 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
||||
args <- getArgs
|
||||
let commandCall = case args of
|
||||
("new" : newArgs) -> Command.Call.New newArgs
|
||||
-- new-ai-machine is meant to be called and consumed programatically (e.g. by our Wasp AI
|
||||
-- web app).
|
||||
["new-ai-machine", projectName, appDescription] ->
|
||||
Command.Call.NewAiForMachine projectName appDescription
|
||||
["start"] -> Command.Call.Start
|
||||
["start", "db"] -> Command.Call.StartDb
|
||||
["clean"] -> Command.Call.Clean
|
||||
@ -79,6 +83,7 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
||||
|
||||
case commandCall of
|
||||
Command.Call.New newArgs -> runCommand $ createNewProject newArgs
|
||||
Command.Call.NewAiForMachine projectName appDescription -> runCommand $ Command.CreateNewProject.AI.createNewProjectForMachine projectName appDescription
|
||||
Command.Call.Start -> runCommand start
|
||||
Command.Call.StartDb -> runCommand Command.Start.Db.start
|
||||
Command.Call.Clean -> runCommand clean
|
||||
|
@ -2,6 +2,7 @@ module Wasp.Cli.Command.Call where
|
||||
|
||||
data Call
|
||||
= New Arguments
|
||||
| NewAiForMachine String String -- projectName, appDescription
|
||||
| Start
|
||||
| StartDb
|
||||
| Clean
|
||||
|
@ -1,39 +1,15 @@
|
||||
module Wasp.Cli.Command.CreateNewProject
|
||||
( createNewProject,
|
||||
-- TODO: I just exported whatever I needed, I should think more through how to abstract this really.
|
||||
createInitialWaspProjectDir,
|
||||
parseProjectInfo,
|
||||
ProjectInfo (..),
|
||||
getAbsoluteWaspProjectDir,
|
||||
readCoreWaspProjectFiles,
|
||||
createEmptyWaspProjectDir,
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad (when)
|
||||
import Control.Monad.Except (throwError)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Data.List (intercalate)
|
||||
import Data.Text (Text)
|
||||
import Path.IO (copyDirRecur, doesDirExist)
|
||||
import StrongPath (Abs, Dir, File', Path, Path', Rel, System, fromAbsDir, parseAbsDir, reldir, relfile, (</>))
|
||||
import StrongPath.Path (toPathAbsDir)
|
||||
import System.Directory (createDirectory, getCurrentDirectory)
|
||||
import qualified System.FilePath as FP
|
||||
import Text.Printf (printf)
|
||||
import Wasp.Analyzer.Parser (isValidWaspIdentifier)
|
||||
import Wasp.Cli.Command (Command, CommandError (..))
|
||||
import qualified Wasp.Data as Data
|
||||
import Wasp.Project (WaspProjectDir)
|
||||
import Wasp.Util (indent, kebabToCamelCase)
|
||||
import Wasp.Util.IO (readFileStrict)
|
||||
import qualified Wasp.Util.IO as IOUtil
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Data.Function ((&))
|
||||
import StrongPath (Abs, Dir, Path')
|
||||
import qualified StrongPath as SP
|
||||
import Wasp.Cli.Command (Command)
|
||||
import Wasp.Cli.Command.Call (Arguments)
|
||||
import Wasp.Cli.Command.CreateNewProject.AI (createNewProjectForHuman)
|
||||
import Wasp.Cli.Command.CreateNewProject.ArgumentsParser (parseNewProjectArgs)
|
||||
import Wasp.Cli.Command.CreateNewProject.Common (throwProjectCreationError)
|
||||
import Wasp.Cli.Command.CreateNewProject.ProjectDescription
|
||||
@ -51,12 +27,7 @@ import Wasp.Cli.Common (WaspProjectDir)
|
||||
import qualified Wasp.Message as Msg
|
||||
import qualified Wasp.Util.Terminal as Term
|
||||
|
||||
-- TODO(merge): what about new ai?
|
||||
-- One for humans we could offer as an option during interactive choosing of template.
|
||||
-- One for machine should have its own command. Probably `new:ai` would be fine.
|
||||
-- I have to figure out how to fit all this in with the new changes.
|
||||
|
||||
-- It receives all of the arguments that were passed to the `wasp new` command.
|
||||
-- | It receives all of the arguments that were passed to the `wasp new` command.
|
||||
createNewProject :: Arguments -> Command ()
|
||||
createNewProject args = do
|
||||
newProjectArgs <- parseNewProjectArgs args & either throwProjectCreationError return
|
||||
@ -80,52 +51,6 @@ createNewProject args = do
|
||||
putStrLn $ Term.applyStyles [Term.Bold] " wasp start"
|
||||
{- ORMOLU_ENABLE -}
|
||||
|
||||
-- TODO(merge): I think I need this one, do I?
|
||||
-- | Given project info, creates a new empty wasp app directory with appropriate name and no content
|
||||
-- in it. Throws if such directory already exists. Returns path to the newly created directory.
|
||||
createEmptyWaspProjectDir :: ProjectInfo -> Command (Path System Abs (Dir WaspProjectDir))
|
||||
createEmptyWaspProjectDir projectInfo = do
|
||||
waspProjectDir <- determineWaspProjectDirAndThrowIfTaken projectInfo
|
||||
liftIO $ createDirectory $ fromAbsDir waspProjectDir
|
||||
return waspProjectDir
|
||||
|
||||
-- TODO(merge): seems like I need this one for the function above, but check if there
|
||||
-- is some newer logic that does this.
|
||||
determineWaspProjectDirAndThrowIfTaken :: ProjectInfo -> Command (Path System Abs (Dir WaspProjectDir))
|
||||
determineWaspProjectDirAndThrowIfTaken projectInfo = do
|
||||
absWaspProjectDir <- getAbsoluteWaspProjectDir projectInfo
|
||||
dirExists <- doesDirExist $ toPathAbsDir absWaspProjectDir
|
||||
when dirExists $
|
||||
throwProjectCreationError $ show absWaspProjectDir ++ " is an existing directory"
|
||||
return absWaspProjectDir
|
||||
|
||||
-- TODO(merge): This is now repeating what is in templates/new which is not great.
|
||||
coreWaspProjectFiles :: [Path System (Rel WaspProjectDir) File']
|
||||
coreWaspProjectFiles =
|
||||
[ [relfile|.gitignore|],
|
||||
[relfile|.wasproot|],
|
||||
[relfile|src/.waspignore|],
|
||||
[relfile|src/client/tsconfig.json|],
|
||||
[relfile|src/client/vite-env.d.ts|],
|
||||
[relfile|src/server/tsconfig.json|],
|
||||
[relfile|src/shared/tsconfig.json|]
|
||||
]
|
||||
|
||||
-- TODO(merge): Reorganize Cli/templates/new(or basic) into two dirs:
|
||||
-- 1. templates/core
|
||||
-- 2. templates/basic
|
||||
-- Core would contain only the most neccessary files to get started.
|
||||
-- Other templates, like basic, would build on top of it.
|
||||
-- So creating new wasp project from local template would first copy files from "core",
|
||||
-- then from the actual template (e.g. "basic").
|
||||
readCoreWaspProjectFiles :: IO [(Path System (Rel WaspProjectDir) File', Text)]
|
||||
readCoreWaspProjectFiles = do
|
||||
dataDir <- Data.getAbsDataDirPath
|
||||
let templatesNewDir = dataDir </> [reldir|Cli/templates/new|]
|
||||
contents <- mapM (readFileStrict . (templatesNewDir </>)) coreWaspProjectFiles
|
||||
return $ zip coreWaspProjectFiles contents
|
||||
|
||||
=======
|
||||
createProjectOnDisk :: NewProjectDescription -> Command ()
|
||||
createProjectOnDisk
|
||||
NewProjectDescription
|
||||
@ -140,4 +65,5 @@ createProjectOnDisk
|
||||
createProjectOnDiskFromRemoteTemplate absWaspProjectDir projectName appName remoteTemplateName
|
||||
LocalStarterTemplate localTemplateName ->
|
||||
liftIO $ createProjectOnDiskFromLocalTemplate absWaspProjectDir projectName appName localTemplateName
|
||||
>>>>>>> main
|
||||
AiGeneratedStarterTemplate ->
|
||||
createNewProjectForHuman absWaspProjectDir appName
|
||||
|
@ -1,6 +1,3 @@
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
module Wasp.Cli.Command.CreateNewProject.AI
|
||||
( createNewProjectForHuman,
|
||||
createNewProjectForMachine,
|
||||
@ -11,9 +8,9 @@ import Control.Arrow ()
|
||||
import Control.Monad.Except (MonadError (throwError), MonadIO (liftIO))
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T.IO
|
||||
import StrongPath (fromAbsDir)
|
||||
import StrongPath (Abs, Dir, Path', fromAbsDir)
|
||||
import StrongPath.Operations ()
|
||||
import System.Directory (createDirectoryIfMissing, setCurrentDirectory)
|
||||
import System.Directory (createDirectory, createDirectoryIfMissing, setCurrentDirectory)
|
||||
import System.Environment (lookupEnv)
|
||||
import System.FilePath (takeDirectory)
|
||||
import System.IO (hFlush, stdout)
|
||||
@ -22,25 +19,20 @@ import qualified Wasp.AI.GenerateNewProject as GNP
|
||||
import Wasp.AI.GenerateNewProject.Common (AuthProvider (..), NewProjectDetails (..))
|
||||
import Wasp.AI.OpenAI (OpenAIApiKey)
|
||||
import Wasp.Cli.Command (Command, CommandError (CommandError))
|
||||
import Wasp.Cli.Command.CreateNewProject (readCoreWaspProjectFiles)
|
||||
import qualified Wasp.Cli.Command.CreateNewProject as CNP
|
||||
import Wasp.Cli.Command.CreateNewProject.ProjectDescription (NewProjectAppName (..), parseWaspProjectNameIntoAppName)
|
||||
import Wasp.Cli.Command.CreateNewProject.StarterTemplates (readCoreWaspProjectFiles)
|
||||
import Wasp.Cli.Common (WaspProjectDir)
|
||||
import qualified Wasp.Cli.Interactive as Interactive
|
||||
|
||||
createNewProjectForHuman :: Command ()
|
||||
createNewProjectForHuman = do
|
||||
createNewProjectForHuman :: Path' Abs (Dir WaspProjectDir) -> NewProjectAppName -> Command ()
|
||||
createNewProjectForHuman waspProjectDir appName = do
|
||||
openAIApiKey <- getOpenAIApiKey
|
||||
|
||||
-- TODO: Use new fancy logic we have for interactive stuff like this! We need to merge with main though first.
|
||||
(webAppName, webAppDescription) <- liftIO $ do
|
||||
putStrLn "App name (e.g. MyFirstApp):"
|
||||
appName <- getLine
|
||||
putStrLn "Describe your app in a couple of sentences:"
|
||||
desc <- getLine
|
||||
return (appName, desc)
|
||||
appDescription <- liftIO $ Interactive.askForRequiredInput "Describe your app in a couple of sentences:\n"
|
||||
|
||||
projectInfo <- CNP.parseProjectInfo webAppName
|
||||
|
||||
absWaspProjectDir <- CNP.createEmptyWaspProjectDir projectInfo
|
||||
liftIO $ setCurrentDirectory $ fromAbsDir absWaspProjectDir
|
||||
liftIO $ do
|
||||
createDirectory $ fromAbsDir waspProjectDir
|
||||
setCurrentDirectory $ fromAbsDir waspProjectDir
|
||||
|
||||
let codeAgentConfig =
|
||||
CA.CodeAgentConfig
|
||||
@ -49,7 +41,7 @@ createNewProjectForHuman = do
|
||||
CA._writeLog = forwardLogToStdout
|
||||
}
|
||||
|
||||
liftIO $ generateNewProject codeAgentConfig webAppName webAppDescription
|
||||
liftIO $ generateNewProject codeAgentConfig appName appDescription
|
||||
where
|
||||
writeFileToDisk path content = do
|
||||
createDirectoryIfMissing True (takeDirectory path)
|
||||
@ -62,10 +54,12 @@ createNewProjectForHuman = do
|
||||
hFlush stdout
|
||||
|
||||
createNewProjectForMachine :: String -> String -> Command ()
|
||||
createNewProjectForMachine webAppName webAppDescription = do
|
||||
createNewProjectForMachine projectName appDescription = do
|
||||
openAIApiKey <- getOpenAIApiKey
|
||||
|
||||
_projectInfo <- CNP.parseProjectInfo webAppName
|
||||
appName <- case parseWaspProjectNameIntoAppName projectName of
|
||||
Right appName -> pure appName
|
||||
Left err -> throwError $ CommandError "Invalid project name" err
|
||||
|
||||
let codeAgentConfig =
|
||||
CA.CodeAgentConfig
|
||||
@ -74,7 +68,7 @@ createNewProjectForMachine webAppName webAppDescription = do
|
||||
CA._writeLog = writeLogToStdoutWithDelimiters
|
||||
}
|
||||
|
||||
liftIO $ generateNewProject codeAgentConfig webAppName webAppDescription
|
||||
liftIO $ generateNewProject codeAgentConfig appName appDescription
|
||||
where
|
||||
writeFileToStdoutWithDelimiters path content =
|
||||
writeToStdoutWithDelimiters "WRITE FILE" [T.pack path, content]
|
||||
@ -94,11 +88,11 @@ createNewProjectForMachine webAppName webAppDescription = do
|
||||
"===/ WASP AI: " <> title <> " ===="
|
||||
]
|
||||
|
||||
generateNewProject :: CA.CodeAgentConfig -> String -> String -> IO ()
|
||||
generateNewProject codeAgentConfig webAppName webAppDescription = do
|
||||
generateNewProject :: CA.CodeAgentConfig -> NewProjectAppName -> String -> IO ()
|
||||
generateNewProject codeAgentConfig (NewProjectAppName appName) appDescription = do
|
||||
coreWaspProjectFiles <- readCoreWaspProjectFiles
|
||||
CA.runCodeAgent codeAgentConfig $
|
||||
GNP.generateNewProject (newProjectDetails webAppName webAppDescription) coreWaspProjectFiles
|
||||
GNP.generateNewProject (newProjectDetails appName appDescription) coreWaspProjectFiles
|
||||
|
||||
getOpenAIApiKey :: Command OpenAIApiKey
|
||||
getOpenAIApiKey =
|
||||
|
@ -3,6 +3,7 @@ module Wasp.Cli.Command.CreateNewProject.ProjectDescription
|
||||
NewProjectDescription (..),
|
||||
NewProjectName (..),
|
||||
NewProjectAppName (..),
|
||||
parseWaspProjectNameIntoAppName,
|
||||
)
|
||||
where
|
||||
|
||||
@ -122,23 +123,25 @@ obtainAvailableProjectDirPath projectName = do
|
||||
"Directory \"" ++ projectDirName ++ "\" is not empty."
|
||||
|
||||
mkNewProjectDescription :: String -> Path' Abs (Dir WaspProjectDir) -> StarterTemplateName -> Command NewProjectDescription
|
||||
mkNewProjectDescription projectName absWaspProjectDir templateName
|
||||
| isValidWaspIdentifier appName =
|
||||
return $
|
||||
NewProjectDescription
|
||||
{ _projectName = NewProjectName projectName,
|
||||
_appName = NewProjectAppName appName,
|
||||
_templateName = templateName,
|
||||
_absWaspProjectDir = absWaspProjectDir
|
||||
}
|
||||
mkNewProjectDescription projectName absWaspProjectDir templateName = do
|
||||
appName <- either throwProjectCreationError pure $ parseWaspProjectNameIntoAppName projectName
|
||||
return $
|
||||
NewProjectDescription
|
||||
{ _projectName = NewProjectName projectName,
|
||||
_appName = appName,
|
||||
_templateName = templateName,
|
||||
_absWaspProjectDir = absWaspProjectDir
|
||||
}
|
||||
|
||||
parseWaspProjectNameIntoAppName :: String -> Either String NewProjectAppName
|
||||
parseWaspProjectNameIntoAppName projectName
|
||||
| isValidWaspIdentifier appName = Right $ NewProjectAppName appName
|
||||
| otherwise =
|
||||
throwProjectCreationError $
|
||||
intercalate
|
||||
"\n"
|
||||
[ "The project's name is not in the valid format!",
|
||||
indent 2 "- It can start with a letter or an underscore.",
|
||||
indent 2 "- It can contain only letters, numbers, dashes, or underscores.",
|
||||
indent 2 "- It can't be a Wasp keyword."
|
||||
]
|
||||
Left . intercalate "\n" $
|
||||
[ "The project's name is not in the valid format!",
|
||||
indent 2 "- It can start with a letter or an underscore.",
|
||||
indent 2 "- It can contain only letters, numbers, dashes, or underscores.",
|
||||
indent 2 "- It can't be a Wasp keyword."
|
||||
]
|
||||
where
|
||||
appName = kebabToCamelCase projectName
|
||||
|
@ -3,25 +3,36 @@ module Wasp.Cli.Command.CreateNewProject.StarterTemplates
|
||||
StarterTemplateName (..),
|
||||
findTemplateNameByString,
|
||||
defaultStarterTemplateName,
|
||||
coreWaspProjectFiles,
|
||||
readCoreWaspProjectFiles,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Either (fromRight)
|
||||
import Data.Foldable (find)
|
||||
import Data.Text (Text)
|
||||
import StrongPath (File', Path, Rel, System, reldir, relfile, (</>))
|
||||
import Wasp.Cli.Command.CreateNewProject.StarterTemplates.Remote.Github (starterTemplateGithubRepo)
|
||||
import Wasp.Cli.Common (WaspProjectDir)
|
||||
import qualified Wasp.Cli.GithubRepo as GR
|
||||
import qualified Wasp.Data as Data
|
||||
import Wasp.Util.IO (readFileStrict)
|
||||
|
||||
data StarterTemplateName = RemoteStarterTemplate String | LocalStarterTemplate String
|
||||
data StarterTemplateName
|
||||
= RemoteStarterTemplate String
|
||||
| LocalStarterTemplate String
|
||||
| AiGeneratedStarterTemplate
|
||||
deriving (Eq)
|
||||
|
||||
instance Show StarterTemplateName where
|
||||
show (RemoteStarterTemplate templateName) = templateName
|
||||
show (LocalStarterTemplate templateName) = templateName
|
||||
show AiGeneratedStarterTemplate = "ai-generated (experimental)"
|
||||
|
||||
getStarterTemplateNames :: IO [StarterTemplateName]
|
||||
getStarterTemplateNames = do
|
||||
remoteTemplates <- fromRight [] <$> fetchRemoteStarterTemplateNames
|
||||
return $ localTemplates ++ remoteTemplates
|
||||
return $ localTemplates ++ remoteTemplates ++ [AiGeneratedStarterTemplate]
|
||||
|
||||
fetchRemoteStarterTemplateNames :: IO (Either String [StarterTemplateName])
|
||||
fetchRemoteStarterTemplateNames = do
|
||||
@ -39,3 +50,30 @@ defaultStarterTemplateName = LocalStarterTemplate "basic"
|
||||
|
||||
findTemplateNameByString :: [StarterTemplateName] -> String -> Maybe StarterTemplateName
|
||||
findTemplateNameByString templateNames query = find ((== query) . show) templateNames
|
||||
|
||||
-- TODO: This is now repeating what is in templates/basic which is not great.
|
||||
-- TODO: Reorganize Cli/templates/basic into two dirs:
|
||||
-- 1. templates/core
|
||||
-- 2. templates/basic
|
||||
-- Core would contain only the most neccessary files to get started.
|
||||
-- Other templates, like basic, would build on top of it.
|
||||
-- So creating new wasp project from local template would first copy files from "core",
|
||||
-- then from the actual template (e.g. "basic").
|
||||
-- Then I wouldn't need this list here, I would just list all the files from Cli/templates/core.
|
||||
coreWaspProjectFiles :: [Path System (Rel WaspProjectDir) File']
|
||||
coreWaspProjectFiles =
|
||||
[ [relfile|.gitignore|],
|
||||
[relfile|.wasproot|],
|
||||
[relfile|src/.waspignore|],
|
||||
[relfile|src/client/tsconfig.json|],
|
||||
[relfile|src/client/vite-env.d.ts|],
|
||||
[relfile|src/server/tsconfig.json|],
|
||||
[relfile|src/shared/tsconfig.json|]
|
||||
]
|
||||
|
||||
readCoreWaspProjectFiles :: IO [(Path System (Rel WaspProjectDir) File', Text)]
|
||||
readCoreWaspProjectFiles = do
|
||||
dataDir <- Data.getAbsDataDirPath
|
||||
let templatesNewDir = dataDir </> [reldir|Cli/templates/basic|]
|
||||
contents <- mapM (readFileStrict . (templatesNewDir </>)) coreWaspProjectFiles
|
||||
return $ zip coreWaspProjectFiles contents
|
||||
|
@ -75,7 +75,7 @@ generateBaseWaspFile newProjectDetails = ((path, content), planRules)
|
||||
wasp: {
|
||||
version: "^${waspVersion}"
|
||||
},
|
||||
title: ${appTitle},
|
||||
title: "${appTitle}",
|
||||
${appAuth}
|
||||
}
|
||||
|
||||
|
@ -221,8 +221,7 @@ bytestringToHex :: B.ByteString -> Hex
|
||||
bytestringToHex = Hex . concatMap (printf "%02x") . B.unpack
|
||||
|
||||
hexFromString :: String -> Hex
|
||||
|
||||
hexFromString
|
||||
hexFromString = Hex
|
||||
|
||||
hexToString :: Hex -> String
|
||||
hexToString (Hex s) = s
|
||||
|
Loading…
Reference in New Issue
Block a user