waveterm/cmd/wsh/cmd/wshcmd-getvar.go
Mike Sawka 72f36a9639
wsh run (#1376)
implements `wsh run` command.  lots of fixes (and new options) for command blocks.  cleans up the UX/UI for command blocks.  lots of bug fixes for blockcontrollers.  other minor bug fixes.

also makes editor:* vars into settings override atoms.
2024-12-04 14:16:50 -08:00

153 lines
3.5 KiB
Go

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"encoding/base64"
"fmt"
"io/fs"
"sort"
"github.com/spf13/cobra"
"github.com/wavetermdev/waveterm/pkg/util/envutil"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
)
var getVarCmd = &cobra.Command{
Use: "getvar [flags] [key]",
Short: "get variable(s) from a block",
Long: `Get variable(s) from a block. Without --all, requires a key argument.
With --all, prints all variables. Use -0 for null-terminated output.`,
Example: " wsh getvar FOO\n wsh getvar --all\n wsh getvar --all -0",
RunE: getVarRun,
PreRunE: preRunSetupRpcClient,
}
var (
getVarFileName string
getVarAllVars bool
getVarNullTerminate bool
getVarLocal bool
getVarFlagNL bool
getVarFlagNoNL bool
)
func init() {
rootCmd.AddCommand(getVarCmd)
getVarCmd.Flags().StringVar(&getVarFileName, "varfile", DefaultVarFileName, "var file name")
getVarCmd.Flags().BoolVar(&getVarAllVars, "all", false, "get all variables")
getVarCmd.Flags().BoolVarP(&getVarNullTerminate, "null", "0", false, "use null terminators in output")
getVarCmd.Flags().BoolVarP(&getVarLocal, "local", "l", false, "get variables local to block")
getVarCmd.Flags().BoolVarP(&getVarFlagNL, "newline", "n", false, "print newline after output")
getVarCmd.Flags().BoolVarP(&getVarFlagNoNL, "no-newline", "N", false, "do not print newline after output")
}
func shouldPrintNewline() bool {
isTty := getIsTty()
if getVarFlagNL {
return true
}
if getVarFlagNoNL {
return false
}
return isTty
}
func getVarRun(cmd *cobra.Command, args []string) error {
defer func() {
sendActivity("getvar", WshExitCode == 0)
}()
// Resolve block to get zoneId
if blockArg == "" {
if getVarLocal {
blockArg = "this"
} else {
blockArg = "client"
}
}
fullORef, err := resolveBlockArg()
if err != nil {
return err
}
if getVarAllVars {
if len(args) > 0 {
return fmt.Errorf("cannot specify key with --all")
}
return getAllVariables(fullORef.OID)
}
// Single variable case - existing logic
if len(args) != 1 {
OutputHelpMessage(cmd)
return fmt.Errorf("requires a key argument")
}
key := args[0]
commandData := wshrpc.CommandVarData{
Key: key,
ZoneId: fullORef.OID,
FileName: getVarFileName,
}
resp, err := wshclient.GetVarCommand(RpcClient, commandData, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
return fmt.Errorf("getting variable: %w", err)
}
if !resp.Exists {
WshExitCode = 1
return nil
}
WriteStdout("%s", resp.Val)
if shouldPrintNewline() {
WriteStdout("\n")
}
return nil
}
func getAllVariables(zoneId string) error {
fileData := wshrpc.CommandFileData{
ZoneId: zoneId,
FileName: getVarFileName,
}
envStr64, err := wshclient.FileReadCommand(RpcClient, fileData, &wshrpc.RpcOpts{Timeout: 2000})
err = convertNotFoundErr(err)
if err == fs.ErrNotExist {
return nil
}
if err != nil {
return fmt.Errorf("reading variables: %w", err)
}
envBytes, err := base64.StdEncoding.DecodeString(envStr64)
if err != nil {
return fmt.Errorf("decoding variables: %w", err)
}
envMap := envutil.EnvToMap(string(envBytes))
terminator := "\n"
if getVarNullTerminate {
terminator = "\x00"
}
// Sort keys for consistent output
keys := make([]string, 0, len(envMap))
for k := range envMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
WriteStdout("%s=%s%s", k, envMap[k], terminator)
}
return nil
}