Skip to content

[RFC][build-script] SR-237: Merge build-script-impl into build-script #2190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions utils-experimental/build-script
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python
# utils/build-script - The ultimate tool for building Swift -----*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------

import os
import sys


PYTHONPATH = os.path.join(os.path.dirname(__file__), 'build-script-impl')
if "PYTHONPATH" in os.environ:
PYTHONPATH += os.pathsep + os.environ["PYTHONPATH"]

env = dict(os.environ)
env.update(PYTHONPATH=PYTHONPATH)

os.execve(sys.executable,
[sys.executable, '-m', 'build_script'] + sys.argv,
env)
5 changes: 5 additions & 0 deletions utils-experimental/build-script-impl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#==============================================================================#
# Ignore coverage report files
#==============================================================================#
/.coverage
/htmlcov
29 changes: 29 additions & 0 deletions utils-experimental/build-script-impl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# build_script_impl

`build_script_impl` holds implementation of Swift build script.

## Tests

You may run unit tests for `build-script` from the command line:

```sh
apple/swift $ python -m unittest discover utils/build-script-impl
```

## Developer notes

- `build-script` : the launcher
- `build-script-impl/`
- `build_script/` : package
- `__main__.py` : main entry point
- `main_normal.py` : the main work flow
- `workspace.py` : `workspace` represents whole source tree.
- `host/` : `host` represents running machine itself. Subclassed depends on
the machine.
- `cmake.py` : represents cmake command.
- `products/` : represents each product to be built.
- `shell.py` : every shell command invocation must be done via this module.
- `utils/` : some utility functions
- `main_preset.py` : sub entry point when `__main__.py` is called with
`--preset`
- `tests/` : TESTS
15 changes: 15 additions & 0 deletions utils-experimental/build-script-impl/build_script/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# build_script/__init__.py -------------------------------------*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
'''
build-script implementation detail
'''
# ----------------------------------------------------------------------------
66 changes: 66 additions & 0 deletions utils-experimental/build-script-impl/build_script/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# build_script/__main__.py --------------------------------------*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
"""
The entry point for Swift build script
"""
# ----------------------------------------------------------------------------

from __future__ import absolute_import

import sys
import os.path

from . import env
from .utils import printf_with_argv0
from .exceptions import BuildError, CalledProcessError


def main():

if not env.SWIFT_SOURCE_ROOT:
printf_with_argv0(
"Could not infer source root directory. "
"Forgot to set $SWIFT_SOURCE_ROOT environment variable?")
return 1

if not os.path.isdir(env.SWIFT_SOURCE_ROOT):
printf_with_argv0(
"Source root directory '{0}' does not exists. "
"Forgot to set $SWIFT_SOURCE_ROOT environment variable?",
env.SWIFT_SOURCE_ROOT)
return 1

# Determine if we are invoked in the preset mode and dispatch accordingly.
if any([(opt.startswith("--preset") or opt == "--show-presets")
for opt in sys.argv[1:]]):
from .main_preset import main as impl_main
else:
from .main_driver import main as impl_main

try:
return impl_main(sys.argv)
except (OSError, CalledProcessError, BuildError) as e:
printf_with_argv0("Error: {0}", e)
return 1

return 0


if __name__ == "__main__":
# Since this script is invoked from ./utils/build-script like:
#
# python -m build_script ./utils/build-script --options ...
#
# argv[0] is "path/to/build_script/__main__.py".
# Shift sys.argv so that we can process it normally.
sys.argv = sys.argv[1:]
sys.exit(main())
194 changes: 194 additions & 0 deletions utils-experimental/build-script-impl/build_script/_shell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# build_script/shell.py -----------------------------------------*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
"""
Implementaion detail of build_script.shell module.
"""
# ----------------------------------------------------------------------------
from __future__ import print_function

import os
import sys
import shutil
import pipes
import subprocess
from contextlib import contextmanager


def _print_line(line):
print(line)
# To prevent mixed output with executed command output.
sys.stdout.flush()


def _print_command(args, env=None, prompt="+ "):
output = []

def q(val):
return pipes.quote(str(val))

if env is not None:
output += ['env'] + [q("%s=%s" % (k, v)) for k, v in env]
output += [q(arg) for arg in args]
_print_line(prompt + ' '.join(output))


@contextmanager
def pushd(path, echo=True, dry_run=False):
old_dir = os.getcwd()
if echo or dry_run:
_print_command(["pushd", path])
if not dry_run:
os.chdir(path)
yield
if echo or dry_run:
_print_command(["popd"])
if not dry_run:
os.chdir(old_dir)


def chdir(path, echo=True, dry_run=False):
if echo or dry_run:
_print_command(["cd", path])
if dry_run:
return

os.chdir(path)


def query(args, env=None, stderr=subprocess.PIPE, echo=False, strip=True):
'''
Run command and returns its output.
'''
if echo:
_print_command(args, env)

if env is not None:
env = dict(os.environ.items() + env)
out = subprocess.check_output(args, stderr=stderr, env=env)
# Coerce to `str`. Not `bytes`(py3), not `unicode`(py2)
out = str(out.decode())
if strip:
out = out.strip()
return out


def execv(args, echo=True, dry_run=False):
'''
Execute given command, replacing current process. Never return.
'''
if echo or dry_run:
_print_command(args)
if dry_run:
# FIXME: I'm not sure what to to for `execv` dry-run.
sys.exit(0)

os.execv(args[0], args)


def invoke(args, env=None, echo=True, dry_run=False):
'''
Invoke given command
'''
if echo or dry_run:
_print_command(args, env)
if dry_run:
return

if env is not None:
env = dict(os.environ.items() + env)
subprocess.check_call(args, env=env)


def runscript(script, env=None, ignore_errors=False, echo=True, dry_run=False):
prompt = '++ '
if dry_run:
import shlex
for command in script.splitlines():
_print_command(shlex.split(command), prompt=prompt)
return

cmd = ['sh', ]
if not ignore_errors:
cmd += ['-e', ]
if echo:
cmd += ['-x', ]

env = dict(os.environ)
env['PS4'] = prompt
if env is not None:
env.update(env)

pipe = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE)
pipe.communicate(script.encode())
if pipe.returncode != 0:
raise subprocess.CalledProcessError(pipe.returncode, script)


def copy(src, dst, echo=True, dry_run=False):
if echo or dry_run:
_print_command(['cp', src, dst])
if dry_run:
return

shutil.copy(src, dst)


def remove(path, echo=True, dry_run=False):
if echo or dry_run:
_print_command(['rm', path])
if dry_run:
return

os.remove(path)


def makedirs(directory, echo=True, dry_run=False):
if echo or dry_run:
_print_command(['mkdir', '-p', directory])
if dry_run:
return

os.makedirs(directory)


def rmtree(path, echo=True, dry_run=False):
if echo or dry_run:
_print_command(['rm', '-rf', path])
if dry_run:
return

shutil.rmtree(path)


def copytree(src, dst, symlinks=False, echo=True, dry_run=False):
if echo or dry_run:
_print_command(['cp', '-r', src, dst])
if dry_run:
return

shutil.copytree(src, dst, symlinks=symlinks)


def symlink(source, link_name, relative=False, echo=True, dry_run=False):
'''
Create symbolic link
'''
if relative:
target_dir = os.path.dirname(link_name)
source = os.path.relpath(source, target_dir)

if echo or dry_run:
_print_command(['ln', '-s', source, link_name])
if dry_run:
return

os.symlink(source, link_name)
Loading