Changeset View
Changeset View
Standalone View
Standalone View
setup.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (C) 2015-2020 The Software Heritage developers | # Copyright (C) 2015-2020 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from distutils.cmd import Command | from distutils.cmd import Command | ||||
from distutils.command.build import build | |||||
from io import open | from io import open | ||||
import os | import os | ||||
import shutil | import shutil | ||||
import subprocess | import subprocess | ||||
import sys | |||||
from setuptools import find_packages, setup | from setuptools import find_packages, setup | ||||
from setuptools.command.build_py import build_py | |||||
from setuptools.command.sdist import sdist | from setuptools.command.sdist import sdist | ||||
here = os.path.abspath(os.path.dirname(__file__)) | here = os.path.abspath(os.path.dirname(__file__)) | ||||
# Get the long description from the README file | # Get the long description from the README file | ||||
with open(os.path.join(here, "README.md"), encoding="utf-8") as f: | with open(os.path.join(here, "README.md"), encoding="utf-8") as f: | ||||
long_description = f.read() | long_description = f.read() | ||||
Show All 32 Lines | |||||
class TSInstallCommand(TSCommand): | class TSInstallCommand(TSCommand): | ||||
description = "Installs node_modules related to query language" | description = "Installs node_modules related to query language" | ||||
def run(self): | def run(self): | ||||
subprocess.run([yarn, "install"], check=True) | subprocess.run([yarn, "install"], check=True) | ||||
class TSGenerateCommand(TSCommand): | |||||
description = "Generates parser related files from grammar.js" | |||||
def run(self): | |||||
subprocess.run([yarn, "generate"], check=True) | |||||
class TSBuildSoCommand(TSCommand): | class TSBuildSoCommand(TSCommand): | ||||
description = "Builds swh_ql.so" | description = "Builds swh_ql.so" | ||||
def initialize_options(self): | |||||
self.build_lib = None | |||||
super().initialize_options() | |||||
def finalize_options(self): | |||||
self.set_undefined_options("build", ("build_lib", "build_lib")) | |||||
super().finalize_options() | |||||
def run(self): | def run(self): | ||||
# setup_requires changes sys.path so the build dependencies | self.run_command("ts_install") | ||||
# can be imported even though they are in a temporary | |||||
# directory (usually `.eggs`). We need to pass this updated sys.path to | ql_dir = os.path.join(self.build_lib, "swh/search/query_language") | ||||
# 'yarn build-so', as it invokes a Python script that needs to import | if not os.path.exists(os.path.join(ql_dir, "src/parser.c")): | ||||
# tree_sitter | generate_parser(ql_dir) | ||||
env = {**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)} | |||||
subprocess.run([yarn, "build-so"], check=True, env=env) | static_dir = os.path.join(self.build_lib, "swh/search/static") | ||||
os.makedirs(static_dir, exist_ok=True) | |||||
# This import cannot be toplevel, as setuptools installs it after the script | |||||
# starts running | |||||
from tree_sitter import Language | |||||
Language.build_library(os.path.join(static_dir, "swh_ql.so"), [ql_dir]) | |||||
print("swh_ql.so file generated") | print("swh_ql.so file generated") | ||||
class TSBuildWasmCommand(TSCommand): | class TSBuildWasmCommand(TSCommand): | ||||
description = "Builds swh_ql.wasm" | description = "Builds swh_ql.wasm" | ||||
def run(self): | def run(self): | ||||
subprocess.run([yarn, "build-wasm"], check=True) | subprocess.run([yarn, "build-wasm"], check=True) | ||||
print("swh_ql.wasm file generated") | print("swh_ql.wasm file generated") | ||||
class TSBuildCommand(TSCommand): | class TSBuildCommand(TSCommand): | ||||
description = "Builds swh_ql.so and swh_ql.wasm" | description = "Builds swh_ql.so and swh_ql.wasm" | ||||
def run(self): | def run(self): | ||||
self.run_command("ts_build_so") | self.run_command("ts_build_so") | ||||
self.run_command("ts_build_wasm") | |||||
class TSBuildExportCommand(TSCommand): | |||||
description = "Builds swh_ql.so and swh_ql.wasm and exports them to static/" | |||||
def initialize_options(self): | |||||
self.build_lib = None | |||||
super().initialize_options() | |||||
def finalize_options(self): | |||||
self.set_undefined_options("build", ("build_lib", "build_lib")) | |||||
super().finalize_options() | |||||
def run(self): | |||||
self.run_command("ts_install") | |||||
self.run_command("ts_build") | |||||
print("static files generated. copying them to package dir") | |||||
os.makedirs(os.path.join(self.build_lib, "swh/search/static"), exist_ok=True) | |||||
shutil.copyfile( | |||||
"query_language/swh_ql.so", | |||||
os.path.join(self.build_lib, "swh/search/static/swh_ql.so"), | |||||
) | |||||
shutil.copyfile( | |||||
"query_language/swh_ql.wasm", | |||||
os.path.join(self.build_lib, "swh/search/static/swh_ql.wasm"), | |||||
) | |||||
class custom_build(build_py): | class custom_build(build): | ||||
def run(self): | def run(self): | ||||
super().run() | super().run() | ||||
if not self.dry_run: | if not self.dry_run: | ||||
self.run_command("ts_build_export") | self.run_command("ts_build") | ||||
class custom_sdist(sdist): | class custom_sdist(sdist): | ||||
def make_release_tree(self, base_dir, files): | def make_release_tree(self, base_dir, files): | ||||
super().make_release_tree(base_dir, files) | super().make_release_tree(base_dir, files) | ||||
# TODO: build the .c file and .wasm but not .so, because it's architecture- | |||||
# dependent, and shouldn't be in a sdist (aka *source* distribution) | dist_ql_path = os.path.join(base_dir, "swh/search/query_language") | ||||
if not self.dry_run: | if not self.dry_run: | ||||
self.run_command("ts_install") | self.run_command("ts_install") | ||||
self.run_command("ts_build") | |||||
print("static files generated. copying them to package dir") | generate_parser(dist_ql_path) | ||||
os.makedirs(os.path.join(base_dir, "swh/search/static"), exist_ok=True) | |||||
shutil.copyfile( | |||||
"query_language/swh_ql.so", | def generate_parser(dest_path): | ||||
os.path.join(base_dir, "swh/search/static/swh_ql.so"), | # FIXME: setuptools should copy this itself... | ||||
) | print("Copying parser files") | ||||
shutil.copyfile( | if os.path.exists(dest_path): | ||||
"query_language/swh_ql.wasm", | shutil.rmtree(dest_path) | ||||
os.path.join(base_dir, "swh/search/static/swh_ql.wasm"), | shutil.copytree("swh/search/query_language", dest_path) | ||||
) | |||||
print("Getting path") | |||||
path = subprocess.check_output([yarn, "bin"]).decode().strip() | |||||
env = {**os.environ, "PATH": os.pathsep.join([path, os.environ["PATH"]])} | |||||
print("Generating") | |||||
subprocess.run(["tree-sitter", "generate", "--no-bindings"], cwd=dest_path, env=env) | |||||
setup( | setup( | ||||
name="swh.search", | name="swh.search", | ||||
description="Software Heritage search service", | description="Software Heritage search service", | ||||
long_description=long_description, | long_description=long_description, | ||||
long_description_content_type="text/markdown", | long_description_content_type="text/markdown", | ||||
python_requires=">=3.7", | python_requires=">=3.7", | ||||
Show All 20 Lines | setup( | ||||
], | ], | ||||
project_urls={ | project_urls={ | ||||
"Bug Reports": "https://forge.softwareheritage.org/maniphest", | "Bug Reports": "https://forge.softwareheritage.org/maniphest", | ||||
"Funding": "https://www.softwareheritage.org/donate", | "Funding": "https://www.softwareheritage.org/donate", | ||||
"Source": "https://forge.softwareheritage.org/source/swh-search", | "Source": "https://forge.softwareheritage.org/source/swh-search", | ||||
"Documentation": "https://docs.softwareheritage.org/devel/swh-search/", | "Documentation": "https://docs.softwareheritage.org/devel/swh-search/", | ||||
}, | }, | ||||
cmdclass={ | cmdclass={ | ||||
"build_py": custom_build, | "build": custom_build, | ||||
"sdist": custom_sdist, | "sdist": custom_sdist, | ||||
"ts_install": TSInstallCommand, | "ts_install": TSInstallCommand, | ||||
"ts_generate": TSGenerateCommand, | |||||
"ts_build_so": TSBuildSoCommand, | "ts_build_so": TSBuildSoCommand, | ||||
"ts_build_wasm": TSBuildWasmCommand, | |||||
"ts_build": TSBuildCommand, | "ts_build": TSBuildCommand, | ||||
"ts_build_export": TSBuildExportCommand, | |||||
}, | }, | ||||
zip_safe=False, | zip_safe=False, | ||||
) | ) |