blob: d1929cb1d39ef582b9156fcb78ce8c5d18c007e2 [file] [log] [blame]
// 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.
import 'dart:io';
import 'package:archive/archive.dart';
import 'package:path/path.dart' as path;
import 'asset.dart';
import 'base/process.dart';
abstract class ZipBuilder {
factory ZipBuilder() {
if (exitsHappy(<String>['which', 'zip'])) {
return new _ZipToolBuilder();
} else {
return new _ArchiveZipBuilder();
}
}
ZipBuilder._();
List<AssetBundleEntry> entries = <AssetBundleEntry>[];
void addEntry(AssetBundleEntry entry) => entries.add(entry);
void createZip(File outFile, Directory zipBuildDir);
}
class _ArchiveZipBuilder extends ZipBuilder {
_ArchiveZipBuilder() : super._();
@override
void createZip(File outFile, Directory zipBuildDir) {
Archive archive = new Archive();
for (AssetBundleEntry entry in entries) {
List<int> data = entry.contentsAsBytes();
archive.addFile(new ArchiveFile.noCompress(entry.archivePath, data.length, data));
}
List<int> zipData = new ZipEncoder().encode(archive);
outFile.writeAsBytesSync(zipData);
}
}
class _ZipToolBuilder extends ZipBuilder {
_ZipToolBuilder() : super._();
@override
void createZip(File outFile, Directory zipBuildDir) {
// If there are no assets, then create an empty zip file.
if (entries.isEmpty) {
List<int> zipData = new ZipEncoder().encode(new Archive());
outFile.writeAsBytesSync(zipData);
return;
}
if (outFile.existsSync())
outFile.deleteSync();
if (zipBuildDir.existsSync())
zipBuildDir.deleteSync(recursive: true);
zipBuildDir.createSync(recursive: true);
for (AssetBundleEntry entry in entries) {
List<int> data = entry.contentsAsBytes();
File file = new File(path.join(zipBuildDir.path, entry.archivePath));
file.parent.createSync(recursive: true);
file.writeAsBytesSync(data);
}
if (_getCompressedNames().isNotEmpty) {
runCheckedSync(
<String>['zip', '-q', outFile.absolute.path]..addAll(_getCompressedNames()),
workingDirectory: zipBuildDir.path
);
}
if (_getStoredNames().isNotEmpty) {
runCheckedSync(
<String>['zip', '-q', '-0', outFile.absolute.path]..addAll(_getStoredNames()),
workingDirectory: zipBuildDir.path
);
}
}
static const List<String> _kNoCompressFileExtensions = const <String>['.png', '.jpg'];
bool isAssetCompressed(AssetBundleEntry entry) {
return !_kNoCompressFileExtensions.any(
(String extension) => entry.archivePath.endsWith(extension)
);
}
Iterable<String> _getCompressedNames() {
return entries
.where(isAssetCompressed)
.map((AssetBundleEntry entry) => entry.archivePath);
}
Iterable<String> _getStoredNames() {
return entries
.where((AssetBundleEntry entry) => !isAssetCompressed(entry))
.map((AssetBundleEntry entry) => entry.archivePath);
}
}