Search in sources :

Example 1 with UninstantiatedDescribable

use of org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable in project workflow-cps-plugin by jenkinsci.

the class ArgumentsActionImpl method sanitizeObjectAndRecordMutation.

/**
 * Recursively sanitize a single object by:
 *   - Exploding {@link Step}s and {@link UninstantiatedDescribable}s into their Maps to sanitize
 *   - Removing unsafe strings using {@link #isStringSafe(String, EnvVars, Set)} and replace with {@link NotStoredReason#MASKED_VALUE}
 *   - Removing oversized objects using {@link #isOversized(Object)} and replacing with {@link NotStoredReason#OVERSIZE_VALUE}
 *  While making an effort not to retain needless copies of objects and to re-use originals where possible
 *   (including the Step or UninstantiatedDescribable)
 */
@CheckForNull
@SuppressWarnings("unchecked")
Object sanitizeObjectAndRecordMutation(@CheckForNull Object o, @CheckForNull EnvVars vars) {
    // Package scoped so we can test it directly
    Object tempVal = o;
    if (tempVal instanceof Step) {
        // Ugly but functional used for legacy syntaxes with metasteps
        tempVal = ((Step) tempVal).getDescriptor().defineArguments((Step) tempVal);
    } else if (tempVal instanceof UninstantiatedDescribable) {
        tempVal = ((UninstantiatedDescribable) tempVal).toMap();
    }
    if (isOversized(tempVal)) {
        this.isUnmodifiedBySanitization = false;
        return NotStoredReason.OVERSIZE_VALUE;
    }
    Object modded = tempVal;
    if (modded instanceof Map) {
        // Recursive sanitization, oh my!
        modded = sanitizeMapAndRecordMutation((Map) modded, vars);
    } else if (modded instanceof List) {
        modded = sanitizeListAndRecordMutation((List) modded, vars);
    } else if (modded instanceof String && vars != null && !vars.isEmpty() && !isStringSafe((String) modded, vars, SAFE_ENVIRONMENT_VARIABLES)) {
        this.isUnmodifiedBySanitization = false;
        return NotStoredReason.MASKED_VALUE;
    }
    if (modded != tempVal) {
        // Sanitization stripped out some values, so we need to record that and return modified version
        this.isUnmodifiedBySanitization = false;
        if (o instanceof UninstantiatedDescribable) {
            // Need to retain the symbol.
            UninstantiatedDescribable ud = (UninstantiatedDescribable) o;
            return new UninstantiatedDescribable(ud.getSymbol(), ud.getKlass(), (Map<String, ?>) modded);
        } else {
            return modded;
        }
    } else {
        // Any mutation was just from exploding step/uninstantiated describable, and we can just use the original
        return o;
    }
}
Also used : UninstantiatedDescribable(org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable) ArrayList(java.util.ArrayList) List(java.util.List) Step(org.jenkinsci.plugins.workflow.steps.Step) HashMap(java.util.HashMap) Map(java.util.Map) CheckForNull(javax.annotation.CheckForNull)

Example 2 with UninstantiatedDescribable

use of org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable 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 3 with UninstantiatedDescribable

use of org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable 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)

Aggregations

UninstantiatedDescribable (org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable)3 List (java.util.List)2 Map (java.util.Map)2 TreeMap (java.util.TreeMap)2 DescribableParameter (org.jenkinsci.plugins.structs.describable.DescribableParameter)2 Step (org.jenkinsci.plugins.workflow.steps.Step)2 StepDescriptor (org.jenkinsci.plugins.workflow.steps.StepDescriptor)2 GString (groovy.lang.GString)1 GroovyObject (groovy.lang.GroovyObject)1 GroovyRuntimeException (groovy.lang.GroovyRuntimeException)1 ExtensionList (hudson.ExtensionList)1 Descriptor (hudson.model.Descriptor)1 BuildStepDescriptor (hudson.tasks.BuildStepDescriptor)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 CheckForNull (javax.annotation.CheckForNull)1 SimpleBuildStep (jenkins.tasks.SimpleBuildStep)1 JSONObject (net.sf.json.JSONObject)1 MissingContextVariableException (org.jenkinsci.plugins.workflow.steps.MissingContextVariableException)1