-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #77 from kif/meson
Meson
- Loading branch information
Showing
85 changed files
with
1,223 additions
and
2,004 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
name: Pylint | ||
|
||
on: [push] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: ["3.8", "3.9", "3.10"] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v3 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install pylint | ||
- name: Analysing the code with pylint | ||
run: | | ||
pylint $(git ls-files '*.py') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,73 +10,94 @@ | |
__authors__ = ["Frédéric-Emmanuel Picca", "Jérôme Kieffer"] | ||
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__date__ = "09/07/2020" | ||
__date__ = "03/03/2023" | ||
|
||
import sys | ||
import os | ||
import distutils.util | ||
import subprocess | ||
import logging | ||
import collections | ||
from argparse import ArgumentParser | ||
|
||
if sys.version_info[:2] < (3, 11): | ||
import tomli | ||
else: | ||
import tomllib as tomli | ||
logging.basicConfig() | ||
logger = logging.getLogger("bootstrap") | ||
|
||
|
||
def is_debug_python(): | ||
"""Returns true if the Python interpreter is in debug mode.""" | ||
try: | ||
import sysconfig | ||
except ImportError: # pragma nocover | ||
# Python < 2.7 | ||
import distutils.sysconfig as sysconfig | ||
def get_project_name(root_dir): | ||
"""Retrieve project name by running python setup.py --name in root_dir. | ||
if sysconfig.get_config_var("Py_DEBUG"): | ||
return True | ||
:param str root_dir: Directory where to run the command. | ||
:return: The name of the project stored in root_dir | ||
""" | ||
logger.debug("Getting project name in %s", root_dir) | ||
with open("pyproject.toml") as f: | ||
pyproject = tomli.loads(f.read()) | ||
return pyproject.get("project", {}).get("name") | ||
|
||
return hasattr(sys, "gettotalrefcount") | ||
|
||
def build_project(name, root_dir): | ||
"""Build locally the project using meson | ||
def _distutils_dir_name(dname="lib"): | ||
""" | ||
Returns the name of a distutils build directory | ||
:param str name: Name of the project. | ||
:param str root_dir: Root directory of the project | ||
:return: The path to the directory were build was performed | ||
""" | ||
platform = distutils.util.get_platform() | ||
architecture = "%s.%s-%i.%i" % (dname, platform, | ||
sys.version_info[0], sys.version_info[1]) | ||
if is_debug_python(): | ||
architecture += "-pydebug" | ||
return architecture | ||
|
||
|
||
def _distutils_scripts_name(): | ||
"""Return the name of the distrutils scripts sirectory""" | ||
f = "scripts-{version[0]}.{version[1]}" | ||
return f.format(version=sys.version_info) | ||
extra = [] | ||
libdir = "lib" | ||
if sys.platform == "win32": | ||
libdir = "Lib" | ||
# extra = ["--buildtype", "plain"] | ||
|
||
build = os.path.join(root_dir, "build") | ||
if not(os.path.isdir(build) and os.path.isdir(os.path.join(build, name))): | ||
p = subprocess.Popen(["meson", "setup", "build"], | ||
shell=False, cwd=root_dir, env=os.environ) | ||
p.wait() | ||
p = subprocess.Popen(["meson", "configure", "--prefix", "/"] + extra, | ||
shell=False, cwd=build, env=os.environ) | ||
p.wait() | ||
p = subprocess.Popen(["meson", "install", "--destdir", "."], | ||
shell=False, cwd=build, env=os.environ) | ||
logger.debug("meson install ended with rc= %s", p.wait()) | ||
|
||
home = None | ||
if os.environ.get("PYBUILD_NAME") == name: | ||
# we are in the debian packaging way | ||
home = os.environ.get("PYTHONPATH", "").split(os.pathsep)[-1] | ||
if not home: | ||
if os.environ.get("BUILDPYTHONPATH"): | ||
home = os.path.abspath(os.environ.get("BUILDPYTHONPATH", "")) | ||
else: | ||
if sys.platform == "win32": | ||
home = os.path.join(build, libdir, "site-packages") | ||
else: | ||
python_version = f"python{sys.version_info.major}.{sys.version_info.minor}" | ||
home = os.path.join(build, libdir, python_version, "site-packages") | ||
home = os.path.abspath(home) | ||
|
||
cnt = 0 | ||
while not os.path.isdir(home): | ||
cnt += 1 | ||
home = os.path.split(home)[0] | ||
for _ in range(cnt): | ||
n = os.listdir(home)[0] | ||
home = os.path.join(home, n) | ||
|
||
def _get_available_scripts(path): | ||
res = [] | ||
try: | ||
res = " ".join([s.rstrip('.py') for s in os.listdir(path)]) | ||
except OSError: | ||
res = ["no script available, did you ran " | ||
"'python setup.py build' before bootstrapping ?"] | ||
return res | ||
logger.warning("Building %s to %s", name, home) | ||
|
||
return home | ||
|
||
if sys.version_info[0] >= 3: # Python3 | ||
|
||
def execfile(fullpath, globals=None, locals=None): | ||
"Python3 implementation for execfile" | ||
with open(fullpath) as f: | ||
try: | ||
data = f.read() | ||
except UnicodeDecodeError: | ||
raise SyntaxError("Not a Python script") | ||
code = compile(data, fullpath, 'exec') | ||
exec(code, globals, locals) | ||
def execfile(fullpath, globals=None, locals=None): | ||
"Python3 implementation for execfile" | ||
with open(fullpath) as f: | ||
try: | ||
data = f.read() | ||
except UnicodeDecodeError: | ||
raise SyntaxError("Not a Python script") | ||
code = compile(data, fullpath, 'exec') | ||
exec(code, globals, locals) | ||
|
||
|
||
def run_file(filename, argv): | ||
|
@@ -117,21 +138,18 @@ def run_file(filename, argv): | |
run.wait() | ||
|
||
|
||
def run_entry_point(entry_point, argv): | ||
def run_entry_point(target_name, entry_point, argv): | ||
""" | ||
Execute an entry_point using the current python context | ||
(http://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation) | ||
:param str entry_point: A string identifying a function from a module | ||
(NAME = PACKAGE.MODULE:FUNCTION [EXTRA]) | ||
(NAME = PACKAGE.MODULE:FUNCTION) | ||
:param argv: list of arguments | ||
""" | ||
import importlib | ||
elements = entry_point.split("=") | ||
target_name = elements[0].strip() | ||
elements = elements[1].split(":") | ||
elements = entry_point.split(":") | ||
module_name = elements[0].strip() | ||
# Take care of entry_point optional "extra" requirements declaration | ||
function_name = elements[1].split()[0].strip() | ||
function_name = elements[1].strip() | ||
|
||
logger.info("Execute target %s (function %s from module %s) using importlib", target_name, function_name, module_name) | ||
full_args = [target_name] | ||
|
@@ -163,74 +181,49 @@ def find_executable(target): | |
if os.path.isfile(target): | ||
return ("path", os.path.abspath(target)) | ||
|
||
# search the file from setup.py | ||
import setup | ||
config = setup.get_project_configuration(dry_run=True) | ||
# scripts from project configuration | ||
if "scripts" in config: | ||
for script_name in config["scripts"]: | ||
if os.path.basename(script_name) == target: | ||
return ("path", os.path.abspath(script_name)) | ||
# entry-points from project configuration | ||
if "entry_points" in config: | ||
for kind in config["entry_points"]: | ||
for entry_point in config["entry_points"][kind]: | ||
elements = entry_point.split("=") | ||
name = elements[0].strip() | ||
if name == target: | ||
return ("entry_point", entry_point) | ||
|
||
# search the file from env PATH | ||
for dirname in os.environ.get("PATH", "").split(os.pathsep): | ||
path = os.path.join(dirname, target) | ||
if os.path.isfile(path): | ||
return ("path", path) | ||
# search the executable in pyproject.toml | ||
with open(os.path.join(PROJECT_DIR, "pyproject.toml")) as f: | ||
pyproject = tomli.loads(f.read()) | ||
|
||
scripts = {} | ||
scripts.update(pyproject.get("project", {}).get("scripts", {})) | ||
scripts.update(pyproject.get("project", {}).get("gui-scripts", {})) | ||
|
||
for script, entry_point in scripts.items(): | ||
if script == target: | ||
print(script, entry_point) | ||
return ("entry_point", target, entry_point) | ||
return None, None | ||
|
||
|
||
def main(argv): | ||
parser = ArgumentParser(prog="bootstrap", usage="./bootstrap.py <script>", | ||
description=__doc__) | ||
parser.add_argument("script", nargs="*") | ||
parser.add_argument("-m", help="run library module as a script (terminates option list)") | ||
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
PROJECT_NAME = get_project_name(PROJECT_DIR) | ||
logger.info("Project name: %s", PROJECT_NAME) | ||
|
||
Options = collections.namedtuple("Options", ["script", "module"]) | ||
if len(argv) == 1: | ||
options = Options(script=None, module=None) | ||
if __name__ == "__main__": | ||
LIBPATH = build_project(PROJECT_NAME, PROJECT_DIR) | ||
if len(sys.argv) < 2: | ||
logger.warning("usage: ./bootstrap.py <script>\n") | ||
script = None | ||
else: | ||
if argv[1] in ["-h", "--help"]: | ||
parser.print_help() | ||
return | ||
if argv[1] == "-m": | ||
if len(argv) < 3: | ||
parser.parse_args(argv[1:]) | ||
return | ||
options = Options(script=None, module=argv[2:]) | ||
else: | ||
options = Options(script=argv[1:], module=None) | ||
|
||
if options.script is not None: | ||
logger.info("Executing %s from source checkout", options.script) | ||
script = options.script[0] | ||
argv = options.script[1:] | ||
kind, target = find_executable(script) | ||
if kind == "path": | ||
run_file(target, argv) | ||
elif kind == "entry_point": | ||
run_entry_point(target, argv) | ||
script = sys.argv[1] | ||
|
||
if script: | ||
logger.info("Executing %s from source checkout", script) | ||
else: | ||
logging.info("Running iPython by default") | ||
sys.path.insert(0, LIBPATH) | ||
logger.info("Patched sys.path with %s", LIBPATH) | ||
|
||
if script: | ||
argv = sys.argv[2:] | ||
res = find_executable(script) | ||
if res[0] == "path": | ||
run_file(res[1], argv) | ||
elif res[0] == "entry_point": | ||
run_entry_point(res[1], res[2], argv) | ||
else: | ||
logger.error("Script %s not found", options.script) | ||
elif options.module is not None: | ||
logging.info("Running module %s", options.module) | ||
import runpy | ||
module = options.module[0] | ||
try: | ||
old = sys.argv | ||
sys.argv = [None] + options.module[1:] | ||
runpy.run_module(module, run_name="__main__", alter_sys=True) | ||
finally: | ||
sys.argv = old | ||
logger.error("Script %s not found", script) | ||
else: | ||
logging.info("Running IPython by default") | ||
logger.info("Patch the sys.argv: %s", sys.argv) | ||
|
@@ -245,28 +238,3 @@ def main(argv): | |
else: | ||
embed() | ||
|
||
|
||
if __name__ == "__main__": | ||
home = os.path.dirname(os.path.abspath(__file__)) | ||
LIBPATH = os.path.join(home, 'build', _distutils_dir_name('lib')) | ||
cwd = os.getcwd() | ||
os.chdir(home) | ||
build = subprocess.Popen([sys.executable, "setup.py", "build"], | ||
shell=False, cwd=os.path.dirname(os.path.abspath(__file__))) | ||
build_rc = build.wait() | ||
if not os.path.exists(LIBPATH): | ||
logger.warning("`lib` directory does not exist, trying common Python3 lib") | ||
LIBPATH = os.path.join(os.path.split(LIBPATH)[0], "lib") | ||
os.chdir(cwd) | ||
|
||
if build_rc == 0: | ||
logger.info("Build process ended.") | ||
else: | ||
logger.error("Build process ended with rc=%s", build_rc) | ||
sys.exit(-1) | ||
|
||
sys.path.insert(0, LIBPATH) | ||
logger.info("Patched sys.path with %s", LIBPATH) | ||
|
||
main(sys.argv) | ||
|
Oops, something went wrong.