| // Copyright 2019 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:args/args.dart'; |
| import 'package:file/file.dart'; |
| import 'package:process/process.dart'; |
| |
| import 'log.dart'; |
| |
| enum FileType { |
| folder, |
| zip, |
| binary, |
| other; |
| |
| // Artifact files have many different types. Codesign would be no-op when encoutering non typical types such as application/octet-stream. |
| factory FileType.fromMimeType(String mimeType) { |
| if (mimeType.contains('inode/directory')) { |
| return FileType.folder; |
| } else if (mimeType.contains('application/zip')) { |
| return FileType.zip; |
| } else if (mimeType.contains('application/x-mach-binary')) { |
| return FileType.binary; |
| } else { |
| return FileType.other; |
| } |
| } |
| } |
| |
| Future<void> unzip({ |
| required FileSystemEntity inputZip, |
| required Directory outDir, |
| required ProcessManager processManager, |
| }) async { |
| await processManager.run(<String>[ |
| 'unzip', |
| inputZip.absolute.path, |
| '-d', |
| outDir.absolute.path, |
| ]); |
| outDir.listSync(recursive: true).forEach((entity) { |
| if (entity.basename.toLowerCase() == '.ds_store') { |
| try { |
| entity.deleteSync(); |
| log.info('Deleted ${entity.path}.'); |
| } catch (err) { |
| log.severe('Error while trying to delete ${entity.path}'); |
| rethrow; |
| } |
| } |
| }); |
| log.info( |
| 'The downloaded file is unzipped from ${inputZip.absolute.path} to ${outDir.absolute.path}', |
| ); |
| } |
| |
| Future<void> zip({ |
| required Directory inputDir, |
| required String outputZipPath, |
| required ProcessManager processManager, |
| }) async { |
| await processManager.run(<String>[ |
| 'zip', |
| '--symlinks', |
| '--recurse-paths', |
| outputZipPath, |
| // use '.' so that the full absolute path is not encoded into the zip file |
| '.', |
| '--include', |
| '*', |
| ], workingDirectory: inputDir.absolute.path); |
| } |
| |
| /// Check mime-type of file at [filePath] to determine if it is a directory. |
| FileType getFileType(String filePath, ProcessManager processManager) { |
| final result = processManager.runSync(<String>[ |
| 'file', |
| '--mime-type', |
| '-b', // is binary |
| filePath, |
| ]); |
| final output = result.stdout as String; |
| return FileType.fromMimeType(output); |
| } |
| |
| class CodesignException implements Exception { |
| CodesignException(this.message, {this.isRetryable = false}); |
| |
| final String message; |
| |
| /// Whether the exception represents something that could succeed if retried. |
| final bool isRetryable; |
| |
| @override |
| String toString() => 'Exception: $message'; |
| } |
| |
| /// Return the command line argument by parsing [argResults]. |
| /// |
| /// If the key does not exist in CLI args, throws a [CodesignException]. |
| String? getValueFromArgs( |
| String name, |
| ArgResults argResults, { |
| bool allowNull = false, |
| }) { |
| final argValue = argResults[name] as String?; |
| if (argValue != null) { |
| return argValue; |
| } |
| if (allowNull) { |
| return null; |
| } |
| throw CodesignException( |
| 'Expected either the CLI arg --$name ' |
| 'to be provided!', |
| ); |
| } |
| |
| String joinEntitlementPaths(String entitlementParentPath, String pathToJoin) { |
| if (entitlementParentPath == '') { |
| return pathToJoin; |
| } else { |
| return '$entitlementParentPath/$pathToJoin'; |
| } |
| } |