Improved:

- The setting pane refined.
- We can enable `hidden files sync` with several initial behaviours: `Merge`, `Fetch` remote, and `Overwrite` remote.
- No longer `Touch hidden files`
This commit is contained in:
vorotamoroz
2023-04-11 12:45:24 +09:00
parent 6b2c7b56a5
commit 02c69b202e
2 changed files with 81 additions and 53 deletions

View File

@@ -215,7 +215,7 @@ export class HiddenFileSync extends LiveSyncCommands {
} }
//TODO: Tidy up. Even though it is experimental feature, So dirty... //TODO: Tidy up. Even though it is experimental feature, So dirty...
async syncInternalFilesAndDatabase(direction: "push" | "pull" | "safe", showMessage: boolean, files: InternalFileInfo[] | false = false, targetFiles: string[] | false = false) { async syncInternalFilesAndDatabase(direction: "push" | "pull" | "safe" | "pullForce" | "pushForce", showMessage: boolean, files: InternalFileInfo[] | false = false, targetFiles: string[] | false = false) {
await this.resolveConflictOnInternalFiles(); await this.resolveConflictOnInternalFiles();
const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO; const logLevel = showMessage ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO;
Logger("Scanning hidden files.", logLevel, "sync_internal"); Logger("Scanning hidden files.", logLevel, "sync_internal");
@@ -289,43 +289,43 @@ export class HiddenFileSync extends LiveSyncCommands {
p.push(addProc(async () => { p.push(addProc(async () => {
const xFileOnStorage = fileOnStorage; const xFileOnStorage = fileOnStorage;
const xfileOnDatabase = fileOnDatabase; const xFileOnDatabase = fileOnDatabase;
if (xFileOnStorage && xfileOnDatabase) { if (xFileOnStorage && xFileOnDatabase) {
// Both => Synchronize // Both => Synchronize
if (xfileOnDatabase.mtime == cache.docMtime && xFileOnStorage.mtime == cache.storageMtime) { if ((direction != "pullForce" && direction != "pushForce") && xFileOnDatabase.mtime == cache.docMtime && xFileOnStorage.mtime == cache.storageMtime) {
return; return;
} }
const nw = compareMTime(xFileOnStorage.mtime, xfileOnDatabase.mtime); const nw = compareMTime(xFileOnStorage.mtime, xFileOnDatabase.mtime);
if (nw > 0) { if (nw > 0 || direction == "pushForce") {
await this.storeInternalFileToDatabase(xFileOnStorage); await this.storeInternalFileToDatabase(xFileOnStorage);
} }
if (nw < 0) { if (nw < 0 || direction == "pullForce") {
// skip if not extraction performed. // skip if not extraction performed.
if (!await this.extractInternalFileFromDatabase(filename)) if (!await this.extractInternalFileFromDatabase(filename))
return; return;
} }
// If process successfully updated or file contents are same, update cache. // If process successfully updated or file contents are same, update cache.
cache.docMtime = xfileOnDatabase.mtime; cache.docMtime = xFileOnDatabase.mtime;
cache.storageMtime = xFileOnStorage.mtime; cache.storageMtime = xFileOnStorage.mtime;
caches[filename] = cache; caches[filename] = cache;
countUpdatedFolder(filename); countUpdatedFolder(filename);
} else if (!xFileOnStorage && xfileOnDatabase) { } else if (!xFileOnStorage && xFileOnDatabase) {
if (direction == "push") { if (direction == "push" || direction == "pushForce") {
if (xfileOnDatabase.deleted) if (xFileOnDatabase.deleted)
return; return;
await this.deleteInternalFileOnDatabase(filename, false); await this.deleteInternalFileOnDatabase(filename, false);
} else if (direction == "pull") { } else if (direction == "pull" || direction == "pullForce") {
if (await this.extractInternalFileFromDatabase(filename)) { if (await this.extractInternalFileFromDatabase(filename)) {
countUpdatedFolder(filename); countUpdatedFolder(filename);
} }
} else if (direction == "safe") { } else if (direction == "safe") {
if (xfileOnDatabase.deleted) if (xFileOnDatabase.deleted)
return; return;
if (await this.extractInternalFileFromDatabase(filename)) { if (await this.extractInternalFileFromDatabase(filename)) {
countUpdatedFolder(filename); countUpdatedFolder(filename);
} }
} }
} else if (xFileOnStorage && !xfileOnDatabase) { } else if (xFileOnStorage && !xFileOnDatabase) {
await this.storeInternalFileToDatabase(xFileOnStorage); await this.storeInternalFileToDatabase(xFileOnStorage);
} else { } else {
throw new Error("Invalid state on hidden file sync"); throw new Error("Invalid state on hidden file sync");
@@ -337,7 +337,7 @@ export class HiddenFileSync extends LiveSyncCommands {
await this.kvDB.set("diff-caches-internal", caches); await this.kvDB.set("diff-caches-internal", caches);
// When files has been retrieved from the database. they must be reloaded. // When files has been retrieved from the database. they must be reloaded.
if (direction == "pull" && filesChanged != 0) { if (direction == "pull" || direction == "pullForce" && filesChanged != 0) {
const configDir = normalizePath(this.app.vault.configDir); const configDir = normalizePath(this.app.vault.configDir);
// Show notification to restart obsidian when something has been changed in configDir. // Show notification to restart obsidian when something has been changed in configDir.
if (configDir in updatedFolders) { if (configDir in updatedFolders) {
@@ -468,7 +468,7 @@ export class HiddenFileSync extends LiveSyncCommands {
}; };
} else { } else {
if (isDocContentSame(old.data, content) && !forceWrite) { if (isDocContentSame(old.data, content) && !forceWrite) {
// Logger(`internal files STORAGE --> DB:${file.path}: Not changed`); // Logger(`STORAGE --> DB:${file.path}: (hidden) Not changed`, LOG_LEVEL.VERBOSE);
return; return;
} }
saveData = saveData =

View File

@@ -966,7 +966,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}); });
c.addClass("op-warn"); c.addClass("op-warn");
} }
containerSyncSettingEl.createEl("h3", { text: "Synchronization Methods" });
const syncLive: Setting[] = []; const syncLive: Setting[] = [];
const syncNonLive: Setting[] = []; const syncNonLive: Setting[] = [];
syncLive.push( syncLive.push(
@@ -1019,6 +1019,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
text.inputEl.setAttribute("type", "number"); text.inputEl.setAttribute("type", "number");
}), }),
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Sync on Save") .setName("Sync on Save")
.setDesc("When you save file, sync automatically") .setDesc("When you save file, sync automatically")
@@ -1060,7 +1061,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}) })
), ),
); );
containerSyncSettingEl.createEl("h3", { text: "File deletion" });
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Use Trash for deleted files") .setName("Use Trash for deleted files")
.setDesc("Do not delete files that are deleted in remote, just move to trash.") .setDesc("Do not delete files that are deleted in remote, just move to trash.")
@@ -1081,6 +1082,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}) })
); );
containerSyncSettingEl.createEl("h3", { text: "Conflict resolution" });
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Use newer file if conflicted (beta)") .setName("Use newer file if conflicted (beta)")
.setDesc("Resolve conflicts by newer files automatically.") .setDesc("Resolve conflicts by newer files automatically.")
@@ -1119,14 +1121,63 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}) })
); );
containerSyncSettingEl.createEl("h3", { text: "Hidden files" });
const LABEL_ENABLED = "🔁 : Enabled";
const LABEL_DISABLED = "⏹️ : Disabled"
const hiddenFileSyncSetting = new Setting(containerSyncSettingEl)
.setName("Hidden file synchronization")
const hiddenFileSyncSettingEl = hiddenFileSyncSetting.settingEl
const hiddenFileSyncSettingDiv = hiddenFileSyncSettingEl.createDiv("");
hiddenFileSyncSettingDiv.innerText = this.plugin.settings.syncInternalFiles ? LABEL_ENABLED : LABEL_DISABLED;
if (this.plugin.settings.syncInternalFiles) {
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Sync hidden files") .setName("Disable Hidden files sync")
.addToggle((toggle) => .addButton((button) => {
toggle.setValue(this.plugin.settings.syncInternalFiles).onChange(async (value) => { button.setButtonText("Disable")
this.plugin.settings.syncInternalFiles = value; .onClick(async () => {
this.plugin.settings.syncInternalFiles = false;
await this.plugin.saveSettings(); await this.plugin.saveSettings();
this.display();
}) })
); })
} else {
new Setting(containerSyncSettingEl)
.setName("Enable Hidden files sync")
.addButton((button) => {
button.setButtonText("Merge")
.onClick(async () => {
this.plugin.settings.syncInternalFiles = true;
this.display();
await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("safe", true);
await this.plugin.saveSettings();
this.display();
})
})
.addButton((button) => {
button.setButtonText("Fetch")
.onClick(async () => {
this.plugin.settings.syncInternalFiles = true;
this.display();
await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pullForce", true);
await this.plugin.saveSettings();
Logger(`Restarting the app is strongly recommended!`, LOG_LEVEL.NOTICE);
this.display();
})
})
.addButton((button) => {
button.setButtonText("Overwrite")
.onClick(async () => {
this.plugin.settings.syncInternalFiles = true;
this.display();
await this.plugin.addOnHiddenFileSync.syncInternalFilesAndDatabase("pushForce", true);
await this.plugin.saveSettings();
this.display();
})
});
}
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Scan for hidden files before replication") .setName("Scan for hidden files before replication")
@@ -1191,31 +1242,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}) })
}) })
new Setting(containerSyncSettingEl)
.setName("Touch hidden files")
.setDesc("Update the modified time of all hidden files to the current time.")
.addButton((button) =>
button
.setButtonText("Touch")
.setWarning()
.setDisabled(false)
.onClick(async () => {
const filesAll = await this.plugin.addOnHiddenFileSync.scanInternalFiles();
const targetFiles = await this.plugin.filterTargetFiles(filesAll);
const now = Date.now();
const newFiles = targetFiles.map(e => ({ ...e, mtime: now }));
let i = 0;
const maxFiles = newFiles.length;
for (const file of newFiles) {
i++;
Logger(`Touched:${file.path} (${i}/${maxFiles})`, LOG_LEVEL.NOTICE, "touch-files");
await this.plugin.applyMTimeToFile(file);
}
})
)
containerSyncSettingEl.createEl("h3", { containerSyncSettingEl.createEl("h3", {
text: sanitizeHTMLToDom(`Experimental`), text: sanitizeHTMLToDom(`Synchronization filters`),
}); });
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Regular expression to ignore files") .setName("Regular expression to ignore files")
@@ -1263,7 +1292,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
return text; return text;
} }
); );
containerSyncSettingEl.createEl("h3", { text: "Efficiency" });
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Chunk size") .setName("Chunk size")
.setDesc("Customize chunk size for binary files (0.1MBytes). This cannot be increased when using IBM Cloudant.") .setDesc("Customize chunk size for binary files (0.1MBytes). This cannot be increased when using IBM Cloudant.")
@@ -1282,7 +1311,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}); });
new Setting(containerSyncSettingEl) new Setting(containerSyncSettingEl)
.setName("Read chunks online.") .setName("Read chunks online")
.setDesc("If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.") .setDesc("If this option is enabled, LiveSync reads chunks online directly instead of replicating them locally. Increasing Custom chunk size is recommended.")
.addToggle((toggle) => { .addToggle((toggle) => {
toggle toggle
@@ -1292,8 +1321,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
await this.plugin.saveSettings(); await this.plugin.saveSettings();
}) })
return toggle; return toggle;
} });
);
containerSyncSettingEl.createEl("h3", { containerSyncSettingEl.createEl("h3", {
text: sanitizeHTMLToDom(`Advanced settings`), text: sanitizeHTMLToDom(`Advanced settings`),
}); });
@@ -1487,8 +1515,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
} }
} }
this.plugin.saveSettings(); this.plugin.saveSettings();
await this.plugin.realizeSettingSyncMode();
this.display(); this.display();
await this.plugin.realizeSettingSyncMode();
if (inWizard) { if (inWizard) {
// @ts-ignore // @ts-ignore
this.plugin.app.setting.close() this.plugin.app.setting.close()