feat: [CDE-472]: add status code to the channel for gitspace exec (#3096)

* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
* feat: [CDE-472]: add status code to the channel
pull/3597/head
Ansuman Satapathy 2024-12-03 04:49:05 +00:00 committed by Harness
parent 384fb7a7d2
commit 74ff87178f
8 changed files with 207 additions and 109 deletions

View File

@ -17,6 +17,7 @@ package common
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"strings" "strings"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
@ -156,16 +157,50 @@ func ExecuteCommandInHomeDirAndLog(
gitspaceLogger types.GitspaceLogger, gitspaceLogger types.GitspaceLogger,
verbose bool, verbose bool,
) error { ) error {
outputCh := make(chan []byte) // Buffer upto a thousand messages
err := exec.ExecuteCommandInHomeDirectory(ctx, script, root, false, outputCh) outputCh := make(chan []byte, 1000)
for output := range outputCh { err := exec.ExecuteCmdInHomeDirectoryAsyncStream(ctx, script, root, false, outputCh)
msg := string(output) if err != nil {
// Log output from the command as a string return err
if len(output) > 0 { }
if verbose || strings.HasPrefix(msg, devcontainer.LoggerErrorPrefix) { // Use select to wait for the output and exit status
gitspaceLogger.Info(msg) for {
select {
case output := <-outputCh:
done, chErr := handleOutputChannel(output, verbose, gitspaceLogger)
if done {
return chErr
} }
case <-ctx.Done():
// Handle context cancellation or timeout
return ctx.Err()
} }
} }
return err }
func handleOutputChannel(output []byte, verbose bool, gitspaceLogger types.GitspaceLogger) (bool, error) {
// Handle the exit status first
if strings.HasPrefix(string(output), devcontainer.ChannelExitStatus) {
// Extract the exit code from the message
exitCodeStr := strings.TrimPrefix(string(output), devcontainer.ChannelExitStatus)
exitCode, err := strconv.Atoi(exitCodeStr)
if err != nil {
return true, fmt.Errorf("invalid exit status format: %w", err)
}
if exitCode != 0 {
gitspaceLogger.Info("Process Exited with status " + exitCodeStr)
return true, fmt.Errorf("command exited with non-zero status: %d", exitCode)
}
// If exit status is zero, just continue processing
return true, nil
}
// Handle regular command output
msg := string(output)
if len(output) > 0 {
// Log output if verbose or if it's an error
if verbose || strings.HasPrefix(msg, devcontainer.LoggerErrorPrefix) {
gitspaceLogger.Info(msg)
}
}
return false, nil
} }

View File

@ -53,9 +53,9 @@ func ValidateSupportedOS(
return nil return nil
} }
func ExecuteCommands( func ExecuteLifecycleCommands(
ctx context.Context, ctx context.Context,
exec *devcontainer.Exec, exec devcontainer.Exec,
codeRepoDir string, codeRepoDir string,
gitspaceLogger gitspaceTypes.GitspaceLogger, gitspaceLogger gitspaceTypes.GitspaceLogger,
commands []string, commands []string,
@ -69,18 +69,12 @@ func ExecuteCommands(
gitspaceLogger.Info(fmt.Sprintf("Executing %s command: %s", actionType, command)) gitspaceLogger.Info(fmt.Sprintf("Executing %s command: %s", actionType, command))
gitspaceLogger.Info(fmt.Sprintf("%s command execution output...", actionType)) gitspaceLogger.Info(fmt.Sprintf("%s command execution output...", actionType))
// Create a channel to stream command output exec.DefaultWorkingDir = codeRepoDir
outputCh := make(chan []byte) err := common.ExecuteCommandInHomeDirAndLog(ctx, &exec, command, false, gitspaceLogger, true)
err := exec.ExecuteCommand(ctx, command, false, false, codeRepoDir, outputCh)
if err != nil { if err != nil {
return logStreamWrapError( return logStreamWrapError(
gitspaceLogger, fmt.Sprintf("Error while executing %s command: %s", actionType, command), err) gitspaceLogger, fmt.Sprintf("Error while executing %s command: %s", actionType, command), err)
} }
for output := range outputCh {
gitspaceLogger.Info(string(output))
}
gitspaceLogger.Info(fmt.Sprintf("Completed execution %s command: %s", actionType, command)) gitspaceLogger.Info(fmt.Sprintf("Completed execution %s command: %s", actionType, command))
} }

View File

@ -1,15 +0,0 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package container

View File

@ -197,12 +197,12 @@ func (e *EmbeddedDockerOrchestrator) startStoppedGitspace(
codeRepoDir := filepath.Join(homeDir, resolvedRepoDetails.RepoName) codeRepoDir := filepath.Join(homeDir, resolvedRepoDetails.RepoName)
exec := &devcontainer.Exec{ exec := &devcontainer.Exec{
ContainerName: containerName, ContainerName: containerName,
DockerClient: dockerClient, DockerClient: dockerClient,
HomeDir: homeDir, DefaultWorkingDir: homeDir,
RemoteUser: remoteUser, RemoteUser: remoteUser,
AccessKey: accessKey, AccessKey: accessKey,
AccessType: gitspaceConfig.GitspaceInstance.AccessType, AccessType: gitspaceConfig.GitspaceInstance.AccessType,
} }
// Set up git credentials if needed // Set up git credentials if needed
@ -220,7 +220,7 @@ func (e *EmbeddedDockerOrchestrator) startStoppedGitspace(
// Execute post-start command // Execute post-start command
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
command := ExtractLifecycleCommands(PostStartAction, devcontainerConfig) command := ExtractLifecycleCommands(PostStartAction, devcontainerConfig)
startErr = ExecuteCommands(ctx, exec, codeRepoDir, logStreamInstance, command, PostStartAction) startErr = ExecuteLifecycleCommands(ctx, *exec, codeRepoDir, logStreamInstance, command, PostStartAction)
if startErr != nil { if startErr != nil {
log.Warn().Msgf("Error is post-start command, continuing : %s", startErr.Error()) log.Warn().Msgf("Error is post-start command, continuing : %s", startErr.Error())
} }
@ -454,12 +454,12 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
// Setup and run commands // Setup and run commands
exec := &devcontainer.Exec{ exec := &devcontainer.Exec{
ContainerName: containerName, ContainerName: containerName,
DockerClient: dockerClient, DockerClient: dockerClient,
HomeDir: homeDir, DefaultWorkingDir: homeDir,
RemoteUser: remoteUser, RemoteUser: remoteUser,
AccessKey: *gitspaceConfig.GitspaceInstance.AccessKey, AccessKey: *gitspaceConfig.GitspaceInstance.AccessKey,
AccessType: gitspaceConfig.GitspaceInstance.AccessType, AccessType: gitspaceConfig.GitspaceInstance.AccessType,
} }
if err := e.setupGitspaceAndIDE( if err := e.setupGitspaceAndIDE(
@ -598,7 +598,7 @@ func (e *EmbeddedDockerOrchestrator) buildSetupSteps(
gitspaceLogger gitspaceTypes.GitspaceLogger, gitspaceLogger gitspaceTypes.GitspaceLogger,
) error { ) error {
command := ExtractLifecycleCommands(PostCreateAction, devcontainerConfig) command := ExtractLifecycleCommands(PostCreateAction, devcontainerConfig)
return ExecuteCommands(ctx, exec, codeRepoDir, gitspaceLogger, command, PostCreateAction) return ExecuteLifecycleCommands(ctx, *exec, codeRepoDir, gitspaceLogger, command, PostCreateAction)
}, },
StopOnFailure: false, StopOnFailure: false,
}, },
@ -610,7 +610,7 @@ func (e *EmbeddedDockerOrchestrator) buildSetupSteps(
gitspaceLogger gitspaceTypes.GitspaceLogger, gitspaceLogger gitspaceTypes.GitspaceLogger,
) error { ) error {
command := ExtractLifecycleCommands(PostStartAction, devcontainerConfig) command := ExtractLifecycleCommands(PostStartAction, devcontainerConfig)
return ExecuteCommands(ctx, exec, codeRepoDir, gitspaceLogger, command, PostStartAction) return ExecuteLifecycleCommands(ctx, *exec, codeRepoDir, gitspaceLogger, command, PostStartAction)
}, },
StopOnFailure: false, StopOnFailure: false,
}, },

View File

@ -16,47 +16,93 @@ package devcontainer
import ( import (
"bufio" "bufio"
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
"log"
"strings" "strings"
"sync" "sync"
"github.com/harness/gitness/types/enum" "github.com/harness/gitness/types/enum"
dockerTypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/stdcopy"
"github.com/rs/zerolog/log"
) )
const RootUser = "root" const RootUser = "root"
const ErrMsgTCP = "unable to upgrade to tcp, received 200" const ErrMsgTCP = "unable to upgrade to tcp, received 200"
const LoggerErrorPrefix = "ERR>> " const LoggerErrorPrefix = "ERR>> "
const ChannelExitStatus = "DEVCONTAINER_EXIT_STATUS"
type Exec struct { type Exec struct {
ContainerName string ContainerName string
DockerClient *client.Client DockerClient *client.Client
HomeDir string DefaultWorkingDir string
RemoteUser string RemoteUser string
AccessKey string AccessKey string
AccessType enum.GitspaceAccessType AccessType enum.GitspaceAccessType
} }
type execResult struct { type execResult struct {
StdOut io.Reader ExecID string
StdErr io.Reader StdOut io.Reader
ExitCode int StdErr io.Reader
} }
func (e *Exec) ExecuteCommand( func (e *Exec) ExecuteCommand(
ctx context.Context, ctx context.Context,
command string, command string,
root bool, root bool,
detach bool,
workingDir string, workingDir string,
outputCh chan []byte, // channel to stream output as []byte ) (string, error) {
) error { containerExecCreate, err := e.createExecution(ctx, command, root, workingDir, false)
if err != nil {
return "", err
}
// Attach and inspect exec session to get the output
inspectExec, err := e.attachAndInspectExec(ctx, containerExecCreate.ID, false)
if err != nil {
return "", fmt.Errorf("failed to start docker exec for container %s: %w", e.ContainerName, err)
}
var stdoutBuf bytes.Buffer
var stderrBuf bytes.Buffer
stdoutData, err := io.ReadAll(inspectExec.StdOut)
if err != nil {
return "", fmt.Errorf("error reading stdout: %w", err)
}
stdoutBuf.Write(stdoutData)
stderrData, err := io.ReadAll(inspectExec.StdErr)
if err != nil {
return "", fmt.Errorf("error reading stderr: %w", err)
}
stderrBuf.Write(stderrData)
inspect, err := e.DockerClient.ContainerExecInspect(ctx, containerExecCreate.ID)
if err != nil {
return "", fmt.Errorf("failed to inspect exec session: %w", err)
}
// If the exit code is non-zero, return both stdout and stderr
if inspect.ExitCode != 0 {
// Combine stdout and stderr
return fmt.Sprintf(
"STDOUT:\n%s\nSTDERR:\n%s", stdoutBuf.String(), stderrBuf.String()),
fmt.Errorf("command exited with non-zero status: %d", inspect.ExitCode)
}
// If the exit code is zero, only return stdout
return stdoutBuf.String(), nil
}
func (e *Exec) createExecution(
ctx context.Context,
command string,
root bool,
workingDir string,
detach bool,
) (*dockerTypes.IDResponse, error) {
user := e.RemoteUser user := e.RemoteUser
if root { if root {
user = RootUser user = RootUser
@ -73,11 +119,26 @@ func (e *Exec) ExecuteCommand(
} }
// Create exec instance for the container // Create exec instance for the container
log.Debug().Msgf("Creating execution for container %s", e.ContainerName)
containerExecCreate, err := e.DockerClient.ContainerExecCreate(ctx, e.ContainerName, execConfig) containerExecCreate, err := e.DockerClient.ContainerExecCreate(ctx, e.ContainerName, execConfig)
if err != nil { if err != nil {
return fmt.Errorf("failed to create docker exec for container %s: %w", e.ContainerName, err) return nil, fmt.Errorf("failed to create docker exec for container %s: %w", e.ContainerName, err)
} }
return &containerExecCreate, nil
}
func (e *Exec) executeCmdAsyncStream(
ctx context.Context,
command string,
root bool,
detach bool,
workingDir string,
outputCh chan []byte, // channel to stream output as []byte
) error {
containerExecCreate, err := e.createExecution(ctx, command, root, workingDir, detach)
if err != nil {
return err
}
// Attach and inspect exec session to get the output // Attach and inspect exec session to get the output
inspectExec, err := e.attachAndInspectExec(ctx, containerExecCreate.ID, detach) inspectExec, err := e.attachAndInspectExec(ctx, containerExecCreate.ID, detach)
if err != nil && !strings.Contains(err.Error(), ErrMsgTCP) { if err != nil && !strings.Contains(err.Error(), ErrMsgTCP) {
@ -88,25 +149,18 @@ func (e *Exec) ExecuteCommand(
close(outputCh) close(outputCh)
return nil return nil
} }
// Wait for the exit code after the command completes
if inspectExec != nil && inspectExec.ExitCode != 0 {
return fmt.Errorf("error during command execution in container %s. exit code %d",
e.ContainerName, inspectExec.ExitCode)
}
e.streamResponse(inspectExec, outputCh) e.streamResponse(inspectExec, outputCh)
return nil return nil
} }
func (e *Exec) ExecuteCommandInHomeDirectory( func (e *Exec) ExecuteCmdInHomeDirectoryAsyncStream(
ctx context.Context, ctx context.Context,
command string, command string,
root bool, root bool,
detach bool, detach bool,
outputCh chan []byte, // channel to stream output as []byte outputCh chan []byte, // channel to stream output as []byte
) error { ) error {
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir, outputCh) return e.executeCmdAsyncStream(ctx, command, root, detach, e.DefaultWorkingDir, outputCh)
} }
func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool) (*execResult, error) { func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool) (*execResult, error) {
@ -117,7 +171,6 @@ func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool)
// If in detach mode, we just need to close the connection, not process output // If in detach mode, we just need to close the connection, not process output
if detach { if detach {
// No need to process output in detach mode, so we simply close the connection
resp.Close() resp.Close()
return nil, nil //nolint:nilnil return nil, nil //nolint:nilnil
} }
@ -130,6 +183,7 @@ func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool)
// Return the output streams and the response // Return the output streams and the response
return &execResult{ return &execResult{
ExecID: id,
StdOut: stdoutPipe, // Pipe for stdout StdOut: stdoutPipe, // Pipe for stdout
StdErr: stderrPipe, // Pipe for stderr StdErr: stderrPipe, // Pipe for stderr
}, nil }, nil
@ -138,6 +192,7 @@ func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool)
func (e *Exec) streamResponse(resp *execResult, outputCh chan []byte) { func (e *Exec) streamResponse(resp *execResult, outputCh chan []byte) {
// Stream the output asynchronously if not in detach mode // Stream the output asynchronously if not in detach mode
go func() { go func() {
defer close(outputCh)
if resp != nil { if resp != nil {
var wg sync.WaitGroup var wg sync.WaitGroup
@ -153,20 +208,31 @@ func (e *Exec) streamResponse(resp *execResult, outputCh chan []byte) {
} }
// Wait for all readers to finish before closing the channel // Wait for all readers to finish before closing the channel
wg.Wait() wg.Wait()
// Close the output channel after all output has been processed
close(outputCh) // Now that streaming is finished, inspect the exit status
log.Debug().Msgf("Inspecting container for status: %s", resp.ExecID)
inspect, err := e.DockerClient.ContainerExecInspect(context.Background(), resp.ExecID)
if err != nil {
log.Error().Err(err).Msgf("Failed to inspect exec session: %s", err.Error())
return
}
// Send the exit status as a final message
exitStatusMsg := fmt.Sprintf(ChannelExitStatus+"%d", inspect.ExitCode)
outputCh <- []byte(exitStatusMsg)
} }
}() }()
} }
// copyOutput copies the output from the exec response to the pipes, and is blocking.
func (e *Exec) copyOutput(reader io.Reader, stdoutWriter, stderrWriter io.WriteCloser) { func (e *Exec) copyOutput(reader io.Reader, stdoutWriter, stderrWriter io.WriteCloser) {
defer func() {
stdoutWriter.Close()
stderrWriter.Close()
}()
_, err := stdcopy.StdCopy(stdoutWriter, stderrWriter, reader) _, err := stdcopy.StdCopy(stdoutWriter, stderrWriter, reader)
if err != nil { if err != nil {
log.Printf("Error copying output: %v", err) log.Error().Err(err).Msg("Error in stdcopy.StdCopy " + err.Error())
} }
stdoutWriter.Close()
stderrWriter.Close()
} }
// streamStdOut reads from the stdout pipe and sends each line to the output channel. // streamStdOut reads from the stdout pipe and sends each line to the output channel.
@ -174,10 +240,16 @@ func (e *Exec) streamStdOut(stdout io.Reader, outputCh chan []byte, wg *sync.Wai
defer wg.Done() defer wg.Done()
stdoutReader := bufio.NewScanner(stdout) stdoutReader := bufio.NewScanner(stdout)
for stdoutReader.Scan() { for stdoutReader.Scan() {
outputCh <- stdoutReader.Bytes() select {
case <-context.Background().Done():
log.Info().Msg("Context canceled, stopping stdout streaming")
return
default:
outputCh <- stdoutReader.Bytes()
}
} }
if err := stdoutReader.Err(); err != nil { if err := stdoutReader.Err(); err != nil {
log.Println("Error reading stdout:", err) log.Error().Err(err).Msg("Error reading stdout " + err.Error())
} }
} }
@ -186,9 +258,15 @@ func (e *Exec) streamStdErr(stderr io.Reader, outputCh chan []byte, wg *sync.Wai
defer wg.Done() defer wg.Done()
stderrReader := bufio.NewScanner(stderr) stderrReader := bufio.NewScanner(stderr)
for stderrReader.Scan() { for stderrReader.Scan() {
outputCh <- []byte(LoggerErrorPrefix + stderrReader.Text()) select {
case <-context.Background().Done():
log.Info().Msg("Context canceled, stopping stderr streaming")
return
default:
outputCh <- []byte(LoggerErrorPrefix + stderrReader.Text())
}
} }
if err := stderrReader.Err(); err != nil { if err := stderrReader.Err(); err != nil {
log.Println("Error reading stderr:", err) log.Error().Err(err).Msg("Error reading stderr " + err.Error())
} }
} }

View File

@ -25,6 +25,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/harness/gitness/app/gitspace/orchestrator/common"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
"github.com/harness/gitness/app/gitspace/orchestrator/template" "github.com/harness/gitness/app/gitspace/orchestrator/template"
gitspaceTypes "github.com/harness/gitness/app/gitspace/types" gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
@ -81,18 +82,10 @@ func (v *VSCodeWeb) Setup(
err, err,
) )
} }
outputCh := make(chan []byte) err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, setupScript, false, gitspaceLogger, false)
err = exec.ExecuteCommandInHomeDirectory(ctx, setupScript, false, false, outputCh)
if err != nil { if err != nil {
return fmt.Errorf("failed to install VSCode Web: %w", err) return fmt.Errorf("failed to install VSCode Web: %w", err)
} }
for chunk := range outputCh {
_, err := io.Discard.Write(chunk)
if err != nil {
return err
}
}
if err = v.updateMediaContent(ctx, exec); err != nil { if err = v.updateMediaContent(ctx, exec); err != nil {
return err return err
} }
@ -101,18 +94,11 @@ func (v *VSCodeWeb) Setup(
} }
func (v *VSCodeWeb) updateMediaContent(ctx context.Context, exec *devcontainer.Exec) error { func (v *VSCodeWeb) updateMediaContent(ctx context.Context, exec *devcontainer.Exec) error {
findCh := make(chan []byte) findOutput, err := exec.ExecuteCommand(ctx, findPathScript, true, exec.DefaultWorkingDir)
err := exec.ExecuteCommandInHomeDirectory(ctx, findPathScript, true, false, findCh)
var findOutput []byte
for chunk := range findCh {
findOutput = append(findOutput, chunk...) // Concatenate each chunk of data
}
if err != nil { if err != nil {
return fmt.Errorf("failed to find VSCode Web install path: %w", err) return fmt.Errorf("failed to find VSCode Web install path: %w", err)
} }
path := string(findOutput) path := findOutput
startIndex := strings.Index(path, startMarker) startIndex := strings.Index(path, startMarker)
endIndex := strings.Index(path, endMarker) endIndex := strings.Index(path, endMarker)
if startIndex == -1 || endIndex == -1 || startIndex >= endIndex { if startIndex == -1 || endIndex == -1 || startIndex >= endIndex {
@ -153,10 +139,8 @@ func (v *VSCodeWeb) Run(
) )
} }
gitspaceLogger.Info("Starting IDE ...") gitspaceLogger.Info("Starting IDE ...")
outputCh := make(chan []byte)
// Execute the script in the home directory // Execute the script in the home directory
err = exec.ExecuteCommandInHomeDirectory(ctx, runScript, false, false, outputCh) err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, runScript, false, gitspaceLogger, true)
if err != nil { if err != nil {
return fmt.Errorf("failed to run VSCode Web: %w", err) return fmt.Errorf("failed to run VSCode Web: %w", err)
} }

View File

@ -7,10 +7,11 @@ port={{ .Port }}
proxyuri="{{ .ProxyURI }}" proxyuri="{{ .ProxyURI }}"
# Ensure the configuration directory exists # Ensure the configuration directory exists
mkdir -p $HOME/.config/code-server config_dir="$HOME/.config/code-server"
mkdir -p "$config_dir"
# Create or overwrite the config file with new settings # Create or overwrite the config file with new settings
cat > $HOME/.config/code-server/config.yaml <<EOF cat > "$config_dir/config.yaml" <<EOF
bind-addr: 0.0.0.0:$port bind-addr: 0.0.0.0:$port
auth: none auth: none
cert: false cert: false
@ -22,5 +23,26 @@ if [ -n "$proxyuri" ]; then
echo "Exported VSCODE_PROXY_URI: $proxyuri" echo "Exported VSCODE_PROXY_URI: $proxyuri"
fi fi
# Run code-server with templated arguments # Start code-server in the background
eval "code-server --disable-workspace-trust" nohup code-server --disable-workspace-trust > "$HOME/code-server.log" 2>&1 &
code_server_pid=$!
# Wait for the code-server IPC socket file to exist
echo "Waiting for vscode web to start..."
while true; do
# Check if the process is still running
if ! kill -0 "$code_server_pid" 2>/dev/null; then
echo "Error: code-server process has stopped unexpectedly."
exit 1
fi
# Check for the IPC socket
ipc_socket=$(find "$HOME/.local/" -type s -name "code-server-ipc.sock" 2>/dev/null)
if [ -n "$ipc_socket" ]; then
echo "vscode web is now running and ready."
break
fi
sleep 3
done
exit 0

View File

@ -45,7 +45,7 @@ func (u *ServiceImpl) Manage(
Username: exec.RemoteUser, Username: exec.RemoteUser,
AccessKey: exec.AccessKey, AccessKey: exec.AccessKey,
AccessType: exec.AccessType, AccessType: exec.AccessType,
HomeDir: exec.HomeDir, HomeDir: exec.DefaultWorkingDir,
}) })
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(