Add guest.session.send and vm.workspace.export RPCs
guest.session.send — write to a pipe-mode session's stdin without holding the exclusive attach. The daemon dials a fresh SSH connection, uploads the payload to a temp file, and cats it into the session's named FIFO. Linux atomicity for writes ≤ PIPE_BUF covers all pi RPC JSONL lines. Attach exclusivity is unchanged. vm.workspace.export — pull changes from guest back to host. Runs `git add -A && git diff --cached HEAD --binary` inside the guest via a new RunScriptOutput helper on guest.Client (stdout-only capture, distinct from RunScript which merges stderr). Returns a binary-safe patch and a list of changed files. CLI writes the patch to stdout for `| git apply` or to a file via --output. RunScriptOutput is implemented as a direct SSH session (same pattern as runSession) rather than going through StartCommand/StreamSession to avoid closing the underlying Client, which is required since ExportVMWorkspace calls it twice on the same connection. New files: internal/daemon/workspace_test.go
This commit is contained in:
parent
797a9de1ce
commit
94c353f317
9 changed files with 1074 additions and 1 deletions
|
|
@ -89,6 +89,35 @@ func (c *Client) RunScript(ctx context.Context, script string, logWriter io.Writ
|
|||
return c.runSession(ctx, "bash -se", strings.NewReader(script), logWriter)
|
||||
}
|
||||
|
||||
// RunScriptOutput runs script on the guest and returns its stdout.
|
||||
// Stderr is discarded. Use for capturing structured output (patches, JSON,
|
||||
// file content) where mixing stderr into stdout would corrupt the result.
|
||||
func (c *Client) RunScriptOutput(ctx context.Context, script string) ([]byte, error) {
|
||||
if c == nil || c.client == nil {
|
||||
return nil, fmt.Errorf("ssh client is not connected")
|
||||
}
|
||||
session, err := c.client.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer session.Close()
|
||||
session.Stdin = strings.NewReader(script)
|
||||
var stdout bytes.Buffer
|
||||
session.Stdout = &stdout
|
||||
// session.Stderr left nil: stderr is intentionally discarded.
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = c.client.Close()
|
||||
case <-done:
|
||||
}
|
||||
}()
|
||||
err = session.Run("bash -se")
|
||||
done <- nil
|
||||
return stdout.Bytes(), err
|
||||
}
|
||||
|
||||
func (c *Client) UploadFile(ctx context.Context, remotePath string, mode os.FileMode, data []byte, logWriter io.Writer) error {
|
||||
command := fmt.Sprintf("install -D -m %04o /dev/stdin %s", mode.Perm(), shellQuote(remotePath))
|
||||
return c.runSession(ctx, command, bytes.NewReader(data), logWriter)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue