package org.jenkinsci.plugins.p4.workspace; import com.perforce.p4java.client.IClient; import com.perforce.p4java.client.IClientSummary.ClientLineEnd; import com.perforce.p4java.client.IClientViewMapping; import com.perforce.p4java.core.file.FileSpecBuilder; import com.perforce.p4java.core.file.IFileSpec; import com.perforce.p4java.exception.P4JavaException; import com.perforce.p4java.impl.generic.client.ClientOptions; import com.perforce.p4java.impl.generic.client.ClientView; import com.perforce.p4java.impl.generic.client.ClientView.ClientViewMapping; import com.perforce.p4java.impl.mapbased.client.Client; import com.perforce.p4java.option.server.GetFileContentsOptions; import com.perforce.p4java.server.IOptionsServer; import hudson.AbortException; import hudson.Extension; import hudson.model.AutoCompletionCandidates; import hudson.util.FormValidation; import net.sf.json.JSONObject; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.jenkinsci.Symbol; import org.jenkinsci.plugins.p4.client.ConnectionFactory; import org.jenkinsci.plugins.p4.client.ViewMapHelper; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.bind.JavaScriptMethod; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ManualWorkspaceImpl extends Workspace implements Serializable { private static final long serialVersionUID = 1L; private String name; public WorkspaceSpec spec; private static final Logger logger = Logger.getLogger(ManualWorkspaceImpl.class.getName()); private static final String InitialViewExpandKey = "P4_INITIAL_VIEW"; @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } public WorkspaceSpec getSpec() { return spec; } public void setSpec(WorkspaceSpec spec) { this.spec = spec; } @Override public WorkspaceType getType() { return WorkspaceType.MANUAL; } @DataBoundConstructor public ManualWorkspaceImpl(String charset, boolean pinHost, String name, WorkspaceSpec spec, boolean cleanup) { super(charset, pinHost, cleanup); this.name = name; this.spec = spec; } @Deprecated public ManualWorkspaceImpl(String charset, boolean pinHost, String name, WorkspaceSpec spec) { super(charset, pinHost, false); this.name = name; this.spec = spec; } @Override public Object clone() throws CloneNotSupportedException { ManualWorkspaceImpl ws = (ManualWorkspaceImpl) super.clone(); ws.spec = (WorkspaceSpec) spec.clone(); return ws; } private ClientView getClientView(IOptionsServer connection, WorkspaceSpec workspaceSpec) throws Exception { String clientName = getFullName(); ClientView clientView = new ClientView(); int order = 0; String specString = getExpand().format(workspaceSpec.getView(), true); boolean fromFile = false; if (specString.startsWith("@")) { // extract View from file: JENKINS-69491. fromFile = true; logger.fine("P4: view from file=" + specString); String specPathFull = specString.substring(1).trim(); List<IFileSpec> file = FileSpecBuilder.makeFileSpecList(specPathFull); GetFileContentsOptions printOpts = new GetFileContentsOptions(); printOpts.setNoHeaderLine(true); InputStream ins = connection.getFileContents(file, printOpts); try { specString = IOUtils.toString(ins, "UTF-8"); } finally { ins.close(); } specString = getExpand().format(specString, true); } // Split on new line and trim any following white space for (String line : specString.split("\n\\s*")) { String origName = getExpand().format(getName(), false); line = line.replace(origName, clientName); line = adjustViewLine(line, clientName, fromFile); try { ClientViewMapping entry = new ClientViewMapping(order, line); order++; clientView.addEntry(entry); } catch (Exception e) { String msg = "P4: invalid client view: " + line; logger.warning(msg); throw new AbortException(msg); } } return clientView; } // for matching the depot/clients paths in view line. private static final Pattern PAT_DETECT = Pattern.compile("//([^/]*)/"); /** * Support for old plugin view mappings, see JENKINS-69491. * Two possible actions: * 1) If view has only a LHS, construct a RHS. * <pre>//depot/path/to/product/...</pre> * becomes: * <pre>//depot/path/to/product/... //CLIENT/path/to/product/...</pre> * Note that this is different from a p4sync constructed RHS. * 2) if view came from a file, substitute the clientName in the RHS. p4sync has already * created the RHS correctly so don't alter. * @param line one line of a view * @param clientName client name for RHS * @param adjustClientName use true to fix clientName in RHS (for when RHS comes from a file) * @return */ public String adjustViewLine(String line, String clientName, boolean adjustClientName) { line = getExpand().format(line, true); Matcher matcher = PAT_DETECT.matcher(line); // first found is depot name, optional second is clientname String depot = null, client = null; if (matcher.find()) { depot = matcher.group(1); if (matcher.find()) { client = matcher.group(1); } } if (depot != null && client == null) { // compose RHS. line = ViewMapHelper.getClientView(Arrays.asList(new String[]{line}), clientName, true, false); // getClientView() adds the depot to the RHS: we remove it here. line = line.replace("//" + clientName + "/" + depot, "//" + clientName); } else if (client != null && adjustClientName) { line = line.replace("//" + client, "//" + clientName); } return line; } private ArrayList<String> getChangeView(IOptionsServer connection, WorkspaceSpec workspaceSpec) throws Exception { ArrayList<String> changeView = new ArrayList<>(); String view = workspaceSpec.getChangeView(); if (view != null) { String specString = getExpand().format(view, true); if (specString.startsWith("@")) { // extract View from file: JENKINS-69491. logger.fine("P4: view from file=" + specString); String specPathFull = specString.substring(1).trim(); List<IFileSpec> file = FileSpecBuilder.makeFileSpecList(specPathFull); GetFileContentsOptions printOpts = new GetFileContentsOptions(); printOpts.setNoHeaderLine(true); InputStream ins = null; try { ins = connection.getFileContents(file, printOpts); specString = IOUtils.toString(ins, "UTF-8"); } finally { if (ins != null) { ins.close(); } } specString = getExpand().format(specString, true); } for (String line : specString.split("\\n")) { changeView.add(line); } } return changeView; } private ClientOptions getClientOptions(WorkspaceSpec spec) { ClientOptions options = new ClientOptions(); options.setAllWrite(spec.allwrite); options.setClobber(spec.clobber); options.setCompress(spec.compress); options.setLocked(spec.locked); options.setModtime(spec.modtime); options.setRmdir(spec.rmdir); return options; } @Override public IClient setClient(IOptionsServer connection, String user) throws Exception { // expands Workspace name if formatters are used. String clientName = getFullName(); IClient iclient = connection.getClient(clientName); // If a new client then initialise if (iclient == null) { logger.info("P4: Creating manual client: " + clientName); iclient = new Client(connection); iclient.setName(clientName); iclient.setOwnerName(user); iclient.setRoot(getRootPath()); if (connection.getServerVersionNumber() >= 20162) { WorkspaceSpecType type = parseClientType(getSpec().getType()); if (connection.getServerVersionNumber() >= type.getMinVersion()) { iclient.setType(type.getId()); } } } // Owner set for use with p4maven iclient.setOwnerName(user); // Set options iclient.setOptions(getClientOptions(getSpec())); iclient.setLineEnd(parseLineEnd(getSpec().getLine())); // Expand Stream name String streamFullName = getSpec().getStreamName(); if (streamFullName != null) { streamFullName = getExpand().format(streamFullName, true); } iclient.setStream(streamFullName); String streamAtChange = getSpec().getStreamAtChange(); if(StringUtils.isNotEmpty(streamAtChange)){ streamAtChange = getExpand().format(streamAtChange,true); iclient.setStreamAtChange(Integer.parseInt(streamAtChange)); } // Set Client view iclient.setClientView(getClientView(connection, getSpec())); // Set Change view if (connection.getServerVersionNumber() >= 20172) { iclient.setChangeView(getChangeView(connection, getSpec())); } // Allow change between GRAPH and WRITEABLE if (connection.getServerVersionNumber() >= 20162) { WorkspaceSpecType type = parseClientType(getSpec().getType()); if (connection.getServerVersionNumber() >= type.getMinVersion()) { switch (type) { case GRAPH: case WRITABLE: iclient.setType(type.getId()); break; default: } } } iclient.setServerId(getSpec().getServerID()); // Set Backup option, defaults to enable (enable/disable) if (connection.getServerVersionNumber() >= 20172) { if (getSpec().isBackup()) { iclient.setBackup("enable"); } else { iclient.setBackup("disable"); } } return iclient; } private ClientLineEnd parseLineEnd(String line) { for (ClientLineEnd end : ClientLineEnd.values()) { if (end.name().equalsIgnoreCase(line)) { return end; } } return ClientLineEnd.LOCAL; } private WorkspaceSpecType parseClientType(String line) { for (WorkspaceSpecType type : WorkspaceSpecType.values()) { if (type.name().equalsIgnoreCase(line)) { return type; } } return WorkspaceSpecType.WRITABLE; } @Extension @Symbol("manualSpec") public static final class DescriptorImpl extends WorkspaceDescriptor { @Override public String getDisplayName() { return "Manual (custom view)"; } /** * Provides auto-completion for workspace names. Stapler finds this * method via the naming convention. * * @param value The text that the user entered. * @return suggestion */ public AutoCompletionCandidates doAutoCompleteName(@QueryParameter String value) { return autoCompleteName(value); } public FormValidation doCheckName(@QueryParameter String value) { return checkClientName(value); } } @JavaScriptMethod public JSONObject getSpecJSON(String client) { try { IOptionsServer p4 = ConnectionFactory.getConnection(); IClient c = p4.getClient(client); StringBuffer sb = new StringBuffer(); for (IClientViewMapping view : c.getClientView()) { sb.append(view.toString(" ", true)); sb.append("\n"); } JSONObject option = new JSONObject(); option.put("allwrite", c.getOptions().isAllWrite()); option.put("clobber", c.getOptions().isClobber()); option.put("compress", c.getOptions().isCompress()); option.put("locked", c.getOptions().isLocked()); option.put("modtime", c.getOptions().isModtime()); option.put("rmdir", c.getOptions().isRmdir()); JSONObject spec = new JSONObject(); spec.put("stream", (c.getStream() == null) ? "" : c.getStream()); spec.put("line", c.getLineEnd().name()); spec.put("view", sb.toString()); spec.put("options", option); return spec; } catch (P4JavaException e) { JSONObject option = new JSONObject(); option.put("allwrite", false); option.put("clobber", true); option.put("compress", false); option.put("locked", false); option.put("modtime", false); option.put("rmdir", false); JSONObject spec = new JSONObject(); spec.put("stream", ""); spec.put("line", "LOCAL"); spec.put("view", "please define view..."); spec.put("options", option); return spec; } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#39 | 30144 | Sandeep Kumar |
Merge pull request #[184] from [lleroy/manual-spec-from-file-in-perforce-view] [JENKINS-69491] Implement support for "@/path/to/spec" for "Change View" |
||
#38 | 29848 | Sandeep Kumar |
Merge pull request #195 from jenkinsci/StreamAtChange Support StreamAtChange for ManualWorkspace. |
||
#37 | 29322 | Paul Allen | Remove self-closing element | ||
#36 | 29213 | Paul Allen |
Merge pull request #159 from joel-f-brown/bugsView For ManualWorkspace views from a file, construct RHS if missing. |
||
#35 | 28009 | Paul Allen |
Merge pull request #130 from lleroy/manual-spec-from-file-in-perforce Implemented support for "Manual Spec" stored in a file in Perforce |
||
#34 | 27675 | Paul Allen |
Substitute missing Axes for Key Name. Added useKey option to substitute empty keys in client views, depot paths and stream paths. JENKINS-55985 |
||
#33 | 26673 | Paul Allen |
Code cleanup - remove calls to Deprecated methods - Deprecated classes like AbstractStepImpl, AbstractStepDescriptorImpl and AbstractSynchronousStepExecution for P4TaggingStep |
||
#32 | 25737 | Paul Allen | Trim white space for Manual Workspace Views. | ||
#31 | 24942 | Paul Allen |
Deep clone of Workspace objects. WorkspaceSpec was not cloned and caused the View to change. JENKINS-54695 |
||
#30 | 24777 | Paul Allen |
Global Library to use UUID for client name and delete after use. Add a new 'Delete the Perforce Client after checkout' option (for Manual clients) which normaly is false, but set to true for Global Library checkouts. JENKINS-50975 |
||
#29 | 24472 | Paul Allen |
Add a min version check for each Client Type. JENKINS-51048 |
||
#28 | 24409 | Paul Allen | Added ChangeView and Client Backup support. | ||
#27 | 24406 | Paul Allen |
Cleanup client setup. Should reduce 'null' root and views and work with replica Perforce Servers. |
||
#26 | 23796 | Paul Allen |
Look for the expanded original name when updating the view. Added test case for Job names with a '/' restricted character. JENKINS-50393 |
||
#25 | 23684 | Paul Allen |
Merge pull request #70 from PaSaSaP/master Expand view mappings. |
||
#24 | 23372 | Paul Allen | Add setter to modify workspace name and spec. | ||
#23 | 22684 | Paul Allen | Added @Symbol to Extension classes for Pipeline Syntax. | ||
#22 | 22163 | Paul Allen |
Manual Workspace support for READONLY and PARTITIONED. Change Type to Enum. JENKINS-39753 |
||
#21 | 22128 | Paul Allen |
Helix Graph support for Jenkins. JENKINS-40354 |
||
#20 | 22043 | Paul Allen |
Access remote Channel to find NODE_NAME If NODE_NAME is not set in the environment, look at the remote channel, then default to 'master'. JENKINS-34128 JENKINS-43551 |
||
#19 | 20308 | Paul Allen |
P4Groovy (experimental) Get a P4 object in groovy. Supporting basic functions: ’run’ (to run perforce commands), ‘fetch’ and ‘save’ (to access Perforce specs). |
||
#18 | 20179 | Paul Allen | Javadoc fixes for java 8 builds. | ||
#17 | 19750 | Paul Allen | Add default workspace name to Manual Client. | ||
#16 | 19581 | Paul Allen | Minor fixes to satisfy FindBugs Analysis. | ||
#15 | 16674 | Paul Allen |
Merge pull request #20 from KangTheTerrible/master Allow expansion of stream name in manual workspaces |
||
#14 | 16628 | Paul Allen |
Set the Client Owner field on update as well as creation. (support for p4maven) |
||
#13 | 16625 | Paul Allen | Set the Workspace Owner at creation (not on update). | ||
#12 | 15645 | Paul Allen |
Missing if statement in parseLineEnd. JENKINS-24025 |
||
#11 | 15138 | Paul Allen | Fix: StreamName not shown in Manual Workspace config. | ||
#10 | 13681 | Paul Allen |
Abstracted Expand class from Workspace. Added support for Label variable expansion in the name and description. |
||
#9 | 11472 | Paul Allen |
Pin the Workspace to the build host. Added a check box under the Workspace configuration to allow Jenkins to Pin the workspace, by setting the Host field. The hostname is resolved from the Computer object or InetAddress. |
||
#8 | 10907 | Paul Allen |
Minor fixes for Parent builds. - Disable ‘*’ substitution (too dangerous on large systems). - Skip change calculation when skipping parent. |
||
#7 | 10906 | Paul Allen |
Matrix Polling and Parent control - Polling for Matrix builds calculates changes based on children. - Parent build disabled when using "Matrix options for Perforce" in the Matrix Configuration (can be enabled by checking the “Build parent” box). - Parent Build now substitutes ${var} with ‘*’ for the workspace view. e.g. //depot/${os}/… //ws/${os}/… becomes… //depot/*/… //ws/*/… instead of… //depot/os/… //ws/os/… |
||
#6 | 10854 | Paul Allen |
Clone Workspace Object Seems Jenkins makes re-entrant calls to the PerforceScm Object and caused the Workspace Object to get trampled. JENKINS-25547 |
||
#5 | 10801 | Paul Allen |
Improvements to SCM Polling Moved change list calculation into a new class CheckoutChanges. Should enable normal build to build every thing and poll to follow polling behaviour: limit based on pin and per-change if set. JENKINS-25300 |
||
#4 | 10510 | Paul Allen |
Fixed name in client map for Manual workspaces. The client name in the RHS of the depot view was not matching the correct name. The name was expanded, but not replaced with the '/' and '=' chars. Fixes JENKINS-24028 |
||
#3 | 9769 | Paul Allen | Copying using p4-jenkins | ||
#2 | 9738 | Paul Allen | Merging using p4-jenkins | ||
#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/workspace/ManualWorkspaceImpl.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/workspace/ManualWorkspaceImpl.java | |||||
#11 | 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. |
||
#10 | 8929 | Paul Allen |
Clean up doCheck Warnings on configuration page (TPI-80). - Added check exceptions to log as warnings. |
||
#9 | 8902 | Paul Allen |
Updated test cases: Pushed Workspace 'charset' to abstract Workspace class. Minor bugfixes in Workspace AutoCompletionCandidates method. |
||
#8 | 8899 | Paul Allen | Move Workspace setup/creation code to Implementation class. | ||
#7 | 8896 | Paul Allen | Moved common method 'doFillCharsetItems' into abstract class 'WorkspaceDescriptor'. | ||
#6 | 8771 | Paul Allen |
Perforce Server 12.1 min check for: Build configuration and password/ticket credentials. Includes: - Added logging for Perforce connections (fine) and set connection pool to 2. - Add 'none' to empty charset list (connection bug?) - Supress P4Java errors for syncing ubinary, xtext, unicode |
||
#5 | 8769 | Paul Allen | Update to charset option for workspaces to use a drop-down select with a default of 'none'. | ||
#4 | 8756 | Paul Allen | Added Stream field to Manual Workspace config. | ||
#3 | 8755 | Paul Allen | JavaScript automation for populating Client workspace spec in Manual mode. | ||
#2 | 8749 | Paul Allen |
Split off Worksapce Spec from Manual Workspace configuration into a Property Jelly item. Plan to autoload values based on selected client. |
||
#1 | 8697 | Paul Allen |
Added Manual workspace option for user to define Options/LineEnd/View etc... in Jenkins. |