Initial commit
This commit is contained in:
commit
3273579297
4
.envrc
Normal file
4
.envrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
# reload when these files change
|
||||
export TRITON_DONT_SOURCE_PROFILE=1
|
||||
watch_file flake.nix
|
||||
use_flake
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.direnv
|
134
fix-conflicts.ts
Normal file
134
fix-conflicts.ts
Normal file
|
@ -0,0 +1,134 @@
|
|||
(async () => {
|
||||
const dir = '/home/ben/Nextcloud';
|
||||
|
||||
const DRY_RUN = false;
|
||||
const BATCH_SIZE = 16;
|
||||
const ENCRYPTED_CONTENT_STRING = 'HBEGIN:oc_encryption_module:OC_DEFAULT_MODULE:cipher';
|
||||
const CONFLICTED_COPY_REGEX = /.*( \(conflicted copy \d{4}-\d{2}-\d{2} \d+\))(\.[^\.]*)?/;
|
||||
|
||||
const p = Deno.run({
|
||||
cmd: ['bash', '-c', `find ${dir} -type f | grep conflicted\\ copy`],
|
||||
stdout: 'piped',
|
||||
});
|
||||
|
||||
const output = await p.output();
|
||||
p.close();
|
||||
|
||||
const outputStr = (new TextDecoder()).decode(output);
|
||||
const fileNames = [...new Set(outputStr.split('\n').filter(s => !!s))];
|
||||
|
||||
const totalFiles = fileNames.length;
|
||||
let filesSuccess = 0;
|
||||
let fileData = [];
|
||||
|
||||
for (let i = 0; i < totalFiles; i += BATCH_SIZE) {
|
||||
fileData = [
|
||||
...fileData,
|
||||
...(await Promise.all(fileNames.slice(i, i + BATCH_SIZE).map(async (conflictedFileName, index) => {
|
||||
const conflictedNameMatch = conflictedFileName.match(CONFLICTED_COPY_REGEX);
|
||||
if (!conflictedNameMatch) {
|
||||
return `[${conflictedFileName}] encountered regex error`;
|
||||
}
|
||||
const conflictString = conflictedNameMatch[1];
|
||||
const nonConflictedFileName = conflictedFileName.replace(conflictString, '');
|
||||
|
||||
const conflictedFile = await Deno.open(conflictedFileName, { read: true });
|
||||
const conflictedFileInfo = await Deno.fstat(conflictedFile.rid);
|
||||
const normalFile = await Deno.open(nonConflictedFileName, { read: true }).catch(() => null);
|
||||
if (!normalFile) {
|
||||
if (!DRY_RUN) {
|
||||
// Only the conflicted file exists, just move it to the non-conflict filename
|
||||
await Deno.rename(conflictedFileName, nonConflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] only conflicted exists. Move to non-conflict filename`;
|
||||
}
|
||||
const normalFileInfo = await Deno.fstat(normalFile.rid);
|
||||
conflictedFile.close();
|
||||
normalFile.close();
|
||||
|
||||
const shaP = Deno.run({
|
||||
cmd: ['sha256sum', nonConflictedFileName, conflictedFileName],
|
||||
stdout: 'piped',
|
||||
});
|
||||
|
||||
const shaOutputStr = (new TextDecoder()).decode(await shaP.output());
|
||||
const shaOutputs = shaOutputStr.split('\n');
|
||||
const normalSha = shaOutputs[0].split(' ')[0];
|
||||
const conflictedSha = shaOutputs[1].split(' ')[0];
|
||||
|
||||
shaP.close();
|
||||
|
||||
if (normalSha === conflictedSha) {
|
||||
if (!DRY_RUN) {
|
||||
// They're the same, remove the conflicted file
|
||||
await Deno.remove(conflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] conflict and non-conflict have the same contents, remove the conflict`;
|
||||
}
|
||||
|
||||
const headP = Deno.run({
|
||||
cmd: ['head', '-c', '64', nonConflictedFileName, conflictedFileName],
|
||||
stdout: 'piped',
|
||||
});
|
||||
|
||||
const headOutputStr = (new TextDecoder()).decode(await headP.output());
|
||||
const headOutputs = headOutputStr.split('\n');
|
||||
const normalHead = headOutputs[1].split(' ')[0];
|
||||
const conflictedHead = headOutputs[3].split(' ')[0];
|
||||
|
||||
headP.close();
|
||||
|
||||
const normalEncrypted = normalHead.startsWith(ENCRYPTED_CONTENT_STRING);
|
||||
const conflictedEncrypted = conflictedHead.startsWith(ENCRYPTED_CONTENT_STRING);
|
||||
|
||||
if (normalEncrypted && conflictedEncrypted) {
|
||||
console.error("Both files encrypted differently!");
|
||||
console.error(nonConflictedFileName, conflictedFileName);
|
||||
if (!DRY_RUN) {
|
||||
// Whatever, deleted the conflicted one
|
||||
await Deno.remove(conflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] both are encrypted but with different contents. We'll remove the conflict`;
|
||||
}
|
||||
|
||||
if (normalEncrypted) {
|
||||
if (!DRY_RUN) {
|
||||
// delete normal
|
||||
await Deno.remove(nonConflictedFileName);
|
||||
await Deno.rename(conflictedFileName, nonConflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] the non-conflict is encrypted. Remove it and move the conflicted file in its place`;
|
||||
}
|
||||
|
||||
if (conflictedEncrypted) {
|
||||
if (!DRY_RUN) {
|
||||
// delete conflicted
|
||||
await Deno.remove(conflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] the conflict is encrypted. Remove it and keep the normal file`;
|
||||
}
|
||||
|
||||
if (normalFileInfo.mtime > conflictedFileInfo.mtime) {
|
||||
if (!DRY_RUN) {
|
||||
// delete conflicted
|
||||
await Deno.remove(conflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] conflict is older than the non-conflict. Remove the conflict`;
|
||||
}
|
||||
|
||||
if (!DRY_RUN) {
|
||||
// delete normal
|
||||
await Deno.remove(nonConflictedFileName);
|
||||
await Deno.rename(conflictedFileName, nonConflictedFileName);
|
||||
}
|
||||
return `[${conflictedFileName}] non-conflict is older than the conflict. Remove the non-conflict`;
|
||||
}).map(p => p.then((msg) => {
|
||||
filesSuccess++;
|
||||
console.log(`[${filesSuccess}/${totalFiles}] ${msg}`);
|
||||
return msg;
|
||||
})))),
|
||||
];
|
||||
}
|
||||
|
||||
// console.log(fileData);
|
||||
})();
|
67
flake.lock
Normal file
67
flake.lock
Normal file
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"nodes": {
|
||||
"devshell": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1671489820,
|
||||
"narHash": "sha256-qoei5HDJ8psd1YUPD7DhbHdhLIT9L2nadscp4Qk37uk=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "5aa3a8039c68b4bf869327446590f4cdf90bb634",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1673796341,
|
||||
"narHash": "sha256-1kZi9OkukpNmOaPY7S5/+SlCDOuYnP3HkXHvNDyLQcc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6dccdc458512abce8d19f74195bb20fdb067df50",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devshell": "devshell",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
27
flake.nix
Normal file
27
flake.nix
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
devshell.url = "github:numtide/devshell";
|
||||
devshell.inputs.flake-utils.follows = "flake-utils";
|
||||
devshell.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, devshell, flake-utils, nixpkgs }:
|
||||
flake-utils.lib.simpleFlake {
|
||||
inherit self nixpkgs;
|
||||
name = "fix-nc-encrypted-file-conflicts";
|
||||
preOverlays = [ devshell.overlay ];
|
||||
shell = { pkgs }:
|
||||
pkgs.devshell.mkShell {
|
||||
devshell.packages = with pkgs; [
|
||||
deno
|
||||
];
|
||||
bash.extra = ''
|
||||
export NVIM_USE_DENOLS=1
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue