addDirectory method

Future<void> addDirectory(
  1. Directory dir, {
  2. bool followLinks = true,
  3. bool includeDirName = true,
  4. ZipFileProgress? filter,
})

Implementation

Future<void> addDirectory(Directory dir,
    {bool followLinks = true,
    bool includeDirName = true,
    ZipFileProgress? filter}) async {
  Stream<FileSystemEntity> files() async* {
    await for (final file
        in dir.list(recursive: true, followLinks: followLinks)) {
      if (file is File &&
          await FileSystemEntity.identical(file.path, tarPath)) {
        continue;
      }
      yield file;
    }
  }

  // A filter is given a progress fraction, which needs the count up front,
  // so the list is kept in that case, as it always was. Walking the tree
  // twice instead would double the directory reads, and a file added or
  // removed between the walks would put the fraction past 1 or short of it.
  // Without a filter the entries are handled as they are listed.
  final listed = filter != null ? await files().toList() : null;
  final numFiles = listed?.length ?? 0;

  final dirName = path.basename(dir.path);
  var fileCount = 0;
  await for (final file
      in listed != null ? Stream.fromIterable(listed) : files()) {
    final progress = numFiles == 0 ? 0.0 : ++fileCount / numFiles;
    if (filter != null) {
      final operation = filter(file, progress);
      if (operation == ZipFileOperation.cancel) {
        break;
      }
      if (operation == ZipFileOperation.skip) {
        continue;
      }
    }
    if (file is Directory) {
      var filename = path.relative(file.path, from: dir.path);
      filename = includeDirName ? '$dirName/$filename' : filename;
      final af = ArchiveFile.directory('$filename/');
      af.mode = (await file.stat()).mode;
      _encoder.add(af);
    } else if (file is File) {
      final dirName = path.basename(dir.path);
      final relPath = path.relative(file.path, from: dir.path);
      await addFile(file, includeDirName ? '$dirName/$relPath' : relPath);
    }
  }
}