package org.jenkinsci.plugins.p4.client; import hudson.model.TaskListener; import hudson.security.ACL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import jenkins.model.Jenkins; import org.acegisecurity.Authentication; import org.jenkinsci.plugins.p4.credentials.P4StandardCredentials; import org.jenkinsci.plugins.p4.workspace.Workspace; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.domains.DomainRequirement; import com.perforce.p4java.core.file.FileSpecOpStatus; import com.perforce.p4java.core.file.IFileSpec; import com.perforce.p4java.server.IOptionsServer; public class ConnectionHelper { private static Logger logger = Logger.getLogger(ConnectionHelper.class .getName()); protected final ConnectionConfig connectionConfig; protected final AuthorisationConfig authorisationConfig; protected IOptionsServer connection; protected final TaskListener listener; public ConnectionHelper(String credentialID, TaskListener listener) { this.listener = listener; P4StandardCredentials credential = findCredential(credentialID); this.connectionConfig = new ConnectionConfig(credential); this.authorisationConfig = new AuthorisationConfig(credential); connect(); } public ConnectionHelper(P4StandardCredentials credential, TaskListener listener) { this.listener = listener; this.connectionConfig = new ConnectionConfig(credential); this.authorisationConfig = new AuthorisationConfig(credential); connect(); } public ConnectionHelper(P4StandardCredentials credential) { this.listener = null; this.connectionConfig = new ConnectionConfig(credential); this.authorisationConfig = new AuthorisationConfig(credential); connect(); } /** * Convenience wrapper to connect and report errors */ private void connect() { try { // Connect to the Perforce server this.connection = ConnectionFactory.getConnection(connectionConfig); logger.fine("P4: opened connection OK"); } catch (Exception e) { String err = "P4: Unable to connect: " + e; logger.severe(err); if (listener != null) { listener.getLogger().println(err); } e.printStackTrace(); } } public boolean isConnected() { return connection.isConnected(); } public boolean isUnicode() { try { return connection.getServerInfo().isUnicodeEnabled(); } catch (Exception e) { return false; } } /** * Checks the Perforce server version number and returns true if greater * than or equal to the min version. The value of min must be of the form * 20092 or 20073 (corresponding to 2009.2 and 2007.3 respectively). * * @param min * @return */ public boolean checkVersion(int min) { int ver = connection.getServerVersionNumber(); return (ver >= min); } public boolean login() throws Exception { connection.setUserName(authorisationConfig.getUsername()); // CHARSET is not defined (only for client access) if (connection.getServerInfo().isUnicodeEnabled()) { connection.setCharsetName("utf8"); } switch (authorisationConfig.getType()) { case PASSWORD: String status = connection.getLoginStatus(); if (!status.contains("not necessary")) { String pass = authorisationConfig.getPassword(); connection.login(pass); } break; case TICKET: String ticket = authorisationConfig.getTicketValue(); connection.setAuthTicket(ticket); break; case TICKETPATH: String path = authorisationConfig.getTicketPath(); connection.setTicketsFilePath(path); break; default: throw new Exception("Unknown Authorisation type: " + authorisationConfig.getType()); } return isLogin(); } public void logout() throws Exception { if (isLogin()) { connection.logout(); } } private boolean isLogin() throws Exception { String status = connection.getLoginStatus(); if (status.contains("not necessary")) { return true; } if (status.contains("ticket expires in")) { return true; } // If there is a broker or something else that swallows the message if (status.isEmpty()) { return true; } logger.info("P4: login failed '" + status + "'"); return false; } public void deleteClient(Workspace workspace) throws Exception { if (connectionConfig.isUnicode()) { String charset = "utf8"; connection.setCharsetName(charset); } String name = workspace.getFullName(); connection.deleteClient(name, true); } /** * Disconnect from the Perforce Server. * * @throws Exception */ public void disconnect() { try { connection.disconnect(); logger.fine("P4: closed connection OK"); } catch (Exception e) { String err = "P4: Unable to close Perforce connection: " + e; logger.severe(err); if (listener != null) { listener.getLogger().println(err); } e.printStackTrace(); } } /** * Look for a message in the returned FileSpec from operation. * * @param fileSpecs * @param ignore * @return * @throws ConverterException */ public boolean validateFileSpecs(List<IFileSpec> fileSpecs, String... ignore) throws Exception { return validateFileSpecs(fileSpecs, false, ignore); } public boolean validateFileSpecs(List<IFileSpec> fileSpecs, boolean quiet, String... ignore) throws Exception { for (IFileSpec fileSpec : fileSpecs) { if (fileSpec.getOpStatus() != FileSpecOpStatus.VALID) { String msg = fileSpec.getStatusMessage(); // superfluous p4java message boolean unknownMsg = true; ArrayList<String> ignoreList = new ArrayList<String>(); ignoreList.addAll(Arrays.asList(ignore)); for (String istring : ignoreList) { if (msg.contains(istring)) { // its a known message unknownMsg = false; } } // check and report unknown message if (unknownMsg) { if (!quiet) { log("P4JAVA: " + msg); logger.warning("p4java: " + msg); } return false; } } } return true; } /** * Finds a Perforce Credential based on the String id. * * @return a P4StandardCredentials credential or null if not found. */ public static P4StandardCredentials findCredential(String id) { Class<P4StandardCredentials> type = P4StandardCredentials.class; Jenkins scope = Jenkins.getInstance(); Authentication acl = ACL.SYSTEM; DomainRequirement domain = new DomainRequirement(); List<P4StandardCredentials> list; list = CredentialsProvider.lookupCredentials(type, scope, acl, domain); for (P4StandardCredentials c : list) { if (c.getId().equals(id)) { return c; } } return null; } protected void log(String msg) { if (listener == null) { return; } listener.getLogger().println(msg); } public void stop() throws Exception { connection.execMapCmd("admin", new String[] { "stop" }, null); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#90 | 29812 | Sandeep Kumar |
Merge pull request #[178] from [joel-f-brown:masterp] Do not call "p4 counter " when the value is an integer as the helix core server does not allow integer counters. In isCounter() method, check for all digits early. If all digits, return false. |
||
#89 | 28805 | Paul Allen |
Merge pull request #145 from joel-f-brown/master Allow option to not detect changelists for build, JENKINS-68516 |
||
#88 | 28555 | Paul Allen | Update p4java patch version 2021.2.2240592 | ||
#87 | 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 |
||
#86 | 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. |
||
#85 | 26640 | Paul Allen |
Tick interval message to prevent timeout. An advanced setting in the Credential sets a 'tick' interval to print out a 'waiting' message to the log during long running commands. The value needs to be less than 30,000ms to avoid Jenkins automatic disconnect. JENKINS-58161 |
||
#84 | 26617 | Paul Allen |
Prevent `ssl:` string from appearing in the P4PORT Jelly field. Jelly uses getP4port() method for binding the fields; adding the ssl prefix was causing issues. JENKINS-63246 |
||
#83 | 26601 | Paul Allen | Code cleanup for getHead and getLowestHead. | ||
#82 | 26587 | Paul Allen |
Use default P4IGNORE if unset. Check if P4Java's envrionment has set P4IGNORE for the server connection, otherwise use OS defaults. JENKINS-59726 JENKINS-54707 |
||
#81 | 26579 | Paul Allen |
Prevent logging if Populate quiet flag is set. Originally the Populate quiet flag was passed as a '-q' flag to the command, but some commands using callback streaming handlers still reported output. JENKINS-59750 |
||
#80 | 26210 | charusheela_b |
Merge pull request #93 from lystor/bug-56290 [JENKINS-56290] Impossible to Add Streams with Exact Names to Multibranch Pipeline |
||
#79 | 25973 | Paul Allen | Fix JavaDoc issues | ||
#78 | 25826 | Paul Allen |
Global option to limit change query. By default 'Head change query limit' is set to 0 (no limit) and the plugin will query all changes when looking within a workspace view. For large servers set the value to a range based on commit rate and job queue duration. e.g. 200 global commits/hour and jobs are queued for no longer than 10 hours, so 2000 change query limit (200*10). JENKINS-58116 JENKINS-57870 |
||
#77 | 25014 | Paul Allen |
Scan per change support for MultiBranch with remote Jenkinsfiles. Only the 'Polling per Change' Filter is supported; need to disable or support the other filter types. JENKINS-53936 |
||
#76 | 24944 | Paul Allen |
Merge pull request #86 from p4charu/jenkinsci-master JENKINS-51632 and minor code cleanup |
||
#75 | 24826 | Paul Allen | Update Perforce Server Unicode check. | ||
#74 | 24805 | Paul Allen |
Tidy up connection methods. Cache TagAction calls to getTicket() when adding P4_TICKET to the Environment. JENKINS-54222 |
||
#73 | 24500 | Paul Allen | Tidyup and refactor P4Ref classes. | ||
#72 | 24487 | Paul Allen | Perforce Connection Refactor. | ||
#71 | 24455 | Paul Allen |
Allow query of single streams by appending a `*` to a streams path. https://github.com/p4paul/p4-jenkins/issues/36 |
||
#70 | 23941 | Paul Allen |
Track Credentials at build time. Unable to track when the Job is configured as Pipeline Jobs may use one or more credentials in the Jenkinsfile. JENKINS-44706 |
||
#69 | 23604 | Paul Allen |
Merge pull request #68 from ChadiEM/deleted-jenkinsfile Make sure branch is not discovered when a Jenkinsfile has been removed. |
||
#68 | 23425 | Paul Allen |
Backwards compatibility for p4 describe. Max limit on files for p4 describe (-m flag) was introduced in 2014.1 JENKINS-48433 |
||
#67 | 23327 | Paul Allen | Use client less connection when scanning MultiBranch. | ||
#66 | 22998 | Paul Allen | Remove unused 'admin stop' method. | ||
#65 | 22970 | Paul Allen |
Merge pull request #57 from jfperusse-bhvr/fix-changelog-errors Fix changelog issues caused by NullPointerException in getSwarm JENKINS-47336 |
||
#64 | 22915 | Paul Allen | Advanced AllHosts login option (login -a) | ||
#63 | 22861 | Paul Allen | Use long for change number. | ||
#62 | 22841 | Paul Allen |
Switch to `P4.Swarm.URL` property for Swarm url. JENKINS-45464 |
||
#61 | 22816 | Paul Allen |
Merge pull request #51 from jenkinsci/limit-describe. Limit output from describe. JENKINS-46671 |
||
#60 | 22815 | Paul Allen |
Provide repo with connection.getCommitObject(). The `p4 graph cat-file commit` requires `super` level access if the repo name is not provided. JENKINS-46595 |
||
#59 | 22398 | Paul Allen | Pass Perforce ticket using BasicAuth to Swarm API. | ||
#58 | 22183 | Paul Allen | Ticket Credential; an empty path will use system default. | ||
#57 | 22168 | Paul Allen |
Check all login messages. Fix for 'pre-user-login' triggers. JENKINS-44166 |
||
#56 | 22159 | Paul Allen |
Minor fix on Graph commit change summary. Skip query when listing commits between the same SHAs. |
||
#55 | 22128 | Paul Allen |
Helix Graph support for Jenkins. JENKINS-40354 |
||
#54 | 21794 | Paul Allen |
Merge pull request #39 from Dohbedoh/JENKINS-34825 Jenkins 34825 |
||
#53 | 21781 | Paul Allen | Minor spelling error. | ||
#52 | 21758 | Paul Allen |
Merge pull request #38 from jenkinsci/dev scm-api 2.0.2 updates |
||
#51 | 21658 | Paul Allen |
Reduce login requests. Avoid running `p4 login -s` twice. |
||
#50 | 20986 | Paul Allen |
Ground work for MultiJob support. Pushed validate up to ConnectionHelper and added new Perforce functions. |
||
#49 | 20873 | Paul Allen | Support Pin to a change in a counter. | ||
#48 | 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). |
||
#47 | 20245 | Paul Allen |
Don't disconnect after an abort. Don't disconnect from the P4 server immediately after an abort is detected. JENKINS-37487 @stuartr |
||
#46 | 20179 | Paul Allen | Javadoc fixes for java 8 builds. | ||
#45 | 19712 | Paul Allen | NPE fix when code line has no changes. | ||
#44 | 19593 | Paul Allen | More minor fixes to satisfy FindBugs Analysis. | ||
#43 | 19574 | Paul Allen | Support for guessBrowser and getKey. | ||
#42 | 18889 | Paul Allen |
Asynchronous sync operation. To avoid memory issues with very large sync operations. #review-18773 |
||
#41 | 18809 | Paul Allen |
Use p4 describe -s for listing files in a change. Previously used p4 files @=<change>, but without a client to limit view. |
||
#40 | 18616 | mjoubert |
@pallen Unable to get current change: com.perforce.p4java.exception.RequestException: Can't use a pending changelist number for this command. FATAL: null java.lang.NullPointerException Fix for critial bug |
||
#39 | 16820 | Paul Allen |
Delete client workspace and files on a delete Jenkins Job Global Perforce options for delete files and/or delete client. JENKINS-32454 |
||
#38 | 16585 | Paul Allen |
Fetch full change description. The 'p4 changes' optimisation only fetched the first 32 characters. Added the '-l' flag to fetch the full description. JENKINS-31748 |
||
#37 | 16516 | Paul Allen |
Use empty email "" for deleted users. JENKINS-31169 |
||
#36 | 16515 | Paul Allen |
Extend support for 'now' revision specifier. If 'now' is used it will be substituted for the latest change within the scope of the workspace view. |
||
#35 | 16409 | Paul Allen |
Use Fix records for Job information. 'p4 fixes' is lighter and still provides enough useful data. Includes jelly fix and extra job data in changelog.xml. |
||
#34 | 16390 | Paul Allen |
Update change/file reporting. Use `p4 changes @=1234` to get change summary and `p4 files -m50 @=1234` to get limited file list. |
||
#33 | 16297 | Paul Allen |
Set P4IGNORE filename to defaults. With slaves and different users I can’t rely on the P4IGNORE in the environment, so I set the default ’.p4ignore’ or ‘p4ignore.txt’ on Windows. https://github.com/p4paul/p4-jenkins/issues/14 |
||
#32 | 16085 | Paul Allen |
If Change number is missing try looking for the original. Use p4 change -O if a RequestException is thrown. JENKINS-30525 |
||
#31 | 15866 | Paul Allen |
Abort if unshelve fails. JENKINS-30525 |
||
#30 | 15663 | Paul Allen |
Added P4_USER and P4_TICKET environment variables. Added Perforce environment variables to the buildEnv documentation. JENKINS-24591 |
||
#29 | 15656 | Paul Allen |
Updated credentials to extend BaseStandardCredentials. Allows users to set the ID at creation. JENKINS-29702 |
||
#28 | 15431 | Paul Allen |
Add Perforce User's email to Jenkins User property. JENKINS-28421 |
||
#27 | 15430 | Paul Allen |
Trap User Abort and stop Perforce. Uses the ‘tick’ function on Progress to check if the Thread has been interrupted. If a user aborts the build then the Perforce connection is dropped at the next tick. JENKINS-26650 |
||
#26 | 15293 | Paul Allen |
Add retry attempts to Perforce Tasks. If a task fails due to an exception then the task will retry based on the value specified in the connection Credential. |
||
#25 | 14838 | Paul Allen |
Check if the workspace exists before cleanup. JENKINS-29030 |
||
#24 | 13603 | Paul Allen | Improved Error for Publish step when connection is down. | ||
#23 | 12976 | Paul Allen | Improved logging to include 'actual' Perforce command. | ||
#22 | 12953 | Paul Allen |
Update logging to support expand/collapse divs. - Additional Publish logging |
||
#21 | 12931 | Paul Allen |
#review-12907 @mjoubert Added P4PORT to env for command line calls. |
||
#20 | 12355 | Paul Allen |
Connection retry. Connection retry with 3 attempts and a back off period of n^2 seconds for subsequent attempts. |
||
#19 | 12310 | Paul Allen |
@mjoubert performance/logging Improved performance on validateFileSpecs() Reduce delete logging |
||
#18 | 12297 | Paul Allen |
Only login if there is no valid ticket. JENKINS-27068 |
||
#17 | 12296 | Paul Allen | Monitor P4Java progress, reporting to console log. | ||
#16 | 11452 | Paul Allen |
Push out mjoubert fixes for Force sync. @mjoubert |
||
#15 | 11334 | Paul Allen |
Remote slave support for Publish Perforce Publish commands need to be executed from the remote slave. - Includes refactoring into task package |
||
#14 | 10757 | Paul Allen |
More efficient listing of files. Listing files for the Change reporting used `p4 files //…@=<id>`, this now uses `p4 describe -s <id>` for changes and `p4 files //…@<id>` for labels. The `\\…@label` should be much more efficient as it only looks as the db.label table not db.rev. I can’t limit the scope to a workspace. Often the client name uses ${var}, which are not present at this point in the code. JENKINS-25303 |
||
#13 | 10526 | Paul Allen |
Log all P4JAVA errors/messages. Originally only the first error was reported, before dropping out of validation code. |
||
#12 | 10031 | Paul Allen |
Test URI path before connection. Report Perforce Errors and Trust fingerprint if using SSL. |
||
#11 | 10013 | Paul Allen |
Added Client support to sync check https://issues.jenkins-ci.org/browse/JENKINS-24055 |
||
#10 | 9991 | Paul Allen |
Don't abort on non-error messages. Support the p4broker returning unknown messages. |
||
#9 | 9987 | Paul Allen | Better logging for slave connections. | ||
#8 | 9984 | Paul Allen |
Set P4_CHANGELIST to change for Automatic Labels. P4_CHANGELIST is set to a change number or label if defined in Populate as pinned or a build parameter. |
||
#7 | 9980 | Paul Allen |
Changed error reporting to use AbortException. - Use direct access of scm attributes, not via build.getProject().getScm() - Improved logging around labels/changes. |
||
#6 | 9851 | Paul Allen | Merging using p4-jenkins | ||
#5 | 9819 | Paul Allen | Merging using p4-jenkins | ||
#4 | 9803 | Paul Allen | Merging using p4-jenkins | ||
#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/client/ConnectionHelper.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/ConnectionHelper.java | |||||
#35 | 9460 | Paul Allen | Skip login, if no password set. | ||
#34 | 9447 | Paul Allen |
Small mod to force a login for each connection. There may be a case with a broker/replica when the login test may incorrectly report the users is logged. |
||
#33 | 9429 | Paul Allen |
Fix SCM Polling bug. Client workspace was not set (unless by an earlier build). - Move listChanges method to ClientHelper. |
||
#32 | 9091 | Paul Allen |
Added Changelist build filtering for SCM polling: - Configuration uses 'repeatableHeteroProperty' - Filter on Perforce username - Filter on Perforce Depot path (no wildcard support) |
||
#31 | 9077 | Paul Allen |
Added support for automatic Labels as a post-build Action. Ported original code for promoted builds, but not tested. |
||
#30 | 9055 | Paul Allen |
Label support. Build at a label using the pram 'label'. This includes adding the label to the ChangeEntry, building the change reports and Browser links to Swarm. (TPI-102) |
||
#29 | 8969 | Paul Allen |
Adds all contributing change-lists for the build to the change log (using p4 cstat). - Includes exception logging for server connection to the Jenkins console. |
||
#28 | 8940 | Paul Allen |
Major refactor for the ConnectionHelper class to simplify serialisation. Fixed remote Jenkins JNLP slave connection issue. ClientHelper now extends ConnectionHelper and takes on all methods that require a client workspace. P4StandardCredentials is sent to the remote node instead of Credentials ID due to an issue accessing the Credentials store over a remote connection. For simplicity Client ID (workspace name) is serialised instead of the Workspace object. |
||
#27 | 8924 | Paul Allen | Sync workspace to last change in workspace (not depot). | ||
#26 | 8915 | Paul Allen |
Support for ChangeLog and RepoBrowser. - Added RepoBrowser for Swarm (porting the others should be easy) - ChangeLog XML file now only stores the changelist number all other information is fetched from Perforce |
||
#25 | 8909 | Paul Allen |
[TPI-83] Clean Workspace that may contain files with wildcards. Added (-f) flag to reconcile and ignore warnings for empty files. |
||
#24 | 8899 | Paul Allen | Move Workspace setup/creation code to Implementation class. | ||
#23 | 8864 | Paul Allen | BugFix on template workspaces; view was not generated during creation. | ||
#22 | 8852 | Paul Allen |
Functional test for unshelve. Includes fix for reconcile and unshelve exclusive locked files. |
||
#21 | 8815 | Paul Allen | P4D test harness. | ||
#20 | 8805 | Paul Allen | Minor fix to ignore Perforce encoding messages when finding 'extra' files during a 'reconcile -a'. | ||
#19 | 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 |
||
#18 | 8770 | Paul Allen |
Implemented SCM hook for when Jenkins deletes a workspace. The PerforceScm plugin deletes the workspace, but leaves Jenkins to clean up the local files and directories. (includes dummy 'p4 cstat' code for change reporting) |
||
#17 | 8766 | Paul Allen |
Bug fix: Client Owner not set when creating workspace. Now jenkins will set the owner for new workspaces and take ownership of other manual workspaces it uses for build. |
||
#16 | 8764 | Paul Allen | Supress P4Java warnings, to prevent SCM tasks from failing. | ||
#15 | 8763 | Paul Allen | More Console Output logging | ||
#14 | 8762 | Paul Allen |
Console Ouptut logging for SCM build steps. - Removed SLF4J and used old style logger (matching Jenkins) - Set Client Host filed to null, Jenkins sometimes gives an IP address. - Test p4java setps in SCM tasks for success(true/false) |
||
#13 | 8756 | Paul Allen | Added Stream field to Manual Workspace config. | ||
#12 | 8749 | Paul Allen |
Split off Worksapce Spec from Manual Workspace configuration into a Property Jelly item. Plan to autoload values based on selected client. |
||
#11 | 8744 | Paul Allen |
Support basic SCM Polling. When Jenkins has "Poll SCM" checked the Perforce SCM provider just runs a 'p4 sync -n' on the Workspace. Simple and Fast. |
||
#10 | 8741 | Paul Allen |
Added "Test Connection" to Perforce Password and Ticket Credentials. Does not support SSL connections...yet |
||
#9 | 8738 | Paul Allen |
Workspace Name Formatter. For Template and Stream workspaces it allows the substitution of the following tags: ${node} The name given to the slave Jenkins node. ${hostname} The hostname for the slave Jenkins node. ${project} The name of the Jenkins build Job. ${hash} Unique hash code of the Jenkins node. |
||
#8 | 8725 | Paul Allen |
Minor fixes: - Improved tidy workspace method - Fix for template clients - After an unshelf revert -k files - Minor bug in CheckoutTask - Clear callback urls to prevet reuse |
||
#7 | 8697 | Paul Allen |
Added Manual workspace option for user to define Options/LineEnd/View etc... in Jenkins. |
||
#6 | 8694 | Paul Allen | Added support for unshelve and revert -w behaviour for builds. | ||
#5 | 8664 | Paul Allen | Simplified connection to Perforce to get around the SCM initilisation (or lack of). | ||
#4 | 8662 | Paul Allen | Added auto fill and checks for streams and templates. | ||
#3 | 8661 | Paul Allen | Workspace auto fill | ||
#2 | 8641 | Paul Allen | Added workspace helper (setClient) and template/stream types. | ||
#1 | 8629 | Paul Allen |
Added p4java with connection/authorisation helper classes. Included SSL support and detection of Unicode servers. |