diff --git a/cmd/daytona/config/const.go b/cmd/daytona/config/const.go index 3bb17b9040..86c6886002 100644 --- a/cmd/daytona/config/const.go +++ b/cmd/daytona/config/const.go @@ -32,6 +32,7 @@ func GetIdeList() []Ide { {"ssh", "Terminal SSH"}, {"jupyter", "Jupyter"}, {"fleet", "Fleet"}, + {"positron", "Positron"}, {"zed", "Zed"}, {"windsurf", "Windsurf"}, } diff --git a/docs/daytona_code.md b/docs/daytona_code.md index d0386cc4dd..9da23b8960 100644 --- a/docs/daytona_code.md +++ b/docs/daytona_code.md @@ -9,7 +9,7 @@ daytona code [WORKSPACE] [PROJECT] [flags] ### Options ``` - -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) -y, --yes Automatically confirm any prompts ``` diff --git a/docs/daytona_create.md b/docs/daytona_create.md index 0788768fa7..b920343675 100644 --- a/docs/daytona_create.md +++ b/docs/daytona_create.md @@ -17,7 +17,7 @@ daytona create [REPOSITORY_URL | PROJECT_CONFIG_NAME]... [flags] --devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value --env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') --git-provider-config string Specify the Git provider configuration ID or alias - -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) --manual Manually enter the Git repository --multi-project Workspace with multiple projects/repos --name string Specify the workspace name diff --git a/hack/docs/daytona_code.yaml b/hack/docs/daytona_code.yaml index bf00cbb408..408fb1f161 100644 --- a/hack/docs/daytona_code.yaml +++ b/hack/docs/daytona_code.yaml @@ -5,7 +5,7 @@ options: - name: ide shorthand: i usage: | - Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) - name: "yes" shorthand: "y" default_value: "false" diff --git a/hack/docs/daytona_create.yaml b/hack/docs/daytona_create.yaml index e85f584522..ae77e59b35 100644 --- a/hack/docs/daytona_create.yaml +++ b/hack/docs/daytona_create.yaml @@ -28,7 +28,7 @@ options: - name: ide shorthand: i usage: | - Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + Specify the IDE (vscode, code-insiders, browser, cursor, codium, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) - name: manual default_value: "false" usage: Manually enter the Git repository diff --git a/pkg/cmd/ide.go b/pkg/cmd/ide.go index 13869346b0..ff75569847 100644 --- a/pkg/cmd/ide.go +++ b/pkg/cmd/ide.go @@ -65,6 +65,11 @@ var ideCmd = &cobra.Command{ if err := ide_util.CheckFleetInstallation(); err != nil { log.Error(err) } + case "positron": + _, err := ide_util.GetPositronBinaryPath() + if err != nil { + log.Error(err) + } case "zed": _, err := ide_util.GetZedBinaryPath() if err != nil { diff --git a/pkg/cmd/workspace/code.go b/pkg/cmd/workspace/code.go index 1e3f14f8fd..6203320c98 100644 --- a/pkg/cmd/workspace/code.go +++ b/pkg/cmd/workspace/code.go @@ -195,6 +195,8 @@ func openIDE(ideId string, activeProfile config.Profile, workspaceId string, pro return ide.OpenJupyterIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, yesFlag, gpgKey) case "fleet": return ide.OpenFleet(activeProfile, workspaceId, projectName, gpgKey) + case "positron": + return ide.OpenPositron(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) case "zed": return ide.OpenZed(activeProfile, workspaceId, projectName, gpgKey) case "windsurf": diff --git a/pkg/ide/positron.go b/pkg/ide/positron.go new file mode 100644 index 0000000000..d26f4c5cfc --- /dev/null +++ b/pkg/ide/positron.go @@ -0,0 +1,67 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package ide + +import ( + "errors" + "fmt" + "os/exec" + "runtime" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/build/devcontainer" + "github.com/daytonaio/daytona/pkg/views" +) + +func OpenPositron(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { + path, err := GetPositronBinaryPath() + if err != nil { + return err + } + + projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + + projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + if err != nil { + return err + } + + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + if runtime.GOARCH == "arm64" { + printPositronDisclaimer() + } + positronCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) + + err = positronCommand.Run() + if err != nil { + return err + } + + if projectProviderMetadata == "" { + return nil + } + + return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.positron-server/*/bin/positron-server", "$HOME/.positron-server/data/Machine/settings.json", ".daytona-customizations-lock-positron") +} + +func GetPositronBinaryPath() (string, error) { + path, err := exec.LookPath("positron") + if err == nil { + return path, err + } + + redBold := "\033[1;31m" // ANSI escape code for red and bold + reset := "\033[0m" // ANSI escape code to reset text formatting + + errorMessage := "Please install Positron from https://positron.posit.co/download.html and ensure it's in your PATH.\n" + + return "", errors.New(redBold + errorMessage + reset) +} + +func printPositronDisclaimer() { + views.RenderTip(` +Note: Positron does not currently support Linux ARM64 builds, including remote environments and SSH sessions. +Refer to https://github.com/posit-dev/positron/issues/5911 for updates.`) +}