def test_architecture_options( self, monkeypatch, machine, architecture, expected_arch_triplet, expected_deb_arch, expected_kernel_arch, expected_core_dynamic_linker, ): monkeypatch.setattr(platform, "architecture", lambda: architecture) monkeypatch.setattr(platform, "machine", lambda: machine) options = snapcraft.ProjectOptions() assert options.arch_triplet == expected_arch_triplet assert options.deb_arch == expected_deb_arch assert options.kernel_arch == expected_kernel_arch # The core dynamic linker is correct. Guard against stray absolute # paths, as they cause os.path.join to discard the previous # argument. monkeypatch.setattr(os.path, "lexists", lambda x: True) monkeypatch.setattr(os.path, "islink", lambda x: False) expected_linker_path = os.path.join( common.get_installed_snap_path("core"), expected_core_dynamic_linker ) assert options.get_core_dynamic_linker("core") == expected_linker_path
def test_architecture_options( self, mock_platform_machine, mock_platform_architecture ): mock_platform_machine.return_value = self.machine mock_platform_architecture.return_value = self.architecture options = snapcraft.ProjectOptions() self.assertThat(options.arch_triplet, Equals(self.expected_arch_triplet)) self.assertThat(options.deb_arch, Equals(self.expected_deb_arch)) self.assertThat(options.kernel_arch, Equals(self.expected_kernel_arch)) # The core dynamic linker is correct. Guard against stray absolute # paths, as they cause os.path.join to discard the previous # argument. self.assertFalse(os.path.isabs(self.expected_core_dynamic_linker)) with mock.patch("os.path.lexists") as mock_lexists: mock_lexists.return_value = True with mock.patch("os.path.islink") as mock_islink: mock_islink.return_value = False self.assertThat( options.get_core_dynamic_linker("core"), Equals( os.path.join( common.get_installed_snap_path("core"), self.expected_core_dynamic_linker, ) ), )
def get_provider_content_directories(self) -> Set[str]: """Get provider content directories from installed snaps.""" provider_dirs: Set[str] = set() for plug in self.get_content_plugs(): # Get matching slot provider for plug. provider = plug.provider provider_path = common.get_installed_snap_path(provider) yaml_path = os.path.join(provider_path, "meta", "snap.yaml") snap = Snap.from_file(yaml_path) for slot in snap.get_content_slots(): slot_installed_path = common.get_installed_snap_path( plug.provider) provider_dirs |= slot.get_content_dirs( installed_path=slot_installed_path) return provider_dirs
def get_core_dynamic_linker(self, base: str, expand: bool = True) -> str: """Returns the dynamic linker used for the targeted core. :param str base: the base core snap to search for linker. :param bool expand: expand the linker to the actual linker if True, else the main entry point to the linker for the projects architecture. :return: the absolute path to the linker :rtype: str :raises snapcraft.internal.errors.SnapcraftMissingLinkerInBaseError: if the linker cannot be found in the base. :raises snapcraft.internal.errors.SnapcraftEnvironmentError: if a loop is found while resolving the real path to the linker. """ core_path = common.get_installed_snap_path(base) dynamic_linker_path = os.path.join( core_path, self.__machine_info.get("core-dynamic-linker", "lib/ld-linux.so.2"), ) # return immediately if we do not need to expand if not expand: return dynamic_linker_path # We can't use os.path.realpath because any absolute symlinks # have to be interpreted relative to core_path, not the real # root. seen_paths = set() # type: Set[str] while True: if dynamic_linker_path in seen_paths: raise errors.SnapcraftEnvironmentError( "found symlink loop resolving dynamic linker path" ) seen_paths.add(dynamic_linker_path) if not os.path.lexists(dynamic_linker_path): raise errors.SnapcraftMissingLinkerInBaseError( base=base, linker_path=dynamic_linker_path ) if not os.path.islink(dynamic_linker_path): return dynamic_linker_path link_contents = os.readlink(dynamic_linker_path) if os.path.isabs(link_contents): dynamic_linker_path = os.path.join(core_path, link_contents.lstrip("/")) else: dynamic_linker_path = os.path.join( os.path.dirname(dynamic_linker_path), link_contents )
def build(self): super().build() self.run( ["shards", "build", "--without-development"] + self.options.crystal_build_options, self.builddir, ) output_bin = os.path.join(self.builddir, "bin") if not os.path.exists(output_bin): raise errors.SnapcraftEnvironmentError( "No binaries were built. Ensure the shards.yaml contains valid targets." ) install_bin_path = os.path.join(self.installdir, "bin") bin_paths = (os.path.join(output_bin, b) for b in os.listdir(output_bin)) elf_files = (elf.ElfFile(path=b) for b in bin_paths if elf.ElfFile.is_elf(b)) os.makedirs(install_bin_path, exist_ok=True) for elf_file in elf_files: shutil.copy2( elf_file.path, os.path.join(install_bin_path, os.path.basename(elf_file.path)), ) elf_dependencies_path = elf_file.load_dependencies( root_path=self.installdir, core_base_path=common.get_installed_snap_path( self.project._get_build_base()), arch_triplet=self.project.arch_triplet, content_dirs=self.project._get_provider_content_dirs(), ) for elf_dependency_path in elf_dependencies_path: lib_install_path = os.path.join(self.installdir, elf_dependency_path[1:]) os.makedirs(os.path.dirname(lib_install_path), exist_ok=True) if not os.path.exists(lib_install_path): file_utils.link_or_copy(elf_dependency_path, lib_install_path, follow_symlinks=True)