"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter_tools/lib/src/build_system/source.dart" (13 Nov 2020, 9333 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 '../artifacts.dart';
    6 import '../base/file_system.dart';
    7 import '../build_info.dart';
    8 import 'build_system.dart';
    9 import 'exceptions.dart';
   10 
   11 /// A set of source files.
   12 abstract class ResolvedFiles {
   13   /// Whether any of the sources we evaluated contained a missing depfile.
   14   ///
   15   /// If so, the build system needs to rerun the visitor after executing the
   16   /// build to ensure all hashes are up to date.
   17   bool get containsNewDepfile;
   18 
   19   /// The resolved source files.
   20   List<File> get sources;
   21 }
   22 
   23 /// Collects sources for a [Target] into a single list of [FileSystemEntities].
   24 class SourceVisitor implements ResolvedFiles {
   25   /// Create a new [SourceVisitor] from an [Environment].
   26   SourceVisitor(this.environment, [ this.inputs = true ]);
   27 
   28   /// The current environment.
   29   final Environment environment;
   30 
   31   /// Whether we are visiting inputs or outputs.
   32   ///
   33   /// Defaults to `true`.
   34   final bool inputs;
   35 
   36   @override
   37   final List<File> sources = <File>[];
   38 
   39   @override
   40   bool get containsNewDepfile => _containsNewDepfile;
   41   bool _containsNewDepfile = false;
   42 
   43   /// Visit a depfile which contains both input and output files.
   44   ///
   45   /// If the file is missing, this visitor is marked as [containsNewDepfile].
   46   /// This is used by the [Node] class to tell the [BuildSystem] to
   47   /// defer hash computation until after executing the target.
   48   // depfile logic adopted from https://github.com/flutter/flutter/blob/7065e4330624a5a216c8ffbace0a462617dc1bf5/dev/devicelab/lib/framework/apk_utils.dart#L390
   49   void visitDepfile(String name) {
   50     final File depfile = environment.buildDir.childFile(name);
   51     if (!depfile.existsSync()) {
   52       _containsNewDepfile = true;
   53       return;
   54     }
   55     final String contents = depfile.readAsStringSync();
   56     final List<String> colonSeparated = contents.split(': ');
   57     if (colonSeparated.length != 2) {
   58       environment.logger.printError('Invalid depfile: ${depfile.path}');
   59       return;
   60     }
   61     if (inputs) {
   62       sources.addAll(_processList(colonSeparated[1].trim()));
   63     } else {
   64       sources.addAll(_processList(colonSeparated[0].trim()));
   65     }
   66   }
   67 
   68   final RegExp _separatorExpr = RegExp(r'([^\\]) ');
   69   final RegExp _escapeExpr = RegExp(r'\\(.)');
   70 
   71   Iterable<File> _processList(String rawText) {
   72     return rawText
   73     // Put every file on right-hand side on the separate line
   74         .replaceAllMapped(_separatorExpr, (Match match) => '${match.group(1)}\n')
   75         .split('\n')
   76     // Expand escape sequences, so that '\ ', for example,ß becomes ' '
   77         .map<String>((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim())
   78         .where((String path) => path.isNotEmpty)
   79         .toSet()
   80         .map(environment.fileSystem.file);
   81   }
   82 
   83   /// Visit a [Source] which contains a file URL.
   84   ///
   85   /// The URL may include constants defined in an [Environment]. If
   86   /// [optional] is true, the file is not required to exist. In this case, it
   87   /// is never resolved as an input.
   88   void visitPattern(String pattern, bool optional) {
   89     // perform substitution of the environmental values and then
   90     // of the local values.
   91     final List<String> segments = <String>[];
   92     final List<String> rawParts = pattern.split('/');
   93     final bool hasWildcard = rawParts.last.contains('*');
   94     String wildcardFile;
   95     if (hasWildcard) {
   96       wildcardFile = rawParts.removeLast();
   97     }
   98     // If the pattern does not start with an env variable, then we have nothing
   99     // to resolve it to, error out.
  100     switch (rawParts.first) {
  101       case Environment.kProjectDirectory:
  102         segments.addAll(
  103           environment.fileSystem.path.split(environment.projectDir.resolveSymbolicLinksSync()));
  104         break;
  105       case Environment.kBuildDirectory:
  106         segments.addAll(environment.fileSystem.path.split(
  107           environment.buildDir.resolveSymbolicLinksSync()));
  108         break;
  109       case Environment.kCacheDirectory:
  110         segments.addAll(
  111           environment.fileSystem.path.split(environment.cacheDir.resolveSymbolicLinksSync()));
  112         break;
  113       case Environment.kFlutterRootDirectory:
  114         // flutter root will not contain a symbolic link.
  115         segments.addAll(
  116           environment.fileSystem.path.split(environment.flutterRootDir.absolute.path));
  117         break;
  118       case Environment.kOutputDirectory:
  119         segments.addAll(
  120           environment.fileSystem.path.split(environment.outputDir.resolveSymbolicLinksSync()));
  121         break;
  122       default:
  123         throw InvalidPatternException(pattern);
  124     }
  125     rawParts.skip(1).forEach(segments.add);
  126     final String filePath = environment.fileSystem.path.joinAll(segments);
  127     if (!hasWildcard) {
  128       if (optional && !environment.fileSystem.isFileSync(filePath)) {
  129         return;
  130       }
  131       sources.add(environment.fileSystem.file(
  132         environment.fileSystem.path.normalize(filePath)));
  133       return;
  134     }
  135     // Perform a simple match by splitting the wildcard containing file one
  136     // the `*`. For example, for `/*.dart`, we get [.dart]. We then check
  137     // that part of the file matches. If there are values before and after
  138     // the `*` we need to check that both match without overlapping. For
  139     // example, `foo_*_.dart`. We want to match `foo_b_.dart` but not
  140     // `foo_.dart`. To do so, we first subtract the first section from the
  141     // string if the first segment matches.
  142     final List<String> wildcardSegments = wildcardFile.split('*');
  143     if (wildcardSegments.length > 2) {
  144       throw InvalidPatternException(pattern);
  145     }
  146     if (!environment.fileSystem.directory(filePath).existsSync()) {
  147       throw Exception('$filePath does not exist!');
  148     }
  149     for (final FileSystemEntity entity in environment.fileSystem.directory(filePath).listSync()) {
  150       final String filename = environment.fileSystem.path.basename(entity.path);
  151       if (wildcardSegments.isEmpty) {
  152         sources.add(environment.fileSystem.file(entity.absolute));
  153       } else if (wildcardSegments.length == 1) {
  154         if (filename.startsWith(wildcardSegments[0]) ||
  155             filename.endsWith(wildcardSegments[0])) {
  156           sources.add(environment.fileSystem.file(entity.absolute));
  157         }
  158       } else if (filename.startsWith(wildcardSegments[0])) {
  159         if (filename.substring(wildcardSegments[0].length).endsWith(wildcardSegments[1])) {
  160           sources.add(environment.fileSystem.file(entity.absolute));
  161         }
  162       }
  163     }
  164   }
  165 
  166   /// Visit a [Source] which is defined by an [Artifact] from the flutter cache.
  167   ///
  168   /// If the [Artifact] points to a directory then all child files are included.
  169   /// To increase the performance of builds that use a known revision of Flutter,
  170   /// these are updated to point towards the engine.version file instead of
  171   /// the artifact itself.
  172   void visitArtifact(Artifact artifact, TargetPlatform platform, BuildMode mode) {
  173     // This is not a local engine.
  174     if (environment.engineVersion != null) {
  175       sources.add(environment.flutterRootDir
  176         .childDirectory('bin')
  177         .childDirectory('internal')
  178         .childFile('engine.version'),
  179       );
  180       return;
  181     }
  182     final String path = environment.artifacts
  183       .getArtifactPath(artifact, platform: platform, mode: mode);
  184     if (environment.fileSystem.isDirectorySync(path)) {
  185       sources.addAll(<File>[
  186         for (FileSystemEntity entity in environment.fileSystem.directory(path).listSync(recursive: true))
  187           if (entity is File)
  188             entity,
  189       ]);
  190       return;
  191     }
  192     sources.add(environment.fileSystem.file(path));
  193   }
  194 }
  195 
  196 /// A description of an input or output of a [Target].
  197 abstract class Source {
  198   /// This source is a file URL which contains some references to magic
  199   /// environment variables.
  200   const factory Source.pattern(String pattern, { bool optional }) = _PatternSource;
  201   /// The source is provided by an [Artifact].
  202   ///
  203   /// If [artifact] points to a directory then all child files are included.
  204   const factory Source.artifact(Artifact artifact, {TargetPlatform platform, BuildMode mode}) = _ArtifactSource;
  205 
  206   /// Visit the particular source type.
  207   void accept(SourceVisitor visitor);
  208 
  209   /// Whether the output source provided can be known before executing the rule.
  210   ///
  211   /// This does not apply to inputs, which are always explicit and must be
  212   /// evaluated before the build.
  213   ///
  214   /// For example, [Source.pattern] and [Source.version] are not implicit
  215   /// provided they do not use any wildcards.
  216   bool get implicit;
  217 }
  218 
  219 class _PatternSource implements Source {
  220   const _PatternSource(this.value, { this.optional = false });
  221 
  222   final String value;
  223   final bool optional;
  224 
  225   @override
  226   void accept(SourceVisitor visitor) => visitor.visitPattern(value, optional);
  227 
  228   @override
  229   bool get implicit => value.contains('*');
  230 }
  231 
  232 class _ArtifactSource implements Source {
  233   const _ArtifactSource(this.artifact, { this.platform, this.mode });
  234 
  235   final Artifact artifact;
  236   final TargetPlatform platform;
  237   final BuildMode mode;
  238 
  239   @override
  240   void accept(SourceVisitor visitor) => visitor.visitArtifact(artifact, platform, mode);
  241 
  242   @override
  243   bool get implicit => false;
  244 }