package org.jenkinsci.plugins.p4.client; import com.perforce.p4java.core.IDepot; import com.perforce.p4java.core.file.FileSpecBuilder; import com.perforce.p4java.core.file.FileSpecOpStatus; import com.perforce.p4java.core.file.IFileSpec; import com.perforce.p4java.exception.P4JavaException; import com.perforce.p4java.option.server.GetDepotFilesOptions; import com.perforce.p4java.option.server.GetDirectoriesOptions; import com.perforce.p4java.server.IOptionsServer; import hudson.model.AutoCompletionCandidates; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class NavigateHelper implements Closeable { private final int max; private final IOptionsServer p4; private final String root; private List<Node> nodes; public NavigateHelper(IOptionsServer p4) { this.max = 0; this.p4 = p4; String client = p4.getCurrentClient().getName(); this.root = "//" + client + "/"; } public NavigateHelper(int max) { this.max = max; p4 = ConnectionFactory.getConnection(); root = ""; } /** * Matches for a partial depot path * * @param depotPath a Perforce Depot path e.g. //depot/pro * @return matches for the depot path e.g. //depot/projA */ public AutoCompletionCandidates getCandidates(String depotPath) { nodes = new ArrayList<>(); buildPaths(depotPath); return getCandidates(); } /** * Get a list of path nodes. * * @param localPath a relative local path e.g. "" for root or "projA/comX" * @return list of nodes */ public List<Node> getNodes(String localPath) { nodes = new ArrayList<>(); String path = root + localPath; if (!path.isEmpty() && !path.endsWith("/")) { path = path + "/"; } buildPaths(path); return nodes; } private void buildPaths(String value) { try { if (!value.startsWith("//")) { value = "//" + value; } // remove leading '//' markers for depot matching String depot = value.substring(2); if (!depot.contains("/")) { if (!listDepots(depot)) { return; } } listDirs(value); listFiles(value); } catch (P4JavaException e) { } } /** * @param value path to match * @return true if value is a depot, false if partial match. e.g. false is returned * for 'dep' as it is only partial match to 'depot', even thought there may be only one match. * @throws P4JavaException */ private boolean listDepots(String value) throws P4JavaException { if (p4 != null) { List<IDepot> list = p4.getDepots(); for (IDepot l : list) { if (l.getName().equals(value)) { // complete match, return early nodes = new ArrayList<>(); return true; } if (l.getName().startsWith(value)) { nodes.add(new Node("//" + l.getName(), true)); } } } return false; } private void listDirs(String value) throws P4JavaException { if (p4 != null && value.length() > 4) { List<IFileSpec> dirs = specBuilder(value); GetDirectoriesOptions opts = new GetDirectoriesOptions(); List<IFileSpec> list = p4.getDirectories(dirs, opts); if (list == null) { return; } if (max > 0 && list.size() > max) { list = list.subList(0, max); } for (IFileSpec l : list) { String dir = l.getOriginalPathString(); if (dir != null) { nodes.add(new Node(dir, true)); } } } } private void listFiles(String value) throws P4JavaException { if (p4 != null && value.length() > 4) { List<IFileSpec> files = specBuilder(value); GetDepotFilesOptions opts = new GetDepotFilesOptions(); if (max > 0) { opts.setMaxResults(max); } List<IFileSpec> list = p4.getDepotFiles(files, opts); for (IFileSpec l : list) { if (l.getOpStatus().equals(FileSpecOpStatus.VALID)) { nodes.add(new Node(l.getDepotPathString(), false)); } } } } private List<IFileSpec> specBuilder(String value) { List<IFileSpec> files = FileSpecBuilder.makeFileSpecList(value + "*"); return files; } private AutoCompletionCandidates getCandidates() { AutoCompletionCandidates c = new AutoCompletionCandidates(); for (Node node : nodes) { c.add(node.getDepotPath()); } return c; } @Override public void close() throws IOException { try { p4.disconnect(); } catch (P4JavaException e) { throw new IOException(e); } } public static final class Node { private String name; private String depotPath; private boolean isDir; protected Node(String depotPath, boolean isDir) { this.isDir = isDir; this.depotPath = depotPath; this.name = depotPath.substring(depotPath.lastIndexOf("/") + 1); if (isDir && !depotPath.endsWith("/")) { this.depotPath = depotPath + "/"; } } public String getName() { return name; } public String getDepotPath() { return depotPath; } public boolean isDir() { return isDir; } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#6 | 28508 | Paul Allen |
Cache P4TICKET in session. Session cache now keyed on Credential ID and stores: User, Expiry time and Ticket. |
||
#5 | 28464 | Paul Allen |
Formalise user session cache. Added Jelly options to Global Configuration. User cache is disabled by default. Ticket Minimum life is set to 30 minutes. JENKINS-60141 |
||
#4 | 28460 | Paul Allen |
Session cache to track ticket time. Initial design to reduce 'p4 login -s' calls with user session cache to track ticket time. |
||
#3 | 23373 | Paul Allen |
Lightweight checkout support. Implementation for scm-api classes SCMFile and SCMFileSystem, allowing Jenkins to navigate Perforce within the scope of a workspace view. Lightweight checkout uses a tempoary Perforce workspace to naviagete and fetch the files. The client name and client view mapping will be modified from a template name e.g. jenkins-${NODE_NAME}-${JOB_NAME} to the tempoary name jenkinsTemp-UUID. Alternativly if a user as used ${P4_CLIENT} in the client mapping this will remain unchanged and will be get expanded during the job run. JENKINS-45999 JENKINS-46269 |
||
#2 | 23263 | Paul Allen | Update NavigateHelper for future use. | ||
#1 | 9690 | Paul Allen |
[Branching using p4-jenkins] Release 1.0.1 |
||
//guest/paul_allen/dev/p4-jenkins/p4-client/src/main/java/org/jenkinsci/plugins/p4/client/NavigateHelper.java | |||||
#1 | 9672 | Paul Allen | Refactor name from 'p4_client' to 'p4'. | ||
//guest/paul_allen/dev/p4-jenkins/p4-client/src/main/java/org/jenkinsci/plugins/p4_client/client/NavigateHelper.java | |||||
#1 | 9133 | Paul Allen |
Added Workspace mode for versioned Client Specs. Client Spec can be specified by depot path and used to configure workspace for build. - Includes fix for removing header when using p4 print. |