<commit_before>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright (c) 2013, 6WIND S.A. All rights reserved.                 *
 *                                                                     *
 * This file is part of the Jenkins Lockable Resources Plugin and is   *
 * published under the MIT license.                                    *
 *                                                                     *
 * See the "LICENSE.txt" file for more information.                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package org.jenkins.plugins.lockableresources;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.BulkChange;
import hudson.Extension;
import hudson.model.Run;
import hudson.model.TaskListener;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.jenkins.plugins.lockableresources.queue.LockableResourcesCandidatesStruct;
import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct;
import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct;
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.StaplerRequest;

@Extension
public class LockableResourcesManager extends GlobalConfiguration {

  @Deprecated private transient int defaultPriority;
  @Deprecated private transient String priorityParameterName;
  private List<LockableResource> resources;

  /**
   * Only used when this lockable resource is tried to be locked by {@link LockStep}, otherwise
   * (freestyle builds) regular Jenkins queue is used.
   */
  private List<QueuedContextStruct> queuedContexts = new ArrayList<>();

  public LockableResourcesManager() {
    resources = new ArrayList<>();
    load();
  }

  public List<LockableResource> getResources() {
    return resources;
  }

  public synchronized List<LockableResource> getDeclaredResources() {
    ArrayList<LockableResource> declaredResources = new ArrayList<>();
    for (LockableResource r : resources) {
      if (!r.isEphemeral()) {
        declaredResources.add(r);
      }
    }
    return declaredResources;
  }

  @DataBoundSetter
  public synchronized void setDeclaredResources(List<LockableResource> declaredResources) {
    Map<String, LockableResource> lockedResources = new HashMap<>();
    for (LockableResource r : this.resources) {
      if (!r.isLocked()) continue;
      lockedResources.put(r.getName(), r);
    }

    // Removed from configuration locks became ephemeral.
    ArrayList<LockableResource> mergedResources = new ArrayList<>();
    Set<String> addedLocks = new HashSet<>();
    for (LockableResource r : declaredResources) {
      if (!addedLocks.add(r.getName())) {
        continue;
      }
      LockableResource locked = lockedResources.remove(r.getName());
      if (locked != null) {
        // Merge already locked lock.
        locked.setDescription(r.getDescription());
        locked.setLabels(r.getLabels());
        locked.setEphemeral(false);
        mergedResources.add(locked);
        continue;
      }
      mergedResources.add(r);
    }

    for (LockableResource r : lockedResources.values()) {
      // Removed locks became ephemeral.
      r.setDescription("");
      r.setLabels("");
      r.setEphemeral(true);
      mergedResources.add(r);
    }

    this.resources = mergedResources;
  }

  public List<LockableResource> getResourcesFromProject(String fullName) {
    List<LockableResource> matching = new ArrayList<>();
    for (LockableResource r : resources) {
      String rName = r.getQueueItemProject();
      if (rName != null && rName.equals(fullName)) {
        matching.add(r);
      }
    }
    return matching;
  }

  public List<LockableResource> getResourcesFromBuild(Run<?, ?> build) {
    List<LockableResource> matching = new ArrayList<>();
    for (LockableResource r : resources) {
      Run<?, ?> rBuild = r.getBuild();
      if (rBuild != null && rBuild == build) {
        matching.add(r);
      }
    }
    return matching;
  }

  public Boolean isValidLabel(String label) {
    return this.getAllLabels().contains(label);
  }

  public Set<String> getAllLabels() {
    Set<String> labels = new HashSet<>();
    for (LockableResource r : this.resources) {
      String rl = r.getLabels();
      if (rl == null || "".equals(rl)) continue;
      labels.addAll(Arrays.asList(rl.split("\\s+")));
    }
    return labels;
  }

  public int getFreeResourceAmount(String label) {
    int free = 0;
    for (LockableResource r : this.resources) {
      if (r.isLocked() || r.isQueued() || r.isReserved()) continue;
      if (Arrays.asList(r.getLabels().split("\\s+")).contains(label)) free += 1;
    }
    return free;
  }

  public List<LockableResource> getResourcesWithLabel(String label, Map<String, Object> params) {
    List<LockableResource> found = new ArrayList<>();
    for (LockableResource r : this.resources) {
      if (r.isValidLabel(label, params)) found.add(r);
    }
    return found;
  }

  /**
   * Get a list of resources matching the script.
   *
   * @param script Script
   * @param params Additional parameters
   * @return List of the matching resources
   * @throws ExecutionException Script execution failed for one of the resources. It is considered
   *     as a fatal failure since the requirement list may be incomplete
   * @since TODO
   */
  @Nonnull
  public List<LockableResource> getResourcesMatchingScript(
      @Nonnull SecureGroovyScript script, @CheckForNull Map<String, Object> params)
      throws ExecutionException {
    List<LockableResource> found = new ArrayList<>();
    for (LockableResource r : this.resources) {
      if (r.scriptMatches(script, params)) found.add(r);
    }
    return found;
  }

  public LockableResource fromName(String resourceName) {
    if (resourceName != null) {<commit_msg>JENKINS-57727: Make fromName() synchronized (#191)<commit_after>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright (c) 2013, 6WIND S.A. All rights reserved.                 *
 *                                                                     *
 * This file is part of the Jenkins Lockable Resources Plugin and is   *
 * published under the MIT license.                                    *
 *                                                                     *
 * See the "LICENSE.txt" file for more information.                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package org.jenkins.plugins.lockableresources;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.BulkChange;
import hudson.Extension;
import hudson.model.Run;
import hudson.model.TaskListener;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import jenkins.model.GlobalConfiguration;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.jenkins.plugins.lockableresources.queue.LockableResourcesCandidatesStruct;
import org.jenkins.plugins.lockableresources.queue.LockableResourcesStruct;
import org.jenkins.plugins.lockableresources.queue.QueuedContextStruct;
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.StaplerRequest;

@Extension
public class LockableResourcesManager extends GlobalConfiguration {

  @Deprecated private transient int defaultPriority;
  @Deprecated private transient String priorityParameterName;
  private List<LockableResource> resources;

  /**
   * Only used when this lockable resource is tried to be locked by {@link LockStep}, otherwise
   * (freestyle builds) regular Jenkins queue is used.
   */
  private List<QueuedContextStruct> queuedContexts = new ArrayList<>();

  public LockableResourcesManager() {
    resources = new ArrayList<>();
    load();
  }

  public List<LockableResource> getResources() {
    return resources;
  }

  public synchronized List<LockableResource> getDeclaredResources() {
    ArrayList<LockableResource> declaredResources = new ArrayList<>();
    for (LockableResource r : resources) {
      if (!r.isEphemeral()) {
        declaredResources.add(r);
      }
    }
    return declaredResources;
  }

  @DataBoundSetter
  public synchronized void setDeclaredResources(List<LockableResource> declaredResources) {
    Map<String, LockableResource> lockedResources = new HashMap<>();
    for (LockableResource r : this.resources) {
      if (!r.isLocked()) continue;
      lockedResources.put(r.getName(), r);
    }

    // Removed from configuration locks became ephemeral.
    ArrayList<LockableResource> mergedResources = new ArrayList<>();
    Set<String> addedLocks = new HashSet<>();
    for (LockableResource r : declaredResources) {
      if (!addedLocks.add(r.getName())) {
        continue;
      }
      LockableResource locked = lockedResources.remove(r.getName());
      if (locked != null) {
        // Merge already locked lock.
        locked.setDescription(r.getDescription());
        locked.setLabels(r.getLabels());
        locked.setEphemeral(false);
        mergedResources.add(locked);
        continue;
      }
      mergedResources.add(r);
    }

    for (LockableResource r : lockedResources.values()) {
      // Removed locks became ephemeral.
      r.setDescription("");
      r.setLabels("");
      r.setEphemeral(true);
      mergedResources.add(r);
    }

    this.resources = mergedResources;
  }

  public List<LockableResource> getResourcesFromProject(String fullName) {
    List<LockableResource> matching = new ArrayList<>();
    for (LockableResource r : resources) {
      String rName = r.getQueueItemProject();
      if (rName != null && rName.equals(fullName)) {
        matching.add(r);
      }
    }
    return matching;
  }

  public List<LockableResource> getResourcesFromBuild(Run<?, ?> build) {
    List<LockableResource> matching = new ArrayList<>();
    for (LockableResource r : resources) {
      Run<?, ?> rBuild = r.getBuild();
      if (rBuild != null && rBuild == build) {
        matching.add(r);
      }
    }
    return matching;
  }

  public Boolean isValidLabel(String label) {
    return this.getAllLabels().contains(label);
  }

  public Set<String> getAllLabels() {
    Set<String> labels = new HashSet<>();
    for (LockableResource r : this.resources) {
      String rl = r.getLabels();
      if (rl == null || "".equals(rl)) continue;
      labels.addAll(Arrays.asList(rl.split("\\s+")));
    }
    return labels;
  }

  public int getFreeResourceAmount(String label) {
    int free = 0;
    for (LockableResource r : this.resources) {
      if (r.isLocked() || r.isQueued() || r.isReserved()) continue;
      if (Arrays.asList(r.getLabels().split("\\s+")).contains(label)) free += 1;
    }
    return free;
  }

  public List<LockableResource> getResourcesWithLabel(String label, Map<String, Object> params) {
    List<LockableResource> found = new ArrayList<>();
    for (LockableResource r : this.resources) {
      if (r.isValidLabel(label, params)) found.add(r);
    }
    return found;
  }

  /**
   * Get a list of resources matching the script.
   *
   * @param script Script
   * @param params Additional parameters
   * @return List of the matching resources
   * @throws ExecutionException Script execution failed for one of the resources. It is considered
   *     as a fatal failure since the requirement list may be incomplete
   * @since TODO
   */
  @Nonnull
  public List<LockableResource> getResourcesMatchingScript(
      @Nonnull SecureGroovyScript script, @CheckForNull Map<String, Object> params)
      throws ExecutionException {
    List<LockableResource> found = new ArrayList<>();
    for (LockableResource r : this.resources) {
      if (r.scriptMatches(script, params)) found.add(r);
    }
    return found;
  }

  public synchronized LockableResource fromName(String resourceName) {
    if (resourceName != null) {
{'fraction_non_alphanumeric': 0.11760541220893644, 'fraction_numerical': 0.0017306482064191316, 'mean_word_length': 3.094363929146538, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6275776', 'n_tokens_mistral': 3691, 'n_tokens_neox': 3561, 'n_words': 855}