1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport;
12
13 import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
14 import static org.eclipse.jgit.util.StringUtils.toLowerCase;
15
16 import java.io.File;
17 import java.util.EnumSet;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.eclipse.jgit.annotations.Nullable;
22 import org.eclipse.jgit.internal.storage.file.LazyObjectIdSetFile;
23 import org.eclipse.jgit.lib.Config;
24 import org.eclipse.jgit.lib.ConfigConstants;
25 import org.eclipse.jgit.lib.Config.SectionParser;
26 import org.eclipse.jgit.lib.ObjectChecker;
27 import org.eclipse.jgit.lib.ObjectIdSet;
28 import org.eclipse.jgit.lib.Ref;
29 import org.eclipse.jgit.lib.Repository;
30 import org.eclipse.jgit.util.SystemReader;
31
32
33
34
35
36 public class TransferConfig {
37 private static final String FSCK = "fsck";
38
39
40 public static final Config.SectionParser<TransferConfig> KEY =
41 TransferConfig::new;
42
43
44
45
46
47
48 public enum FsckMode {
49
50
51
52 ERROR,
53
54
55
56 WARN,
57
58
59
60 IGNORE;
61 }
62
63
64
65
66
67
68
69 public enum ProtocolVersion {
70
71
72
73 V0("0"),
74
75
76
77 V2("2");
78
79 final String name;
80
81 ProtocolVersion(String name) {
82 this.name = name;
83 }
84
85
86
87
88
89
90 public String version() {
91 return name;
92 }
93
94 @Nullable
95 static ProtocolVersion parse(@Nullable String name) {
96 if (name == null) {
97 return null;
98 }
99 for (ProtocolVersion v : ProtocolVersion.values()) {
100 if (v.name.equals(name)) {
101 return v;
102 }
103 }
104 if ("1".equals(name)) {
105 return V0;
106 }
107 return null;
108 }
109 }
110
111 private final boolean fetchFsck;
112 private final boolean receiveFsck;
113 private final String fsckSkipList;
114 private final EnumSet<ObjectChecker.ErrorType> ignore;
115 private final boolean allowInvalidPersonIdent;
116 private final boolean safeForWindows;
117 private final boolean safeForMacOS;
118 private final boolean allowRefInWant;
119 private final boolean allowTipSha1InWant;
120 private final boolean allowReachableSha1InWant;
121 private final boolean allowFilter;
122 private final boolean allowSidebandAll;
123
124 private final boolean advertiseSidebandAll;
125 private final boolean advertiseWaitForDone;
126 private final boolean advertiseObjectInfo;
127
128 final @Nullable ProtocolVersion protocolVersion;
129 final String[] hideRefs;
130
131
132
133
134
135
136
137
138
139
140 public TransferConfig(Repository db) {
141 this(db.getConfig());
142 }
143
144
145
146
147
148
149
150
151
152
153
154 @SuppressWarnings("nls")
155 public TransferConfig(Config rc) {
156 boolean fsck = rc.getBoolean("transfer", "fsckobjects", false);
157 fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck);
158 receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck);
159 fsckSkipList = rc.getString(FSCK, null, "skipList");
160 allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent",
161 false);
162 safeForWindows = rc.getBoolean(FSCK, "safeForWindows",
163 SystemReader.getInstance().isWindows());
164 safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS",
165 SystemReader.getInstance().isMacOS());
166
167 ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
168 EnumSet<ObjectChecker.ErrorType> set = EnumSet
169 .noneOf(ObjectChecker.ErrorType.class);
170 for (String key : rc.getNames(FSCK)) {
171 if (equalsIgnoreCase(key, "skipList")
172 || equalsIgnoreCase(key, "allowLeadingZeroFileMode")
173 || equalsIgnoreCase(key, "allowInvalidPersonIdent")
174 || equalsIgnoreCase(key, "safeForWindows")
175 || equalsIgnoreCase(key, "safeForMacOS")) {
176 continue;
177 }
178
179 ObjectChecker.ErrorType id = FsckKeyNameHolder.parse(key);
180 if (id != null) {
181 switch (rc.getEnum(FSCK, null, key, FsckMode.ERROR)) {
182 case ERROR:
183 ignore.remove(id);
184 break;
185 case WARN:
186 case IGNORE:
187 ignore.add(id);
188 break;
189 }
190 set.add(id);
191 }
192 }
193 if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
194 && rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) {
195 ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
196 }
197
198 allowRefInWant = rc.getBoolean("uploadpack", "allowrefinwant", false);
199 allowTipSha1InWant = rc.getBoolean(
200 "uploadpack", "allowtipsha1inwant", false);
201 allowReachableSha1InWant = rc.getBoolean(
202 "uploadpack", "allowreachablesha1inwant", false);
203 allowFilter = rc.getBoolean(
204 "uploadpack", "allowfilter", false);
205 protocolVersion = ProtocolVersion.parse(rc
206 .getString(ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
207 ConfigConstants.CONFIG_KEY_VERSION));
208 hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
209 allowSidebandAll = rc.getBoolean(
210 "uploadpack", "allowsidebandall", false);
211 advertiseSidebandAll = rc.getBoolean("uploadpack",
212 "advertisesidebandall", false);
213 advertiseWaitForDone = rc.getBoolean("uploadpack",
214 "advertisewaitfordone", false);
215 advertiseObjectInfo = rc.getBoolean("uploadpack",
216 "advertiseobjectinfo", false);
217 }
218
219
220
221
222
223
224
225
226 @Nullable
227 public ObjectChecker newObjectChecker() {
228 return newObjectChecker(fetchFsck);
229 }
230
231
232
233
234
235
236
237
238 @Nullable
239 public ObjectChecker newReceiveObjectChecker() {
240 return newObjectChecker(receiveFsck);
241 }
242
243 private ObjectChecker newObjectChecker(boolean check) {
244 if (!check) {
245 return null;
246 }
247 return new ObjectChecker()
248 .setIgnore(ignore)
249 .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
250 .setSafeForWindows(safeForWindows)
251 .setSafeForMacOS(safeForMacOS)
252 .setSkipList(skipList());
253 }
254
255 private ObjectIdSet skipList() {
256 if (fsckSkipList != null && !fsckSkipList.isEmpty()) {
257 return new LazyObjectIdSetFile(new File(fsckSkipList));
258 }
259 return null;
260 }
261
262
263
264
265
266
267
268 public boolean isAllowTipSha1InWant() {
269 return allowTipSha1InWant;
270 }
271
272
273
274
275
276
277
278 public boolean isAllowReachableSha1InWant() {
279 return allowReachableSha1InWant;
280 }
281
282
283
284
285
286 public boolean isAllowFilter() {
287 return allowFilter;
288 }
289
290
291
292
293
294 public boolean isAllowRefInWant() {
295 return allowRefInWant;
296 }
297
298
299
300
301
302
303 public boolean isAllowSidebandAll() {
304 return allowSidebandAll;
305 }
306
307
308
309
310
311 public boolean isAdvertiseSidebandAll() {
312 return advertiseSidebandAll && allowSidebandAll;
313 }
314
315
316
317
318
319 public boolean isAdvertiseWaitForDone() {
320 return advertiseWaitForDone;
321 }
322
323
324
325
326
327 public boolean isAdvertiseObjectInfo() {
328 return advertiseObjectInfo;
329 }
330
331
332
333
334
335
336
337
338
339 public RefFilter getRefFilter() {
340 if (hideRefs.length == 0)
341 return RefFilter.DEFAULT;
342
343 return new RefFilter() {
344 @Override
345 public Map<String, Ref> filter(Map<String, Ref> refs) {
346 Map<String, Ref> result = new HashMap<>();
347 for (Map.Entry<String, Ref> e : refs.entrySet()) {
348 boolean add = true;
349 for (String hide : hideRefs) {
350 if (e.getKey().equals(hide) || prefixMatch(hide, e.getKey())) {
351 add = false;
352 break;
353 }
354 }
355 if (add)
356 result.put(e.getKey(), e.getValue());
357 }
358 return result;
359 }
360
361 private boolean prefixMatch(String p, String s) {
362 return p.charAt(p.length() - 1) == '/' && s.startsWith(p);
363 }
364 };
365 }
366
367
368
369
370
371
372
373 boolean hasDefaultRefFilter() {
374 return hideRefs.length == 0;
375 }
376
377 static class FsckKeyNameHolder {
378 private static final Map<String, ObjectChecker.ErrorType> errors;
379
380 static {
381 errors = new HashMap<>();
382 for (ObjectChecker.ErrorType m : ObjectChecker.ErrorType.values()) {
383 errors.put(keyNameFor(m.name()), m);
384 }
385 }
386
387 @Nullable
388 static ObjectChecker.ErrorType parse(String key) {
389 return errors.get(toLowerCase(key));
390 }
391
392 private static String keyNameFor(String name) {
393 StringBuilder r = new StringBuilder(name.length());
394 for (int i = 0; i < name.length(); i++) {
395 char c = name.charAt(i);
396 if (c != '_') {
397 r.append(c);
398 }
399 }
400 return toLowerCase(r.toString());
401 }
402
403 private FsckKeyNameHolder() {
404 }
405 }
406 }