I have a function which writes/updates a json. But I need to stop the executable, run go build again and re-run the executable to get the json updated in url.
For example, I have a Handler.go file which takes argument from URL as key and runs an if condition and updates the json. So If json value before building the executable is {"Name":"Sneha"} and i pass parameter "Nair" in the url, the json gets updated in the server as {"Name":"Nair"}, but doesnt get updated in the URL. So I have to stop the executable, run go build again and run the executable again to reflect the new json value {"Name":"Nair"} in the URL.
1. Can somebody please suggest an alternative idea ?
2. Can we run go build or go update inside a function?
Help much appreciated.
PS: I have got URL for goagain.go. But am not sure if that matches my requirement.
Handler.go
func handler(w http.ResponseWriter, r *http.Request) {
keys, ok := r.URL.Query()["key"]
if !ok || len(keys) < 1 {
log.Println("Url Param 'key' is missing")
return
}
key := keys[0]
log.Println("Url Param 'key' is: " + string(key))
if key == "java" {
commands := []string{
"Version=`java -version`",
"sed -i -e 's/^\\( *Name: *\\) .*$/ Name:\"Java\",/' Handler.go",
"sed -i -e 's/^\\( *Version: *\\) .*$/ Version:\" '$Version'\",/' Handler.go",
}
exe_cmd(commands)
}
if key == "go" {
commands := []string{
"Version=`go version`",
"sed -i -e 's/^\\( *Name: *\\) .*$/ Name:\"Go\",/' Handler.go",
"sed -i -e 's/^\\( *Version: *\\) .*$/ Version:\" '$Version'\",/' Handler.go",
}
exe_cmd(commands)
}
GetHands := GetHand{
Name:"java",
Version:" 1.7.0_71",
}
if err := json.NewEncoder(w).Encode(GetHands); err != nil {
panic(err)
}
So on running this package, the url shows json value : {"name":"java","version":" 1.7.0_71"} If I call url : http://localhost:8080/?key=go this Handler.go gets updated to,
GetHands := GetHand{
Name:"go",
Version:" 1.9",
}
If I stop the executable, run go build again and run executable again the url gets returned as :{"name":"go","version":" 1.9"}
So basically I need dynamic url which on hitting the http:/localhost/?key=go would return go's corresponding value annd htpp://localhost/?key=java would return java's corresponding value. This should be attained without restarting the executable or re-running the go build
Its quite difficult to understand exactly what you want. But I suspect that is essence you simply want to extract the output from a shell command and write it to JSON.
For this there is no need to modify the Handler.go file or do go build
. You can simply write the output directly into the GetHand
structure.
A basic example is as follows :
package main
import (
"fmt"
"os/exec"
)
var cmds = map[string][]string{
"go": []string{"/usr/local/go/bin/go", "version"},
"java": []string{"java", "-version"},
}
type GetHand struct {
Name string
Version string
}
func handleKey(key string) (*GetHand, error) {
cmd := cmds[key]
if cmd == nil {
return nil, fmt.Errorf("No such key : %v", key)
}
b, err := exec.Command("/usr/local/go/bin/go", "version").Output()
if err != nil {
return nil, err
}
return &GetHand{
Name: key,
Version: string(b),
}, nil
}
func main() {
h, err := handleKey("go")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(h)
h, err = handleKey("java")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(h)
}
Your current code with all those sed
tried to modify yor source code. It does not work that way. Some ancient practices (usually using bash) auctually did that kind of staff but it is outdated and problemtic.
As for go, you sure know go is a compiled language, which compiles source code into binaries. In that way, any modification to the source code will not affect binaries, and resulting the process running unaware of that. In that sense, modifying the source code by the process it self is wrong and uneffective. Even if it is possible to use compiler to rebuild binaries, it is going to be both dangerous and inefficient. Do not do it that way.
In your specified case, there is a much better and a much common practice: variable. You sure use it everyday. It would be the simplest to just set the fields of GetHands
to needed value. By doing that, your response to each request (what you call URL, but it is wrong) will change because the fields of GetHands change as variable.
I write the code below:
import (
"os/exec"
"regex"
"runtime"
)
var pattern = regexp.MustCompile(`version \"(.+)\"`)
func GetJavaVersion() string {
cmd := exec.Command("Java", "-version")
out, err := cmd.Output()
if err != nil {
panic(err)
}
return string(pattern.FindSubmatch(out)[1])
}
func GetGoVersion() string {
return runtime.Version()[2:]
}
func handler(w http.ResponseWriter, r *http.Request) {
keys, ok := r.URL.Query()["key"]
if !ok || len(keys) < 1 {
log.Println("Url Param 'key' is missing")
return
}
key := keys[0]
log.Println("Url Param 'key' is: " + string(key))
var GetHands GetHand
if key == "java" {
GetHands = GetHand{Name: "java", Version: GetJavaVersion()}
}
if key == "go" {
GetHands = GetHand{Name: "go", Version: GetGoVersion()}
}
if err := json.NewEncoder(w).Encode(GetHands); err != nil {
panic(err)
}
}
So, for go, you can auctually get the version info from package runtime
, though the info started with "go". You can simply slice it. And for java, you would have to run a command: The same as your orignal code: java -version
. But instead of passing it to sed
, you get the output from it by using Command.Output
and then use a regexp
to find the version information. regexp
is a very useful tool to get info from strings. You can read about it here