-2

Im trying to check if package is installed in system (Centos/Yum). Im trying to use for that exec.Command method:

func YumCheckIfPackageInstalled(pkg string) string {
    out,err := exec.Command("yum", "list", "installed", pkg).Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Output %s\n", out)

    return "string"
}

Problem is that when "pkg" is installed program is continuing to work, but if it is not it is exiting with:

exit status 1

How to prevent program to exit on os command error?

What i want to achieve is to check if some packages are installed and if not i want to install them. Maybe there is some better way to solve that problem than executing exec.Command-s?

user3069488
  • 75
  • 1
  • 6
  • You should probably read the process stderr to see what the error was. Otherwise this is sort of a question about how to use `yum`, rather than programming in Go. – JimB Mar 22 '19 at 16:39
  • The best would be to reply on exit code of the command. See here how to get exit code in Go: https://stackoverflow.com/questions/10385551/get-exit-code-go – Nik Mar 22 '19 at 16:53
  • It helped but have no idea how it is working. Need to rebuild it to return status but not sure what was use there is it about error handling? – user3069488 Mar 22 '19 at 18:00

1 Answers1

3

Your program is not exiting because of command error.

It is exiting because you put log.Fatal(err).

log.Fatal exits the program with SIGINT 1, if you just want to log the error, do log.Println(err). See the doc here: https://golang.org/pkg/log/#Logger.Fatal

Also, to do it the goway, you should bubble up the error and let the caller of the function handle the error.

Now, regarding what you want to do, I suggest to use the function LookPath of the exec package, it does exactly what you want by searching for an executable with the given name in your path. Here is the doc: https://golang.org/pkg/os/exec/#LookPath

You could do something like that:

package main

import (
        "flag"
        "fmt"
        "log"
        "os/exec"
)

var pkg = flag.String("pkg", "", "package name")

func main() {
        flag.Parse()

        if !PackageInstalled(*pkg) {
                if err := InstallPackage(*pkg); err != nil {
                        log.Fatal(err)
                }
                fmt.Printf("Package %s installed\n", *pkg)
                return
        }
        fmt.Printf("Package %s already installed\n", *pkg)
}

func PackageInstalled(pkg string) bool {
        _, err := exec.LookPath(pkg)

        // check error
        if err != nil {
                // the executable is not found, return false
                if execErr, ok := err.(*exec.Error); ok && execErr.Err == exec.ErrNotFound {
                        return false
                }
                // another kind of error happened, let's log and exit
                log.Fatal(err)
        }

        return true
}

func InstallPackage(pkg string) error {
        // install your package
        // ...
        return nil
}

and run it this way go run main.go -pkg yum

Francois
  • 3,050
  • 13
  • 21
  • It is exactly what i needed. Only one thing which im not understanding is that line: if execErr, ok := err.(*exec.Error); ok && execErr.Err == exec.ErrNotFound {} what it is doing? EDIT: i find out: https://golang.org/ref/spec#Type_assertions – user3069488 Mar 22 '19 at 18:17
  • 1
    I should have explained a little more. So basically the `exec` package wraps its errors in an `Error` structure, here I'm checking that the error returned is of the type `*exec.Error` if yes, then I have the `execErr`value and I can check if it is a `exec.NotFoundError` which is the error returned when the executable is not found. Here is the doc https://golang.org/pkg/os/exec/#Error, an error in go is simply an interface, this is good read https://blog.golang.org/error-handling-and-go – Francois Mar 22 '19 at 18:20