JJ_MKVMaker/lib/core/file_ops.dart

89 lines
5.1 KiB
Dart

import 'files/any_transfer.dart';
import 'files/local_transfer.dart' as local;
import 'files/name_ops.dart';
import 'files/transfer_control.dart';
import 'files/transfer_guard.dart';
import 'rsync_filter.dart';
import 'vfs.dart';
export 'files/file_listing.dart' show FileEntry, SortBy, sortEntries, listEntries, searchFiles, formatSize;
export 'files/windows_drives.dart' show windowsDrives, driveType, isNetworkDrive, uncRoot;
export 'files/path_rules.dart'
show
NameConflict,
uniqueTarget,
samePath,
shortUnder,
isSameOrInside,
outermostPaths,
transferProblem,
isPartialFile,
isAppTempName,
appTempRsyncExcludes,
appTempRobocopyExcludes;
export 'files/name_ops.dart' show nameProblem, usesWindowsNames;
export 'files/transfer_guard.dart' show FileOpCancelled, SourceUnreadableException, ensureSourceForDelete, removeEmptyDirs;
export 'files/transfer_control.dart' show CopyProgress;
// 약속 (나누기 file_ops): 파일 탐색기 (X-plore 참고) 의 화면과 상관없는 부분 - 부르는 곳은 이 파일 하나만 가져온다.
// 일은 lib/core/files/ 의 모듈이 한다: file_listing (폴더 읽기 · 정렬 · 찾기) · windows_drives · path_rules · name_ops ·
// transfer_guard · transfer_control · local_transfer (로컬끼리) · any_transfer (원격이 섞임).
// [FileOps]: 입력 = 설정 (속도 제한 · 알림 · 같은 이름 처리), 원본들 · 받는 폴더. 출력 = 만든 경로 · 복사한 수.
// 오류 = 취소 [FileOpCancelled] · 원본을 읽지 못함 [SourceUnreadableException] · 파일 오류 (FileSystemException · DavException) 그대로.
/// 복사 · 이동 · 삭제. [cancel] 을 부르면 다음 조각에서 멈춘다. 한쪽이라도 원격 (WebDAV 등) 이면 어느 저장소든 판으로
class FileOps extends TransferControl {
FileOps({
super.bandwidthKBps,
super.onFileDone,
super.onBytes,
super.conflict,
super.onSettled,
super.skipNewerInMerge,
});
/// 한쪽이라도 WebDAV 면 어느 저장소든 판으로
static bool _anyDav(Iterable<String> paths) => paths.any(isDav);
/// 전체 크기 (진행률용)
static Future<int> totalSize(List<String> paths) => _anyDav(paths) ? anyTotalSize(paths) : local.localTotalSize(paths);
/// [sources] 를 [destDir] 로 복사 (같은 이름이 있으면 "이름 (2)"). 만든 경로들을 돌려준다.
Future<List<String>> copy(List<String> sources, String destDir, {CopyProgress? onProgress}) => _anyDav([...sources, destDir])
? anyCopy(this, sources, destDir, onProgress: onProgress)
: local.localCopy(this, sources, destDir, onProgress: onProgress);
/// 229: [target] 이 있고 [src] 보다 2초 넘게 새것인지
static Future<bool> isNewerThere(String src, String target) => local.isNewerThere(src, target);
/// 229: 같은 이름 창 - 폴더를 합치면 안쪽에서 받는 쪽이 더 새 파일 수 ([limit] 개까지 셈, 로컬만)
static Future<int> countNewerInside(String src, String dst, {int limit = 5000}) =>
local.countNewerInside(src, dst, limit: limit);
/// 이동: 같은 드라이브면 이름 바꾸기, 아니면 복사한 뒤 원본 삭제
Future<List<String>> move(List<String> sources, String destDir, {CopyProgress? onProgress}) => _anyDav([...sources, destDir])
? anyMove(this, sources, destDir, onProgress: onProgress)
: local.localMove(this, sources, destDir, onProgress: onProgress);
/// 동기화 (실시간 동기화 · lsyncd 처럼): [srcDir] 의 내용을 [dstDir] 에 맞춘다.
/// 크기나 바뀐 시각이 다른 파일만 복사, [delete] 면 원본에 없는 것을 대상에서 지운다. 복사한 파일 수를 돌려준다.
///
/// [update] (rsync -u): 대상이 더 새 파일이면 건너뛴다 (양쪽 ⇄ 을 함께 맞출 때 서로 덮어쓰지 않게).
/// [strict] (214, 이동): 같음은 크기 + 바뀐 때 (±2초) 로만. 느슨하게 같아 보이는 것 (WebDAV 의 "대상이 더 새것") 은 다시 보낸다
/// [filter] (관리자 지시 10/19, M2 의 본 고침): rsync 옵션의 거르기 - 원격 (앱이 직접 맞춤) 도 미리 보기와 같은 규칙을 따른다
Future<int> mirror(String srcDir, String dstDir,
{bool delete = false, bool update = false, bool allowEmptySource = false, bool strict = false, RsyncFilter filter = RsyncFilter.none}) async {
// 지우기 포함이면 원본을 확실히 읽을 수 있을 때만 (읽지 못하면 원본이 빈 것으로 보여 대상이 모두 지워졌다)
if (delete) await ensureSourceForDelete(srcDir, dstDir, allowEmpty: allowEmptySource);
if (_anyDav([srcDir, dstDir])) return anyMirror(this, srcDir, dstDir, delete: delete, update: update, strict: strict, filter: filter);
return local.localMirror(this, srcDir, dstDir, delete: delete, update: update);
}
Future<void> delete(List<String> paths) => local.deletePaths(this, paths);
/// 이름 바꾸기 (같은 폴더 안). 새 경로를 돌려준다.
static Future<String> rename(String path, String newName) => renameInPlace(path, newName);
static Future<String> makeFolder(String dir, String name) => createFolder(dir, name);
}