-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bootstrap: add initial implementation
Has some rough edges, but seems to be working. Signed-off-by: Filipe Laíns <[email protected]>
- Loading branch information
Showing
3 changed files
with
207 additions
and
0 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,138 @@ | ||
# SPDX-License-Identifier: MIT | ||
|
||
import atexit | ||
import logging | ||
import os | ||
import pathlib | ||
import shutil | ||
import subprocess | ||
import sys | ||
import tempfile | ||
|
||
from collections.abc import Collection, Mapping, Sequence | ||
from typing import NamedTuple, Optional, Tuple | ||
|
||
|
||
class Package(NamedTuple): | ||
srcdir: pathlib.Path | ||
module_path: pathlib.Path | ||
module_sources: Collection[str] | ||
|
||
|
||
ROOT = pathlib.Path(__file__).parent.parent | ||
WORKING_DIR = ROOT / '.bootstrap' | ||
MODULES = WORKING_DIR / 'modules' | ||
TMPDIR = WORKING_DIR / 'tmp' | ||
EXTERNAL = ROOT / 'external' | ||
|
||
PACKAGES = { | ||
# what we need | ||
'build': Package( | ||
EXTERNAL / 'build', | ||
EXTERNAL / 'build' / 'src', | ||
{'build'}, | ||
), | ||
'installer': Package( | ||
EXTERNAL / 'installer', | ||
EXTERNAL / 'installer' / 'src', | ||
{'installer'}, | ||
), | ||
# dependencies | ||
'setuptools': Package( | ||
EXTERNAL / 'setuptools', | ||
EXTERNAL / 'setuptools', | ||
{'setuptools', 'pkg_resources', '_distutils_hack'}, | ||
), | ||
'flit_core': Package( | ||
EXTERNAL / 'flit' / 'flit_core', | ||
EXTERNAL / 'flit' / 'flit_core', | ||
{'flit_core'}, | ||
), | ||
'wheel': Package( | ||
EXTERNAL / 'wheel', | ||
EXTERNAL / 'wheel' / 'src', | ||
{'wheel'}, | ||
), | ||
'tomli': Package( | ||
EXTERNAL / 'tomli', | ||
EXTERNAL / 'tomli', | ||
{'tomli'}, | ||
), | ||
'pep517': Package( | ||
EXTERNAL / 'pep517', | ||
EXTERNAL / 'pep517', | ||
{'pep517'}, | ||
), | ||
} | ||
|
||
EXTRA_PATH = [str(package.module_path) for package in PACKAGES.values()] | ||
PACKAGE_PATH_ENV = { | ||
'PYTHONPATH': os.path.pathsep.join(EXTRA_PATH), | ||
} | ||
|
||
|
||
# copy sources to module dir and inject it into sys.path | ||
MODULES.mkdir(parents=True) | ||
for package in PACKAGES.values(): | ||
for path in package.module_sources: | ||
shutil.copytree( | ||
package.module_path / path, | ||
MODULES / path, | ||
) | ||
atexit.register(shutil.rmtree, MODULES) | ||
sys.path.insert(0, str(MODULES)) | ||
|
||
|
||
# import what we need from the inject modules | ||
import build # noqa: E402 | ||
import build.env # noqa: E402 | ||
import pep517 # noqa: E402 | ||
|
||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
def log(msg): | ||
_logger.info(msg) | ||
|
||
|
||
# not needed after https://github.com/pypa/build/pull/361 | ||
def create_isolated_env_venv_no_pip(path: str) -> Tuple[str, str]: | ||
import venv | ||
|
||
venv.EnvBuilder(symlinks=build.env._fs_supports_symlink()).create(path) | ||
executable, script_dir, purelib = build.env._find_executable_and_scripts(path) | ||
|
||
return executable, script_dir | ||
|
||
|
||
def custom_runner( | ||
cmd: Sequence[str], | ||
cwd: Optional[str] = None, | ||
extra_environ: Optional[Mapping[str, str]] = None, | ||
) -> None: | ||
extra_environ = dict(extra_environ) if extra_environ else {} | ||
extra_environ.update(PACKAGE_PATH_ENV) | ||
pep517.default_subprocess_runner(cmd, cwd, extra_environ) | ||
|
||
|
||
def build_package(name: str, outdir: pathlib.Path) -> pathlib.Path: | ||
log(f'Building {name}...') | ||
|
||
if name == 'setuptools': | ||
# setuptools needs to think that wheel is installed, so we inject its metadata | ||
wheel_src = PACKAGES['wheel'].srcdir | ||
subprocess.check_call( | ||
[sys.executable, 'setup.py', 'egg_info'], | ||
env=os.environ | PACKAGE_PATH_ENV, | ||
cwd=wheel_src | ||
) | ||
shutil.copytree( | ||
wheel_src / 'src' / 'wheel.egg-info', | ||
MODULES / 'wheel.egg-info', | ||
) | ||
|
||
srcdir = PACKAGES[name].srcdir | ||
builder = build.ProjectBuilder(str(srcdir), runner=custom_runner) | ||
wheel = builder.build('wheel', str(outdir)) | ||
return pathlib.Path(wheel) |
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,57 @@ | ||
# SPDX-License-Identifier: MIT | ||
|
||
import argparse | ||
import json | ||
import logging | ||
import pathlib | ||
import shutil | ||
import sys | ||
|
||
from typing import Dict, Optional | ||
from collections.abc import Sequence | ||
|
||
import bootstrap | ||
|
||
|
||
def main_parser() -> argparse.ArgumentParser: | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument( | ||
'--outdir', | ||
'-o', | ||
type=str, | ||
default='dist', | ||
help='output directory (defaults to `dist`)', | ||
) | ||
return parser | ||
|
||
|
||
def main(cli_args: Sequence[str], prog: Optional[str] = None): | ||
parser = main_parser() | ||
if prog: | ||
parser.prog = prog | ||
args, unknown = parser.parse_known_args(cli_args) | ||
|
||
logging.basicConfig(level=logging.INFO) | ||
|
||
outdir = pathlib.Path(args.outdir).absolute() | ||
if outdir.exists(): | ||
if not outdir.is_dir(): | ||
raise NotADirectoryError(f"{str(outdir)} exists and it's not a directory") | ||
shutil.rmtree(outdir) | ||
outdir.mkdir(parents=True) | ||
|
||
artifacts = { | ||
package: bootstrap.build_package(package, outdir) | ||
for package in bootstrap.PACKAGES | ||
} | ||
outdir.joinpath('artifacts.json').write_text(json.dumps({ | ||
package: path.name for package, path in artifacts.items() | ||
})) | ||
|
||
print(f'Written wheels to `{str(args.outdir)}`:' + ''.join(sorted( | ||
f'\n\t{artifact.name}' for artifact in artifacts.values() | ||
))) | ||
|
||
|
||
if __name__ == '__main__': | ||
main(sys.argv[1:], 'python -m bootstra.build') |
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,12 @@ | ||
# SPDX-License-Identifier: MIT | ||
|
||
import sys | ||
|
||
import bootstrap # noqa: F401 | ||
|
||
# bootstrap injects the extra sources | ||
import installer.__main__ # noqa: E402 | ||
|
||
|
||
if __name__ == '__main__': | ||
installer.__main__.main(sys.argv[1:], 'python -m bootstrap.install') |