| // Copyright 2014 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 'dart:io'; | |
| import 'package:args/args.dart'; | |
| import 'package:path/path.dart' as path; | |
| /// If no `copies` param is passed in, we scale the generated app up to 60k lines. | |
| const int kTargetLineCount = 60 * 1024; | |
| /// Make `n` copies of flutter_gallery. | |
| void main(List<String> args) { | |
| // If we're run from the `tools` dir, set the cwd to the repo root. | |
| if (path.basename(Directory.current.path) == 'tools') { | |
| Directory.current = Directory.current.parent.parent; | |
| } | |
| final ArgParser argParser = ArgParser(); | |
| argParser.addOption('out'); | |
| argParser.addOption('copies'); | |
| argParser.addFlag('delete', negatable: false); | |
| argParser.addFlag('help', abbr: 'h', negatable: false); | |
| final ArgResults results = argParser.parse(args); | |
| if (results['help'] as bool) { | |
| print('Generate n copies of flutter_gallery.\n'); | |
| print('usage: dart mega_gallery.dart <options>'); | |
| print(argParser.usage); | |
| exit(0); | |
| } | |
| final Directory source = Directory(_normalize('dev/integration_tests/flutter_gallery')); | |
| final Directory out = Directory(_normalize(results['out'] as String)); | |
| if (results['delete'] as bool) { | |
| if (out.existsSync()) { | |
| print('Deleting ${out.path}'); | |
| out.deleteSync(recursive: true); | |
| } | |
| exit(0); | |
| } | |
| if (!results.wasParsed('out')) { | |
| print('The --out parameter is required.'); | |
| print(argParser.usage); | |
| exit(1); | |
| } | |
| int copies; | |
| if (!results.wasParsed('copies')) { | |
| final SourceStats stats = getStatsFor(_dir(source, 'lib')); | |
| copies = (kTargetLineCount / stats.lines).round(); | |
| } else { | |
| copies = int.parse(results['copies'] as String); | |
| } | |
| print('Making $copies copies of flutter_gallery.'); | |
| print(''); | |
| print('Stats:'); | |
| print(' packages/flutter : ${getStatsFor(Directory("packages/flutter"))}'); | |
| print(' dev/integration_tests/flutter_gallery : ${getStatsFor(Directory("dev/integration_tests/flutter_gallery"))}'); | |
| final Directory lib = _dir(out, 'lib'); | |
| if (lib.existsSync()) { | |
| lib.deleteSync(recursive: true); | |
| } | |
| // Copy everything that's not a symlink, dot directory, or build/. | |
| _copy(source, out); | |
| // Make n - 1 copies. | |
| for (int i = 1; i < copies; i++) { | |
| _copyGallery(out, i); | |
| } | |
| // Create a new entry-point. | |
| _createEntry(_file(out, 'lib/main.dart'), copies); | |
| // Update the pubspec. | |
| String pubspec = _file(out, 'pubspec.yaml').readAsStringSync(); | |
| pubspec = pubspec.replaceAll('../../packages/flutter', '../../../packages/flutter'); | |
| _file(out, 'pubspec.yaml').writeAsStringSync(pubspec); | |
| // Remove the (flutter_gallery specific) analysis_options.yaml file. | |
| _file(out, 'analysis_options.yaml').deleteSync(); | |
| _file(out, '.dartignore').writeAsStringSync(''); | |
| // Count source lines and number of files; tell how to run it. | |
| print(' ${path.relative(results["out"] as String)} : ${getStatsFor(out)}'); | |
| } | |
| // TODO(devoncarew): Create an entry-point that builds a UI with all `n` copies. | |
| void _createEntry(File mainFile, int copies) { | |
| final StringBuffer imports = StringBuffer(); | |
| for (int i = 1; i < copies; i++) { | |
| imports.writeln('// ignore: unused_import'); | |
| imports.writeln("import 'gallery_$i/main.dart' as main_$i;"); | |
| } | |
| final String contents = ''' | |
| // Copyright 2014 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:flutter/widgets.dart'; | |
| import 'gallery/app.dart'; | |
| ${imports.toString().trim()} | |
| void main() { | |
| runApp(const GalleryApp()); | |
| } | |
| '''; | |
| mainFile.writeAsStringSync(contents); | |
| } | |
| void _copyGallery(Directory galleryDir, int index) { | |
| final Directory lib = _dir(galleryDir, 'lib'); | |
| final Directory dest = _dir(lib, 'gallery_$index'); | |
| dest.createSync(); | |
| // Copy demo/, gallery/, and main.dart. | |
| _copy(_dir(lib, 'demo'), _dir(dest, 'demo')); | |
| _copy(_dir(lib, 'gallery'), _dir(dest, 'gallery')); | |
| _file(dest, 'main.dart').writeAsBytesSync(_file(lib, 'main.dart').readAsBytesSync()); | |
| } | |
| void _copy(Directory source, Directory target) { | |
| if (!target.existsSync()) { | |
| target.createSync(recursive: true); | |
| } | |
| for (final FileSystemEntity entity in source.listSync(followLinks: false)) { | |
| final String name = path.basename(entity.path); | |
| if (entity is Directory) { | |
| if (name == 'build' || name.startsWith('.')) { | |
| continue; | |
| } | |
| _copy(entity, Directory(path.join(target.path, name))); | |
| } else if (entity is File) { | |
| if (name == '.packages' || name == 'pubspec.lock') { | |
| continue; | |
| } | |
| final File dest = File(path.join(target.path, name)); | |
| dest.writeAsBytesSync(entity.readAsBytesSync()); | |
| } | |
| } | |
| } | |
| Directory _dir(Directory parent, String name) => Directory(path.join(parent.path, name)); | |
| File _file(Directory parent, String name) => File(path.join(parent.path, name)); | |
| String _normalize(String filePath) => path.normalize(path.absolute(filePath)); | |
| class SourceStats { | |
| int files = 0; | |
| int lines = 0; | |
| @override | |
| String toString() => '${_comma(files).padLeft(3)} files, ${_comma(lines).padLeft(6)} lines'; | |
| } | |
| SourceStats getStatsFor(Directory dir, [SourceStats? stats]) { | |
| stats ??= SourceStats(); | |
| for (final FileSystemEntity entity in dir.listSync(followLinks: false)) { | |
| final String name = path.basename(entity.path); | |
| if (entity is File && name.endsWith('.dart')) { | |
| stats.files += 1; | |
| stats.lines += _lineCount(entity); | |
| } else if (entity is Directory && !name.startsWith('.')) { | |
| getStatsFor(entity, stats); | |
| } | |
| } | |
| return stats; | |
| } | |
| int _lineCount(File file) { | |
| return file.readAsLinesSync().where((String line) { | |
| line = line.trim(); | |
| if (line.isEmpty || line.startsWith('//')) { | |
| return false; | |
| } | |
| return true; | |
| }).length; | |
| } | |
| String _comma(int count) { | |
| final String str = count.toString(); | |
| if (str.length > 3) { | |
| return '${str.substring(0, str.length - 3)},${str.substring(str.length - 3)}'; | |
| } | |
| return str; | |
| } |