236{
239 {
241 }
242
244
245 std::size_t countRecentUpdates = 0;
246 std::size_t countArchivedUpdates = 0;
247
248
249 for (auto const& entry : applied)
251 ++countRecentUpdates;
252 else
253 ++countArchivedUpdates;
254
255
257 for (auto& entry : applied)
258 hashToName.insert(std::make_pair(entry.second.hash, entry.first));
259
260 std::size_t importedUpdates = 0;
261
263 {
264 auto filePath = sqlFile.first;
265 auto fileState = sqlFile.second;
266
267 LOG_DEBUG(
"sql.updates",
"Checking update \"{}\"...", filePath.filename().generic_string());
268
269 AppliedFileStorage::const_iterator iter = applied.find(filePath.filename().string());
270 if (iter != applied.end())
271 {
272
273 if (!redundancyChecks)
274 {
275 LOG_DEBUG(
"sql.updates",
">> Update is already applied, skipping redundancy checks.");
276 applied.erase(iter);
277 return;
278 }
279
280
281 if (!archivedRedundancy && (iter->second.state ==
ARCHIVED) && (sqlFile.second ==
ARCHIVED))
282 {
283 LOG_DEBUG(
"sql.updates",
">> Update is archived and marked as archived in database, skipping redundancy checks.");
284 applied.erase(iter);
285 return;
286 }
287 }
288
290
292
293
294 if (iter == applied.end())
295 {
296
297 HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash);
298 if (hashIter != hashToName.end())
299 {
300
301 LocaleFileStorage::const_iterator localeIter;
302
303
304 for (localeIter = available.begin(); (localeIter != available.end()) &&
305 (localeIter->first.filename().string() != hashIter->second); ++localeIter);
306
307
308 if (localeIter != available.end())
309 {
310 LOG_WARN(
"sql.updates",
">> It seems like the update \"{}\" \'{}\' was renamed, but the old file is still there! " \
311 "Treating it as a new file! (It is probably an unmodified copy of the file \"{}\")",
312 filePath.filename().string(), hash.substr(0, 7),
313 localeIter->first.filename().string());
314 }
315 else
316 {
317 LOG_INFO(
"sql.updates",
">> Renaming update \"{}\" to \"{}\" \'{}\'.",
318 hashIter->second, filePath.filename().string(), hash.substr(0, 7));
319
320 RenameEntry(hashIter->second, filePath.filename().string());
321 applied.erase(hashIter->second);
322 return;
323 }
324 }
325
326 else
327 {
328 LOG_INFO(
"sql.updates",
">> Applying update \"{}\" \'{}\'...",
329 filePath.filename().string(), hash.substr(0, 7));
330 }
331 }
332
333 else if (allowRehash && iter->second.hash.empty())
334 {
336
337 LOG_INFO(
"sql.updates",
">> Re-hashing update \"{}\" \'{}\'...", filePath.filename().string(),
338 hash.substr(0, 7));
339 }
340 else
341 {
342
343 if (iter->second.hash != hash)
344 {
345 LOG_INFO(
"sql.updates",
">> Reapplying update \"{}\" \'{}\' -> \'{}\' (it changed)...", filePath.filename().string(),
346 iter->second.hash.substr(0, 7), hash.substr(0, 7));
347 }
348 else
349 {
350
351 if (iter->second.state != fileState)
352 {
353 LOG_DEBUG(
"sql.updates",
">> Updating the state of \"{}\" to \'{}\'...",
355
356 UpdateState(filePath.filename().string(), fileState);
357 }
358
359 LOG_DEBUG(
"sql.updates",
">> Update is already applied and matches the hash \'{}\'.", hash.substr(0, 7));
360
361 applied.erase(iter);
362 return;
363 }
364 }
365
367 AppliedFileEntry const file = { filePath.filename().string(), hash, fileState, 0 };
368
369 switch (mode)
370 {
372 speed =
Apply(filePath);
373 [[fallthrough]];
376 break;
377 }
378
379 if (iter != applied.end())
380 applied.erase(iter);
381
383 ++importedUpdates;
384 };
385
386
387 for (auto const& availableQuery : available)
388 {
389 if (availableQuery.second !=
CUSTOM && availableQuery.second !=
MODULE)
390 ApplyUpdateFile(availableQuery);
391 }
392
393
394 for (auto const& availableQuery : available)
395 {
396 if (availableQuery.second ==
CUSTOM || availableQuery.second ==
MODULE)
397 ApplyUpdateFile(availableQuery);
398 }
399
400
402 {
403 bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast<size_t>(cleanDeadReferencesMaxCount));
404
406 for (auto const& entry : applied)
407 {
408 if (entry.second.state !=
MODULE)
409 {
411 ">> The file \'{}\' was applied to the database, but is missing in"
412 " your update directory now!",
413 entry.first);
414
415 if (doCleanup)
416 {
417 LOG_INFO(
"sql.updates",
"Deleting orphaned entry \'{}\'...", entry.first);
418 toCleanup.insert(entry);
419 }
420 }
421 }
422
423 if (!toCleanup.empty())
424 {
425 if (doCleanup)
427 else
428 {
430 "Cleanup is disabled! There were {} dirty files applied to your database, "
431 "but they are now missing in your source directory!",
432 toCleanup.size());
433 }
434 }
435 }
436
437 return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates);
438}
#define LOG_INFO(filterType__,...)
Definition: Log.h:165
#define LOG_ERROR(filterType__,...)
Definition: Log.h:157
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:169
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition: Util.h:381
static Digest GetDigestOf(uint8 const *data, std::size_t len)
Definition: CryptoHash.h:48
Definition: UpdateFetcher.h:30
uint32 Apply(Path const &path) const
Definition: UpdateFetcher.cpp:440
LocaleFileStorage GetFileList() const
Definition: UpdateFetcher.cpp:64
void UpdateState(std::string const &name, State const state) const
Definition: UpdateFetcher.cpp:505
UpdateMode
Definition: UpdateFetcher.h:66
std::string ReadSQLUpdate(Path const &file) const
Definition: UpdateFetcher.cpp:208
void UpdateEntry(AppliedFileEntry const &entry, uint32 const speed=0) const
Definition: UpdateFetcher.cpp:454
void RenameEntry(std::string const &from, std::string const &to) const
Definition: UpdateFetcher.cpp:463
std::unordered_map< std::string, std::string > HashToFileNameStorage
Definition: UpdateFetcher.h:134
AppliedFileStorage ReceiveAppliedFiles() const
Definition: UpdateFetcher.cpp:185
void CleanUp(AppliedFileStorage const &storage) const
Definition: UpdateFetcher.cpp:482