通过 Java ProcessBuilder 激活 virtualenv

Sim*_*zon 3 java unix bash multithreading processbuilder

尝试通过以下代码以编程方式激活 Python 的virtualenv 时获得以下信息:

java.io.IOException: Cannot run program "." (in directory "/Users/simeon.../..../reporting"): error=13, Permission denied
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at VirtualEnvCreateCmdTest.runCommandInDirectory(VirtualEnvCreateCmdTest.java:30)
    at VirtualEnvCreateCmdTest.createVirtEnv(VirtualEnvCreateCmdTest.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at ......
Caused by: java.io.IOException: error=13, Permission denied
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 25 more
Run Code Online (Sandbox Code Playgroud)

代码:

public class VirtualEnvCreateCmdTest {

    private final static Logger LOG = LoggerFactory.getLogger(VirtualEnvCreateCmdTest.class);

    private void runCommandInDirectory(String path,String ... command) throws Throwable
    {

        LOG.info("Running command '"+String.join(" ",command)+"' in path '"+path+"'");


        ProcessBuilder builder = new ProcessBuilder(command)
                .directory(new File(path))
                .inheritIO();

        Process pr = builder.start();

        final String failureMsg = format("Failed to run '%s' in path '%s'.  Got exit code: %d", join(" ",command), path, pr.exitValue());
        LOG.info("prepared message {}: ", failureMsg);

        if(!pr.waitFor(120, TimeUnit.SECONDS))
        {
            throw new Exception(failureMsg);

        }


        int output = IOUtils.copy(pr.getInputStream(), System.out);

        int exitCode=pr.exitValue();

        if(exitCode!=0)
            throw new Exception(failureMsg);

    }

    @Test
    public void createVirtEnv()  throws Throwable {

        String path = "/Users/simeon/.../reporting";
        String [] commands = new String[]{".", "activate"};
        //String [] commands = new String [] {"/bin/bash", "-c", ". /Users/simeon/..../venv2.7/bin/activate"};
        runCommandInDirectory(path, commands);

    }
Run Code Online (Sandbox Code Playgroud)

更改文件的权限似乎不起作用:

chmod u+x ./bin/activate

/bin/bash尽管有不同的错误,但通过它仍然不起作用。

同时,以下在命令行上工作正常:

. /Users/simeon/.../venv2.7/bin/activate
Run Code Online (Sandbox Code Playgroud)

关于如何从 Java 中调用 python virtualenv activate 命令的任何示例?

===什么有效:=====

以下最终对我有用:

    private void runDjangoMigrate() throws Throwable {

        final String REPORTING_PROJECT_LOCATION = "/Users/simeon.../.../reporting";
        final String UNIX_SHELL_LOCATION = "/bin/bash";
        final String PYTHON_VIRTUALENV_ACTIVATOR_COMMAND =". /Users/simeon.../.../venv2.7/bin/activate;";
        final String PYTHON_VIRTUALENV_ACTIVATOR_COMMAND =". " + PYTHON_VIRTUALENV_ACTIVATE_SCRIPT_LOCATION + ";"; 
        final String DJANGO_MANAGE_MODULE = " manage.py";

        final String[] DJANGO_MIGRATE_COMMAND = new String[] { UNIX_SHELL_LOCATION, "-c", PYTHON_VIRTUALENV_ACTIVATOR_COMMAND
                + PYTHON_INTERPRETER + DJANGO_MANAGE_MODULE + " migrate --noinput --fake-initial" };

        runCommandInDirectory(REPORTING_PROJECT_LOCATION, DJANGO_MIGRATE_COMMAND);


}


    private void runCommandInDirectory(String path, String... command) throws Throwable {

        LOG.info(format("Running '%s' command in path '%s'", join(" ",command),path));

        ProcessBuilder builder = new ProcessBuilder(command).directory(new File(path)).inheritIO();

        Process pr = null;

        pr = builder.start();

        IOUtils.copy(pr.getInputStream(), System.out);  

        boolean terminated = pr.waitFor(SPAWNED_PYTHON_PROCESS_TTL_SEC, SECONDS);

        int exitCode = -1;

        if (terminated) {

            exitCode = pr.exitValue();
        }

        if (exitCode != 0) {

            final String failureMsg = format("Failed to run '%s' in path '%s'.  Got exit code: %d", join(" ", command),
                    path, pr.exitValue());

            throw new Exception(failureMsg);
        }

    }
Run Code Online (Sandbox Code Playgroud)

并产生以下预期输出:

[java] System check identified some issues:
 [java]
 [java] WARNINGS:
 [java] ?: (urls.W005) URL namespace 'admin' isn't unique. You may not be able to reverse all URLs in this namespace
 [java] Building permissions...
 [java] Operations to perform:
 [java]   Apply all migrations: admin, auth, contenttypes, sessions
 [java] Running migrations:
 [java]   No migrations to apply.
 [java] System check identified some issues:
 [java]
 [java] WARNINGS:
 [java] ?: (urls.W005) URL namespace 'admin' isn't unique. You may not be able to reverse all URLs in this namespace
 [java] Building permissions...
 [java] User exists, exiting normally due to --preserve
 [java] System check identified some issues:
 [java]
Run Code Online (Sandbox Code Playgroud)

phd*_*phd 5

您可以在 bash(也可能是 zsh)和 Python 中激活 Python 虚拟环境,但不能在 Java 或任何其他环境中激活。要理解的主要事情是虚拟环境激活不会做一些系统魔术——激活脚本只是改变当前环境,而 Python 虚拟环境准备改变 shell 或 Python 但没有别的。

就 Java 而言,这意味着当你调用runCommandInDirectory()它运行一个新的 shell 时,这个新的 shell 会短暂地激活一个虚拟环境,但随后 shell 退出,所有“激活”虚拟环境的更改都消失了。

这反过来意味着,如果您需要在虚拟环境中运行某些 shell 或 Python 命令,则必须在每次runCommandInDirectory()调用时激活环境:

String [] commands1 = new String [] {"/bin/bash", "-c", ". /Users/simeon/..../venv2.7/bin/activate; script1.sh"};
runCommandInDirectory(path, commands)

String [] commands2 = new String [] {"/bin/bash", "-c", ". /Users/simeon/..../venv2.7/bin/activate; script2.sh"};
runCommandInDirectory(path, commands)
Run Code Online (Sandbox Code Playgroud)

对于 Python 脚本,它更简单一些,因为您可以python从环境中运行并自动激活环境:

String [] commands = new String [] {"/Users/simeon/..../venv2.7/bin/python", "script.py"};
runCommandInDirectory(path, commands)
Run Code Online (Sandbox Code Playgroud)

  • bash 的代码必须是单个字符串:`"/bin/bash", "-c", "./Users/simeon/..../venv2.7/bin/activate; python manage.py migrate"` . 否则`bash`不带参数执行`python`,`python`进入交互模式。 (2认同)