Commit 7a670211 authored by Robin Schoonover's avatar Robin Schoonover

Add support for replacing localization keyword via curse localization API.

parent 56a30278
Pipeline #887 failed with stages
in 2 minutes and 40 seconds
build/
/build/
.cache/
.coverage
dist/
......
......@@ -4,8 +4,72 @@ import unittest
class ProcessorTestMixin(object):
def assertProcessor(self, a, b, **kwargs):
proc = self.processor(**kwargs)
if isinstance(a, str):
a = a.encode('utf-8')
if isinstance(b, str):
b = b.encode('utf-8')
self.assertEqual(proc.process(a), b)
class KeywordArgParserTest(unittest.TestCase):
def test_empty(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs(""), {})
self.assertEqual(parse_kwargs(" "), {})
def test_string1(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("s=\"abc\""), {'s' : 'abc'})
self.assertEqual(parse_kwargs("s2='def'"), {'s2' : 'def'})
self.assertEqual(parse_kwargs("a_bc='def'"), {'a_bc' : 'def'})
self.assertEqual(parse_kwargs("a-bc='def'"), {'a-bc' : 'def'})
def test_string2(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("s=\"abc\", s2=\"kji\""), {'s' : 'abc', 's2' : 'kji'})
self.assertEqual(parse_kwargs("s2='bla', v='jef'"), {'s2' : 'bla', 'v' : 'jef'})
def test_escape_nl(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("s=\"two\nlines\""), {'s' : 'two\nlines'})
self.assertEqual(parse_kwargs("s=\"a\n\""), {'s' : 'a\n'})
self.assertEqual(parse_kwargs("s=\"\n\""), {'s' : '\n'})
self.assertEqual(parse_kwargs("s=\"\nb\""), {'s' : '\nb'})
def test_escape_quote(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs('s="abc\\""'), {'s' : 'abc"'})
self.assertEqual(parse_kwargs('s="\\"abc"'), {'s' : '"abc'})
self.assertEqual(parse_kwargs("s='abc\\''"), {'s' : 'abc\''})
self.assertEqual(parse_kwargs("s='abc\\\"\\''"), {'s' : 'abc"\''})
def test_escape_bs(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs('s="\\\\"'), {'s' : '\\'})
self.assertEqual(parse_kwargs('s="\\\\abc"'), {'s' : '\\abc'})
self.assertEqual(parse_kwargs('s="abc\\\\"'), {'s' : 'abc\\'})
def test_number1(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("s=1"), {'s' : 1})
self.assertEqual(parse_kwargs("s2=547"), {'s2' : 547})
def test_number2(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("re=1, sold=76"), {'re' : 1, 'sold' : 76})
def test_string_and_number(self):
from wowui_builder.build.preprocess import parse_kwargs
self.assertEqual(parse_kwargs("f=\"a\", b=2"), {'f' : 'a', 'b' : 2})
class LuaProcTest(ProcessorTestMixin, unittest.TestCase):
def processor(self, **kwargs):
from wowui_builder.build.preprocess import LuaPreProcessor
......
......@@ -14,7 +14,8 @@ import zipfile
from ..main import cli
from ..pkgmeta import PkgMeta
from ..vcs import get_working_copy, checkout_repo, VCSError
from .preprocess import PreProcessor
from .localizer import AutoLocalizer
from .preprocess import PreProcessor, PreProcessorError
from .utils import *
def make_zip(zip_name, root_dir):
......@@ -32,7 +33,7 @@ def make_zip(zip_name, root_dir):
zf.write(fullpath, arcname)
class TreeCopy(object):
def __init__(self, src, dest, verbose=True, keyword_func=None, alpha=False, vcs_tag=None, filter_func=None, version=None):
def __init__(self, src, dest, verbose=True, keyword_func=None, alpha=False, vcs_tag=None, filter_func=None, localizer=None, version=None):
if keyword_func is None:
keyword_func = self.get_keyword
self.verbose = verbose
......@@ -40,7 +41,7 @@ class TreeCopy(object):
self.vcs = get_working_copy(src)
self.version = version
alpha = alpha or (vcs_tag is not None and self.vcs.project_version() != vcs_tag)
self.preprocessor = PreProcessor(keyword_func=keyword_func, alpha=alpha)
self.preprocessor = PreProcessor(keyword_func=keyword_func, alpha=alpha, localizer=localizer)
self.src = src
self.dest = dest
......@@ -135,7 +136,7 @@ class FilterPathExternal(object):
return True
class PackageBuild(object):
def __init__(self, pkg, builddir, distdir, verbose=True, version=None):
def __init__(self, pkg, builddir, distdir, verbose=True, version=None, localizer=None):
self.path = pkg.path
self.pkgmeta = pkg.pkgmeta
self.builddir = builddir
......@@ -145,6 +146,7 @@ class PackageBuild(object):
self.distdir = distdir
self.version = version
self.vcs_tag = pkg.vcs_tag
self.localizer = localizer
@property
def ignore_paths(self):
......@@ -249,7 +251,7 @@ class PackageBuild(object):
self.generate_changelog(vcs, os.path.join(self.distdir, name+".txt"))
tree_copy(self.path, os.path.join(self.workdir, self.pkgmeta.dist_name), filter_func=self.filter_path)
tree_copy(self.path, os.path.join(self.workdir, self.pkgmeta.dist_name), filter_func=self.filter_path, localizer=self.localizer)
self.pull_externals(os.path.join(self.workdir, self.pkgmeta.dist_name))
self.move_folders()
......@@ -280,7 +282,7 @@ class Package(object):
raise
return Package(tempdir.name, _tempdir=tempdir, **kwargs)
def build(self, distdir, build_dir=None):
def build(self, distdir, build_dir=None, localizer=None):
tmp_build_dir = None
try:
......@@ -291,7 +293,7 @@ class Package(object):
os.makedirs(build_dir, exist_ok=True)
os.makedirs(distdir, exist_ok=True)
PackageBuild(self, build_dir, distdir, version=self.version).build()
PackageBuild(self, build_dir, distdir, version=self.version, localizer=localizer).build()
finally:
if tmp_build_dir is None:
tmp_build_dir.cleanup()
......@@ -306,10 +308,13 @@ class Package(object):
help="Build directory")
@click.option('--dist-dir', '-d', type=click.Path(file_okay=False, dir_okay=True),
help="Destination directory")
@click.option('--curse-api-token', envvar='CURSE_API_TOKEN')
@click.option('--curse-localization-url', envvar='CURSE_LOCALIZATION_URL', default='https://wow.curseforge.com/api/projects/{project_id}/localization/export')
@click.option('--curse-project-id', envvar='CURSE_PROJECT_ID', help='The project id (used for localization)')
@click.option('--vcs-tag', help='VCS tag we are building against. Verified against version. If blank or mismatch, mark as alpha')
@click.option('--version')
@click.argument('source', type=click.Path(exists=True), default=".")
def build_cli(source, build_dir, dist_dir, vcs_tag, version):
def build_cli(source, build_dir, dist_dir, curse_api_token, curse_project_id, curse_localization_url, vcs_tag, version):
pkg = Package(source, vcs_tag=vcs_tag, version=version)
if dist_dir is None:
......@@ -318,7 +323,15 @@ def build_cli(source, build_dir, dist_dir, vcs_tag, version):
click.echo("Dist dir cannot be source root!", err=True)
sys.exit(1)
localizer = AutoLocalizer(
curse_api_token=curse_api_token,
curse_project_id=curse_project_id,
curse_localization_url=curse_localization_url
)
try:
pkg.build(dist_dir, build_dir=build_dir)
except VCSError as exc:
pkg.build(dist_dir, build_dir=build_dir, localizer=localizer)
except (VCSError, PreProcessorError) as exc:
click.echo(str(exc), err=True)
click.echo("Build failed!", err=True)
sys.exit(1)
import requests
from .. import __version__
def create_session(headers=None):
session = requests.Session()
version = "wowui-builder/%s %s"%(__version__, session.headers.get('User-Agent', '?'))
session.headers.update({'User-Agent': version})
if headers is not None:
session.headers.update(headers)
return session
class LocalizationError(Exception):
pass
class CurseLocalizer(object):
def __init__(self, curse_api_token=None, curse_project_id=None, curse_localization_url=None):
self.api_token = curse_api_token
self.project_id = curse_project_id
self.localization_url = curse_localization_url
def __call__(self, kwargs):
params = self._make_params(kwargs)
curse_session = create_session(headers={
'X-Api-Token' : self.api_token
})
url = self.localization_url.format(project_id=self.project_id)
response = curse_session.get(url, params=params)
return response.content
def _make_params(self, kwargs):
params = {
'lang' : kwargs.pop("locale", "enUS")
}
export_format = kwargs.pop('format', "lua_table")
if export_format == "lua_table":
params['export-type'] = 'Table'
elif export_format == 'lua_additive_table':
params['export-type'] = 'TableAdditions'
elif export_format == 'globals':
params['export-type'] = 'GlobalStrings'
elif export_format is not None:
raise LocalizationError("Unknown format value for localization: %r"%(export_format,))
unlocalized = kwargs.pop("handle-unlocalized", None)
if unlocalized == "english" or unlocalized == "primary":
params['unlocalized'] = 'ShowPrimary'
elif unlocalized == "comment":
params['unlocalized'] = "ShowPrimaryAsComment"
elif unlocalized == "blank":
params['unlocalized'] = "ShowBlankAsComment"
elif unlocalized == "ignore":
params['unlocalized'] = "Ignore"
elif unlocalized is not None:
raise LocalizationError("Unknown handle-unlocalized value for localization: %r"%(export_format,))
if kwargs.pop("escape-non-ascii", False):
params['escape-non-ascii-characters'] = 'true'
table_name = kwargs.pop("table-name", None)
if table_name is not None:
params['table-name'] = table_name
if kwargs.pop('same-key-is-true', False):
params['true-if-value-equals-key'] = 'true'
handle_namespace = kwargs.pop('handle-subnamespaces', "none")
if handle_namespace == "none":
# do nothing
pass
elif handle_namespace == 'concat':
namespace_delim = kwargs.pop('namespace-delimiter', None)
if namespace_delim == '/':
params['concatenate-subnamespaces'] = 'true'
elif namespace_delim is not None:
raise LocalizationError("Namespace delimiters other than '/' are not supported")
elif handle_namespace == 'subtable':
raise LocalizationError("Namespace subtables not supported")
elif handle_namespace is not None:
raise LocalizationError("Unknown handle-subnamespaces value for localization: %r"%(export_format,))
namespace = kwargs.pop('namespace', '')
if namespace:
params['namespaces'] = namespace
return params
def valid(self):
return self.api_token and self.project_id and self.localization_url
class AutoLocalizer(object):
def __init__(self, curse_api_token=None, curse_project_id=None, curse_localization_url=None):
self._curse = CurseLocalizer(
curse_api_token=curse_api_token,
curse_project_id=curse_project_id,
curse_localization_url=curse_localization_url
)
def valid(self):
return self._curse.valid()
def __call__(self, kwargs):
if self._curse.valid():
return self._curse(kwargs)
raise LocalizationError("No localizers available (only curse supported currently, please set environment variables)")
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment