mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-28 20:43:37 +01:00
fxconv: expose fxconv-metadata.txt parsing functions in API
This commit is contained in:
parent
6dae13007e
commit
4d46661d3b
2 changed files with 116 additions and 58 deletions
|
@ -3,8 +3,6 @@
|
||||||
import getopt
|
import getopt
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import fnmatch
|
|
||||||
import fxconv
|
import fxconv
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
||||||
|
@ -54,52 +52,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
converters = []
|
converters = []
|
||||||
|
|
||||||
def parse_parameters(params):
|
|
||||||
"""Parse parameters of the form "NAME:VALUE" into a dictionary."""
|
|
||||||
d = dict()
|
|
||||||
|
|
||||||
def insert(d, path, value):
|
|
||||||
if len(path) == 1:
|
|
||||||
d[path[0]] = value
|
|
||||||
else:
|
|
||||||
if not path[0] in d:
|
|
||||||
d[path[0]] = dict()
|
|
||||||
insert(d[path[0]], path[1:], value)
|
|
||||||
|
|
||||||
for decl in params:
|
|
||||||
if ":" not in decl:
|
|
||||||
raise FxconvError(f"invalid parameter {decl}, ignoring")
|
|
||||||
else:
|
|
||||||
name, value = decl.split(":", 1)
|
|
||||||
value = value.strip()
|
|
||||||
if name == "name_regex":
|
|
||||||
value = value.split(" ", 1)
|
|
||||||
insert(d, name.split("."), value)
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
def parse_parameters_metadata(contents):
|
|
||||||
"""Parse parameters from a metadata file contents."""
|
|
||||||
|
|
||||||
RE_COMMENT = re.compile(r'#.*$', re.MULTILINE)
|
|
||||||
contents = re.sub(RE_COMMENT, "", contents)
|
|
||||||
|
|
||||||
RE_WILDCARD = re.compile(r'^(\S(?:[^:\s]|\\:|\\ )*)\s*:\s*$', re.MULTILINE)
|
|
||||||
lead, *elements = [ s.strip() for s in re.split(RE_WILDCARD, contents) ]
|
|
||||||
|
|
||||||
if lead:
|
|
||||||
raise FxconvError(f"invalid metadata: {lead} appears before wildcard")
|
|
||||||
|
|
||||||
# Group elements by pairs (left: wildcard, right: list of properties)
|
|
||||||
elements = list(zip(elements[::2], elements[1::2]))
|
|
||||||
|
|
||||||
metadata = []
|
|
||||||
for (wildcard, params) in elements:
|
|
||||||
params = [ s.strip() for s in params.split("\n") if s.strip() ]
|
|
||||||
metadata.append((wildcard, parse_parameters(params)))
|
|
||||||
|
|
||||||
return metadata
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
types = "binary image font bopti-image libimg-image custom"
|
types = "binary image font bopti-image libimg-image custom"
|
||||||
mode = ""
|
mode = ""
|
||||||
|
@ -155,21 +107,15 @@ def main():
|
||||||
# In automatic mode, look for information in fxconv-metadata.txt
|
# In automatic mode, look for information in fxconv-metadata.txt
|
||||||
if mode == "":
|
if mode == "":
|
||||||
metadata_file = os.path.dirname(input) + "/fxconv-metadata.txt"
|
metadata_file = os.path.dirname(input) + "/fxconv-metadata.txt"
|
||||||
basename = os.path.basename(input)
|
|
||||||
|
|
||||||
if not os.path.exists(metadata_file):
|
if not os.path.exists(metadata_file):
|
||||||
return err(f"using auto mode but {metadata_file} does not exist")
|
return err(f"using auto mode but {metadata_file} does not exist")
|
||||||
|
|
||||||
with open(metadata_file, "r") as fp:
|
metadata = fxconv.Metadata(path=metadata_file)
|
||||||
metadata = parse_parameters_metadata(fp.read())
|
params = metadata.rules_for(input)
|
||||||
|
|
||||||
params = dict()
|
if "section" in params:
|
||||||
for (wildcard, p) in metadata:
|
target["section"] = params["section"]
|
||||||
if fnmatch.fnmatchcase(basename, wildcard):
|
|
||||||
params.update(**p)
|
|
||||||
|
|
||||||
if "section" in params:
|
|
||||||
target["section"] = params["section"]
|
|
||||||
|
|
||||||
# In manual conversion modes, read parameters from the command-line
|
# In manual conversion modes, read parameters from the command-line
|
||||||
else:
|
else:
|
||||||
|
|
112
fxconv/fxconv.py
112
fxconv/fxconv.py
|
@ -6,6 +6,7 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import collections
|
import collections
|
||||||
|
import fnmatch
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -23,6 +24,8 @@ __all__ = [
|
||||||
"convert_bopti_fx", "convert_bopti_cg",
|
"convert_bopti_fx", "convert_bopti_cg",
|
||||||
"convert_topti",
|
"convert_topti",
|
||||||
"convert_libimg_fx", "convert_libimg_cg",
|
"convert_libimg_fx", "convert_libimg_cg",
|
||||||
|
# Meta API to use fxconv-metadata.txt files
|
||||||
|
"Metadata",
|
||||||
]
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1349,3 +1352,112 @@ def elf(data, output, symbol, toolchain=None, arch=None, section=None,
|
||||||
fp_obj.close()
|
fp_obj.close()
|
||||||
if assembly:
|
if assembly:
|
||||||
fp_asm.close()
|
fp_asm.close()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Meta API
|
||||||
|
#
|
||||||
|
|
||||||
|
def _parse_parameters(params):
|
||||||
|
"""Parse parameters of the form "NAME:VALUE" into a dictionary."""
|
||||||
|
d = dict()
|
||||||
|
|
||||||
|
def insert(d, path, value):
|
||||||
|
if len(path) == 1:
|
||||||
|
d[path[0]] = value
|
||||||
|
else:
|
||||||
|
if not path[0] in d:
|
||||||
|
d[path[0]] = dict()
|
||||||
|
insert(d[path[0]], path[1:], value)
|
||||||
|
|
||||||
|
for decl in params:
|
||||||
|
if ":" not in decl:
|
||||||
|
raise FxconvError(f"invalid parameter {decl}, ignoring")
|
||||||
|
else:
|
||||||
|
name, value = decl.split(":", 1)
|
||||||
|
value = value.strip()
|
||||||
|
if name == "name_regex":
|
||||||
|
value = value.split(" ", 1)
|
||||||
|
insert(d, name.split("."), value)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _parse_metadata(contents):
|
||||||
|
"""
|
||||||
|
Parse the contents of an fxconv-metadata.txt file. Comments start with '#'
|
||||||
|
anywhere on a line and extend to the end of the line.
|
||||||
|
|
||||||
|
The file is divided in blocks that start with a "<wildcard>:" pattern at
|
||||||
|
the first column of a line (no leading spaces) followed by zero or more
|
||||||
|
properties declared as "key: value" (with at least one leading space).
|
||||||
|
|
||||||
|
The key can contain dots (eg. "category.field"), in which case the value
|
||||||
|
for the main component ("category") is itself a dictionary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
RE_COMMENT = re.compile(r'#.*$', re.MULTILINE)
|
||||||
|
contents = re.sub(RE_COMMENT, "", contents)
|
||||||
|
|
||||||
|
RE_WILDCARD = re.compile(r'^(\S(?:[^:\s]|\\:|\\ )*)\s*:\s*$', re.MULTILINE)
|
||||||
|
lead, *elements = [ s.strip() for s in re.split(RE_WILDCARD, contents) ]
|
||||||
|
|
||||||
|
if lead:
|
||||||
|
raise FxconvError(f"invalid metadata: {lead} appears before wildcard")
|
||||||
|
|
||||||
|
# Group elements by pairs (left: wildcard, right: list of properties)
|
||||||
|
elements = list(zip(elements[::2], elements[1::2]))
|
||||||
|
|
||||||
|
metadata = []
|
||||||
|
for (wildcard, params) in elements:
|
||||||
|
params = [ s.strip() for s in params.split("\n") if s.strip() ]
|
||||||
|
metadata.append((wildcard, _parse_parameters(params)))
|
||||||
|
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
class Metadata:
|
||||||
|
def __init__(self, path=None, text=None):
|
||||||
|
"""
|
||||||
|
Load either an fxconv-metadata.txt file (if path is not None) or the
|
||||||
|
contents of such a file (if text is not None).
|
||||||
|
"""
|
||||||
|
|
||||||
|
if (path is not None) == (text is not None):
|
||||||
|
raise ValueError("Metadata must have exactly one of path and text")
|
||||||
|
|
||||||
|
if path is not None:
|
||||||
|
self._path = path
|
||||||
|
with open(path, "r") as fp:
|
||||||
|
self._rules = _parse_metadata(fp.read())
|
||||||
|
elif text is not None:
|
||||||
|
self._path = None
|
||||||
|
self._rules = _parse_metadata(text)
|
||||||
|
|
||||||
|
def path(self):
|
||||||
|
"""
|
||||||
|
Returns the path of the file from which the metadata was parsed, or
|
||||||
|
None if the metadata was parsed from string.
|
||||||
|
"""
|
||||||
|
return self._path
|
||||||
|
|
||||||
|
def rules(self):
|
||||||
|
"""
|
||||||
|
Returns a list of pairs (wildcard, rules) where the wildcard is a
|
||||||
|
string and the rules are a nested dictionary.
|
||||||
|
"""
|
||||||
|
return self._rules
|
||||||
|
|
||||||
|
def rules_for(self, path):
|
||||||
|
"""
|
||||||
|
Returns the parameters that apply to the specified path, or None if no
|
||||||
|
wildcard matches it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
basename = os.path.basename(path)
|
||||||
|
params = dict()
|
||||||
|
matched = False
|
||||||
|
|
||||||
|
for (wildcard, p) in self._rules:
|
||||||
|
if fnmatch.fnmatchcase(basename, wildcard):
|
||||||
|
params.update(**p)
|
||||||
|
matched = True
|
||||||
|
|
||||||
|
return params if matched else None
|
||||||
|
|
Loading…
Reference in a new issue