View Javadoc
1   /*
2    * Copyright (C) 2011, Robin Stocker <robin@nibor.org>
3    * Copyright (C) 2012, Matthias Sohn <matthias.sohn@sap.com>
4    * and other copyright owners as documented in the project's IP log.
5    *
6    * This program and the accompanying materials are made available
7    * under the terms of the Eclipse Distribution License v1.0 which
8    * accompanies this distribution, is reproduced below, and is
9    * available at http://www.eclipse.org/org/documents/edl-v10.php
10   *
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or
14   * without modification, are permitted provided that the following
15   * conditions are met:
16   *
17   * - Redistributions of source code must retain the above copyright
18   *   notice, this list of conditions and the following disclaimer.
19   *
20   * - Redistributions in binary form must reproduce the above
21   *   copyright notice, this list of conditions and the following
22   *   disclaimer in the documentation and/or other materials provided
23   *   with the distribution.
24   *
25   * - Neither the name of the Eclipse Foundation, Inc. nor the
26   *   names of its contributors may be used to endorse or promote
27   *   products derived from this software without specific prior
28   *   written permission.
29   *
30   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43   */
44  
45  package org.eclipse.jgit.lib;
46  
47  import java.net.URISyntaxException;
48  
49  import org.eclipse.jgit.transport.RefSpec;
50  import org.eclipse.jgit.transport.RemoteConfig;
51  
52  /**
53   * Branch section of a Git configuration file.
54   */
55  public class BranchConfig {
56  
57  	/**
58  	 * Config values for branch.[name].rebase (and pull.rebase).
59  	 *
60  	 * @since 4.5
61  	 */
62  	public enum BranchRebaseMode implements Config.ConfigEnum {
63  
64  		/** Value for rebasing */
65  		REBASE("true"), //$NON-NLS-1$
66  		/** Value for rebasing preserving local merge commits */
67  		PRESERVE("preserve"), //$NON-NLS-1$
68  		/** Value for rebasing interactively */
69  		INTERACTIVE("interactive"), //$NON-NLS-1$
70  		/** Value for not rebasing at all but merging */
71  		NONE("false"); //$NON-NLS-1$
72  
73  		private final String configValue;
74  
75  		private BranchRebaseMode(String configValue) {
76  			this.configValue = configValue;
77  		}
78  
79  		@Override
80  		public String toConfigValue() {
81  			return configValue;
82  		}
83  
84  		@Override
85  		public boolean matchConfigValue(String s) {
86  			return configValue.equals(s);
87  		}
88  	}
89  
90  	/**
91  	 * The value that means "local repository" for {@link #getRemote()}:
92  	 * {@value}
93  	 *
94  	 * @since 3.5
95  	 */
96  	public static final String LOCAL_REPOSITORY = "."; //$NON-NLS-1$
97  
98  	private final Config config;
99  	private final String branchName;
100 
101 	/**
102 	 * Create a new branch config, which will read configuration from config
103 	 * about specified branch.
104 	 *
105 	 * @param config
106 	 *            the config to read from
107 	 * @param branchName
108 	 *            the short branch name of the section to read
109 	 */
110 	public BranchConfig(final Config config, String branchName) {
111 		this.config = config;
112 		this.branchName = branchName;
113 	}
114 
115 	/**
116 	 * Get the full tracking branch name
117 	 *
118 	 * @return the full tracking branch name or <code>null</code> if it could
119 	 *         not be determined
120 	 */
121 	public String getTrackingBranch() {
122 		String remote = getRemoteOrDefault();
123 		String mergeRef = getMerge();
124 		if (remote == null || mergeRef == null)
125 			return null;
126 
127 		if (isRemoteLocal())
128 			return mergeRef;
129 
130 		return findRemoteTrackingBranch(remote, mergeRef);
131 	}
132 
133 	/**
134 	 * Get the full remote-tracking branch name
135 	 *
136 	 * @return the full remote-tracking branch name or {@code null} if it could
137 	 *         not be determined. If you also want local tracked branches use
138 	 *         {@link #getTrackingBranch()} instead.
139 	 */
140 	public String getRemoteTrackingBranch() {
141 		String remote = getRemoteOrDefault();
142 		String mergeRef = getMerge();
143 		if (remote == null || mergeRef == null)
144 			return null;
145 
146 		return findRemoteTrackingBranch(remote, mergeRef);
147 	}
148 
149 	/**
150 	 * Whether the "remote" setting points to the local repository (with
151 	 * {@value #LOCAL_REPOSITORY})
152 	 *
153 	 * @return {@code true} if the "remote" setting points to the local
154 	 *         repository (with {@value #LOCAL_REPOSITORY}), false otherwise
155 	 * @since 3.5
156 	 */
157 	public boolean isRemoteLocal() {
158 		return LOCAL_REPOSITORY.equals(getRemote());
159 	}
160 
161 	/**
162 	 * Get the remote this branch is configured to fetch from/push to
163 	 *
164 	 * @return the remote this branch is configured to fetch from/push to, or
165 	 *         {@code null} if not defined
166 	 * @since 3.5
167 	 */
168 	public String getRemote() {
169 		return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
170 				branchName, ConfigConstants.CONFIG_KEY_REMOTE);
171 	}
172 
173 	/**
174 	 * Get the name of the upstream branch as it is called on the remote
175 	 *
176 	 * @return the name of the upstream branch as it is called on the remote, or
177 	 *         {@code null} if not defined
178 	 * @since 3.5
179 	 */
180 	public String getMerge() {
181 		return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
182 				branchName, ConfigConstants.CONFIG_KEY_MERGE);
183 	}
184 
185 	/**
186 	 * Whether the branch is configured to be rebased
187 	 *
188 	 * @return {@code true} if the branch is configured to be rebased
189 	 * @since 3.5
190 	 */
191 	public boolean isRebase() {
192 		return getRebaseMode() != BranchRebaseMode.NONE;
193 	}
194 
195 	/**
196 	 * Retrieves the config value of branch.[name].rebase.
197 	 *
198 	 * @return the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
199 	 * @since 4.5
200 	 */
201 	public BranchRebaseMode getRebaseMode() {
202 		return config.getEnum(BranchRebaseMode.values(),
203 				ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
204 				ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
205 	}
206 
207 	/**
208 	 * Finds the tracked remote tracking branch
209 	 *
210 	 * @param remote
211 	 *            Remote name
212 	 * @param mergeRef
213 	 *            merge Ref of the local branch tracking the remote tracking
214 	 *            branch
215 	 * @return full remote tracking branch name or null
216 	 */
217 	private String findRemoteTrackingBranch(String remote, String mergeRef) {
218 		RemoteConfig remoteConfig;
219 		try {
220 			remoteConfig = new RemoteConfig(config, remote);
221 		} catch (URISyntaxException e) {
222 			return null;
223 		}
224 		for (RefSpec refSpec : remoteConfig.getFetchRefSpecs()) {
225 			if (refSpec.matchSource(mergeRef)) {
226 				RefSpec expanded = refSpec.expandFromSource(mergeRef);
227 				return expanded.getDestination();
228 			}
229 		}
230 		return null;
231 	}
232 
233 	private String getRemoteOrDefault() {
234 		String remote = getRemote();
235 		if (remote == null)
236 			return Constants.DEFAULT_REMOTE_NAME;
237 		else
238 			return remote;
239 	}
240 }