Exemplo n.º 1
0
def process_config(config_path, py3_wrapper=None):
    """
    Parse i3status.conf so we can adapt our code to the i3status config.
    """
    def notify_user(error):
        if py3_wrapper:
            py3_wrapper.notify_user(error)
        else:
            print(error)

    def parse_config(config):
        """
        Parse text or file as a py3status config file.
        """

        if hasattr(config, "readlines"):
            config = "".join(config.readlines())
        parser = ConfigParser(config, py3_wrapper)
        parser.parse()
        parsed = parser.config
        del parser
        return parsed

    def parse_config_error(e, config_path):
        # There was a problem use our special error config
        error = e.one_line(config_path)
        notify_user(error)
        # to display correctly in i3bar we need to do some substitutions
        for char in ['"', "{", "|"]:
            error = error.replace(char, "\\" + char)
        error_config = Template(ERROR_CONFIG).substitute(error=error)
        return parse_config(error_config)

    config = {}

    # get the file encoding this is important with multi-byte unicode chars
    try:
        encoding = check_output(
            ["file", "-b", "--mime-encoding", "--dereference", config_path])
        encoding = encoding.strip().decode("utf-8")
    except CalledProcessError:
        # bsd does not have the --mime-encoding so assume utf-8
        encoding = "utf-8"
    try:
        with codecs.open(config_path, "r", encoding) as f:
            try:
                config_info = parse_config(f)
            except ParseException as e:
                config_info = parse_config_error(e, config_path)
    except LookupError:
        with codecs.open(config_path) as f:
            try:
                config_info = parse_config(f)
            except ParseException as e:
                config_info = parse_config_error(e, config_path)

    # update general section with defaults
    general_defaults = GENERAL_DEFAULTS.copy()
    if "general" in config_info:
        general_defaults.update(config_info["general"])
    config["general"] = general_defaults

    config["py3status"] = config_info.get("py3status", {})
    modules = {}
    on_click = {}
    i3s_modules = []
    py3_modules = []
    module_groups = {}

    def process_onclick(key, value, group_name):
        """
        Check on_click events are valid.  Store if they are good
        """
        button_error = False
        button = ""
        try:
            button = key.split()[1]
            if int(button) not in range(1, 20):
                button_error = True
        except (ValueError, IndexError):
            button_error = True

        if button_error:
            err = "Invalid on_click for `{}`. Number not in range 1-20: `{}`."
            notify_user(err.format(group_name, button))
            return False
        clicks = on_click.setdefault(group_name, {})
        clicks[button] = value
        return True

    def get_module_type(name):
        """
        i3status or py3status?
        """
        if name.split()[0] in I3S_MODULE_NAMES:
            return "i3status"
        return "py3status"

    def process_module(name, module, parent):
        if parent:
            modules[parent]["items"].append(name)
            mg = module_groups.setdefault(name, [])
            mg.append(parent)
            if get_module_type(name) == "py3status":
                module[".group"] = parent

        # check module content
        for k, v in list(module.items()):
            if k.startswith("on_click"):
                # on_click event
                process_onclick(k, v, name)
                # on_click should not be passed to the module via the config.
                del module[k]
            if isinstance(v, ModuleDefinition):
                # we are a container
                module["items"] = []
        return module

    def get_modules(data, parent=None):
        for k, v in data.items():
            if isinstance(v, ModuleDefinition):
                module = process_module(k, v, parent)
                modules[k] = module
                get_modules(v, parent=k)

    get_modules(config_info)

    config["order"] = []

    def remove_any_contained_modules(module):
        """
        takes a module definition and returns a dict without any modules that
        may be defined with it.
        """
        fixed = {}
        for k, v in module.items():
            if not isinstance(v, ModuleDefinition):
                fixed[k] = v
        return fixed

    def append_modules(item):
        module_type = get_module_type(item)
        if module_type == "i3status":
            if item not in i3s_modules:
                i3s_modules.append(item)
        else:
            if item not in py3_modules:
                py3_modules.append(item)

    def add_container_items(module_name):
        module = modules.get(module_name, {})
        items = module.get("items", [])
        for item in items:
            if item in config:
                continue

            append_modules(item)
            module = modules.get(item, {})
            config[item] = remove_any_contained_modules(module)
            # add any children
            add_container_items(item)

    # create config for modules in order
    for name in config_info.get("order", []):
        module = modules.get(name, {})
        config["order"].append(name)
        add_container_items(name)
        append_modules(name)

        config[name] = remove_any_contained_modules(module)

    config["on_click"] = on_click
    config["i3s_modules"] = i3s_modules
    config["py3_modules"] = py3_modules
    config[".module_groups"] = module_groups

    # time and tztime modules need a format for correct processing
    for name in config:
        if name.split()[0] in TIME_MODULES and "format" not in config[name]:
            if name.split()[0] == "time":
                config[name]["format"] = TIME_FORMAT
            else:
                config[name]["format"] = TZTIME_FORMAT

    if not config["order"]:
        notify_user("Your configuration file does not list any module"
                    ' to be loaded with the "order" directive.')
    return config
Exemplo n.º 2
0
def process_config(config_path, py3_wrapper=None):
    """
    Parse i3status.conf so we can adapt our code to the i3status config.
    """
    def notify_user(error):
        if py3_wrapper:
            py3_wrapper.notify_user(error)
        else:
            print(error)

    def parse_config(config):
        '''
        Parse text or file as a py3status config file.
        '''

        if hasattr(config, 'readlines'):
            config = ''.join(config.readlines())
        parser = ConfigParser(config)
        parser.parse()
        parsed = parser.config
        del parser
        return parsed

    config = {}

    # get the file encoding this is important with multi-byte unicode chars
    encoding = check_output(
        ['file', '-b', '--mime-encoding', '--dereference', config_path])
    encoding = encoding.strip().decode('utf-8')
    with codecs.open(config_path, 'r', encoding) as f:
        try:
            config_info = parse_config(f)
        except ParseException as e:
            # There was a problem use our special error config
            error = e.one_line()
            notify_user(error)
            error_config = Template(ERROR_CONFIG).substitute(
                error=error.replace('"', '\\"'))
            config_info = parse_config(error_config)

    # update general section with defaults
    general_defaults = GENERAL_DEFAULTS.copy()
    if 'general' in config_info:
        general_defaults.update(config_info['general'])
    config['general'] = general_defaults

    config['py3status'] = config_info.get('py3status', {})
    modules = {}
    on_click = {}
    i3s_modules = []
    py3_modules = []
    module_groups = {}

    def process_onclick(key, value, group_name):
        '''
        Check on_click events are valid.  Store if they are good
        '''
        button_error = False
        button = ''
        try:
            button = key.split()[1]
            if int(button) not in range(1, 6):
                button_error = True
        except (ValueError, IndexError):
            button_error = True

        if button_error:
            err = 'Invalid on_click for `{}` should be 1, 2, 3, 4 or 5 saw `{}`'
            notify_user(err.format(group_name, button))
            return False
        clicks = on_click.setdefault(group_name, {})
        clicks[button] = value
        return True

    def get_module_type(name):
        '''
        i3status or py3status?
        '''
        if name.split()[0] in I3S_MODULE_NAMES:
            return 'i3status'
        return 'py3status'

    def process_module(name, module, parent):
        if parent:
            modules[parent]['items'].append(name)
            mg = module_groups.setdefault(name, [])
            mg.append(parent)
            if get_module_type(name) == 'py3status':
                module['.group'] = parent

        # check module content
        for k, v in list(module.items()):
            if k.startswith('on_click'):
                # on_click event
                process_onclick(k, v, name)
                # on_click should not be passed to the module via the config.
                del module[k]
            if isinstance(v, ModuleDefinition):
                # we are a container
                module['items'] = []
        return module

    def get_modules(data, parent=None):
        for k, v in data.items():
            if isinstance(v, ModuleDefinition):
                module = process_module(k, v, parent)
                modules[k] = module
                get_modules(v, parent=k)

    get_modules(config_info)

    config['order'] = []

    def remove_any_contained_modules(module):
        '''
        takes a module definition and returns a dict without any modules that
        may be defined with it.
        '''
        fixed = {}
        for k, v in module.items():
            if not isinstance(v, ModuleDefinition):
                fixed[k] = v
        return fixed

    def add_container_items(module_name):
        module = modules.get(module_name, {})
        items = module.get('items', [])
        for item in items:
            if item in config:
                continue
            module_type = get_module_type(item)
            if module_type == 'i3status':
                if item not in i3s_modules:
                    i3s_modules.append(item)
            else:
                if item not in py3_modules:
                    py3_modules.append(item)
            module = modules.get(item, {})
            config[item] = remove_any_contained_modules(module)
            # add any children
            add_container_items(item)

    # create config for modules in order
    for name in config_info.get('order', []):
        module = modules.get(name, {})
        module_type = get_module_type(name)
        config['order'].append(name)
        add_container_items(name)
        if module_type == 'i3status':
            if name not in i3s_modules:
                i3s_modules.append(name)
        else:
            if name not in py3_modules:
                py3_modules.append(name)
        config[name] = remove_any_contained_modules(module)

    config['on_click'] = on_click
    config['i3s_modules'] = i3s_modules
    config['py3_modules'] = py3_modules
    config['.module_groups'] = module_groups

    # time and tztime modules need a format for correct processing
    for name in config:
        if name.split()[0] in TIME_MODULES and 'format' not in config[name]:
            if name.split()[0] == 'time':
                config[name]['format'] = TIME_FORMAT
            else:
                config[name]['format'] = TZTIME_FORMAT

    if not config['order']:
        notify_user('Your configuration file does not list any module'
                    ' to be loaded with the "order" directive.')
    return config
Exemplo n.º 3
0
def process_config(config_path, py3_wrapper=None):
    """
    Parse i3status.conf so we can adapt our code to the i3status config.
    """

    def notify_user(error):
        if py3_wrapper:
            py3_wrapper.notify_user(error)
        else:
            print(error)

    def parse_config(config):
        """
        Parse text or file as a py3status config file.
        """

        if hasattr(config, "readlines"):
            config = "".join(config.readlines())
        parser = ConfigParser(config, py3_wrapper)
        parser.parse()
        parsed = parser.config
        del parser
        return parsed

    def parse_config_error(e, config_path):
        # There was a problem use our special error config
        error = e.one_line(config_path)
        notify_user(error)
        # to display correctly in i3bar we need to do some substitutions
        for char in ['"', "{", "|"]:
            error = error.replace(char, "\\" + char)
        error_config = Template(ERROR_CONFIG).substitute(error=error)
        return parse_config(error_config)

    config = {}

    # get the file encoding this is important with multi-byte unicode chars
    try:
        encoding = check_output(
            ["file", "-b", "--mime-encoding", "--dereference", config_path]
        )
        encoding = encoding.strip().decode("utf-8")
    except CalledProcessError:
        # bsd does not have the --mime-encoding so assume utf-8
        encoding = "utf-8"
    try:
        with codecs.open(config_path, "r", encoding) as f:
            try:
                config_info = parse_config(f)
            except ParseException as e:
                config_info = parse_config_error(e, config_path)
    except LookupError:
        with codecs.open(config_path) as f:
            try:
                config_info = parse_config(f)
            except ParseException as e:
                config_info = parse_config_error(e, config_path)

    # update general section with defaults
    general_defaults = GENERAL_DEFAULTS.copy()
    if "general" in config_info:
        general_defaults.update(config_info["general"])
    config["general"] = general_defaults

    config["py3status"] = config_info.get("py3status", {})
    modules = {}
    on_click = {}
    i3s_modules = []
    py3_modules = []
    module_groups = {}

    def process_onclick(key, value, group_name):
        """
        Check on_click events are valid.  Store if they are good
        """
        button_error = False
        button = ""
        try:
            button = key.split()[1]
            if int(button) not in range(1, 20):
                button_error = True
        except (ValueError, IndexError):
            button_error = True

        if button_error:
            err = "Invalid on_click for `{}`. Number not in range 1-20: `{}`."
            notify_user(err.format(group_name, button))
            return False
        clicks = on_click.setdefault(group_name, {})
        clicks[button] = value
        return True

    def get_module_type(name):
        """
        i3status or py3status?
        """
        if name.split()[0] in I3S_MODULE_NAMES:
            return "i3status"
        return "py3status"

    def process_module(name, module, parent):
        if parent:
            modules[parent]["items"].append(name)
            mg = module_groups.setdefault(name, [])
            mg.append(parent)
            if get_module_type(name) == "py3status":
                module[".group"] = parent

        # check module content
        for k, v in list(module.items()):
            if k.startswith("on_click"):
                # on_click event
                process_onclick(k, v, name)
                # on_click should not be passed to the module via the config.
                del module[k]
            if isinstance(v, ModuleDefinition):
                # we are a container
                module["items"] = []
        return module

    def get_modules(data, parent=None):
        for k, v in data.items():
            if isinstance(v, ModuleDefinition):
                module = process_module(k, v, parent)
                modules[k] = module
                get_modules(v, parent=k)

    get_modules(config_info)

    config["order"] = []

    def remove_any_contained_modules(module):
        """
        takes a module definition and returns a dict without any modules that
        may be defined with it.
        """
        fixed = {}
        for k, v in module.items():
            if not isinstance(v, ModuleDefinition):
                fixed[k] = v
        return fixed

    def append_modules(item):
        module_type = get_module_type(item)
        if module_type == "i3status":
            if item not in i3s_modules:
                i3s_modules.append(item)
        else:
            if item not in py3_modules:
                py3_modules.append(item)

    def add_container_items(module_name):
        module = modules.get(module_name, {})
        items = module.get("items", [])
        for item in items:
            if item in config:
                continue

            append_modules(item)
            module = modules.get(item, {})
            config[item] = remove_any_contained_modules(module)
            # add any children
            add_container_items(item)

    # create config for modules in order
    for name in config_info.get("order", []):
        if name in module_groups:
            msg = "Module `{}` should not be listed in the 'order' directive, use"
            msg += " its parent group instead."
            notify_user(msg.format(name))
            continue
        module_name = name.split(" ")[0]
        if module_name in RETIRED_MODULES:
            notify_user(
                "Module `{}` is no longer available".format(module_name)
                + ". Alternative modules are: {}.".format(
                    ", ".join("`{}`".format(x) for x in RETIRED_MODULES[module_name])
                )
            )
            continue
        module = modules.get(name, {})
        config["order"].append(name)
        add_container_items(name)
        append_modules(name)

        config[name] = remove_any_contained_modules(module)

    config["on_click"] = on_click
    config["i3s_modules"] = i3s_modules
    config["py3_modules"] = py3_modules
    config[".module_groups"] = module_groups

    # time and tztime modules need a format for correct processing
    for name in config:
        if name.split()[0] in TIME_MODULES and "format" not in config[name]:
            if name.split()[0] == "time":
                config[name]["format"] = TIME_FORMAT
            else:
                config[name]["format"] = TZTIME_FORMAT

    if not config["order"]:
        notify_user(
            "Your configuration file does not list any module"
            ' to be loaded with the "order" directive.'
        )
    return config
Exemplo n.º 4
0
def process_config(config_path, py3_wrapper=None):
    """
    Parse i3status.conf so we can adapt our code to the i3status config.
    """

    def notify_user(error):
        if py3_wrapper:
            py3_wrapper.notify_user(error)
        else:
            print(error)

    def parse_config(config):
        '''
        Parse text or file as a py3status config file.
        '''

        if hasattr(config, 'readlines'):
            config = ''.join(config.readlines())
        parser = ConfigParser(config)
        parser.parse()
        parsed = parser.config
        del parser
        return parsed

    config = {}

    # get the file encoding this is important with multi-byte unicode chars
    encoding = check_output(['file', '-b', '--mime-encoding', '--dereference', config_path])
    encoding = encoding.strip().decode('utf-8')
    with codecs.open(config_path, 'r', encoding) as f:
        try:
            config_info = parse_config(f)
        except ParseException as e:
            # There was a problem use our special error config
            error = e.one_line()
            notify_user(error)
            error_config = Template(ERROR_CONFIG).substitute(
                error=error.replace('"', '\\"'))
            config_info = parse_config(error_config)

    # update general section with defaults
    general_defaults = GENERAL_DEFAULTS.copy()
    if 'general' in config_info:
        general_defaults.update(config_info['general'])
    config['general'] = general_defaults

    config['py3status'] = config_info.get('py3status', {})
    modules = {}
    on_click = {}
    i3s_modules = []
    py3_modules = []
    module_groups = {}

    def process_onclick(key, value, group_name):
        '''
        Check on_click events are valid.  Store if they are good
        '''
        button_error = False
        button = ''
        try:
            button = key.split()[1]
            if int(button) not in range(1, 6):
                button_error = True
        except (ValueError, IndexError):
                button_error = True

        if button_error:
            err = 'Invalid on_click for `{}` should be 1, 2, 3, 4 or 5 saw `{}`'
            notify_user(err.format(group_name, button))
            return False
        clicks = on_click.setdefault(group_name, {})
        clicks[button] = value
        return True

    def get_module_type(name):
        '''
        i3status or py3status?
        '''
        if name.split()[0] in I3S_MODULE_NAMES:
            return 'i3status'
        return 'py3status'

    def process_module(name, module, parent):
        if parent:
            modules[parent]['items'].append(name)
            mg = module_groups.setdefault(name, [])
            mg.append(parent)
            if get_module_type(name) == 'py3status':
                module['.group'] = parent

        # check module content
        for k, v in list(module.items()):
            if k.startswith('on_click'):
                # on_click event
                process_onclick(k, v, name)
                # on_click should not be passed to the module via the config.
                del module[k]
            if isinstance(v, ModuleDefinition):
                # we are a container
                module['items'] = []
        return module

    def get_modules(data, parent=None):
        for k, v in data.items():
            if isinstance(v, ModuleDefinition):
                module = process_module(k, v, parent)
                modules[k] = module
                get_modules(v, parent=k)

    get_modules(config_info)

    config['order'] = []

    def remove_any_contained_modules(module):
        '''
        takes a module definition and returns a dict without any modules that
        may be defined with it.
        '''
        fixed = {}
        for k, v in module.items():
            if not isinstance(v, ModuleDefinition):
                fixed[k] = v
        return fixed

    def add_container_items(module_name):
        module = modules.get(module_name, {})
        items = module.get('items', [])
        for item in items:
            if item in config:
                continue
            module_type = get_module_type(item)
            if module_type == 'i3status':
                if item not in i3s_modules:
                    i3s_modules.append(item)
            else:
                if item not in py3_modules:
                    py3_modules.append(item)
            module = modules.get(item, {})
            config[item] = remove_any_contained_modules(module)
            # add any children
            add_container_items(item)

    # create config for modules in order
    for name in config_info.get('order', []):
        module = modules.get(name, {})
        module_type = get_module_type(name)
        config['order'].append(name)
        add_container_items(name)
        if module_type == 'i3status':
            if name not in i3s_modules:
                i3s_modules.append(name)
        else:
            if name not in py3_modules:
                py3_modules.append(name)
        config[name] = remove_any_contained_modules(module)

    config['on_click'] = on_click
    config['i3s_modules'] = i3s_modules
    config['py3_modules'] = py3_modules
    config['.module_groups'] = module_groups

    # time and tztime modules need a format for correct processing
    for name in config:
        if name.split()[0] in TIME_MODULES and 'format' not in config[name]:
            if name.split()[0] == 'time':
                config[name]['format'] = TIME_FORMAT
            else:
                config[name]['format'] = TZTIME_FORMAT

    if not config['order']:
        notify_user('Your configuration file does not list any module'
                    ' to be loaded with the "order" directive.')
    return config