def install_and_test_packages(version: str, *, extra_pip_args: list[str] | None = None) -> None: with create_tmp_venv() as venv_tmpdir: for pkg in PACKAGES: pip_req = f"{pkg.name}=={version}" banner(f"Installing and testing {pip_req}") pkg.validate(version, venv_tmpdir, extra_pip_args or []) green(f"Tests succeeded for {pip_req}")
def build_pants_wheels() -> None: banner(f"Building Pants wheels with Python {CONSTANTS.python_version}") version = CONSTANTS.pants_unstable_version dest = CONSTANTS.deploy_pants_wheel_dir / version dest.mkdir(parents=True, exist_ok=True) args = ( "./pants", # TODO(#9924). "--no-dynamic-ui", # TODO(#7654): It's not safe to use Pantsd because we're already using Pants to run # this script. "--concurrent", "package", *(package.target for package in PACKAGES), ) with set_pants_version(CONSTANTS.pants_unstable_version): try: subprocess.run(args, check=True) except subprocess.CalledProcessError as e: failed_packages = ",".join(package.name for package in PACKAGES) failed_targets = " ".join(package.target for package in PACKAGES) die( softwrap(f""" Failed to build packages {failed_packages} for {version} with targets {failed_targets}. {e!r} """)) # TODO(#10718): Allow for sdist releases. We can build an sdist for # `pantsbuild.pants.testutil`, but need to wire it up to the rest of our release process. for package in PACKAGES: found_wheels = sorted( Path("dist").glob(f"{package}-{version}-*.whl")) # NB: For any platform-specific wheels, like pantsbuild.pants, we assume that the # top-level `dist` will only have wheels built for the current platform. This # should be safe because it is not possible to build native wheels for another # platform. if not is_cross_platform(found_wheels) and len(found_wheels) > 1: die( softwrap(f""" Found multiple wheels for {package} in the `dist/` folder, but was expecting only one wheel: {sorted(wheel.name for wheel in found_wheels)}. """)) for wheel in found_wheels: if not (dest / wheel.name).exists(): # We use `copy2` to preserve metadata. shutil.copy2(wheel, dest) green(f"Wrote Pants wheels to {dest}.") banner(f"Validating Pants wheels for {CONSTANTS.python_version}.") create_twine_venv() subprocess.run( [CONSTANTS.twine_venv_dir / "bin/twine", "check", dest / "*.whl"], check=True) green(f"Validated Pants wheels for {CONSTANTS.python_version}.")
def build_pex(fetch: bool) -> None: if fetch: extra_pex_args = [ f"--platform={plat}-{abi}" for plat in ("linux_x86_64", "macosx_10.15_x86_64") for abi in ("cp-37-m", "cp-38-cp38", "cp-39-cp39") ] pex_name = f"pants.{CONSTANTS.pants_unstable_version}.pex" banner(f"Building {pex_name} by fetching wheels.") else: extra_pex_args = [f"--python={sys.executable}"] plat = os.uname()[0].lower() py = f"cp{''.join(map(str, sys.version_info[:2]))}" pex_name = f"pants.{CONSTANTS.pants_unstable_version}.{plat}-{py}.pex" banner(f"Building {pex_name} by building wheels.") if CONSTANTS.deploy_dir.exists(): shutil.rmtree(CONSTANTS.deploy_dir) CONSTANTS.deploy_dir.mkdir(parents=True) if fetch: fetch_prebuilt_wheels(CONSTANTS.deploy_dir) check_prebuilt_wheels_present(CONSTANTS.deploy_dir) else: build_pants_wheels() build_3rdparty_wheels() dest = Path("dist") / pex_name with download_pex_bin() as pex_bin: subprocess.run( [ sys.executable, str(pex_bin), "-o", str(dest), "--no-build", "--no-pypi", "--disable-cache", "-f", str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_unstable_version), "-f", str(CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version), "--no-strip-pex-env", "--console-script=pants", "--unzip", *extra_pex_args, f"pantsbuild.pants=={CONSTANTS.pants_unstable_version}", ], check=True, ) if os.environ.get("PANTS_PEX_RELEASE", "") == "STABLE": stable_dest = CONSTANTS.deploy_dir / "pex" / f"pants.{CONSTANTS.pants_stable_version}.pex" stable_dest.parent.mkdir(parents=True, exist_ok=True) dest.rename(stable_dest) dest = stable_dest green(f"Built {dest}") subprocess.run([sys.executable, str(dest), "--version"], check=True) green(f"Validated {dest}")
def check_prebuilt_wheels(check_dir: str) -> None: banner(f"Checking prebuilt wheels for {CONSTANTS.pants_unstable_version}") missing_packages = [] for package in sorted(all_packages()): local_files = package.find_locally( version=CONSTANTS.pants_unstable_version, search_dir=check_dir ) if not local_files: missing_packages.append(package.name) continue # If the package is cross platform, confirm that we have whls for two platforms. is_cross_platform = not all( local_file.name.endswith("-none-any.whl") for local_file in local_files ) if is_cross_platform and len(local_files) != 2: formatted_local_files = ", ".join(f.name for f in local_files) missing_packages.append( f"{package.name} (expected a macOS wheel and a linux wheel, but found " f"{formatted_local_files})" ) if missing_packages: formatted_missing = "\n ".join(missing_packages) die(f"Failed to find prebuilt wheels:\n {formatted_missing}") green(f"All {len(all_packages())} pantsbuild.pants packages were fetched and are valid.")
def publish() -> None: banner("Releasing packages to PyPI and GitHub") # Check prereqs. check_clean_git_branch() check_pgp() check_roles() # Fetch and validate prebuilt wheels. if CONSTANTS.deploy_pants_wheel_dir.exists(): shutil.rmtree(CONSTANTS.deploy_pants_wheel_dir) fetch_prebuilt_wheels(CONSTANTS.deploy_dir) check_prebuilt_wheels_present(CONSTANTS.deploy_dir) reversion_prebuilt_wheels() # Release. create_twine_venv() subprocess.run( [ str(CONSTANTS.twine_venv_dir / "bin/twine"), "upload", "--sign", f"--sign-with={get_pgp_program_name()}", f"--identity={get_pgp_key_id()}", "--skip-existing", # Makes the upload idempotent. str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_stable_version / "*.whl"), ], check=True, ) tag_release() banner("Successfully released packages to PyPI and GitHub")
def build_3rdparty_wheels() -> None: banner(f"Building 3rdparty wheels with Python {CONSTANTS.python_version}") dest = CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version pkg_tgts = [pkg.target for pkg in PACKAGES] with create_tmp_venv() as venv_tmpdir: deps = ( subprocess.run( [ "./pants", "--concurrent", "--no-dynamic-ui", "dependencies", "--transitive", "--type=3rdparty", *pkg_tgts, ], stdout=subprocess.PIPE, check=True, ) .stdout.decode() .strip() .splitlines() ) if not deps: die( f"No 3rd-party dependencies detected for {pkg_tgts}. Is `./pants dependencies` " "broken?" ) subprocess.run( [Path(venv_tmpdir, "bin/pip"), "wheel", f"--wheel-dir={dest}", *deps], check=True, )
def setup_python_interpreter(version: PythonVersion) -> None: if "PY" not in os.environ: os.environ["PY"] = f"python{version}" constraints_env_var = "PANTS_PYTHON_SETUP_INTERPRETER_CONSTRAINTS" if constraints_env_var not in os.environ: os.environ[constraints_env_var] = f"['CPython=={version}.*']" banner(f"Setting interpreter constraints to {os.environ[constraints_env_var]}")
def build_fs_util() -> None: # See https://www.pantsbuild.org/docs/contributions-rust for a description of fs_util. We # include it in our releases because it can be a useful standalone tool. banner("Building fs_util") command = ["./cargo", "build", "-p", "fs_util"] release_mode = os.environ.get("MODE", "") != "debug" if release_mode: command.append("--release") subprocess.run(command, check=True, env={**os.environ, "RUST_BACKTRACE": "1"}) current_os = ( subprocess.run(["build-support/bin/get_os.sh"], stdout=subprocess.PIPE, check=True) .stdout.decode() .strip() ) dest_dir = ( Path(CONSTANTS.deploy_dir) / "bin" / "fs_util" / current_os / CONSTANTS.pants_unstable_version ) dest_dir.mkdir(parents=True, exist_ok=True) shutil.copy( f"src/rust/engine/target/{'release' if release_mode else 'debug'}/fs_util", dest_dir, ) green(f"Built fs_util at {dest_dir / 'fs_util'}.")
def build_pants_wheels() -> None: banner("Building Pants wheels") version = CONSTANTS.pants_unstable_version destination = CONSTANTS.deploy_pants_wheel_dir / version destination.mkdir(parents=True, exist_ok=True) def build(packages: Iterable[Package], bdist_wheel_flags: Iterable[str]) -> None: args = ( "./pants", # TODO(#9924). "--no-dynamic-ui", # TODO(#7654): It's not safe to use Pantsd because we're already using Pants to run # this script. "--concurrent", "setup-py", *(package.target for package in packages), "--", "bdist_wheel", *bdist_wheel_flags, ) try: subprocess.run(args, check=True) for package in packages: found_wheels = sorted( Path("dist").glob(f"{package}-{version}-*.whl")) # NB: For any platform-specific wheels, like pantsbuild.pants, we assume that the # top-level `dist` will only have wheels built for the current platform. This # should be safe because it is not possible to build native wheels for another # platform. if not is_cross_platform( found_wheels) and len(found_wheels) > 1: raise ValueError( f"Found multiple wheels for {package} in the `dist/` folder, but was " f"expecting only one wheel: {sorted(wheel.name for wheel in found_wheels)}." ) for wheel in found_wheels: if not (destination / wheel.name).exists(): # We use `copy2` to preserve metadata. shutil.copy2(wheel, destination) except subprocess.CalledProcessError as e: failed_packages = ",".join(package.name for package in packages) failed_targets = " ".join(package.target for package in packages) die( f"Failed to build packages {failed_packages} for {version} with targets " f"{failed_targets}.\n\n{e!r}", ) packages_by_flags = defaultdict(list) for package in PACKAGES: packages_by_flags[package.bdist_wheel_flags].append(package) with set_pants_version(CONSTANTS.pants_unstable_version): for flags, packages in packages_by_flags.items(): build(packages, flags) green(f"Wrote Pants wheels to {destination}.")
def main() -> None: if not Path("src/python/pants").is_dir(): raise ValueError( "This script assumes that you are in the Pants build root. Instead, you are at " f"{Path.cwd()}.") args = create_parser().parse_args() pex_url = f"s3://{args.aws_bucket}/{args.pex_key}" native_engine_so_local_path = "./src/python/pants/engine/internals/native_engine.so" # NB: we must set `$PY` before calling `bootstrap()` to ensure that we use the exact same # Python interpreter when calculating the hash of `native_engine.so` as the one we use when # calling `ci.py --bootstrap`. python_version = create_parser().parse_args().python_version if "PY" not in os.environ: os.environ["PY"] = f"python{python_version}" native_engine_so_hash = calculate_native_engine_so_hash() native_engine_so_aws_key = ( f"{args.native_engine_so_key_prefix}/{native_engine_so_hash}/native_engine.so" ) native_engine_so_aws_url = f"s3://{args.aws_bucket}/{native_engine_so_aws_key}" if native_engine_so_in_s3_cache( aws_bucket=args.aws_bucket, native_engine_so_aws_key=native_engine_so_aws_key): banner( f"`native_engine.so` found in the AWS S3 cache at {native_engine_so_aws_url}. " f"Downloading to avoid unnecessary Rust compilation.") get_native_engine_so( native_engine_so_aws_url=native_engine_so_aws_url, native_engine_so_local_path=native_engine_so_local_path, ) else: banner( f"`native_engine.so` not found in the AWS S3 cache at {native_engine_so_aws_url}. " f"Recompiling Rust...") bootstrap_pants_pex(python_version) if native_engine_so_in_s3_cache( aws_bucket=args.aws_bucket, native_engine_so_aws_key=native_engine_so_aws_key): banner( f"`native_engine.so` already cached at {native_engine_so_aws_url}. Skipping deploy." ) else: banner(f"Deploying `native_engine.so` to {native_engine_so_aws_url}.") deploy_native_engine_so( native_engine_so_aws_url=native_engine_so_aws_url, native_engine_so_local_path=native_engine_so_local_path, ) banner(f"Deploying `pants.pex` to {pex_url}.") deploy_pants_pex(pex_url=pex_url)
def check_pgp() -> None: banner("Checking PGP setup") key = get_pgp_key_id() if not key: die("You must set up a PGP key. See https://www.pantsbuild.org/docs/release-process." ) print("Found the following key for release signing:\n") subprocess.run([get_pgp_program_name(), "-k", key], check=True) key_confirmation = input("\nIs this the correct key? [Y/n]: ") if key_confirmation and key_confirmation.lower() != "y": die("Please configure the key you intend to use. See " "https://www.pantsbuild.org/docs/release-process.")
def check_roles() -> None: # Check that the packages we plan to publish are correctly owned. banner("Checking current user.") username = get_pypi_config("server-login", "username") if username not in _expected_owners and username not in _expected_maintainers: die(f"User {username} not authorized to publish.") banner("Checking package roles.") validator = PackageAccessValidator() for pkg in PACKAGES: if pkg.name not in _known_packages: die(f"Unknown package {pkg}") validator.validate_package_access(pkg.name)
def fetch_prebuilt_wheels(destination_dir: str) -> None: banner(f"Fetching pre-built wheels for {CONSTANTS.pants_unstable_version}") print(f"Saving to {destination_dir}.\n", file=sys.stderr) for wheel in determine_prebuilt_wheels(): full_url = f"{CONSTANTS.binary_base_url}/{wheel.url}" print(f"Fetching {full_url}", file=sys.stderr) response = requests.get(full_url) response.raise_for_status() print(file=sys.stderr) dest = Path(destination_dir, wheel.path) dest.parent.mkdir(parents=True, exist_ok=True) dest.write_bytes(response.content)
def check_clean_git_branch() -> None: banner("Checking for a clean Git branch") git_status = (subprocess.run(["git", "status", "--porcelain"], stdout=subprocess.PIPE, check=True).stdout.decode().strip()) if git_status: die("Uncommitted changes detected when running `git status`. You must be on a clean branch " "to release.") valid_branch_pattern = r"^(main)|([0-9]+\.[0-9]+\.x)$" git_branch = get_git_branch() if not re.match(valid_branch_pattern, git_branch): die("On an invalid branch. You must either be on `main` or a release branch like " f"`2.4.x`. Detected: {git_branch}")
def main() -> None: banner("CI BEGINS") args = create_parser().parse_args() setup_environment(python_version=args.python_version) with maybe_get_remote_execution_oauth_token_path( remote_execution_enabled=args.remote_execution_enabled ) as remote_execution_oauth_token_path: if args.bootstrap: bootstrap( clean=args.bootstrap_clean, try_to_skip_rust_compilation=args. bootstrap_try_to_skip_rust_compilation, python_version=args.python_version, ) set_run_from_pex() if args.githooks: run_githooks() if args.sanity_checks: run_sanity_checks() if args.lint: run_lint(oauth_token_path=remote_execution_oauth_token_path) if args.doc_gen: run_doc_gen_tests() if args.clippy: run_clippy() if args.cargo_audit: run_cargo_audit() if args.unit_tests: run_unit_tests(oauth_token_path=remote_execution_oauth_token_path) if args.rust_tests: run_rust_tests() if args.jvm_tests: run_jvm_tests() if args.integration_tests_v1: run_integration_tests_v1(shard=args.integration_shard) if args.integration_tests_v2: run_integration_tests_v2( oauth_token_path=remote_execution_oauth_token_path) if args.plugin_tests: run_plugin_tests( oauth_token_path=remote_execution_oauth_token_path) if args.platform_specific_tests: run_platform_specific_tests() banner("CI ENDS") print() green("SUCCESS")
def build_3rdparty_wheels() -> None: banner(f"Building 3rdparty wheels with Python {CONSTANTS.python_version}") dest = CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version pkg_tgts = [pkg.target for pkg in PACKAGES] with create_tmp_venv() as bin_dir: deps = (subprocess.run( [ "./pants", "--concurrent", "dependencies", "--transitive", *pkg_tgts, ], stdout=subprocess.PIPE, check=True, ).stdout.decode().strip().splitlines()) python_requirements = (subprocess.run( [ "./pants", "--concurrent", "filter", "--target-type=python_requirement", *deps, ], stdout=subprocess.PIPE, check=True, ).stdout.decode().strip().splitlines()) if not python_requirements: die( softwrap(f""" No 3rd-party dependencies detected for {pkg_tgts}. Is `./pants dependencies` broken? """)) reqs = itertools.chain.from_iterable(obj["requirements"] for obj in json.loads( subprocess.run( [ "./pants", "--concurrent", "peek", *python_requirements, ], stdout=subprocess.PIPE, check=True, ).stdout)) subprocess.run( [bin_dir / "pip", "wheel", f"--wheel-dir={dest}", *reqs], check=True, ) green(f"Wrote 3rdparty wheels to {dest}")
def dry_run_install() -> None: banner(f"Performing a dry run release with {CONSTANTS.python_version}") build_pants_wheels() build_3rdparty_wheels() install_and_test_packages( CONSTANTS.pants_unstable_version, extra_pip_args=[ "--only-binary=:all:", "-f", str(CONSTANTS.deploy_3rdparty_wheel_dir / CONSTANTS.pants_unstable_version), "-f", str(CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_unstable_version), ], ) banner(f"Dry run release succeeded with {CONSTANTS.python_version}")
def fetch_prebuilt_wheels(destination_dir: str | Path, *, include_3rdparty: bool) -> None: banner(f"Fetching pre-built wheels for {CONSTANTS.pants_unstable_version}") print(f"Saving to {destination_dir}.\n", file=sys.stderr) session = requests.Session() session.mount(CONSTANTS.binary_base_url, requests.adapters.HTTPAdapter(max_retries=4)) for wheel in determine_prebuilt_wheels(include_3rdparty=include_3rdparty): full_url = f"{CONSTANTS.binary_base_url}/{wheel.url}" print(f"Fetching {full_url}", file=sys.stderr) response = session.get(full_url) response.raise_for_status() print(file=sys.stderr) dest = Path(destination_dir, wheel.path) dest.parent.mkdir(parents=True, exist_ok=True) dest.write_bytes(response.content)
def check_ownership(i: int, package: Package) -> None: banner( f"[{i}/{len(PACKAGES)}] checking ownership for {package}: > {minimum_owner_count} " f"releasers including {', '.join(users)}") if not package.exists_on_pypi(): print( f"The {package.name} package is new! There are no owners yet.") return owners = package.owners() if len(owners) <= minimum_owner_count: insufficient.add(package) difference = users.difference(owners) for d in difference: unowned.setdefault(d, set()).add(package)
def main(): """Process command line args.""" clrm.init() args = sys.argv[1:] if args: args_set = set(args) max_args = 2 # -q and one other doc_arg_set = set(['-d', '--doc']) help_arg_set = set(['-h', '--help']) license_arg_set = set(['-l', '--license']) quiet_arg_set = set(['-q', '--quiet']) reference_arg_set = set(['-r', '--reference']) version_arg_set = set(['-V', '--version']) legal_args_set = (doc_arg_set | help_arg_set | license_arg_set | quiet_arg_set | reference_arg_set | version_arg_set) # if any wrong arg, too many args or (max args and -q not among them) if (args_set - legal_args_set or len(args) > max_args or (len(args) == max_args and not (quiet_arg_set & args_set))): print(common.banner()) print(clrm.Fore.RED + lcl.WRONG_ARG + '\n') print(clrm.Fore.RESET + common.usage()) else: if not (quiet_arg_set & args_set): print(common.banner()) if doc_arg_set & args_set: get_app_info() update_doc() elif license_arg_set & args_set: print(common.license_()) elif help_arg_set & args_set: print(common.usage()) elif reference_arg_set & args_set: get_app_info() update_ref() elif version_arg_set & args_set: print(lcl.VERSION, common.version()) else: # only -q create_setup() else: print(common.banner()) create_setup()
def check_ownership(users, minimum_owner_count: int = 3) -> None: minimum_owner_count = max(len(users), minimum_owner_count) packages = sorted(all_packages()) banner(f"Checking package ownership for {len(packages)} packages") users = {user.lower() for user in users} insufficient = set() unowned: Dict[str, Set[Package]] = dict() def check_ownership(i: int, package: Package) -> None: banner( f"[{i}/{len(packages)}] checking ownership for {package}: > {minimum_owner_count} " f"releasers including {', '.join(users)}") if not package.exists_on_pypi(): print( f"The {package.name} package is new! There are no owners yet.") return owners = package.owners() if len(owners) <= minimum_owner_count: insufficient.add(package) difference = users.difference(owners) for d in difference: unowned.setdefault(d, set()).add(package) for i, package in enumerate(packages): check_ownership(i, package) if unowned: for user, unowned_packages in sorted(unowned.items()): formatted_unowned = "\n".join(package.name for package in sorted(packages)) print( f"PyPI account {user} needs to be added as an owner for the following " f"packages:\n{formatted_unowned}", file=sys.stderr, ) raise SystemExit() if insufficient: insufficient_packages = "\n".join(package.name for package in insufficient) die( f"The following packages have fewer than {minimum_owner_count} owners but should be " f"setup for all releasers:\n{insufficient_packages}", )
def check_pants_wheels_present(check_dir: str | Path) -> None: banner(f"Checking prebuilt wheels for {CONSTANTS.pants_unstable_version}") missing_packages = [] for package in PACKAGES: local_files = package.find_locally( version=CONSTANTS.pants_unstable_version, search_dir=check_dir) if not local_files: missing_packages.append(package.name) continue if is_cross_platform(local_files) and len(local_files) != 6: formatted_local_files = ", ".join(f.name for f in local_files) missing_packages.append( f"{package.name} (expected 6 wheels, {{macosx, linux}} x {{cp37m, cp38, cp39}}, " f"but found {formatted_local_files})") if missing_packages: formatted_missing = "\n ".join(missing_packages) die(f"Failed to find prebuilt wheels:\n {formatted_missing}") green( f"All {len(PACKAGES)} pantsbuild.pants packages were fetched and are valid." )
def main() -> None: banner("CI BEGINS") args = create_parser().parse_args() setup_environment(python_version=args.python_version) if args.bootstrap: bootstrap(clean=args.bootstrap_clean, python_version=args.python_version) set_run_from_pex() if args.githooks: run_githooks() if args.sanity_checks: run_sanity_checks() if args.lint: run_lint() if args.doc_gen: run_doc_gen_tests() if args.clippy: run_clippy() if args.cargo_audit: run_cargo_audit() if args.python_tests_v1: run_python_tests_v1() if args.python_tests_v2: run_python_tests_v2() if args.rust_tests: run_rust_tests() if args.jvm_tests: run_jvm_tests() if args.integration_tests: run_integration_tests(shard=args.integration_shard) if args.plugin_tests: run_plugin_tests() if args.platform_specific_tests: run_platform_specific_tests() banner("CI ENDS") print() green("SUCCESS")
def publish_apple_silicon() -> None: banner("Building and publishing an Apple Silicon wheel") if os.environ.get("USE_PY39") != "true": die("Must set `USE_PY39=true` when building for Apple Silicon.") if os.environ.get("MODE") == "debug": die("Must build Rust in release mode, not debug. Please run `unset MODE`." ) check_clean_git_branch() check_pgp() check_roles() dest_dir = CONSTANTS.deploy_pants_wheel_dir / CONSTANTS.pants_stable_version if dest_dir.exists(): shutil.rmtree(dest_dir) subprocess.run( [ "./pants", "--concurrent", f"--pants-distdir={dest_dir}", "package", PANTS_PKG.target, ], check=True, ) expected_whl = ( dest_dir / f"pantsbuild.pants-{CONSTANTS.pants_stable_version}-cp39-cp39-macosx_11_0_arm64.whl" ) if not expected_whl.exists(): die( softwrap(f""" Failed to find {expected_whl}. Are you running from the correct platform and macOS version? """)) create_twine_venv() subprocess.run( [CONSTANTS.twine_venv_dir / "bin/twine", "check", expected_whl], check=True) upload_wheels_via_twine() banner("Successfully released Apple Silicon wheel to PyPI")
def publish() -> None: banner("Releasing to PyPI and GitHub") # Check prereqs. check_clean_git_branch() prompt_artifact_freshness() check_pgp() check_roles() # Fetch and validate prebuilt wheels. if CONSTANTS.deploy_pants_wheel_dir.exists(): shutil.rmtree(CONSTANTS.deploy_pants_wheel_dir) fetch_prebuilt_wheels(CONSTANTS.deploy_dir, include_3rdparty=False) check_pants_wheels_present(CONSTANTS.deploy_dir) reversion_prebuilt_wheels() # Release. create_twine_venv() upload_wheels_via_twine() tag_release() banner("Successfully released to PyPI and GitHub") prompt_apple_silicon() prompt_to_generate_docs()
def main() -> None: banner("CI BEGINS") args = create_parser().parse_args() setup_environment(python_version=args.python_version) if args.bootstrap: bootstrap( clean=args.bootstrap_clean, try_to_skip_rust_compilation=args. bootstrap_try_to_skip_rust_compilation, python_version=args.python_version, ) set_run_from_pex() if args.githooks: run_githooks() if args.smoke_tests: run_smoke_tests() if args.lint: run_lint(remote_cache_enabled=args.remote_cache_enabled) if args.clippy: run_clippy() if args.cargo_audit: run_cargo_audit() if args.unit_tests or args.integration_tests: run_python_tests( include_unit=args.unit_tests, include_integration=args.integration_tests, remote_cache_enabled=args.remote_cache_enabled, ) if args.rust_tests: run_rust_tests() if args.platform_specific_tests: run_platform_specific_tests() banner("CI ENDS") print() green("SUCCESS")
def main(): # 这里还要在check 基本环境 argpa = argparse.ArgumentParser(description="A Scan For Network") argpa.add_argument("--banner") argpa.add_argument("--debug") argpa.add_argument("-u", help="Web Url") argpa.add_argument("-p", help="Server Port") argpa.add_argument("-H", help="Server Host") args = argpa.parse_args() # arg_dict= arg.__dict__ # # print arg_dict if Os_win: print "a" banner() try: initoptions(args) except Exception, msg: pass
def start(argv): """Print banner, read/create data & log file and process args.""" clrm.init() print(common.banner()) childs, last_upd = shrd.open_create_datafile() arg0 = argv[0] if arg0 in ['-a', '--auto']: auto_upd(childs, last_upd) elif arg0 in ['-h', '--help']: print(common.usage()) elif arg0 in ['-l', '--license']: print(common.license_()) elif arg0 in ['-V', '--version']: print(lcl.VERSION, common.version()) else: man_upd(argv, childs, last_upd) sys.exit(0) # ToDo: other return codes
def setup_python_version(test_python_version: PythonVersion): """Modify pants.ini to allow the Python version to be unspecified or change to what was requested.""" updated_config = read_config() config_entry = "pants_runtime_python_version" if test_python_version == PythonVersion.unspecified: updated_config.remove_option(CONFIG_GLOBAL_SECTION, config_entry) banner(f"Temporarily removing `{config_entry}` from pants.ini.") else: updated_config[CONFIG_GLOBAL_SECTION][ config_entry] = test_python_version.value banner( f"Temporarily rewriting `{config_entry}` to `{test_python_version}`." ) with temporarily_rewrite_config(updated_config): yield banner(f"Restoring original `{config_entry}` value in pants.ini.")
def start(argv): """Print banner and process args.""" ansi.init() print(common.banner()) if not argv: print_ips() else: arg0 = argv[0] if arg0 in ['-h', '--help']: print(common.usage()) elif arg0 in ['-l', '--license']: print(common.license_()) elif arg0 in ['-p', '--pause']: print_ips() input(lcl.PRESS_ANY_KEY) elif arg0 in ['-V', '--version']: print(lcl.VERSION, common.version()) else: print(ansi.Fore.RED + lcl.WRONG_ARG + arg0 + '\n') print(ansi.Fore.RESET + common.usage()) sys.exit(0) # ToDo: other return codes
def start(): """Print banner, read/create data & log file and start GUI.""" global prev_child, child, childs, last_upd def plus_btn(*args): """Plus button was pressed. Update days_var.""" if int(days_var.get()) < 0: days_var.set(0) else: days_var.set(min(shrd.MAX_DAYS, int(days_var.get()) + 1)) def minus_btn(*args): """Minus button was pressed. Update days_var.""" if int(days_var.get()) > shrd.MAX_DAYS: days_var.set(shrd.MAX_DAYS) else: days_var.set(max(0, int(days_var.get()) - 1)) def days_scale_chg(*args): """Days scale changed. Update. Update days_var.""" days_var.set(int(float(days_var.get()))) # fix increment to integer def childs_combo_chg(*args): """ Child selection changed. Save current child's grounded days and update all fields with new child's. """ global child, prev_child try: int(days_var.get()) except ValueError: # as error: days_var.set(0) if 0 <= int(days_var.get()) <= shrd.MAX_DAYS: childs[prev_child] = int(days_var.get()) child = prev_child = childs_combo.get() days_var.set(childs[child]) else: childs_combo.set(prev_child) tk_msg_box.showwarning(lcl.WARNING, lcl.DAYS_RANGE + shrd.MAX_DAYS_STR) def set_upd_btn(upd): """Set or update selected child's grounded days.""" global last_upd try: int(days_var.get()) except ValueError: # as error: days_var.set(0) if 0 <= int(days_var.get()) <= shrd.MAX_DAYS: childs[childs_combo.get()] = int(days_var.get()) if upd: last_upd = shrd.auto_upd_datafile(childs, last_upd) else: last_upd = dt.date.today() shrd.update_file(childs, last_upd) last_upd_var.set(value=str(last_upd)) else: tk_msg_box.showwarning(lcl.WARNING, lcl.DAYS_RANGE + shrd.MAX_DAYS_STR) def confirm_exit(): """Confirm exit from program.""" if tk_msg_box.askokcancel(lcl.EXIT, lcl.CONFIRM_EXIT): root.destroy() sys.exit(0) # ToDo: other return codes def digits_only(up_down, idx, value, prev_val, char, val_type, source, widget): """Only allow digits in source field.""" return char in '0123456789' and len(value) <= len(shrd.MAX_DAYS_STR) def center(window): """Center window.""" window.update_idletasks() width = window.winfo_width() frm_width = window.winfo_rootx() - window.winfo_x() win_width = width + 2 * frm_width height = window.winfo_height() titlebar_height = window.winfo_rooty() - window.winfo_y() win_height = height + titlebar_height + frm_width x = window.winfo_screenwidth() // 2 - win_width // 2 y = window.winfo_screenheight() // 2 - win_height // 2 window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) if window.attributes('-alpha') == 0: window.attributes('-alpha', 1.0) window.deiconify() def show_help(*args): """Show help message.""" tk_msg_box.showinfo(lcl.HELP, common.usage()) print(common.banner()) childs, last_upd = shrd.open_create_datafile() root = tk.Tk() root.withdraw() win = tk.Toplevel(root) # for exit confirmation win.protocol('WM_DELETE_WINDOW', confirm_exit) win.title(lcl.WIN_TITLE) # not resizable win.resizable(False, False) # resizable (limits) # win.minsize(250, 125) # win.maxsize(500, 250) # needed by center function? # win.attributes('-alpha', 0.0) win.bind('<F1>', show_help) win.bind('+', plus_btn) win.bind('-', minus_btn) # menu win.option_add('*tearOff', False) menubar = tk.Menu(win) win.config(menu=menubar) filemenu = tk.Menu(menubar) helpmenu = tk.Menu(menubar) menubar.add_cascade(label=lcl.FILE, menu=filemenu, underline=0) menubar.add_cascade(label=lcl.HELP, menu=helpmenu, underline=0) filemenu.add_command(label=lcl.EXIT, underline=0, command=confirm_exit) helpmenu.add_command(label=lcl.HELP, underline=0, command=show_help, accelerator='F1') helpmenu.add_separator() helpmenu.add_command(label=lcl.ABOUT, underline=0, state='disabled') # ToDo: log menu item # filemenu.add_separator() # check = StringVar(value=1) # filemenu.add_checkbutton(label='Log', variable=check, onvalue=1, # offvalue=0) frame = tk_ttk.Frame(win, padding='3 3 3 3') frame.grid(column=0, row=0, sticky='WNES') # if the main window is resized, the frame should expand # frame.columnconfigure(0, weight=1) # frame.rowconfigure(0, weight=1) # must convert to list for Python 3 compatibility prev_child = child = list(childs.keys())[0] child_lbl = tk.StringVar(value=lcl.CHILD) last_upd_lbl = tk.StringVar(value=lcl.LAST_UPDATE) days_var = tk.StringVar(value=childs[child]) last_upd_var = tk.StringVar(value=str(last_upd)) # 1st row tk_ttk.Button(frame, text='+', command=plus_btn).grid(column=3, row=1) days_scale = tk_ttk.Scale(frame, orient=tk.VERTICAL, length=100, from_=shrd.MAX_DAYS, to=0, command=days_scale_chg, variable=days_var) days_scale.grid(column=4, row=1, rowspan=3) # 2nd row tk_ttk.Label(frame, textvariable=child_lbl).grid(column=1, row=2) childs_combo = tk_ttk.Combobox(frame, state='readonly', # width=10, values=list(childs.keys())) childs_combo.grid(column=2, row=2) childs_combo.set(child) childs_combo.bind('<<ComboboxSelected>>', childs_combo_chg) # validate command, used below by some widgets vcmd = (win.register(digits_only), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W') days_entry = tk_ttk.Entry(frame, width=len(shrd.MAX_DAYS_STR) + 1, justify=tk.RIGHT, textvariable=days_var, validate='key', validatecommand=vcmd) days_entry.grid(column=3, row=2) # , sticky='WE') # for expanding tk.Spinbox(frame, from_=0, to=shrd.MAX_DAYS, width=len(shrd.MAX_DAYS_STR) + 1, justify=tk.RIGHT, textvariable=days_var, validate='key', validatecommand=vcmd).grid(column=5, row=2) # 3rd row tk_ttk.Button(frame, text='-', command=minus_btn).grid(column=3, row=3) # 4th row # lambda is necessary so that the function is called on button creation tk_ttk.Button(frame, text=lcl.UPDATE, command=lambda: set_upd_btn(upd=True)).grid(column=1, row=4) tk_ttk.Label(frame, textvariable=last_upd_lbl).grid(column=2, row=4, sticky='E') tk_ttk.Label(frame, textvariable=last_upd_var).grid(column=3, row=4, sticky='W') tk_ttk.Button(frame, text=lcl.SET, command=lambda: set_upd_btn(upd=False)).grid(column=4, row=4, columnspan=2) # remove if windows is non resizable # tk_ttk.Sizegrip(frame).grid(column=999, row=999, sticky=(E,S)) # padding around all widgets for widget in frame.winfo_children(): widget.grid_configure(padx=5, pady=5) days_entry.focus() # center window center(win) root.mainloop()
def start(): """Print banner and start GUI.""" def exit_gui(): """Exit program.""" root.destroy() sys.exit(0) # ToDo: other return codes def center(window): """Center window.""" window.update_idletasks() width = window.winfo_width() frm_width = window.winfo_rootx() - window.winfo_x() win_width = width + 2 * frm_width height = window.winfo_height() titlebar_height = window.winfo_rooty() - window.winfo_y() win_height = height + titlebar_height + frm_width x = window.winfo_screenwidth() // 2 - win_width // 2 y = window.winfo_screenheight() // 2 - win_height // 2 window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) if window.attributes('-alpha') == 0: window.attributes('-alpha', 1.0) window.deiconify() def show_help(*args): """Show help message.""" tk_msg_box.showinfo(lcl.HELP, common.usage()) print(common.banner()) root = tk.Tk() root.withdraw() win = tk.Toplevel(root) # for exit confirmation win.protocol('WM_DELETE_WINDOW', exit_gui) win.title(lcl.WIN_TITLE) # not resizable win.resizable(False, False) # resizable (limits) # win.minsize(250, 125) # win.maxsize(500, 250) # needed by center function? # win.attributes('-alpha', 0.0) win.bind('<F1>', show_help) # menu win.option_add('*tearOff', False) menubar = tk.Menu(win) win.config(menu=menubar) filemenu = tk.Menu(menubar) helpmenu = tk.Menu(menubar) menubar.add_cascade(label=lcl.FILE, menu=filemenu, underline=0) menubar.add_cascade(label=lcl.HELP, menu=helpmenu, underline=0) filemenu.add_command(label=lcl.EXIT, underline=0, command=exit_gui) helpmenu.add_command(label=lcl.HELP, underline=0, command=show_help, accelerator='F1') helpmenu.add_separator() helpmenu.add_command(label=lcl.ABOUT, underline=0, state='disabled') # ToDo: log menu item # filemenu.add_separator() # check = StringVar(value=1) # filemenu.add_checkbutton(label='Log', variable=check, onvalue=1, # offvalue=0) frame = tk_ttk.Frame(win, padding='3 3 3 3') frame.grid(column=0, row=0, sticky='WNES') # if the main window is resized, the frame should expand # frame.columnconfigure(0, weight=1) # frame.rowconfigure(0, weight=1) private_lbl = tk.StringVar(value=lcl.PRIVATE_IP + shrd.get_private_ip()) public_lbl = tk.StringVar(value=lcl.PUBLIC_IP + shrd.get_public_ip()) # 1st row tk_ttk.Label(frame, textvariable=private_lbl).grid(column=1, row=1) # 2nd row tk_ttk.Label(frame, textvariable=public_lbl).grid(column=1, row=2) # remove if windows is non resizable # tk_ttk.Sizegrip(frame).grid(column=999, row=999, sticky=(E,S)) # padding around all widgets for widget in frame.winfo_children(): widget.grid_configure(padx=5, pady=5) # center window center(win) root.mainloop()