mirror of
https://github.com/gnosygnu/xowa.git
synced 2024-10-27 20:34:16 +00:00
Cfg: Add upgrade code for old cfg system
This commit is contained in:
parent
fd2f01eb94
commit
f0296305d5
@ -169,6 +169,7 @@ public class Xoae_app implements Xoa_app, Gfo_invk {
|
|||||||
if (Launch_done()) return;
|
if (Launch_done()) return;
|
||||||
xwiki_mgr__sitelink_mgr.Init_by_app();
|
xwiki_mgr__sitelink_mgr.Init_by_app();
|
||||||
stage = Xoa_stage_.Tid_launch;
|
stage = Xoa_stage_.Tid_launch;
|
||||||
|
gplx.xowa.addons.apps.cfgs.upgrades.Xocfg_upgrade_mgr.Convert(this);
|
||||||
Xouc_setup_mgr.Setup_run_check(this); log_bfr.Add("app.upgrade.done");
|
Xouc_setup_mgr.Setup_run_check(this); log_bfr.Add("app.upgrade.done");
|
||||||
user.Wiki().Init_assert(); // NOTE: must assert wiki and load langs first, else will be asserted during Portal_mgr().Init(), which will cause IndexOutOfBounds; DATE:2014-10-04
|
user.Wiki().Init_assert(); // NOTE: must assert wiki and load langs first, else will be asserted during Portal_mgr().Init(), which will cause IndexOutOfBounds; DATE:2014-10-04
|
||||||
gplx.xowa.addons.users.wikis.regys.Xou_regy_addon.Init(this);
|
gplx.xowa.addons.users.wikis.regys.Xou_regy_addon.Init(this);
|
||||||
|
@ -18,10 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
package gplx.xowa.addons.apps.cfgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*;
|
package gplx.xowa.addons.apps.cfgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*;
|
||||||
import gplx.dbs.*; import gplx.xowa.addons.apps.cfgs.mgrs.caches.*; import gplx.xowa.addons.apps.cfgs.mgrs.dflts.*; import gplx.xowa.addons.apps.cfgs.mgrs.types.*; import gplx.xowa.addons.apps.cfgs.mgrs.execs.*;
|
import gplx.dbs.*; import gplx.xowa.addons.apps.cfgs.mgrs.caches.*; import gplx.xowa.addons.apps.cfgs.mgrs.dflts.*; import gplx.xowa.addons.apps.cfgs.mgrs.types.*; import gplx.xowa.addons.apps.cfgs.mgrs.execs.*;
|
||||||
public class Xocfg_mgr implements Gfo_invk {
|
public class Xocfg_mgr implements Gfo_invk {
|
||||||
private final Xocfg_cache_mgr cache_mgr = new Xocfg_cache_mgr();
|
|
||||||
public Xocfg_mgr() {
|
public Xocfg_mgr() {
|
||||||
this.dflt_mgr = new Xocfg_dflt_mgr(cache_mgr);
|
this.dflt_mgr = new Xocfg_dflt_mgr(cache_mgr);
|
||||||
}
|
}
|
||||||
|
public Xocfg_cache_mgr Cache_mgr() {return cache_mgr;} private final Xocfg_cache_mgr cache_mgr = new Xocfg_cache_mgr();
|
||||||
public Xocfg_type_mgr Type_mgr() {return type_mgr;} private final Xocfg_type_mgr type_mgr = new Xocfg_type_mgr();
|
public Xocfg_type_mgr Type_mgr() {return type_mgr;} private final Xocfg_type_mgr type_mgr = new Xocfg_type_mgr();
|
||||||
public Xocfg_dflt_mgr Dflt_mgr() {return dflt_mgr;} private final Xocfg_dflt_mgr dflt_mgr;
|
public Xocfg_dflt_mgr Dflt_mgr() {return dflt_mgr;} private final Xocfg_dflt_mgr dflt_mgr;
|
||||||
public Xocfg_exec_mgr Exec_mgr() {return exec_mgr;} private final Xocfg_exec_mgr exec_mgr = new Xocfg_exec_mgr();
|
public Xocfg_exec_mgr Exec_mgr() {return exec_mgr;} private final Xocfg_exec_mgr exec_mgr = new Xocfg_exec_mgr();
|
||||||
|
@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*;
|
package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*;
|
||||||
class Xocfg_cache_grp {
|
public class Xocfg_cache_grp {
|
||||||
private final Hash_adp vals = Hash_adp_.New();
|
private final Hash_adp vals = Hash_adp_.New();
|
||||||
private final Ordered_hash subs = Ordered_hash_.New();
|
private final Ordered_hash subs = Ordered_hash_.New();
|
||||||
public Xocfg_cache_grp(String key, String dflt) {
|
public Xocfg_cache_grp(String key, String dflt) {
|
||||||
|
@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*;
|
package gplx.xowa.addons.apps.cfgs.mgrs.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*; import gplx.xowa.addons.apps.cfgs.mgrs.*;
|
||||||
class Xocfg_cache_itm {
|
public class Xocfg_cache_itm {
|
||||||
public Xocfg_cache_itm(String ctx, String key, String val) {
|
public Xocfg_cache_itm(String ctx, String key, String val) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
@ -48,7 +48,12 @@ public class Xocfg_cache_mgr {
|
|||||||
public void Set(boolean save, String ctx, String key, String val) {
|
public void Set(boolean save, String ctx, String key, String val) {
|
||||||
Xocfg_cache_grp grp = Grps__get_or_load(key);
|
Xocfg_cache_grp grp = Grps__get_or_load(key);
|
||||||
grp.Set(ctx, val);
|
grp.Set(ctx, val);
|
||||||
if (save) db_usr.Set_str(ctx, key, val);
|
if (save) {
|
||||||
|
if (String_.Eq(grp.Dflt(), val))
|
||||||
|
db_usr.Del(ctx, key);
|
||||||
|
else
|
||||||
|
db_usr.Set_str(ctx, key, val);
|
||||||
|
}
|
||||||
grp.Pub(ctx, val);
|
grp.Pub(ctx, val);
|
||||||
}
|
}
|
||||||
public void Del(String ctx, String key) {
|
public void Del(String ctx, String key) {
|
||||||
@ -69,7 +74,7 @@ public class Xocfg_cache_mgr {
|
|||||||
Xocfg_cache_grp grp = Grps__get_or_load(key);
|
Xocfg_cache_grp grp = Grps__get_or_load(key);
|
||||||
grp.Dflt_(val);
|
grp.Dflt_(val);
|
||||||
}
|
}
|
||||||
private Xocfg_cache_grp Grps__get_or_load(String key) {
|
public Xocfg_cache_grp Grps__get_or_load(String key) {
|
||||||
Xocfg_cache_grp grp = (Xocfg_cache_grp)grps.Get_by(key);
|
Xocfg_cache_grp grp = (Xocfg_cache_grp)grps.Get_by(key);
|
||||||
if (grp == null) {
|
if (grp == null) {
|
||||||
grp = Load_grp(key, "");
|
grp = Load_grp(key, "");
|
||||||
|
@ -19,7 +19,7 @@ package gplx.xowa.addons.apps.cfgs.specials.edits.services; import gplx.*; impor
|
|||||||
import gplx.langs.jsons.*;
|
import gplx.langs.jsons.*;
|
||||||
import gplx.core.gfobjs.*;
|
import gplx.core.gfobjs.*;
|
||||||
import gplx.xowa.guis.cbks.*; import gplx.xowa.addons.apps.cfgs.dbs.*; import gplx.xowa.addons.apps.cfgs.specials.edits.objs.*;
|
import gplx.xowa.guis.cbks.*; import gplx.xowa.addons.apps.cfgs.dbs.*; import gplx.xowa.addons.apps.cfgs.specials.edits.objs.*;
|
||||||
import gplx.xowa.addons.apps.cfgs.specials.edits.pages.*;
|
import gplx.xowa.addons.apps.cfgs.specials.edits.pages.*; import gplx.xowa.addons.apps.cfgs.mgrs.caches.*;
|
||||||
public class Xocfg_edit_svc {
|
public class Xocfg_edit_svc {
|
||||||
private final Xoa_app app;
|
private final Xoa_app app;
|
||||||
private Xocfg_edit_loader edit_loader;
|
private Xocfg_edit_loader edit_loader;
|
||||||
@ -36,6 +36,11 @@ public class Xocfg_edit_svc {
|
|||||||
val = gplx.xowa.addons.apps.cfgs.enums.Xoitm_gui_binding.To_db_str(val);
|
val = gplx.xowa.addons.apps.cfgs.enums.Xoitm_gui_binding.To_db_str(val);
|
||||||
}
|
}
|
||||||
app.Cfg().Set_str(ctx, key, val);
|
app.Cfg().Set_str(ctx, key, val);
|
||||||
|
|
||||||
|
Xocfg_cache_grp grp = app.Cfg().Cache_mgr().Grps__get_or_load(key);
|
||||||
|
if (String_.Eq(grp.Dflt(), val))
|
||||||
|
app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.revert__recv", Gfobj_nde.New().Add_str("key", key).Add_str("val", val));
|
||||||
|
else
|
||||||
app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.upsert__recv", Gfobj_nde.New().Add_str("key", key));
|
app.Gui__cbk_mgr().Send_json(cbk_trg, "xo.cfg_edit.upsert__recv", Gfobj_nde.New().Add_str("key", key));
|
||||||
}
|
}
|
||||||
public void Revert(Json_nde args) {
|
public void Revert(Json_nde args) {
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package gplx.xowa.addons.apps.cfgs.upgrades; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*;
|
||||||
|
import gplx.dbs.*;
|
||||||
|
public class Xocfg_upgrade_mgr {
|
||||||
|
public static void Convert(Xoae_app app) {
|
||||||
|
// get cfg_fil; if empty, exit
|
||||||
|
Io_url cfg_fil = app.Fsys_mgr().Root_dir().GenSubFil_nest("user", "anonymous", "app", "data", "cfg", "xowa_user_cfg.gfs");
|
||||||
|
byte[] cfg_raw = Io_mgr.Instance.LoadFilBryOrNull(cfg_fil);
|
||||||
|
if (cfg_raw == null) return;
|
||||||
|
|
||||||
|
// log and rename file
|
||||||
|
Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:old cfg found; converting");
|
||||||
|
Io_mgr.Instance.MoveFil(cfg_fil, cfg_fil.GenNewExt(".bak"));
|
||||||
|
|
||||||
|
// parse, remap, and update
|
||||||
|
Keyval[] kvs = Parse(cfg_raw);
|
||||||
|
|
||||||
|
// get mappings
|
||||||
|
Ordered_hash mappings = Ordered_hash_.New();
|
||||||
|
Db_conn conn = app.Cfg().Cache_mgr().Db_app().Conn();
|
||||||
|
Db_rdr rdr = conn.Stmt_sql("SELECT * FROM cfg_upgrade").Exec_select__rls_auto();
|
||||||
|
try {
|
||||||
|
while (rdr.Move_next()) {
|
||||||
|
String cfg_old = rdr.Read_str("cfg_old");
|
||||||
|
String cfg_new = rdr.Read_str("cfg_new");
|
||||||
|
mappings.Add(cfg_old, Keyval_.new_(cfg_old, cfg_new));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {rdr.Rls();}
|
||||||
|
|
||||||
|
// remap
|
||||||
|
for (Keyval kv : kvs) {
|
||||||
|
Keyval mapping = (Keyval)mappings.Get_by(kv.Key());
|
||||||
|
if (mapping == null) {
|
||||||
|
Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find mapping; key=~{0} val=~{1}", kv.Key(), kv.Val());
|
||||||
|
kv.Key_("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kv.Key_(mapping.Val());
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply
|
||||||
|
for (Keyval kv : kvs) {
|
||||||
|
if (String_.Eq(kv.Key(), "")) continue;
|
||||||
|
app.Cfg().Set_str_app(kv.Key(), kv.Val_to_str_or_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Keyval[] Parse(byte[] src) {
|
||||||
|
int pos = 0; int len = src.length;
|
||||||
|
byte[] key_bgn_bry = Bry_.new_a7("app.cfgs.get('");
|
||||||
|
byte[] key_end_bry = Bry_.new_a7("', 'app').val = '");
|
||||||
|
byte[] val_end_bry = Bry_.new_a7("';\n");
|
||||||
|
byte[] apos_2_bry = Bry_.new_a7("''");
|
||||||
|
|
||||||
|
// main parse
|
||||||
|
Ordered_hash hash = Ordered_hash_.New();
|
||||||
|
while (true) {
|
||||||
|
// find "app.cfgs.get('"
|
||||||
|
int key_bgn = Bry_find_.Find_fwd(src, key_bgn_bry, pos, len);
|
||||||
|
if (key_bgn == Bry_find_.Not_found) break; // no more cfgs; break;
|
||||||
|
|
||||||
|
// update key_bgn; find key_end
|
||||||
|
key_bgn += key_bgn_bry.length;
|
||||||
|
int key_end = Bry_find_.Find_fwd(src, key_end_bry, key_bgn, len);
|
||||||
|
if (key_end == Bry_find_.Not_found) {
|
||||||
|
Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find key_end; src=~{0}", Bry_.Mid(src, key_bgn, len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for val_end
|
||||||
|
int val_bgn = key_end + key_end_bry.length;
|
||||||
|
int val_end = Bry_find_.Find_fwd(src, val_end_bry, val_bgn, len);
|
||||||
|
if (val_end == Bry_find_.Not_found) {
|
||||||
|
Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find val_bgn; src=~{0}", Bry_.Mid(src, val_bgn, len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] key = Bry_.Replace(Bry_.Mid(src, key_bgn, key_end), apos_2_bry, Byte_ascii.Apos_bry);
|
||||||
|
byte[] val = Bry_.Replace(Bry_.Mid(src, val_bgn, val_end), apos_2_bry, Byte_ascii.Apos_bry);
|
||||||
|
String key_str = String_.new_u8(key);
|
||||||
|
hash.Add_if_dupe_use_nth(key_str, Keyval_.new_(key_str, String_.new_u8(val)));
|
||||||
|
pos = val_end + val_end_bry.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consolidate io.cmd
|
||||||
|
List_adp deleted = List_adp_.New();
|
||||||
|
len = hash.Len();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Keyval args_kv = (Keyval)hash.Get_at(i);
|
||||||
|
String args_kv_key = args_kv.Key();
|
||||||
|
String args_kv_val = args_kv.Val_to_str_or_empty();
|
||||||
|
if (String_.Has_at_end(args_kv_key, ".args")) {
|
||||||
|
Keyval cmd_kv = (Keyval)hash.Get_by(String_.Replace(args_kv_key, ".args", ".cmd"));
|
||||||
|
if (cmd_kv == null) {
|
||||||
|
Gfo_usr_dlg_.Instance.Log_many("", "", "cfg.convert:could not find cmd; key=~{0} val=~{1}", args_kv_key, args_kv.Val());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String cmd_kv_val = cmd_kv.Val_to_str_or_empty();
|
||||||
|
if (!String_.Has_at_end(cmd_kv_val, "|")) cmd_kv_val += "|";
|
||||||
|
cmd_kv.Val_(cmd_kv_val + args_kv_val);
|
||||||
|
deleted.Add(args_kv_key);
|
||||||
|
}
|
||||||
|
else if (String_.Has_at_bgn(args_kv_key, "app.cfg.get.gui.bnds.init('")) {
|
||||||
|
args_kv_key = String_.Replace(args_kv_key, "app.cfg.get.gui.bnds.init('", "");
|
||||||
|
args_kv_key = String_.Replace(args_kv_key, "').src", "");
|
||||||
|
args_kv_key = "xowa.gui.shortcuts." + args_kv_key;
|
||||||
|
args_kv.Key_(args_kv_key);
|
||||||
|
|
||||||
|
args_kv_val = String_.Replace(args_kv_val, "box='", "");
|
||||||
|
args_kv_val = String_.Replace(args_kv_val, "';ipt='", "|");
|
||||||
|
args_kv_val = String_.Replace(args_kv_val, "';", "");
|
||||||
|
args_kv.Val_(args_kv_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete args
|
||||||
|
len = deleted.Len();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
String deleted_key = (String)deleted.Get_at(i);
|
||||||
|
hash.Del(deleted_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Keyval[])hash.To_ary_and_clear(Keyval.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
XOWA: the XOWA Offline Wiki Application
|
||||||
|
Copyright (C) 2012 gnosygnu@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package gplx.xowa.addons.apps.cfgs.upgrades; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.apps.*; import gplx.xowa.addons.apps.cfgs.*;
|
||||||
|
import org.junit.*; import gplx.core.tests.*;
|
||||||
|
public class Xocfg_upgrade_mgr__tst {
|
||||||
|
private final Xocfg_upgrade_mgr__fxt fxt = new Xocfg_upgrade_mgr__fxt();
|
||||||
|
@Test public void Parse__one() {
|
||||||
|
fxt.Test__parse("app.cfgs.get('k_1', 'app').val = 'v_1';\n", Keyval_.new_("k_1", "v_1"));
|
||||||
|
}
|
||||||
|
@Test public void Parse__apos() {
|
||||||
|
fxt.Test__parse("app.cfgs.get('k_1(''k_1a'')', 'app').val = 'v_1';\n", Keyval_.new_("k_1('k_1a')", "v_1"));
|
||||||
|
}
|
||||||
|
@Test public void Parse__many() {
|
||||||
|
fxt.Test__parse
|
||||||
|
( "app.cfgs.get('k_1', 'app').val = 'v_1';\n"
|
||||||
|
+ "app.cfgs.get('k_2', 'app').val = 'v_2';\n"
|
||||||
|
, Keyval_.new_("k_1", "v_1"), Keyval_.new_("k_2", "v_2"));
|
||||||
|
}
|
||||||
|
@Test public void Parse__multi_line() {
|
||||||
|
fxt.Test__parse
|
||||||
|
( "app.cfgs.get('k_1', 'app').val = 'v_1\n"
|
||||||
|
+ "v_2\n"
|
||||||
|
+ "v_3';\n"
|
||||||
|
, Keyval_.new_("k_1", "v_1\nv_2\nv_3"));
|
||||||
|
}
|
||||||
|
@Test public void Parse__io_cmd() {
|
||||||
|
fxt.Test__parse
|
||||||
|
( "app.cfgs.get('a.cmd', 'app').val = 'cmd_1';\n"
|
||||||
|
+ "app.cfgs.get('a.args', 'app').val = 'args_1';\n"
|
||||||
|
, Keyval_.new_("a.cmd", "cmd_1|args_1"));
|
||||||
|
}
|
||||||
|
@Test public void Parse__gui_binding() {
|
||||||
|
fxt.Test__parse
|
||||||
|
( "app.cfgs.get('app.cfg.get.gui.bnds.init('xowa.app.exit-1').src', 'app').val = 'box='browser';ipt='key.none';';\n"
|
||||||
|
, Keyval_.new_("xowa.gui.shortcuts.xowa.app.exit-1", "browser|key.none"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Xocfg_upgrade_mgr__fxt {
|
||||||
|
public void Test__parse(String raw, Keyval... expd) {
|
||||||
|
Keyval[] actl = Xocfg_upgrade_mgr.Parse(Bry_.new_u8(raw));
|
||||||
|
Gftest.Eq__str(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user