Esempio n. 1
0
    def _run_scriptlet(self, scriptlet_name: str, scriptlet: str,
                       workdir: str) -> None:
        with tempfile.TemporaryDirectory() as tempdir:
            call_fifo = _NonBlockingRWFifo(
                os.path.join(tempdir, 'function_call'))
            feedback_fifo = _NonBlockingRWFifo(
                os.path.join(tempdir, 'call_feedback'))

            env = ''
            if common.is_snap():
                # Since the snap is classic, $SNAP/bin is not on the $PATH.
                # Let's set an alias to make sure it's found (but only if it
                # exists).
                snapcraftctl_path = os.path.join(os.getenv('SNAP'), 'bin',
                                                 'snapcraftctl')
                if os.path.exists(snapcraftctl_path):
                    env += 'alias snapcraftctl="$SNAP/bin/snapcraftctl"\n'
            env += common.assemble_env()

            # snapcraftctl only works consistently if it's using the exact same
            # interpreter as that used by snapcraft itself, thus the definition
            # of SNAPCRAFT_INTERPRETER.
            script = textwrap.dedent("""\
                export SNAPCRAFTCTL_CALL_FIFO={call_fifo}
                export SNAPCRAFTCTL_FEEDBACK_FIFO={feedback_fifo}
                export SNAPCRAFT_INTERPRETER={interpreter}
                {env}
                {scriptlet}
            """.format(interpreter=sys.executable,
                       call_fifo=call_fifo.path,
                       feedback_fifo=feedback_fifo.path,
                       env=env,
                       scriptlet=scriptlet))

            process = subprocess.Popen(['/bin/sh', '-e', '-c', script],
                                       cwd=workdir)

            status = None
            try:
                while status is None:
                    function_call = call_fifo.read()
                    if function_call:
                        # Handle the function and let caller know that function
                        # call has been handled (must contain at least a
                        # newline, anything beyond is considered an error by
                        # snapcraftctl)
                        feedback_fifo.write('{}\n'.format(
                            self._handle_builtin_function(
                                scriptlet_name, function_call.strip())))
                    status = process.poll()

                    # Don't loop TOO busily
                    time.sleep(0.1)
            finally:
                call_fifo.close()
                feedback_fifo.close()

            if status:
                raise errors.ScriptletRunError(scriptlet_name=scriptlet_name,
                                               code=status)
Esempio n. 2
0
    def _run_scriptlet(self, scriptlet_name: str, scriptlet: str, workdir: str) -> None:
        with tempfile.TemporaryDirectory(dir=self._partdir) as tempdir:
            call_fifo = _NonBlockingRWFifo(os.path.join(tempdir, "function_call"))
            feedback_fifo = _NonBlockingRWFifo(os.path.join(tempdir, "call_feedback"))

            # snapcraftctl only works consistently if it's using the exact same
            # interpreter as that used by snapcraft itself, thus the definition
            # of SNAPCRAFT_INTERPRETER.
            script = textwrap.dedent(
                """\
                set -e
                export SNAPCRAFTCTL_CALL_FIFO={call_fifo}
                export SNAPCRAFTCTL_FEEDBACK_FIFO={feedback_fifo}
                export SNAPCRAFT_INTERPRETER={interpreter}
                {env}
                {scriptlet}"""
            ).format(
                interpreter=sys.executable,
                call_fifo=call_fifo.path,
                feedback_fifo=feedback_fifo.path,
                scriptlet=scriptlet,
                env=_get_env(),
            )

            with tempfile.TemporaryFile(mode="w+") as script_file:
                print(script, file=script_file)
                script_file.flush()
                script_file.seek(0)

                process = subprocess.Popen(["/bin/sh"], stdin=script_file, cwd=workdir)

            status = None
            try:
                while status is None:
                    function_call = call_fifo.read()
                    if function_call:
                        # Handle the function and let caller know that function
                        # call has been handled (must contain at least a
                        # newline, anything beyond is considered an error by
                        # snapcraftctl)
                        feedback_fifo.write(
                            "{}\n".format(
                                self._handle_builtin_function(
                                    scriptlet_name, function_call.strip()
                                )
                            )
                        )
                    status = process.poll()

                    # Don't loop TOO busily
                    time.sleep(0.1)
            finally:
                call_fifo.close()
                feedback_fifo.close()

            if status:
                raise errors.ScriptletRunError(
                    scriptlet_name=scriptlet_name, code=status
                )
Esempio n. 3
0
    def _run_scriptlet(
        self,
        scriptlet_name: str,
        scriptlet: str,
        workdir: str,
        env_generator: Callable[..., str] = common.assemble_env,
    ) -> None:
        if common.is_snap():
            # Since the snap is classic, there is no $PATH pointing into the snap, which
            # means snapcraftctl won't be found. We can't use aliases since they don't
            # persist into subshells. However, we know that snapcraftctl lives in its own
            # directory, so adding that to the PATH should have no ill side effects.
            snapcraftctl_env = 'export PATH="$PATH:$SNAP/bin/scriptlet-bin"\n'
        else:
            snapcraftctl_env = ""

        with tempfile.TemporaryDirectory(dir=self._partdir) as tempdir:
            call_fifo = _NonBlockingRWFifo(os.path.join(tempdir, "function_call"))
            feedback_fifo = _NonBlockingRWFifo(os.path.join(tempdir, "call_feedback"))

            # snapcraftctl only works consistently if it's using the exact same
            # interpreter as that used by snapcraft itself, thus the definition
            # of SNAPCRAFT_INTERPRETER.
            script = textwrap.dedent(
                """\
                set -e
                export SNAPCRAFTCTL_CALL_FIFO={call_fifo}
                export SNAPCRAFTCTL_FEEDBACK_FIFO={feedback_fifo}
                export SNAPCRAFT_INTERPRETER={interpreter}
                {snapcraftctl_env}
                {env}
                {scriptlet}"""
            ).format(
                interpreter=sys.executable,
                call_fifo=call_fifo.path,
                feedback_fifo=feedback_fifo.path,
                scriptlet=scriptlet,
                snapcraftctl_env=snapcraftctl_env,
                env=env_generator(),
            )

            with tempfile.TemporaryFile(mode="w+") as script_file:
                print(script, file=script_file)
                script_file.flush()
                script_file.seek(0)

                process = subprocess.Popen(["/bin/sh"], stdin=script_file, cwd=workdir)

            status = None
            try:
                while status is None:
                    function_call = call_fifo.read()
                    if function_call:
                        # Handle the function and let caller know that function
                        # call has been handled (must contain at least a
                        # newline, anything beyond is considered an error by
                        # snapcraftctl)
                        feedback_fifo.write(
                            "{}\n".format(
                                self._handle_builtin_function(
                                    scriptlet_name, function_call.strip()
                                )
                            )
                        )
                    status = process.poll()

                    # Don't loop TOO busily
                    time.sleep(0.1)
            finally:
                call_fifo.close()
                feedback_fifo.close()

            if status:
                raise errors.ScriptletRunError(
                    scriptlet_name=scriptlet_name, code=status
                )