Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbazile/dbf1e5bfbd399dfb5978a44444d0e56b to your computer and use it in GitHub Desktop.
Save dbazile/dbf1e5bfbd399dfb5978a44444d0e56b to your computer and use it in GitHub Desktop.
#!/bin/env python3
import argparse
import json
import logging
import os
import re
import yaml
LOG = logging.getLogger()
def main():
ap = argparse.ArgumentParser()
ap.add_argument('-v', '--verbose', action='store_true')
ap.add_argument('file', nargs='+', help='path to a Spring config file')
params = ap.parse_args()
logging.basicConfig(
format='[%(funcName)-8s] %(message)s',
level=logging.DEBUG if params.verbose else logging.INFO,
)
props = {}
for file_path in params.file: # type: str
LOG.info('import: \033[1m%s\033[0m', os.path.relpath(file_path))
file_path = file_path.strip()
if not os.path.isfile(file_path):
raise Exception(f'not a file: {file_path!r}')
with open(file_path) as f:
if file_path.lower().rsplit('.')[-1] in ('yml', 'yaml'):
lines = flatten(yaml.safe_load(f))
elif file_path.lower().rsplit('.')[-1] in ('properties',):
lines = f.readlines()
else:
raise Exception(f'wtf: {file_path}')
for line in lines:
line = line.strip()
if not line:
LOG.debug(f'skip: \033[2m{line}\033[0m')
continue
name, value = line.split('=', 1)
value = value.lower().strip()
m = re.match(r'^(?P<name>.*)\[\d+\]$', name)
if m:
name = m.group('name')
type = 'java.util.List<java.lang.String>'
elif value.lower() in ('yes', 'true', 'false', 'no'):
type = 'java.lang.Boolean'
elif re.match(r'^[-+]?\d+L?$', value):
type = 'java.lang.Long'
elif re.match(r'^[-+]?\d+\.\d+?$', value):
type = 'java.lang.Float'
else:
type = 'java.lang.String'
if not name \
or name in props \
or name.startswith('#') \
or name.startswith('logging') \
or name.startswith('server') \
or name.startswith('spring'):
LOG.debug(f'skip: \033[2m{line}\033[0m')
continue
prop = {'name': name, 'type': type}
LOG.debug(f'take: \033[32m{prop}\033[0m')
props[name] = prop
print(json.dumps({
'properties': sorted(props.values(), key=lambda d: d['name']),
}, indent=4))
return 0
def flatten(tree):
"""
:type tree: dict
:rtype: [str]
"""
items = []
LOG.debug('flatten: %s', tree)
def _walk(node, path):
for k, v in node.items():
if isinstance(v, dict):
LOG.debug('branch: \033[35m%r\033[0m = \033[2m%r\033[0m', path + k, v)
_walk(v, path + k + '.')
elif isinstance(v, list):
for i, element in enumerate(v):
items.append(f'{path + k}[{i}]={element}')
else:
LOG.debug('leaf: \033[35m%r\033[0m = \033[2m%r\033[0m', path + k, v)
items.append(f'{path + k}={v}')
_walk(tree, '')
return items
if __name__ == '__main__':
exit(main())
WHAT IS THIS
Scans Spring config files and generates a manifest so IntelliJ stops complaining about
not "Cannot resolve configuration property 'blahblah'"
USAGE
$ generate-additional-spring-configuration-metadata.py src/main/resources/config/* > src/main/resources/META-INF/additional-spring-configuration-metadata.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment