From d7da812da678f425d9af3c88d713a225acdc247a Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:15:50 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B1=B0=EB=A5=B4=EA=B8=B0:=20"=EC=9D=B4?= =?UTF-8?q?=EB=A6=84/***"=20=EC=9D=84=20=EA=B2=BD=EB=A1=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=A4=20-=20"P=20keep/***"=20=EA=B0=80=20=EB=B0=9B?= =?UTF-8?q?=EB=8A=94=20=EC=AA=BD=EC=97=90=EB=A7=8C=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EC=95=88=EC=AA=BD=20=ED=8F=B4=EB=8D=94=EA=B9=8C=EC=A7=80=20?= =?UTF-8?q?=EC=A7=80=ED=82=B4=20(=EA=B2=80=ED=86=A0=20=EB=8C=80=EA=B8=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 28 확인 (10/20, c593440 독립 확인 22개 중 1개 - 안전한 쪽으로 다름): -a --delete --filter="R keep/extra.txt" --filter="P keep/***", 받는 쪽에만 keep/extra.txt · keep/sub/deep.txt 가 있으면 실제 rsync 는 keep/extra.txt 만 지우는데, 미리 보기 · 실시간 동기화의 묻는 목록은 keep/sub/ 까지 지운다고 보였다 (맞춘 뒤에도 지울 것으로 남음). 원인: "이름/***" 의 끝을 떼고 나면 패턴에 / 가 없어 이름으로만 맞췄다 - keep/sub 는 이름이 sub 라 맞지 않음. 원래 패턴에 / 가 있으므로 rsync 처럼 경로 (끝부분) 로 맞춘다. 보내는 쪽에서는 거른 폴더 안으로 내려가지 않아 드러나지 않았다. rsync_phsr_test 에 28 의 장면 (keep/k.txt · 받는 쪽 keep/extra.txt · keep/sub/deep.txt) 과 *** 장면 4개 - 고치기 전에는 32 · 33 번 실패. Co-Authored-By: Claude Opus 5.5 --- lib/core/rsync_filter.dart | 4 +++- test/rsync_phsr_test.dart | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/core/rsync_filter.dart b/lib/core/rsync_filter.dart index 724c332..bdf4760 100644 --- a/lib/core/rsync_filter.dart +++ b/lib/core/rsync_filter.dart @@ -203,7 +203,9 @@ class RsyncFilterRule { } final anchored = p.startsWith('/'); if (anchored) p = p.substring(1); - final whole = anchored || p.contains('/') || p.contains('**'); + // "이름/***" 은 원래 패턴에 / 가 있으므로 경로로 맞춘다 (28 확인 10/20: 이름으로만 맞추면 받는 쪽에만 있는 keep/sub 같은 + // 안쪽 폴더를 "P keep/***" 가 지키지 못해 미리 보기가 더 지운다고 보였다 - 거른 폴더 안으로 내려가지 않는 보내는 쪽에서는 드러나지 않음) + final whole = anchored || all || p.contains('/') || p.contains('**'); // rsync 의 wildmatch 는 바이트로 맞춘다 - 패턴 · 이름을 UTF-8 바이트 (한 글자 = 한 바이트) 로 바꿔 맞춘다 final body = _glob(_bytes(p)) + (all ? '(?:/.*)?' : ''); _re = RegExp(anchored ? '^$body\$' : whole ? '^(?:.*/)?$body\$' : '^$body\$'); diff --git a/test/rsync_phsr_test.dart b/test/rsync_phsr_test.dart index 43a1003..86587bd 100644 --- a/test/rsync_phsr_test.dart +++ b/test/rsync_phsr_test.dart @@ -24,7 +24,7 @@ import 'support/rsync_scenes.dart'; /// 보내는 쪽 (양쪽에 같은 이름이 많게 - H · S 는 보내기, P · R 은 지우기에 걸리게) const _src = [ 'a.txt', 'b.log', 'keep.log', 'both.txt', 'both.log', 'shared/x.txt', 'shared/y.log', 'build/x.o', 'build/sub/y.o', - 'sub/c.txt', 'sub/deep/d.txt', 'sub/deep/e.log', 'tmp/t.txt', '한글 폴더/가.txt', 'docs/r.md', 'z.txt', + 'sub/c.txt', 'sub/deep/d.txt', 'sub/deep/e.log', 'tmp/t.txt', '한글 폴더/가.txt', 'docs/r.md', 'z.txt', 'keep/k.txt', ]; /// 받는 쪽 (같은 이름은 크기가 달라 늘 바뀜 · 받는 쪽에만 있는 것은 지우기 대상) @@ -32,6 +32,8 @@ const _dst = [ 'a.txt', 'keep.log', 'both.txt', 'both.log', 'shared/x.txt', 'shared/onlyd.log', 'shared/onlyd.txt', 'build/old.o', 'old/keep.log', 'old/gone.txt', 'old2/deep/x/keep.log', 'old2/deep/x/g.txt', 'old2/e.txt', 'tmp/old.txt', 'extra.txt', 'extra.log', 'sub/deep/z.txt', '한글 폴더/나.txt', 'onlydst/a.bak', + // 28 확인 (10/20): 원본에도 있는 폴더 안의, 받는 쪽에만 있는 파일 · 하위 폴더 ("P keep/***" 가 안쪽까지 지키는지) + 'keep/extra.txt', 'keep/sub/deep.txt', ]; /// 규칙 장면 (지우기 포함이 많게 - 지우기가 데이터 쪽 위험) @@ -67,6 +69,11 @@ const phsrOptions = [ '-a --delete --filter="P shared/onlyd.*" --filter="H shared/"', '-a --filter="H *.log"', '-a --filter="P *.log" --exclude=*.txt', + // 28 확인 (10/20): "이름/***" 이 안쪽 (받는 쪽에만 있는 하위 폴더) 까지 + '-a --delete --filter="R keep/extra.txt" --filter="P keep/***"', + '-a --delete --filter="P keep/***"', + '-a --delete --exclude=keep/***', + '-a --delete --filter="H keep/***"', ]; void main() {