aboutsummaryrefslogtreecommitdiff
path: root/man/krino.conf.5
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 10:56:21 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 10:56:21 +0200
commit1506c7dcd6032c04c1df6f5785b6dd3dfe4511cc (patch)
treefb6d573ca8726c1b1d91ba273a284ba666cde3f6 /man/krino.conf.5
parentebdd7bb254a0f19f815a644d26ce232de7be0adb (diff)
downloadkrino-1506c7dcd6032c04c1df6f5785b6dd3dfe4511cc.tar.gz
krino-1506c7dcd6032c04c1df6f5785b6dd3dfe4511cc.zip
krino: duplicates are found, never deleted
A rule combining (duplicate) with a delete action is refused at load, and a file that is a duplicate under any duplicate scope its directory uses gets no delete step from any rule: the plan shows it skipped and the chain continues. A failed duplicate check blocks the delete too. Tests cover (matched), another rule's own condition, a test evaluation skipped, two scopes and a failed check, each checking every copy is still on disk.
Diffstat (limited to 'man/krino.conf.5')
-rw-r--r--man/krino.conf.5123
1 files changed, 72 insertions, 51 deletions
diff --git a/man/krino.conf.5 b/man/krino.conf.5
index fbd1c06..0778779 100644
--- a/man/krino.conf.5
+++ b/man/krino.conf.5
@@ -254,6 +254,20 @@ A rule with only
.Ic (stop)
is an exclusion: files it matches receive no actions from later rules.
.Pp
+A rule whose condition contains
+.Ic (duplicate)
+anywhere, including inside
+.Ic or
+or
+.Ic not ,
+cannot contain
+.Ic (delete)
+or
+.Ic (delete permanent) ;
+.Ic krino check
+and every run refuse it
+.Pq Sx DUPLICATES .
+.Pp
.Ar dest
is a directory: a relative path is relative to the root,
.Ql ~
@@ -462,6 +476,11 @@ its directory, and later steps use the new path;
.Ic delete
ends the chain, and steps after it are shown in the plan as
.Dq skipped: deleted by rule Ar x .
+A
+.Ic delete
+of a duplicate is itself skipped
+.Pq Sx DUPLICATES
+and does not end the chain.
.Pp
The plan warns when a chain moves a file more than once; that is usually
a missing
@@ -609,54 +628,62 @@ between
and
.Dq this should not exist twice
exists only in the user's intent, not in the files.
-Pairing
-.Ic (duplicate)
-with
-.Ic (delete)
-over a directory that may hold intentional copies
+A
+.Ic move
+rule over a directory that holds intentional copies
.Pq a mirror, a staging queue, anything another tool manages
-will delete things the user meant to keep.
-Keep such a rule on a directory scoped narrowly enough that every
-byte-identical pair in it really is an accident.
+will move things the user meant to keep there; keep such a rule on a
+directory scoped narrowly enough that every byte-identical pair in it really
+is an accident.
.Pp
-.Sy Warning:
-each
+.Sy Duplicates are found, never deleted.
+Deciding which copy to remove is left to the user, or to a tool built for it
+such as
+.Xr jdupes 1 .
+A rule combining
.Ic (duplicate)
-or
-.Ic (duplicate Ar dir )
-condition elects its own original from its own candidates; two conditions
-with different scopes can therefore elect
-.Em different
-originals for the same content.
-Within one directory's rules
-.Pq one rule combining conditions with Ic or , or two separate rules ,
-this can make every copy in a group selected by some condition, and with
-.Ic (delete permanent)
-every copy selected is gone for good.
-.Ic krino
-plans and applies one directory at a time, so a directory already applied
-in the run stays applied while a later directory is planned; a
-.Fl n
-run only ever plans, so it shows every directory's plan as if none of the
-others had been applied.
-Two files in different directories that a
-.Fl n
-plan each lists as a duplicate of the other are therefore not necessarily
-both deleted when the same run is applied with
-.Fl y :
-deleting the first can remove the very original the second file was a
-duplicate of, leaving the second no longer a duplicate by the time its own
-directory is planned.
-Use one duplicate scope for rules that delete within a directory; prefer
-.Ic (delete)
-to
-.Ic (delete permanent)
-with
-.Ic (duplicate) ;
-and within one directory's rules, two files each listed as a duplicate of
-the other in the
-.Fl n
-plan means both would be deleted.
+with a delete action is refused
+.Pq Sx RULES .
+And in a directory whose rules use
+.Ic (duplicate) ,
+a file that is a duplicate under any of the duplicate scopes those rules use
+\(em each distinct set of
+.Ar dir
+arguments, and the plain
+.Ic (duplicate) ,
+looked up for the file whether or not evaluation reached that test \(em gets
+no delete step from any rule.
+The plan shows the step as
+.Dq skipped: a duplicate is never deleted ,
+or, when that lookup fails,
+.Dq skipped: duplicate check failed, so not deleted: Ar reason ;
+the rest of the chain continues from the file's current path.
+This covers what the refusal cannot see: a later rule deleting through
+.Ic (matched)
+or through a condition of its own.
+.Pp
+Together they mean no rule can delete every copy of content a duplicate test
+in that directory can see.
+A file displaced by
+.Ic (on-conflict overwrite)
+is not covered; it goes to the trash, and
+.Ic krino undo
+restores it.
+.Pp
+The way to deal with duplicates is to move them aside and decide later:
+.Bd -literal -offset indent
+(rule "dupes"
+ (when (duplicate "~/docs/Archive"))
+ (move "~/.dupes/")
+ (stop))
+.Ed
+.Pp
+Every move is logged, so
+.Ic krino undo
+puts them back.
+Duplicate conditions with different scopes do not share an original, so two
+such rules can between them move every copy of a group aside; nothing is
+deleted.
.Sh KNOWN LIMITATIONS
A
.Ar dest
@@ -682,12 +709,6 @@ Give such a rule its own narrow
pattern, or a
.Ar dest
whose first path component is a literal string, when that matters.
-.Pp
-.Ic (duplicate)
-conditions with different scopes do not share an original: two conditions
-electing from different candidate sets can each treat a different file as
-the original of the same content
-.Pq Sx DUPLICATES .
.Sh SEE ALSO
.Xr krino 1
.Pp