#!/usr/bin/env dart // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. 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"; class Symbol { String? name; String? type; int? shallowSize; int? retainedSize; List children = []; Symbol compressTrivialPaths() { for (var i = 0; i < children.length; i++) { children[i] = children[i].compressTrivialPaths(); } if ((type == "path") && (children.length == 1) && (children[0].type == "path")) { return children[0]; } return this; } int computeRetainedSize() { var s = shallowSize!; for (var child in children) { s += child.computeRetainedSize(); } retainedSize = s; return s; } writeJson(StringBuffer out) { out.write("{"); out.write('"name": "$name",'); out.write('"shallowSize": $shallowSize,'); out.write('"retainedSize": $retainedSize,'); out.write('"type": "$type",'); out.write('"children": ['); bool first = true; for (var child in children) { if (first) { first = false; } else { out.write(","); } child.writeJson(out); } out.write("]}"); } } const filteredPathComponents = [ "", ]; var cwd = Directory.current.path; String prettyPath(String path) { if (path.startsWith(cwd)) { path = path.substring(cwd.length); } return path .split("/") .where((component) => !filteredPathComponents.contains(component)) .join("/"); } main(List args) { if (args.length != 1) { print("Usage: zip_size "); exit(1); } var path = args[0]; var unzipExec = "unzip"; var unzipArgs = ["-l", path]; var unzipResult = Process.runSync(unzipExec, unzipArgs); if (unzipResult.exitCode != 0) { print("+ ${unzipExec} ${unzipArgs.join(' ')}"); print(unzipResult.exitCode); print(unzipResult.stdout); print(unzipResult.stderr); exit(1); } var root = new Symbol(); root.name = path; root.type = "archive"; root.shallowSize = 0; var paths = new Map(); paths[""] = root; addToPath(Symbol s, String path) { Symbol? p = paths[path]; if (p == null) { p = new Symbol(); p.name = path; p.type = "path"; p.shallowSize = 0; paths[path] = p; var i = path.lastIndexOf("/"); if (i != -1) { p.name = path.substring(i + 1); addToPath(p, path.substring(0, i)); } else { root.children.add(p); } } p.children.add(s); } var lines = unzipResult.stdout.split("\n"); var regexp = new RegExp(r"\s*(\d+)\s+\d+-\d+-\d+\s+\d+:\d+\s+(.*)"); for (var line in lines) { var match = regexp.firstMatch(line); if (match == null) { continue; } var name = match[2]!; var size = int.parse(match[1]!); var path = ""; if (name.contains("/")) { path = name.substring(0, name.lastIndexOf("/")); name = name.substring(name.lastIndexOf("/") + 1); } path = prettyPath(path); var s = new Symbol(); s.name = name; s.type = "file"; s.shallowSize = size; addToPath(s, path); } root.compressTrivialPaths(); root.computeRetainedSize(); var json = new StringBuffer(); root.writeJson(json); var html = viewer.replaceAll("__DATA__", json.toString()); new File("${path}.html").writeAsStringSync(html); // This written as a URL instead of path because some terminals will // automatically recognize it and make it a link. var url = Directory.current.uri.resolve("${path}.html"); print("Wrote $url"); } var viewer = """ """;