250 lines
8.5 KiB
Python
250 lines
8.5 KiB
Python
import argparse
|
|
import pathlib
|
|
import shutil
|
|
import sys
|
|
|
|
import modulus.artifacts
|
|
import modulus.build
|
|
import modulus.conan
|
|
import modulus.container
|
|
import modulus.process
|
|
import modulus.publishing
|
|
import modulus.python
|
|
|
|
def create_package(context, target, update, no_remote=False):
|
|
command = [
|
|
"conan",
|
|
"create",
|
|
".",
|
|
f"--profile:host={target.profile}",
|
|
f"--profile:build={context.default_target.profile}",
|
|
f"--build={modulus.publishing.package_name(context)}/*",
|
|
*modulus.build.dependency_build_args(context),
|
|
"-o",
|
|
"&:with_tests=False",
|
|
]
|
|
if update:
|
|
command.append("--update")
|
|
if no_remote:
|
|
command.append("--no-remote")
|
|
return modulus.process.run(context, command)
|
|
|
|
def upload_all_packages(context, remote, force=False):
|
|
command = [
|
|
"conan",
|
|
"upload",
|
|
f"{modulus.publishing.package_name(context)}/latest:*",
|
|
"-r",
|
|
remote,
|
|
"--confirm",
|
|
]
|
|
if force:
|
|
command.append("--force")
|
|
return modulus.process.run(context, command)
|
|
|
|
def upload_packages(context, replace=False):
|
|
if replace and not modulus.publishing.allow_package_replace():
|
|
print("--replace requires MODULUS_ALLOW_PACKAGE_REPLACE=1", file=sys.stderr)
|
|
return 1
|
|
remote = modulus.conan.conan_remote(context)
|
|
try:
|
|
status = modulus.conan.configure_conan_remote(context, authenticate=True)
|
|
if status == 0:
|
|
status = upload_all_packages(context, remote, force=replace)
|
|
finally:
|
|
logout_status = modulus.process.run(context, ["conan", "remote", "logout", remote])
|
|
status = status or logout_status
|
|
if status != 0 and not replace:
|
|
print(f"upload failed for {modulus.publishing.package_name(context)}/latest. Use --replace with MODULUS_ALLOW_PACKAGE_REPLACE=1 to intentionally replace an existing version.", file=sys.stderr)
|
|
return status
|
|
|
|
def package_artifact_conan_option_args(context):
|
|
result = []
|
|
for name, value in context.artifact["conan_options"].items():
|
|
result.extend(["-o", f"&:{name}={modulus.build.option_value(value)}"])
|
|
return result
|
|
|
|
def package_artifact_cmake_definition_args(context):
|
|
return modulus.build.cmake_definition_args(context.artifact["cmake_definitions"])
|
|
|
|
def package_artifact_targets(context, names, all_targets):
|
|
if all_targets or names:
|
|
return context.selected_targets(names, all_targets)
|
|
configured = context.artifact["targets"]
|
|
if configured:
|
|
return [context.target(name) for name in configured]
|
|
return [context.default_target]
|
|
|
|
def package_artifact_build_root(context, target):
|
|
return context.common_dir / "artifacts" / target.name
|
|
|
|
def package_artifact_dist_dir(context):
|
|
return context.build_root / "packages"
|
|
|
|
def package_artifact_install_prefix(context, stage_root):
|
|
install_prefix = pathlib.Path(str(context.artifact["install_prefix"]))
|
|
if str(install_prefix) == ".":
|
|
return stage_root
|
|
return stage_root / install_prefix
|
|
|
|
def create_artifact_package(context, target, update, no_remote=False):
|
|
modulus.python.interpreter(context, install=True, offline=no_remote)
|
|
root = package_artifact_build_root(context, target)
|
|
build_dir = root / "build"
|
|
stage_root = root / "stage"
|
|
conan_dir = build_dir / "conan"
|
|
if root.exists():
|
|
shutil.rmtree(root)
|
|
build_dir.mkdir(parents=True)
|
|
stage_root.mkdir(parents=True)
|
|
install_prefix = package_artifact_install_prefix(context, stage_root)
|
|
install_prefix.mkdir(parents=True, exist_ok=True)
|
|
conan_command = [
|
|
"conan",
|
|
"install",
|
|
".",
|
|
f"--output-folder={conan_dir}",
|
|
f"--profile:host={target.profile}",
|
|
f"--profile:build={context.default_target.profile}",
|
|
*modulus.build.dependency_build_args(context),
|
|
"-o",
|
|
"&:with_tests=False",
|
|
*package_artifact_conan_option_args(context),
|
|
]
|
|
if update:
|
|
conan_command.append("--update")
|
|
if no_remote:
|
|
conan_command.append("--no-remote")
|
|
status = modulus.process.run(context, conan_command)
|
|
if status != 0:
|
|
return status, []
|
|
status = modulus.process.run(
|
|
context,
|
|
[
|
|
"cmake",
|
|
"-S",
|
|
".",
|
|
"-B",
|
|
build_dir,
|
|
"-G",
|
|
"Ninja",
|
|
f"-DCMAKE_TOOLCHAIN_FILE={conan_dir / 'conan_toolchain.cmake'}",
|
|
f"-DCMAKE_BUILD_TYPE={target.build_type}",
|
|
"-DBUILD_TESTING=OFF",
|
|
f"-DCMAKE_PREFIX_PATH={conan_dir}",
|
|
f"-DCMAKE_INSTALL_PREFIX={install_prefix}",
|
|
*modulus.build.cmake_definition_args(modulus.python.cmake_definitions(context)),
|
|
*package_artifact_cmake_definition_args(context),
|
|
],
|
|
)
|
|
if status != 0:
|
|
return status, []
|
|
status = modulus.process.run(
|
|
context,
|
|
[
|
|
"cmake",
|
|
"--build",
|
|
build_dir,
|
|
"--parallel",
|
|
"2",
|
|
],
|
|
)
|
|
if status != 0:
|
|
return status, []
|
|
status = modulus.process.run(
|
|
context,
|
|
[
|
|
"cmake",
|
|
"--install",
|
|
build_dir,
|
|
],
|
|
)
|
|
if status != 0:
|
|
return status, []
|
|
dist_dir = package_artifact_dist_dir(context)
|
|
dist_dir.mkdir(parents=True, exist_ok=True)
|
|
archive = dist_dir / modulus.artifacts.archive_name(modulus.publishing.package_name(context), target.name)
|
|
if archive.exists():
|
|
archive.unlink()
|
|
modulus.artifacts.create_archive(stage_root, archive)
|
|
checksum = modulus.artifacts.write_checksum(archive)
|
|
print(f"Created {archive}")
|
|
print(f"Created {checksum}")
|
|
return 0, [archive, checksum]
|
|
|
|
def package_artifacts(context, argv):
|
|
if not modulus.process.in_docker(context):
|
|
return modulus.container.docker_run(
|
|
context,
|
|
[
|
|
f"./{context.tools_rel}/package.py",
|
|
*argv,
|
|
],
|
|
)
|
|
parser = argparse.ArgumentParser(description=f"Create {context.package['name']} application tarballs.")
|
|
parser.add_argument(
|
|
"--target",
|
|
action="append",
|
|
default=[],
|
|
choices=sorted(context.targets),
|
|
help="Target to package. May be passed more than once. Defaults to package.artifact.targets.",
|
|
)
|
|
parser.add_argument("--all", action="store_true", help="Package all supported targets.")
|
|
parser.add_argument("--update", action="store_true", help="Check Conan remotes for newer dependency revisions.")
|
|
parser.add_argument("--no-remote", action="store_true", help="Do not query Conan remotes or upload package artifacts.")
|
|
args = parser.parse_args(argv)
|
|
context.conan_cache_dir.mkdir(parents=True, exist_ok=True)
|
|
if modulus.publishing.should_upload_artifacts(context) and not args.no_remote and modulus.publishing.package_registry_credentials() is None:
|
|
return 1
|
|
if not args.no_remote:
|
|
status = modulus.conan.configure_conan_remote(context)
|
|
if status != 0:
|
|
return status
|
|
artifacts = []
|
|
for target in package_artifact_targets(context, args.target, args.all):
|
|
status, created = create_artifact_package(context, target, args.update, no_remote=args.no_remote)
|
|
if status != 0:
|
|
return status
|
|
artifacts.extend(created)
|
|
if modulus.publishing.should_upload_artifacts(context) and not args.no_remote:
|
|
return modulus.artifacts.main(context, [])
|
|
return 0
|
|
|
|
def package(context, argv):
|
|
if modulus.publishing.artifact_packaging_enabled(context):
|
|
return package_artifacts(context, argv)
|
|
if not modulus.process.in_docker(context):
|
|
return modulus.container.docker_run(
|
|
context,
|
|
[
|
|
f"./{context.tools_rel}/package.py",
|
|
*argv,
|
|
],
|
|
)
|
|
parser = argparse.ArgumentParser(description=f"Create {context.package['name']} Conan packages.")
|
|
parser.add_argument(
|
|
"--target",
|
|
action="append",
|
|
default=[],
|
|
choices=sorted(context.targets),
|
|
help="Target to package. May be passed more than once. Defaults to the default target.",
|
|
)
|
|
parser.add_argument("--all", action="store_true", help="Package all supported targets.")
|
|
parser.add_argument("--update", action="store_true", help="Check Conan remotes for newer dependency revisions.")
|
|
parser.add_argument("--no-remote", action="store_true", help="Do not query Conan remotes. Requires all dependencies to be available locally or buildable from local recipes.")
|
|
parser.add_argument("--replace", action="store_true", help="Delete the remote package version before upload. Requires MODULUS_ALLOW_PACKAGE_REPLACE=1.")
|
|
args = parser.parse_args(argv)
|
|
context.conan_cache_dir.mkdir(parents=True, exist_ok=True)
|
|
if not args.no_remote:
|
|
status = modulus.conan.configure_conan_remote(context)
|
|
if status != 0:
|
|
return status
|
|
update = args.update
|
|
for target in context.selected_targets(args.target, args.all):
|
|
status = create_package(context, target, update, no_remote=args.no_remote)
|
|
if status != 0:
|
|
return status
|
|
if modulus.publishing.should_upload(context) and not args.no_remote:
|
|
return upload_packages(context, replace=args.replace)
|
|
return 0
|