虽然这来得很晚,但这里有一个解决方案建议。
基本上,它只是通过添加自定义逻辑并将其注册到 setup 函数中来继承distutils
'命令。不幸的是,这个主题的官方文档有点模糊和简洁;扩展 Distutils至少提供了一个小例子。我发现阅读包中模块的代码以了解实际命令的实现方式要好得多。sdist
distutils.command
要执行任意命令,您可以使用distutils.cmd.Command::spawn
执行传递的输入字符串的方法,DistutilsExecError
如果命令的退出代码不为零,则引发 a:
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
}
)
运行上面的设置脚本会产生:
$ 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)
重用命令
这是(虽然简化了)我们在项目中使用的命令的真实示例,该命令用于 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
示例用法:
$ 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.
你也可以yarn
在你的命令链中使用它作为所有其他命令:python setup.py yarn test sdist
等等。