Skip to content

Commit 1f86413

Browse files
committed
fix(levers): update deployment tasks for copy-free resource resolution
1 parent 8264748 commit 1f86413

File tree

4 files changed

+120
-129
lines changed

4 files changed

+120
-129
lines changed

src/rime/lever/customizer.cc

-5
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,4 @@ bool Customizer::UpdateConfigFile() {
147147
return true;
148148
}
149149

150-
bool Customizer::TrashCustomizedCopy() {
151-
// TODO: unimplemented
152-
return false;
153-
}
154-
155150
} // namespace rime

src/rime/lever/customizer.h

-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ class Customizer {
2121
// DEPRECATED: in favor of auto-patch config compiler plugin
2222
bool UpdateConfigFile();
2323

24-
bool TrashCustomizedCopy();
25-
2624
protected:
2725
boost::filesystem::path source_path_;
2826
boost::filesystem::path dest_path_;

src/rime/lever/deployment_tasks.cc

+118-122
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
#include <boost/uuid/uuid.hpp>
1111
#include <boost/uuid/uuid_io.hpp>
1212
#include <rime/common.h>
13+
#include <rime/resource.h>
1314
#include <rime/schema.h>
15+
#include <rime/service.h>
1416
#include <rime/setup.h>
1517
#include <rime/ticket.h>
1618
#include <rime/algo/utilities.h>
1719
#include <rime/dict/dictionary.h>
1820
#include <rime/dict/dict_compiler.h>
19-
#include <rime/lever/customizer.h>
2021
#include <rime/lever/deployment_tasks.h>
2122
#include <rime/lever/user_dict_manager.h>
2223
#ifdef _WIN32
@@ -115,22 +116,18 @@ bool WorkspaceUpdate::Run(Deployer* deployer) {
115116
the<DeploymentTask> t;
116117
t.reset(new ConfigFileUpdate("default.yaml", "config_version"));
117118
t->Run(deployer);
118-
// since brise 0.18
119119
t.reset(new ConfigFileUpdate("symbols.yaml", "config_version"));
120120
t->Run(deployer);
121121
t.reset(new SymlinkingPrebuiltDictionaries);
122122
t->Run(deployer);
123123
}
124124

125-
fs::path user_data_path(deployer->user_data_dir);
126-
fs::path default_config_path(user_data_path / "default.yaml");
127-
Config config;
128-
if (!config.LoadFromFile(default_config_path.string())) {
129-
LOG(ERROR) << "Error loading default config from '"
130-
<< default_config_path.string() << "'.";
125+
the<Config> config(Config::Require("config")->Create("default"));
126+
if (!config) {
127+
LOG(ERROR) << "Error loading default config.";
131128
return false;
132129
}
133-
auto schema_list = config.GetList("schema_list");
130+
auto schema_list = config->GetList("schema_list");
134131
if (!schema_list) {
135132
LOG(WARNING) << "schema list not defined.";
136133
return false;
@@ -140,90 +137,60 @@ bool WorkspaceUpdate::Run(Deployer* deployer) {
140137
int success = 0;
141138
int failure = 0;
142139
map<string, string> schemas;
143-
for (auto it = schema_list->begin(); it != schema_list->end(); ++it) {
144-
auto item = As<ConfigMap>(*it);
145-
if (!item)
146-
continue;
147-
auto schema_property = item->GetValue("schema");
148-
if (!schema_property)
149-
continue;
150-
const string& schema_id(schema_property->str());
140+
the<ResourceResolver> resolver(
141+
Service::instance().CreateResourceResolver({
142+
"schema", "", ".schema.yaml"
143+
}));
144+
auto build_schema = [&](const string& schema_id) {
145+
if (schemas.find(schema_id) != schemas.end()) // already built
146+
return;
151147
LOG(INFO) << "schema: " << schema_id;
152148
string schema_path;
153149
if (schemas.find(schema_id) == schemas.end()) {
154-
schema_path = GetSchemaPath(deployer, schema_id, true);
150+
schema_path = resolver->ResolvePath(schema_id).string();
155151
schemas[schema_id] = schema_path;
156152
}
157153
else {
158154
schema_path = schemas[schema_id];
159155
}
160156
if (schema_path.empty()) {
161157
LOG(WARNING) << "missing schema file for '" << schema_id << "'.";
162-
continue;
158+
return;
163159
}
164-
// build schema
165160
the<DeploymentTask> t(new SchemaUpdate(schema_path));
166161
if (t->Run(deployer))
167162
++success;
168163
else
169164
++failure;
170-
}
171-
// find dependencies
172-
for (auto s = schemas.cbegin(); s != schemas.cend(); ++s) {
173-
Config schema_config;
174-
// user could have customized dependencies in the resulting schema
175-
string user_schema_path = GetSchemaPath(deployer, s->first, false);
176-
if (!schema_config.LoadFromFile(user_schema_path))
165+
};
166+
auto schema_component = Config::Require("schema");
167+
for (auto it = schema_list->begin(); it != schema_list->end(); ++it) {
168+
auto item = As<ConfigMap>(*it);
169+
if (!item)
177170
continue;
178-
auto dependencies = schema_config.GetList("schema/dependencies");
179-
if (!dependencies)
171+
auto schema_property = item->GetValue("schema");
172+
if (!schema_property)
180173
continue;
181-
for (auto d = dependencies->begin(); d != dependencies->end(); ++d) {
182-
auto dependency = As<ConfigValue>(*d);
183-
if (!dependency)
184-
continue;
185-
string dependency_id(dependency->str());
186-
if (schemas.find(dependency_id) != schemas.end()) // already built
187-
continue;
188-
LOG(INFO) << "new dependency: " << dependency_id;
189-
string dependency_path = GetSchemaPath(deployer, dependency_id, true);
190-
schemas[dependency_id] = dependency_path;
191-
if (dependency_path.empty()) {
192-
LOG(WARNING) << "missing schema file for dependency '" << dependency_id << "'.";
193-
continue;
174+
const string& schema_id = schema_property->str();
175+
build_schema(schema_id);
176+
the<Config> schema_config(schema_component->Create(schema_id));
177+
if (!schema_config)
178+
continue;
179+
if (auto dependencies = schema_config->GetList("schema/dependencies")) {
180+
for (auto d = dependencies->begin(); d != dependencies->end(); ++d) {
181+
auto dependency = As<ConfigValue>(*d);
182+
if (!dependency)
183+
continue;
184+
const string& dependency_id = dependency->str();
185+
build_schema(dependency_id);
194186
}
195-
// build dependency
196-
the<DeploymentTask> t(new SchemaUpdate(dependency_path));
197-
if (t->Run(deployer))
198-
++success;
199-
else
200-
++failure;
201187
}
202188
}
203189
LOG(INFO) << "finished updating schemas: "
204190
<< success << " success, " << failure << " failure.";
205191
return failure == 0;
206192
}
207193

208-
string WorkspaceUpdate::GetSchemaPath(Deployer* deployer,
209-
const string& schema_id,
210-
bool prefer_shared_copy) {
211-
fs::path schema_path;
212-
if (prefer_shared_copy) {
213-
fs::path shared_data_path(deployer->shared_data_dir);
214-
schema_path = shared_data_path / (schema_id + ".schema.yaml");
215-
if (!fs::exists(schema_path))
216-
schema_path.clear();
217-
}
218-
if (schema_path.empty()) {
219-
fs::path user_data_path(deployer->user_data_dir);
220-
schema_path = user_data_path / (schema_id + ".schema.yaml");
221-
if (!fs::exists(schema_path))
222-
schema_path.clear();
223-
}
224-
return schema_path.string();
225-
}
226-
227194
SchemaUpdate::SchemaUpdate(TaskInitializer arg) : verbose_(false) {
228195
try {
229196
schema_file_ = boost::any_cast<string>(arg);
@@ -233,6 +200,43 @@ SchemaUpdate::SchemaUpdate(TaskInitializer arg) : verbose_(false) {
233200
}
234201
}
235202

203+
static bool IsCustomizedCopy(const string& file_name);
204+
205+
static bool TrashCustomizedCopy(const fs::path& shared_copy,
206+
const fs::path& user_copy,
207+
const string& version_key,
208+
const fs::path& trash) {
209+
if (fs::equivalent(shared_copy, user_copy))
210+
return false;
211+
if (IsCustomizedCopy(user_copy.string())) {
212+
string shared_copy_version;
213+
string user_copy_version;
214+
Config shared_config;
215+
if (shared_config.LoadFromFile(shared_copy.string())) {
216+
shared_config.GetString(version_key, &shared_copy_version);
217+
}
218+
Config user_config;
219+
if (user_config.LoadFromFile(user_copy.string()) &&
220+
user_config.GetString(version_key, &user_copy_version)) {
221+
size_t custom_version_suffix = user_copy_version.find(".custom.");
222+
if (custom_version_suffix != string::npos) {
223+
user_copy_version.erase(custom_version_suffix);
224+
}
225+
}
226+
if (CompareVersionString(shared_copy_version, user_copy_version) >= 0) {
227+
fs::path backup = trash / user_copy.filename();
228+
boost::system::error_code ec;
229+
fs::rename(user_copy, backup, ec);
230+
if (ec) {
231+
LOG(ERROR) << "error trashing file " << user_copy.string();
232+
return false;
233+
}
234+
return true;
235+
}
236+
}
237+
return false;
238+
}
239+
236240
bool SchemaUpdate::Run(Deployer* deployer) {
237241
fs::path source_path(schema_file_);
238242
if (!fs::exists(source_path)) {
@@ -241,37 +245,33 @@ bool SchemaUpdate::Run(Deployer* deployer) {
241245
return false;
242246
}
243247
string schema_id;
244-
{
245-
Config source;
246-
if (!source.LoadFromFile(schema_file_) ||
247-
!source.GetString("schema/schema_id", &schema_id) ||
248-
schema_id.empty()) {
249-
LOG(ERROR) << "invalid schema definition in '" << schema_file_ << "'.";
250-
return false;
251-
}
248+
the<Config> config(new Config);
249+
if (!config->LoadFromFile(schema_file_) ||
250+
!config->GetString("schema/schema_id", &schema_id) ||
251+
schema_id.empty()) {
252+
LOG(ERROR) << "invalid schema definition in '" << schema_file_ << "'.";
253+
return false;
252254
}
253255
fs::path shared_data_path(deployer->shared_data_dir);
254256
fs::path user_data_path(deployer->user_data_dir);
255257
fs::path destination_path(user_data_path / (schema_id + ".schema.yaml"));
256-
Customizer customizer(source_path, destination_path, "schema/version");
257-
if (customizer.TrashCustomizedCopy()) {
258-
LOG(INFO) << "patched copy of schema '" << schema_id << "' is moved to trash";
258+
fs::path trash = user_data_path / "trash";
259+
if (TrashCustomizedCopy(source_path,
260+
destination_path,
261+
"schema/version",
262+
trash)) {
263+
LOG(INFO) << "patched copy of schema '" << schema_id
264+
<< "' is moved to trash";
259265
}
260266

261-
Schema schema(schema_id, new Config);
262-
Config* config = schema.config();
263-
if (!config || !config->LoadFromFile(destination_path.string())) {
264-
LOG(ERROR) << "Error loading schema file '"
265-
<< destination_path.string() << "'.";
266-
return false;
267-
}
268267
string dict_name;
269268
if (!config->GetString("translator/dictionary", &dict_name)) {
270269
// not requiring a dictionary
271270
return true;
272271
}
273-
DictionaryComponent component;
274-
the<Dictionary> dict(component.Create({&schema, "translator"}));
272+
Schema schema(schema_id, config.release());
273+
the<Dictionary> dict(
274+
Dictionary::Require("dictionary")->Create({&schema, "translator"}));
275275
if (!dict) {
276276
LOG(ERROR) << "Error creating dictionary '" << dict_name << "'.";
277277
return false;
@@ -281,7 +281,7 @@ bool SchemaUpdate::Run(Deployer* deployer) {
281281
if (verbose_) {
282282
dict_compiler.set_options(DictCompiler::kRebuild | DictCompiler::kDump);
283283
}
284-
if (!dict_compiler.Compile(destination_path.string())) {
284+
if (!dict_compiler.Compile(schema_file_)) {
285285
LOG(ERROR) << "dictionary '" << dict_name << "' failed to compile.";
286286
return false;
287287
}
@@ -305,13 +305,18 @@ bool ConfigFileUpdate::Run(Deployer* deployer) {
305305
fs::path user_data_path(deployer->user_data_dir);
306306
fs::path source_config_path(shared_data_path / file_name_);
307307
fs::path dest_config_path(user_data_path / file_name_);
308+
fs::path trash = user_data_path / "trash";
308309
if (!fs::exists(source_config_path)) {
309310
LOG(WARNING) << "'" << file_name_
310311
<< "' is missing from shared data directory.";
311-
source_config_path = dest_config_path;
312+
return false;
313+
}
314+
if (TrashCustomizedCopy(source_config_path,
315+
dest_config_path,
316+
version_key_,
317+
trash)) {
318+
LOG(INFO) << "patched copy of '" << file_name_ << "' is moved to trash.";
312319
}
313-
Customizer customizer(source_config_path, dest_config_path, version_key_);
314-
customizer.TrashCustomizedCopy();
315320
return true;
316321
}
317322

@@ -341,15 +346,16 @@ bool SymlinkingPrebuiltDictionaries::Run(Deployer* deployer) {
341346
fs::equivalent(shared_data_path, user_data_path))
342347
return false;
343348
bool success = false;
344-
// test existing link
349+
// remove symlinks to shared data files created by previous version
345350
for (fs::directory_iterator test(user_data_path), end;
346351
test != end; ++test) {
347352
fs::path entry(test->path());
348-
if (fs::is_symlink(entry) && entry.extension().string() == ".bin") {
353+
if (fs::is_symlink(entry)) {
349354
try {
350-
if (!fs::exists(entry)) {
351-
LOG(INFO) << "removing dangling symlink: "
352-
<< entry.filename().string();
355+
auto target_path = fs::canonical(entry);
356+
if (target_path.has_parent_path() &&
357+
fs::equivalent(shared_data_path, target_path.parent_path())) {
358+
LOG(INFO) << "removing symlink: " << entry.filename().string();
353359
fs::remove(entry);
354360
}
355361
}
@@ -359,24 +365,6 @@ bool SymlinkingPrebuiltDictionaries::Run(Deployer* deployer) {
359365
}
360366
}
361367
}
362-
// create link
363-
for (fs::directory_iterator iter(shared_data_path), end;
364-
iter != end; ++iter) {
365-
fs::path entry(iter->path());
366-
fs::path link(user_data_path / entry.filename());
367-
try {
368-
if (fs::is_regular_file(entry) &&
369-
entry.extension().string() == ".bin" &&
370-
!fs::exists(link)) {
371-
LOG(INFO) << "symlinking '" << entry.filename().string() << "'.";
372-
fs::create_symlink(entry, link);
373-
}
374-
}
375-
catch (const fs::filesystem_error& ex) {
376-
LOG(ERROR) << ex.what();
377-
success = false;
378-
}
379-
}
380368
return success;
381369
}
382370

@@ -402,6 +390,19 @@ bool UserDictSync::Run(Deployer* deployer) {
402390
return mgr.SynchronizeAll();
403391
}
404392

393+
static bool IsCustomizedCopy(const string& file_name) {
394+
if (boost::ends_with(file_name, ".yaml") &&
395+
!boost::ends_with(file_name, ".custom.yaml")) {
396+
Config config;
397+
string checksum;
398+
if (config.LoadFromFile(file_name) &&
399+
config.GetString("customization", &checksum)) {
400+
return true;
401+
}
402+
}
403+
return false;
404+
}
405+
405406
bool BackupConfigFiles::Run(Deployer* deployer) {
406407
LOG(INFO) << "backing up config files.";
407408
fs::path user_data_path(deployer->user_data_dir);
@@ -433,14 +434,9 @@ bool BackupConfigFiles::Run(Deployer* deployer) {
433434
++latest; // already up-to-date
434435
continue;
435436
}
436-
if (is_yaml_file && !boost::ends_with(entry.string(), ".custom.yaml")) {
437-
Config config;
438-
string checksum;
439-
if (config.LoadFromFile(entry.string()) &&
440-
config.GetString("customization", &checksum)) {
441-
++skipped; // customized copy
442-
continue;
443-
}
437+
if (is_yaml_file && IsCustomizedCopy(entry.string())) {
438+
++skipped; // customized copy
439+
continue;
444440
}
445441
boost::system::error_code ec;
446442
fs::copy_file(entry, backup, fs::copy_option::overwrite_if_exists, ec);

0 commit comments

Comments
 (0)