Search code examples
linuxbashgopython-venv

How can I use source in golang's os.StartProcess arguments?


I'm trying to use os.StartProcess to activate a python virtual environment, but the source command doesnt work, if I use exec.Command it works just fine.

Using os.StartProcess it gives me this error:

source: filename argument required

source: usage: source filename [arguments]

package main

import (
    "os"
    "os/exec"
)

func main() {
    // this works ok
    cmd := exec.Command("/bin/bash", "-c", "source ./venv/bin/activate && python3 -u main.py")
    cmd.Run()

    // this doesnt works - error:
    // source: filename argument required
    // source: usage: source filename [arguments]
    var procAttr os.ProcAttr
    procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
    p, _ := os.StartProcess(
        "/bin/bash",
        []string{
            "/bin/bash",
            "-c",
            "source",
            "./venv/bin/activate",
            "&&",
            "python3", 
            "-u",
            "main.py",
        },
        &procAttr,
    )
    p.Wait()
}

I know I should just use exec.Command, but I have to use os.StartProcess for my Windows implementation, os/exec doesnt work for what Im doing in windows and I would like to have the same implementation for both linux and win.

If there is no way around this, I will end up using exec.Command in linux and os.StartProcess in windows

thank you for your help


UPDATE - thanks @that other guy for your help

The solution was simpler than i thought, you just do It the same way as in exec.Command. The thing is that os.StartProcess is not well documented, and can be confusing sometimes

    procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
    p, _ := os.StartProcess(
        "/bin/bash",
        []string{
            "/bin/bash",
            "-c",
            "source ./venv/bin/activate && python3 -u main.py",
        },
        &procAttr,
    )
    p.Wait()
}

Solution

  • I don't know how Windows affects things, but generally the shell string to evaluate must be a single string and not multiple arguments:

        []string{
            "/bin/bash",
            "-c",
            "source ./venv/bin/activate",
        },
    

    Be aware that the environment effects of this source command won't survive the shell. If you want to run something in the context of it, it must be run in the same shell command:

        []string{
            "/bin/bash",
            "-c",
            "source ./venv/bin/activate; python whatever",
        },