View Javadoc
1   /*
2    * Copyright (C) 2022 Thomas Wolf <thomas.wolf@paranor.ch> 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  
12  import java.util.HashMap;
13  import java.util.Map;
14  import java.util.Map.Entry;
15  
16  import org.eclipse.jgit.lib.Config;
17  
18  /**
19   * Support for URL translations via git configs {@code url.<base>.insteadOf} and
20   * {@code url.<base>.pushInsteadOf}.
21   *
22   * @since 6.2
23   */
24  public class UrlConfig {
25  
26  	private static final String KEY_INSTEADOF = "insteadof"; //$NON-NLS-1$
27  
28  	private static final String KEY_PUSHINSTEADOF = "pushinsteadof"; //$NON-NLS-1$
29  
30  	private static final String SECTION_URL = "url"; //$NON-NLS-1$
31  
32  	private final Config config;
33  
34  	private Map<String, String> insteadOf;
35  
36  	private Map<String, String> pushInsteadOf;
37  
38  	/**
39  	 * Creates a new {@link UrlConfig} instance.
40  	 *
41  	 * @param config
42  	 *            {@link Config} to read values from
43  	 */
44  	public UrlConfig(Config config) {
45  		this.config = config;
46  	}
47  
48  	/**
49  	 * Performs replacements as defined by git config
50  	 * {@code url.<base>.insteadOf}. If there is no match, the input is returned
51  	 * unchanged.
52  	 *
53  	 * @param url
54  	 *            to substitute
55  	 * @return the {@code url} with substitution applied
56  	 */
57  	public String replace(String url) {
58  		if (insteadOf == null) {
59  			insteadOf = load(KEY_INSTEADOF);
60  		}
61  		return replace(url, insteadOf);
62  	}
63  
64  	/**
65  	 * Tells whether there are push replacements.
66  	 *
67  	 * @return {@code true} if there are push replacements, {@code false}
68  	 *         otherwise
69  	 */
70  	public boolean hasPushReplacements() {
71  		if (pushInsteadOf == null) {
72  			pushInsteadOf = load(KEY_PUSHINSTEADOF);
73  		}
74  		return !pushInsteadOf.isEmpty();
75  	}
76  
77  	/**
78  	 * Performs replacements as defined by git config
79  	 * {@code url.<base>.pushInsteadOf}. If there is no match, the input is
80  	 * returned unchanged.
81  	 *
82  	 * @param url
83  	 *            to substitute
84  	 * @return the {@code url} with substitution applied
85  	 */
86  	public String replacePush(String url) {
87  		if (pushInsteadOf == null) {
88  			pushInsteadOf = load(KEY_PUSHINSTEADOF);
89  		}
90  		return replace(url, pushInsteadOf);
91  	}
92  
93  	private Map<String, String> load(String key) {
94  		Map<String, String> replacements = new HashMap<>();
95  		for (String url : config.getSubsections(SECTION_URL)) {
96  			for (String prefix : config.getStringList(SECTION_URL, url, key)) {
97  				replacements.put(prefix, url);
98  			}
99  		}
100 		return replacements;
101 	}
102 
103 	private String replace(String uri, Map<String, String> replacements) {
104 		Entry<String, String> match = null;
105 		for (Entry<String, String> replacement : replacements.entrySet()) {
106 			// Ignore current entry if not longer than previous match
107 			if (match != null && match.getKey().length() > replacement.getKey()
108 					.length()) {
109 				continue;
110 			}
111 			if (uri.startsWith(replacement.getKey())) {
112 				match = replacement;
113 			}
114 		}
115 		if (match != null) {
116 			return match.getValue() + uri.substring(match.getKey().length());
117 		}
118 		return uri;
119 	}
120 }