Skip to content

Commit b439d94

Browse files
committed
2024.2 Code Drop
1 parent 36b3329 commit b439d94

21 files changed

+646
-259
lines changed

LICENSE.txt

Lines changed: 194 additions & 220 deletions
Large diffs are not rendered by default.

RELEASE.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Release Notes for
22
P4Java, the Perforce Java API
33

4-
Version 2024.1
4+
Version 2024.2
55

66
Introduction
77

@@ -20,7 +20,7 @@ Introduction
2020

2121
Requirements
2222

23-
* Perforce server at Release 2015.1 or higher.
23+
* Perforce server at Release 2021.1 or higher.
2424

2525
* Java: full standard JDK 11 or later. Implementation as
2626
discussed in "Known Limitations" below.
@@ -30,7 +30,7 @@ Requirements
3030

3131
SSL and Trust
3232

33-
Perforce server 2015.1 or higher supports 256-bit SSL connections
33+
Perforce server 2021.1 or higher supports 256-bit SSL connections
3434
and trust establishment via accepting the fingerprint of the SSL
3535
certificate's public key. The standard JDK comes with 128-bit
3636
encryption level ciphers. In order to use P4Java to connect to
@@ -108,7 +108,7 @@ Known Limitations
108108
mean either true shift-jis or CP932 by the Perforce server and
109109
many Windows tools. There is currently no workaround known.
110110

111-
* The Perforce server (2015.1 or higher) only support 256-bit
111+
* The Perforce server (2021.1 or higher) only support 256-bit
112112
encryption. Due to current US export control restrictions
113113
for some countries, the standard JDK package only comes with
114114
128-bit encryption level ciphers. In order to use P4Java to
@@ -123,6 +123,42 @@ Known Limitations
123123
124124
* P4Java would not support file operations on altsync enabled clients.
125125

126+
-------------------------------------------
127+
Updates in 2024.2 (2024.2/2695691) (2024/12/13)
128+
129+
#2693987 (Job #123372)
130+
Fixed a bug where localWhere should include path of the sparse stream instead
131+
of the mainline from which the sparse stream is created
132+
133+
#2692452 (Job #123888)
134+
Added 'long' value support for 'TicketExpiration' field while login
135+
136+
#2693212, #2693848 (Job #123268)
137+
Added support of P4IGNORE from env variable working for absolute path
138+
Added support for all patterns in ignore file
139+
140+
#2687877, #2686707 (Job #122068)
141+
Added support of -m flag for "p4 protects" command
142+
143+
#2684594 (Job #123229)
144+
Added support for user case insensitive suboption for "p4 labels" command
145+
146+
#2684552 (Job #122974)
147+
Added support for user case insensitive suboption for "p4 clients" command
148+
149+
#2684551 (Job #122978)
150+
Added support for user case insensitive suboption for "p4 branches" command
151+
152+
#2684163, #2685729 (Job #123231)
153+
Added support for multiple client and user option with a generic case-insensitive
154+
sub option for "p4 changes" command
155+
156+
#2684163, #2681088 (Job #122972)
157+
Added support for client and user case insensitive option for
158+
"p4 changes -c and -u"
159+
160+
#2684152, #2688244 (Job #121727)
161+
Added support for Sparse Streams
126162

127163
-------------------------------------------
128164
Updates in 2024.1 Patch 1 (2024.1/2674354) (2024/10/29)

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dependencies {
2727
testImplementation 'org.apache.commons:commons-exec:1.3'
2828
testImplementation 'org.apache.commons:commons-compress:1.21'
2929
testImplementation 'junit:junit:4.13.1'
30-
testImplementation 'org.mockito:mockito-core:4.0.0'
30+
testImplementation 'org.mockito:mockito-core:5.5.0'
3131
testImplementation 'com.googlecode.java-diff-utils:diffutils:1.3.0'
3232
}
3333

src/main/java/com/perforce/p4java/admin/IProtectionEntry.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,11 @@ public interface IProtectionEntry extends IMapEntry {
108108
* the path excluded indicator (true/false)
109109
*/
110110
void setPathExcluded(boolean pathExcluded);
111+
112+
/**
113+
* Returns the single word summary
114+
*
115+
* @return permMax
116+
*/
117+
String getPermMax();
111118
}

src/main/java/com/perforce/p4java/core/IStreamSummary.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,20 @@ public interface IStreamSummary extends IServerResource {
2121

2222
/**
2323
* Types of streams include 'mainline', 'release', 'development', 'virtual'
24-
* and 'task'. The default is 'development'.
24+
* 'task', 'sparsedev' and 'sparserel'. The default is 'development'.
2525
* <p>
2626
* Defines the role of a stream: A 'mainline' may not have a parent. A
2727
* 'virtual' stream is not a stream but an alternate view of its parent
2828
* stream. The 'development' and 'release' streams have controlled flow. Can
2929
* be changed. A 'task' stream is a lightweight short-lived stream that only
3030
* promotes modified content to the repository, branched data is stored in
3131
* shadow tables that are removed when the task stream is deleted or
32-
* unloaded.
32+
* unloaded. A 'sparsedev' stream is for development with the same flow
33+
* control as a stream of type development and a 'sparserel' stream is for
34+
* release with the same flow control as a stream of type release
3335
*/
3436
public enum Type {
35-
MAINLINE, RELEASE, DEVELOPMENT, VIRTUAL, TASK, UNKNOWN;
37+
MAINLINE, RELEASE, DEVELOPMENT, VIRTUAL, TASK, UNKNOWN, SPARSEDEV, SPARSEREL;
3638

3739
/**
3840
* Return a suitable Stream type as inferred from the passed-in

src/main/java/com/perforce/p4java/impl/generic/admin/ProtectionEntry.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.HOST;
1414
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.IS_GROUP;
1515
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.PERM;
16+
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.PERM_MAX;
1617
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.UNMAP;
1718
import static com.perforce.p4java.impl.mapbased.rpc.func.RpcFunctionMapKey.USER;
1819
import static java.util.Objects.nonNull;
@@ -67,6 +68,11 @@ public class ProtectionEntry extends MapEntry implements IProtectionEntry {
6768
*/
6869
private String name = null;
6970

71+
/**
72+
* If -m flag is true, a single word summary of the maximum access level is reported.
73+
*/
74+
private String permMax = null;
75+
7076
/**
7177
* Default constructor -- sets all fields to null, zero, or false.
7278
*/
@@ -134,6 +140,7 @@ public ProtectionEntry(final Map<String, Object> map, final int order) {
134140
if (map.containsKey(UNMAP)) {
135141
type = EntryType.EXCLUDE;
136142
}
143+
permMax = parseString(map, PERM_MAX);
137144
}
138145
}
139146

@@ -216,6 +223,12 @@ public void setPathExcluded(boolean pathExcluded) {
216223
}
217224
}
218225

226+
@Override
227+
228+
public String getPermMax() {
229+
return permMax;
230+
}
231+
219232
/**
220233
* Add exclude ('-') to a string. If it is a double quoted string, add the
221234
* exclude immediately after the first double quote char.

src/main/java/com/perforce/p4java/impl/mapbased/client/cmd/WhereDelegator.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public List<IFileSpec> localWhere(List<IFileSpec> fileSpecs) {
7979
if (mt.translate(mt.get(i), MapTableT.RHS, s) != null) {
8080
String depotPath = mt.translate(mt.get(i), MapTableT.RHS, s);
8181
spec.setDepotPath(depotPath);
82+
//Last view mapping should override all
83+
if (spec.getDepotPath() != null) {
84+
break;
85+
}
8286
}
8387
}
8488
resultList.add(spec);
@@ -88,6 +92,9 @@ public List<IFileSpec> localWhere(List<IFileSpec> fileSpecs) {
8892
if (mt.translate(mt.get(i), MapTableT.LHS, s) != null) {
8993
String clientPath = mt.translate(mt.get(i), MapTableT.LHS, s);
9094
spec.setClientPath(clientPath);
95+
if (spec.getClientPath() != null) {
96+
break;
97+
}
9198
}
9299
}
93100
spec = clientPathToLocalPath(spec, client);
@@ -98,6 +105,10 @@ public List<IFileSpec> localWhere(List<IFileSpec> fileSpecs) {
98105
if (mt.translate(mt.get(i), MapTableT.RHS, s) != null) {
99106
String depotPath = mt.translate(mt.get(i), MapTableT.RHS, s);
100107
spec.setDepotPath(depotPath);
108+
//Last view mapping should override all
109+
if (spec.getDepotPath() != null) {
110+
break;
111+
}
101112
}
102113
}
103114
spec = clientPathToLocalPath(spec, client);

src/main/java/com/perforce/p4java/impl/mapbased/rpc/func/RpcFunctionMapKey.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ public class RpcFunctionMapKey {
118118
public static final String KEY = "key";
119119
public static final String LABEL_REC_DELETED = "labelRecDeleted";
120120
public static final String LABEL = "label";
121+
public static final String LADDR = "listenAddr";
121122
public static final String LINEEND = "LineEnd";
122123
public static final String LOCAL_FILE = "localFile";
123124
public static final String LOWER = "lower";
@@ -214,6 +215,7 @@ public class RpcFunctionMapKey {
214215
public static final String SERVERID = "serverID";
215216
public static final String SERVERLICENSE = "serverLicense";
216217
public static final String SERVERROOT = "serverRoot";
218+
public static final String SERVERTYPE = "serverType";
217219
public static final String SERVERUPTIME = "serverUptime";
218220
public static final String SERVERVERSION = "serverVersion";
219221
public static final String SET = "set";
@@ -230,7 +232,10 @@ public class RpcFunctionMapKey {
230232
public static final String STATUS = "status";
231233
public static final String SUBMITOPTIONS = "SubmitOptions";
232234
public static final String SUMMARY = "summary";
235+
public static final String SVRID = "svrid";
233236
public static final String SVRNAME = "svrname";
237+
public static final String SVRTYPE = "svrtype";
238+
public static final String SVRVERSION = "svrversion";
234239
public static final String SYNCTIME = "syncTime";
235240
public static final String TAG = "tag";
236241
public static final String THEIRNAME = "theirName";
@@ -296,6 +301,8 @@ public class RpcFunctionMapKey {
296301

297302
public static final String URL = "url";
298303

304+
public static final String PERM_MAX = "permMax";
305+
299306
/**
300307
* RPC keys map
301308
*/

src/main/java/com/perforce/p4java/impl/mapbased/rpc/func/client/ClientIgnoreChecker.java

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ public boolean match(File file) throws FileNotFoundException, IOException {
7878
}
7979

8080
/**
81-
* Check all ignore files up to the client root directory.
81+
* Check for the ignore file as an absolute path
82+
* or check the ignore file up to the client root directory.
8283
*
8384
* @param file
8485
* the file
@@ -88,23 +89,62 @@ public boolean match(File file) throws FileNotFoundException, IOException {
8889
*/
8990
private boolean checkIgnoreFiles(File file) throws IOException {
9091
if (file != null) {
91-
// Signal for inverse match
92+
// when ignoreFileName is in the form of absolute path
93+
File ignoreFile = new File(ignoreFileName);
94+
if (ignoreFile.exists() && !ignoreFileName.startsWith(".")) {
95+
if (checkIgnorePatternInSubDirectories(ignoreFile, file)) {
96+
return true;
97+
}
98+
}
99+
// when ignoreFileName is in the form of a relative path of client root
100+
else {
101+
File clientRootDir = new File(clientRoot);
102+
File fileDir = file;
103+
do {
104+
fileDir = fileDir.getParentFile();
105+
if (fileDir != null) {
106+
ignoreFile = new File(fileDir, ignoreFileName);
107+
if (ignoreFile.exists()) {
108+
if (checkIgnorePatternInSubDirectories(ignoreFile, file)) {
109+
return true;
110+
}
111+
}
112+
}
113+
} while (fileDir != null && !fileDir.getAbsoluteFile().equals(clientRootDir));
114+
}
115+
}
116+
117+
return false;
118+
}
119+
120+
/**
121+
* Checks for the ignore file patterns in all the directories and sub-directories
122+
*
123+
* @param ignoreFile
124+
* the ignore file
125+
* @param file
126+
* the file
127+
* @return true, if successful
128+
* @throws IOException
129+
* Signals that an I/O exception has occurred.
130+
*/
131+
private boolean checkIgnorePatternInSubDirectories(File ignoreFile, File file) throws IOException {
132+
if (file != null && ignoreFile.exists()) {
133+
// Signal for inverse match (if negation is used in ignore rules)
92134
Negate negate = this.new Negate();
93135

94136
File clientRootDir = new File(clientRoot);
95137
File fileDir = file;
138+
96139
do {
97140
fileDir = fileDir.getParentFile();
98141
if (fileDir != null) {
99-
File ignoreFile = new File(fileDir, ignoreFileName);
100-
if (ignoreFile.exists()) {
101-
if (checkIgnoreFile(ignoreFile, fileDir, file, negate)) {
102-
// Inverse match
103-
if (negate.isMatch()) {
104-
return false;
105-
}
106-
return true;
142+
if (traverseIgnoreFileForPattern(ignoreFile, fileDir, file, negate)) {
143+
// Inverse match
144+
if (negate.isMatch()) {
145+
return false;
107146
}
147+
return true;
108148
}
109149
}
110150
} while (fileDir != null && !fileDir.getAbsoluteFile().equals(clientRootDir));
@@ -128,7 +168,7 @@ private boolean checkIgnoreFiles(File file) throws IOException {
128168
* @throws IOException
129169
* Signals that an I/O exception has occurred.
130170
*/
131-
private boolean checkIgnoreFile(File ignoreFile, File currentDir, File file, Negate negate)
171+
private boolean traverseIgnoreFileForPattern(File ignoreFile, File currentDir, File file, Negate negate)
132172
throws IOException {
133173

134174
BufferedReader br = null;

src/main/java/com/perforce/p4java/impl/mapbased/rpc/func/client/ClientUserInteraction.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,9 @@ protected RpcPacketDispatcherResult clientCrypto(RpcConnection rpcConnection, Co
624624
boolean proxy = props.containsKey(RpcFunctionMapKey.IPADDR) && props.containsKey(RpcFunctionMapKey.SVRNAME) && props.containsKey(RpcFunctionMapKey.PORT);
625625

626626
String svcUser = props.getProperty(RpcFunctionMapKey.SVRNAME);
627+
String svrId = props.getProperty(RpcFunctionMapKey.SVRID);
628+
String svrType = props.getProperty(RpcFunctionMapKey.SVRTYPE);
629+
String svrVersion = props.getProperty(RpcFunctionMapKey.SVRVERSION);
627630

628631
try {
629632
// Use the auth ticket associated with specified server address
@@ -695,11 +698,10 @@ protected RpcPacketDispatcherResult clientCrypto(RpcConnection rpcConnection, Co
695698
respMap.put(RpcFunctionMapKey.TOKEN2, resp);
696699
}
697700

698-
if (proxy) {
701+
if (proxy && daddr0 != null) {
699702
respMap.put(RpcFunctionMapKey.CADDR, props.getProperty(RpcFunctionMapKey.IPADDR));
700-
}
703+
respMap.put(RpcFunctionMapKey.LADDR, props.getProperty(RpcFunctionMapKey.PORT));
701704

702-
if (daddr0 != null) {
703705
digester.reset();
704706
digester.update(svcUser.getBytes());
705707
if (svcTicketStr != null) {
@@ -712,6 +714,16 @@ protected RpcPacketDispatcherResult clientCrypto(RpcConnection rpcConnection, Co
712714
respMap.put("svrname0", svcUser);
713715
respMap.put(RpcFunctionMapKey.DADDR + "0", daddr0);
714716
respMap.put("dhash0", resp);
717+
718+
if(svrType != null) {
719+
respMap.put(RpcFunctionMapKey.SERVERTYPE + "0", svrType);
720+
}
721+
if(svrId != null) {
722+
respMap.put(RpcFunctionMapKey.SERVERID + "0", svrId);
723+
}
724+
if(svrVersion != null) {
725+
respMap.put(RpcFunctionMapKey.SERVERVERSION + "0", svrVersion);
726+
}
715727
}
716728

717729
RpcPacket respPacket = RpcPacket.constructRpcPacket(confirm, respMap, null);

0 commit comments

Comments
 (0)