You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TransferConfig.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Copyright (C) 2008, 2020 Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.transport;
  11. import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
  12. import static org.eclipse.jgit.util.StringUtils.toLowerCase;
  13. import java.io.File;
  14. import java.util.EnumSet;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. import org.eclipse.jgit.annotations.Nullable;
  18. import org.eclipse.jgit.internal.storage.file.LazyObjectIdSetFile;
  19. import org.eclipse.jgit.lib.Config;
  20. import org.eclipse.jgit.lib.ConfigConstants;
  21. import org.eclipse.jgit.lib.Config.SectionParser;
  22. import org.eclipse.jgit.lib.ObjectChecker;
  23. import org.eclipse.jgit.lib.ObjectIdSet;
  24. import org.eclipse.jgit.lib.Ref;
  25. import org.eclipse.jgit.lib.Repository;
  26. import org.eclipse.jgit.util.SystemReader;
  27. /**
  28. * The standard "transfer", "fetch", "protocol", "receive", and "uploadpack"
  29. * configuration parameters.
  30. */
  31. public class TransferConfig {
  32. private static final String FSCK = "fsck"; //$NON-NLS-1$
  33. /** Key for {@link Config#get(SectionParser)}. */
  34. public static final Config.SectionParser<TransferConfig> KEY =
  35. TransferConfig::new;
  36. /**
  37. * A git configuration value for how to handle a fsck failure of a particular kind.
  38. * Used in e.g. fsck.missingEmail.
  39. * @since 4.9
  40. */
  41. public enum FsckMode {
  42. /**
  43. * Treat it as an error (the default).
  44. */
  45. ERROR,
  46. /**
  47. * Issue a warning (in fact, jgit treats this like IGNORE, but git itself does warn).
  48. */
  49. WARN,
  50. /**
  51. * Ignore the error.
  52. */
  53. IGNORE;
  54. }
  55. /**
  56. * A git configuration variable for which versions of the Git protocol to
  57. * prefer. Used in protocol.version.
  58. *
  59. * @since 5.9
  60. */
  61. public enum ProtocolVersion {
  62. /**
  63. * Git wire protocol version 0 (the default).
  64. */
  65. V0("0"), //$NON-NLS-1$
  66. /**
  67. * Git wire protocol version 2.
  68. */
  69. V2("2"); //$NON-NLS-1$
  70. final String name;
  71. ProtocolVersion(String name) {
  72. this.name = name;
  73. }
  74. /**
  75. * Returns version number
  76. *
  77. * @return string version
  78. */
  79. public String version() {
  80. return name;
  81. }
  82. @Nullable
  83. static ProtocolVersion parse(@Nullable String name) {
  84. if (name == null) {
  85. return null;
  86. }
  87. for (ProtocolVersion v : ProtocolVersion.values()) {
  88. if (v.name.equals(name)) {
  89. return v;
  90. }
  91. }
  92. if ("1".equals(name)) { //$NON-NLS-1$
  93. return V0;
  94. }
  95. return null;
  96. }
  97. }
  98. private final boolean fetchFsck;
  99. private final boolean receiveFsck;
  100. private final String fsckSkipList;
  101. private final EnumSet<ObjectChecker.ErrorType> ignore;
  102. private final boolean allowInvalidPersonIdent;
  103. private final boolean safeForWindows;
  104. private final boolean safeForMacOS;
  105. private final boolean allowRefInWant;
  106. private final boolean allowTipSha1InWant;
  107. private final boolean allowReachableSha1InWant;
  108. private final boolean allowFilter;
  109. private final boolean allowSidebandAll;
  110. private final boolean advertiseSidebandAll;
  111. private final boolean advertiseWaitForDone;
  112. final @Nullable ProtocolVersion protocolVersion;
  113. final String[] hideRefs;
  114. /**
  115. * Create a configuration honoring the repository's settings.
  116. *
  117. * @param db
  118. * the repository to read settings from. The repository is not
  119. * retained by the new configuration, instead its settings are
  120. * copied during the constructor.
  121. * @since 5.1.4
  122. */
  123. public TransferConfig(Repository db) {
  124. this(db.getConfig());
  125. }
  126. /**
  127. * Create a configuration honoring settings in a
  128. * {@link org.eclipse.jgit.lib.Config}.
  129. *
  130. * @param rc
  131. * the source to read settings from. The source is not retained
  132. * by the new configuration, instead its settings are copied
  133. * during the constructor.
  134. * @since 5.1.4
  135. */
  136. @SuppressWarnings("nls")
  137. public TransferConfig(Config rc) {
  138. boolean fsck = rc.getBoolean("transfer", "fsckobjects", false);
  139. fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck);
  140. receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck);
  141. fsckSkipList = rc.getString(FSCK, null, "skipList");
  142. allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent",
  143. false);
  144. safeForWindows = rc.getBoolean(FSCK, "safeForWindows",
  145. SystemReader.getInstance().isWindows());
  146. safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS",
  147. SystemReader.getInstance().isMacOS());
  148. ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
  149. EnumSet<ObjectChecker.ErrorType> set = EnumSet
  150. .noneOf(ObjectChecker.ErrorType.class);
  151. for (String key : rc.getNames(FSCK)) {
  152. if (equalsIgnoreCase(key, "skipList")
  153. || equalsIgnoreCase(key, "allowLeadingZeroFileMode")
  154. || equalsIgnoreCase(key, "allowInvalidPersonIdent")
  155. || equalsIgnoreCase(key, "safeForWindows")
  156. || equalsIgnoreCase(key, "safeForMacOS")) {
  157. continue;
  158. }
  159. ObjectChecker.ErrorType id = FsckKeyNameHolder.parse(key);
  160. if (id != null) {
  161. switch (rc.getEnum(FSCK, null, key, FsckMode.ERROR)) {
  162. case ERROR:
  163. ignore.remove(id);
  164. break;
  165. case WARN:
  166. case IGNORE:
  167. ignore.add(id);
  168. break;
  169. }
  170. set.add(id);
  171. }
  172. }
  173. if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
  174. && rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) {
  175. ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
  176. }
  177. allowRefInWant = rc.getBoolean("uploadpack", "allowrefinwant", false);
  178. allowTipSha1InWant = rc.getBoolean(
  179. "uploadpack", "allowtipsha1inwant", false);
  180. allowReachableSha1InWant = rc.getBoolean(
  181. "uploadpack", "allowreachablesha1inwant", false);
  182. allowFilter = rc.getBoolean(
  183. "uploadpack", "allowfilter", false);
  184. protocolVersion = ProtocolVersion.parse(rc
  185. .getString(ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
  186. ConfigConstants.CONFIG_KEY_VERSION));
  187. hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
  188. allowSidebandAll = rc.getBoolean(
  189. "uploadpack", "allowsidebandall", false);
  190. advertiseSidebandAll = rc.getBoolean("uploadpack",
  191. "advertisesidebandall", false);
  192. advertiseWaitForDone = rc.getBoolean("uploadpack",
  193. "advertisewaitfordone", false);
  194. }
  195. /**
  196. * Create checker to verify fetched objects
  197. *
  198. * @return checker to verify fetched objects, or null if checking is not
  199. * enabled in the repository configuration.
  200. * @since 3.6
  201. */
  202. @Nullable
  203. public ObjectChecker newObjectChecker() {
  204. return newObjectChecker(fetchFsck);
  205. }
  206. /**
  207. * Create checker to verify objects pushed into this repository
  208. *
  209. * @return checker to verify objects pushed into this repository, or null if
  210. * checking is not enabled in the repository configuration.
  211. * @since 4.2
  212. */
  213. @Nullable
  214. public ObjectChecker newReceiveObjectChecker() {
  215. return newObjectChecker(receiveFsck);
  216. }
  217. private ObjectChecker newObjectChecker(boolean check) {
  218. if (!check) {
  219. return null;
  220. }
  221. return new ObjectChecker()
  222. .setIgnore(ignore)
  223. .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
  224. .setSafeForWindows(safeForWindows)
  225. .setSafeForMacOS(safeForMacOS)
  226. .setSkipList(skipList());
  227. }
  228. private ObjectIdSet skipList() {
  229. if (fsckSkipList != null && !fsckSkipList.isEmpty()) {
  230. return new LazyObjectIdSetFile(new File(fsckSkipList));
  231. }
  232. return null;
  233. }
  234. /**
  235. * Whether to allow clients to request non-advertised tip SHA-1s
  236. *
  237. * @return allow clients to request non-advertised tip SHA-1s?
  238. * @since 3.1
  239. */
  240. public boolean isAllowTipSha1InWant() {
  241. return allowTipSha1InWant;
  242. }
  243. /**
  244. * Whether to allow clients to request non-tip SHA-1s
  245. *
  246. * @return allow clients to request non-tip SHA-1s?
  247. * @since 4.1
  248. */
  249. public boolean isAllowReachableSha1InWant() {
  250. return allowReachableSha1InWant;
  251. }
  252. /**
  253. * @return true if clients are allowed to specify a "filter" line
  254. * @since 5.0
  255. */
  256. public boolean isAllowFilter() {
  257. return allowFilter;
  258. }
  259. /**
  260. * @return true if clients are allowed to specify a "want-ref" line
  261. * @since 5.1
  262. */
  263. public boolean isAllowRefInWant() {
  264. return allowRefInWant;
  265. }
  266. /**
  267. * @return true if the server accepts sideband-all requests (see
  268. * {{@link #isAdvertiseSidebandAll()} for the advertisement)
  269. * @since 5.5
  270. */
  271. public boolean isAllowSidebandAll() {
  272. return allowSidebandAll;
  273. }
  274. /**
  275. * @return true to advertise sideband all to the clients
  276. * @since 5.6
  277. */
  278. public boolean isAdvertiseSidebandAll() {
  279. return advertiseSidebandAll && allowSidebandAll;
  280. }
  281. /**
  282. * @return true to advertise wait-for-done all to the clients
  283. * @since 5.13
  284. */
  285. public boolean isAdvertiseWaitForDone() {
  286. return advertiseWaitForDone;
  287. }
  288. /**
  289. * Get {@link org.eclipse.jgit.transport.RefFilter} respecting configured
  290. * hidden refs.
  291. *
  292. * @return {@link org.eclipse.jgit.transport.RefFilter} respecting
  293. * configured hidden refs.
  294. * @since 3.1
  295. */
  296. public RefFilter getRefFilter() {
  297. if (hideRefs.length == 0)
  298. return RefFilter.DEFAULT;
  299. return new RefFilter() {
  300. @Override
  301. public Map<String, Ref> filter(Map<String, Ref> refs) {
  302. Map<String, Ref> result = new HashMap<>();
  303. for (Map.Entry<String, Ref> e : refs.entrySet()) {
  304. boolean add = true;
  305. for (String hide : hideRefs) {
  306. if (e.getKey().equals(hide) || prefixMatch(hide, e.getKey())) {
  307. add = false;
  308. break;
  309. }
  310. }
  311. if (add)
  312. result.put(e.getKey(), e.getValue());
  313. }
  314. return result;
  315. }
  316. private boolean prefixMatch(String p, String s) {
  317. return p.charAt(p.length() - 1) == '/' && s.startsWith(p);
  318. }
  319. };
  320. }
  321. /**
  322. * Like {@code getRefFilter() == RefFilter.DEFAULT}, but faster.
  323. *
  324. * @return {@code true} if no ref filtering is needed because there
  325. * are no configured hidden refs.
  326. */
  327. boolean hasDefaultRefFilter() {
  328. return hideRefs.length == 0;
  329. }
  330. static class FsckKeyNameHolder {
  331. private static final Map<String, ObjectChecker.ErrorType> errors;
  332. static {
  333. errors = new HashMap<>();
  334. for (ObjectChecker.ErrorType m : ObjectChecker.ErrorType.values()) {
  335. errors.put(keyNameFor(m.name()), m);
  336. }
  337. }
  338. @Nullable
  339. static ObjectChecker.ErrorType parse(String key) {
  340. return errors.get(toLowerCase(key));
  341. }
  342. private static String keyNameFor(String name) {
  343. StringBuilder r = new StringBuilder(name.length());
  344. for (int i = 0; i < name.length(); i++) {
  345. char c = name.charAt(i);
  346. if (c != '_') {
  347. r.append(c);
  348. }
  349. }
  350. return toLowerCase(r.toString());
  351. }
  352. private FsckKeyNameHolder() {
  353. }
  354. }
  355. }