def test_pack_snap_output_file_output_directory_non_existant(mocker, new_dir): """Output to a non-existent directory.""" mock_run = mocker.patch("subprocess.run") output_directory = new_dir / "output" assert not output_directory.exists() pack.pack_snap(new_dir, output=output_directory / "test.snap") assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( [ "snap", "pack", "--filename", "test.snap", new_dir, (new_dir / "output"), ], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_error(mocker, new_dir): mocker.patch("subprocess.run", side_effect=subprocess.CalledProcessError(42, "cmd")) with pytest.raises(errors.SnapcraftError) as raised: pack.pack_snap(new_dir, output=str(new_dir)) assert str(raised.value) == ( "Cannot pack snap file: Command 'cmd' returned non-zero exit status 42." )
def run(self, parsed_args): """Run the command.""" if parsed_args.directory: snap_filename = pack.pack_snap(parsed_args.directory, output=parsed_args.output) emit.message(f"Created snap package {snap_filename}") else: super().run(parsed_args)
def test_pack_snap(mocker, new_dir): mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=None) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_output_file_output_directory_cwd(mocker, new_dir): """Output to a filename in the current working directory.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=f"{new_dir}/test.snap") assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", "--filename", "test.snap", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_compression(mocker, new_dir): """Compression should be passed to snap pack.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=None, compression="zz") assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", "--compression", "zz", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_compression_none(mocker, new_dir): """No compression uses snap default.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=None, compression=None) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_output_directory_cwd_no_filename(mocker, new_dir): """Output to the current working directory when no filename is specified.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=str(new_dir)) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_file_name_missing_parameters(mocker, new_dir, parameters): """If name, version, and target architecture are not all specified, then use snap's default naming convention.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap(new_dir, output=None, **parameters) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_output_file_output_directory_existing_no_filename(mocker, new_dir): """Outputs to an existing directory when no filename is specified.""" mock_run = mocker.patch("subprocess.run") output_directory = new_dir / "output" output_directory.mkdir() assert output_directory.is_dir() pack.pack_snap(new_dir, output=output_directory) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", new_dir, output_directory], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_use_output_name_over_name_version_arch(mocker, new_dir): """Output filename takes priority over name, version, and target_arch parameters.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap( new_dir, output="test.snap", name="hello", version="1.0", target_arch="armhf", ) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", "--filename", "test.snap", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def test_pack_snap_file_name_valid(mocker, new_dir): """Passing name, version, and target_arch should produce a valid file name.""" mock_run = mocker.patch("subprocess.run") pack.pack_snap( new_dir, output=None, name="hello", version="1.0", target_arch="armhf", ) assert mock_run.mock_calls[:2] == [ call( ["snap", "pack", "--check-skeleton", new_dir], capture_output=True, check=True, universal_newlines=True, ), call( ["snap", "pack", "--filename", "hello_1.0_armhf.snap", new_dir, new_dir], capture_output=True, check=True, universal_newlines=True, ), ]
def _run_command( command_name: str, *, project: Project, parse_info: Dict[str, List[str]], assets_dir: Path, start_time: datetime, parallel_build_count: int, parsed_args: "argparse.Namespace", ) -> None: managed_mode = utils.is_managed_mode() part_names = getattr(parsed_args, "parts", None) if not managed_mode: run_project_checks(project, assets_dir=assets_dir) if command_name == "snap": emit.progress( "The 'snap' command is deprecated, use 'pack' instead.", permanent=True, ) if parsed_args.use_lxd and providers.get_platform_default_provider( ) == "lxd": emit.progress("LXD is used by default on this platform.", permanent=True) if (not managed_mode and not parsed_args.destructive_mode and not os.getenv("SNAPCRAFT_BUILD_ENVIRONMENT") == "host"): if command_name == "clean" and not part_names: _clean_provider(project, parsed_args) else: _run_in_provider(project, command_name, parsed_args) return if managed_mode: work_dir = utils.get_managed_environment_home_path() project_dir = utils.get_managed_environment_project_path() else: work_dir = Path.cwd() project_dir = Path.cwd() step_name = "prime" if command_name in ("pack", "snap") else command_name lifecycle = PartsLifecycle( project.parts, work_dir=work_dir, assets_dir=assets_dir, base=project.get_effective_base(), package_repositories=project.package_repositories, parallel_build_count=parallel_build_count, part_names=part_names, adopt_info=project.adopt_info, project_name=project.name, parse_info=parse_info, project_vars={ "version": project.version or "", "grade": project.grade or "", }, extra_build_snaps=project.get_extra_build_snaps(), ) if command_name == "clean": lifecycle.clean(part_names=part_names) return lifecycle.run( step_name, debug=parsed_args.debug, shell=getattr(parsed_args, "shell", False), shell_after=getattr(parsed_args, "shell_after", False), ) # Extract metadata and generate snap.yaml project_vars = lifecycle.project_vars if step_name == "prime" and not part_names: emit.progress("Extracting and updating metadata...") metadata_list = lifecycle.extract_metadata() update_project_metadata( project, project_vars=project_vars, metadata_list=metadata_list, assets_dir=assets_dir, prime_dir=lifecycle.prime_dir, ) emit.progress("Copying snap assets...") setup_assets( project, assets_dir=assets_dir, project_dir=project_dir, prime_dir=lifecycle.prime_dir, ) emit.progress("Generating snap metadata...") snap_yaml.write( project, lifecycle.prime_dir, arch=lifecycle.target_arch, arch_triplet=lifecycle.target_arch_triplet, ) emit.progress("Generated snap metadata", permanent=True) if parsed_args.enable_manifest: _generate_manifest( project, lifecycle=lifecycle, start_time=start_time, parsed_args=parsed_args, ) if command_name in ("pack", "snap"): snap_filename = pack.pack_snap( lifecycle.prime_dir, output=parsed_args.output, compression=project.compression, name=project.name, version=process_version(project.version), target_arch=lifecycle.target_arch, ) emit.message(f"Created snap package {snap_filename}")
def _run_command( command_name: str, *, project: Project, parse_info: Dict[str, List[str]], assets_dir: Path, start_time: datetime, parallel_build_count: int, parsed_args: "argparse.Namespace", ) -> None: managed_mode = utils.is_managed_mode() part_names = getattr(parsed_args, "parts", None) if not managed_mode: run_project_checks(project, assets_dir=assets_dir) if command_name == "snap": emit.progress( "The 'snap' command is deprecated, use 'pack' instead.", permanent=True, ) if parsed_args.use_lxd and providers.get_platform_default_provider( ) == "lxd": emit.progress("LXD is used by default on this platform.", permanent=True) if (not managed_mode and not parsed_args.destructive_mode and not os.getenv("SNAPCRAFT_BUILD_ENVIRONMENT") == "host"): if command_name == "clean" and not part_names: _clean_provider(project, parsed_args) else: _run_in_provider(project, command_name, parsed_args) return if managed_mode: work_dir = utils.get_managed_environment_home_path() project_dir = utils.get_managed_environment_project_path() else: work_dir = project_dir = Path.cwd() step_name = "prime" if command_name in ("pack", "snap") else command_name lifecycle = PartsLifecycle( project.parts, work_dir=work_dir, assets_dir=assets_dir, base=project.get_effective_base(), package_repositories=project.package_repositories, parallel_build_count=parallel_build_count, part_names=part_names, adopt_info=project.adopt_info, project_name=project.name, parse_info=parse_info, project_vars={ "version": project.version or "", "grade": project.grade or "", }, extra_build_snaps=project.get_extra_build_snaps(), target_arch=project.get_build_for(), ) if command_name == "clean": lifecycle.clean(part_names=part_names) return lifecycle.run( step_name, debug=parsed_args.debug, shell=getattr(parsed_args, "shell", False), shell_after=getattr(parsed_args, "shell_after", False), ) # Extract metadata and generate snap.yaml if step_name == "prime" and not part_names: _generate_metadata( project=project, lifecycle=lifecycle, project_dir=project_dir, assets_dir=assets_dir, start_time=start_time, parsed_args=parsed_args, ) if command_name in ("pack", "snap"): issues = linters.run_linters(lifecycle.prime_dir, lint=project.lint) status = linters.report(issues, intermediate=True) # In case of linter errors, stop execution and return the error code. if status in (LinterStatus.ERRORS, LinterStatus.FATAL): raise errors.LinterError("Linter errors found", exit_code=status) snap_filename = pack.pack_snap( lifecycle.prime_dir, output=parsed_args.output, compression=project.compression, name=project.name, version=process_version(project.version), target_arch=project.get_build_for(), ) emit.message(f"Created snap package {snap_filename}")