more work on parsing

This commit is contained in:
Radovan Bast 2016-05-19 18:46:12 +02:00
parent 24ff4c430e
commit 90b89354db
4 changed files with 125 additions and 87 deletions

View File

@ -12,3 +12,35 @@ def extract_list(config, section):
else: else:
l.append(x[section]) l.append(x[section])
return l return l
def to_d(l):
"""
Converts list of dicts to dict.
"""
_d = {}
for x in l:
for k, v in x.items():
_d[k] = v
return _d
def test_to_d():
l = [{'a': 'b'}, {'c': 'd'}]
d = {'a': 'b', 'c': 'd'}
assert to_d(l) == d
def to_l(x):
"""
Converts list of dicts to dict.
"""
if isinstance(x, str):
return [x]
else:
return x
def test_to_l():
assert to_l('foo') == ['foo']
assert to_l(['foo', 'bar']) == ['foo', 'bar']

View File

@ -1,4 +1,4 @@
def parse_cmake_module(s_in, override={}): def parse_cmake_module(s_in, overrides={}):
import sys import sys
from collections import Mapping, Iterable, defaultdict from collections import Mapping, Iterable, defaultdict
from autocmake.parse_yaml import parse_yaml from autocmake.parse_yaml import parse_yaml
@ -33,7 +33,7 @@ def parse_cmake_module(s_in, override={}):
autocmake_entry = autocmake_entry.replace('\n ', '\n') autocmake_entry = autocmake_entry.replace('\n ', '\n')
buf = StringIO(autocmake_entry) buf = StringIO(autocmake_entry)
config = parse_yaml(buf, override) config = parse_yaml(buf, overrides)
for k, v in config.items(): for k, v in config.items():
if isinstance(v, Iterable) and not isinstance(v, str): if isinstance(v, Iterable) and not isinstance(v, str):
@ -109,7 +109,7 @@ enable_language(CXX)'''
assert parsed_config['c'] == ['v3'] assert parsed_config['c'] == ['v3']
def test_parse_cmake_module_override(): def test_parse_cmake_module_overrides():
s = r'''#.rst: s = r'''#.rst:
# #

View File

@ -1,4 +1,4 @@
def parse_yaml(stream, override={}): def parse_yaml(stream, overrides={}):
import yaml import yaml
import sys import sys
from autocmake.interpolate import interpolate from autocmake.interpolate import interpolate
@ -10,8 +10,8 @@ def parse_yaml(stream, override={}):
sys.exit(-1) sys.exit(-1)
for k in config: for k in config:
if k in override: if k in overrides:
config[k] = override[k] config[k] = overrides[k]
config = interpolate(config, config) config = interpolate(config, config)
return config return config

168
update.py
View File

@ -11,110 +11,99 @@ def print_progress_bar(text, done, total, width):
""" """
Print progress bar. Print progress bar.
""" """
n = int(float(width) * float(done) / float(total)) if total > 0:
sys.stdout.write("\r{0} [{1}{2}] ({3}/{4})".format(text, '#' * n, ' ' * (width - n), done, total)) n = int(float(width) * float(done) / float(total))
sys.stdout.flush() sys.stdout.write("\r{0} [{1}{2}] ({3}/{4})".format(text, '#' * n, ' ' * (width - n), done, total))
sys.stdout.flush()
def prepend_or_set(config, section, option, value, defaults): def flat_add(l, x):
""" if isinstance(x, str):
If option is already set, then value is prepended. l.append(x)
If option is not set, then it is created and set to value. return l
This is used to prepend options with values which come from the module documentation. else:
""" return l + x
if value:
if config.has_option(section, option):
value += '\n{0}'.format(config.get(section, option, 0, defaults))
config.set(section, option, value)
return config
def fetch_modules(config, relative_path): def fetch_modules(config, relative_path, download_directory):
""" """
Assemble modules which will Assemble modules which will
be included in CMakeLists.txt. be included in CMakeLists.txt.
""" """
from collections import Iterable, namedtuple from collections import Iterable, namedtuple, defaultdict
from autocmake.extract import extract_list from autocmake.extract import extract_list, to_d, to_l
from autocmake.parse_rst import parse_cmake_module
download_directory = 'downloaded' cleaned_config = defaultdict(lambda: [])
if not os.path.exists(download_directory):
os.makedirs(download_directory)
# here we get the list of sources to fetch
sources = extract_list(config, 'source')
modules = [] modules = []
Module = namedtuple('Module', 'path name') Module = namedtuple('Module', 'path name')
warnings = [] num_sources = len(extract_list(config, 'source'))
if len(sources) > 0: # otherwise division by zero in print_progress_bar print_progress_bar(text='- assembling modules:',
print_progress_bar(text='- assembling modules:', done=0, total=len(sources), width=30) done=0,
for i, src in enumerate(sources): total=num_sources,
module_name = os.path.basename(src) width=30)
if 'http' in src:
path = download_directory i = 0
name = 'autocmake_{0}'.format(module_name) for t in config['modules']:
dst = os.path.join(download_directory, 'autocmake_{0}'.format(module_name)) for k, v in t.items():
fetch_url(src, dst)
file_name = dst i += 1
fetch_dst_directory = download_directory d = to_d(v)
else: for _k, _v in to_d(v).items():
if os.path.exists(src): cleaned_config[_k] = flat_add(cleaned_config[_k], _v)
path = os.path.dirname(src)
name = module_name # fetch sources and parse them
file_name = src for src in to_l(d['source']):
fetch_dst_directory = path
# we download the file
module_name = os.path.basename(src)
if 'http' in src:
path = download_directory
name = 'autocmake_{0}'.format(module_name)
dst = os.path.join(download_directory, 'autocmake_{0}'.format(module_name))
fetch_url(src, dst)
file_name = dst
fetch_dst_directory = download_directory
else: else:
sys.stderr.write("ERROR: {0} does not exist\n".format(src)) if os.path.exists(src):
sys.exit(-1) path = os.path.dirname(src)
name = module_name
file_name = src
fetch_dst_directory = path
else:
sys.stderr.write("ERROR: {0} does not exist\n".format(src))
sys.exit(-1)
# FIXME # we infer config from the module documentation
# if config.has_option(section, 'override'): # dictionary d overrides the configuration in the module documentation
# defaults = ast.literal_eval(config.get(section, 'override')) # this allows to override interpolation inside the module
# else: with open(file_name, 'r') as f:
# defaults = {} parsed_config = parse_cmake_module(f.read(), d)
for _k2, _v2 in parsed_config.items():
if _k2 not in to_d(v):
# we add to clean_config only if the entry does not exist
# in parent autocmake.yml already
# this allows to override
cleaned_config[_k2] = flat_add(cleaned_config[_k2], _v2)
# FIXME modules.append(Module(path=path, name=name))
# # we infer config from the module documentation print_progress_bar(text='- assembling modules:',
# with open(file_name, 'r') as f: done=i,
# parsed_config = parse_cmake_module(f.read(), defaults) total=num_sources,
# if parsed_config['warning']: width=30)
# warnings.append('WARNING from {0}: {1}'.format(module_name, parsed_config['warning']))
# config = prepend_or_set(config, section, 'docopt', parsed_config['docopt'], defaults)
# config = prepend_or_set(config, section, 'define', parsed_config['define'], defaults)
# config = prepend_or_set(config, section, 'export', parsed_config['export'], defaults)
# if parsed_config['fetch']:
# for src in parsed_config['fetch'].split('\n'):
# dst = os.path.join(fetch_dst_directory, os.path.basename(src))
# fetch_url(src, dst)
modules.append(Module(path=path, name=name)) print('')
print_progress_bar(
text='- assembling modules:',
done=(i + 1),
total=len(sources),
width=30
)
# FIXME
# if config.has_option(section, 'fetch'):
# # when we fetch directly from autocmake.yml
# # we download into downloaded/
# for src in config.get(section, 'fetch').split('\n'):
# dst = os.path.join(download_directory, os.path.basename(src))
# fetch_url(src, dst)
print('')
if warnings != []: return modules, cleaned_config
print('- {0}'.format('\n- '.join(warnings)))
return modules
def process_yaml(argv): def process_yaml(argv):
from autocmake.parse_yaml import parse_yaml from autocmake.parse_yaml import parse_yaml
from autocmake.generate import gen_cmakelists, gen_setup from autocmake.generate import gen_cmakelists, gen_setup
from autocmake.extract import extract_list
project_root = argv[1] project_root = argv[1]
if not os.path.isdir(project_root): if not os.path.isdir(project_root):
@ -149,8 +138,25 @@ def process_yaml(argv):
# get relative path from setup script to this directory # get relative path from setup script to this directory
relative_path = os.path.relpath(os.path.abspath('.'), project_root) relative_path = os.path.relpath(os.path.abspath('.'), project_root)
download_directory = 'downloaded'
if not os.path.exists(download_directory):
os.makedirs(download_directory)
# fetch modules from the web or from relative paths # fetch modules from the web or from relative paths
modules = fetch_modules(config, relative_path) modules, cleaned_config = fetch_modules(config, relative_path, download_directory)
# FIXME
# for k, v in cleaned_config.items():
# print(k, v)
# fetch files which are not parsed
for src in extract_list(config, 'fetch'):
dst = os.path.join(download_directory, os.path.basename(src))
fetch_url(src, dst)
# print warnings
for warning in extract_list(config, 'warning'):
print('- WARNING: {0}'.format(warning))
# create CMakeLists.txt # create CMakeLists.txt
print('- generating CMakeLists.txt') print('- generating CMakeLists.txt')