Search in sources :

Example 1 with DescribableParameter

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);
}
Also used : DescribableParameter(org.jenkinsci.plugins.structs.describable.DescribableParameter) GString(groovy.lang.GString) NoStaplerConstructorException(org.kohsuke.stapler.NoStaplerConstructorException)

Example 2 with DescribableParameter

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;
}
Also used : DescribableParameter(org.jenkinsci.plugins.structs.describable.DescribableParameter) UninstantiatedDescribable(org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable) Describable(hudson.model.Describable) TreeSet(java.util.TreeSet) HeterogeneousObjectType(org.jenkinsci.plugins.structs.describable.HeterogeneousObjectType) BuildStepDescriptor(hudson.tasks.BuildStepDescriptor) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) Restricted(org.kohsuke.accmod.Restricted)

Example 3 with DescribableParameter

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);
        }
    }
}
Also used : UninstantiatedDescribable(org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable) DescribableParameter(org.jenkinsci.plugins.structs.describable.DescribableParameter) GString(groovy.lang.GString) TreeMap(java.util.TreeMap) NoStaplerConstructorException(org.kohsuke.stapler.NoStaplerConstructorException) GroovyRuntimeException(groovy.lang.GroovyRuntimeException) IOException(java.io.IOException) MissingContextVariableException(org.jenkinsci.plugins.workflow.steps.MissingContextVariableException) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) ClassDescriptor(org.kohsuke.stapler.ClassDescriptor) Descriptor(hudson.model.Descriptor) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) GroovyObject(groovy.lang.GroovyObject)

Example 4 with DescribableParameter

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('>');
}
Also used : UninstantiatedDescribable(org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable) DescribableParameter(org.jenkinsci.plugins.structs.describable.DescribableParameter) Step(org.jenkinsci.plugins.workflow.steps.Step) SimpleBuildStep(jenkins.tasks.SimpleBuildStep) TreeMap(java.util.TreeMap) BuildStepDescriptor(hudson.tasks.BuildStepDescriptor) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) List(java.util.List) ExtensionList(hudson.ExtensionList) JSONObject(net.sf.json.JSONObject) Map(java.util.Map) TreeMap(java.util.TreeMap)

Example 5 with DescribableParameter

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());
    }
}
Also used : DescribableParameter(org.jenkinsci.plugins.structs.describable.DescribableParameter) UninstantiatedDescribable(org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable) Describable(hudson.model.Describable) Step(org.jenkinsci.plugins.workflow.steps.Step) SimpleBuildStep(jenkins.tasks.SimpleBuildStep) Jenkins(jenkins.model.Jenkins) JSONObject(net.sf.json.JSONObject) BuildStepDescriptor(hudson.tasks.BuildStepDescriptor) Descriptor(hudson.model.Descriptor) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) BuildStepDescriptor(hudson.tasks.BuildStepDescriptor) StepDescriptor(org.jenkinsci.plugins.workflow.steps.StepDescriptor) JSONObject(net.sf.json.JSONObject) Restricted(org.kohsuke.accmod.Restricted)

Aggregations

DescribableParameter (org.jenkinsci.plugins.structs.describable.DescribableParameter)5 UninstantiatedDescribable (org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable)4 StepDescriptor (org.jenkinsci.plugins.workflow.steps.StepDescriptor)4 BuildStepDescriptor (hudson.tasks.BuildStepDescriptor)3 GString (groovy.lang.GString)2 Describable (hudson.model.Describable)2 Descriptor (hudson.model.Descriptor)2 TreeMap (java.util.TreeMap)2 SimpleBuildStep (jenkins.tasks.SimpleBuildStep)2 JSONObject (net.sf.json.JSONObject)2 Step (org.jenkinsci.plugins.workflow.steps.Step)2 Restricted (org.kohsuke.accmod.Restricted)2 NoStaplerConstructorException (org.kohsuke.stapler.NoStaplerConstructorException)2 GroovyObject (groovy.lang.GroovyObject)1 GroovyRuntimeException (groovy.lang.GroovyRuntimeException)1 ExtensionList (hudson.ExtensionList)1 IOException (java.io.IOException)1 List (java.util.List)1 Map (java.util.Map)1 TreeSet (java.util.TreeSet)1