<commit_before>/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.util;

import groovy.lang.Closure;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.gradle.api.Action;
import org.gradle.internal.deprecation.DeprecationLogger;
import org.gradle.internal.metaobject.DynamicObjectUtil;
import org.gradle.internal.Actions;
import org.gradle.internal.metaobject.ConfigureDelegate;
import org.gradle.internal.metaobject.DynamicInvokeResult;
import org.gradle.internal.metaobject.DynamicObject;
import org.gradle.util.internal.ClosureBackedAction;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;

import static org.gradle.util.internal.CollectionUtils.toStringList;

/**
 * Contains utility methods to configure objects with Groovy Closures.
 * <p>
 * Plugins should avoid using this class and methods that use {@link groovy.lang.Closure} as this makes the plugin harder to use in other languages. Instead, plugins should create methods that use {@link Action}.
 * Here's an example pseudocode:
 * <pre class='autoTested'>
 *     interface MyOptions {
 *         RegularFileProperty getOptionsFile()
 *     }
 *     abstract class MyExtension {
 *         private final MyOptions options
 *
 *         {@literal @}Inject abstract ObjectFactory getObjectFactory()
 *
 *         public MyExtension() {
 *             this.options = getObjectFactory().newInstance(MyOptions)
 *         }
 *
 *         public void options(Action{@literal <?} extends MyOptions{@literal >}  action) {
 *              action.execute(options)
 *         }
 *     }
 *     extensions.create("myExtension", MyExtension)
 *     myExtension {
 *         options {
 *             optionsFile = layout.projectDirectory.file("options.properties")
 *         }
 *     }
 * </pre>
 * <p>
 * Gradle automatically generates a Closure-taking method at runtime for each method with an {@link Action} as a single argument as long as the object is created with {@link org.gradle.api.model.ObjectFactory#newInstance(Class, Object...)}.
 * <p>
 * As a last resort, to apply some configuration represented by a Groovy Closure, a plugin can use {@link org.gradle.api.Project#configure(Object, Closure)}.
 *
 * @deprecated Will be removed in Gradle 9.0.
 */
@Deprecated
public class ConfigureUtil {

    public static <T> T configureByMap(Map<?, ?> properties, T delegate) {
        logDeprecation();
        if (properties.isEmpty()) {
            return delegate;
        }
        DynamicObject dynamicObject = DynamicObjectUtil.asDynamicObject(delegate);

        for (Map.Entry<?, ?> entry : properties.entrySet()) {
            String name = entry.getKey().toString();
            Object value = entry.getValue();

            DynamicInvokeResult result = dynamicObject.trySetProperty(name, value);
            if (result.isFound()) {
                continue;
            }

            result = dynamicObject.tryInvokeMethod(name, value);
            if (!result.isFound()) {
                throw dynamicObject.setMissingProperty(name);
            }
        }

        return delegate;
    }

    public static <T> T configureByMap(Map<?, ?> properties, T delegate, Collection<?> mandatoryKeys) {
        if (!mandatoryKeys.isEmpty()) {
            Collection<String> missingKeys = toStringList(mandatoryKeys);
            missingKeys.removeAll(toStringList(properties.keySet()));
            if (!missingKeys.isEmpty()) {
                throw new IncompleteInputException("Input configuration map does not contain following mandatory keys: " + missingKeys, missingKeys);
            }
        }
        return configureByMap(properties, delegate);
    }

    /**<commit_msg>Do not nag for ConfigureUtil.configureByMap(props,delegate)<commit_after>/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.util;

import groovy.lang.Closure;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.gradle.api.Action;
import org.gradle.internal.deprecation.DeprecationLogger;
import org.gradle.internal.metaobject.DynamicObjectUtil;
import org.gradle.internal.Actions;
import org.gradle.internal.metaobject.ConfigureDelegate;
import org.gradle.internal.metaobject.DynamicInvokeResult;
import org.gradle.internal.metaobject.DynamicObject;
import org.gradle.util.internal.ClosureBackedAction;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;

import static org.gradle.util.internal.CollectionUtils.toStringList;

/**
 * Contains utility methods to configure objects with Groovy Closures.
 * <p>
 * Plugins should avoid using this class and methods that use {@link groovy.lang.Closure} as this makes the plugin harder to use in other languages. Instead, plugins should create methods that use {@link Action}.
 * Here's an example pseudocode:
 * <pre class='autoTested'>
 *     interface MyOptions {
 *         RegularFileProperty getOptionsFile()
 *     }
 *     abstract class MyExtension {
 *         private final MyOptions options
 *
 *         {@literal @}Inject abstract ObjectFactory getObjectFactory()
 *
 *         public MyExtension() {
 *             this.options = getObjectFactory().newInstance(MyOptions)
 *         }
 *
 *         public void options(Action{@literal <?} extends MyOptions{@literal >}  action) {
 *              action.execute(options)
 *         }
 *     }
 *     extensions.create("myExtension", MyExtension)
 *     myExtension {
 *         options {
 *             optionsFile = layout.projectDirectory.file("options.properties")
 *         }
 *     }
 * </pre>
 * <p>
 * Gradle automatically generates a Closure-taking method at runtime for each method with an {@link Action} as a single argument as long as the object is created with {@link org.gradle.api.model.ObjectFactory#newInstance(Class, Object...)}.
 * <p>
 * As a last resort, to apply some configuration represented by a Groovy Closure, a plugin can use {@link org.gradle.api.Project#configure(Object, Closure)}.
 *
 * @deprecated Will be removed in Gradle 9.0.
 */
@Deprecated
public class ConfigureUtil {

    public static <T> T configureByMap(Map<?, ?> properties, T delegate) {
        // TODO log deprecation once idea is fixed
        return configureByMapInternal(properties, delegate);
    }

    private static <T> T configureByMapInternal(Map<?, ?> properties, T delegate) {
        if (properties.isEmpty()) {
            return delegate;
        }
        DynamicObject dynamicObject = DynamicObjectUtil.asDynamicObject(delegate);

        for (Map.Entry<?, ?> entry : properties.entrySet()) {
            String name = entry.getKey().toString();
            Object value = entry.getValue();

            DynamicInvokeResult result = dynamicObject.trySetProperty(name, value);
            if (result.isFound()) {
                continue;
            }

            result = dynamicObject.tryInvokeMethod(name, value);
            if (!result.isFound()) {
                throw dynamicObject.setMissingProperty(name);
            }
        }

        return delegate;
    }

    public static <T> T configureByMap(Map<?, ?> properties, T delegate, Collection<?> mandatoryKeys) {
        if (!mandatoryKeys.isEmpty()) {
            Collection<String> missingKeys = toStringList(mandatoryKeys);
            missingKeys.removeAll(toStringList(properties.keySet()));
            if (!missingKeys.isEmpty()) {
                throw new IncompleteInputException("Input configuration map does not contain following mandatory keys: " + missingKeys, missingKeys);
            }
        }
        logDeprecation();
        return configureByMapInternal(properties, delegate);
    }

    /**
{'fraction_non_alphanumeric': 0.09787668899738844, 'fraction_numerical': 0.0022709208584080847, 'mean_word_length': 3.079666512274201, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '680518', 'n_tokens_mistral': 2298, 'n_tokens_neox': 2215, 'n_words': 698}