make argument to project.create optional

This commit is contained in:
Mitchell Rosen 2023-06-16 10:41:04 -04:00
parent f45d31b34d
commit 00e2039a99
8 changed files with 94 additions and 40 deletions

View File

@ -57,6 +57,7 @@ dependencies:
- pretty-simple
- process
- random >= 1.2.0
- random-shuffle
- recover-rtti
- regex-tdfa
- semialign

View File

@ -1637,7 +1637,6 @@ inputDescription input =
branchId2 <- hp' (input ^. #branchId2)
patch <- ps' (input ^. #patch)
pure (Text.unwords ["diff.namespace.to-patch", branchId1, branchId2, patch])
ProjectCreateI project -> pure ("project.create " <> into @Text project)
ClearI {} -> pure "clear"
DocToMarkdownI name -> pure ("debug.doc-to-markdown " <> Name.toText name)
--
@ -1678,6 +1677,7 @@ inputDescription input =
PreviewAddI {} -> wat
PreviewMergeLocalBranchI {} -> wat
PreviewUpdateI {} -> wat
ProjectCreateI {} -> wat
ProjectRenameI {} -> wat
ProjectSwitchI {} -> wat
ProjectsI -> wat

View File

@ -4,7 +4,9 @@ module Unison.Codebase.Editor.HandleInput.ProjectCreate
)
where
import Data.Text qualified as Text
import Data.UUID.V4 qualified as UUID
import System.Random.Shuffle qualified as RandomShuffle
import U.Codebase.Sqlite.DbId
import U.Codebase.Sqlite.ProjectBranch qualified as Sqlite
import U.Codebase.Sqlite.Queries qualified as Queries
@ -12,12 +14,12 @@ import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.MonadUtils qualified as Cli (stepAt)
import Unison.Cli.ProjectUtils (projectBranchPath)
import Unison.Codebase.Branch (Branch0)
import Unison.Codebase.Branch qualified as Branch
import Unison.Codebase.Editor.Output qualified as Output
import Unison.Codebase.Path qualified as Path
import Unison.Prelude
import Unison.Project (ProjectAndBranch (..), ProjectName)
import Unison.Project (ProjectAndBranch (..), ProjectBranchName, ProjectName)
import Unison.Sqlite qualified as Sqlite
import Witch (unsafeFrom)
-- | Create a new project.
@ -46,35 +48,76 @@ import Witch (unsafeFrom)
--
-- For now, it doesn't seem worth it to do (1) or (2), since we want to do (3) eventually, and we'd rather not waste too
-- much time getting everything perfectly correct before we get there.
projectCreate :: ProjectName -> Cli ()
projectCreate projectName = do
projectCreate :: Maybe ProjectName -> Cli ()
projectCreate maybeProjectName = do
projectId <- liftIO (ProjectId <$> UUID.nextRandom)
branchId <- liftIO (ProjectBranchId <$> UUID.nextRandom)
let branchName = unsafeFrom @Text "main"
Cli.runEitherTransaction do
Queries.projectExistsByName projectName >>= \case
False -> do
Queries.insertProject projectId projectName
Queries.insertProjectBranch
Sqlite.ProjectBranch
{ projectId,
branchId,
name = branchName,
parentBranchId = Nothing
}
Queries.setMostRecentBranch projectId branchId
pure (Right ())
True -> pure (Left (Output.ProjectNameAlreadyExists projectName))
projectName <-
case maybeProjectName of
Nothing -> do
randomProjectNames <- liftIO generateRandomProjectNames
Cli.runTransaction do
let loop = \case
[] -> error (reportBug "E066388" "project name supply is supposed to be infinite")
projectName : projectNames ->
Queries.projectExistsByName projectName >>= \case
False -> do
insertProjectAndBranch projectId projectName branchId branchName
pure projectName
True -> loop projectNames
loop randomProjectNames
Just projectName -> do
Cli.runEitherTransaction do
Queries.projectExistsByName projectName >>= \case
False -> do
insertProjectAndBranch projectId projectName branchId branchName
pure (Right projectName)
True -> pure (Left (Output.ProjectNameAlreadyExists projectName))
let path = projectBranchPath ProjectAndBranch {project = projectId, branch = branchId}
Cli.stepAt "project.create" (Path.unabsolute path, const mainBranchContents)
Cli.respond (Output.CreatedProject projectName branchName)
Cli.stepAt "project.create" (Path.unabsolute path, const Branch.empty0)
Cli.respond (Output.CreatedProject (isNothing maybeProjectName) projectName)
Cli.cd path
-- The initial contents of the main branch of a new project.
insertProjectAndBranch :: ProjectId -> ProjectName -> ProjectBranchId -> ProjectBranchName -> Sqlite.Transaction ()
insertProjectAndBranch projectId projectName branchId branchName = do
Queries.insertProject projectId projectName
Queries.insertProjectBranch
Sqlite.ProjectBranch
{ projectId,
branchId,
name = branchName,
parentBranchId = Nothing
}
Queries.setMostRecentBranch projectId branchId
-- An infinite list of random project names that looks like
--
-- FIXME we should put a README here, or something
mainBranchContents :: Branch0 m
mainBranchContents =
Branch.empty0
-- [
-- -- We have some reasonable amount of base names...
-- "happy-giraffe", "happy-gorilla", "silly-giraffe", "silly-gorilla",
--
-- -- But if we need more, we just add append a number, and so on...
-- "happy-giraffe-2", "happy-gorilla-2", "silly-giraffe-2", "silly-gorilla-2",
--
-- ...
-- ]
--
-- It's in IO because the base supply (without numbers) gets shuffled.
generateRandomProjectNames :: IO [ProjectName]
generateRandomProjectNames = do
baseNames <-
RandomShuffle.shuffleM do
adjective <- ["happy", "silly"]
noun <- ["giraffe", "gorilla"]
pure (adjective <> "-" <> noun)
let namesWithNumbers = do
n <- [(2 :: Int) ..]
name <- baseNames
pure (name <> "-" <> Text.pack (show n))
pure (map (unsafeFrom @Text) (baseNames ++ namesWithNumbers))

View File

@ -226,7 +226,7 @@ data Input
| AuthLoginI
| VersionI
| DiffNamespaceToPatchI DiffNamespaceToPatchInput
| ProjectCreateI ProjectName
| ProjectCreateI (Maybe ProjectName)
| ProjectRenameI ProjectName
| ProjectSwitchI ProjectAndBranchNames
| ProjectsI

View File

@ -324,7 +324,7 @@ data Output
| DisplayDebugCompletions [Completion.Completion]
| ClearScreen
| PulledEmptyBranch (ReadRemoteNamespace Share.RemoteProjectBranch)
| CreatedProject ProjectName ProjectBranchName
| CreatedProject Bool {- randomly-generated name? -} ProjectName
| CreatedProjectBranch CreatedProjectBranchFrom (ProjectAndBranch ProjectName ProjectBranchName)
| CreatedRemoteProject URI (ProjectAndBranch ProjectName ProjectBranchName)
| CreatedRemoteProjectBranch URI (ProjectAndBranch ProjectName ProjectBranchName)

View File

@ -2400,17 +2400,18 @@ projectCreate =
{ patternName = "project.create",
aliases = ["create.project"],
visibility = I.Hidden,
argTypes = [(Required, projectNameArg)],
argTypes = [],
help =
P.wrapColumn2
[ ("`project.create foo`", "creates the project foo and switches you to foo/main")
[ ("`project.create`", "creates a project with a random name"),
("`project.create foo`", "creates a project named `foo`")
],
parse = \case
[name] ->
case tryInto @ProjectName (Text.pack name) of
Left _ -> Left "Invalid project name."
Right name1 -> Right (Input.ProjectCreateI name1)
_ -> Left (showPatternHelp projectCreate)
Right name1 -> Right (Input.ProjectCreateI (Just name1))
_ -> Right (Input.ProjectCreateI Nothing)
}
projectRenameInputPattern :: InputPattern

View File

@ -1796,15 +1796,19 @@ notifyUser dir = \case
PulledEmptyBranch remote ->
pure . P.warnCallout . P.wrap $
P.group (prettyReadRemoteNamespace remote) <> "has some history, but is currently empty."
CreatedProject projectName branchName ->
CreatedProject nameWasRandomlyGenerated projectName ->
pure $
P.wrap
( "I just created project"
<> prettyProjectName projectName
<> "with branch"
<> prettyProjectBranchName branchName
)
<> "."
if nameWasRandomlyGenerated
then
P.wrap $
"🎉 I've created the project with the randomly-chosen name"
<> prettyProjectName projectName
<> "(use"
<> IP.makeExample IP.projectRenameInputPattern ["<new-name>"]
<> "to change it)."
else
P.wrap $
"🎉 I've created the project" <> P.group (prettyProjectName projectName <> ".")
CreatedProjectBranch from projectAndBranch ->
case from of
CreatedProjectBranchFrom'LooseCode path ->

View File

@ -190,6 +190,7 @@ library
, pretty-simple
, process
, random >=1.2.0
, random-shuffle
, recover-rtti
, regex-tdfa
, semialign
@ -322,6 +323,7 @@ executable cli-integration-tests
, pretty-simple
, process
, random >=1.2.0
, random-shuffle
, recover-rtti
, regex-tdfa
, semialign
@ -448,6 +450,7 @@ executable transcripts
, pretty-simple
, process
, random >=1.2.0
, random-shuffle
, recover-rtti
, regex-tdfa
, semialign
@ -580,6 +583,7 @@ executable unison
, pretty-simple
, process
, random >=1.2.0
, random-shuffle
, recover-rtti
, regex-tdfa
, semialign
@ -718,6 +722,7 @@ test-suite cli-tests
, pretty-simple
, process
, random >=1.2.0
, random-shuffle
, recover-rtti
, regex-tdfa
, semialign