blob: 87ff8ddcd66b318008ee1d47bcc35beace950326 [file] [log] [blame]
// 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 sibling zircon build output directory.
Directory zirconBuildDirectory() {
final buildDirName = path.split(dir.path).last;
return dir.parent / Directory('$buildDirName.zircon');
}
/// 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;
}