Skip to content
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

use liblzma.dylib for xz on osx and add platform-specific testing to the rust osx shard #5936

Merged
merged 16 commits into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
f607ea3
vary the xz shared lib filename depending on the current platform
cosmicexplorer Jun 8, 2018
3b4e07c
use the correct key 'mac' instead of 'darwin' into the platform
cosmicexplorer Jun 8, 2018
7a9f397
add `platform_specific_behavior` tag to python native code tests and …
cosmicexplorer Jun 8, 2018
b34dbb1
use self._liblzma_shared_lib_filename to make xz error messages more …
cosmicexplorer Jun 8, 2018
633a2b6
don't re-run platform-specific test sources twice in linux
cosmicexplorer Jun 8, 2018
0b493d5
add the bootstrap phase to the platform-specific python testing in th…
cosmicexplorer Jun 8, 2018
a1617a9
don't re-run platform-specific integration tests either on linux
cosmicexplorer Jun 8, 2018
4f78bbe
increase the timeout on platform-specific testing
cosmicexplorer Jun 8, 2018
34bd769
use the correct platform-specific library search path for the xz exe
cosmicexplorer Jun 9, 2018
62892ca
fix library path handling by using get_joined_path()
cosmicexplorer Jun 11, 2018
fe240da
remove library path manipulation thanks to pantsbuild/binaries#71
cosmicexplorer Jun 11, 2018
ff93b84
bump default_version and add comment
cosmicexplorer Jun 12, 2018
b43003b
set our member variable which was accidentally removed
cosmicexplorer Jun 12, 2018
bc5c0e0
remove pants-side xz execution wrapping
cosmicexplorer Jun 12, 2018
cead478
bump default xz version to match binary archive with wrapper script
cosmicexplorer Jun 12, 2018
1a38e92
sync up with pantsbuild/binaries#74
cosmicexplorer Jun 13, 2018
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
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,15 @@ matrix:
osx_image: xcode8.3
language: generic
env:
- SHARD="Rust Tests OSX"
- SHARD="Rust + Platform-specific Tests OSX"
before_install:
- brew tap caskroom/cask && brew update && brew cask install osxfuse
before_script:
- ulimit -c unlimited
- ulimit -n 8192
script:
- ./build-support/bin/ci.sh -bcfjklmnprtx
# Platform-specific tests currently need a pants pex, so we bootstrap here (no -b) and set -z to run the platform-specific tests.
- ./build-support/bin/ci.sh -cfjklmnprtxz

deploy:
# See: https://docs.travis-ci.com/user/deployment/s3/
Expand Down
79 changes: 48 additions & 31 deletions build-support/bin/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,40 @@ cd ${REPO_ROOT}
source build-support/common.sh

function usage() {
echo "Runs commons tests for local or hosted CI."
echo
echo "Usage: $0 (-h|-fxbkmsrjlpuyncia)"
echo " -h print out this help message"
echo " -f skip python code formatting checks"
echo " -x skip bootstrap clean-all (assume bootstrapping from a"
echo " fresh clone)"
echo " -b skip bootstraping pants from local sources"
echo " -k skip bootstrapped pants self compile check"
echo " -m skip sanity checks of bootstrapped pants and repo BUILD"
echo " files"
echo " -r skip doc generation tests"
echo " -j skip core jvm tests"
echo " -l skip internal backends python tests"
echo " -p skip core python tests"
echo " -u SHARD_NUMBER/TOTAL_SHARDS"
echo " if running core python tests, divide them into"
echo " TOTAL_SHARDS shards and just run those in SHARD_NUMBER"
echo " to run only even tests: '-u 0/2', odd: '-u 1/2'"
echo " -n skip contrib python tests"
echo " -e skip rust tests"
echo " -y SHARD_NUMBER/TOTAL_SHARDS"
echo " if running contrib python tests, divide them into"
echo " TOTAL_SHARDS shards and just run those in SHARD_NUMBER"
echo " to run only even tests: '-u 0/2', odd: '-u 1/2'"
echo " -c skip pants integration tests (includes examples and testprojects)"
echo " -i SHARD_NUMBER/TOTAL_SHARDS"
echo " if running integration tests, divide them into"
echo " TOTAL_SHARDS shards and just run those in SHARD_NUMBER"
echo " to run only even tests: '-i 0/2', odd: '-i 1/2'"
cat <<EOF
Runs commons tests for local or hosted CI.
Usage: $0 (-h|-fxbkmsrjlpuyncia)
-h print out this help message
-f skip python code formatting checks
-x skip bootstrap clean-all (assume bootstrapping from a
fresh clone)
-b skip bootstraping pants from local sources
-k skip bootstrapped pants self compile check
-m skip sanity checks of bootstrapped pants and repo BUILD
files
-r skip doc generation tests
-j skip core jvm tests
-l skip internal backends python tests
-p skip core python tests
-u SHARD_NUMBER/TOTAL_SHARDS
if running core python tests, divide them into
TOTAL_SHARDS shards and just run those in SHARD_NUMBER
to run only even tests: '-u 0/2', odd: '-u 1/2'
-n skip contrib python tests
-e skip rust tests
-y SHARD_NUMBER/TOTAL_SHARDS
if running contrib python tests, divide them into
TOTAL_SHARDS shards and just run those in SHARD_NUMBER
to run only even tests: '-u 0/2', odd: '-u 1/2'
-c skip pants integration tests (includes examples and testprojects)
-i SHARD_NUMBER/TOTAL_SHARDS
if running integration tests, divide them into
TOTAL_SHARDS shards and just run those in SHARD_NUMBER
to run only even tests: '-i 0/2', odd: '-i 1/2'
-t skip lint
-z test platform-specific behavior
EOF
if (( $# > 0 )); then
die "$@"
else
Expand All @@ -57,7 +61,7 @@ python_unit_shard="0/1"
python_contrib_shard="0/1"
python_intg_shard="0/1"

while getopts "hfxbkmsrjlpeu:ny:ci:at" opt; do
while getopts "hfxbkmrjlpeu:ny:ci:tz" opt; do
case ${opt} in
h) usage ;;
f) skip_pre_commit_checks="true" ;;
Expand All @@ -76,6 +80,7 @@ while getopts "hfxbkmsrjlpeu:ny:ci:at" opt; do
c) skip_integration="true" ;;
i) python_intg_shard=${OPTARG} ;;
t) skip_lint="true" ;;
z) test_platform_specific_behavior="true" ;;
*) usage "Invalid option: -${OPTARG}" ;;
esac
done
Expand Down Expand Up @@ -224,6 +229,18 @@ if [[ "${skip_rust_tests:-false}" == "false" ]]; then
end_travis_section
fi

# NB: this only tests python tests right now -- the command needs to be edited if test targets in
# other languages are tagged with 'platform_specific_behavior' in the future.
if [[ "${test_platform_specific_behavior:-false}" == 'true' ]]; then
start_travis_section "Platform-specific tests" \
"Running platform-specific testing on platform: $(uname)"
(
./pants.pex ${PANTS_ARGS[@]} --tag='+platform_specific_behavior' test \
tests/python:: -- ${PYTEST_PASSTHRU_ARGS}
) || die "Pants platform-specific test failure"
end_travis_section
fi


if [[ "${skip_integration:-false}" == "false" ]]; then
if [[ "0/1" != "${python_intg_shard}" ]]; then
Expand Down
6 changes: 3 additions & 3 deletions src/python/pants/backend/native/subsystems/llvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class LLVMReleaseUrlGenerator(BinaryToolUrlGenerator):

_ARCHIVE_BASE_FMT = 'clang+llvm-{version}-x86_64-{system_id}'

# TODO(cosmicexplorer): Give a more useful error message than KeyError if the host platform was
# not recognized (and make it easy for other BinaryTool subclasses to do this as well).
# TODO: Give a more useful error message than KeyError if the host platform was not recognized
# (and make it easy for other BinaryTool subclasses to do this as well).
_SYSTEM_ID = {
'darwin': 'apple-darwin',
'mac': 'apple-darwin',
'linux': 'linux-gnu-ubuntu-16.04',
}

Expand Down
5 changes: 2 additions & 3 deletions src/python/pants/binaries/binary_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ class BinaryToolBase(Subsystem):
def subsystem_dependencies(cls):
sub_deps = super(BinaryToolBase, cls).subsystem_dependencies() + (BinaryUtil.Factory,)

# TODO(cosmicexplorer): if we need to do more conditional subsystem dependencies, do it
# declaratively with a dict class field so that we only try to create or access it if we
# declared a dependency on it.
# TODO: if we need to do more conditional subsystem dependencies, do it declaratively with a
# dict class field so that we only try to create or access it if we declared a dependency on it.
if cls.archive_type == 'txz':
sub_deps = sub_deps + (XZ.scoped(cls),)

Expand Down
50 changes: 37 additions & 13 deletions src/python/pants/fs/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
from pants.util.contextutil import open_tar, open_zip, temporary_dir
from pants.util.dirutil import (is_executable, safe_concurrent_rename, safe_walk,
split_basename_and_dirname)
from pants.util.memo import memoized_classproperty
from pants.util.meta import AbstractClass
from pants.util.osutil import get_normalized_os_name
from pants.util.process_handler import subprocess
from pants.util.strutil import ensure_text

Expand Down Expand Up @@ -103,9 +105,21 @@ class XZCompressedTarArchiver(TarArchiver):

class XZArchiverError(Exception): pass

# FIXME: move Platform#resolve_platform_specific() into somewhere common and consume it here after
# #5815 is merged.
@memoized_classproperty
def _liblzma_shared_lib_filename(cls):
normalized_os_name = get_normalized_os_name()
if normalized_os_name == 'darwin':
return 'liblzma.dylib'
elif normalized_os_name == 'linux':
return 'liblzma.so'
else:
raise cls.XZArchiverError("Unrecognized platform: {}.".format(normalized_os_name))

def __init__(self, xz_binary_path, xz_library_path):

# TODO(cosmicexplorer): test these exceptions somewhere!
# TODO: test these exceptions somewhere!
if not is_executable(xz_binary_path):
raise self.XZArchiverError(
"The path {} does not name an existing executable file. An xz executable must be provided "
Expand All @@ -116,16 +130,18 @@ def __init__(self, xz_binary_path, xz_library_path):

if not os.path.isdir(xz_library_path):
raise self.XZArchiverError(
"The path {} does not name an existing directory. A directory containing liblzma.so must "
"be provided to decompress xz archives."
.format(xz_library_path))
"The path {lib_dir} does not name an existing directory. A directory containing "
"{dylib_filename} must be provided to decompress xz archives."
.format(lib_dir=xz_library_path,
dylib_filename=self._liblzma_shared_lib_filename))

lib_lzma_dylib = os.path.join(xz_library_path, 'liblzma.so')
lib_lzma_dylib = os.path.join(xz_library_path, self._liblzma_shared_lib_filename)
if not os.path.isfile(lib_lzma_dylib):
raise self.XZArchiverError(
"The path {} names an existing directory, but it does not contain liblzma.so. A directory "
"containing liblzma.so must be provided to decompress xz archives."
.format(xz_library_path))
"The path {lib_dir} names an existing directory, but it does not contain {dylib_filename}. "
"A directory containing {dylib_filename} must be provided to decompress xz archives."
.format(lib_dir=xz_library_path,
dylib_filename=self._liblzma_shared_lib_filename))

self._xz_library_path = xz_library_path

Expand All @@ -140,16 +156,24 @@ def _invoke_xz(self, xz_input_file):
"""
(xz_bin_dir, xz_filename) = split_basename_and_dirname(self._xz_binary_path)

# TODO(cosmicexplorer): --threads=0 is supposed to use "the number of processor cores on the
# machine", but I see no more than 100% cpu used at any point. This seems like it could be a
# bug? If performance is an issue, investigate further.
# FIXME: --threads=0 is supposed to use "the number of processor cores on the machine", but I
# see no more than 100% cpu used at any point. This seems like it could be a bug? If performance
# is an issue, investigate further.
cmd = [xz_filename, '--decompress', '--stdout', '--keep', '--threads=0', xz_input_file]
env = {
# Isolate the path so we know we're using our provided version of xz.
'PATH': xz_bin_dir,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than setting $PATH here, just using self._xz_binary_path as the first arg of cmd should do the job, right?

Then we can either use the system env, as pants tends to, or an empty env, as I would be very happy about

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! The env bit was only necessary to emulate the kind of wrapping we are now doing in pantsbuild/binaries#72. Were you thinking I might want to explicitly clear the env here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, explicitly clearing the env in general is nice because it means we're more consistent/reproducible.

It probably doesn't matter either way here, but for things on the build path which we cache (possibly even outside of the local machine) things (like invoking gcc), stripping the entire env, and adding whatever we need explicitly, is a nice safe approach to try to ensure reproducibility. It also means that we can think to explicitly add those env vars to any cache keys we may need to (or, with v2 process execution, this happens by default, so it ensures that we actually get cache hits across users, because otherwise things like $HOME will always be different! :))

# Only allow our xz's lib directory to resolve the liblzma.so dependency at runtime.
'LD_LIBRARY_PATH': self._xz_library_path,
}

# Only allow our xz's lib directory to resolve the liblzma.{so,dylib} dependency at runtime.
normalized_os_name = get_normalized_os_name()
if normalized_os_name == 'darwin':
env['DYLD_FALLBACK_LIBRARY_PATH'] = self._xz_library_path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should probably actually be:
env['DYLD_LIBRARY_PATH'] = '{}:{}'.format(self.._xz_library_path, env.get('DYLD_LIBRARY_PATH', ''))

Two important differences:

  1. Set the main path not the fallback
  2. Preserve existing values; they may be important

(The one below should probably also set the existing path)

But I think it would be better for us to make sure the xz we release to pantsbinaries runs out of the box (either by linking differently, or with a wrapper script), rather than patching this up in pants...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is a very useful method get_joined_path() I added to contextutil.py to do the path operations you describe. However, I believe pantsbuild/binaries#71 lets us remove these lines. I will make the changes here and wait for that PR to be merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a wrapper script to the xz released to pants-binaries in pantsbuild/binaries#72! Thanks, that was an very useful suggestion.

elif normalized_os_name == 'linux':
env['LD_LIBRARY_PATH'] = self._xz_library_path
else:
raise self.XZArchiverError("Unrecognized platform: {}.".format(normalized_os_name))

try:
# Pipe stderr to our own stderr, but leave stdout open so we can yield it.
process = subprocess.Popen(
Expand Down
29 changes: 27 additions & 2 deletions tests/python/pants_test/backend/python/tasks/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,33 @@ python_library(
]
)

python_native_code_test_files = [
# TODO: This test does not have any platform-specific testing right now, but that will be
# changed when #5815 is merged.
'test_build_local_python_distributions.py',
'test_python_distribution_integration.py',
]

python_tests(
name='python_native_code_testing',
sources=python_native_code_test_files,
dependencies=[
':python_task_test_base',
'src/python/pants/backend/native',
'src/python/pants/backend/python:plugin',
'src/python/pants/backend/python/targets',
'src/python/pants/backend/python/tasks',
'src/python/pants/util:contextutil',
'src/python/pants/util:process_handler',
'tests/python/pants_test:int-test',
'tests/python/pants_test/engine:scheduler_test_base',
],
tags={'platform_specific_behavior'},
timeout=2400,
)

python_tests(
sources=globs('test_*.py', exclude=[globs('*_integration.py')]),
sources=globs('test_*.py', exclude=([globs('*_integration.py')] + python_native_code_test_files)),
dependencies=[
':python_task_test_base',
'3rdparty/python/twitter/commons:twitter.common.collections',
Expand Down Expand Up @@ -55,7 +80,7 @@ python_tests(

python_tests(
name='integration',
sources=globs('*_integration.py'),
sources=globs('*_integration.py', exclude=python_native_code_test_files),
dependencies=[
'3rdparty/python:pex',
'src/python/pants/util:contextutil',
Expand Down