Beispiel #1
0
 def run(self, args):
     this = base.get_program_name()
     if (len(args) == 1) and (args[0] in ACTIONS):
         action = args[0]
         print('Usage for %s %s' % (this, action))
         ACTIONS[action](workspace=None)(['--help'])
     else:
         print(USAGE % {'this': this})
         FLAGS.print_usage()
Beispiel #2
0
 def run(self, args):
     this = base.get_program_name()
     if (len(args) == 1) and (args[0] in ACTIONS):
         action = args[0]
         print('Usage for %s %s' % (this, action))
         ACTIONS[action](workspace=None)(['--help'])
     else:
         print(USAGE % {'this': this})
         FLAGS.print_usage()
Beispiel #3
0
    def run(self, args):
        action = self.flags.do
        if (action is None) and (len(args) >= 1) and (args[0] in _ACTIONS):
            action = args[0]
            args = args[1:]

        if action is None:
            print("Must specify an action to perform with {} [--do=]action".
                  format(base.get_program_name()))
            return os.EX_USAGE

        repo = maven_repo.MavenRepository(
            local=self.flags.local,
            remotes=self.flags.remotes.split(","),
        )

        action_class = _ACTIONS[action]
        cli = action_class(repo=repo)
        return cli(args)
Beispiel #4
0
    def run(self, args):
        action = self.flags.do
        if (action is None) and (len(args) >= 1) and (args[0] in _ACTIONS):
            action = args[0]
            args = args[1:]

        if action is None:
            print("Must specify an action to perform with {} [--do=]action"
                  .format(base.get_program_name()))
            return os.EX_USAGE

        repo = maven_repo.MavenRepository(
            local=self.flags.local,
            remotes=self.flags.remotes.split(","),
        )

        action_class = _ACTIONS[action]
        cli = action_class(repo=repo)
        return cli(args)
    def register_flags(self):
        profiles = self.config["profiles"]
        profile_name = base.get_program_name()
        if profile_name not in profiles:
            profile_name = self.config["default_profile"]
        profile = profiles[profile_name]

        self.flags.add_string(
            name="java-path",
            default=self.which_java(),
            help="Path of the 'java' executable. Default is the result of $(which java).",
        )
        self.flags.add_string(
            name="class-name",
            default=None,
            help=("Fully qualified name of the Java class to invoke.\n"
                  "Java class for profile {!r} is {!r}"
                  .format(profile_name, profile["main_class"])),
        )
        self.flags.add_string(
            name="profile",
            default=None,
            help=("Profile of the JVM application to run.\n"
                  "Defaults is to use args[0].\n"
                  "Currently selected profile is {!r}."
                  .format(profile_name)),
        )
        self.flags.add_boolean(
            name="print-classpath",
            default=False,
            help="When set, prints the selected classpath and exits.",
        )
        self.flags.add_boolean(
            name="print-config",
            default=False,
            help="When set, prints the selected JSON config and exits.",
        )
        self.flags.add_boolean(
            name="ignore-profile-jvm-args",
            default=False,
            help="When set, ignore JVM arguments from the profile configuration.",
        )
Beispiel #6
0
    def __call__(self, args, config_file=None):
        """Allows invoking an action as a function.

        Args:
            args: Command-line arguments specific to the action.
            config_file: Location of a file containing a json object with base flag values
                (values in args will take precedence over these values).
        Returns:
            Exit code.
        """
        if not self._flags.parse(args, config_file):
            return os.EX_USAGE

        if (self._help_flag == HELP_FLAG.ADD_HANDLE) and self.flags.help:
            print(base.strip_margin(self.USAGE.strip() % {
                'this': '%s %s' % (base.get_program_name(), self.get_name()),
            }))
            print()
            self.flags.print_usage()
            return os.EX_OK

        return self.run(self._flags.get_unparsed())
Beispiel #7
0
                        with open(sha1_path, "w") as f:
                            f.write(sha1)
                        return local_path
                    else:
                        logging.warning("Checksum invalid for %r", local_path)
                        os.remove(local_path)
                finally:
                    http_reply.close()

            except urllib.error.HTTPError as err:
                logging.error("Error on remote %r: %r", remote,
                              err.readall().decode())

            except urllib.error.URLError as err:
                if isinstance(err.reason, FileNotFoundError):
                    logging.debug("File not found: %r", err.reason.filename)
                else:
                    logging.error("Error on remote %r: %r", remote, err)

        # Artifact is nowhere to be found:
        return None

    AddRemote = base.deprecated(add_remote)


# ------------------------------------------------------------------------------

if __name__ == "__main__":
    raise Error("Cannot run %s as a standalone script." %
                base.get_program_name())
class Launcher(cli.Action):
    USAGE = """\
    |Usage:
    |
    |    {program} <program-arg> ... \\
    |        [{launcher_args} <launcher-arg> ...] \\
    |        [{jvm_args} <jvm-arg> ...] \\
    |        [{program_args} <program-arg> ...]
    |
    |Environment variables:
    |    CLASSPATH : Pre-existing classpath to append to.
    |
    |JVM arguments (<jvm-arg>) are options passed to the JVM, eg. '-Xmx2G'.
    |Program arguments (<program-arg>) are passed to the Java program invoked.
    |Launcher arguments (<launcher-arg>) are listed below.
    """.format(
        program=base.get_program_name(),
        launcher_args=LAUNCHER_ARGS,
        jvm_args=JVM_ARGS,
        program_args=PROGRAM_ARGS,
    )

    def register_flags(self):
        profiles = self.config["profiles"]
        profile_name = base.get_program_name()
        if profile_name not in profiles:
            profile_name = self.config["default_profile"]
        profile = profiles[profile_name]

        self.flags.add_string(
            name="java-path",
            default=self.which_java(),
            help="Path of the 'java' executable. Default is the result of $(which java).",
        )
        self.flags.add_string(
            name="class-name",
            default=None,
            help=("Fully qualified name of the Java class to invoke.\n"
                  "Java class for profile {!r} is {!r}"
                  .format(profile_name, profile["main_class"])),
        )
        self.flags.add_string(
            name="profile",
            default=None,
            help=("Profile of the JVM application to run.\n"
                  "Defaults is to use args[0].\n"
                  "Currently selected profile is {!r}."
                  .format(profile_name)),
        )
        self.flags.add_boolean(
            name="print-classpath",
            default=False,
            help="When set, prints the selected classpath and exits.",
        )
        self.flags.add_boolean(
            name="print-config",
            default=False,
            help="When set, prints the selected JSON config and exits.",
        )
        self.flags.add_boolean(
            name="ignore-profile-jvm-args",
            default=False,
            help="When set, ignore JVM arguments from the profile configuration.",
        )

    def run(self, args):
        assert (len(args) == 0), "Unexpected launcher command-line arguments: {!r}".format(args)

        assert os.path.exists(self.flags.java_path), \
            "JVM executable not found: {!r}".format(self.flags.java_path)

        self.extract()

        # Identify which profile to use:
        profiles = self.config["profiles"]

        if self.flags.profile is not None:
            # Profile explicitly specified by user must exist:
            assert (self.flags.profile in profiles), \
                "Invalid profile {!r}, use one of {}." \
                .format(self.flags.profile, sorted(profiles.keys()))
            profile_name = self.flags.profile
        else:
            # No explicit override, default is to use the program name if possible,
            # falling back to the configured default profile if needed.
            profile_name = base.get_program_name()
            if profile_name not in profiles:
                profile_name = self.config["default_profile"]
        profile = profiles[profile_name]

        # Compute the JVM arguments from explicit extension/overrides and from global map:
        jvm_args = list()
        if not self.flags.ignore_profile_jvm_args:
            jvm_args.extend(profile.get("jvm_args", tuple()))
        jvm_args.extend(arg_map[JVM_ARGS])

        # Recover program arguments from global map:
        program_args = arg_map[PROGRAM_ARGS]

        # Compute concrete classpath and set environment CLASSPATH accordingly:
        cp_entries = tuple(self.make_classpath_entries(profile))
        env = dict(os.environ)
        env["CLASSPATH"] = ":".join(cp_entries)

        # Handle --print-X launcher commands:
        should_exit = False  # becomes true if a special command is invoked (eg. --print-foo)
        if self.flags.print_classpath:
            print(":".join(cp_entries))
            should_exit = True
        if self.flags.print_config:
            print(base.json_encode(self.config))
            should_exit = True
        if should_exit:
            return os.EX_OK

        # Determine which Java class to invoke:
        class_name = profile["main_class"]
        if self.flags.class_name is not None:
            class_name = self.flags.class_name

        log.info("Using Java executable: {!r}", self.flags.java_path)
        log.info("Using JVM arguments: {!r}", jvm_args)
        log.info("Using Java main class: {!r}", class_name)
        log.info("Using classpath: {}", base.json_encode(cp_entries))
        log.info("Using Java program arguments: {!r}", program_args)
        log.debug("Using environment: {}", base.json_encode(env))

        args = list()
        args.append(self.flags.java_path)
        args.extend(jvm_args)
        args.append(class_name)
        args.extend(program_args)

        os.execve(self.flags.java_path, args, env)

    def make_classpath_entries(self, profile):
        """Generates the complete classpath for the specified Java application profile.

        Args:
            profile: Java application profile.
        Yields:
            Classpath entry absolute file path, in order.
        """
        yield from filter(None, os.environ.get("CLASSPATH", "").split(":"))
        for cp_entry in profile["classpath"]:
            yield os.path.join(self.package_dir, cp_entry)

    @base.memoized_property
    def config(self):
        """Loads the configuration record (Python dictionary) from the 'java.config' resource."""
        return eval(base.get_resource(package_name="java", resource="config"))

    def extract(self):
        """Extracts this archive into a MD5-named folder.

        Also creates or updates the symlink 'package'.
        """
        this_path = self.this_path
        run_dir = "{}.run".format(this_path)

        # Extract archive, if necessary:
        md5 = md5_sum(this_path)
        md5_dir = os.path.join(run_dir, "md5.%s" % md5)
        if not os.path.isdir(md5_dir):
            pid_dir = '%s.%s' % (md5_dir, os.getpid())

            # Extract the archive contained in this shell-script/file:
            zf = zipfile.ZipFile(this_path)
            zf.extractall(path=pid_dir)

            try:
                # Atomically renamed the 'md5.<sum>.<pid>' directory into 'md5.<sum>'.
                os.rename(pid_dir, md5_dir)
            except OSError as err:
                # The directory rename failed, most likely because another concurrent process raced
                # with this process. At this point, the 'md5.<sum>' folder exists, we just need to
                # cleanup the pid_dir that could not be renamed.
                shutil.rmtree(pid_dir)
            assert os.path.isdir(md5_dir), "Unable to self-extract into {!r}".format(md5_dir)

        # Symlink the md5 dir:
        with tempfile.NamedTemporaryFile(
            prefix="%s." % self.package_dir,
            suffix=".new",
            delete=False
        ) as new_package:
            os.remove(new_package.name)
            os.symlink(src=md5_dir, dst=new_package.name)
            os.rename(src=new_package.name, dst=self.package_dir)

    @property
    def this_path(self):
        """Absolute path of the self-extracting executable archive."""
        return os.path.realpath(sys.argv[0])

    @property
    def run_dir(self):
        """Working directory of self-extracting executable."""
        return "{}.run".format(self.this_path)

    @property
    def package_dir(self):
        """Directory where the content of the self-extracting archive is unpacked."""
        return os.path.join(self.run_dir, "package")

    def which_java(self):
        """Looks up the path of the 'java' executable.

        Returns:
            The path of the 'java' executable available in the current environment.
            None if no 'java' executable is found on the shell path.
        """
        try:
            return subprocess.check_output(args=["which", "java"]).decode().strip()
        except subprocess.CalledProcessError:
            return None
    def run(self, args):
        assert (len(args) == 0), "Unexpected launcher command-line arguments: {!r}".format(args)

        assert os.path.exists(self.flags.java_path), \
            "JVM executable not found: {!r}".format(self.flags.java_path)

        self.extract()

        # Identify which profile to use:
        profiles = self.config["profiles"]

        if self.flags.profile is not None:
            # Profile explicitly specified by user must exist:
            assert (self.flags.profile in profiles), \
                "Invalid profile {!r}, use one of {}." \
                .format(self.flags.profile, sorted(profiles.keys()))
            profile_name = self.flags.profile
        else:
            # No explicit override, default is to use the program name if possible,
            # falling back to the configured default profile if needed.
            profile_name = base.get_program_name()
            if profile_name not in profiles:
                profile_name = self.config["default_profile"]
        profile = profiles[profile_name]

        # Compute the JVM arguments from explicit extension/overrides and from global map:
        jvm_args = list()
        if not self.flags.ignore_profile_jvm_args:
            jvm_args.extend(profile.get("jvm_args", tuple()))
        jvm_args.extend(arg_map[JVM_ARGS])

        # Recover program arguments from global map:
        program_args = arg_map[PROGRAM_ARGS]

        # Compute concrete classpath and set environment CLASSPATH accordingly:
        cp_entries = tuple(self.make_classpath_entries(profile))
        env = dict(os.environ)
        env["CLASSPATH"] = ":".join(cp_entries)

        # Handle --print-X launcher commands:
        should_exit = False  # becomes true if a special command is invoked (eg. --print-foo)
        if self.flags.print_classpath:
            print(":".join(cp_entries))
            should_exit = True
        if self.flags.print_config:
            print(base.json_encode(self.config))
            should_exit = True
        if should_exit:
            return os.EX_OK

        # Determine which Java class to invoke:
        class_name = profile["main_class"]
        if self.flags.class_name is not None:
            class_name = self.flags.class_name

        log.info("Using Java executable: {!r}", self.flags.java_path)
        log.info("Using JVM arguments: {!r}", jvm_args)
        log.info("Using Java main class: {!r}", class_name)
        log.info("Using classpath: {}", base.json_encode(cp_entries))
        log.info("Using Java program arguments: {!r}", program_args)
        log.debug("Using environment: {}", base.json_encode(env))

        args = list()
        args.append(self.flags.java_path)
        args.extend(jvm_args)
        args.append(class_name)
        args.extend(program_args)

        os.execve(self.flags.java_path, args, env)
Beispiel #10
0
                        logging.debug("Writing SHA1 sum for %r", local_path)
                        with open(sha1_path, "w") as f:
                            f.write(sha1)
                        return local_path
                    else:
                        logging.warning("Checksum invalid for %r", local_path)
                        os.remove(local_path)
                finally:
                    http_reply.close()

            except urllib.error.HTTPError as err:
                logging.error("Error on remote %r: %r", remote, err.readall().decode())

            except urllib.error.URLError as err:
                if isinstance(err.reason, FileNotFoundError):
                    logging.debug("File not found: %r", err.reason.filename)
                else:
                    logging.error("Error on remote %r: %r", remote, err)

        # Artifact is nowhere to be found:
        return None

    AddRemote = base.deprecated(add_remote)


# ------------------------------------------------------------------------------


if __name__ == "__main__":
    raise Error("Cannot run %s as a standalone script." % base.get_program_name())