robocopy 이동은 같은 파일도 포함 (/IS) (217)

관리자 지시 (Windows 실제 확인): 대상에 같은 파일이 있으면 robocopy /MOVE 는 건너뛰고 원본에 남긴다 (종료 코드 0 → "옮겼습니다").
이동일 때 /IS 를 붙여 옮긴다 (사용자가 이미 넣었으면 그대로). 속성만 다른 "수정됨" 파일은 /IS · /IT 로도 남아, 216 의 "원본에 남음" 으로 알린다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_mkv
RyuJongJin 2026-10-11 22:43:31 +09:00
parent b0d7f021f7
commit 64ce867612
3 changed files with 20 additions and 2 deletions

View File

@ -113,6 +113,9 @@ List<List<String>> robocopyRuns({
final extra = [
if (bandwidthKBps > 0 && !opts.any((o) => o.toUpperCase().startsWith('/IPG'))) '/IPG:${robocopyIpg(bandwidthKBps)}',
if (move) '/MOVE',
// 217: 대상에 같은 파일이 있으면 robocopy 는 건너뛰고 원본에 남긴다 (종료 코드 0 - "옮겼습니다" 인데 남음, Windows 에서 확인).
// 이동은 같은 파일도 포함 (/IS) 해 원본에서 지운다. 속성만 다른 것 (Tweaked) 등 그래도 남는 것은 이동 뒤 다시 세어 알린다 (216)
if (move && !opts.any((o) => o.toUpperCase() == '/IS')) '/IS',
];
final runs = <List<String>>[
for (final f in folders) [f, contents ? dest : p.join(dest, p.basename(f)), ...opts, ...extra],

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/app/transfer_job.dart';
import 'package:jj_mkvmaker/core/sync_tools.dart' show CopyMethod;
import 'package:jj_mkvmaker/core/webdav.dart';
import 'package:path/path.dart' as p;
@ -94,6 +95,20 @@ void main() {
expect(rsyncFailureText(12, ['rsync error: error in rsync protocol data stream (code 12)'], const []), isNot(contains('원본 파일을 지우지')));
});
test('217: robocopy 이동 - 대상에 같은 파일이 있어도 원본에서 지운다 (예전에는 남기고 "옮겼습니다")', () async {
if (!Platform.isWindows) return;
// robocopy 가 "같음" 으로 보는 파일 (탐색기 · Copy-Item 복사처럼 속성까지 같은 것)
final r = Process.runSync('powershell', ['-NoProfile', '-Command', "Copy-Item -LiteralPath '${p.join(src, 'a.txt')}' -Destination '${p.join(dst, 'a.txt')}'"]);
expect(r.exitCode, 0);
final job = TransferJob(sources: [src], dest: dst, move: true, contents: true, method: CopyMethod.robocopy, options: '/E');
await job.run();
expect(job.error, isNull);
expect(File(p.join(src, 'a.txt')).existsSync(), isFalse, reason: '같은 파일도 옮김');
expect(File(p.join(dst, 'a.txt')).readAsStringSync(), 'a');
expect(job.leftInSource, 0);
// (속성만 다른 "수정됨" 파일은 /IS · /IT 로도 남는다 - 그때는 216 의 "n개는 원본에 남음" 으로 알린다)
});
group('214 b: WebDAV', () {
late Directory remote;
late TestDavServer server;

View File

@ -61,8 +61,8 @@ void main() {
bandwidthKBps: 640,
move: true,
);
expect(runs[0], [r'C:\a\movies', p.join(r'E:\dst', 'movies'), '/E', '/R:2', '/IPG:100', '/MOVE']);
expect(runs[1], [r'C:\b', r'E:\dst', '1.mkv', '2.mkv', '/R:2', '/IPG:100', '/MOV']); // 파일만: /E 빼고 /MOV
expect(runs[0], [r'C:\a\movies', p.join(r'E:\dst', 'movies'), '/E', '/R:2', '/IPG:100', '/MOVE', '/IS']);
expect(runs[1], [r'C:\b', r'E:\dst', '1.mkv', '2.mkv', '/R:2', '/IPG:100', '/MOV', '/IS']); // 파일만: /E 빼고 /MOV. 217: 이동은 같은 파일도 (/IS)
expect(runs[2].sublist(0, 3), [r'C:\c', r'E:\dst', '3.mkv']);
expect(robocopyIpg(0), 0);
});