func (d *execSource) Init(p datasource.ConfigProvider) (fErr error) {
	defer func() {
		fErr = errors.Wrapf(fErr, "init data source %s", d.name)  
	}()
	cfgJSON, err := p(d.configVar)
	if err != nil {
		return err
	}
	var c Config
	err = json.Unmarshal([]byte(cfgJSON), &c)
	if err != nil {
		return err
	}
	err = c.assertValid()
	if err != nil {
		return err
	}
	c.initDefaults()
	d.runner = newRunner(&c)
	return nil
}
Init implements the interface method.
package exec
import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"
	"github.com/pkg/errors"
	"github.com/splunk/qbec/vm/datasource"
	"github.com/splunk/qbec/vm/internal/ds"
)
const (
	Scheme = "exec"
)
type Config struct {
	Command    string            `json:"command"`               
	Args       []string          `json:"args,omitempty"`        
	Env        map[string]string `json:"env,omitempty"`         
	Stdin      string            `json:"stdin,omitempty"`       
	Timeout    string            `json:"timeout,omitempty"`     
	InheritEnv bool              `json:"inheritEnv,omitempty"`  
	timeout time.Duration  
}
func findExecutable(cmd string) (string, error) {
	if !filepath.IsAbs(cmd) {
		p, err := filepath.Abs(cmd)
		if err == nil {
			stat, err := os.Stat(cmd)
			if err == nil {
				if m := stat.Mode(); !m.IsDir() && m&0111 != 0 {
					return p, nil
				}
			}
		}
	}
	return exec.LookPath(cmd)
}
func (c *Config) assertValid() error {
	if c.Command == "" {
		return fmt.Errorf("command not specified")
	}
	if c.Timeout != "" {
		t, err := time.ParseDuration(c.Timeout)
		if err != nil {
			return fmt.Errorf("invalid timeout '%s': %v", c.Timeout, err)
		}
		c.timeout = t
	}
	exe, err := findExecutable(c.Command)
	if err != nil {
		return fmt.Errorf("invalid command '%s': %v", c.Command, err)
	}
	c.Command = exe
	return nil
}
func (c *Config) initDefaults() {
	if c.timeout == 0 {
		c.timeout = time.Minute
	}
}
type execSource struct {
	name      string
	configVar string
	runner    *runner
}
func New(name string, configVar string) ds.DataSourceWithLifecycle {
	return &execSource{
		name:      name,
		configVar: configVar,
	}
}
func (d *execSource) Name() string {
	return d.name
}