Esempio n. 1
0
def setup(shell_obj, settings):
    """
    Does the setup for the current shell. Needs to be run once per shell before the system is usable.

    :param shell_obj: An object to handle shell specific tasks.
    :param settings: The settings dictionary.

    :return: Nothing.
    """

    output = list()

    # # Check to see if there is already a use history file for this shell.
    # # Create one if needed.
    # try:
    #     use_history_file = os.environ[USE_PKG_HISTORY_FILE_ENV]
    # except KeyError:
    #     f, use_history_file = tempfile.mkstemp(suffix=".usehistory", text=True)
    #
    # # Store this file name in the form of an environmental variable.
    # output.append(shell.format_env(USE_PKG_HISTORY_FILE_ENV, use_history_file))
    # # output = "export " + USE_PKG_HISTORY_FILE_ENV + "=" + use_history_file

    legal_path_found = False

    # Start by validating that we have actually found some legal search paths. (making sure that we handle cases where
    # the user passed in a "~" instead of an explicit path)
    for path in settings["pkg_av_search_paths"]:
        path = os.path.expanduser(path)
        if os.path.exists(path) and os.path.isdir(path):
            legal_path_found = True
    for path in settings["pkg_bv_search_paths"]:
        path = os.path.expanduser(path)
        if os.path.exists(path) and os.path.isdir(path):
            legal_path_found = True

    if not legal_path_found:
        display.display_error(
            "No use package directories found. I looked for:",
            ":".join(settings["pkg_av_search_paths"]), "and",
            ":".join(settings["pkg_bv_search_paths"]))
        sys.exit(1)

    # Store the auto version use package search paths in an env var
    # output.append(shell.format_path_var(USE_PKG_AV_SEARCH_PATHS_ENV, settings["pkg_av_search_paths"]))

    # Store the baked version use package search paths in an env var
    # output.append(shell.format_path_var(USE_PKG_BV_SEARCH_PATHS_ENV, settings["pkg_bv_search_paths"]))

    # Save the existing use packages to an env var
    output.append(
        make_write_use_pkgs_to_env_shellcmd(shell_obj,
                                            settings["pkg_av_search_paths"],
                                            settings["pkg_bv_search_paths"],
                                            settings["auto_version_offset"],
                                            settings["do_recursive_search"]))

    # Export these env variables.
    shell_obj.export_shell_command(output)
Esempio n. 2
0
def debug(*msgs):
    """
    If the module level global value of DEBUG is set to True, this will attempt to print a debug statement.

    :param msgs: an arbitrary number of messages to print to the stderr. Note, each msg will be printed on a new line.

    :return: Nothing.
    """

    if DEBUG:
        for msg in msgs:
            display.display_error(msg)
Esempio n. 3
0
    def __init__(self, shell_type):
        """
        Initialize the object.

        :param shell_type: The type of shell (bash, tcsh, etc.) Currently only handles "bash".

        :return: Nothing.
        """

        if shell_type.lower() not in LEGAL_SHELLS:
            display.display_error("Unknown shell: " + sys.argv[1])
            display.display_usage()
            sys.exit(1)

        self.shell_type = shell_type.lower()
Esempio n. 4
0
def read_user_settings_from_env():
    """
    Reads some specific settings from the env. If they are missing, then it uses the built in constants.

    :return: a dictionary containing the values of the env settings. If any of these settings are missing from the env,
             then the globals will be substituted.
    """

    output = dict()

    # Auto Version Search paths (converted to a list)
    output["pkg_av_search_paths"] = os.getenv(
        envmapping.USE_PKG_AV_SEARCH_PATHS_ENV, DEFAULT_USE_PKG_AV_PATHS)
    output["pkg_av_search_paths"] = output["pkg_av_search_paths"].split(":")

    # Baked Version Search paths (converted to a list)
    output["pkg_bv_search_paths"] = os.getenv(
        envmapping.USE_PKG_BV_SEARCH_PATHS_ENV, DEFAULT_USE_PKG_BV_PATHS)
    output["pkg_bv_search_paths"] = output["pkg_bv_search_paths"].split(":")

    # Whether to search recursively, converted to a boolean
    output["do_recursive_search"] = os.getenv(
        envmapping.USE_PKG_SEARCH_RECURSIVE_ENV,
        str(DEFAULT_DO_RECURSIVE_SEARCH))
    if output["do_recursive_search"].upper() not in ["TRUE", "FALSE"]:
        msg = "Environmental variable: " + envmapping.USE_PKG_SEARCH_RECURSIVE_ENV
        msg += " must be either 'True' or 'False'. Exiting."
        display.display_error(msg)
        sys.exit(1)
    if output["do_recursive_search"].upper() == "TRUE":
        output["do_recursive_search"] = True
    else:
        output["do_recursive_search"] = False

    # Get the default offset for auto versions, converted to an integer
    output["auto_version_offset"] = os.getenv(
        envmapping.USE_PKG_AUTO_VERSION_OFFSET_ENV,
        DEFAULT_AUTO_VERSION_OFFSET)
    try:
        output["auto_version_offset"] = int(output["auto_version_offset"])
    except ValueError:
        msg = "Environmental variable: " + envmapping.USE_PKG_AUTO_VERSION_OFFSET_ENV
        msg += " must be an integer. Exiting."
        display.display_error(msg)
        sys.exit(1)

    return output
Esempio n. 5
0
def handle_permission_violation(file_name):
    """
    Handles a permission violation for a particular file. Normally we just
    display an error message and exit. But during development this is
    burdensome. So in that case, we might want to either display the error but
    not exit, or not even display an error.

    :param file_name: The name of the file that violated the permissions.

    :return: Nothing.
    """

    if DISPLAY_PERMISSIONS_VIOLATIONS:
        display.display_error(
            file_name,
            "must be owned by root and only writable by root. Exiting.")
    sys.exit(1)
Esempio n. 6
0
File: bash.py Progetto: bvz2000/use
def export_shell_command(cmds):
    """
    Exports the command for the calling bash shell script to process. Fairly
    simple: It concatenates the list of commands using a semi-colon and then
    simply prints it to stdout.

    :param cmds: A list of shell commands to run.

    :return: Nothing.
    """

    output = ""

    for cmd in cmds:
        if ";" in cmd:
            msg = "This use package has a ; somewhere in one of the commands. This is not allowed."
            display.display_error(msg, quit_after_display=True)
        output += cmd + ";"

    print(output)
Esempio n. 7
0
File: use.py Progetto: bvz2000/use
def read_use_pkg(use_pkg_file):
    """
    Opens a use package file (given by use_pkg_file).

    :param use_pkg_file: The full path to the use package file.

    :return: A configParser object.
    """

    use_pkg_obj = configparser.ConfigParser(allow_no_value=True,
                                            delimiters="=",
                                            empty_lines_in_values=True)

    # Force configparser to maintain capitalization of keys
    use_pkg_obj.optionxform = str

    try:
        use_pkg_obj.read(use_pkg_file)
    except configparser.DuplicateOptionError as e:
        display.display_error("Duplicate entries in .use config file:",
                              use_pkg_file)
        display.display_error(e.message.split(":")[1])
        display.display_error("Exiting")
        sys.exit(1)

    return use_pkg_obj
Esempio n. 8
0
File: use.py Progetto: bvz2000/use
def read_use_pkg_without_delimiters(use_pkg_file):
    """
    Opens a use package file (given by use_pkg_file). This disables the delimiter so that items read are read exactly
    as entered (instead of trying to process key/value pairs).

    :param use_pkg_file: The full path to the use package file.

    :return: A configParser object.
    """

    use_pkg_obj = configparser.ConfigParser(allow_no_value=True,
                                            delimiters="\n",
                                            empty_lines_in_values=True)

    # Force configparser to maintain capitalization of keys
    use_pkg_obj.optionxform = str

    try:
        use_pkg_obj.read(use_pkg_file)
    except configparser.DuplicateOptionError as e:
        display.display_error("Duplicate entries in .use config file:",
                              use_pkg_file)
        display.display_error(e.message.split(":")[1])
        display.display_error("Exiting")
        sys.exit(1)

    return use_pkg_obj
Esempio n. 9
0
File: use.py Progetto: bvz2000/use
def get_branch_from_use_pkg_name(use_pkg_name):
    """
    Given a use package name, returns the branch name associated with that use package.

    :param use_pkg_name: The name of the use package.

    :return: The branch name from this use package.
    """

    # Find the use package file from this use package name
    use_pkg_file = get_use_pkg_file_from_use_pkg_name(use_pkg_name)
    if use_pkg_file is None:
        display.display_error("No use package named: " + use_pkg_name)
        sys.exit(1)

    # Read the use package file
    use_obj = read_use_pkg(use_pkg_file)

    # Extract the branch
    branch = get_use_package_item_list(use_obj, "branch", {})[0]

    return branch
Esempio n. 10
0
File: use.py Progetto: bvz2000/use
def use(shell_obj, use_pkg_name, raw_aliases, settings):
    """
    Uses a new package (given by use_pkg_name). Processes this file and exports the contents converted into bash
    commands.

    :param shell_obj: A shell object to handle shell specific formatting.
    :param use_pkg_name: A name of the use package (not the file name, just the package name. (Eg: clarisse-3.6sp2, and
           not clarisse-3.6sp2.use).
    :param raw_aliases: The contents of the stdin which should hold all of the existing aliases. This is used so that we
           can store what an alias was before we changed it (to set it back when we unuse).
    :param settings: A dictionary containing the settings

    :return: Nothing
    """

    # Find the use package file from this use package name
    use_pkg_file = get_use_pkg_file_from_use_pkg_name(use_pkg_name)
    if use_pkg_file is None:
        display.display_error("No use package named: " + use_pkg_name)
        sys.exit(1)

    permissions.validate_use_pkg_permissions(use_pkg_file)
    use_obj = read_use_pkg(use_pkg_file)
    use_raw_obj = read_use_pkg_without_delimiters(use_pkg_file)

    substitutions = get_built_in_vars(use_pkg_file,
                                      settings["auto_version_offset"])

    branch = get_use_package_item_list(use_obj, "branch", substitutions)[0]
    aliases = get_use_package_key_value_pairs(use_obj, "alias", substitutions)
    env_vars = get_use_package_key_value_pairs(use_obj, "env", substitutions)
    path_prepends = get_use_package_path_appends(use_obj, substitutions, True)
    path_postpends = get_use_package_path_appends(use_obj, substitutions,
                                                  False)
    use_shell_cmds = get_use_package_item_list(use_raw_obj, "use-shell-cmds",
                                               substitutions)
    unuse_shell_cmds = get_use_package_item_list(use_raw_obj,
                                                 "unuse-shell-cmds",
                                                 substitutions)

    # Check to see if the branch is already present in USE_BRANCHES. If so, then an error has occurred since an unuse
    # should have happened first to remove this branch.
    use_branches_env = os.getenv("USE_BRANCHES", "")
    if use_branches_env.startswith(
            branch + ",") or ":" + branch + "," in use_branches_env:
        msg = "The branch '" + branch + "' still exists in this shell. "
        msg += "Auto-unuse may have failed. "
        msg += "Unable to run use command. "
        msg += "Try creating a new shell and running use in that shell instead."
        display.display_error(msg)
        sys.exit(1)

    shell_cmds = list()

    for alias in aliases.keys():
        shell_cmds.append(shell_obj.format_alias(alias, aliases[alias]))

    for env_var in env_vars.keys():
        shell_cmds.append(shell_obj.format_env(env_var, env_vars[env_var]))

    # Merge the list of prepend path variables and postpend path variable names into a single, de-duplicated list. So
    # now we have a list of all path variables that we will be modifying.
    path_var_names = list(path_prepends.keys())
    path_var_names.extend(path_postpends.keys())
    path_var_names = list(set(path_var_names))

    # Go through this list and for each variable name, get a list of prepends AND postpends to apply to this variable.
    for path_var_name in path_var_names:

        # Build the list of paths to prepend to this var
        try:
            prepends = path_prepends[path_var_name].copy()
        except KeyError:
            prepends = list()

        # Build the list of paths to postpend to this var
        try:
            postpends = path_postpends[path_var_name]
        except KeyError:
            postpends = list()

        # Remove any actual paths from the postpends if they also exist in the prepends (prepends win).
        postpends = [path for path in postpends if path not in prepends]

        # Get a list of existing paths for this variable (empty list if the variable does not exist)
        try:
            existing = os.environ[path_var_name].split(":")
        except KeyError:
            existing = list()

        # Build a list of existing paths where we remove any of the new paths we are prepending or postpending. This
        # essentially means that if we are prepending or postpending a path that is already a part of the existing var
        # then this path will be removed from the existing var before being added again.
        existing_with_new_paths_removed = [
            path for path in existing if path not in prepends
        ]
        existing_with_new_paths_removed = [
            path for path in existing_with_new_paths_removed
            if path not in postpends
        ]

        # Take the prepends list, and extend it with the existing paths.
        prepends.extend(existing_with_new_paths_removed)

        # Now postpend the postpends list.
        prepends.extend(postpends)

        # Add this command to the shell commands.
        shell_cmds.append(shell_obj.format_path_var(path_var_name, prepends))

    if permissions.validate_arbitrary_shell_permissions():
        for use_shell_cmd in use_shell_cmds:
            shell_cmds.append(use_shell_cmd)

    # Convert the list of existing aliases to a dictionary
    existing_aliases = format_existing_aliases_into_dict(raw_aliases)

    # Get a list of the new aliases from the use package that already exist in the shell.
    original_aliases = get_matching_aliases(aliases, existing_aliases)

    # Get a list of the new env vars from the use package that already exist in the shell.
    original_env_vars = get_matching_env_vars(env_vars)

    # Get a list of the new path vars from the use package that already exist in the shell.
    original_path_vars = get_matching_paths(path_prepends, path_postpends)

    write_history(shell_obj=shell_obj,
                  use_pkg_name=use_pkg_name,
                  use_pkg_file=use_pkg_file,
                  branch=branch,
                  new_aliases=aliases,
                  new_env_vars=env_vars,
                  new_path_prepends=path_prepends,
                  new_path_postpends=path_postpends,
                  use_shell_cmds=use_shell_cmds,
                  unuse_shell_cmds=unuse_shell_cmds,
                  original_aliases=original_aliases,
                  original_env_vars=original_env_vars,
                  original_path_vars=original_path_vars)

    shell_obj.export_shell_command(shell_cmds)
Esempio n. 11
0
def main():
    """
    Main entry point for the python portion of the app.

    sys.argv[1] is the name of the shell type (bash, tcsh, etc.) that is being used.

    sys.argv[2] is the name of the command that is to be run.

    :return: Nothing.
    """

    # Make sure this script is owned by root and only writable by root.
    permissions.validate_app_permissions()

    # Create a shell object to handle shell specific tasks
    shell_obj = shell.Shell(sys.argv[1])

    # Only handle specific types of requests
    if sys.argv[2] not in LEGAL_COMMANDS:
        display.display_error("Unknown command: " + sys.argv[2])
        display.display_usage()
        sys.exit(1)

    # Read the env and stuff its settings into the constants
    settings = read_user_settings_from_env()

    # ===========================
    if sys.argv[2] == "setup":
        setup.setup(shell_obj, settings)
        sys.exit(0)

    # ===========================
    if sys.argv[2] == "refresh":
        setup.setup(shell_obj, settings)
        sys.exit(0)

    # ===========================
    if sys.argv[2] == "complete_use":
        completions.complete_use(sys.argv[3])

    # ===========================
    if sys.argv[2] == "complete_unuse":
        completions.complete_unuse(sys.argv[3])

    # ===========================
    if sys.argv[2] == "use":
        if len(sys.argv) != 4:
            display.display_error("use: Wrong number of arguments.")
            sys.exit(1)
        stdin = list(
            sys.stdin
        )  # List of existing aliases in the shell. Used to store for history and unuse purposes.
        use.use(shell_obj, sys.argv[3], stdin, settings)

    # ===========================
    if sys.argv[2] == "used":
        used.used(shell_obj)

    # ===========================
    if sys.argv[2] == "unuse":
        stdin = list(
            sys.stdin
        )  # List of existing aliases in the shell. Used to store for history and unuse purposes.
        if len(sys.argv) > 3:
            branch_name = use.get_branch_from_use_pkg_name(sys.argv[3])
            unuse.unuse(shell_obj, branch_name, stdin)

    # ===========================
    if sys.argv[2] == "get_branch_from_use_pkg_name":
        branch_name = use.get_branch_from_use_pkg_name(sys.argv[3])
        print(branch_name)