Skip to content

Commit

Permalink
Mark build-support Python files as Pants targets to lint build-support (
Browse files Browse the repository at this point in the history
pantsbuild#7633)

### Converting to Pants targets
Now that we have two Python scripts, and may have more scripts in the future, there is value in linting our script code.

By making these two scripts as targets, we can now use `./pants fmt`, `./pants lint`, and `./pants mypy` on the build-support folder for little cost.

The pre-commit check will check `./pants fmt` and `./pants lint` automatically on the `build-support` Python files now. It will not do the header check until we explicitly add the folder.

### Add `common.py`
We also add `common.py` to reduce duplication and simplify writing scripts.

See the `NB` in that file about why we only use the stdlib for that file.
  • Loading branch information
Eric-Arellano committed May 10, 2019
1 parent e97e3a2 commit 5eed2e7
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 17 deletions.
22 changes: 22 additions & 0 deletions build-support/bin/BUILD
@@ -0,0 +1,22 @@
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

python_library(
name = 'common',
sources = 'common.py',
compatibility = ['CPython>=3.6'],
)

python_binary(
name = 'check_header_helper',
sources = 'check_header_helper.py',
)

python_binary(
name = 'check_pants_pex_abi',
sources = 'check_pants_pex_abi.py',
dependencies = [
':common',
],
compatibility = ['CPython>=3.6'],
)
1 change: 1 addition & 0 deletions build-support/bin/check_header_helper.py
Expand Up @@ -16,6 +16,7 @@
import sys
from io import open


EXPECTED_HEADER="""# coding=utf-8
# Copyright YYYY Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
Expand Down
15 changes: 2 additions & 13 deletions build-support/bin/check_pants_pex_abi.py
Expand Up @@ -9,10 +9,7 @@
import zipfile
from pathlib import Path


RED = "\033[31m"
BLUE = "\033[34m"
RESET = "\033[0m"
from common import die, green


def main() -> None:
Expand All @@ -32,7 +29,7 @@ def main() -> None:
if not parsed_abis.issubset(expected_abis):
die("pants.pex was built with the incorrect ABI. Expected wheels with: {}, found: {}."
.format(' or '.join(sorted(expected_abis)), ', '.join(sorted(parsed_abis))))
success("Success. The pants.pex was built with wheels carrying the expected ABIs: {}."
green("Success. The pants.pex was built with wheels carrying the expected ABIs: {}."
.format(', '.join(sorted(parsed_abis))))


Expand All @@ -52,13 +49,5 @@ def parse_abi_from_filename(filename: str) -> str:
return filename.split("-")[-2]


def success(message: str) -> None:
print(f"{BLUE}{message}{RESET}")


def die(message: str) -> None:
raise SystemExit(f"{RED}{message}{RESET}")


if __name__ == "__main__":
main()
81 changes: 81 additions & 0 deletions build-support/bin/common.py
@@ -0,0 +1,81 @@
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

"""Utils for scripts to interface with the outside world.
NB: We intentionally only use the standard library here, rather than using
Pants code and/or 3rd-party dependencies like `colors`, to ensure that all
scripts that import this file may still be invoked directly, rather than having
to run via `./pants run`.
We want to allow direct invocation of scripts for these reasons:
1) Consistency with how we invoke Bash scripts, which notably may _not_ be ran via `./pants run`.
2) More ergonomic command line arguments, e.g. `./build-support/bin/check_header.py src tests`,
rather than `./pants run build-support/bin:check_header -- src tests`.
3) Avoid undesired dependencies on Pants for certain scripts. For example, `shellcheck.py`
lints the `./pants` script, and we would like the script to still work even if `./pants`
breaks. If we had to rely on invoking via `./pants run`, this would not be possible.
Callers of this file, however, are free to dogfood Pants as they'd like, and any script
may be called via `./pants run` instead of direct invocation if desired."""

import time
from contextlib import contextmanager
from pathlib import Path
from typing import Iterator, Tuple


_SCRIPT_START_TIME = time.time()

_CLEAR_LINE = "\x1b[K"
_COLOR_BLUE = "\x1b[34m"
_COLOR_RED = "\x1b[31m"
_COLOR_GREEN = "\x1b[32m"
_COLOR_RESET = "\x1b[0m"


def die(message: str) -> None:
raise SystemExit(f"{_COLOR_RED}{message}{_COLOR_RESET}")


def green(message: str) -> None:
print(f"{_COLOR_GREEN}{message}{_COLOR_RESET}")


def banner(message: str) -> None:
minutes, seconds = elapsed_time()
print(f"{_COLOR_BLUE}[=== {minutes:02d}:{seconds:02d} {message} ===]{_COLOR_RESET}")


def elapsed_time() -> Tuple[int, int]:
now = time.time()
elapsed_seconds = int(now - _SCRIPT_START_TIME)
return elapsed_seconds // 60, elapsed_seconds % 60


@contextmanager
def travis_section(slug: str, message: str) -> Iterator[None]:
travis_fold_state = "/tmp/.travis_fold_current"

def travis_fold(action: str, target: str) -> None:
print(f"travis_fold:{action}:{target}\r{_CLEAR_LINE}", end="")

def read_travis_fold_state() -> str:
with open(travis_fold_state, "r") as f:
return f.readline()

def write_slug_to_travis_fold_state() -> None:
with open(travis_fold_state, "w") as f:
f.write(slug)

def remove_travis_fold_state() -> None:
Path(travis_fold_state).unlink()

travis_fold("start", slug)
write_slug_to_travis_fold_state()
banner(message)
try:
yield
finally:
travis_fold("end", read_travis_fold_state())
remove_travis_fold_state()
2 changes: 2 additions & 0 deletions build-support/githooks/pre-commit
Expand Up @@ -18,6 +18,8 @@ DIRS_TO_CHECK=(
pants-plugins
examples
contrib
# TODO(6071): Add `build-support/bin` once we update the check_header_helper.py script to
# allow Python 3 headers (i.e. without __future__ and coding=utf-8).
)

# TODO(#7068): Fix all these checks to only act on staged files with
Expand Down
1 change: 1 addition & 0 deletions testprojects/src/python/no_build_file/dummy.py
@@ -0,0 +1 @@
# An empty python file.
Expand Up @@ -24,6 +24,8 @@ def use_pantsd_env_var(cls):
"""
return False

_NO_BUILD_FILE_TARGET_BASE = 'testprojects/src/python/no_build_file'

_SOURCES_TARGET_BASE = 'testprojects/src/python/sources'

_SOURCES_ERR_MSGS = {
Expand Down Expand Up @@ -146,10 +148,7 @@ def test_existing_bundles(self):
self.assertNotIn("WARN]", pants_run.stderr_data)

def test_existing_directory_with_no_build_files_fails(self):
options = [
'--pants-ignore=+["/build-support/bin/native/src"]',
]
pants_run = self.run_pants(options + ['list', 'build-support/bin::'])
pants_run = self.run_pants(['list', "{}::".format(self._NO_BUILD_FILE_TARGET_BASE)])
self.assert_failure(pants_run)
self.assertIn("does not match any targets.", pants_run.stderr_data)

Expand Down

0 comments on commit 5eed2e7

Please sign in to comment.