use of org.jenkinsci.plugins.structs.describable.DescribableParameter in project workflow-cps-plugin by jenkinsci.
the class DSL method parseArgs.
static NamedArgsAndClosure parseArgs(Object arg, StepDescriptor d) {
boolean singleArgumentOnly = false;
try {
DescribableModel<?> stepModel = DescribableModel.of(d.clazz);
singleArgumentOnly = stepModel.hasSingleRequiredParameter() && stepModel.getParameters().size() == 1;
if (singleArgumentOnly) {
// Can fetch the one argument we need
DescribableParameter dp = stepModel.getSoleRequiredParameter();
String paramName = (dp != null) ? dp.getName() : null;
return parseArgs(arg, d.takesImplicitBlockArgument(), paramName, singleArgumentOnly);
}
} catch (NoStaplerConstructorException e) {
// Ignore steps without databound constructors and treat them as normal.
}
return parseArgs(arg, d.takesImplicitBlockArgument(), loadSoleArgumentKey(d), singleArgumentOnly);
}
use of org.jenkinsci.plugins.structs.describable.DescribableParameter in project workflow-cps-plugin by jenkinsci.
the class Snippetizer method getQuasiDescriptors.
@Restricted(NoExternalUse.class)
public Collection<QuasiDescriptor> getQuasiDescriptors(boolean advanced) {
TreeSet<QuasiDescriptor> t = new TreeSet<>();
for (StepDescriptor d : StepDescriptor.all()) {
if (d.isAdvanced() == advanced) {
t.add(new QuasiDescriptor(d));
if (d.isMetaStep()) {
DescribableModel<?> m = DescribableModel.of(d.clazz);
Collection<DescribableParameter> parameters = m.getParameters();
if (parameters.size() == 1) {
DescribableParameter delegate = parameters.iterator().next();
if (delegate.isRequired()) {
if (delegate.getType() instanceof HeterogeneousObjectType) {
// TODO HeterogeneousObjectType does not yet expose symbol information, and DescribableModel.symbolOf is private
for (DescribableModel<?> delegateOptionSchema : ((HeterogeneousObjectType) delegate.getType()).getTypes().values()) {
Class<?> delegateOptionType = delegateOptionSchema.getType();
Descriptor<?> delegateDescriptor = Jenkins.getActiveInstance().getDescriptorOrDie(delegateOptionType.asSubclass(Describable.class));
Set<String> symbols = SymbolLookup.getSymbolValue(delegateDescriptor);
if (!symbols.isEmpty()) {
t.add(new QuasiDescriptor(delegateDescriptor));
}
}
}
}
}
// TODO currently not handling metasteps with other parameters, either required or (like GenericSCMStep) not
}
}
}
return t;
}
use of org.jenkinsci.plugins.structs.describable.DescribableParameter in project workflow-cps-plugin by jenkinsci.
the class DSL method invokeDescribable.
/**
* When {@link #invokeMethod(String, Object)} is calling a generic {@link Descriptor}
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Object invokeDescribable(String symbol, Object _args) {
List<StepDescriptor> metaSteps = StepDescriptor.metaStepsOf(symbol);
StepDescriptor metaStep = metaSteps.size() == 1 ? metaSteps.get(0) : null;
boolean singleArgumentOnly = false;
if (metaStep != null) {
Descriptor symbolDescriptor = SymbolLookup.get().findDescriptor((Class) (metaStep.getMetaStepArgumentType()), symbol);
DescribableModel<?> symbolModel = DescribableModel.of(symbolDescriptor.clazz);
singleArgumentOnly = symbolModel.hasSingleRequiredParameter() && symbolModel.getParameters().size() == 1;
}
// The only time a closure is valid is when the resulting Describable is immediately executed via a meta-step
NamedArgsAndClosure args = parseArgs(_args, metaStep != null && metaStep.takesImplicitBlockArgument(), UninstantiatedDescribable.ANONYMOUS_KEY, singleArgumentOnly);
UninstantiatedDescribable ud = new UninstantiatedDescribable(symbol, null, args.namedArgs);
if (metaStep == null) {
// might be resolved with a specific type.
return ud;
} else {
Descriptor d = SymbolLookup.get().findDescriptor((Class) (metaStep.getMetaStepArgumentType()), symbol);
try {
// execute this Describable through a meta-step
// split args between MetaStep (represented by mm) and Describable (represented by dm)
DescribableModel<?> mm = DescribableModel.of(metaStep.clazz);
DescribableModel<?> dm = DescribableModel.of(d.clazz);
DescribableParameter p = mm.getFirstRequiredParameter();
if (p == null) {
// meta-step not having a required parameter is a bug in this meta step
throw new IllegalArgumentException("Attempted to use meta-step " + metaStep.getFunctionName() + " to process " + symbol + " but this meta-step is buggy; it has no mandatory parameter");
}
// order of preference:
// 1. mandatory parameter in mm
// 2. mandatory parameter in dm
// 3. other parameters in mm
// 4. other parameters in dm
// mm is preferred over dm because that way at least the arguments that mm defines
// act consistently
Map<String, Object> margs = new TreeMap<>();
Map<String, Object> dargs = new TreeMap<>();
for (Entry<String, ?> e : ud.getArguments().entrySet()) {
String n = e.getKey();
Object v = e.getValue();
DescribableParameter mp = mm.getParameter(n);
DescribableParameter dp = dm.getParameter(n);
if (mp != null && mp.isRequired()) {
margs.put(n, v);
} else if (dp != null && dp.isRequired()) {
dargs.put(n, v);
} else if (mp != null) {
margs.put(n, v);
} else {
// dp might be null, but this error will be caught by UD.instantiate() later
dargs.put(n, v);
}
}
ud = new UninstantiatedDescribable(symbol, null, dargs);
margs.put(p.getName(), ud);
return invokeStep(metaStep, new NamedArgsAndClosure(margs, args.body));
} catch (Exception e) {
throw new IllegalArgumentException("Failed to prepare " + symbol + " step", e);
}
}
}
use of org.jenkinsci.plugins.structs.describable.DescribableParameter in project workflow-cps-plugin by jenkinsci.
the class Snippetizer method object2Groovy.
/**
* Renders the invocation syntax to re-create a given object 'o' into 'b'
*
* @param nestedExp
* true if this object is written as a nested expression (in which case we always produce parenthesis for readability)
* @return the same object as 'b'
*/
static StringBuilder object2Groovy(StringBuilder b, Object o, boolean nestedExp) throws UnsupportedOperationException {
if (o == null) {
return b.append("null");
}
final Class<?> clazz = o.getClass();
if (clazz == String.class || clazz == Character.class) {
String text = String.valueOf(o);
if (text.contains("\n")) {
b.append("'''").append(text.replace("\\", "\\\\").replace("'", "\\'")).append("'''");
} else {
b.append('\'').append(text.replace("\\", "\\\\").replace("'", "\\'")).append('\'');
}
return b;
}
if (clazz == Boolean.class || clazz == Integer.class || clazz == Long.class || clazz == Float.class || clazz == Double.class || clazz == Byte.class || clazz == Short.class) {
return b.append(o);
}
if (o instanceof List) {
return list2groovy(b, (List<?>) o);
}
if (o instanceof Map) {
return map2groovy(b, (Map) o);
}
if (o instanceof UninstantiatedDescribable) {
return ud2groovy(b, (UninstantiatedDescribable) o, false, nestedExp);
}
for (StepDescriptor d : StepDescriptor.all()) {
if (d.clazz.equals(clazz)) {
Step step = (Step) o;
UninstantiatedDescribable uninst = d.uninstantiate(step);
boolean blockArgument = d.takesImplicitBlockArgument();
if (d.isMetaStep()) {
// if we have a symbol name for the wrapped Describable, we can produce
// a more concise form that hides it
DescribableModel<?> m = DescribableModel.of(d.clazz);
DescribableParameter p = m.getFirstRequiredParameter();
if (p != null) {
Object wrapped = uninst.getArguments().get(p.getName());
if (wrapped instanceof UninstantiatedDescribable) {
// if we cannot represent this 'o' in a concise syntax that hides meta-step, set this to true
boolean failSimplification = false;
UninstantiatedDescribable nested = (UninstantiatedDescribable) wrapped;
TreeMap<String, Object> copy = new TreeMap<String, Object>(nested.getArguments());
for (Entry<String, ?> e : uninst.getArguments().entrySet()) {
if (!e.getKey().equals(p.getName())) {
if (copy.put(e.getKey(), e.getValue()) != null) {
// collision between a parameter in meta-step and wrapped-step,
// which cannot be reconciled unless we explicitly write out
// meta-step
failSimplification = true;
}
}
}
if (!canUseMetaStep(nested))
failSimplification = true;
if (!failSimplification) {
// write out in a short-form
UninstantiatedDescribable combined = new UninstantiatedDescribable(nested.getSymbol(), nested.getKlass(), copy);
combined.setModel(nested.getModel());
return ud2groovy(b, combined, blockArgument, nestedExp);
}
}
} else {
// this can only happen with buggy meta-step
LOGGER.log(Level.WARNING, "Buggy meta-step " + d.clazz + " defines no mandatory parameter");
// use the default code path to write it out as: metaStep(describable(...))
}
}
uninst.setSymbol(d.getFunctionName());
return functionCall(b, uninst, blockArgument, nestedExp);
}
}
// unknown type
return b.append("<object of type ").append(clazz.getCanonicalName()).append('>');
}
use of org.jenkinsci.plugins.structs.describable.DescribableParameter in project workflow-cps-plugin by jenkinsci.
the class Snippetizer method doGenerateSnippet.
// accessed via REST API
@Restricted(DoNotUse.class)
public HttpResponse doGenerateSnippet(StaplerRequest req, @QueryParameter String json) throws Exception {
// TODO is there not an easier way to do this? Maybe Descriptor.newInstancesFromHeteroList on a one-element JSONArray?
JSONObject jsonO = JSONObject.fromObject(json);
Jenkins j = Jenkins.getActiveInstance();
Class<?> c = j.getPluginManager().uberClassLoader.loadClass(jsonO.getString("stapler-class"));
Descriptor descriptor = j.getDescriptor(c.asSubclass(Describable.class));
if (descriptor == null) {
return HttpResponses.plainText("<could not find " + c.getName() + ">");
}
Object o;
try {
o = descriptor.newInstance(req, jsonO);
} catch (RuntimeException x) {
// e.g. IllegalArgumentException
return HttpResponses.plainText(Functions.printThrowable(x));
}
try {
Step step = null;
if (o instanceof Step) {
step = (Step) o;
} else {
// Look for a metastep which could take this as its delegate.
for (StepDescriptor d : StepDescriptor.allMeta()) {
if (d.getMetaStepArgumentType().isInstance(o)) {
DescribableModel<?> m = DescribableModel.of(d.clazz);
DescribableParameter soleRequiredParameter = m.getSoleRequiredParameter();
if (soleRequiredParameter != null) {
step = d.newInstance(Collections.singletonMap(soleRequiredParameter.getName(), o));
break;
}
}
}
}
if (step == null) {
return HttpResponses.plainText("Cannot find a step corresponding to " + o.getClass().getName());
}
String groovy = step2Groovy(step);
if (descriptor instanceof StepDescriptor && ((StepDescriptor) descriptor).isAdvanced()) {
String warning = Messages.Snippetizer_this_step_should_not_normally_be_used_in();
groovy = "// " + warning + "\n" + groovy;
}
return HttpResponses.plainText(groovy);
} catch (UnsupportedOperationException x) {
Logger.getLogger(CpsFlowExecution.class.getName()).log(Level.WARNING, "failed to render " + json, x);
return HttpResponses.plainText(x.getMessage());
}
}
Aggregations