Creating waiting/busy indicator for executed process

故事扮演 提交于 2019-12-01 23:20:17

问题


i've program which execute child process like

cmd := exec.Command("npm", "install")
log.Printf("Running command and waiting for it to finish...")
err := cmd.Run()
log.Printf("Command finished with error: %v", err)

While this command is running it download and install npm packages which take some time between 10 to 40 sec, and the user doesnt know what happen until he see the stdout (10-40 sec depend on the network) , there is something that I can use which prints something to the cli to make it more clear that something happen, some busy indicator(any type) until the stdout is printed to the cli ?


回答1:


You may use another goroutine to print something (like a dot) periodically, like in every second. When the command completes, signal that goroutine to terminate.

Something like this:

func indicator(shutdownCh <-chan struct{}) {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    for {
        select {
        case <-ticker.C:
            fmt.Print(".")
        case <-shutdownCh:
            return
        }
    }
}

func main() {
    cmd := exec.Command("npm", "install")
    log.Printf("Running command and waiting for it to finish...")

    // Start indicator:
    shutdownCh := make(chan struct{})
    go indicator(shutdownCh)

    err := cmd.Run()

    close(shutdownCh) // Signal indicator() to terminate

    fmt.Println()
    log.Printf("Command finished with error: %v", err)
}

If you want to start a new line after every 5 dots, this is how it can be done:

func indicator(shutdownCh <-chan struct{}) {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    for i := 0; ; {
        select {
        case <-ticker.C:
            fmt.Print(".")
            if i++; i%5 == 0 {
                fmt.Println()
            }
        case <-shutdownCh:
            return
        }
    }
}



回答2:


Another way is to turn icza's answer around. Since the npm command is a long-running execution, it would probably be better to use a goroutine for it instead of the ticker (or both as a goroutine), but it's a matter of preference.

Like this:

func npmInstall(done chan struct{}) {
    cmd := exec.Command("npm", "install")
    log.Printf("Running command and waiting for it to finish...")

    err := cmd.Run()
    if err != nil {
        log.Printf("\nCommand finished with error: %v", err)
    }
    close(done)
}

func main() {
    done := make(chan struct{})
    go npmInstall(done)

    ticker := time.NewTicker(3 * time.Second)
    defer ticker.Stop()
    for {
        select {
        case <-ticker.C:
            fmt.Print(".")
        case <-done:
            fmt.Println()
            return
        }
    }
}


来源:https://stackoverflow.com/questions/50467037/creating-waiting-busy-indicator-for-executed-process

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!