more structure
This commit is contained in:
		
							
								
								
									
										28
									
								
								autocmake/http.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								autocmake/http.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| def fetch_url(src, dst): | ||||
|     """ | ||||
|     Fetch file from URL src and save it to dst. | ||||
|     """ | ||||
|     # we do not use the nicer sys.version_info.major | ||||
|     # for compatibility with Python < 2.7 | ||||
|     if sys.version_info[0] > 2: | ||||
|         import urllib.request | ||||
|  | ||||
|         class URLopener(urllib.request.FancyURLopener): | ||||
|             def http_error_default(self, url, fp, errcode, errmsg, headers): | ||||
|                 sys.stderr.write("ERROR: could not fetch {0}\n".format(url)) | ||||
|                 sys.exit(-1) | ||||
|     else: | ||||
|         import urllib | ||||
|  | ||||
|         class URLopener(urllib.FancyURLopener): | ||||
|             def http_error_default(self, url, fp, errcode, errmsg, headers): | ||||
|                 sys.stderr.write("ERROR: could not fetch {0}\n".format(url)) | ||||
|                 sys.exit(-1) | ||||
|  | ||||
|     dirname = os.path.dirname(dst) | ||||
|     if dirname != '': | ||||
|         if not os.path.isdir(dirname): | ||||
|             os.makedirs(dirname) | ||||
|  | ||||
|     opener = URLopener() | ||||
|     opener.retrieve(src, dst) | ||||
							
								
								
									
										47
									
								
								autocmake/interpolate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								autocmake/interpolate.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| def replace(s, d): | ||||
|     from re import findall | ||||
|     if isinstance(s, str): | ||||
|         for var in findall(r"%\(([A-Za-z0-9_]*)\)", s): | ||||
|             s = s.replace("%({})".format(var), str(d[var])) | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def test_replace(): | ||||
|     assert replace('hey %(foo) ho %(bar)', | ||||
|                    {'foo': 'hey', 'bar': 'ho'}) == 'hey hey ho ho' | ||||
|  | ||||
|  | ||||
| def interpolate(d, d_map): | ||||
|     from collections import Mapping, Iterable | ||||
|     from copy import copy | ||||
|     for k, v in d.items(): | ||||
|         if isinstance(v, Mapping): | ||||
|             d[k] = interpolate(d[k], d_map) | ||||
|         elif isinstance(v, Iterable) and not isinstance(v, str): | ||||
|             l = [] | ||||
|             for x in v: | ||||
|                 if isinstance(x, Mapping): | ||||
|                     l.append(interpolate(x, d_map)) | ||||
|                 else: | ||||
|                     l.append(replace(x, d_map)) | ||||
|             d[k] = copy(l) | ||||
|         else: | ||||
|             d[k] = replace(d[k], d_map) | ||||
|     return d | ||||
|  | ||||
|  | ||||
| def test_interpolate(): | ||||
|     d = {'foo': 'hey', | ||||
|          'bar': 'ho', | ||||
|          'one': 'hey %(foo) ho %(bar)', | ||||
|          'two': {'one': 'hey %(foo) ho %(bar)', | ||||
|                  'two': 'raboof'}} | ||||
|     d_interpolated = {'foo': 'hey', | ||||
|                       'bar': 'ho', | ||||
|                       'one': 'hey hey ho ho', | ||||
|                       'two': {'one': 'hey hey ho ho', | ||||
|                               'two': 'raboof'}} | ||||
|     assert interpolate(d, d) == d_interpolated | ||||
|     d2 = {'modules': [{'fc': [{'source': '%(url_root)fc_optional.cmake'}]}], 'url_root': 'downloaded/downloaded_'} | ||||
|     d2_interpolated = {'modules': [{'fc': [{'source': 'downloaded/downloaded_fc_optional.cmake'}]}], 'url_root': 'downloaded/downloaded_'} | ||||
|     assert interpolate(d2, d2) == d2_interpolated | ||||
							
								
								
									
										133
									
								
								autocmake/parse_rst.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								autocmake/parse_rst.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| def parse_cmake_module(s_in, override={}): | ||||
|     import sys | ||||
|     from collections import Mapping, Iterable, defaultdict | ||||
|     from autocmake.parse_yaml import parse_yaml | ||||
|  | ||||
|     # we do not use the nicer sys.version_info.major | ||||
|     # for compatibility with Python < 2.7 | ||||
|     if sys.version_info[0] > 2: | ||||
|         from io import StringIO | ||||
|     else: | ||||
|         from StringIO import StringIO | ||||
|  | ||||
|     parsed_config = defaultdict(lambda: None) | ||||
|  | ||||
|     if 'autocmake.yml configuration::' not in s_in: | ||||
|         return parsed_config | ||||
|  | ||||
|     s_out = [] | ||||
|     is_rst_line = False | ||||
|     for line in s_in.split('\n'): | ||||
|         if is_rst_line: | ||||
|             if len(line) > 0: | ||||
|                 if line[0] != '#': | ||||
|                     is_rst_line = False | ||||
|             else: | ||||
|                 is_rst_line = False | ||||
|         if is_rst_line: | ||||
|             s_out.append(line[2:]) | ||||
|         if '#.rst:' in line: | ||||
|             is_rst_line = True | ||||
|  | ||||
|     autocmake_entry = '\n'.join(s_out).split('autocmake.yml configuration::')[1] | ||||
|     autocmake_entry = autocmake_entry.replace('\n  ', '\n') | ||||
|  | ||||
|     buf = StringIO(autocmake_entry) | ||||
|     config = parse_yaml(buf, override) | ||||
|  | ||||
|     for k, v in config.items(): | ||||
|         if isinstance(v, Iterable) and not isinstance(v, str): | ||||
|             parsed_config[k] = [x for x in config[k]] | ||||
|         else: | ||||
|             parsed_config[k] = [config[k]] | ||||
|  | ||||
|     return parsed_config | ||||
|  | ||||
|  | ||||
| def test_parse_cmake_module(): | ||||
|  | ||||
|     s = r'''#.rst: | ||||
| # | ||||
| # Foo ... | ||||
| # | ||||
| # autocmake.yml configuration:: | ||||
| # | ||||
| #   docopt: | ||||
| #     - "--cxx=<CXX> C++ compiler [default: g++]." | ||||
| #     - "--extra-cxx-flags=<EXTRA_CXXFLAGS> Extra C++ compiler flags [default: '']." | ||||
| #   export: "'CXX={0}'.format(arguments['--cxx'])" | ||||
| #   define: "'-DEXTRA_CXXFLAGS=\"{0}\"'.format(arguments['--extra-cxx-flags'])" | ||||
|  | ||||
| enable_language(CXX) | ||||
|  | ||||
| if(NOT DEFINED CMAKE_C_COMPILER_ID) | ||||
|     message(FATAL_ERROR "CMAKE_C_COMPILER_ID variable is not defined!") | ||||
| endif()''' | ||||
|  | ||||
|     parsed_config = parse_cmake_module(s) | ||||
|     assert parsed_config['docopt'] == ["--cxx=<CXX> C++ compiler [default: g++].", "--extra-cxx-flags=<EXTRA_CXXFLAGS> Extra C++ compiler flags [default: '']."] | ||||
|  | ||||
|  | ||||
| def test_parse_cmake_module_no_key(): | ||||
|  | ||||
|     s = '''#.rst: | ||||
| # | ||||
| # Foo ... | ||||
| # | ||||
| # Bar ... | ||||
|  | ||||
| enable_language(CXX) | ||||
|  | ||||
| if(NOT DEFINED CMAKE_C_COMPILER_ID) | ||||
|     message(FATAL_ERROR "CMAKE_C_COMPILER_ID variable is not defined!") | ||||
| endif()''' | ||||
|  | ||||
|     parsed_config = parse_cmake_module(s) | ||||
|     assert parsed_config['docopt'] is None | ||||
|  | ||||
|  | ||||
| def test_parse_cmake_module_interpolate(): | ||||
|  | ||||
|     s = r'''#.rst: | ||||
| # | ||||
| # Foo ... | ||||
| # | ||||
| # autocmake.yml configuration:: | ||||
| # | ||||
| #   major: 1 | ||||
| #   minor: 2 | ||||
| #   patch: 3 | ||||
| #   a: v%(major) | ||||
| #   b: v%(minor) | ||||
| #   c: v%(patch) | ||||
|  | ||||
| enable_language(CXX)''' | ||||
|  | ||||
|     parsed_config = parse_cmake_module(s) | ||||
|     assert parsed_config['a'] == ['v1'] | ||||
|     assert parsed_config['b'] == ['v2'] | ||||
|     assert parsed_config['c'] == ['v3'] | ||||
|  | ||||
|  | ||||
| def test_parse_cmake_module_override(): | ||||
|  | ||||
|     s = r'''#.rst: | ||||
| # | ||||
| # Foo ... | ||||
| # | ||||
| # autocmake.yml configuration:: | ||||
| # | ||||
| #   major: 1 | ||||
| #   minor: 2 | ||||
| #   patch: 3 | ||||
| #   a: v%(major) | ||||
| #   b: v%(minor) | ||||
| #   c: v%(patch) | ||||
|  | ||||
| enable_language(CXX)''' | ||||
|  | ||||
|     d = {'minor': 4} | ||||
|     parsed_config = parse_cmake_module(s, d) | ||||
|     assert parsed_config['a'] == ['v1'] | ||||
|     assert parsed_config['b'] == ['v4'] | ||||
|     assert parsed_config['c'] == ['v3'] | ||||
							
								
								
									
										16
									
								
								autocmake/parse_yaml.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								autocmake/parse_yaml.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| def parse_yaml(stream, override={}): | ||||
|     import yaml | ||||
|     from autocmake.interpolate import interpolate | ||||
|  | ||||
|     try: | ||||
|         config = yaml.load(stream, yaml.SafeLoader) | ||||
|     except yaml.YAMLError as exc: | ||||
|         print(exc) | ||||
|         sys.exit(-1) | ||||
|  | ||||
|     for k in config: | ||||
|         if k in override: | ||||
|             config[k] = override[k] | ||||
|  | ||||
|     config = interpolate(config, config) | ||||
|     return config | ||||
		Reference in New Issue
	
	Block a user