2013-06-24 49 views
0

我使用subprocess.Popen为Scipy堆栈创建自动构建脚本。确保子进程的执行顺序.Popen调用

我现在的流程如下。

mathbuild.json:

{"suitesparse": {"version": "4.2.1", 
     "dependencies": ["metis"], 
     "downloads": ["http://www.cise.ufl.edu/research/sparse/SuiteSparse/SuiteSparse-4.2.1.tar.gz"], 
     "build": ["cd $DL_DIR", 
       "tar xvfz SuiteSparse-4.2.1.tar.gz", 
       "cd SuiteSparse", 
       "cp -r $DL_DIR/metis-4.0.3 metis-4.0.3"]}, 

"metis": {"version": "4.0.3", 
     "dependencies": [], 
     "downloads": ["http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD/metis-4.0.3.tar.gz"], 
     "build": ["cd $DL_DIR", 
      "tar xvfz metis-4.0.3.tar.gz", 
      "cd metis-4.0.3", 
      "make"]}} 

mathbuild.py:

def package_list(package, config): 
    for dependency in config[package]['dependencies']: 
     yield from package_list(dependency, config) 
    yield package 

def build_package(package, config): 
    command = '; '.join(config[package]['build']) 
    build = subprocess.Popen(command, shell=True) 


def process_package(package, config, env_dir, dl_dir): 
    print('INSTALLING {0}'.format(package)) 
    print('Downloading...') 
    download_package(package, config, dl_dir) 
    print('Building...') 
    build_package(package, config) 


if __name__ == '__main__': 
    parser = argparse.ArgumentParser(description='Install Pylab in a new venv.') 
    parser.add_argument('env_dir', help='target directory for new environment') 
    args = parser.parse_args() 
    os.environ['ENV_DIR'], os.environ['DL_DIR'] = create_venv(args.env_dir) 
    with open('mathbuild.json') as f: 
     cfg = json.load(f) 
    processed = [] 
    for package in package_list('suitesparse', cfg): 
     if package not in processed: 
      process_package(package, cfg, 
          os.environ['ENV_DIR'], 
          os.environ['DL_DIR']) 
      processed += [package] 

它创建依赖列表(例如稍后的项目依赖于早期的),然后处理每一个(下载和然后根据json文件中的命令进行构建)。

问题是在完全构建依赖关系之前,将通过新的subprocess.Popen调用构建包。在上面的示例中,即使在metis构建完成之前,suitesparse执行也会开始。我认为这是因为我每次围绕for package in package_list('suitesparse', cfg)循环打开一个新的子进程,而不考虑先前的子进程是否完成。

问题 什么是同步的基于循环的POPEN调用,以便时才会POPEN以前的调用(在列表中即前一个项目)完成每次通话开始的最佳方式?

我已经试过 我试图改变环路,这样它建立一个联合POPEN(既包版本),但似乎的hackish。

回答

2

它看起来像你想要subprocess.check_call()而不是Popen。从the docs

带参数运行命令。等待命令完成。如果返回码为零,则返回,否则引发CalledProcessError。

你构建功能将类似于:

def build_package(package, config): 
    command = '; '.join(config[package]['build']) 
    subprocess.check_call(command, shell=True) 

如果你实际使用POPEN对象,你可以调用wait()方法来等待子命令来完成:

def build_package(package, config): 
    command = '; '.join(config[package]['build']) 
    build = subprocess.Popen(command, shell=True) 
    # do something with the build object 
    build.wait() 
    # command is done