Example #1
0
  /**
   * Load Skylark aspect from an extension file. Is to be called from a SkyFunction.
   *
   * @return {@code null} if dependencies cannot be satisfied.
   */
  @Nullable
  public static SkylarkAspect loadSkylarkAspect(
      Environment env, Label extensionLabel, String skylarkValueName)
      throws AspectCreationException {
    SkyKey importFileKey = SkylarkImportLookupValue.key(extensionLabel, false);
    try {
      SkylarkImportLookupValue skylarkImportLookupValue =
          (SkylarkImportLookupValue)
              env.getValueOrThrow(importFileKey, SkylarkImportFailedException.class);
      if (skylarkImportLookupValue == null) {
        return null;
      }

      Object skylarkValue =
          skylarkImportLookupValue.getEnvironmentExtension().get(skylarkValueName);
      if (!(skylarkValue instanceof SkylarkAspect)) {
        throw new ConversionException(
            skylarkValueName + " from " + extensionLabel.toString() + " is not an aspect");
      }
      return (SkylarkAspect) skylarkValue;
    } catch (SkylarkImportFailedException | ConversionException e) {
      env.getListener().handle(Event.error(e.getMessage()));
      throw new AspectCreationException(e.getMessage());
    }
  }
  SkyValue computeInternal(
      SkyKey skyKey, Environment env, @Nullable Set<SkyKey> visitedKeysForCycle)
      throws SkyFunctionException, InterruptedException {
    PackageIdentifier arg = (PackageIdentifier) skyKey.argument();
    PathFragment file = arg.getPackageFragment();
    ASTFileLookupValue astLookupValue = null;
    try {
      SkyKey astLookupKey = ASTFileLookupValue.key(arg);
      astLookupValue =
          (ASTFileLookupValue)
              env.getValueOrThrow(
                  astLookupKey,
                  ErrorReadingSkylarkExtensionException.class,
                  InconsistentFilesystemException.class);
    } catch (ErrorReadingSkylarkExtensionException e) {
      throw new SkylarkImportLookupFunctionException(
          SkylarkImportFailedException.errorReadingFile(file, e.getMessage()));
    } catch (InconsistentFilesystemException e) {
      throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
    }
    if (astLookupValue == null) {
      return null;
    }
    if (astLookupValue.getAST() == null) {
      // Skylark import files have to exist.
      throw new SkylarkImportLookupFunctionException(SkylarkImportFailedException.noFile(file));
    }

    BuildFileAST ast = astLookupValue.getAST();
    if (ast.containsErrors()) {
      throw new SkylarkImportLookupFunctionException(
          SkylarkImportFailedException.skylarkErrors(file));
    }

    Label label = pathFragmentToLabel(arg.getRepository(), file, env);
    if (label == null) {
      Preconditions.checkState(env.valuesMissing(), "null label with no missing %s", file);
      return null;
    }

    Map<Location, PathFragment> astImports = ast.getImports();
    Map<PathFragment, Extension> importMap = Maps.newHashMapWithExpectedSize(astImports.size());
    ImmutableList.Builder<SkylarkFileDependency> fileDependencies = ImmutableList.builder();
    Map<SkyKey, PathFragment> skylarkImports = Maps.newHashMapWithExpectedSize(astImports.size());
    for (Map.Entry<Location, PathFragment> entry : ast.getImports().entrySet()) {
      try {
        skylarkImports.put(
            PackageFunction.getImportKey(entry, ruleClassProvider.getPreludePath(), file, arg),
            entry.getValue());
      } catch (ASTLookupInputException e) {
        throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
      }
    }

    Map<SkyKey, SkyValue> skylarkImportMap;
    boolean valuesMissing = false;
    if (visitedKeysForCycle == null) {
      // Not inlining.
      skylarkImportMap = env.getValues(skylarkImports.keySet());
      valuesMissing = env.valuesMissing();
    } else {
      // inlining calls to SkylarkImportLookupFunction.
      if (!visitedKeysForCycle.add(skyKey)) {
        ImmutableList<SkyKey> cycle =
            CycleUtils.splitIntoPathAndChain(Predicates.equalTo(skyKey), visitedKeysForCycle)
                .second;
        if (env.getValue(SkylarkImportUniqueCycleValue.key(cycle)) == null) {
          return null;
        }
        throw new SkylarkImportLookupFunctionException(
            new SkylarkImportFailedException("Skylark import cycle"));
      }
      skylarkImportMap = Maps.newHashMapWithExpectedSize(astImports.size());
      for (SkyKey skylarkImport : skylarkImports.keySet()) {
        SkyValue skyValue = this.computeWithInlineCalls(skylarkImport, env, visitedKeysForCycle);
        if (skyValue == null) {
          Preconditions.checkState(
              env.valuesMissing(), "no skylark import value for %s", skylarkImport);
          // Don't give up on computing. This is against the Skyframe contract, but we don't want to
          // pay the price of serializing all these calls, since they are fundamentally independent.
          valuesMissing = true;
        } else {
          skylarkImportMap.put(skylarkImport, skyValue);
        }
      }
      // All imports traversed, this key can no longer be part of a cycle.
      visitedKeysForCycle.remove(skyKey);
    }

    if (valuesMissing) {
      // This means some imports are unavailable.
      return null;
    }

    for (Map.Entry<SkyKey, SkyValue> entry : skylarkImportMap.entrySet()) {
      SkylarkImportLookupValue importLookupValue = (SkylarkImportLookupValue) entry.getValue();
      importMap.put(
          skylarkImports.get(entry.getKey()), importLookupValue.getEnvironmentExtension());
      fileDependencies.add(importLookupValue.getDependency());
    }

    // Skylark UserDefinedFunction-s in that file will share this function definition Environment,
    // which will be frozen by the time it is returned by createExtension.
    Extension extension = createExtension(ast, file, importMap, env);

    return new SkylarkImportLookupValue(
        extension, new SkylarkFileDependency(label, fileDependencies.build()));
  }
  @Override
  public SkyValue compute(SkyKey skyKey, Environment env)
      throws SkyFunctionException, InterruptedException {
    PackageIdentifier arg = (PackageIdentifier) skyKey.argument();
    PathFragment file = arg.getPackageFragment();
    ASTFileLookupValue astLookupValue = null;
    try {
      SkyKey astLookupKey = ASTFileLookupValue.key(arg);
      astLookupValue =
          (ASTFileLookupValue)
              env.getValueOrThrow(
                  astLookupKey,
                  ErrorReadingSkylarkExtensionException.class,
                  InconsistentFilesystemException.class);
    } catch (ErrorReadingSkylarkExtensionException e) {
      throw new SkylarkImportLookupFunctionException(
          SkylarkImportFailedException.errorReadingFile(file, e.getMessage()));
    } catch (InconsistentFilesystemException e) {
      throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
    }
    if (astLookupValue == null) {
      return null;
    }
    if (astLookupValue.getAST() == null) {
      // Skylark import files have to exist.
      throw new SkylarkImportLookupFunctionException(SkylarkImportFailedException.noFile(file));
    }

    BuildFileAST ast = astLookupValue.getAST();
    if (ast.containsErrors()) {
      throw new SkylarkImportLookupFunctionException(
          SkylarkImportFailedException.skylarkErrors(file));
    }

    Map<Location, PathFragment> astImports = ast.getImports();
    Map<PathFragment, Extension> importMap = Maps.newHashMapWithExpectedSize(astImports.size());
    ImmutableList.Builder<SkylarkFileDependency> fileDependencies = ImmutableList.builder();
    Map<SkyKey, PathFragment> skylarkImports = Maps.newHashMapWithExpectedSize(astImports.size());
    for (Map.Entry<Location, PathFragment> entry : ast.getImports().entrySet()) {
      try {
        skylarkImports.put(
            PackageFunction.getImportKey(entry, ruleClassProvider.getPreludePath(), file, arg),
            entry.getValue());
      } catch (ASTLookupInputException e) {
        throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
      }
    }
    Map<SkyKey, SkyValue> skylarkImportMap = env.getValues(skylarkImports.keySet());

    if (env.valuesMissing()) {
      // This means some imports are unavailable.
      return null;
    }
    for (Map.Entry<SkyKey, SkyValue> entry : skylarkImportMap.entrySet()) {
      SkylarkImportLookupValue importLookupValue = (SkylarkImportLookupValue) entry.getValue();
      importMap.put(
          skylarkImports.get(entry.getKey()), importLookupValue.getEnvironmentExtension());
      fileDependencies.add(importLookupValue.getDependency());
    }

    Label label = pathFragmentToLabel(arg.getRepository(), file, env);

    if (label == null) {
      Preconditions.checkState(env.valuesMissing(), "label null but no missing for %s", file);
      return null;
    }

    // Skylark UserDefinedFunction-s in that file will share this function definition Environment,
    // which will be frozen by the time it is returned by createExtension.
    Extension extension = createExtension(ast, file, importMap, env);

    return new SkylarkImportLookupValue(
        extension, new SkylarkFileDependency(label, fileDependencies.build()));
  }