diff --git a/pkg/plugins/plugin.go b/pkg/plugins/plugin.go
index 92aba9832..2ef1c1c4e 100644
--- a/pkg/plugins/plugin.go
+++ b/pkg/plugins/plugin.go
@@ -3,7 +3,6 @@ package plugins
import (
"bytes"
"context"
- "encoding/json"
"fmt"
"io"
"io/ioutil"
@@ -181,7 +180,7 @@ func NewPlugin(command string) *Plugin {
// Use the context for cancelation.
func (p *Plugin) Run(ctx context.Context) {
var err error
- p.Variables, err = p.loadVariablesFromJSONFile()
+ p.Variables, err = p.loadVariablesAsEnvVars()
if err != nil {
p.Debugf("ERR: %s", err)
p.OnErr(err)
@@ -316,34 +315,6 @@ func (p *Plugin) refresh(ctx context.Context) error {
return nil
}
-func (p *Plugin) loadVariablesFromJSONFile() ([]string, error) {
- variablesJSONFilename := p.Command + variableJSONFileExt
- f, err := os.Open(variablesJSONFilename)
- if err != nil && os.IsNotExist(err) {
- // no .vars.json file - no probs
- p.Debugf("(skipping) no variable file: %s", variablesJSONFilename)
- return nil, nil
- } else if err != nil {
- p.Debugf("ERR: %s", variablesJSONFilename, err)
- p.OnErr(err)
- }
- defer f.Close()
- b, err := io.ReadAll(io.LimitReader(f, 1_000_000))
- if err != nil {
- return nil, err
- }
- p.Debugf("%s: %s", variablesJSONFilename, string(b))
- var varmap map[string]interface{}
- if err := json.Unmarshal(b, &varmap); err != nil {
- return nil, errors.Wrap(err, "json.Unmarshal")
- }
- var vars []string
- for k, v := range varmap {
- vars = append(vars, fmt.Sprintf("%s=%v", k, v))
- }
- return vars, nil
-}
-
// OnErr is called when something has gone wrong at some point.
func (p *Plugin) OnErr(err error) {
p.Items.CycleItems = []*Item{
diff --git a/pkg/plugins/testdata/vars-test/plugin.sh b/pkg/plugins/testdata/vars-test/plugin.sh
index 07cc9aea9..188b80536 100755
--- a/pkg/plugins/testdata/vars-test/plugin.sh
+++ b/pkg/plugins/testdata/vars-test/plugin.sh
@@ -1,3 +1,9 @@
#!/bin/bash
+
+# string(XBAR_TEST_EXPLICIT_VAR): An explicit variable
+# string(XBAR_TEST_DEFAULT_VAR="default-value"): A default variable (from metadata)
+# string(XBAR_TEST_SET_IN_VARS_JSON): A variable set in the JSON
+
echo "XBAR_TEST_EXPLICIT_VAR=${XBAR_TEST_EXPLICIT_VAR}"
echo "XBAR_TEST_SET_IN_VARS_JSON=${XBAR_TEST_SET_IN_VARS_JSON}"
+echo "XBAR_TEST_DEFAULT_VAR=${XBAR_TEST_DEFAULT_VAR}"
diff --git a/pkg/plugins/variables.go b/pkg/plugins/variables.go
index 0a61ea05c..36274770b 100644
--- a/pkg/plugins/variables.go
+++ b/pkg/plugins/variables.go
@@ -2,11 +2,14 @@ package plugins
import (
"encoding/json"
+ "fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
+ "sync"
+ "github.com/matryer/xbar/pkg/metadata"
"github.com/pkg/errors"
)
@@ -50,3 +53,93 @@ func LoadVariableValues(pluginDir, installedPluginPath string) (map[string]inter
}
return values, nil
}
+
+func (p *Plugin) loadVariablesAsEnvVars() ([]string, error) {
+ vars, err := p.loadVariables()
+ if err != nil {
+ return nil, errors.Wrap(err, "loadVariables")
+ }
+ envvars := make([]string, 0, len(vars))
+ for k, v := range vars {
+ envvars = append(envvars, fmt.Sprintf("%s=%v", k, v))
+ }
+ return envvars, nil
+}
+
+func (p *Plugin) loadVariables() (map[string]interface{}, error) {
+ var wg sync.WaitGroup
+ var defaultVars, jsonFileVars map[string]interface{}
+ var defaultVarsErr, jsonFileVarsErr error
+ wg.Add(1)
+ go func() {
+ defaultVars, defaultVarsErr = p.loadVariablesFromPluginMetadata()
+ wg.Done()
+ }()
+ wg.Add(1)
+ go func() {
+ jsonFileVars, jsonFileVarsErr = p.loadVariablesFromJSONFile()
+ wg.Done()
+ }()
+ wg.Wait()
+ if defaultVarsErr != nil {
+ return nil, errors.Wrap(defaultVarsErr, "load default vars")
+ }
+ if jsonFileVarsErr != nil {
+ return nil, errors.Wrap(jsonFileVarsErr, "load json file vars")
+ }
+ // add the json file vars to the defaults,
+ // and return them.
+ for k, v := range jsonFileVars {
+ defaultVars[k] = v
+ }
+ return defaultVars, nil
+}
+
+// loadVariablesFromJSONFile gets a list of environment variable friendly
+// key=value pairs.
+func (p *Plugin) loadVariablesFromJSONFile() (map[string]interface{}, error) {
+ variablesJSONFilename := p.Command + variableJSONFileExt
+ f, err := os.Open(variablesJSONFilename)
+ if err != nil && os.IsNotExist(err) {
+ // no .vars.json file - no probs
+ return nil, nil
+ } else if err != nil {
+ return nil, errors.Wrap(err, "open vars json file")
+ }
+ defer f.Close()
+ b, err := io.ReadAll(io.LimitReader(f, 1_000_000))
+ if err != nil {
+ return nil, err
+ }
+ var vars map[string]interface{}
+ if err := json.Unmarshal(b, &vars); err != nil {
+ return nil, errors.Wrap(err, "json.Unmarshal")
+ }
+ return vars, nil
+}
+
+func (p *Plugin) loadVariablesFromPluginMetadata() (map[string]interface{}, error) {
+ // read the plugin metadata for default values
+ pluginFile, err := os.Open(p.Command)
+ if err != nil {
+ return nil, errors.Wrap(err, "open plugin source")
+ }
+ defer pluginFile.Close()
+ pluginFileB, err := io.ReadAll(io.LimitReader(pluginFile, 1_000_000))
+ if err != nil {
+ return nil, errors.Wrap(err, "read plugin source")
+ }
+ pluginMetadata, err := metadata.Parse(metadata.DebugFunc(p.Debugf), p.CleanFilename(), string(pluginFileB))
+ if err != nil {
+ return nil, errors.Wrap(err, "metadata.Parse")
+ }
+ vars := make(map[string]interface{})
+ for _, pluginVar := range pluginMetadata.Vars {
+ if pluginVar.Default == "" {
+ // skip values with no default
+ continue
+ }
+ vars[pluginVar.Name] = pluginVar.DefaultValue()
+ }
+ return vars, nil
+}
diff --git a/pkg/plugins/variables_test.go b/pkg/plugins/variables_test.go
index 057dc2d83..e6a9d40d4 100644
--- a/pkg/plugins/variables_test.go
+++ b/pkg/plugins/variables_test.go
@@ -34,9 +34,10 @@ func TestEnvironmentVariables(t *testing.T) {
}
p.Run(ctx)
- is.Equal(len(p.Items.CycleItems), 2)
- is.Equal(p.Items.CycleItems[0].Text, `XBAR_TEST_EXPLICIT_VAR=explicit`) // inherited
- is.Equal(p.Items.CycleItems[1].Text, `XBAR_TEST_SET_IN_VARS_JSON=json`) // in vars.json file
+ is.Equal(len(p.Items.CycleItems), 3)
+ is.Equal(p.Items.CycleItems[0].Text, `XBAR_TEST_EXPLICIT_VAR=explicit`) // inherited
+ is.Equal(p.Items.CycleItems[1].Text, `XBAR_TEST_SET_IN_VARS_JSON=json`) // in vars.json file
+ is.Equal(p.Items.CycleItems[2].Text, `XBAR_TEST_DEFAULT_VAR=default-value`) // from plugin metadata
}