2 Star 0 Fork 0

mirrors_gnu/pyconfigure

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
pyconf.in 11.07 KB
一键复制 编辑 原始数据 按行查看 历史
Brandon Invergo 提交于 2013-08-20 00:14 . change CRLF to LF
#!/usr/bin/env python
# Copyright (C) 2013 Brandon Invergo <[email protected]>
#
# This file is part of pyconfigure.
#
# pyconfigure is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyconfigure is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyconfigure. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import os
import stat
import sys
import getopt
import shutil
import subprocess
import warnings
DATADIR = "@pkgdatadir@"
# os.mkdir throws an OSError in Python 2.x when the target already
# exists, while it throws a FileExistsError in Python 3.x.
try:
raise FileExistsError
except:
FileExistsError = OSError
def safe_copy(src, dst, overwrite=False):
if not overwrite and os.path.exists(dst):
warnings.warn("{0} exists. Skipping.".format(dst))
else:
shutil.copy(src, dst)
def parse_pkg_info(pkg_info):
"""Parse a PKG-INFO file to get all the relevant package meta-data.
The file should be in PKG-INFO format version 1.2"""
# Fields that can only appear once in the file
singles = ["Name", "Version", "Summary", "Keywords", "Home-page",
"Download-URL", "Author", "Author-email", "Maintainer",
"Maintainer-email", "License", "Requires-Python",
"Description", "Metadata-Version"]
# Fields that can appear more than once
multis = ["Platform", "Supported-Platform", "Classifier", "Requires-Dist",
"Provides-Dist", "Obsoletes-Dist", "Requires-External",
"Project-URL"]
pkg_meta = {}
for key in singles:
pkg_meta[key] = ""
for key in multis:
pkg_meta[key] = []
with open(pkg_info) as h:
lines = h.readlines()
for line in lines:
if line[0:8] == " |":
if key is None or key == "":
sys.exit("*** Error: Folded field that doesn't belong to any key")
pkg_meta[key] = '\n'.join([pkg_meta[key], line[8:]])
continue
key, sep, val = line.partition(':')
val = val.strip()
if key == "Metadata-Version" and float(val) < 1.2:
sys.exit("*** Error: PKG-INFO metadata format version 1.2 or greater \
is required")
elif key in singles:
if pkg_meta[key] == "":
pkg_meta[key] = val
else:
print("==> Warning: multiple entries for metadata field \
'{0}'".format(key))
elif key in multis:
pkg_meta[key].append(val)
else:
print("==> Warning: unknown metadata field '{0}'".format(key))
continue
if "Project-URL" in pkg_meta and len(pkg_meta["Project-URL"]) > 0:
pkg_meta["URL"] = pkg_meta["Project-URL"][0]
else:
pkg_meta["URL"] = ""
for key in multis:
if key in pkg_meta and len(pkg_meta[key]) > 0:
pkg_meta["{0}-list".format(key)] = "',\n\t\t'".join(pkg_meta[key])
else:
pkg_meta["{0}-list".format(key)] = ""
return pkg_meta
def subst_meta(in_file, out_file, pkg_meta):
"""Substitute the package's metadata into the template files. Substitutions
occur where one of the metadata keys appears in the file wrapped in \[ and \]
(i.e. \[URL\] -> {http://myproject.org})"""
with open(in_file) as h:
lines = h.readlines()
with open(out_file, 'w') as h:
for line in lines:
line_fmt = line.format(**pkg_meta)
line_fmt = line_fmt.replace("\\[", "{")
line_fmt = line_fmt.replace("\\]", "}")
h.write(line_fmt)
def copy_aux_files(output):
"""Copy auxiliary install scripts to the destination directory."""
bootstrap = os.path.join(DATADIR, "bootstrap.sh")
install_sh = os.path.join(DATADIR, "install-sh")
print("Copying bootstrap.sh")
shutil.copy(bootstrap, output)
os.chmod(os.path.join(output, "bootstrap.sh"),
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | \
stat.S_IROTH | stat.S_IXOTH)
print("Copying install-sh")
shutil.copy(install_sh, output)
os.chmod(os.path.join(output, "install-sh"),
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | \
stat.S_IROTH | stat.S_IXOTH)
def copy_macros(output):
"""Copy the Autoconf macros to the destination directory."""
macros = os.path.join(DATADIR, "m4", "python.m4")
macro_dir = os.path.join(output, "m4")
print("Copying Python M4 macros")
try:
os.mkdir(macro_dir)
except FileExistsError:
pass
shutil.copy(macros, macro_dir)
def gen_configure(pkg_meta, output, overwrite):
"""Generate the configure script. Copy the source files into the project
directory and then run autoreconf to generate the configure script"""
config_src = os.path.join(DATADIR, "configure.ac")
config_dst = os.path.join(output, "configure.ac")
print("Generating configure.ac")
if not overwrite and os.path.exists(config_dst):
warnings.warn("configure.ac exists. Skipping.")
else:
subst_meta(config_src, config_dst, pkg_meta)
print("Generating configure")
subprocess.call(["autoreconf", "-fvi", output])
def gen_makefile(pkg_meta, output, prefer_make, overwrite):
"""Generate the Makefile. If the --prefer-make option was passed, copy the
Makefile that contains the installation logic written in Make, otherwise
copy the Makefile that acts as a wrapper around Distutils"""
if prefer_make:
makefile_src = os.path.join(DATADIR, "Makefile.in.make")
else:
makefile_src = os.path.join(DATADIR, "Makefile.in.distutils")
makefile_dst = os.path.join(output, "Makefile.in")
print("Generating Makefile.in")
safe_copy(makefile_src, makefile_dst, overwrite)
def gen_distutils(pkg_meta, output, prefer_make, target, overwrite):
"""Generate the setup.py.in script. If the --prefer-make option was passed,
copy the setup.py.in that wraps the Makefile, otherwise script that uses
'target'. 'target' is a number representing which Python-based distribution
to use. 0 -> distutils """
if prefer_make:
setup_py_src = os.path.join(DATADIR, "setup.py.in.make")
else:
setup_py_file = {0: "setup.py.in.distutils"}.get(target)
if setup_py_file is None:
setup_py_file = "setup.py.in.distutils"
setup_py_src = os.path.join(DATADIR, setup_py_file)
setup_py_dst = os.path.join(output, "setup.py.in")
print("Generating setup.py.in")
if not prefer_make:
if not overwrite and os.path.exists(setup_py_dst):
warnings.warn("setup.py.in exists. Skipping.")
else:
subst_meta(setup_py_src, setup_py_dst, pkg_meta)
else:
safe_copy(setup_py_src, setup_py_dst, overwrite)
def print_usage():
print("""Usage: pyconf [OPTIONS] [TARGET] PKG-INFO
Generate `configure' and installation scripts for a Python program
OPTIONS
-o, --output=DIR directory to move the generated files
(default ".")
-m, --prefer-make prefer using Make for performing installation
logic, instead of the Python-based TARGET
--macros-only copy the pyconfigure M4 macros to the output
directory and exit
--no-make do not generate a Makefile
--overwrite overwrite existing files
--help show this information and exit
--version output version information and exit
TARGETS:
distutils (default)
By default, the generated `Makefile' will be a wrapper around the
TARGET-based script for Python (i.e. distutils' `setup.py' script).
If `--prefer-make' is specified, the TARGET-based Python script will
be a wrapper around `Makefile'.
For more information on the PKG-INFO file format, see PEP 345.
<http://www.python.org/dev/peps/pep-0345/>
Report bugs to: [email protected]
pyconfigure home page: <http://www.gnu.org/software/pyconfigure/>
General help using GNU software: <http://www.gnu.org/get/help/>""")
def print_version():
print("""pyconf (GNU pyconfigure) @PACKAGE_VERSION@
Copyright (C) 2013 Brandon Invergo
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.""")
if __name__ == "__main__":
long_args = ["help", "version", "output", "prefer-make", "no-make",
"overwrite", "macros-only"]
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "hvo:m", long_args)
except getopt.GetoptError as err:
print(str(err))
print_usage()
sys.exit(2)
output = os.getcwd()
prefer_make = False
no_make = False
macros_only = False
overwrite = False
for o, a in opts:
if o in ["-h", "--help"]:
print_usage()
sys.exit()
elif o in ["-v", "--version"]:
print_version()
sys.exit()
elif o in ["-o", "--output"]:
output = a
elif o in ["-m", "--prefer-make"]:
prefer_make = True
elif o == "--no-make":
no_make = True
prefer_make = False
elif o == "--macros-only":
macros_only = True
elif o == "--overwrite":
overwrite = True
else:
print("Warning: unhandled option")
if len(args) == 0:
print_usage()
sys.exit(2)
elif len(args) == 1:
target = 0
pkg_info = args[0]
else:
# do the following with an eye to the future of handling more
# Python packaging systems. Right now, only distutils is supported.
# Choose the target number based on the target selected by the user
# i.e. distutils -> 0
target = {"distutils":0}.get(args[0])
if target is None:
print("Error: invalid target {0}".format(args[0]))
sys.exit(2)
pkg_info = args[1]
if not os.path.isfile(pkg_info):
print("Error: PKG-INFO file does not exist")
sys.exit(2)
print("Running pyconfigure in {0}".format(output))
copy_macros(output)
if macros_only:
sys.exit(0)
print("Parsing metadata...")
pkg_meta = parse_pkg_info(pkg_info)
copy_aux_files(output)
gen_configure(pkg_meta, output, overwrite)
if not no_make:
gen_makefile(pkg_meta, output, prefer_make, overwrite)
# also with an eye to the future. This will be a list of gen_TARGET functions
# and the function is chosen according to the index number 'target'. Since
# only distutils is supported, the list has one element, gen_distutils, and
# only target 0 works
[gen_distutils][target](pkg_meta, output, prefer_make, target, overwrite)
sys.exit(0)
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors_gnu/pyconfigure.git
[email protected]:mirrors_gnu/pyconfigure.git
mirrors_gnu
pyconfigure
pyconfigure
master

搜索帮助