Exemple #1
0
    def finalize_options(self):
        if self.bdist_dir is None:
            bdist_base = self.get_finalized_command("bdist").bdist_base
            self.bdist_dir = os.path.join(bdist_base, "xar")
        if self.dist_dir is None:
            script_name = os.path.expanduser(self.distribution.script_name)
            package_dir = os.path.dirname(os.path.realpath(script_name))
            self.dist_dir = os.path.join(package_dir, "dist")
        if self.console_scripts is not None:
            self.console_scripts = self.console_scripts.strip().split(",")
        self.sqopts = xar_util.SquashfsOptions()
        if self.xar_compression_algorithm is not None:
            self.sqopts.compression_algorithm = self.xar_compression_algorithm
        else:
            self.sqopts.compression_algorithm = "gzip"
        if self.xar_block_size is not None:
            self.sqopts.block_size = self.xar_block_size
        if self.xar_zstd_level is not None:
            self.sqopts.zstd_level = self.xar_zstd_level
        self.xar_outputs = []

        self.working_set = pkg_resources.WorkingSet(sys.path)
        self.installer = None
        if self.download:
            bdist_pip = os.path.join(self.bdist_dir, "downloads")
            mkpath(bdist_pip)
            self.installer = pip_installer.PipInstaller(
                bdist_pip, self.working_set, log)
Exemple #2
0
 def setUp(self):
     self.xar_builder = xar_builder.XarBuilder()
     self.sqopts = xar_util.SquashfsOptions()
     self.sqopts.compression_algorithm = "gzip"
     self.src = xar_util.StagingDirectory()
     # A set of files for testing
     self.files = {
         "executable.sh":
         ("executable.sh", "#!echo executable", "w", 0o755),
         "lib.so": ("lib.so", b"binary source", "wb", 0o644),
         "source.txt": ("source.txt", "text source", "w", 0o644),
         "subdir/source.txt": ("subdir/source.txt", "subdir", "w", 0o644),
     }
     for filename, data, mode, permissions in self.files.values():
         self.src.write(data, filename, mode, permissions)
         self.assertEqual(
             xar_test_helpers.mode(self.src.absolute(filename)),
             permissions)
Exemple #3
0
    def build(self, filename, squashfs_options=None):
        """
        Actually build the XAR. Freezes the XarBuilder if not already frozen.
        Writes the XAR to `filename`. Uses `xar_util.SquashfsOptions`
        `squashfs_options` to construct the XAR. Finally calls :func:`delete`.
        The XarBuilder is no longer usable after this call.
        """
        if squashfs_options is None:
            squashfs_options = xar_util.SquashfsOptions()
        if not self._frozen:
            self.freeze()
        xarfiles = {}
        base_name, xar_ext = os.path.splitext(filename)
        # Build the dependent XARs
        for ext, destination in self._partition_dest:
            ext_filename = base_name + ext + xar_ext
            with tempfile.NamedTemporaryFile(delete=False) as tf:
                xarfiles[ext] = (ext_filename, tf.name)
            self._build_staging_dir(
                destination.staging,
                xarfiles[ext][1],
                BORING_SHEBANG,
                {},
                squashfs_options,
            )
        # Build the main XAR
        with tempfile.NamedTemporaryFile(delete=False) as tf:
            tmp_xar = tf.name
        xar_header = self._build_xar_header(xarfiles)
        self._build_staging_dir(self._staging, tmp_xar, self._shebang,
                                xar_header, squashfs_options)

        # Move the results into place
        shutil.move(tmp_xar, filename)
        for ext_filename, tmp_filename in xarfiles.values():
            shutil.move(tmp_filename, ext_filename)

        # Make the output executable if necessary
        if self._executable is not None:
            os.chmod(filename, 0o755)

        self.delete()
Exemple #4
0
def main():
    logging.basicConfig(level=logging.DEBUG,
                        format="%(asctime)s %(levelname)s %(message)s")
    p = argparse.ArgumentParser()
    p.add_argument("--output", required=True, help="Output XAR file.")
    # XAR options
    p.add_argument(
        "--xar-exec",
        help="Path to xarexec, which must be present to run the XAR file.",
        default="/usr/bin/env xarexec_fuse",
    )
    p.add_argument(
        "--xar-mount-root",
        default=None,
        help="Where the XAR file will mount by default.",
    )

    p.add_argument(
        "--xar-compression-algorithm",
        default="gzip",
        help="Compression algorithm for the XAR file.",
    )
    p.add_argument(
        "--xar-block-size",
        default=256 * 1024,
        help="Block size used when compressing the XAR file.",
    )
    p.add_argument(
        "--xar-zstd-level",
        default=16,
        help="Default zstd level when zstd compression is used.",
    )

    group = p.add_mutually_exclusive_group(required=True)
    # Python options
    group.add_argument(
        "--python",
        help="Make an executable python XAR from the given"
        "directory or zip archive.",
    )
    p.add_argument(
        "--python-interpreter",
        default=None,
        help="Python interpreter for building and running the XAR. "
        "If not set and constructing from a zip archive we try "
        "to extract the shebang to get the Python interpreter. "
        "Otherwise we default to 'python'.",
    )
    p.add_argument(
        "--python-entry-point",
        default=None,
        help="MODULE[:FUNCTION]"
        "The entry point for the python XAR. If unset, we look "
        "for a __main__ module in the XAR and use that.",
    )
    # Raw options
    group.add_argument("--raw", help="Make a raw xar from a directory")
    p.add_argument(
        "--raw-executable",
        default=None,
        help="Executable invoked once the XAR is mounted. It must "
        "be a path relative to the XAR root. If unset the XAR "
        "is not executable.",
    )
    opts = p.parse_args()

    squashfs_options = xar_util.SquashfsOptions()
    squashfs_options.compression_algorithm = opts.xar_compression_algorithm
    squashfs_options.block_size = opts.xar_block_size
    squashfs_options.zstd_level = opts.xar_zstd_level

    if opts.python:
        xar = xar_builder.PythonXarBuilder(opts.xar_exec, opts.xar_mount_root)
        interpreter = opts.python_interpreter
        entry_point = opts.python_entry_point
        # Either copy the directory or extract the archive.
        # Infer interpreter and entry_point if unset.
        if os.path.isdir(opts.python):
            xar.add_directory(opts.python)
            entry_point = entry_point or xar_util.get_python_main(opts.python)
        else:
            z_interpreter, z_entry_point = py_util.extract_python_archive_info(
                opts.python)
            with zipfile.ZipFile(opts.python) as zf:
                interpreter = interpreter or z_interpreter
                entry_point = entry_point or z_entry_point
                xar.add_zipfile(zf)
        if entry_point is None:
            raise XarArgumentError(
                "Python entry point not set and no __main__")

        xar.set_interpreter(interpreter)
        xar.set_entry_point(entry_point)
    elif opts.raw:
        xar = xar_builder.XarBuilder(opts.xar_exec, opts.xar_mount_root)
        xar.add_directory(opts.raw)
        if opts.raw_executable is not None:
            xar.set_executable(opts.raw_executable)
    else:
        raise ValueError("Unexpected value")

    xar.build(opts.output, squashfs_options)

    return 0