diff --git a/lib/core/archive_ops.dart b/lib/core/archive_ops.dart index b2ff067..f60b752 100644 --- a/lib/core/archive_ops.dart +++ b/lib/core/archive_ops.dart @@ -8,6 +8,7 @@ import 'package:path/path.dart' as p; import '../l10n/tr.dart'; import 'file_ops.dart' show NameConflict, nameProblem; import '../services/platform_info.dart'; +import 'files/same_file.dart'; /// 86: 압축 종류 (확장자로) enum ArchiveKind { zip, sevenZip, rar } @@ -142,9 +143,8 @@ class ExtractResult { /// 덮어쓰기에서 건너뛸지: 받는 쪽 파일이 압축 안의 것보다 2초 넘게 새것 bool _targetNewer(String target, DateTime? modified) { - if (modified == null) return false; try { - return File(target).lastModifiedSync().isAfter(modified.add(const Duration(seconds: 2))); + return SameFile.keepNewer(skipNewer: true, targetModified: File(target).lastModifiedSync(), modified: modified); } catch (_) { return false; } diff --git a/lib/core/files/any_transfer.dart b/lib/core/files/any_transfer.dart index 6b8368c..f3f92aa 100644 --- a/lib/core/files/any_transfer.dart +++ b/lib/core/files/any_transfer.dart @@ -95,7 +95,7 @@ Future> anyCopy(TransferControl c, List sources, String des // 229: 합치는 폴더 안에서 받는 쪽이 더 새것이면 예전 것으로 덮지 않는다 (WebDAV 도 로컬과 같게) if (inner && c.skipNewerInMerge) { final t = await vStat(target); - if (t != null && !t.isDir && SameFile.targetNewer(t.modified, st.modified)) { + if (t != null && !t.isDir && SameFile.keepNewer(skipNewer: true, targetModified: t.modified, modified: st.modified)) { c.keptNewer.add(src); return; } diff --git a/lib/core/files/local_transfer.dart b/lib/core/files/local_transfer.dart index 069919d..d965b3d 100644 --- a/lib/core/files/local_transfer.dart +++ b/lib/core/files/local_transfer.dart @@ -129,7 +129,7 @@ Future _deleteExcept(String dir, Set keep) async { Future isNewerThere(String src, String target) async { final t = File(target); if (!await t.exists()) return false; - return SameFile.targetNewer(await t.lastModified(), await File(src).lastModified()); + return SameFile.keepNewer(skipNewer: true, targetModified: await t.lastModified(), modified: await File(src).lastModified()); } /// 229: 같은 이름 창 - 폴더를 합치면 안쪽에서 받는 쪽이 더 새 파일 수 ([limit] 개까지 셈, 로컬만) diff --git a/lib/core/files/same_file.dart b/lib/core/files/same_file.dart index af42443..ed83566 100644 --- a/lib/core/files/same_file.dart +++ b/lib/core/files/same_file.dart @@ -24,4 +24,9 @@ class SameFile { /// 받는 쪽이 [window] 넘게 더 새것인지 (-u 건너뛰기 · 미리 보기 "더 새 것" 표시) static bool targetNewer(DateTime targetModified, DateTime modified) => targetModified.isAfter(modified.add(window)); + + /// modular_sync #4 CopyPolicy: 환경 설정 "받는 쪽이 더 새것이면 건너뛰기" ([skipNewer], 229) 로 받는 쪽을 그대로 둘지. + /// 폴더 합치기 (로컬 · 원격) · 압축 풀기 (덮어쓰기) 가 모두 이것을 부른다 (robocopy 는 /XO, rsync 는 -u 로 같은 일). 받는 쪽이 없으면 false + static bool keepNewer({required bool skipNewer, required DateTime? targetModified, required DateTime? modified}) => + skipNewer && targetModified != null && modified != null && targetNewer(targetModified, modified); } diff --git a/lib/core/name_clash.dart b/lib/core/name_clash.dart index 79eb59c..0d87b1c 100644 --- a/lib/core/name_clash.dart +++ b/lib/core/name_clash.dart @@ -1,6 +1,7 @@ import '../l10n/tr.dart'; import 'file_ops.dart' show formatSize; import 'vfs.dart' show vBasename; +import 'files/same_file.dart'; /// 약속: 같은 이름 비교 글 ([clashCompareText]) · 파일 날짜 글 ([fileDateText]). 순수 함수, 오류 없음. /// 탐색기 복사 확인 창 · 끌어 놓기 · 붙여넣기가 함께 쓴다. @@ -15,9 +16,9 @@ String clashCompareText(NameClash x) { final h = x.here, t = x.there; final newer = h == null || h.modified.year <= 1 || t.modified.year <= 1 ? '' - : h.modified.isAfter(t.modified.add(const Duration(seconds: 2))) + : SameFile.targetNewer(h.modified, t.modified) ? tr(' (보낼 것이 더 새것)') - : t.modified.isAfter(h.modified.add(const Duration(seconds: 2))) + : SameFile.targetNewer(t.modified, h.modified) ? tr(' (있는 것이 더 새것)') : tr(' (바뀐 날 같음)'); return '${vBasename(x.src)}: ${trf('보낼 것 {0} / 있는 것 {1}', [h == null ? '?' : one(h), one(t)])}$newer'; diff --git a/test/same_file_contract_test.dart b/test/same_file_contract_test.dart index a739d7e..b81863e 100644 --- a/test/same_file_contract_test.dart +++ b/test/same_file_contract_test.dart @@ -26,6 +26,15 @@ void main() { expect([SameFile.forAppSync(remote: true, move: false).uploadTime, SameFile.forAppSync(remote: true, move: true).uploadTime, SameFile.forAppSync(remote: false, move: false).uploadTime], [true, false, false]); expect([SameFile.targetNewer(t0.add(const Duration(seconds: 3)), t0), SameFile.targetNewer(t0.add(const Duration(seconds: 2)), t0)], [true, false]); + // #4 CopyPolicy: 설정이 켜져 있고 받는 쪽이 2초 넘게 새것일 때만 그대로 둠 · 시각을 모르면 덮음 + final later = t0.add(const Duration(minutes: 1)); + expect([ + SameFile.keepNewer(skipNewer: true, targetModified: later, modified: t0), + SameFile.keepNewer(skipNewer: false, targetModified: later, modified: t0), + SameFile.keepNewer(skipNewer: true, targetModified: t0, modified: later), + SameFile.keepNewer(skipNewer: true, targetModified: null, modified: t0), + SameFile.keepNewer(skipNewer: true, targetModified: later, modified: null), + ], [true, false, false, false, false]); }); group('미리 보기 = 실제 맞추기 (받는 쪽 같은 크기 · 1분 더 새것)', () {