# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-FileCopyrightText: 2011-2024 Blender Authors # import json import os import worker.blender.version import worker.deploy import worker.utils def package(builder: worker.deploy.CodeStoreBuilder) -> None: dry_run = False if builder.service_env_id == "LOCAL" and not ( builder.platform == "linux" and worker.utils.is_tool("snapcraft") ): worker.utils.warning("Performing dry run on LOCAL service environment") dry_run = True elif not builder.platform == "linux": raise Exception("Can only run snapcraft on Linux, aborting") version_info = worker.blender.version.VersionInfo(builder) needs_stable_grade = version_info.risk_id in ["candidate", "stable"] grade = "stable" if needs_stable_grade else "devel" # Clean directory for old_package_file in builder.store_snap_dir.glob("*.tar.xz"): worker.utils.remove_file(old_package_file) os.makedirs(builder.store_snap_dir, exist_ok=True) # Get input package file path package_manifest = builder.package_dir / "manifest.json" builds = json.loads(package_manifest.read_text()) linux_package_file_path = None for build in builds: if build["platform"] == "linux" and build["file_extension"] == "tar.xz": linux_package_file_path = builder.package_dir / build["file_name"] break if not linux_package_file_path: raise Exception(f"Linux package not found in [{builder.package_dir}] manifest") source_file_path = linux_package_file_path dest_file_path = builder.store_snap_dir / linux_package_file_path.name worker.utils.info(f"Copy file [{source_file_path}] -> [{dest_file_path}]") worker.utils.copy_file(source_file_path, dest_file_path) freedesktop_path = builder.code_path / "release" / "freedesktop" snap_source_root_path = freedesktop_path / "snap" blender_icon_file_name = "blender.svg" snapcraft_template_file_path = ( snap_source_root_path / "blender-snapcraft-template.yaml" ) worker.utils.info(f"Using snap config file [{snapcraft_template_file_path}]") snapcraft_text = snapcraft_template_file_path.read_text() snapcraft_text = snapcraft_text.replace("@VERSION@", version_info.version) snapcraft_text = snapcraft_text.replace("@GRADE@", grade) snapcraft_text = snapcraft_text.replace( "@ICON_PATH@", f"./{blender_icon_file_name}" ) snapcraft_text = snapcraft_text.replace( "@PACKAGE_PATH@", f"./{linux_package_file_path.name}" ) snapcraft_file_path = builder.store_snap_dir / "snapcraft.yaml" worker.utils.info(f"Saving snapcraft config file [{snapcraft_file_path}]") snapcraft_file_path.write_text(snapcraft_text) print(snapcraft_text) snap_package_file_name = f"blender_{version_info.version}_amd64.snap" snap_package_file_path = builder.store_snap_dir / snap_package_file_name if snap_package_file_path.exists(): worker.utils.info(f"Clearing snap file [{snap_package_file_path}]") worker.utils.remove_file(snap_package_file_path) os.chdir(builder.store_snap_dir) # Copy all required files into working folder source_file_path = ( freedesktop_path / "icons" / "scalable" / "apps" / blender_icon_file_name ) dest_file_path = builder.store_snap_dir / "blender.svg" worker.utils.info(f"Copy file [{source_file_path}] -> [{dest_file_path}]") worker.utils.copy_file(source_file_path, dest_file_path) source_file_path = snap_source_root_path / "blender-wrapper" dest_file_path = builder.store_snap_dir / "blender-wrapper" worker.utils.info(f"Copy file [{source_file_path}] -> [{dest_file_path}]") worker.utils.copy_file(source_file_path, dest_file_path) worker.utils.call(["snapcraft", "clean", "--use-lxd"], dry_run=dry_run) worker.utils.call(["snapcraft", "--use-lxd"], dry_run=dry_run) worker.utils.call( ["review-tools.snap-review", snap_package_file_path, "--allow-classic"], dry_run=dry_run, ) if dry_run: snap_package_file_path.write_text("Dry run dummy package file") worker.utils.info("To test the snap package run this command") print("sudo snap remove blender") print(f"sudo snap install --dangerous --classic {snap_package_file_path}") def deliver(builder: worker.deploy.CodeStoreBuilder) -> None: dry_run = False if builder.service_env_id == "LOCAL": worker.utils.warning("Performing dry run on LOCAL service environment") dry_run = True elif not builder.platform == "linux": raise Exception("Can only run snapcraft on Linux, aborting") version_info = worker.blender.version.VersionInfo(builder) branches_config = builder.get_branches_config() is_lts = builder.track_id in branches_config.all_lts_tracks is_latest = ( branches_config.track_major_minor_versions[builder.track_id] == version_info.short_version ) # Never push to stable snap_risk_id = version_info.risk_id.replace("stable", "candidate").replace( "alpha", "edge" ) if snap_risk_id == "stable": raise Exception("Delivery to [stable] channel not allowed") snap_track_id = version_info.short_version if is_lts: snap_track_id += "lts" needs_release = True elif is_latest: # latest/edge always vdev snap_track_id = "latest" needs_release = True else: # Push current release under development to beta or candidate needs_release = True # worker.utils.call(["snapcraft", "list-tracks", "blender"], dry_run=dry_run) snap_package_file_name = f"blender_{version_info.version}_amd64.snap" snap_package_file_path = builder.store_snap_dir / snap_package_file_name if not snap_package_file_path.exists(): raise Exception(f"Snap file [{snap_package_file_path}] missing") worker_config = builder.get_worker_config() env = os.environ.copy() env["SNAPCRAFT_STORE_CREDENTIALS"] = worker_config.snap_credentials( builder.service_env_id ) # If this fails, then the permissions were not set correcty with acls worker.utils.call(["snapcraft", "status", "blender"], dry_run=dry_run, env=env) if needs_release: # Upload and release. snap_channel = f"{snap_track_id}/{snap_risk_id}" cmd = ["snapcraft", "upload", "--release", snap_channel, snap_package_file_path] else: # Upload only. snap_channel = "" cmd = ["snapcraft", "upload", snap_package_file_path] # Some api call is making this fail, seems to be status based as we can upload and set channel worker.utils.call(cmd, retry_count=5, retry_wait_time=120, dry_run=dry_run, env=env) if needs_release: worker.utils.info("To test the snap package run this command") print(f"sudo snap refresh blender --classic --channel {snap_channel}")