"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter_tools/lib/src/commands/ide_config.dart" (13 Nov 2020, 10562 Bytes) of package /linux/misc/flutter-1.22.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 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 
    5 import 'dart:async';
    6 
    7 import '../base/common.dart';
    8 import '../base/file_system.dart';
    9 import '../cache.dart';
   10 import '../globals.dart' as globals;
   11 import '../runner/flutter_command.dart';
   12 import '../template.dart';
   13 
   14 class IdeConfigCommand extends FlutterCommand {
   15   IdeConfigCommand() {
   16     argParser.addFlag(
   17       'overwrite',
   18       negatable: true,
   19       defaultsTo: false,
   20       help: 'When performing operations, overwrite existing files.',
   21     );
   22     argParser.addFlag(
   23       'update-templates',
   24       negatable: false,
   25       help: 'Update the templates in the template directory from the current '
   26           'configuration files. This is the opposite of what $name usually does. '
   27           'Will search the flutter tree for .iml files and copy any missing ones '
   28           'into the template directory. If --overwrite is also specified, it will '
   29           'update any out-of-date files, and remove any deleted files from the '
   30           'template directory.',
   31     );
   32     argParser.addFlag(
   33       'with-root-module',
   34       negatable: true,
   35       defaultsTo: true,
   36       help: 'Also create module that corresponds to the root of Flutter tree. '
   37           'This makes the entire Flutter tree browsable and searchable in IDE. '
   38           'Without this flag, only the child modules will be visible in IDE.',
   39     );
   40   }
   41 
   42   @override
   43   final String name = 'ide-config';
   44 
   45   @override
   46   Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
   47 
   48   @override
   49   final String description = 'Configure the IDE for use in the Flutter tree.\n\n'
   50       'If run on a Flutter tree that is already configured for the IDE, this '
   51       'command will add any new configurations, recreate any files that are '
   52       'missing. If --overwrite is specified, will revert existing files to '
   53       'the template versions, reset the module list, and return configuration '
   54       'settings to the template versions.\n\n'
   55       'This command is intended for Flutter developers to help them set up the '
   56       "Flutter tree for development in an IDE. It doesn't affect other projects.\n\n"
   57       'Currently, IntelliJ is the default (and only) IDE that may be configured.';
   58 
   59   @override
   60   final bool hidden = true;
   61 
   62   @override
   63   String get invocation => '${runner.executableName} $name';
   64 
   65   static const String _ideName = 'intellij';
   66   Directory get _templateDirectory {
   67     return globals.fs.directory(globals.fs.path.join(
   68       Cache.flutterRoot,
   69       'packages',
   70       'flutter_tools',
   71       'ide_templates',
   72       _ideName,
   73     ));
   74   }
   75 
   76   Directory get _createTemplatesDirectory {
   77     return globals.fs.directory(globals.fs.path.join(
   78       Cache.flutterRoot,
   79       'packages',
   80       'flutter_tools',
   81       'templates',
   82     ));
   83   }
   84 
   85   Directory get _flutterRoot => globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot));
   86 
   87   // Returns true if any entire path element is equal to dir.
   88   bool _hasDirectoryInPath(FileSystemEntity entity, String dir) {
   89     String path = entity.absolute.path;
   90     while (path.isNotEmpty && globals.fs.path.dirname(path) != path) {
   91       if (globals.fs.path.basename(path) == dir) {
   92         return true;
   93       }
   94       path = globals.fs.path.dirname(path);
   95     }
   96     return false;
   97   }
   98 
   99   // Returns true if child is anywhere underneath parent.
  100   bool _isChildDirectoryOf(FileSystemEntity parent, FileSystemEntity child) {
  101     return child.absolute.path.startsWith(parent.absolute.path);
  102   }
  103 
  104   // Checks the contents of the two files to see if they have changes.
  105   bool _fileIsIdentical(File src, File dest) {
  106     if (src.lengthSync() != dest.lengthSync()) {
  107       return false;
  108     }
  109 
  110     // Test byte by byte. We're assuming that these are small files.
  111     final List<int> srcBytes = src.readAsBytesSync();
  112     final List<int> destBytes = dest.readAsBytesSync();
  113     for (int i = 0; i < srcBytes.length; ++i) {
  114       if (srcBytes[i] != destBytes[i]) {
  115         return false;
  116       }
  117     }
  118     return true;
  119   }
  120 
  121   // Discovers and syncs with existing configuration files in the Flutter tree.
  122   void _handleTemplateUpdate() {
  123     if (!_flutterRoot.existsSync()) {
  124       return;
  125     }
  126 
  127     final Set<String> manifest = <String>{};
  128     final Iterable<File> flutterFiles = _flutterRoot.listSync(recursive: true).whereType<File>();
  129     for (final File srcFile in flutterFiles) {
  130       final String relativePath = globals.fs.path.relative(srcFile.path, from: _flutterRoot.absolute.path);
  131 
  132       // Skip template files in both the ide_templates and templates
  133       // directories to avoid copying onto themselves.
  134       if (_isChildDirectoryOf(_templateDirectory, srcFile) ||
  135           _isChildDirectoryOf(_createTemplatesDirectory, srcFile)) {
  136         continue;
  137       }
  138 
  139       // Skip files we aren't interested in.
  140       final RegExp _trackedIdeaFileRegExp = RegExp(
  141         r'(\.name|modules.xml|vcs.xml)$',
  142       );
  143       final bool isATrackedIdeaFile = _hasDirectoryInPath(srcFile, '.idea') &&
  144           (_trackedIdeaFileRegExp.hasMatch(relativePath) ||
  145               _hasDirectoryInPath(srcFile, 'runConfigurations'));
  146       final bool isAnImlOutsideIdea = !isATrackedIdeaFile && srcFile.path.endsWith('.iml');
  147       if (!isATrackedIdeaFile && !isAnImlOutsideIdea) {
  148         continue;
  149       }
  150 
  151       final File finalDestinationFile = globals.fs.file(globals.fs.path.absolute(
  152           _templateDirectory.absolute.path, '$relativePath${Template.copyTemplateExtension}'));
  153       final String relativeDestination =
  154           globals.fs.path.relative(finalDestinationFile.path, from: _flutterRoot.absolute.path);
  155       if (finalDestinationFile.existsSync()) {
  156         if (_fileIsIdentical(srcFile, finalDestinationFile)) {
  157           globals.printTrace('  $relativeDestination (identical)');
  158           manifest.add('$relativePath${Template.copyTemplateExtension}');
  159           continue;
  160         }
  161         if (boolArg('overwrite')) {
  162           finalDestinationFile.deleteSync();
  163           globals.printStatus('  $relativeDestination (overwritten)');
  164         } else {
  165           globals.printTrace('  $relativeDestination (existing - skipped)');
  166           manifest.add('$relativePath${Template.copyTemplateExtension}');
  167           continue;
  168         }
  169       } else {
  170         globals.printStatus('  $relativeDestination (added)');
  171       }
  172       final Directory finalDestinationDir = globals.fs.directory(finalDestinationFile.dirname);
  173       if (!finalDestinationDir.existsSync()) {
  174         globals.printTrace("  ${finalDestinationDir.path} doesn't exist, creating.");
  175         finalDestinationDir.createSync(recursive: true);
  176       }
  177       srcFile.copySync(finalDestinationFile.path);
  178       manifest.add('$relativePath${Template.copyTemplateExtension}');
  179     }
  180 
  181     // If we're not overwriting, then we're not going to remove missing items either.
  182     if (!boolArg('overwrite')) {
  183       return;
  184     }
  185 
  186     // Look for any files under the template dir that don't exist in the manifest and remove
  187     // them.
  188     final Iterable<File> templateFiles = _templateDirectory.listSync(recursive: true).whereType<File>();
  189     for (final File templateFile in templateFiles) {
  190       final String relativePath = globals.fs.path.relative(
  191         templateFile.absolute.path,
  192         from: _templateDirectory.absolute.path,
  193       );
  194       if (!manifest.contains(relativePath)) {
  195         templateFile.deleteSync();
  196         final String relativeDestination =
  197             globals.fs.path.relative(templateFile.path, from: _flutterRoot.absolute.path);
  198         globals.printStatus('  $relativeDestination (removed)');
  199       }
  200       // If the directory is now empty, then remove it, and do the same for its parent,
  201       // until we escape to the template directory.
  202       Directory parentDir = globals.fs.directory(templateFile.dirname);
  203       while (parentDir.listSync().isEmpty) {
  204         parentDir.deleteSync();
  205         globals.printTrace('  ${globals.fs.path.relative(parentDir.absolute.path)} (empty directory - removed)');
  206         parentDir = globals.fs.directory(parentDir.dirname);
  207         if (globals.fs.path.isWithin(_templateDirectory.absolute.path, parentDir.absolute.path)) {
  208           break;
  209         }
  210       }
  211     }
  212   }
  213 
  214   @override
  215   Future<FlutterCommandResult> runCommand() async {
  216     if (argResults.rest.isNotEmpty) {
  217       throwToolExit('Currently, the only supported IDE is IntelliJ\n$usage', exitCode: 2);
  218     }
  219 
  220     if (boolArg('update-templates')) {
  221       _handleTemplateUpdate();
  222       return FlutterCommandResult.success();
  223     }
  224 
  225     final String flutterRoot = globals.fs.path.absolute(Cache.flutterRoot);
  226     final String dirPath = globals.fs.path.normalize(
  227       globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot)).absolute.path,
  228     );
  229 
  230     final String error = _validateFlutterDir(dirPath, flutterRoot: flutterRoot);
  231     if (error != null) {
  232       throwToolExit(error);
  233     }
  234 
  235     globals.printStatus('Updating IDE configuration for Flutter tree at $dirPath...');
  236     int generatedCount = 0;
  237     generatedCount += _renderTemplate(_ideName, dirPath, <String, dynamic>{
  238       'withRootModule': boolArg('with-root-module'),
  239       'android': true,
  240     });
  241 
  242     globals.printStatus('Wrote $generatedCount files.');
  243     globals.printStatus('');
  244     globals.printStatus('Your IntelliJ configuration is now up to date. It is prudent to '
  245         'restart IntelliJ, if running.');
  246 
  247     return FlutterCommandResult.success();
  248   }
  249 
  250   int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) {
  251     final Template template = Template(
  252       _templateDirectory,
  253       _templateDirectory,
  254       null,
  255       fileSystem: globals.fs,
  256       templateManifest: null,
  257       logger: globals.logger,
  258       templateRenderer: globals.templateRenderer,
  259     );
  260     return template.render(
  261       globals.fs.directory(dirPath),
  262       context,
  263       overwriteExisting: boolArg('overwrite'),
  264     );
  265   }
  266 }
  267 
  268 /// Return null if the flutter root directory is a valid destination. Return a
  269 /// validation message if we should disallow the directory.
  270 String _validateFlutterDir(String dirPath, { String flutterRoot }) {
  271   final FileSystemEntityType type = globals.fs.typeSync(dirPath);
  272 
  273   if (type != FileSystemEntityType.notFound) {
  274     switch (type) {
  275       case FileSystemEntityType.link:
  276         // Do not overwrite links.
  277         return "Invalid project root dir: '$dirPath' - refers to a link.";
  278     }
  279   }
  280 
  281   return null;
  282 }