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 	 * @return the full tracking branch name or <code>null</code> if it could
117 	 *         not be determined
118 	 */
119 	public String getTrackingBranch() {
120 		String remote = getRemoteOrDefault();
121 		String mergeRef = getMerge();
122 		if (remote == null || mergeRef == null)
123 			return null;
124 
125 		if (isRemoteLocal())
126 			return mergeRef;
127 
128 		return findRemoteTrackingBranch(remote, mergeRef);
129 	}
130 
131 	/**
132 	 * @return the full remote-tracking branch name or {@code null} if it could
133 	 *         not be determined. If you also want local tracked branches use
134 	 *         {@link #getTrackingBranch()} instead.
135 	 */
136 	public String getRemoteTrackingBranch() {
137 		String remote = getRemoteOrDefault();
138 		String mergeRef = getMerge();
139 		if (remote == null || mergeRef == null)
140 			return null;
141 
142 		return findRemoteTrackingBranch(remote, mergeRef);
143 	}
144 
145 	/**
146 	 * @return {@code true} if the "remote" setting points to the local
147 	 *         repository (with {@value #LOCAL_REPOSITORY}), false otherwise
148 	 * @since 3.5
149 	 */
150 	public boolean isRemoteLocal() {
151 		return LOCAL_REPOSITORY.equals(getRemote());
152 	}
153 
154 	/**
155 	 * @return the remote this branch is configured to fetch from/push to, or
156 	 *         {@code null} if not defined
157 	 * @since 3.5
158 	 */
159 	public String getRemote() {
160 		return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
161 				branchName, ConfigConstants.CONFIG_KEY_REMOTE);
162 	}
163 
164 	/**
165 	 * @return the name of the upstream branch as it is called on the remote, or
166 	 *         {@code null} if not defined
167 	 * @since 3.5
168 	 */
169 	public String getMerge() {
170 		return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
171 				branchName, ConfigConstants.CONFIG_KEY_MERGE);
172 	}
173 
174 	/**
175 	 * @return {@code true} if the branch is configured to be rebased
176 	 * @since 3.5
177 	 */
178 	public boolean isRebase() {
179 		return getRebaseMode() != BranchRebaseMode.NONE;
180 	}
181 
182 	/**
183 	 * Retrieves the config value of branch.[name].rebase.
184 	 *
185 	 * @return the {@link BranchRebaseMode}
186 	 * @since 4.5
187 	 */
188 	public BranchRebaseMode getRebaseMode() {
189 		return config.getEnum(BranchRebaseMode.values(),
190 				ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
191 				ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
192 	}
193 
194 	/**
195 	 * Finds the tracked remote tracking branch
196 	 *
197 	 * @param remote
198 	 *            Remote name
199 	 * @param mergeRef
200 	 *            merge Ref of the local branch tracking the remote tracking
201 	 *            branch
202 	 * @return full remote tracking branch name or null
203 	 */
204 	private String findRemoteTrackingBranch(String remote, String mergeRef) {
205 		RemoteConfig remoteConfig;
206 		try {
207 			remoteConfig = new RemoteConfig(config, remote);
208 		} catch (URISyntaxException e) {
209 			return null;
210 		}
211 		for (RefSpec refSpec : remoteConfig.getFetchRefSpecs()) {
212 			if (refSpec.matchSource(mergeRef)) {
213 				RefSpec expanded = refSpec.expandFromSource(mergeRef);
214 				return expanded.getDestination();
215 			}
216 		}
217 		return null;
218 	}
219 
220 	private String getRemoteOrDefault() {
221 		String remote = getRemote();
222 		if (remote == null)
223 			return Constants.DEFAULT_REMOTE_NAME;
224 		else
225 			return remote;
226 	}
227 }