Example #1
0
    def test_prime_state_with_dependencies(self, mock_migrate_files,
                                           mock_load_dependencies,
                                           mock_get_symbols):
        mock_load_dependencies.return_value = {
            "/foo/bar/baz",
            "{}/lib1/installed".format(self.handler.part_install_dir),
            "{}/lib2/staged".format(self.handler._project.stage_dir),
            "{}/lib3/primed".format(self.handler._project.prime_dir),
        }
        self.get_elf_files_mock.return_value = frozenset([
            elf.ElfFile(path=os.path.join(self.handler._project.prime_dir,
                                          "bin", "1")),
            elf.ElfFile(path=os.path.join(self.handler._project.prime_dir,
                                          "bin", "2")),
        ])
        self.assertRaises(errors.NoLatestStepError, self.handler.latest_step)
        self.assertThat(self.handler.next_step(), Equals(steps.PULL))

        bindir = os.path.join(self.handler.part_install_dir, "bin")
        os.makedirs(bindir)
        open(os.path.join(bindir, "1"), "w").close()
        open(os.path.join(bindir, "2"), "w").close()

        self.handler.mark_done(steps.BUILD)
        self.handler.stage()

        # Resetting for test clarity
        mock_migrate_files.reset_mock()

        self.handler.prime()

        self.assertThat(self.handler.latest_step(), Equals(steps.PRIME))
        self.assertRaises(errors.NoNextStepError, self.handler.next_step)
        self.get_elf_files_mock.assert_called_once_with(
            self.handler._project.prime_dir, {"bin/1", "bin/2"})
        mock_migrate_files.assert_has_calls([
            call(
                {"bin/1", "bin/2"},
                {"bin"},
                self.handler._project.stage_dir,
                self.handler._project.prime_dir,
            )
        ])

        state = self.handler.get_prime_state()

        self.assertTrue(type(state) is states.PrimeState)
        self.assertTrue(type(state.files) is set)
        self.assertTrue(type(state.directories) is set)
        self.assertTrue(type(state.properties) is OrderedDict)
        self.assertThat(len(state.files), Equals(2))
        self.assertThat(state.dependency_paths, Equals({"lib3"}))
        self.assertTrue("bin/1" in state.files)
        self.assertTrue("bin/2" in state.files)
        self.assertThat(len(state.directories), Equals(1))
        self.assertTrue("bin" in state.directories)
        self.assertTrue("prime" in state.properties)
        self.assertThat(state.properties["prime"], Equals(["*"]))
        self.assertTrue(type(state.project_options) is OrderedDict)
        self.assertThat(len(state.project_options), Equals(0))
Example #2
0
    def _build(self, *, package: str = "") -> None:
        build_cmd = ["go", "build"]

        if self.options.go_buildtags:
            build_cmd.extend(["-tags={}".format(",".join(self.options.go_buildtags))])

        relink_cmd = build_cmd + ["-ldflags", "-linkmode=external"]

        if self._is_using_go_mod(self.builddir) and not package:
            work_dir = self.builddir
            build_cmd.extend(["-o", self._install_bin_dir])
            relink_cmd.extend(["-o", self._install_bin_dir])
        else:
            work_dir = self._install_bin_dir
            build_cmd.append(package)
            relink_cmd.append(package)

        pre_build_files = os.listdir(self._install_bin_dir)
        self._run(build_cmd, cwd=work_dir)
        post_build_files = os.listdir(self._install_bin_dir)

        new_files = set(post_build_files) - set(pre_build_files)
        if len(new_files) != 1:
            raise RuntimeError(f"Expected one binary to be built, found: {new_files!r}")
        binary_path = os.path.join(self._install_bin_dir, new_files.pop())

        # Relink with system linker if executable is dynamic in order to be
        # able to set rpath later on. This workaround can be removed after
        # https://github.com/NixOS/patchelf/issues/146 is fixed.
        if self._is_classic and elf.ElfFile(path=binary_path).is_dynamic:
            self._run(relink_cmd, cwd=work_dir)
Example #3
0
    def test_bin_echo(self):
        # Try parsing a file without the pyelftools logic mocked out
        elf_file = elf.ElfFile(path=sys.executable)

        self.assertThat(elf_file.path, Equals(sys.executable))

        # The arch attribute will be a tuple of three strings
        self.assertTrue(isinstance(elf_file.arch, tuple))
        self.assertThat(len(elf_file.arch), Equals(3))
        self.assertThat(elf_file.arch[0], StartsWith('ELFCLASS'))
        self.assertThat(elf_file.arch[1], StartsWith('ELFDATA'))
        self.assertThat(elf_file.arch[2], StartsWith('EM_'))

        # We expect Python to be a dynamic linked executable with an
        # ELF interpreter.
        self.assertTrue(isinstance(elf_file.interp, str))
        self.assertThat(elf_file.interp, NotEquals(''))

        # Python is not a shared library, so has no soname
        self.assertThat(elf_file.soname, Equals(''))

        # We expect that Python will be linked to libc
        for lib in elf_file.needed.values():
            if lib.name.startswith('libc.so'):
                break
        else:
            self.fail("Expected to find libc in needed library list")

        self.assertTrue(isinstance(lib.name, str))
        for version in lib.versions:
            self.assertTrue(isinstance(version, str),
                            "expected {!r} to be a string".format(version))
Example #4
0
 def test_fail_gracefully_if_system_libs_not_found(self):
     stub_magic = ('ELF 64-bit LSB executable, x86-64, version 1 (SYSV), '
                   'dynamically linked, interpreter '
                   '/lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32')
     self.assertThat(
         elf.ElfFile(path='foo', magic=stub_magic).load_dependencies(),
         Equals(frozenset()))
Example #5
0
    def test_patch_fails_raises_patcherror_exception(self, check_call_mock):
        elf_file = elf.ElfFile(path='/fake-elf', is_executable=True)
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld')

        self.assertRaises(errors.PatcherError,
                          elf_patcher.patch,
                          elf_file=elf_file)
Example #6
0
    def build(self):
        super().build()

        tags = []
        if self.options.go_buildtags:
            tags = ["-tags={}".format(",".join(self.options.go_buildtags))]

        packages = self.options.go_packages
        if not packages:
            packages = self._get_local_main_packages()
        for package in packages:
            binary = os.path.join(self._gopath_bin, self._binary_name(package))
            self._run(["go", "build", "-o", binary] + tags + [package])
            # Relink with system linker if executable is dynamic in order to be
            # able to set rpath later on. This workaround can be removed after
            # https://github.com/NixOS/patchelf/issues/146 is fixed.
            if self._is_classic and elf.ElfFile(path=binary).is_dynamic:
                self._run([
                    "go", "build", "-ldflags", "-linkmode=external", "-o",
                    binary
                ] + tags + [package])

        install_bin_path = os.path.join(self.installdir, "bin")
        os.makedirs(install_bin_path, exist_ok=True)
        for binary in os.listdir(self._gopath_bin):
            binary_path = os.path.join(self._gopath_bin, binary)
            shutil.copy2(binary_path, install_bin_path)
Example #7
0
    def test_get_libraries_filtered_by_system_libraries(self):
        self.get_system_libs_mock.return_value = frozenset(['foo.so.1'])

        elf_file = elf.ElfFile(path='foo', magic=self.stub_magic)
        libs = elf_file.load_dependencies(root_path='/',
                                          core_base_path='/snap/core/current')
        self.assertThat(libs, Equals(frozenset(['/usr/lib/bar.so.2'])))
Example #8
0
    def test_patch_does_nothing_if_no_interpreter(self, check_call_mock):
        stub_magic = ('ELF 64-bit LSB shared object, x86-64, '
                      'version 1 (SYSV), dynamically linked')
        elf_file = elf.ElfFile(path='/fake-elf', magic=stub_magic)
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld')
        elf_patcher.patch(elf_file=elf_file)

        self.assertFalse(check_call_mock.called)
Example #9
0
    def test_non_elf_primed_sonames_matches_are_ignored(self):
        primed_foo = os.path.join(self.prime_dir, 'foo.so.1')
        open(primed_foo, 'w').close()

        elf_file = elf.ElfFile(path='foobar', magic=self.stub_magic)
        libs = elf_file.load_dependencies(root_path=self.prime_dir,
                                          core_base_path=self.core_base_path)
        self.assertThat(libs, Equals(frozenset(
            ['/lib/foo.so.1', '/usr/lib/bar.so.2'])))
Example #10
0
    def test_patch(self, check_call_mock):
        elf_file = elf.ElfFile(path='/fake-elf', is_executable=True)
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld')
        elf_patcher.patch(elf_file=elf_file)

        check_call_mock.assert_called_once_with([
            self.expected_patchelf, '--set-interpreter', '/lib/fake-ld',
            '/fake-elf'
        ])
Example #11
0
    def test_patch_fails_raises_patcherror_exception(self, check_call_mock):
        stub_magic = ('ELF 64-bit LSB executable, x86-64, version 1 (SYSV), '
                      'dynamically linked, interpreter '
                      '/lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32')
        elf_file = elf.ElfFile(path='/fake-elf', magic=stub_magic)
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld')

        self.assertRaises(errors.PatcherError,
                          elf_patcher.patch,
                          elf_file=elf_file)
Example #12
0
    def test_get_libraries_ldd_failure_logs_warning(self):
        self.run_output_mock.side_effect = subprocess.CalledProcessError(
            1, 'foo', b'bar')

        dependencies = elf.ElfFile(path='foo',
                                   magic=self.stub_magic).load_dependencies()
        self.assertThat(dependencies, Equals(set()))
        self.assertThat(
            self.fake_logger.output,
            Equals("Unable to determine library dependencies for 'foo'\n"))
Example #13
0
    def test_patch_fails_raises_patcherror_exception(self):
        elf_file = elf.ElfFile(path='/fake-elf', magic=self.stub_magic)
        # The base_path does not matter here as there are not files to
        # be crawled for.
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld',
                                  root_path='/fake')

        self.assertRaises(errors.PatcherError,
                          elf_patcher.patch,
                          elf_file=elf_file)
Example #14
0
    def test_prime_state_missing_libraries(
        self, mock_migrate_files, mock_load_dependencies, mock_get_symbols
    ):
        self.handler = self.load_part("test_part")

        self.get_elf_files_mock.return_value = frozenset(
            [
                elf.ElfFile(
                    path=os.path.join(self.handler._project.prime_dir, "bin", "file")
                )
            ]
        )
        # Pretend we found a system dependency, as well as a part and stage
        # dependency.
        mock_load_dependencies.return_value = set(
            [
                "/foo/bar/baz",
                "{}/lib1/installed".format(self.handler.part_install_dir),
                "{}/lib2/staged".format(self.handler._project.stage_dir),
                "{}/lib3/primed".format(self.handler._project.prime_dir),
            ]
        )

        self.assertRaises(errors.NoLatestStepError, self.handler.latest_step)
        self.assertThat(self.handler.next_step(), Equals(steps.PULL))

        bindir = os.path.join(self.handler.part_install_dir, "bin")
        os.makedirs(bindir)
        open(os.path.join(bindir, "file"), "w").close()

        self.handler.mark_done(steps.BUILD)
        self.handler.stage()
        mock_migrate_files.reset_mock()
        self.handler.prime()

        self.assertThat(self.handler.latest_step(), Equals(steps.PRIME))
        self.assertRaises(errors.NoNextStepError, self.handler.next_step)
        self.get_elf_files_mock.assert_called_once_with(
            self.handler._project.prime_dir, {"bin/file"}
        )
        # Verify that only the part's files were migrated-- not the system
        # dependency.
        mock_migrate_files.assert_called_once_with(
            {"bin/file"},
            {"bin"},
            self.handler._project.stage_dir,
            self.handler._project.prime_dir,
        )

        state = self.handler.get_prime_state()

        # Verify that only the primed paths were captured.
        # The rest should be considered missing.
        self.assertThat(state.dependency_paths, Equals({"lib3"}))
Example #15
0
    def test_symbols_no_match(self):
        self.check_output_mock.return_value = dedent("""\
            Symbol table '.dynsym' contains 2281 entries:
              Num:    Value          Size Type    Bind   Vis      Ndx Name
                0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
              0000000000565f20
            """).encode()  # noqa

        elf_file = elf.ElfFile(path='/fake-elf', magic=self.stub_magic)

        self.assertThat(len(elf_file.symbols), Equals(0))
Example #16
0
    def test_patch_does_nothing_if_no_interpreter(self, check_call_mock):
        stub_magic = ('ELF 64-bit LSB shared object, x86-64, '
                      'version 1 (SYSV), dynamically linked')
        elf_file = elf.ElfFile(path='/fake-elf', magic=stub_magic)
        # The base_path does not matter here as there are not files to
        # be crawled for.
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld',
                                  root_path='/fake')
        elf_patcher.patch(elf_file=elf_file)

        self.assertFalse(check_call_mock.called)
Example #17
0
    def test_get_libraries_ldd_failure_logs_warning(self):
        self.run_output_mock.side_effect = subprocess.CalledProcessError(
            1, 'foo', b'bar')

        elf_file = elf.ElfFile(path='foo', magic=self.stub_magic)
        libs = elf_file.load_dependencies(root_path='/',
                                          core_base_path='/snap/core/current')
        self.assertThat(libs, Equals(set()))
        self.assertThat(
            self.fake_logger.output,
            Equals("Unable to determine library dependencies for 'foo'\n"))
Example #18
0
    def test_patch(self):
        elf_file = elf.ElfFile(path='/fake-elf', magic=self.stub_magic)
        # The base_path does not matter here as there are not files to
        # be crawled for.
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld',
                                  root_path='/fake')
        elf_patcher.patch(elf_file=elf_file)

        self.check_call_mock.assert_called_once_with([
            self.expected_patchelf, '--set-interpreter', '/lib/fake-ld',
            '/fake-elf'
        ])
Example #19
0
    def test_patch(self, check_call_mock):
        stub_magic = ('ELF 64-bit LSB executable, x86-64, version 1 (SYSV), '
                      'dynamically linked, interpreter '
                      '/lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32')
        elf_file = elf.ElfFile(path='/fake-elf', magic=stub_magic)
        elf_patcher = elf.Patcher(dynamic_linker='/lib/fake-ld')
        elf_patcher.patch(elf_file=elf_file)

        check_call_mock.assert_called_once_with([
            self.expected_patchelf, '--set-interpreter', '/lib/fake-ld',
            '/fake-elf'
        ])
Example #20
0
    def _setUp(self):
        super()._setUp()

        self.core_base_path = self.useFixture(fixtures.TempDir()).path

        binaries_path = os.path.abspath(
            os.path.join(__file__, '..', 'bin', 'readelf'))

        new_binaries_path = self.useFixture(fixtures.TempDir()).path
        current_path = os.environ.get('PATH')
        new_path = '{}:{}'.format(new_binaries_path, current_path)
        self.useFixture(fixtures.EnvironmentVariable('PATH', new_path))

        # Copy readelf
        shutil.copy(os.path.join(binaries_path, 'readelf'),
                    os.path.join(new_binaries_path, 'readelf'))
        os.chmod(os.path.join(new_binaries_path, 'readelf'), 0o755)

        # Some values in ldd need to be set with core_path
        with open(os.path.join(binaries_path, 'ldd')) as rf:
            with open(os.path.join(new_binaries_path, 'ldd'), 'w') as wf:
                for line in rf.readlines():
                    wf.write(line.replace('{CORE_PATH}', self.core_base_path))
        os.chmod(os.path.join(new_binaries_path, 'ldd'), 0o755)

        self._elf_files = {
            'fake_elf-2.26':
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-2.26')),
            'fake_elf-2.23':
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-2.23')),
            'fake_elf-1.1':
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-1.1')),
            'fake_elf-static':
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-static')),
            'fake_elf-shared-object':
            elf.ElfFile(
                path=os.path.join(self.root_path, 'fake_elf-shared-object')),
            'fake_elf-bad-ldd':
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-bad-ldd')),
            'fake_elf-with-core-libs':
            elf.ElfFile(
                path=os.path.join(self.root_path, 'fake_elf-with-core-libs')),
        }

        for elf_file in self._elf_files.values():
            with open(elf_file.path, 'wb') as f:
                f.write(b'\x7fELF')

        self.root_libraries = {
            'foo.so.1': os.path.join(self.root_path, 'foo.so.1'),
        }

        for root_library in self.root_libraries.values():
            with open(root_library, 'wb') as f:
                f.write(b'\x7fELF')
Example #21
0
    def test_get_libraries_excludes_slash_snap(self):
        lines = [
            'foo.so.1 => /lib/foo.so.1 (0xdead)',
            'bar.so.2 => /usr/lib/bar.so.2 (0xbeef)',
            'barsnap.so.2 => /snap/snapcraft/current/bar.so.2 (0xbeef)',
            '/lib/baz.so.2 (0x1234)',
        ]
        self.run_output_mock.return_value = '\t' + '\n\t'.join(lines) + '\n'

        libs = elf.ElfFile(path='foo',
                           magic=self.stub_magic).load_dependencies()
        self.assertThat(
            libs, Equals(frozenset(['/lib/foo.so.1', '/usr/lib/bar.so.2'])))
    def _setUp(self):
        super()._setUp()

        readelf_path = os.path.abspath(os.path.join(
            __file__, '..', '..', 'bin', 'readelf'))
        current_path = os.environ.get('PATH')
        new_path = '{}:{}'.format(readelf_path, current_path)
        self.useFixture(fixtures.EnvironmentVariable('PATH', new_path))

        stub_magic = ('ELF 64-bit LSB executable, x86-64, version 1 (SYSV), '
                      'dynamically linked, interpreter '
                      '/lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32')

        self.elf_files = [
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-2.26'),
                        magic=stub_magic),
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-2.23'),
                        magic=stub_magic),
            elf.ElfFile(path=os.path.join(self.root_path, 'fake_elf-1.1'),
                        magic=stub_magic),
        ]

        for elf_file in self.elf_files:
            open(elf_file.path, 'w').close()
Example #23
0
    def test_get_libraries_excludes_slash_snap(self):
        lines = [
            'foo.so.1 => /lib/foo.so.1 (0xdead)',
            'bar.so.2 => /usr/lib/bar.so.2 (0xbeef)',
            'barsnap.so.2 => {}/barsnap.so.2 (0xbeef)'.format(
                self.core_base_path),
            '/lib/baz.so.2 (0x1234)',
        ]
        self.run_output_mock.return_value = '\t' + '\n\t'.join(lines) + '\n'

        elf_file = elf.ElfFile(path='foo', magic=self.stub_magic)
        libs = elf_file.load_dependencies(root_path=self.prime_dir,
                                          core_base_path=self.core_base_path)
        self.assertThat(libs, Equals(
            frozenset(['/lib/foo.so.1', '/usr/lib/bar.so.2'])))
Example #24
0
    def test_symbols(self):
        elf_file = elf.ElfFile(path='/fake-elf', magic=self.stub_magic)

        self.assertThat(len(elf_file.symbols), Equals(3))

        self.assertThat(elf_file.symbols[0].name, Equals('endgrent'))
        self.assertThat(elf_file.symbols[0].version, Equals('GLIBC_2.2.5'))
        self.assertThat(elf_file.symbols[0].section, Equals('UND'))

        self.assertThat(elf_file.symbols[1].name,
                        Equals('__ctype_toupper_loc'))
        self.assertThat(elf_file.symbols[1].version, Equals('GLIBC_2.3'))
        self.assertThat(elf_file.symbols[1].section, Equals('UND'))

        self.assertThat(elf_file.symbols[2].name, Equals('PyCodec_Register'))
        self.assertThat(elf_file.symbols[2].version, Equals(''))
        self.assertThat(elf_file.symbols[2].section, Equals('13'))
Example #25
0
    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)
Example #26
0
    def test_primed_libraries_are_preferred(self):
        primed_foo = os.path.join(self.prime_dir, 'foo.so.1')
        open(primed_foo, 'w').close()

        self.ms_mock = mock.Mock()
        self.ms_mock.load.return_value = 0
        self.ms_mock.file.return_value = self.stub_magic

        patcher = mock.patch('magic.open')
        self.magic_mock = patcher.start()
        self.magic_mock.return_value = self.ms_mock
        self.addCleanup(patcher.stop)

        elf_file = elf.ElfFile(path='foo', magic=self.stub_magic)
        libs = elf_file.load_dependencies(root_path=self.prime_dir,
                                          core_base_path=self.core_base_path)
        self.assertThat(libs,
                        Equals(frozenset([primed_foo, '/usr/lib/bar.so.2'])))
Example #27
0
    def test_bin_echo(self):
        # Try parsing a file without the pyelftools logic mocked out
        elf_file = elf.ElfFile(path=sys.executable)

        self.assertThat(elf_file.path, Equals(sys.executable))

        # The arch attribute will be a tuple of three strings
        self.assertTrue(isinstance(elf_file.arch, tuple))
        self.assertThat(len(elf_file.arch), Equals(3))
        self.assertThat(elf_file.arch[0], StartsWith("ELFCLASS"))
        self.assertThat(elf_file.arch[1], StartsWith("ELFDATA"))
        self.assertThat(elf_file.arch[2], StartsWith("EM_"))

        # We expect Python to be a dynamic linked executable with an
        # ELF interpreter.
        self.assertTrue(isinstance(elf_file.interp, str))
        self.assertThat(elf_file.interp, NotEquals(""))

        # Python is not a shared library, so has no soname or defined versions
        self.assertThat(elf_file.soname, Equals(""))
        self.assertThat(elf_file.versions, Equals(set()))

        # We expect that Python will be linked to libc
        for lib in elf_file.needed.values():
            if lib.name.startswith("libc.so"):
                break
        else:
            self.fail("Expected to find libc in needed library list")

        self.assertTrue(isinstance(lib.name, str))
        for version in lib.versions:
            self.assertTrue(isinstance(version, str),
                            "expected {!r} to be a string".format(version))

        # GCC adds a build ID to executables
        self.assertThat(elf_file.build_id, NotEquals(""))

        # If the Python interpreter is distro packaged, it probably
        # doesn't have debug info, but we don't know for sure.
        # Instead just check that it is a boolean.
        self.assertTrue(isinstance(elf_file.has_debug_info, bool))

        # Ensure type is detered as executable.
        self.assertThat(elf_file.elf_type, Equals("ET_EXEC"))
Example #28
0
    def _build(self, *, package: str = "") -> None:
        build_cmd = ["go", "build"]

        if self.options.go_buildtags:
            build_cmd.extend(["-tags={}".format(",".join(self.options.go_buildtags))])

        relink_cmd = build_cmd + ["-ldflags", "-linkmode=external"]

        if self._is_using_go_mod(self.builddir) and not package:
            work_dir = self.builddir
            build_type_args = ["-o"]

            # go build ./... is not supported in go 1.11 or 1.12.
            # This will only install the main module.
            if self._get_parsed_go_version() < parse_version(
                _GO_MOD_ENV_FLAG_REQUIRED_GO_VERSION
            ):
                build_type_args.append(
                    os.path.join(self._install_bin_dir, self._get_module())
                )
            else:
                build_type_args.extend([self._install_bin_dir, "./..."])
        else:
            work_dir = self._install_bin_dir
            build_type_args = [package]

        pre_build_files = os.listdir(self._install_bin_dir)
        self._run(build_cmd + build_type_args, cwd=work_dir)
        post_build_files = os.listdir(self._install_bin_dir)

        new_files = set(post_build_files) - set(pre_build_files)

        if len(new_files) == 0:
            logger.warning(f"no binaries found from {build_cmd!r}")

        for new_file in new_files:
            binary_path = os.path.join(self._install_bin_dir, new_file)

            # Relink with system linker if executable is dynamic in order to be
            # able to set rpath later on. This workaround can be removed after
            # https://github.com/NixOS/patchelf/issues/146 is fixed.
            if self._is_classic and elf.ElfFile(path=binary_path).is_dynamic:
                self._run(relink_cmd + build_type_args, cwd=work_dir)
Example #29
0
    def test_prime_state_with_shadowed_dependencies(self, mock_migrate_files,
                                                    mock_load_dependencies,
                                                    mock_get_symbols):
        self.get_elf_files_mock.return_value = frozenset(
            [elf.ElfFile(path="bin/1")])
        mock_load_dependencies.return_value = {
            f"{self.handler._project.prime_dir}/foo/bar/baz"
        }

        self.assertRaises(errors.NoLatestStepError, self.handler.latest_step)
        self.assertThat(self.handler.next_step(), Equals(steps.PULL))

        bindir = os.path.join(self.handler.part_install_dir, "bin")
        foobardir = os.path.join(self.handler.part_install_dir, "foo", "bar")
        os.makedirs(bindir)
        os.makedirs(foobardir)

        # Make a "binary" as well as a "library" at the same path as the one on
        # the system
        open(os.path.join(bindir, "1"), "w").close()
        open(os.path.join(foobardir, "baz"), "w").close()

        self.handler.mark_done(steps.BUILD)
        self.handler.stage()
        mock_migrate_files.reset_mock()
        self.handler.prime()

        self.assertThat(self.handler.latest_step(), Equals(steps.PRIME))
        self.assertRaises(errors.NoNextStepError, self.handler.next_step)
        self.get_elf_files_mock.assert_called_once_with(
            self.handler._project.prime_dir, {"bin/1", "foo/bar/baz"})
        mock_migrate_files.assert_called_once_with(
            {"bin/1", "foo/bar/baz"},
            {"bin", "foo", "foo/bar"},
            self.handler._project.stage_dir,
            self.handler._project.prime_dir,
        )

        state = self.handler.get_prime_state()

        self.assertTrue(type(state) is states.PrimeState)
        self.assertThat(state.dependency_paths, Equals({"foo/bar"}))
Example #30
0
    def build(self):
        super().build()

        self.run(["shards", "install", "--production"], self.builddir)
        self.run(["shards", "build", "--production"], 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_core_path(self.project.info.base),
            )
            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)