assets.dart 3.96 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:pool/pool.dart';

import '../../asset.dart';
import '../../base/file_system.dart';
import '../../devfs.dart';
10
import '../../globals.dart' as globals;
11
import '../build_system.dart';
12
import '../depfile.dart';
13 14
import 'dart.dart';
import 'icon_tree_shaker.dart';
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

/// A helper function to copy an asset bundle into an [environment]'s output
/// directory.
///
/// Returns a [Depfile] containing all assets used in the build.
Future<Depfile> copyAssets(Environment environment, Directory outputDirectory) async {
  final File pubspecFile =  environment.projectDir.childFile('pubspec.yaml');
  final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
  await assetBundle.build(
    manifestPath: pubspecFile.path,
    packagesPath: environment.projectDir.childFile('.packages').path,
  );
  final Pool pool = Pool(kMaxOpenFiles);
  final List<File> inputs = <File>[
    // An asset manifest with no assets would have zero inputs if not
    // for this pubspec file.
    pubspecFile,
  ];
  final List<File> outputs = <File>[];
34 35 36 37 38 39 40 41 42 43

  final IconTreeShaker iconTreeShaker = IconTreeShaker(
    environment,
    assetBundle.entries[kFontManifestJson] as DevFSStringContent,
    processManager: globals.processManager,
    logger: globals.logger,
    fileSystem: globals.fs,
    artifacts: globals.artifacts,
  );

44 45 46 47
  await Future.wait<void>(
    assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
      final PoolResource resource = await pool.request();
      try {
Dan Field's avatar
Dan Field committed
48 49
        // This will result in strange looking files, for example files with `/`
        // on Windows or files that end up getting URI encoded such as `#.ext`
50
        // to `%23.ext`. However, we have to keep it this way since the
Dan Field's avatar
Dan Field committed
51 52
        // platform channels in the framework will URI encode these values,
        // and the native APIs will look for files this way.
53
        final File file = globals.fs.file(globals.fs.path.join(outputDirectory.path, entry.key));
54 55 56 57
        outputs.add(file);
        file.parent.createSync(recursive: true);
        final DevFSContent content = entry.value;
        if (content is DevFSFileContent && content.file is File) {
58
          inputs.add(globals.fs.file(content.file.path));
59 60 61 62 63 64 65
          if (!await iconTreeShaker.subsetFont(
            inputPath: content.file.path,
            outputPath: file.path,
            relativePath: entry.key,
          )) {
            await (content.file as File).copy(file.path);
          }
66 67 68 69 70 71 72
        } else {
          await file.writeAsBytes(await entry.value.contentsAsBytes());
        }
      } finally {
        resource.release();
      }
  }));
73
  return Depfile(inputs + assetBundle.additionalDependencies, outputs);
74 75
}

76 77 78
/// Copy the assets defined in the flutter manifest into a build directory.
class CopyAssets extends Target {
  const CopyAssets();
79

80 81 82 83
  @override
  String get name => 'copy_assets';

  @override
84 85 86
  List<Target> get dependencies => const <Target>[
    KernelSnapshot(),
  ];
87 88 89 90

  @override
  List<Source> get inputs => const <Source>[
    Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/assets.dart'),
91
    ...IconTreeShaker.inputs,
92 93 94
  ];

  @override
95 96 97 98 99
  List<Source> get outputs => const <Source>[];

  @override
  List<String> get depfiles => const <String>[
    'flutter_assets.d'
100 101 102
  ];

  @override
103
  Future<void> build(Environment environment) async {
104 105 106 107
    final Directory output = environment
      .buildDir
      .childDirectory('flutter_assets');
    output.createSync(recursive: true);
108
    final Depfile depfile = await copyAssets(environment, output);
109 110 111 112 113 114 115 116 117
    final DepfileService depfileService = DepfileService(
      fileSystem: globals.fs,
      logger: globals.logger,
      platform: globals.platform,
    );
    depfileService.writeToFile(
      depfile,
      environment.buildDir.childFile('flutter_assets.d'),
    );
118 119
  }
}