| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // @dart = 2.8 |
| |
| /// Utilities and type definitions for interacting with a Fuchsia |
| /// `out/product_config.arch` directory, i.e. the build output directory. |
| library build; |
| |
| import 'dart:core'; |
| import 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| |
| /// Represents an output directory for a Fuchsia build. |
| class Build { |
| /// The absolute location of the build directory. |
| final Directory dir; |
| |
| Build(String buildDir) : dir = Directory(buildDir).absolute; |
| |
| /// Creates a `File` object from a path that is relative to the build |
| /// directory. Prefer to use this method to access files in the build; |
| /// this allows the codesize tool to be run in any working directory. |
| /// If path is already absolute, directly open that file. |
| File openFile(String pathInBuild) { |
| if (path.isAbsolute(pathInBuild)) { |
| return File(pathInBuild); |
| } |
| return dir / File(pathInBuild); |
| } |
| |
| /// Creates a `Directory` object from a path that is relative to the build |
| /// directory. Prefer to use this method to access directories in the build; |
| /// this allows the codesize tool to be run in any working directory. |
| /// If path is already absolute, directly open that directory. |
| Directory openDirectory(String pathInBuild) { |
| if (path.isAbsolute(pathInBuild)) { |
| return Directory(pathInBuild); |
| } |
| return dir / Directory(pathInBuild); |
| } |
| |
| /// Converts any path into one that is relative to the build directory. |
| /// Since some Fuchsia prebuilts are located outside the build directory, |
| /// this function intentionally allows those cases. |
| String rebasePath(String item) { |
| if (path.isAbsolute(item)) { |
| return path.relative(path.normalize(item), from: dir.path); |
| } else { |
| return path.normalize(item); |
| } |
| } |
| |
| /// Returns the blob manifest listing. |
| File blobManifestFile() => |
| openDirectory('obj/build/images') / File('blob.manifest'); |
| } |
| |
| extension SubDir on Directory { |
| /// Constructs a new `FileSystemEntity` located within this directory, |
| /// identified by the path component `sub`. |
| FileSystemEntity operator /(FileSystemEntity sub) { |
| String child = path.join(this.path, path.normalize(sub.path)); |
| final type = FileSystemEntity.typeSync(child); |
| switch (type) { |
| case FileSystemEntityType.directory: |
| return Directory(child); |
| case FileSystemEntityType.file: |
| case FileSystemEntityType.notFound: |
| if (sub is Directory) return Directory(child); |
| if (sub is File) return File(child); |
| throw Exception('Unsupported $sub type'); |
| default: |
| throw Exception('Unexpected type $type for $child'); |
| } |
| } |
| } |
| |
| /// An ELF object produced by the build. |
| /// It can either be a standalone blob, or a ELF contained within a |
| /// Zircon Boot Image (ZBI) blob, see `SubBlob`. |
| abstract class BuildArtifact implements Comparable { |
| /// Path to the file within the build directory. |
| String buildPath; |
| |
| /// Size of the blob on the compiling machine (host). |
| /// This is the uncompressed size. |
| int sizeOnHost; |
| |
| /// Favor standalone files over ones packaged in a zbi. |
| /// Favor in-tree over prebuilt. |
| @override |
| int compareTo(dynamic other) { |
| if (other is BuildArtifact) { |
| if (other is SubBlob && !(this is SubBlob)) return 1; |
| if (this is SubBlob && !(other is SubBlob)) return -1; |
| |
| final compLen = buildPath.length.compareTo(other.buildPath.length); |
| if (compLen != 0) return compLen; |
| return buildPath.compareTo(other.buildPath); |
| } else { |
| throw Exception('Cannot compare $this with $other'); |
| } |
| } |
| } |
| |
| class Blob extends BuildArtifact { |
| /// The merkle root of the blob. |
| String hash; |
| |
| /// A human-readable name for the blob. |
| /// Typically, it is the "source_path" field in the referencing |
| /// pakcage manifest. If multiple packages reference a blob |
| /// via different paths, there will be multiple elements |
| /// in the set. |
| Set<String> sourcePaths = <String>{}; |
| |
| /// Size the blob occupies in the image. |
| /// This might be compressed. |
| int size; |
| |
| /// Number of references to this blob. |
| int count; |
| |
| /// If the blob is a zbi, we would extract and count the contents |
| /// in the zbi too. Those would be listed as `subBlobs`. |
| List<SubBlob> subBlobs = []; |
| |
| @override |
| String toString() => 'Blob { buildPath: $buildPath, sizeOnHost: $sizeOnHost, ' |
| 'hash: $hash, sourcePaths: $sourcePaths, ' |
| 'size: $size, count: $count, subBlobs: $subBlobs }'; |
| } |
| |
| class SubBlob extends BuildArtifact { |
| /// Name of the file relative to the root of the zbi. |
| String name; |
| |
| @override |
| String toString() => |
| 'SubBlob { buildPath: $buildPath, sizeOnHost: $sizeOnHost, ' |
| 'name: $name }'; |
| } |
| |
| class Package { |
| String path; |
| String name; |
| int size; |
| int private; |
| int blobCount; |
| Map<String, Blob> blobsByPath; |
| } |