1// Copyright 2013 The Flutter Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import "dart:io"; 6 7import "package:args/args.dart"; 8 9Future<void> main(List<String> args) async { 10 final parser = new ArgParser(); 11 parser.addOption("far-tool", help: "Path to `far` tool"); 12 parser.addOption("archive", help: "Path to the far archive to extract from"); 13 parser.addOption("out-dir", help: "Path to output directory"); 14 final usage = """ 15Usage: extract_far.dart [options] {paths} 16 17Options: 18${parser.usage}; 19"""; 20 21 ArgResults options; 22 try { 23 options = parser.parse(args); 24 if (options["far-tool"] == null) { 25 throw "Must specify --far-tool"; 26 } 27 if (options["archive"] == null) { 28 throw "Must specify --archive"; 29 } 30 if (options["out-dir"] == null) { 31 throw "Must specify --out-dir"; 32 } 33 } catch (e) { 34 print("ERROR: $e\n"); 35 print(usage); 36 exitCode = 1; 37 return; 38 } 39 40 await run(options); 41} 42 43Future<void> run(ArgResults options) async { 44 final far = options["far-tool"]; 45 46 Future<void> extract(String archive, String file, String output) async { 47 await new File(output).parent.create(recursive: true); 48 final args = ["extract-file", "--archive=$archive", "--file=$file", "--output=$output"]; 49 final result = await Process.run(far, args); 50 if (result.exitCode != 0) { 51 print(result.stdout); 52 print(result.stderr); 53 throw "Command failed: $far $args"; 54 } 55 } 56 57 final outerArchive = options["archive"]; 58 final outDir = options["out-dir"]; 59 60 final innerArchive = "$outDir/meta.far"; 61 await extract(outerArchive, "meta.far", innerArchive); 62 63 final manifest = "$outDir/meta/contents"; 64 await extract(innerArchive, "meta/contents", manifest); 65 66 final blobNames = <String, String>{}; 67 for (final line in await new File(manifest).readAsLines()) { 68 final pivot = line.lastIndexOf("="); 69 blobNames[line.substring(0, pivot)] = line.substring(pivot + 1, line.length); 70 } 71 72 for (final path in options.rest) { 73 final blobName = blobNames[path]; 74 if (blobName == null) { 75 print("Archive contents: "); 76 for (final key in blobNames.keys) { 77 print(key); 78 } 79 throw "$outerArchive does not contain $path"; 80 } 81 await extract(outerArchive, blobName, "$outDir/$path"); 82 } 83} 84