10
10
#include < boost/uuid/uuid.hpp>
11
11
#include < boost/uuid/uuid_io.hpp>
12
12
#include < rime/common.h>
13
+ #include < rime/resource.h>
13
14
#include < rime/schema.h>
15
+ #include < rime/service.h>
14
16
#include < rime/setup.h>
15
17
#include < rime/ticket.h>
16
18
#include < rime/algo/utilities.h>
17
19
#include < rime/dict/dictionary.h>
18
20
#include < rime/dict/dict_compiler.h>
19
- #include < rime/lever/customizer.h>
20
21
#include < rime/lever/deployment_tasks.h>
21
22
#include < rime/lever/user_dict_manager.h>
22
23
#ifdef _WIN32
@@ -115,22 +116,18 @@ bool WorkspaceUpdate::Run(Deployer* deployer) {
115
116
the<DeploymentTask> t;
116
117
t.reset (new ConfigFileUpdate (" default.yaml" , " config_version" ));
117
118
t->Run (deployer);
118
- // since brise 0.18
119
119
t.reset (new ConfigFileUpdate (" symbols.yaml" , " config_version" ));
120
120
t->Run (deployer);
121
121
t.reset (new SymlinkingPrebuiltDictionaries);
122
122
t->Run (deployer);
123
123
}
124
124
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." ;
131
128
return false ;
132
129
}
133
- auto schema_list = config. GetList (" schema_list" );
130
+ auto schema_list = config-> GetList (" schema_list" );
134
131
if (!schema_list) {
135
132
LOG (WARNING) << " schema list not defined." ;
136
133
return false ;
@@ -140,90 +137,60 @@ bool WorkspaceUpdate::Run(Deployer* deployer) {
140
137
int success = 0 ;
141
138
int failure = 0 ;
142
139
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 ;
151
147
LOG (INFO) << " schema: " << schema_id;
152
148
string schema_path;
153
149
if (schemas.find (schema_id) == schemas.end ()) {
154
- schema_path = GetSchemaPath (deployer, schema_id, true );
150
+ schema_path = resolver-> ResolvePath ( schema_id). string ( );
155
151
schemas[schema_id] = schema_path;
156
152
}
157
153
else {
158
154
schema_path = schemas[schema_id];
159
155
}
160
156
if (schema_path.empty ()) {
161
157
LOG (WARNING) << " missing schema file for '" << schema_id << " '." ;
162
- continue ;
158
+ return ;
163
159
}
164
- // build schema
165
160
the<DeploymentTask> t (new SchemaUpdate (schema_path));
166
161
if (t->Run (deployer))
167
162
++success;
168
163
else
169
164
++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)
177
170
continue ;
178
- auto dependencies = schema_config. GetList (" schema/dependencies " );
179
- if (!dependencies )
171
+ auto schema_property = item-> GetValue (" schema" );
172
+ if (!schema_property )
180
173
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);
194
186
}
195
- // build dependency
196
- the<DeploymentTask> t (new SchemaUpdate (dependency_path));
197
- if (t->Run (deployer))
198
- ++success;
199
- else
200
- ++failure;
201
187
}
202
188
}
203
189
LOG (INFO) << " finished updating schemas: "
204
190
<< success << " success, " << failure << " failure." ;
205
191
return failure == 0 ;
206
192
}
207
193
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
-
227
194
SchemaUpdate::SchemaUpdate (TaskInitializer arg) : verbose_(false ) {
228
195
try {
229
196
schema_file_ = boost::any_cast<string>(arg);
@@ -233,6 +200,43 @@ SchemaUpdate::SchemaUpdate(TaskInitializer arg) : verbose_(false) {
233
200
}
234
201
}
235
202
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
+
236
240
bool SchemaUpdate::Run (Deployer* deployer) {
237
241
fs::path source_path (schema_file_);
238
242
if (!fs::exists (source_path)) {
@@ -241,37 +245,33 @@ bool SchemaUpdate::Run(Deployer* deployer) {
241
245
return false ;
242
246
}
243
247
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 ;
252
254
}
253
255
fs::path shared_data_path (deployer->shared_data_dir );
254
256
fs::path user_data_path (deployer->user_data_dir );
255
257
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" ;
259
265
}
260
266
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
- }
268
267
string dict_name;
269
268
if (!config->GetString (" translator/dictionary" , &dict_name)) {
270
269
// not requiring a dictionary
271
270
return true ;
272
271
}
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" }));
275
275
if (!dict) {
276
276
LOG (ERROR) << " Error creating dictionary '" << dict_name << " '." ;
277
277
return false ;
@@ -281,7 +281,7 @@ bool SchemaUpdate::Run(Deployer* deployer) {
281
281
if (verbose_) {
282
282
dict_compiler.set_options (DictCompiler::kRebuild | DictCompiler::kDump );
283
283
}
284
- if (!dict_compiler.Compile (destination_path. string () )) {
284
+ if (!dict_compiler.Compile (schema_file_ )) {
285
285
LOG (ERROR) << " dictionary '" << dict_name << " ' failed to compile." ;
286
286
return false ;
287
287
}
@@ -305,13 +305,18 @@ bool ConfigFileUpdate::Run(Deployer* deployer) {
305
305
fs::path user_data_path (deployer->user_data_dir );
306
306
fs::path source_config_path (shared_data_path / file_name_);
307
307
fs::path dest_config_path (user_data_path / file_name_);
308
+ fs::path trash = user_data_path / " trash" ;
308
309
if (!fs::exists (source_config_path)) {
309
310
LOG (WARNING) << " '" << file_name_
310
311
<< " ' 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." ;
312
319
}
313
- Customizer customizer (source_config_path, dest_config_path, version_key_);
314
- customizer.TrashCustomizedCopy ();
315
320
return true ;
316
321
}
317
322
@@ -341,15 +346,16 @@ bool SymlinkingPrebuiltDictionaries::Run(Deployer* deployer) {
341
346
fs::equivalent (shared_data_path, user_data_path))
342
347
return false ;
343
348
bool success = false ;
344
- // test existing link
349
+ // remove symlinks to shared data files created by previous version
345
350
for (fs::directory_iterator test (user_data_path), end;
346
351
test != end; ++test) {
347
352
fs::path entry (test->path ());
348
- if (fs::is_symlink (entry) && entry. extension (). string () == " .bin " ) {
353
+ if (fs::is_symlink (entry)) {
349
354
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 ();
353
359
fs::remove (entry);
354
360
}
355
361
}
@@ -359,24 +365,6 @@ bool SymlinkingPrebuiltDictionaries::Run(Deployer* deployer) {
359
365
}
360
366
}
361
367
}
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
- }
380
368
return success;
381
369
}
382
370
@@ -402,6 +390,19 @@ bool UserDictSync::Run(Deployer* deployer) {
402
390
return mgr.SynchronizeAll ();
403
391
}
404
392
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
+
405
406
bool BackupConfigFiles::Run (Deployer* deployer) {
406
407
LOG (INFO) << " backing up config files." ;
407
408
fs::path user_data_path (deployer->user_data_dir );
@@ -433,14 +434,9 @@ bool BackupConfigFiles::Run(Deployer* deployer) {
433
434
++latest; // already up-to-date
434
435
continue ;
435
436
}
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 ;
444
440
}
445
441
boost::system ::error_code ec;
446
442
fs::copy_file (entry, backup, fs::copy_option::overwrite_if_exists, ec);
0 commit comments