def construct_yaml( self, name="test", version="0.1", summary="Simple test snap", description="Something something", grade=None, architectures=None, parts=dedent("""\ my-part: plugin: nil """), build_packages="[]", adopt_info=None, ): snapcraft_yaml = { "name": name, "summary": summary, "description": description, "parts": yaml_utils.load(parts), "build-packages": yaml_utils.load(build_packages), } if version: snapcraft_yaml["version"] = version if adopt_info: snapcraft_yaml["adopt-info"] = adopt_info if grade: snapcraft_yaml["grade"] = grade if architectures: snapcraft_yaml["architectures"] = architectures with open("snapcraft.yaml", "w") as f: yaml_utils.dump(snapcraft_yaml, stream=f)
def test_prime_without_packages_version(self): """Test the recorded manifest for a snap with packages This snap declares all the packages that it requires, there are no additional dependencies. The packages don't specify their version. """ self.run_snapcraft("prime", project_dir="stage-packages-without-dependencies") with open(os.path.join("snap", "snapcraft.yaml")) as source_yaml_file: source_yaml = yaml_utils.load(source_yaml_file) part_name = "part-with-stage-packages" expected_packages = [ "{}={}".format( package, integration.get_package_version( package, self.distro_series, self.deb_arch ), ) for package in source_yaml["parts"][part_name]["stage-packages"] ] recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) self.assertThat( recorded_yaml["parts"][part_name]["stage-packages"], Equals(expected_packages), )
def test_prime_records_packages_version(self): """Test the recorded manifest for a snap with packages This snap declares all the packages that it requires, there are no additional dependencies. The packages specify their version. """ expected_packages = ["haskell-doc", "haskell98-tutorial", "haskell98-report"] self.copy_project_to_cwd("stage-packages-without-dependencies") part_name = "part-with-stage-packages" for package in expected_packages: self.set_stage_package_version( os.path.join("snap", "snapcraft.yaml"), part_name, package ) self.run_snapcraft("prime") with open(os.path.join("snap", "snapcraft.yaml")) as source_yaml_file: source_yaml = yaml_utils.load(source_yaml_file) recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) self.assertThat( recorded_yaml["parts"][part_name]["stage-packages"], Equals(source_yaml["parts"][part_name]["stage-packages"]), )
def set_package_version(self, type_, snapcraft_yaml_path, part, package, version=None): # This doesn't handle complex package syntax. with open(snapcraft_yaml_path) as snapcraft_yaml_file: snapcraft_yaml = yaml_utils.load(snapcraft_yaml_file) if part: packages = snapcraft_yaml["parts"][part].get(type_, []) else: packages = snapcraft_yaml.get(type_, []) for index, package_in_yaml in enumerate(packages): if package_in_yaml.split("=")[0] == package: if version is None: version = get_package_version(package, self.distro_series, self.deb_arch) packages[index] = "{}={}".format(package, version) break else: self.fail("The part {} doesn't have a package {}".format( part, package)) with open(snapcraft_yaml_path, "w") as snapcraft_yaml_file: yaml_utils.dump(snapcraft_yaml, stream=snapcraft_yaml_file) return version
def generate_meta_yaml( self, *, build=False, actual_prime_dir=None, snapcraft_yaml_file_path=None ): if snapcraft_yaml_file_path is None: snapcraft_yaml_file_path = self.snapcraft_yaml_file_path os.makedirs("snap", exist_ok=True) with open(snapcraft_yaml_file_path, "w") as f: f.write(yaml_utils.dump(self.config_data)) self.project = Project(snapcraft_yaml_file_path=snapcraft_yaml_file_path) if actual_prime_dir is not None: self.project._prime_dir = actual_prime_dir self.meta_dir = os.path.join(self.project.prime_dir, "meta") self.hooks_dir = os.path.join(self.meta_dir, "hooks") self.snap_yaml = os.path.join(self.meta_dir, "snap.yaml") self.config = project_loader.load_config(project=self.project) if build: for part in self.config.parts.all_parts: part.pull() part.build() part.stage() part.prime() _snap_packaging.create_snap_packaging(self.config) self.assertTrue(os.path.exists(self.snap_yaml), "snap.yaml was not created") with open(self.snap_yaml) as f: return yaml_utils.load(f)
def _load_info(self) -> Dict[str, Any]: filepath = os.path.join(self.provider_project_dir, "project-info.yaml") if not os.path.exists(filepath): return dict() with open(filepath) as info_file: return yaml_utils.load(info_file)
def test_prime_with_packages_missing_dependency(self): """Test the recorded manifest for a snap with packages This snap declares one package that has undeclared dependencies. """ self.copy_project_to_cwd("stage-packages-missing-dependency") part_name = "part-with-stage-packages" self.set_stage_package_version( os.path.join("snap", "snapcraft.yaml"), part_name, package="haskell-doc" ) self.run_snapcraft("prime") expected_packages = [ "{}={}".format( package, integration.get_package_version( package, self.distro_series, self.deb_arch ), ) for package in ["haskell-doc", "haskell98-tutorial", "haskell98-report"] ] recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) self.assertThat( recorded_yaml["parts"][part_name]["stage-packages"], Equals(expected_packages), )
def test_prime_with_build_packages(self): """Test the recorded manifest for a snap with build packages This snap declares one global build package that has undeclared dependencies. """ expected_packages = ["haskell-doc", "haskell98-tutorial", "haskell98-report"] self.addCleanup( subprocess.call, ["sudo", "apt", "remove", "-y"] + expected_packages ) self.run_snapcraft("prime", self.snap) expected_packages_with_version = [ "{}={}".format( package, integration.get_package_version( package, self.distro_series, self.deb_arch ), ) for package in expected_packages ] recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) self.assertThat( recorded_yaml["build-packages"], Equals(expected_packages_with_version) )
def _load_yaml(*, yaml_file_path: str) -> OrderedDict: with open(yaml_file_path, "rb") as fp: bs = fp.read(2) if bs == codecs.BOM_UTF16_LE or bs == codecs.BOM_UTF16_BE: encoding = "utf-16" else: encoding = "utf-8" try: with open(yaml_file_path, encoding=encoding) as fp: # type: ignore yaml_contents = yaml_utils.load(fp) # type: ignore except yaml.MarkedYAMLError as e: raise errors.YamlValidationError( "{} on line {}, column {}".format(e.problem, e.problem_mark.line + 1, e.problem_mark.column + 1), yaml_file_path, ) from e except yaml.reader.ReaderError as e: raise errors.YamlValidationError( "invalid character {!r} at position {}: {}".format( chr(e.character), e.position + 1, e.reason), yaml_file_path, ) from e except yaml.YAMLError as e: raise errors.YamlValidationError(str(e), yaml_file_path) from e return yaml_contents
def test_pull_git(self): repo_fixture = fixture_setup.GitRepo() self.useFixture(repo_fixture) project_dir = "asset-tracking-git" self.run_snapcraft(["pull", self.part_name], project_dir) state_file = os.path.join(self.parts_dir, self.part_name, "state", "pull") self.assertThat(state_file, FileExists()) with open(state_file) as f: state = yaml_utils.load(f) self.assertIn("source-details", state.assets) # fall back to the commit if no other source option is provided # snapcraft.source.Git doesn't allow both a tag and a commit if self.expected_details: self.assertThat( state.assets["source-details"][self.expected_details.field], Equals(self.expected_details.value), ) else: self.assertThat( state.assets["source-details"]["source-commit"], Equals(repo_fixture.commit), )
def __init__(self): super().__init__() if not os.path.exists(self.parts_yaml): update() with open(self.parts_yaml) as parts_file: self._parts = yaml_utils.load(parts_file)
def get_state(state_dir: str, step: steps.Step): state = None state_file = get_step_state_file(state_dir, step) if os.path.isfile(state_file): with open(state_file, "r") as f: state = yaml_utils.load(f) return state
def _load_schema(self): schema_file = os.path.abspath( os.path.join(common.get_schemadir(), "snapcraft.yaml")) try: with open(schema_file) as fp: self._schema = yaml_utils.load(fp) except FileNotFoundError: raise errors.YamlValidationError( "snapcraft validation file is missing from installation path")
def test_arch_with_pull(self): if self.deb_arch == "armhf": self.skipTest("For now, we just support crosscompile from amd64") self.run_snapcraft(["--target-arch=i386", "pull", "go-hello"], "go-hello") state_file = os.path.join(self.parts_dir, "go-hello", "state", "pull") self.assertThat(state_file, FileExists()) with open(state_file) as f: state = yaml_utils.load(f) self.assertThat(state.project_options["deb_arch"], Equals("i386"))
def test_scriptlet_after_repull(self): self.run_command(["prime"]) with open(os.path.join("prime", "meta", "snap.yaml")) as f: y = yaml_utils.load(f) self.assertThat(y["grade"], Equals("devel")) self.assertThat(y["version"], Equals("v1.0")) # modifying source file (src/version.txt) will trigger re-pull open(os.path.join("src", "version.txt"), "w").write("v2.0") self.run_command(["prime"]) with open(os.path.join("prime", "meta", "snap.yaml")) as f: z = yaml_utils.load(f) self.assertThat(z["grade"], Equals("devel")) self.assertThat(z["version"], Equals("v2.0"))
def test_default_architecture(self): self.construct_yaml(architectures=[{"build-on": ["other-arch"]}]) self.run_snapcraft("prime") with open(os.path.join("prime", "meta", "snap.yaml")) as f: y = yaml_utils.load(f) self.assertThat(y["architectures"], Equals([self.deb_arch]))
def test_simple_architecture(self): self.construct_yaml(architectures=[self.deb_arch]) self.run_snapcraft("prime") with open(os.path.join("prime", "meta", "snap.yaml")) as f: y = yaml_utils.load(f) self.assertThat(y["architectures"], Equals([self.deb_arch]))
def _snap_data_from_dir(directory): with open(os.path.join(directory, "meta", "snap.yaml")) as f: snap = yaml_utils.load(f) return { "name": snap["name"], "version": snap["version"], "arch": snap.get("architectures", []), "type": snap.get("type", ""), }
def test_update(self): result = self.run_command(["update"]) self.assertThat(result.exit_code, Equals(0)) self.assertThat(self.parts_yaml, FileExists()) self.assertThat(self.headers_yaml, FileExists()) expected_parts = OrderedDict() expected_parts["curl"] = p = OrderedDict() p["plugin"] = "autotools" p["source"] = "http://curl.org" p["description"] = "test entry for curl" p["maintainer"] = "none" expected_parts["part1"] = p = OrderedDict() p["plugin"] = "go" p["source"] = "http://source.tar.gz" p["description"] = "test entry for part1" p["maintainer"] = "none" expected_parts["long-described-part"] = p = OrderedDict() p["plugin"] = "go" p["source"] = "http://source.tar.gz" p["description"] = "this is a repetitive description " * 3 p["maintainer"] = "none" expected_parts["multiline-part"] = p = OrderedDict() p["plugin"] = "go" p["source"] = "http://source.tar.gz" p["description"] = "this is a multiline description\n" * 3 p["maintainer"] = "none" expected_headers = { "If-Modified-Since": "Thu, 07 Jul 2016 10:00:20 GMT" } with open(self.parts_yaml) as parts_file: parts = yaml_utils.load(parts_file) with open(self.headers_yaml) as headers_file: headers = yaml_utils.load(headers_file) self.assertThat(parts, Equals(expected_parts)) self.assertThat(headers, Equals(expected_headers))
def test_merge_tag_yaml(self): test_yaml = """ base: &base property: value test: <<: *base """ doc = yaml_utils.load(test_yaml) self.assertTrue(isinstance(doc, OrderedDict)) self.assertThat(doc["test"]["property"], Equals("value"))
def test_ordereddict_yaml(self): from collections import OrderedDict data = OrderedDict() data["name"] = "test" data["description"] = "description" output = yaml_utils.dump(data) self.assertTrue(isinstance(yaml_utils.load(output), OrderedDict))
def test_yaml_conversion(self, init_spy): state_string = yaml_utils.dump(self.state) # Verify that the dumped tag was correct self.assertThat(state_string.splitlines()[0], Equals("!BuildState")) # Now verify the conversion state_from_yaml = yaml_utils.load(state_string) self.assertThat(state_from_yaml, Equals(self.state)) # Verify that init was not called init_spy.assert_not_called()
def _edit_validation_sets(validation_sets: str) -> Dict[str, Any]: """Spawn an editor to modify the validation-sets.""" editor_cmd = os.getenv("EDITOR", "vi") with tempfile.NamedTemporaryFile() as ft: ft.close() with open(ft.name, "w") as fw: print(validation_sets, file=fw) subprocess.run([editor_cmd, ft.name], check=True) with open(ft.name, "r") as fr: edited_validation_sets = yaml_utils.load(fr) return edited_validation_sets
def test_specified_metadata_not_overwritten(self): snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path, description=None) snapcraft_yaml.data["adopt-info"] = "test-part" snapcraft_yaml.update_part( "test-part", {"plugin": "dump", "parse-info": ["test.metainfo.xml"]} ) self.useFixture(snapcraft_yaml) self.run_snapcraft("prime") with open(os.path.join("prime", "meta", "snap.yaml")) as snap_yaml_file: snap_yaml = yaml_utils.load(snap_yaml_file) self.assertThat(snap_yaml["description"], Equals("test-appstream-description")) self.assertThat(snap_yaml["summary"], Equals("test-summary"))
def add_stage_packages( *, part_name: str, stage_packages: List[str], snapcraft_yaml_file=None ): if snapcraft_yaml_file is None: snapcraft_yaml_file = os.path.join("snap", "snapcraft.yaml") with open(snapcraft_yaml_file) as file_read: y = yaml_utils.load(file_read) if "stage-packages" in y["parts"][part_name]: y["parts"][part_name]["stage-packages"].extend(stage_packages) else: y["parts"][part_name]["stage-packages"] = stage_packages with open(snapcraft_yaml_file, "w") as file_write: yaml_utils.dump(y, stream=file_write)
def test_pull_build_package_with_any_architecture(self): self.copy_project_to_cwd("build-package") self.set_build_package_architecture( os.path.join("snap", "snapcraft.yaml"), part="hello", package="hello", architecture="any", ) self.run_snapcraft("pull") state_file = os.path.join(self.parts_dir, "hello", "state", "pull") with open(state_file) as f: state = yaml_utils.load(f) self.assertIn("hello", state.assets["build-packages"][0])
def test_prime_with_architectures(self): """Test the recorded manifest for a basic snap This snap doesn't have stage or build packages and is declared that it works on all architectures. """ self.run_snapcraft(["snap", "--output", "basic.snap"], project_dir="basic") recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) self.assertThat(recorded_yaml["architectures"], Equals(["all"])) self.assert_review_passes("basic.snap")
def test_prime_with_git_source(self): self.copy_project_to_cwd("git-head") self.init_source_control() self.commit('"test-commit"', allow_empty=True) self.run_snapcraft(["snap", "--output", "git.snap"]) recorded_yaml_path = os.path.join(self.prime_dir, "snap", "manifest.yaml") with open(recorded_yaml_path) as recorded_yaml_file: recorded_yaml = yaml_utils.load(recorded_yaml_file) commit = self.get_revno() self.assertThat(recorded_yaml["parts"]["git"]["source-commit"], Equals(commit)) self.assert_review_passes("git.snap")
def _edit_developers(developers: List[Dict[str, str]]) -> List[Dict[str, str]]: """Spawn an editor to modify the snap-developer assertion for a snap.""" editor_cmd = os.getenv("EDITOR", "vi") developer_wrapper = {"developers": developers} with tempfile.NamedTemporaryFile() as ft: ft.close() with open(ft.name, "w") as fw: print(_COLLABORATION_HEADER, file=fw) yaml_utils.dump(developer_wrapper, stream=fw) subprocess.check_call([editor_cmd, ft.name]) with open(ft.name, "r") as fr: developers = yaml_utils.load(fr).get("developers") return developers
def _get_data_from_snap_file(snap_path): with tempfile.TemporaryDirectory() as temp_dir: unsquashfs_path = get_tool_path("unsquashfs") output = subprocess.check_output([ unsquashfs_path, "-d", os.path.join(temp_dir, "squashfs-root"), snap_path, "-e", os.path.join("meta", "snap.yaml"), ]) logger.debug(output) with open(os.path.join(temp_dir, "squashfs-root", "meta", "snap.yaml")) as yaml_file: snap_yaml = yaml_utils.load(yaml_file) return snap_yaml