简体   繁体   English

Python setup.py运行外壳脚本

[英]Python setup.py to run shell script

I need to run my own script during 'sdist' phase while creating Python package. 在创建Python包时,我需要在'sdist'阶段运行自己的脚本。 I wrote the following script. 我写了以下脚本。 Do you know better approach? 您知道更好的方法吗? Could you recommend please the better one or link to the official documentation on setuptools where this moment has been explained? 您能推荐一个更好的方法吗,或者链接到setuptools上解释了这一刻的官方文档?

import subprocess
import sys

from setuptools import setup, find_packages, os

if 'sdist' in sys.argv:
    cwd = os.getcwd()
    os.chdir('website/static/stylesheets/')
    result = subprocess.call("scss --update --compass ./*.scss", shell=True)
    if result != 0:
        exit(1)
    os.chdir(cwd)

setup(name = "site",
    author="Vladimir Ignatev",
    author_email="mail@gmail.com",
    version="0.1",
    packages=find_packages(),
    include_package_data=True,
    zip_safe=True,
)

Although this comes pretty late, here is a solution proposal. 尽管这来得很晚,但这是一个解决方案。

Basically, it is simply subclassing the distutils ' sdist command with adding custom logic and registering it in the setup function. 基本上,它只是通过添加自定义逻辑并将其注册到setup函数中而将distutilssdist命令子类化。 Unfortunately, the official documentation to this topic is kind of vague and laconic ; 不幸的是,该主题的官方文档有点含糊不清 Extending Distutils provides at least a tiny example for the start. 扩展Distutils至少提供了一个很小的例子。 I found it much better to read the code of modules in distutils.command package to see how the actual commands are implemented. 我发现最好阅读distutils.command软件包中的模块代码以查看实际命令的实现方式。

To execute an arbitrary command, you can use the method distutils.cmd.Command::spawn that executes passed input string, raising a DistutilsExecError if the command's exit code in not zero: 要执行任意命令,可以使用distutils.cmd.Command::spawn方法执行传递的输入字符串,如果命令的退出代码不为零,则引发DistutilsExecError

from distutils.command.sdist import sdist as sdist_orig
from distutils.errors import DistutilsExecError

from setuptools import setup  


class sdist(sdist_orig):

    def run(self):
        try:
            self.spawn(['ls', '-l'])
        except DistutilsExecError:
            self.warn('listing directory failed')
        super().run()


setup(name='spam',
    version='0.1',
    packages=[],
    cmdclass={
        'sdist': sdist
    }
)

Running the setup script above yields: 运行上面的安装脚本会产生:

$ python setup.py sdist
running sdist
ls -l
total 24
-rw-r--r--  1 hoefling  staff   52 23 Dez 19:06 MANIFEST
drwxr-xr-x  3 hoefling  staff   96 23 Dez 19:06 dist
-rw-r--r--  1 hoefling  staff  484 23 Dez 19:07 setup.py
running check
...
writing manifest file 'MANIFEST'
creating spam-0.1
making hard links in spam-0.1...
hard linking setup.py -> spam-0.1
Creating tar archive
removing 'spam-0.1' (and everything under it)

Reusing commands 重用命令

Here is (although simplified) a real life example of a command we are using in our projects that is used around NodeJS projects and invokes yarn : 这是(尽管简化了)我们在项目中使用的命令的真实示例,该命令用于NodeJS项目并调用yarn

import distutils
import os
import pathlib
import setuptools

_YARN_CMD_SEP = ';'

_HELP_MSG_SUBCMD = (
    'yarn subcommands to execute (separated '
    'by {})'.format(_YARN_CMD_SEP)
)

_HELP_MSG_PREFIX = (
    'path to directory containing package.json. '
    'If not set, current directory is assumed.'
)


class yarn(setuptools.Command):

    description = ('runs yarn commands. Assumes yarn is '
                   'already installed by the user.')

    user_options = [
        ('subcommands=', None, _HELP_MSG_SUBCMD),
        ('prefix=', None, _HELP_MSG_PREFIX),
    ]

    def initialize_options(self) -> None:
        self.subcommands = []
        self.prefix = None  # type: pathlib.Path

    def finalize_options(self) -> None:
        self.subcommands = [
            cmd.strip() for cmd in str(self.subcommands).split(self._YARN_CMD_SEP)
        ]
        self.prefix = pathlib.Path(self.prefix) if self.prefix else pathlib.Path()

    def run(self) -> None:
        cwd = pathlib.Path().absolute()
        os.chdir(str(self.prefix.absolute()))  # change to prefix dir
        for cmd in self.subcommands:
            self.announce('running yarn {} ...'.format(cmd), level=distutils.log.INFO)
            self.spawn(['yarn'] + cmd.split(' '))
        os.chdir(str(cwd))  # change back to our previous dir

Example usage: 用法示例:

$ python setup.py yarn --prefix=. --subcommands="add leftpad; remove leftpad"
running yarn
running yarn add leftpad ...
yarn add leftpad
yarn add v1.3.2
warning package.json: No license field
warning No license field
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
└─ leftpad@0.0.1
warning No license field
✨  Done in 0.33s.
running yarn remove leftpad ...
yarn remove leftpad
yarn remove v1.3.2
warning package.json: No license field
[1/2] Removing module leftpad...
[2/2] Regenerating lockfile and installing missing dependencies...
warning No license field
success Uninstalled packages.
✨  Done in 0.13s.

You can also use the yarn in your command chain as every other command: python setup.py yarn test sdist etc. 您还可以像其他命令一样在命令链中使用yarnpython setup.py yarn test sdist等。

也许尝试distutils我认为它比setuptools更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM