Implement a config parser

Information

ID: 661
PHID: PHID-TASK-7w6xmwr5qkkajazooty3
Author: dau
Status at Migration Time: open
Priority at Migration Time: Normal

Description

The [[ proposals/635-listen-port-convention.txt at master · Kicksecure/proposals · GitHub | Listen Port Convention proposal ]] depends on the parsing of specific files within specific directories. A config parser with the following features should be implemented:

  • Provide a Python package
  • Provide a command-line interface for non-Python apps
  • Provide json and eval serializers
  • Allow different parts of it to be customized

I will create a repo and post it here once I start working on this. Here is the initial code:

import argparse


class Parser:
    @classmethod
    def parse_global(cls, filepath):
        """Read `filepath`, parse it and return all directory paths found.

        The directories in the list are in the order they are intended to be
        read.
        """

    @classmethod
    def is_config_file(cls, filename):
        """Return `True` if `filename` is a config file. `False` otherwise."""

    @classmethod
    def find_config_files(cls, dirpath):
        """Walk through the directory and return all file paths found.

        Depending on `is_config_file`, each file is prepended by the
        directory's path and added to the list. The files in the list are in
        the order they are intended to be read.
        """

    @classmethod
    def parse_file(cls, filepath, configs=None):
        """Read `filepath`, parse it and return a `config: value` dict.

        If no configs are provided, a new dict is created. As the file is read,
        values are added to the configs with
        `add_config(configs, config, value)`."""

    @classmethod
    def add_config(cls, configs, config, value):
        """Add `config: value` to the configs dict and return it.

        In case the config did not exist, it is added to the dict. Otherwise,
        it replaces or merges to the existing one.
        """

    @classmethod
    def parse(cls, name):
        """Read the name of the config and return a `config: value` dict.

        The name defaults to a `/etc/<name>.conf` file path but can optionally
        specify a different path and extension. Its format should be something
        like `[/custom/path/]name[.custom]`.
        """
        cfgs = dict()

        for dirpath in cls.parse_global(name):
            for filepath in cls.find_config_files(dirpath):
                cfgs = cls.parse_file(filepath, cfgs)

        return cfgs

    @classmethod
    def serialize(cls, configs):
        """Serialize the configs dict into a convenient format."""

    @classmethod
    def parse_to_serialized(cls, name):
        """Parse configs and return them serialized."""
        return cls.serialize(cls.parse(name))


def call_parse():
    """Read a config name and print the serialized configs.

    This function should be accessed through an entry point. The name is passed
    via a command-line call and returns the configs in a format that
    applications are able to read in the language they use.
    """
    argparser = argparse.ArgumentParser()
    argparser.add_argument('name')
    args = argparser.parse_args()

    print Parser.parse_to_serialized(args.name)

A Python app would use the parser to retrieve the listen_ip config of the listen convention with the following code:

import Parser

cfgs = Parser.parse('listen')
listen_ip = cfgs['listen_ip']

# bind on `listen_ip`

A non-Python app would receive the serialized configs with the following call:

$ configparser listen

P.S. We need a good name for this.


This is a follow-up ticket to T635

Comments