summaryrefslogtreecommitdiff
path: root/scripts/ini_editor.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/ini_editor.py')
-rwxr-xr-xscripts/ini_editor.py628
1 files changed, 0 insertions, 628 deletions
diff --git a/scripts/ini_editor.py b/scripts/ini_editor.py
deleted file mode 100755
index aeeaefbd..00000000
--- a/scripts/ini_editor.py
+++ /dev/null
@@ -1,628 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-A script to modify dsp.ini config files.
-A dsp.ini config file is represented by an Ini object.
-An Ini object contains one or more Sections.
-Each Section has a name, a list of Ports, and a list of NonPorts.
-"""
-
-import argparse
-import logging
-import os
-import re
-import StringIO
-import sys
-from collections import namedtuple
-
-Parameter = namedtuple('Parameter', ['value', 'comment'])
-
-
-class Port(object):
- """Class for port definition in ini file.
-
- Properties:
- io: "input" or "output".
- index: an integer for port index.
- definition: a string for the content after "=" in port definition line.
- parameter: a Parameter namedtuple which is parsed from definition.
- """
- @staticmethod
- def ParsePortLine(line):
- """Parses a port definition line in ini file and init a Port object.
-
- Args:
- line: A string possibly containing port definition line like
- "input_0=1; something".
-
- Returns:
- A Port object if input is a valid port definition line. Returns
- None if input is not a valid port definition line.
- """
- result = re.match(r'(input|output)_(\d+)=(.*)', line)
- if result:
- parse_values = result.groups()
- io = parse_values[0]
- index = int(parse_values[1])
- definition = parse_values[2]
- return Port(io, index, definition)
- else:
- return None
-
- def __init__(self, io, index, definition):
- """Initializes a port.
-
- Initializes a port with io, index and definition. The definition will be
- further parsed to Parameter(value, comment) if the format matches
- "<some value> ; <some comment>".
-
- Args:
- io: "input" or "output".
- index: an integer for port index.
- definition: a string for the content after "=" in port definition line.
- """
- self.io = io
- self.index = index
- self.definition = definition
- result = re.match(r'(\S+)\s+; (.+)', definition)
- if result:
- self.parameter = Parameter._make(result.groups())
- else:
- self.parameter = None
-
- def FormatLine(self):
- """Returns a port definition line which is used in ini file."""
- line = '%s_%d=' % (self.io, self.index)
- if self.parameter:
- line +="{:<8}; {:}".format(self.parameter.value, self.parameter.comment)
- else:
- line += self.definition
- return line
-
- def _UpdateIndex(self, index):
- """Updates index of this port.
-
- Args:
- index: The new index.
- """
- self.index = index
-
-
-class NonPort(object):
- """Class for non-port definition in ini file.
-
- Properties:
- name: A string representing the non-port name.
- definition: A string representing the non-port definition.
- """
- @staticmethod
- def ParseNonPortLine(line):
- """Parses a non-port definition line in ini file and init a NonPort object.
-
- Args:
- line: A string possibly containing non-port definition line like
- "library=builtin".
-
- Returns:
- A NonPort object if input is a valid non-port definition line. Returns
- None if input is not a valid non-port definition line.
- """
- result = re.match(r'(\w+)=(.*)', line)
- if result:
- parse_values = result.groups()
- name = parse_values[0]
- definition = parse_values[1]
- return NonPort(name, definition)
- else:
- return None
-
- def __init__(self, name, definition):
- """Initializes a NonPort <name>=<definition>.
-
- Args:
- name: A string representing the non-port name.
- definition: A string representing the non-port definition.
- """
- self.name = name
- self.definition = definition
-
- def FormatLine(self):
- """Formats a string representation of a NonPort.
-
- Returns:
- A string "<name>=<definition>".
- """
- line = '%s=%s' % (self.name, self.definition)
- return line
-
-
-class SectionException(Exception):
- pass
-
-
-class Section(object):
- """Class for section definition in ini file.
-
- Properties:
- name: Section name.
- non_ports: A list containing NonPorts of this section.
- ports: A list containing Ports of this section.
- """
- @staticmethod
- def ParseSectionName(line):
- """Parses a section name.
-
- Args:
- line: A string possibly containing a section name like [drc].
-
- Returns:
- Returns parsed section name without '[' and ']' if input matches
- the syntax [<section name>]. Returns None if not.
- """
- result = re.match(r'\[(\w+)\]', line)
- return result.groups()[0] if result else None
-
- @staticmethod
- def ParseLine(line):
- """Parses a line that belongs to a section.
-
- Returns:
- A Port or NonPort object if input line matches the format. Returns None
- if input line does not match the format of Port nor NonPort.
- """
- if not line:
- return
- parse_port = Port.ParsePortLine(line)
- if parse_port:
- return parse_port
- parse_non_port = NonPort.ParseNonPortLine(line)
- if parse_non_port:
- return parse_non_port
-
- def __init__(self, name):
- """Initializes a Section with given name."""
- self.name = name
- self.non_ports= []
- self.ports = []
-
- def AddLine(self, line):
- """Adds a line to this Section.
-
- Args:
- line: A line to be added to this section. If it matches port or non-port
- format, a Port or NonPort will be added to this section. Otherwise,
- this line is ignored.
- """
- to_add = Section.ParseLine(line)
- if not to_add:
- return
- if isinstance(to_add, Port):
- self.AppendPort(to_add)
- return
- if isinstance(to_add, NonPort):
- self.AppendNonPort(to_add)
- return
-
- def AppendNonPort(self, non_port):
- """Appends a NonPort to non_ports.
-
- Args:
- non_port: A NonPort object to be appended.
- """
- self.non_ports.append(non_port)
-
- def AppendPort(self, port):
- """Appends a Port to ports.
-
- Args:
- port: A Port object to be appended. The port should be appended
- in the order of index, so the index of port should equal to the current
- size of ports list.
-
- Raises:
- SectionException if the index of port is not the current size of ports
- list.
- """
- if not port.index == len(self.ports):
- raise SectionException(
- 'The port with index %r can not be appended to the end of ports'
- ' of size' % (port.index, len(self.ports)))
- else:
- self.ports.append(port)
-
- def InsertLine(self, line):
- """Inserts a line to this section.
-
- Inserts a line containing port or non-port definition to this section.
- If input line matches Port or NonPort format, the corresponding insert
- method InsertNonPort or InsertPort will be called. If input line does not
- match the format, SectionException will be raised.
-
- Args:
- line: A line to be inserted. The line should
-
- Raises:
- SectionException if input line does not match the format of Port or
- NonPort.
- """
- to_insert = Section.ParseLine(line)
- if not to_insert:
- raise SectionException(
- 'The line %s does not match Port or NonPort syntax' % line)
- if isinstance(to_insert, Port):
- self.InsertPort(to_insert)
- return
- if isinstance(to_insert, NonPort):
- self.InsertNonPort(to_insert)
- return
-
- def InsertNonPort(self, non_port):
- """Inserts a NonPort to non_ports list.
-
- Currently there is no ordering for non-port definition. This method just
- appends non_port to non_ports list.
-
- Args:
- non_port: A NonPort object.
- """
- self.non_ports.append(non_port)
-
- def InsertPort(self, port):
- """Inserts a Port to ports list.
-
- The index of port should not be greater than the current size of ports.
- After insertion, the index of each port in ports should be updated to the
- new index of that port in the ports list.
- E.g. Before insertion:
- self.ports=[Port("input", 0, "foo0"),
- Port("input", 1, "foo1"),
- Port("output", 2, "foo2")]
- Now we insert a Port with index 1 by invoking
- InsertPort(Port("output, 1, "bar")),
- Then,
- self.ports=[Port("input", 0, "foo0"),
- Port("output, 1, "bar"),
- Port("input", 2, "foo1"),
- Port("output", 3, "foo2")].
- Note that the indices of foo1 and foo2 had been shifted by one because a
- new port was inserted at index 1.
-
- Args:
- port: A Port object.
-
- Raises:
- SectionException: If the port to be inserted does not have a valid index.
- """
- if port.index > len(self.ports):
- raise SectionException('Inserting port index %d but'
- ' currently there are only %d ports' % (port.index,
- len(self.ports)))
-
- self.ports.insert(port.index, port)
- self._UpdatePorts()
-
- def _UpdatePorts(self):
- """Updates the index property of each Port in ports.
-
- Updates the index property of each Port in ports so the new index property
- is the index of that Port in ports list.
- """
- for index, port in enumerate(self.ports):
- port._UpdateIndex(index)
-
- def Print(self, output):
- """Prints the section definition to output.
-
- The format is:
- [section_name]
- non_port_name_0=non_port_definition_0
- non_port_name_1=non_port_definition_1
- ...
- port_name_0=port_definition_0
- port_name_1=port_definition_1
- ...
-
- Args:
- output: A StringIO.StringIO object.
- """
- output.write('[%s]\n' % self.name)
- for non_port in self.non_ports:
- output.write('%s\n' % non_port.FormatLine())
- for port in self.ports:
- output.write('%s\n' % port.FormatLine())
-
-
-class Ini(object):
- """Class for an ini config file.
-
- Properties:
- sections: A dict containing mapping from section name to Section.
- section_names: A list of section names.
- file_path: The path of this ini config file.
- """
- def __init__(self, input_file):
- """Initializes an Ini object from input config file.
-
- Args:
- input_file: The path to an ini config file.
- """
- self.sections = {}
- self.section_names = []
- self.file_path = input_file
- self._ParseFromFile(input_file)
-
- def _ParseFromFile(self, input_file):
- """Parses sections in the input config file.
-
- Reads in the content of the input config file and parses each sections.
- The parsed sections are stored in sections dict.
- The names of each section is stored in section_names list.
-
- Args:
- input_file: The path to an ini config file.
- """
- content = open(input_file, 'r').read()
- content_lines = content.splitlines()
- self.sections = {}
- self.section_names = []
- current_name = None
- for line in content_lines:
- name = Section.ParseSectionName(line)
- if name:
- self.section_names.append(name)
- self.sections[name] = Section(name)
- current_name = name
- else:
- self.sections[current_name].AddLine(line)
-
- def Print(self, output_file=None):
- """Prints all sections of this Ini object.
-
- Args:
- output_file: The path to write output. If this is not None, writes the
- output to this path. Otherwise, just print the output to console.
-
- Returns:
- A StringIO.StringIO object containing output.
- """
- output = StringIO.StringIO()
- for index, name in enumerate(self.section_names):
- self.sections[name].Print(output)
- if index < len(self.section_names) - 1:
- output.write('\n')
- if output_file:
- with open(output_file, 'w') as f:
- f.write(output.getvalue())
- output.close()
- else:
- print output.getvalue()
- return output
-
- def HasSection(self, name):
- """Checks if this Ini object has a section with certain name.
-
- Args:
- name: The name of the section.
- """
- return name in self.sections
-
- def PrintSection(self, name):
- """Prints a section to console.
-
- Args:
- name: The name of the section.
-
- Returns:
- A StringIO.StringIO object containing output.
- """
- output = StringIO.StringIO()
- self.sections[name].Print(output)
- output.write('\n')
- print output.getvalue()
- return output
-
- def InsertLineToSection(self, name, line):
- """Inserts a line to a section.
-
- Args:
- name: The name of the section.
- line: A line to be inserted.
- """
- self.sections[name].InsertLine(line)
-
-
-def prompt(question, binary_answer=True):
- """Displays the question to the user and wait for input.
-
- Args:
- question: The question to be displayed to user.
- binary_answer: True to expect an yes/no answer from user.
- Returns:
- True/False if binary_answer is True. Otherwise, returns a string
- containing user input to the question.
- """
-
- sys.stdout.write(question)
- answer = raw_input()
- if binary_answer:
- answer = answer.lower()
- if answer in ['y', 'yes']:
- return True
- elif answer in ['n', 'no']:
- return False
- else:
- return prompt(question)
- else:
- return answer
-
-
-class IniEditorException(Exception):
- pass
-
-
-class IniEditor(object):
- """The class for ini file editing command line interface.
-
- Properties:
- input_files: The files to be edited. Note that the same editing command
- can be applied on many config files.
- args: The result of ArgumentParser.parse_args method. It is an object
- containing args as attributes.
- """
- def __init__(self):
- self.input_files = []
- self.args = None
-
- def Main(self):
- """The main method of IniEditor.
-
- Parses the arguments and processes files according to the arguments.
- """
- self.ParseArgs()
- self.ProcessFiles()
-
- def ParseArgs(self):
- """Parses the arguments from command line.
-
- Parses the arguments from command line to determine input_files.
- Also, checks the arguments are valid.
-
- Raises:
- IniEditorException if arguments are not valid.
- """
- parser = argparse.ArgumentParser(
- description=('Edit or show the config files'))
- parser.add_argument('--input_file', '-i', default=None,
- help='Use the specified file as input file. If this '
- 'is not given, the editor will try to find config '
- 'files using config_dirs and board.')
- parser.add_argument('--config_dirs', '-c',
- default='~/trunk/src/third_party/adhd/cras-config',
- help='Config directory. By default it is '
- '~/trunk/src/third_party/adhd/cras-config.')
- parser.add_argument('--board', '-b', default=None, nargs='*',
- help='The boards to apply the changes. Use "all" '
- 'to apply on all boards. '
- 'Use --board <board_1> <board_2> to specify more '
- 'than one boards')
- parser.add_argument('--section', '-s', default=None,
- help='The section to be shown/edited in the ini file.')
- parser.add_argument('--insert', '-n', default=None,
- help='The line to be inserted into the ini file. '
- 'Must be used with --section.')
- parser.add_argument('--output-suffix', '-o', default='.new',
- help='The output file suffix. Set it to "None" if you '
- 'want to apply the changes in-place.')
- self.args = parser.parse_args()
-
- # If input file is given, just edit this file.
- if self.args.input_file:
- self.input_files.append(self.args.input_file)
- # Otherwise, try to find config files in board directories of config
- # directory.
- else:
- if self.args.config_dirs.startswith('~'):
- self.args.config_dirs = os.path.join(
- os.path.expanduser('~'),
- self.args.config_dirs.split('~/')[1])
- all_boards = os.walk(self.args.config_dirs).next()[1]
- # "board" argument must be a valid board name or "all".
- if (not self.args.board or
- (self.args.board != ['all'] and
- not set(self.args.board).issubset(set(all_boards)))):
- logging.error('Please select a board from %s or use "all".' % (
- ', '.join(all_boards)))
- raise IniEditorException('User must specify board if input_file '
- 'is not given.')
- if self.args.board == ['all']:
- logging.info('Applying on all boards.')
- boards = all_boards
- else:
- boards = self.args.board
-
- self.input_files = []
- # Finds dsp.ini files in candidate boards directories.
- for board in boards:
- ini_file = os.path.join(self.args.config_dirs, board, 'dsp.ini')
- if os.path.exists(ini_file):
- self.input_files.append(ini_file)
-
- if self.args.insert and not self.args.section:
- raise IniEditorException('--insert must be used with --section')
-
- def ProcessFiles(self):
- """Processes the config files in input_files.
-
- Showes or edits every selected config file.
- """
- for input_file in self.input_files:
- logging.info('Looking at dsp.ini file at %s', input_file)
- ini = Ini(input_file)
- if self.args.insert:
- self.InsertCommand(ini)
- else:
- self.PrintCommand(ini)
-
- def PrintCommand(self, ini):
- """Prints this Ini object.
-
- Prints all sections or a section in input Ini object if
- args.section is specified and there is such section in this Ini object.
-
- Args:
- ini: An Ini object.
- """
- if self.args.section:
- if ini.HasSection(self.args.section):
- logging.info('Printing section %s.', self.args.section)
- ini.PrintSection(self.args.section)
- else:
- logging.info('There is no section %s in %s',
- self.args.section, ini.file_path)
- else:
- logging.info('Printing ini content.')
- ini.Print()
-
- def InsertCommand(self, ini):
- """Processes insertion editing on Ini object.
-
- Inserts args.insert to section named args.section in input Ini object.
- If input Ini object does not have a section named args.section, this method
- does not do anything. If the editing is valid, prints the changed section
- to console. Writes the editied config file to the same path as input path
- plus a suffix speficied in args.output_suffix. If that suffix is "None",
- prompts and waits for user to confirm editing in-place.
-
- Args:
- ini: An Ini object.
- """
- if not ini.HasSection(self.args.section):
- logging.info('There is no section %s in %s',
- self.args.section, ini.file_path)
- return
-
- ini.InsertLineToSection(self.args.section, self.args.insert)
- logging.info('Changed section:')
- ini.PrintSection(self.args.section)
-
- if self.args.output_suffix == 'None':
- answer = prompt(
- 'Writing output file in-place at %s ? [y/n]' % ini.file_path)
- if not answer:
- sys.exit('Abort!')
- output_file = ini.file_path
- else:
- output_file = ini.file_path + self.args.output_suffix
- logging.info('Writing output file to : %s.', output_file)
- ini.Print(output_file)
-
-
-if __name__ == '__main__':
- logging.basicConfig(
- format='%(asctime)s:%(levelname)s:%(filename)s:%(lineno)d:%(message)s',
- level=logging.DEBUG)
- IniEditor().Main()