zip.dart 3.44 KB
Newer Older
Devon Carew's avatar
Devon Carew committed
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'dart:async';

Devon Carew's avatar
Devon Carew committed
7 8
import 'package:archive/archive.dart';

9
import 'base/file_system.dart';
Devon Carew's avatar
Devon Carew committed
10
import 'base/process.dart';
11
import 'devfs.dart';
Devon Carew's avatar
Devon Carew committed
12 13 14 15 16 17 18 19 20 21 22 23

abstract class ZipBuilder {
  factory ZipBuilder() {
    if (exitsHappy(<String>['which', 'zip'])) {
      return new _ZipToolBuilder();
    } else {
      return new _ArchiveZipBuilder();
    }
  }

  ZipBuilder._();

24
  Map<String, DevFSContent> entries = <String, DevFSContent>{};
Devon Carew's avatar
Devon Carew committed
25

26
  Future<Null> createZip(File outFile, Directory zipBuildDir);
Devon Carew's avatar
Devon Carew committed
27 28 29 30 31
}

class _ArchiveZipBuilder extends ZipBuilder {
  _ArchiveZipBuilder() : super._();

32
  @override
33
  Future<Null> createZip(File outFile, Directory zipBuildDir) async {
34
    final Archive archive = new Archive();
Devon Carew's avatar
Devon Carew committed
35

36 37 38
    final Completer<Null> finished = new Completer<Null>();
    int count = entries.length;
    entries.forEach((String archivePath, DevFSContent content) {
39
      content.contentsAsBytes().then<Null>((List<int> data) {
40
        archive.addFile(new ArchiveFile.noCompress(archivePath, data.length, data));
41
        count -= 1;
42 43 44 45 46
        if (count == 0)
          finished.complete();
      });
    });
    await finished.future;
Devon Carew's avatar
Devon Carew committed
47

48
    final List<int> zipData = new ZipEncoder().encode(archive);
49
    await outFile.writeAsBytes(zipData);
Devon Carew's avatar
Devon Carew committed
50 51 52 53 54 55
  }
}

class _ZipToolBuilder extends ZipBuilder {
  _ZipToolBuilder() : super._();

56
  @override
57
  Future<Null> createZip(File outFile, Directory zipBuildDir) async {
58 59
    // If there are no assets, then create an empty zip file.
    if (entries.isEmpty) {
60
      final List<int> zipData = new ZipEncoder().encode(new Archive());
61
      await outFile.writeAsBytes(zipData);
62 63 64
      return;
    }

Devon Carew's avatar
Devon Carew committed
65 66 67 68 69 70 71
    if (outFile.existsSync())
      outFile.deleteSync();

    if (zipBuildDir.existsSync())
      zipBuildDir.deleteSync(recursive: true);
    zipBuildDir.createSync(recursive: true);

72 73 74
    final Completer<Null> finished = new Completer<Null>();
    int count = entries.length;
    entries.forEach((String archivePath, DevFSContent content) {
75
      content.contentsAsBytes().then<Null>((List<int> data) {
76
        final File file = fs.file(fs.path.join(zipBuildDir.path, archivePath));
77
        file.parent.createSync(recursive: true);
78 79
        file.writeAsBytes(data).then<Null>((File value) {
          count -= 1;
80 81 82 83 84 85 86 87 88
          if (count == 0)
            finished.complete();
        });
      });
    });
    await finished.future;

    final Iterable<String> compressedNames = _getCompressedNames();
    if (compressedNames.isNotEmpty) {
89
      await runCheckedAsync(
90
        <String>['zip', '-q', outFile.absolute.path]..addAll(compressedNames),
91
        workingDirectory: zipBuildDir.path
92 93 94
      );
    }

95 96
    final Iterable<String> storedNames = _getStoredNames();
    if (storedNames.isNotEmpty) {
97
      await runCheckedAsync(
98
        <String>['zip', '-q', '-0', outFile.absolute.path]..addAll(storedNames),
99
        workingDirectory: zipBuildDir.path
100 101
      );
    }
Devon Carew's avatar
Devon Carew committed
102 103
  }

104 105
  static const List<String> _kNoCompressFileExtensions = const <String>['.png', '.jpg'];

106
  bool isAssetCompressed(String archivePath) {
107
    return !_kNoCompressFileExtensions.any(
108
        (String extension) => archivePath.endsWith(extension)
109 110 111
    );
  }

112
  Iterable<String> _getCompressedNames() => entries.keys.where(isAssetCompressed);
Devon Carew's avatar
Devon Carew committed
113

114 115
  Iterable<String> _getStoredNames() => entries.keys
      .where((String archivePath) => !isAssetCompressed(archivePath));
Devon Carew's avatar
Devon Carew committed
116
}