Skip to content

[Build System: build-script] Adds a new xcrun module to build_swift. #29315

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

Merged
merged 1 commit into from
Jan 20, 2020
Merged
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
8 changes: 3 additions & 5 deletions utils/build-parser-lib
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ import platform
import sys

from build_swift.build_swift import argparse, defaults
from swift_build_support.swift_build_support import (
shell,
xcrun,
)
from build_swift.build_swift.wrappers import xcrun

from swift_build_support.swift_build_support import shell
from swift_build_support.swift_build_support.SwiftBuildSupport import (
HOME,
SWIFT_BUILD_ROOT,
SWIFT_SOURCE_ROOT,
)
Expand Down
5 changes: 4 additions & 1 deletion utils/build_swift/build_swift/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,12 @@ def check_output(command, **kwargs):
Output is returned as a unicode string.
"""

if six.PY3:
kwargs['encoding'] = 'utf-8'

output = subprocess.check_output(command, **kwargs)

if _PY_VERSION >= (3, 0):
if six.PY3:
return output

# Return unicode string rather than bytes in Python 2.
Expand Down
20 changes: 20 additions & 0 deletions utils/build_swift/build_swift/wrappers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors


from __future__ import absolute_import, unicode_literals

from . import xcrun as _xcrun


__all__ = [
'xcrun',
]


xcrun = _xcrun.XcrunWrapper()
197 changes: 197 additions & 0 deletions utils/build_swift/build_swift/wrappers/xcrun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors


"""
Wrapper module around the 'xcrun' command-line utility.
"""


from __future__ import absolute_import, unicode_literals

import functools
import re
import shlex

import six

from .. import shell
from ..versions import Version


__all__ = [
'XcrunWrapper',
]


# -----------------------------------------------------------------------------
# Constants

_VERSION_PATTERN = re.compile(r'^xcrun version (?P<version>[0-9.]+)\.$')


# -----------------------------------------------------------------------------
# Helpers

def _catch_return_none(exceptions):
"""Decorator used to catch exceptions and return None.
"""

def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except exceptions:
return None

return wrapper
return decorator


def _prepend_sdk_and_toolchain(func):
"""Method decorator used to prepend the sdk and toolchain arguments to the
final command passed to xcrun.
"""

@functools.wraps(func)
def wrapper(self, args, sdk=None, toolchain=None, **kwargs):
if isinstance(args, six.string_types):
args = shlex.split(args)
if toolchain:
args = ['--toolchain', toolchain] + args
if sdk:
args = ['--sdk', sdk] + args

return func(self, args, **kwargs)
return wrapper


# -----------------------------------------------------------------------------

class XcrunWrapper(shell.ExecutableWrapper):
"""Wrapper class around the 'xcrun' command-line utility.
"""

EXECUTABLE = shell.which('xcrun') or 'xcrun'

@_prepend_sdk_and_toolchain
def Popen(self, args, **kwargs):
return super(XcrunWrapper, self).Popen(args, **kwargs)

@_prepend_sdk_and_toolchain
def call(self, args, **kwargs):
return super(XcrunWrapper, self).call(args, **kwargs)

@_prepend_sdk_and_toolchain
def check_call(self, args, **kwargs):
return super(XcrunWrapper, self).check_call(args, **kwargs)

@_prepend_sdk_and_toolchain
def check_output(self, args, **kwargs):
return super(XcrunWrapper, self).check_output(args, **kwargs)

# -------------------------------------------------------------------------

@property
@_catch_return_none(shell.CalledProcessError)
def version(self):
"""Returns the xcrun version.
"""

output = self.check_output('--version')
matches = _VERSION_PATTERN.match(output.rstrip())
if matches:
return Version(matches.group('version'))

return None

# -------------------------------------------------------------------------
# Subcommands

@_catch_return_none(shell.CalledProcessError)
def find(self, tool, sdk=None, toolchain=None):
"""Finds and returns the path to tool using xcrun. Returns None if the
tool cannot be found.
"""

return self.check_output(
['--find', tool],
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL).rstrip()

def kill_cache(self):
"""Kills the xcrun cache. Returns the status code from the command.
"""

return self.call('--kill-cache')

@_catch_return_none(shell.CalledProcessError)
def sdk_path(self, sdk=None, toolchain=None):
"""Returns the SDK path. Returns None if the SDK cannot be found.
"""

return self.check_output(
'--show-sdk-path',
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL).rstrip()

@_catch_return_none(shell.CalledProcessError)
def sdk_version(self, sdk=None, toolchain=None):
"""Returns the SDK version. Returns None if the SDK cannot be found.
"""

output = self.check_output(
'--show-sdk-version',
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL)

return Version(output.rstrip())

@_catch_return_none(shell.CalledProcessError)
def sdk_build_version(self, sdk=None, toolchain=None):
"""Returns the SDK build version. Returns None if the SDK cannot be
found.
"""

output = self.check_output(
'--show-sdk-build-version',
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL)

return Version(output.rstrip())

@_catch_return_none(shell.CalledProcessError)
def sdk_platform_path(self, sdk=None, toolchain=None):
"""Returns the SDK platform path. Returns None if the SDK cannot be
found.
"""

return self.check_output(
'--show-sdk-platform-path',
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL).rstrip()

@_catch_return_none(shell.CalledProcessError)
def sdk_platform_version(self, sdk=None, toolchain=None):
"""Returns the SDK platform version. Returns None if the SDK cannot be
found.
"""

output = self.check_output(
'--show-sdk-platform-version',
sdk=sdk,
toolchain=toolchain,
stderr=shell.DEVNULL)

return Version(output.rstrip())
13 changes: 8 additions & 5 deletions utils/build_swift/tests/build_swift/test_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# Python 3.4
from pathlib import Path
except ImportError:
Path = None
pass

try:
# Python 3.3
Expand Down Expand Up @@ -368,17 +368,20 @@ def test_check_call(self, mock_check_call):
@patch('subprocess.check_output')
def test_check_output(self, mock_check_output):
# Before Python 3 the subprocess.check_output function returned bytes.
if six.PY2:
mock_check_output.return_value = b''
else:
if six.PY3:
mock_check_output.return_value = ''
else:
mock_check_output.return_value = b''

output = shell.check_output('ls')

# We always expect str (utf-8) output
self.assertIsInstance(output, six.text_type)

mock_check_output.assert_called_with('ls')
if six.PY3:
mock_check_output.assert_called_with('ls', encoding='utf-8')
else:
mock_check_output.assert_called_with('ls')


class TestShellUtilities(unittest.TestCase):
Expand Down
7 changes: 7 additions & 0 deletions utils/build_swift/tests/build_swift/wrappers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
Loading