blob: 0c0e8bfd7412c7f17b24a982333045f2303dd42f [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2019 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.
"""Common python commands used by various build scripts."""
from __future__ import print_function
import contextlib
import errno
import six
@contextlib.contextmanager
def _Open(obj, mode='r'):
"""Convenience ctx that accepts a file path or an already open file object."""
if isinstance(obj, six.string_types):
with open(obj, mode=mode) as f:
yield f
else:
yield obj
def LoadData(data, multiline=False, source='<data>'):
"""Turn key=value content into a dict
Note: If you're designing a new data store, please use json rather than
this format. This func is designed to work with legacy/external files
where json isn't an option.
Only UTF-8 content is supported currently.
Args:
data: The data to parse.
multiline: Allow a value enclosed by quotes to span multiple lines.
source: Helpful string for users to diagnose source of errors.
Returns:
a dict of all the key=value pairs found in the file.
"""
d = {}
key = None
in_quotes = None
for raw_line in data.splitlines(True):
line = raw_line.split('#')[0]
if not line.strip():
continue
# Continue processing a multiline value.
if multiline and in_quotes and key:
if line.rstrip()[-1] == in_quotes:
# Wrap up the multiline value if the line ends with a quote.
d[key] += line.rstrip()[:-1]
in_quotes = None
else:
d[key] += line
continue
chunks = line.split('=', 1)
if len(chunks) != 2:
raise ValueError('Malformed key=value file %r; line %r'
% (source, raw_line))
key = chunks[0].strip()
val = chunks[1].strip()
if len(val) >= 2 and val[0] in '"\'' and val[0] == val[-1]:
# Strip matching quotes on the same line.
val = val[1:-1]
elif val and multiline and val[0] in '"\'':
# Unmatched quote here indicates a multiline value. Do not
# strip the '\n' at the end of the line.
in_quotes = val[0]
val = chunks[1].lstrip()[1:]
d[key] = val
return d
def LoadFile(obj, ignore_missing=False, multiline=False):
"""Turn a key=value file into a dict
Note: If you're designing a new data store, please use json rather than
this format. This func is designed to work with legacy/external files
where json isn't an option.
Only UTF-8 content is supported currently.
Args:
obj: The file to read. Can be a path or an open file object.
ignore_missing: If the file does not exist, return an empty dict.
multiline: Allow a value enclosed by quotes to span multiple lines.
Returns:
a dict of all the key=value pairs found in the file.
"""
try:
with _Open(obj) as f:
return LoadData(f.read(), multiline=multiline, source=obj)
except EnvironmentError as e:
if not (ignore_missing and e.errno == errno.ENOENT):
raise
return {}