Reputation:
Im providing command line tool with several command and sub commands, Im using cobra command line and I’ve two separate commands that first is prerequisite to other
e.g. the first command is preferring the environment by creating temp folder and validate some file
The second command should get some properties from the first command
and user should execute it like
btr prepare
btr run
when the run command
is executed it should get some data from the prepare
command outcome
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "btr",
Short: "piping process",
}
var prepare = &cobra.Command{
Use: "pre",
Short: "Prepare The environment" ,
Run: func(cmd *cobra.Command, args []string) {
//This creating the temp folder and validate some configuration file
tmpFolderPath,parsedFile := exe.PreProcess()
},
}
var initProcess = &cobra.Command{
Use: “run”,
Short: “run process”,
Run: func(cmd *cobra.Command, args []string) {
//Here I need those two properties
run(tmpFolderPath, ParsedFile)
},
}
func init() {
rootCmd.AddCommand(prepare,initProcess)
}
UPDATE
Well, the answer below doest really help. I need to share state between two command in local & cloud env) , how I can do it that if I run the command line commands from shell script that call to 1 command and then call to the second which need to get some state from the first command, I need E2E solution with code real example in my context
update 2
let say that I understand that I need config file (json) ,
Where should I create it (path)?
When to clean it ?
in case I use 1file How should I validate to store data which is relevant for specific process and take other process data when needed (guid ) ?
lets say I've config like following
type config struct{
path string,
wd string,
id string,//guid?
}
Upvotes: 4
Views: 2240
Reputation: 2371
Like was said in comments, if you need to share data across commands, you'll need to persist it. The structure you use is no relevant, but for simplicity and because of JSON is the current most extended language for data exchange we'll use it.
My recomendation is to use the home of the user. Many applications save its configuration here. This will allow a solution multi-environment easily. Say that your configuration file will be named myApp.
func configPath() string {
cfgFile := ".myApp"
usr, _ := user.Current()
return path.Join(usr.HomeDir, cfgFile)
}
That obviously will depend on your requirements. But, if you always need to run pre
and run
in that order, I bet that you can clean it inmediately after run
execution, when it won't be longer needed.
That's easy. If what you need to save is your config
struct you can do this:
func saveConfig(c config) {
jsonC, _ := json.Marshal(c)
ioutil.WriteFile(configPath(), jsonC, os.ModeAppend)
}
func readConfig() config {
data, _ := ioutil.ReadFile(configPath())
var cfg config
json.Unmarshal(data, &cfg)
return cfg
}
// pre command
// persist to file the data you need
saveConfig(config{
id: "id",
path: "path",
wd: "wd",
})
// run command
// retrieve the previously stored information
cfg := readConfig()
// from now you can use the data generated by `pre`
DISCLAIMER: I've removed all error handling for short.
Upvotes: 2
Reputation: 5898
If you are trying to persist state across execution of different commands of a command line tool, the you have 2 choices.
On 1.
I think it's good practice for any arguments etc. to only survive for the lifetime of the running of the CLI tool. The equivalent of the smallest scoped variables possible in programming. This works well when you need to persist the state indefinitely, but if your state is no longer used after the initProcess
command has finished then this is probably not the right option.
On 2.
There is some precedence for this. The unix philosophy (wikipedia) suggests to:
Expect the output of every program to become the input to another
So you could pick some output (to stdout) format for the first prepare
command that could be used as the input for the second initProcess
command. And then use |
pipe to run the output of one into the other.
Example:
func Run(cmd *cobra.Command, args []string) {
//This creating the temp folder and validate some configuration file
tmpFolderPath,parsedFile := exe.PreProcess()
fmt.Println(tmpFolderPath)
fmt.Println(parsedFile)
}
func InitProcess(cmd *cobra.Command, args []string) {
tmpFolder, parsedFile := args[0], args[1]
}
Then to run the program, and pipe the commands together:
./program pre | xargs ./program run
Upvotes: 2