/** * 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())); }