private static Artifact getExecutable(RuleContext ruleContext, Object target) throws EvalException { Artifact executable = ruleContext.getRule().getRuleClassObject().outputsDefaultExecutable() // This doesn't actually create a new Artifact just returns the one // created in SkylarkruleContext. ? ruleContext.createOutputArtifact() : null; if (target instanceof SkylarkClassObject) { SkylarkClassObject struct = (SkylarkClassObject) target; if (struct.getValue("executable") != null) { // We need this because of genrule.bzl. This overrides the default executable. executable = cast("executable", struct, Artifact.class, struct.getCreationLoc()); } } return executable; }
private static ConfiguredTarget addStructFields( RuleContext ruleContext, RuleConfiguredTargetBuilder builder, Object target, Artifact executable) throws EvalException { Location loc = null; Runfiles statelessRunfiles = null; Runfiles dataRunfiles = null; Runfiles defaultRunfiles = null; if (target instanceof SkylarkClassObject) { SkylarkClassObject struct = (SkylarkClassObject) target; loc = struct.getCreationLoc(); for (String key : struct.getKeys()) { if (key.equals("files")) { // If we specify files_to_build we don't have the executable in it by default. builder.setFilesToBuild( cast("files", struct, SkylarkNestedSet.class, Artifact.class, loc) .getSet(Artifact.class)); } else if (key.equals("runfiles")) { statelessRunfiles = cast("runfiles", struct, Runfiles.class, loc); } else if (key.equals("data_runfiles")) { dataRunfiles = cast("data_runfiles", struct, Runfiles.class, loc); } else if (key.equals("default_runfiles")) { defaultRunfiles = cast("default_runfiles", struct, Runfiles.class, loc); } else if (!key.equals("executable")) { // We handled executable already. builder.addSkylarkTransitiveInfo(key, struct.getValue(key), loc); } } } if ((statelessRunfiles != null) && (dataRunfiles != null || defaultRunfiles != null)) { throw new EvalException( loc, "Cannot specify the provider 'runfiles' " + "together with 'data_runfiles' or 'default_runfiles'"); } if (statelessRunfiles == null && dataRunfiles == null && defaultRunfiles == null) { // No runfiles specified, set default statelessRunfiles = Runfiles.EMPTY; } RunfilesProvider runfilesProvider = statelessRunfiles != null ? RunfilesProvider.simple(merge(statelessRunfiles, executable)) : RunfilesProvider.withData( // The executable doesn't get into the default runfiles if we have runfiles states. // This is to keep skylark genrule consistent with the original genrule. defaultRunfiles != null ? defaultRunfiles : Runfiles.EMPTY, dataRunfiles != null ? dataRunfiles : Runfiles.EMPTY); builder.addProvider(RunfilesProvider.class, runfilesProvider); Runfiles computedDefaultRunfiles = runfilesProvider.getDefaultRunfiles(); // This works because we only allowed to call a rule *_test iff it's a test type rule. boolean testRule = TargetUtils.isTestRuleName(ruleContext.getRule().getRuleClass()); if (testRule && computedDefaultRunfiles.isEmpty()) { throw new EvalException(loc, "Test rules have to define runfiles"); } if (executable != null || testRule) { RunfilesSupport runfilesSupport = computedDefaultRunfiles.isEmpty() ? null : RunfilesSupport.withExecutable(ruleContext, computedDefaultRunfiles, executable); builder.setRunfilesSupport(runfilesSupport, executable); } try { return builder.build(); } catch (IllegalArgumentException e) { throw new EvalException(loc, e.getMessage()); } }