1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport;
12
13 import static java.math.BigInteger.ZERO;
14 import static java.util.Objects.requireNonNull;
15 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
16 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
17 import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
18 import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
19 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_FILTER;
20
21 import java.math.BigInteger;
22 import java.text.MessageFormat;
23
24 import org.eclipse.jgit.annotations.Nullable;
25 import org.eclipse.jgit.errors.PackProtocolException;
26 import org.eclipse.jgit.internal.JGitText;
27
28
29
30
31
32
33
34 public final class FilterSpec {
35
36
37 static class ObjectTypes {
38 static ObjectTypes ALL = allow(OBJ_BLOB, OBJ_TREE, OBJ_COMMIT, OBJ_TAG);
39
40 private final BigInteger val;
41
42 private ObjectTypes(BigInteger val) {
43 this.val = requireNonNull(val);
44 }
45
46 static ObjectTypes allow(int... types) {
47 BigInteger bits = ZERO;
48 for (int type : types) {
49 bits = bits.setBit(type);
50 }
51 return new ObjectTypes(bits);
52 }
53
54 boolean contains(int type) {
55 return val.testBit(type);
56 }
57
58
59 @Override
60 public boolean equals(Object obj) {
61 if (!(obj instanceof ObjectTypes)) {
62 return false;
63 }
64
65 ObjectTypes other = (ObjectTypes) obj;
66 return other.val.equals(val);
67 }
68
69
70 @Override
71 public int hashCode() {
72 return val.hashCode();
73 }
74 }
75
76 private final ObjectTypes types;
77
78 private final long blobLimit;
79
80 private final long treeDepthLimit;
81
82 private FilterSpec(ObjectTypes types, long blobLimit, long treeDepthLimit) {
83 this.types = requireNonNull(types);
84 this.blobLimit = blobLimit;
85 this.treeDepthLimit = treeDepthLimit;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public static FilterSpec fromFilterLine(String filterLine)
106 throws PackProtocolException {
107 if (filterLine.equals("blob:none")) {
108 return FilterSpec.withObjectTypes(
109 ObjectTypes.allow(OBJ_TREE, OBJ_COMMIT, OBJ_TAG));
110 } else if (filterLine.startsWith("blob:limit=")) {
111 long blobLimit = -1;
112 try {
113 blobLimit = Long
114 .parseLong(filterLine.substring("blob:limit=".length()));
115 } catch (NumberFormatException e) {
116
117
118 }
119 if (blobLimit >= 0) {
120 return FilterSpec.withBlobLimit(blobLimit);
121 }
122 } else if (filterLine.startsWith("tree:")) {
123 long treeDepthLimit = -1;
124 try {
125 treeDepthLimit = Long
126 .parseLong(filterLine.substring("tree:".length()));
127 } catch (NumberFormatException e) {
128
129
130 }
131 if (treeDepthLimit >= 0) {
132 return FilterSpec.withTreeDepthLimit(treeDepthLimit);
133 }
134 }
135
136
137 throw new PackProtocolException(
138 MessageFormat.format(JGitText.get().invalidFilter, filterLine));
139 }
140
141
142
143
144
145
146
147 static FilterSpec withObjectTypes(ObjectTypes types) {
148 return new FilterSpec(types, -1, -1);
149 }
150
151
152
153
154
155
156 static FilterSpec withBlobLimit(long blobLimit) {
157 if (blobLimit < 0) {
158 throw new IllegalArgumentException(
159 "blobLimit cannot be negative: " + blobLimit);
160 }
161 return new FilterSpec(ObjectTypes.ALL, blobLimit, -1);
162 }
163
164
165
166
167
168
169
170 static FilterSpec withTreeDepthLimit(long treeDepthLimit) {
171 if (treeDepthLimit < 0) {
172 throw new IllegalArgumentException(
173 "treeDepthLimit cannot be negative: " + treeDepthLimit);
174 }
175 return new FilterSpec(ObjectTypes.ALL, -1, treeDepthLimit);
176 }
177
178
179
180
181 public static final FilterSpecec.html#FilterSpec">FilterSpec NO_FILTER = new FilterSpec(ObjectTypes.ALL, -1, -1);
182
183
184
185
186
187
188
189
190
191 public boolean allowsType(int type) {
192 return types.contains(type);
193 }
194
195
196
197
198
199 public long getBlobLimit() {
200 return blobLimit;
201 }
202
203
204
205
206
207
208 public long getTreeDepthLimit() {
209 return treeDepthLimit;
210 }
211
212
213
214
215 public boolean isNoOp() {
216 return types.equals(ObjectTypes.ALL) && blobLimit == -1 && treeDepthLimit == -1;
217 }
218
219
220
221
222 @Nullable
223 public String filterLine() {
224 if (isNoOp()) {
225 return null;
226 } else if (types.equals(ObjectTypes.allow(OBJ_TREE, OBJ_COMMIT, OBJ_TAG)) &&
227 blobLimit == -1 && treeDepthLimit == -1) {
228 return OPTION_FILTER + " blob:none";
229 } else if (types.equals(ObjectTypes.ALL) && blobLimit >= 0 && treeDepthLimit == -1) {
230 return OPTION_FILTER + " blob:limit=" + blobLimit;
231 } else if (types.equals(ObjectTypes.ALL) && blobLimit == -1 && treeDepthLimit >= 0) {
232 return OPTION_FILTER + " tree:" + treeDepthLimit;
233 } else {
234 throw new IllegalStateException();
235 }
236 }
237 }