How to execute a (safe) bash shell command within

2019-02-15 15:02发布

问题:

I use nunjucks for templating the frontend in a python project. Nunjucks templates must be precompiled in production. I don't use extensions or asynchronous filters in the nunjucks templates. Rather than use grunt-task to listen for changes to my templates, I prefer to use the nunjucks-precompile command (offered via npm) to sweep the entire templates directory into templates.js.

The idea is to have the nunjucks-precompile --include ["\\.tmpl$"] path/to/templates > templates.js command execute within setup.py so I can simply piggyback our deployer scripts' regular execution.

I found a setuptools override and a distutils scripts argument might serve the right purpose, but I'm not so sure either is the simplest approach to execution.

Another approach is to use subprocess to execute the command directly within setup.py, but I've been cautioned against this (rather preemptively IMHO). I don't really deeply understand why not.

Any ideas? Affirmations? Confirmations?

Update (04/2015): - If you don't have the nunjucks-precompile command available, simply use Node Package Manager to install nunjucks like so:

$ npm install nunjucks

回答1:

Pardon the quick self-answer. I hope this helps someone out there in the ether. I want to share this now that I've worked out a solution I'm satisfied with.

Here's a solution that's safe and based on Peter Lamut's write-up. Note that this does not use shell=True in the subprocess invocation. You may bypass grunt-task requirements on your python deployment system and also use this for obfuscation and JS packaging all the same.

from setuptools import setup
from setuptools.command.install import install
import subprocess
import os

class CustomInstallCommand(install):
    """Custom install setup to help run shell commands (outside shell) before installation"""
    def run(self):
        dir_path = os.path.dirname(os.path.realpath(__file__))
        template_path = os.path.join(dir_path, 'src/path/to/templates')
        templatejs_path = os.path.join(dir_path, 'src/path/to/templates.js')
        templatejs = subprocess.check_output([
            'nunjucks-precompile',
            '--include',
            '["\\.tmpl$"]',
            template_path
        ])
        f = open(templatejs_path, 'w')
        f.write(templatejs)
        f.close()
        install.run(self)

setup(cmdclass={'install': CustomInstallCommand},
      ...
     )


回答2:

I think that the link here encapsulates what you are trying to achieve.