def test_setup_environment_content_x86(tmp_work_path, monkeypatch, machine_platform, distro): snapcraft_project = Project() snapcraft_project._snap_meta = Snap(name="test-snap", base=distro[0]) monkeypatch.setattr(platform, "machine", lambda: machine_platform[0]) recorded_files = dict() @contextlib.contextmanager def fake_namedtempfile(*, suffix: str, **kwargs): # Usage hides the file basename in the suffix. tmp_path = os.path.join("tmpfile") with open(tmp_path, "wb") as f_write: yield f_write with open(tmp_path, "r") as f_read: recorded_files[suffix] = f_read.read() monkeypatch.setattr(tempfile, "NamedTemporaryFile", fake_namedtempfile) provider = ProviderImpl(project=snapcraft_project, echoer=Mock()) provider._setup_environment() assert recorded_files == { ".bashrc": '#!/bin/bash\nexport PS1="\\h \\$(/bin/_snapcraft_prompt)# "\n', "00-snapcraft": 'Apt::Install-Recommends "false";\n', "_snapcraft_prompt": dedent("""\ #!/bin/bash if [[ "$PWD" =~ ^$HOME.* ]]; then path="${PWD/#$HOME/\\ ..}" if [[ "$path" == " .." ]]; then ps1="" else ps1="$path" fi else ps1="$PWD" fi echo -n $ps1 """), "default.sources": dedent(f"""\ Types: deb URIs: {machine_platform[1]["main"]} Suites: {distro[1]} {distro[1]}-updates Components: main multiverse restricted universe """), "default-security.sources": dedent(f"""\ Types: deb URIs: {machine_platform[1]["security"]} Suites: {distro[1]}-security Components: main multiverse restricted universe """), "sources.list": "", }
def conduct_project_sanity_check(project: Project, **kwargs) -> None: """Sanity check the project itself before continuing. The checks done here are meant to be light, and not rely on the build environment. """ # The snapcraft.yaml should be valid even without extensions applied # This here check is mostly for backwards compatibility with the # rest of the code base. if project.info is not None: project.info.validate_raw_snapcraft() if project._get_build_base() == "core": raise errors.UnsupportedBaseError(base="core") snap_dir_path = os.path.join(project._get_snapcraft_assets_dir()) if os.path.isdir(snap_dir_path): # TODO: move this check to the ProjectInfo class. _check_snap_dir(snap_dir_path) if ( project._get_build_base() in ["core20"] and kwargs.get("target_arch") is not None and not os.getenv("SNAPCRAFT_ENABLE_EXPERIMENTAL_TARGET_ARCH") ): raise SnapcraftEnvironmentError( "*EXPERIMENTAL* '--target-arch' configured, but not enabled. " "Enable with '--enable-experimental-target-arch' flag." ) # Icon should refer to project file, verify it exists. icon = project.info.get_raw_snapcraft().get("icon") if icon and not os.path.exists(icon): raise SnapcraftEnvironmentError(f"Specified icon {icon!r} does not exist.")
def get_project(base: str = "core20") -> Project: project = Project() project._snap_meta = Snap(name="project-name", base=base, version="1.0", confinement="strict") return project
def get_project(*, is_managed_host: bool = False, **kwargs): # We need to do this here until we can get_snapcraft_yaml as part of Project. if is_managed_host: try: os.chdir(os.path.expanduser(os.path.join("~", "project"))) except FileNotFoundError: # No project found (fresh environment). raise errors.ProjectNotFoundError() snapcraft_yaml_file_path = get_snapcraft_yaml() # This method may be called from a click.Command with no parent. ctx = click.get_current_context() if ctx.parent is not None: for key, value in ctx.parent.params.items(): if not kwargs.get(key): kwargs[key] = value project = Project( debug=kwargs.pop("debug", False), target_deb_arch=kwargs.pop("target_arch", None), snapcraft_yaml_file_path=snapcraft_yaml_file_path, is_managed_host=is_managed_host, ) # Validate yaml info from schema prior to consumption. if project.info is not None: project.info.validate_raw_snapcraft() # TODO: this should be automatic on get_project(). # This is not the complete meta parsed by the project loader. project._snap_meta = Snap.from_dict(project.info.get_raw_snapcraft()) return project
def project(monkeypatch, tmp_work_path, request): """Return project variants for core and core18""" monkeypatch.setattr(Project, "parallel_build_count", 2) snapcraft_project = Project() snapcraft_project._snap_meta = Snap(name="test-snap", base="core18", confinement="strict") return snapcraft_project
def test_pull_is_dirty_if_target_arch_changes( self, mock_install_build_snaps, mock_install_build_packages, mock_enable_cross_compilation, ): # Set the option to error on dirty/outdated steps with snapcraft_legacy.config.CLIConfig() as cli_config: cli_config.set_outdated_step_action( snapcraft_legacy.config.OutdatedStepAction.ERROR) mock_install_build_packages.return_value = [] project_config = self.make_snapcraft_project( textwrap.dedent("""\ parts: part1: plugin: nil """)) project = Project( snapcraft_yaml_file_path=self.snapcraft_yaml_file_path, target_deb_arch="amd64", ) project_config = project_loader.load_config(project) # Pull it with amd64 lifecycle.execute(steps.PULL, project_config) # Reset logging since we only care about the following self.fake_logger = fixtures.FakeLogger(level=logging.INFO) self.useFixture(self.fake_logger) project = Project( snapcraft_yaml_file_path=self.snapcraft_yaml_file_path, target_deb_arch="armhf", ) project_config = project_loader.load_config(project) # Pull it again with armhf. Should catch that the part needs to be # re-pulled due to the change in target architecture and raise an # error. raised = self.assertRaises(errors.StepOutdatedError, lifecycle.execute, steps.PULL, project_config) self.assertThat(self.fake_logger.output, Contains("Setting target machine to 'armhf'")) self.assertThat(raised.step, Equals(steps.PULL)) self.assertThat(raised.part, Equals("part1")) self.assertThat( raised.report, Equals("The 'deb_arch' project option appears to have changed.\n"), )
def test_use_invalid_openjdk_version_fails(self, base, version, expected_message): class Options: maven_options = [] maven_targets = [""] maven_version = maven._DEFAULT_MAVEN_VERSION maven_version_checksum = maven._DEFAULT_MAVEN_CHECKSUM maven_openjdk_version = version project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") with pytest.raises(maven.UnsupportedJDKVersionError) as error: maven.MavenPlugin("test-part", Options(), project) assert str(error) == expected_message
def test_cross_compile(monkeypatch, deb_arch): monkeypatch.setattr(Project, "is_cross_compiling", True) class Options: configflags = [] project = Project(target_deb_arch=deb_arch) project._snap_meta = meta.snap.Snap(name="test-snap", base="core18") plugin = waf.WafPlugin("test-part", Options(), project) plugin.enable_cross_compilation() env = plugin.env(plugin.sourcedir) assert f"CC={project.arch_triplet}-gcc" in env assert f"CXX={project.arch_triplet}-g++" in env
def test_use_invalid_openjdk_version_fails(self, base, version, expected_message): class Options: ant_properties = {} ant_build_targets = None ant_channel = None ant_version = "1.10.5" ant_version_checksum = "sha512/a7f1e0cec9d5ed1b3ab6cddbb9364f127305a997bbc88ecd734f9ef142ec0332375e01ace3592759bb5c3307cd9c1ac0a78a30053f304c7030ea459498e4ce4e" ant_openjdk_version = version project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") with pytest.raises(ant.UnsupportedJDKVersionError) as error: ant.AntPlugin("test-part", Options(), project) assert str(error) == expected_message
def maven_plugin(tmp_work_path, request): """Return an instance of MavenPlugin setup with different bases and java versions.""" java_version, base = request.param class Options: maven_options = [] maven_targets = [""] maven_version = maven._DEFAULT_MAVEN_VERSION maven_version_checksum = maven._DEFAULT_MAVEN_CHECKSUM maven_openjdk_version = java_version project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") return maven.MavenPlugin("test-part", Options(), project)
def project(snapcraft_yaml_path, request): """Return a project in host and managed-host modes.""" snapcraft_project = Project( is_managed_host=request.param, snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix(), ) return snapcraft_project
def setUp(self): super().setUp() self.project = Project() self.project._snap_meta = Snap(name="test-snap", base="core18", confinement="strict")
def get_project_config(snapcraft_yaml_content): snapcraft_yaml_path = pathlib.Path("snapcraft.yaml") with snapcraft_yaml_path.open("w") as snapcraft_yaml_file: print(snapcraft_yaml_content, file=snapcraft_yaml_file) project = Project(snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix()) return project_loader.load_config(project)
def __init__(self, project: project.Project) -> None: self.build_snaps: Set[str] = set() self.project = project # raw_snapcraft_yaml is read only, create a new copy snapcraft_yaml = apply_extensions(project.info.get_raw_snapcraft()) self.validator = Validator(snapcraft_yaml) self.validator.validate() snapcraft_yaml = self._expand_filesets(snapcraft_yaml) self.data = self._expand_env(snapcraft_yaml) self.data["architectures"] = _process_architectures( self.data.get("architectures"), project.deb_arch) self._ensure_no_duplicate_app_aliases() self._global_grammar_processor = grammar_processing.GlobalGrammarProcessor( properties=self.data, arch=project.host_deb_arch, target_arch=project.target_arch, ) # XXX: Resetting snap_meta due to above mangling of data. # Convergence to operating on snap_meta will remove this requirement... project._snap_meta = Snap.from_dict(self.data) self.parts = PartsConfig(parts=self.data, project=project, validator=self.validator)
def test_use_invalid_openjdk_version_fails(self, base, version, expected_message): class Options: gradle_options = [] gradle_output_dir = "build/libs" gradle_version = gradle._DEFAULT_GRADLE_VERSION gradle_version_checksum = gradle._DEFAULT_GRADLE_CHECKSUM gradle_openjdk_version = version project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") with pytest.raises(gradle.UnsupportedJDKVersionError) as error: gradle.GradlePlugin("test-part", Options(), project) assert str(error) == expected_message
def ant_plugin(tmp_work_path, request): """Return an instance of AntPlugin setup with different bases and java versions.""" java_version, base = request.param class Options: ant_properties = {} ant_build_targets = None ant_channel = None ant_version = "1.10.5" ant_version_checksum = "sha512/a7f1e0cec9d5ed1b3ab6cddbb9364f127305a997bbc88ecd734f9ef142ec0332375e01ace3592759bb5c3307cd9c1ac0a78a30053f304c7030ea459498e4ce4e" ant_openjdk_version = java_version ant_buildfile = None project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") return ant.AntPlugin("test-part", Options(), project)
def test_project_with_arguments(): project = Project(target_deb_arch="armhf", debug=True) assert project.deb_arch == "armhf" assert project.debug is True # This is a backwards compatibility check assert project.info is None
def gradle_plugin(tmp_path, request): """Return an instance of GradlePlugin setup with different bases and java versions.""" java_version, base = request.param class Options: gradle_options = [] gradle_output_dir = "build/libs" gradle_version = gradle._DEFAULT_GRADLE_VERSION gradle_version_checksum = gradle._DEFAULT_GRADLE_CHECKSUM gradle_openjdk_version = java_version os.chdir(tmp_path) project = Project() project._snap_meta = Snap(name="test-snap", base=base, confinement="strict") return gradle.GradlePlugin("test-part", Options(), project)
def load_plugin( plugin_name: str, part_name: str, project: Project, properties, part_schema, definitions_schema, ) -> plugins.v1.PluginV1: local_plugins_dir = project._get_local_plugins_dir() if local_plugins_dir is not None: plugin_class = _get_local_plugin_class( plugin_name=plugin_name, local_plugins_dir=local_plugins_dir ) if plugin_class is None: plugin_class = plugins.get_plugin_for_base( plugin_name, build_base=project._get_build_base() ) if issubclass(plugin_class, plugins.v2.PluginV2): plugin_schema = plugin_class.get_schema() options = _make_options( part_name, part_schema, definitions_schema, properties, plugin_schema ) plugin = plugin_class(part_name=part_name, options=options) else: plugin_schema = plugin_class.schema() _validate_pull_and_build_properties( plugin_name, plugin_class, part_schema, definitions_schema ) options = _make_options( part_name, part_schema, definitions_schema, properties, plugin_schema ) plugin = plugin_class(part_name, options, project) if project.is_cross_compiling: logger.debug( "Setting {!r} as the compilation target for {!r}".format( project.deb_arch, plugin_name ) ) plugin.enable_cross_compilation() return plugin
def make_snapcraft_project(self, parts): snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path) snapcraft_yaml.update_part("part1", dict(plugin="nil")) for part_name, part in parts: snapcraft_yaml.update_part(part_name, part) self.useFixture(snapcraft_yaml) project = Project( snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path) return project_loader.load_config(project)
def _get_snap_packaging(self, **yaml_args): if "parts" not in yaml_args: yaml_args["parts"] = dict(part1=dict(plugin="nil")) snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path, **yaml_args) self.useFixture(snapcraft_yaml) project = Project( snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path) config = load_config(project) return _SnapPackaging(project_config=config, extracted_metadata=None)
def test_cross_compile(monkeypatch, tmp_work_path, mock_run, deb_arch, go_arch): monkeypatch.setattr(Project, "is_cross_compiling", True) class Options: source = "" go_packages = ["github.com/gotools/vet"] go_importpath = "" go_buildtags = "" go_channel = "" project = Project(target_deb_arch=deb_arch) project._snap_meta = meta.snap.Snap(name="test-snap", base="core18") plugin = go.GoPlugin("test-part", Options(), project) os.makedirs(plugin.sourcedir) plugin.pull() assert mock_run.call_count == 1 for call_args in mock_run.call_args_list: env = call_args[1]["env"] assert "CC" in env assert env["CC"] == f"{project.arch_triplet}-gcc" assert "CXX" in env assert env["CXX"] == f"{project.arch_triplet}-g++" assert "CGO_ENABLED" in env assert env["CGO_ENABLED"] == "1" assert "GOARCH" in env assert env["GOARCH"] == go_arch if deb_arch == "armhf": assert "GOARM" in env assert env["GOARM"] == "7"
def test_non_prime_and_no_version(self): snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path, version=None) snapcraft_yaml.data["adopt-info"] = "test-part" snapcraft_yaml.update_part( "test-part", { "plugin": "nil", "override-build": "snapcraftctl set-version 1.0" }, ) self.useFixture(snapcraft_yaml) project = Project( snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path) project_config = project_loader.load_config(project) # This should not fail lifecycle.execute(steps.PULL, project_config)
def test_project_with_snapcraft_yaml_file_path_carries_info(tmp_work_path): snapcraft_yaml_path = pathlib.Path("snapcraft.yaml") with snapcraft_yaml_path.open("w") as snapcraft_yaml_file: print( dedent("""\ name: foo version: "1" summary: bar description: baz confinement: strict parts: part1: plugin: go """), file=snapcraft_yaml_file, ) project = Project(snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix()) # Only 1 value is enough assert project.info.name == "foo"
def test_icon(tmp_work_path): snapcraft_yaml_path = tmp_work_path / "snap/snapcraft.yaml" snapcraft_yaml_path.parent.mkdir(parents=True) with snapcraft_yaml_path.open("w") as snapcraft_file: print( dedent("""\ name: project-name base: core18 version: "1.0" summary: sanity checks description: sanity checks grade: stable confinement: strict icon: foo.png parts: nil: plugin: nil """), file=snapcraft_file, ) project = Project( is_managed_host=False, snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix(), ) # Test without icon raises error with pytest.raises(snapcraft_legacy.internal.errors. SnapcraftEnvironmentError) as exc_info: conduct_project_sanity_check(project) assert exc_info.value.get_brief( ) == "Specified icon 'foo.png' does not exist." # Test with icon passes. (tmp_work_path / "foo.png").touch() conduct_project_sanity_check(project)
def test_project_local_plugin_location(tmp_work_path, location): snapcraft_yaml_path = tmp_work_path / pathlib.Path(location) snapcraft_yaml_path.parent.mkdir(parents=True) with snapcraft_yaml_path.open("w") as snapcraft_yaml_file: print( dedent("""\ name: foo version: "1" summary: bar description: baz confinement: strict parts: part1: plugin: go """), file=snapcraft_yaml_file, ) project = Project(snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix()) expected_plugins_dir = snapcraft_yaml_path.parent / "plugins" assert project.local_plugins_dir == expected_plugins_dir.as_posix()
def __init__(self): self.project = Project() self.project._snap_meta = Snap( name="project-name", base="core20", version="1.0", confinement="strict" ) self.parts = Parts()
def test_unsupported_base_raises(flutter_options): project = Project() project._snap_meta = Snap(name="test-snap", base="bad-base", confinement="strict") with pytest.raises(errors.PluginBaseError): flutter.FlutterPlugin("test-part", flutter_options, project)
def load_project_and_worktree(self): """(Re)load project and worktree.""" self._project = Project(snapcraft_yaml_file_path=self._snapcraft_yaml. snapcraft_yaml_file_path) self._project._project_dir = self._source.path self._wt = WorkTree(self._dest.path, self._project)
def setUp(self): super().setUp() self.useFixture(fixtures.FakeLogger(level=logging.ERROR)) temp_cwd = fixture_setup.TempCWD() self.useFixture(temp_cwd) snapcraft_yaml = fixture_setup.SnapcraftYaml( temp_cwd.path, base="core18", parts={"test-part": { "plugin": "nil" }}) self.useFixture(snapcraft_yaml) project = Project( snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path) self.global_state_filepath = project._get_global_state_file_path() self.project_config = project_loader.load_config(project) self.useFixture( fixtures.MockPatchObject(self.project_config, "get_build_snaps", return_value={"core18"})) self.useFixture( fixtures.MockPatch( "snapcraft_legacy.internal.lifecycle._runner._Executor.run")) self.useFixture( fixtures.MockPatch( "snapcraft_legacy.internal.repo.snaps.install_snaps")) # Avoid unnecessary calls to info. channel_map = [] for arch in ("amd64", "i386", "s390x", "arm64", "armhf", "ppc64el"): channel_map.append({ "channel": { "architecture": arch, "name": "stable", "released-at": "2019-10-15T13:54:06.800280+00:00", "risk": "stable", "track": "latest", }, "confinement": "strict", "download": { "deltas": [], "sha3-384": "64d232d6bfa65be14d7f8d84e952d4e372e12021e2c3dbaf70cf2af5e78bf51c4baf9c9107dd6db815064636b781bda6", "size": 57151488, "url": "https://api.snapcraft.io/api/v1/snaps/download/CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6_1223.snap", }, "revision": 1223, }) info = { "channel-map": channel_map, "default-track": None, "name": "core18", "snap": { "name": "core18", "publisher": { "display-name": "Canonical", "id": "canonical", "username": "******", "validation": "verified", }, "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6", }, "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6", } self.fake_storeapi_get_info = fixtures.MockPatch( "snapcraft_legacy.storeapi._snap_api.SnapAPI.get_info", return_value=SnapInfo(info), ) self.useFixture(self.fake_storeapi_get_info)