Fixed loading of user, repo config files.
[nbgit.git] / src / org / netbeans / modules / git / config / GitConfigFiles.java
blobf452cdabe55f8c0fd29d464b1df4620562716f58
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
24 * Contributor(s):
26 * The Original Software is NetBeans. The Initial Developer of the Original
27 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28 * Microsystems, Inc. All Rights Reserved.
29 * Portions Copyright 2008 Alexander Coles (Ikonoklastik Productions).
31 * If you wish your version of this file to be governed by only the CDDL
32 * or only the GPL Version 2, indicate your decision by adding
33 * "[Contributor] elects to include this software in this distribution
34 * under the [CDDL or GPL Version 2] license." If you do not indicate a
35 * single choice of license, a recipient has the option to distribute
36 * your version of this file under either the CDDL, the GPL Version 2 or
37 * to extend the choice of license to its licensees as provided above.
38 * However, if you add GPL Version 2 code and therefore, elected the GPL
39 * Version 2 license, then the option applies only if the new code is
40 * made subject to such option by the copyright holder.
42 package org.netbeans.modules.git.config;
44 import java.io.BufferedOutputStream;
45 import java.io.File;
46 import java.io.FileNotFoundException;
47 import java.io.FileOutputStream;
48 import java.io.FileReader;
49 import java.io.IOException;
50 import java.util.Iterator;
51 import java.util.Properties;
52 import java.util.Set;
53 import java.util.logging.Level;
54 import org.ini4j.Ini;
55 import org.netbeans.modules.git.Git;
56 import org.openide.filesystems.FileUtil;
57 import org.openide.util.Utilities;
59 /**
60 * Handles the Git configuration files:
61 * <ul>
62 * <li><code>$GIT_DIR/config</code> for repository-specific configuration.</li>
63 * <li><code>~/.gitconfig</code> for user configuration.</li>
64 * <li><code>$(prefix)/etc/gitconfig</code> for system-wide configuration.</li>
65 * </ul>
67 * @author Padraig O'Briain
68 * @author alexbcoles
70 public class GitConfigFiles {
72 public static final String GIT_EXTENSIONS = "extensions"; // NOI18N
73 public static final String GIT_EXTENSIONS_GITK = "gitk"; // NOI18N
74 public static final String GIT_EXTENSIONS_FETCH = "fetch"; // NOI18N
76 public static final String GIT_USER_SECTION = "user"; // NOI18N
77 public static final String GIT_USER_NAME = "name"; // NOI18N
78 public static final String GIT_EMAIL = "email"; // NOI18N
80 public static final String GIT_PATHS_SECTION = "[remote \"origin\"]"; // NOI18N
81 //public static final String GIT_DEFAULT_PUSH = "url"; // NOI18N
82 //public static final String GIT_DEFAULT_PUSH_VALUE = "url"; // NOI18N
83 public static final String GIT_DEFAULT_PULL = "url"; // NOI18N
84 public static final String GIT_DEFAULT_PULL_VALUE = "url"; // NOI18N
86 /** The GitConfigFiles instance for user and system defaults */
87 private static GitConfigFiles instance;
89 /** the Ini instance holding the configuration values stored in the <b>gitconfig</b>
90 * file used by the Git module */
91 private Ini gitConfig = null;
93 /** The repository directory if this instance is for a repository */
94 private File dir;
96 private static final String WINDOWS_USER_APPDATA = getAPPDATA();
97 private static final String WINDOWS_CONFIG_DIR = WINDOWS_USER_APPDATA + "\\Git"; // NOI18N
98 private static final String WINDOWS_GLOBAL_CONFIG_DIR = getGlobalAPPDATA() + "\\Git"; // NOI18N
100 public static final String GITCONFIG_FILE = "gitconfig"; // NOI18N
102 public static final String GIT_REPO_DIR = ".git"; // NOI18N
103 public static final String GIT_REPO_CONFIG_FILE = "config";
106 * Creates a new instance
108 private GitConfigFiles() {
109 // get the system .gitconfig file
110 gitConfig = loadFile(GITCONFIG_FILE);
114 * Returns a singleton instance
116 * @return the GitConfigFiles instance
118 public static GitConfigFiles getInstance() {
119 if (instance == null) {
120 instance = new GitConfigFiles();
122 return instance;
125 public GitConfigFiles(File file) {
126 dir = file;
127 gitConfig = loadFile(file, GIT_REPO_CONFIG_FILE);
130 public void setProperty(String name, String value) {
131 if (name.equals(GIT_USER_NAME)) {
132 setProperty(GIT_USER_SECTION, GIT_USER_NAME, value);
133 } else if (name.equals(GIT_EMAIL)) {
134 setProperty(GIT_USER_SECTION, GIT_EMAIL, value);
135 } else if (name.equals(GIT_DEFAULT_PULL)) {
136 setProperty(GIT_PATHS_SECTION, GIT_DEFAULT_PULL, value);
138 } else if (name.equals(GIT_EXTENSIONS_GITK)) {
140 if(getProperty(GIT_EXTENSIONS, GIT_EXTENSIONS_GITK).equals("")){
141 setProperty(GIT_EXTENSIONS, GIT_EXTENSIONS_GITK, value, true);
143 } else if (name.equals(GIT_EXTENSIONS_FETCH)) {
144 // Allow fetch to be set to some other user defined value if required
145 if(getProperty(GIT_EXTENSIONS, GIT_EXTENSIONS_FETCH).equals("")){
146 setProperty(GIT_EXTENSIONS, GIT_EXTENSIONS_FETCH, value, true);
152 public void setProperty(String section, String name, String value, boolean allowEmpty) {
153 if (!allowEmpty) {
154 if (value.length() == 0) {
155 removeProperty(section, name);
156 } else {
157 Ini.Section inisection = getSection(gitConfig, section, true);
158 inisection.put(name, value);
160 } else {
161 Ini.Section inisection = getSection(gitConfig, section, true);
162 inisection.put(name, value);
164 storeIni(gitConfig);
167 public void setProperty(String section, String name, String value) {
168 setProperty(section, name,value, false);
171 public void setEmail(String value) {
172 setProperty(GIT_USER_SECTION, GIT_EMAIL, value);
175 public void setUserName(String value) {
176 setProperty(GIT_USER_SECTION, GIT_USER_NAME, value);
179 public String getUserName() {
180 return getUserName(true);
183 public String getEmail() {
184 return getEmail(true);
187 public Properties getProperties(String section) {
188 Ini.Section inisection = getSection(gitConfig, section, false);
189 Properties props = new Properties();
190 if (inisection != null) {
191 Set<String> keys = inisection.keySet();
192 for (String key : keys) {
193 props.setProperty(key, inisection.get(key));
196 return props;
199 public void clearProperties(String section) {
200 Ini.Section inisection = getSection(gitConfig, section, false);
201 if (inisection != null) {
202 inisection.clear();
203 storeIni(gitConfig);
207 public void removeProperty(String section, String name) {
208 Ini.Section inisection = getSection(gitConfig, section, false);
209 if (inisection != null) {
210 inisection.remove(name);
211 storeIni(gitConfig);
215 public String getDefaultPull(Boolean reload) {
216 if (reload) {
217 doReload();
219 return getProperty(GIT_PATHS_SECTION, GIT_DEFAULT_PULL_VALUE);
222 public String getDefaultPush(Boolean reload) {
223 if (reload) {
224 doReload();
226 String value = "";
227 //String value = getProperty(GIT_PATHS_SECTION, "");
228 //if (value.length() == 0) {
229 value = getProperty(GIT_PATHS_SECTION, GIT_DEFAULT_PULL_VALUE);
231 return value;
234 public String getUserName(Boolean reload) {
235 if (reload) {
236 doReload();
238 return getProperty(GIT_USER_SECTION, GIT_USER_NAME);
241 public String getEmail(Boolean reload) {
242 if (reload) {
243 doReload();
245 return getProperty(GIT_USER_SECTION, GIT_EMAIL);
248 public String getProperty(String section, String name) {
249 Ini.Section inisection = getSection(gitConfig, section, true);
250 String value = inisection.get(name);
251 return value != null ? value : ""; // NOI18N
254 public boolean containsProperty(String section, String name) {
255 Ini.Section inisection = getSection(gitConfig, section, true);
256 return inisection.containsKey(name);
259 private void doReload () {
260 if (dir == null) {
261 gitConfig = loadFile(GITCONFIG_FILE);
262 } else {
263 gitConfig = loadFile(dir, GIT_REPO_CONFIG_FILE);
267 private Ini.Section getSection(Ini ini, String key, boolean create) {
268 Ini.Section section = ini.get(key);
269 if(section == null && create) {
270 return ini.add(key);
272 return section;
275 private void storeIni(Ini ini) {
276 try {
277 String filePath;
278 if (dir != null) {
279 filePath = dir.getAbsolutePath() + File.separator + GIT_REPO_DIR + File.separator + GIT_REPO_CONFIG_FILE; // NOI18N
280 } else {
281 filePath = getUserConfigPath() + GITCONFIG_FILE;
283 File file = FileUtil.normalizeFile(new File(filePath));
284 file.getParentFile().mkdirs();
285 ini.store(new BufferedOutputStream(new FileOutputStream(file)));
286 } catch (IOException ex) {
287 Git.LOG.log(Level.INFO, null, ex);
292 * Returns the path for the user-specific git configuration.
294 * @return the path
296 public static String getUserConfigPath() {
297 if(Utilities.isUnix()) {
298 String path = System.getProperty("user.home") ; // NOI18N
299 return path + "/."; // NOI18N
300 } else if (Utilities.isWindows()){
301 return WINDOWS_CONFIG_DIR + "/"; // NOI18N
303 return ""; // NOI18N
306 private Ini loadFile(File dir, String fileName) {
307 String filePath = dir.getAbsolutePath() + File.separator + GIT_REPO_DIR + File.separator + fileName; // NOI18N
308 File file = FileUtil.normalizeFile(new File(filePath));
309 Ini system = null;
310 try {
311 system = new Ini(new FileReader(file));
312 } catch (FileNotFoundException ex) {
313 // ignore
314 } catch (IOException ex) {
315 Git.LOG.log(Level.INFO, null, ex);
318 if(system == null) {
319 system = new Ini();
320 Git.LOG.log(Level.WARNING, "Could not load the file " + filePath + ". Falling back on git defaults."); // NOI18N
322 return system;
325 * Loads the configuration file
326 * The settings are loaded and merged together in the folowing order:
327 * <ol>
328 * <li> The per-user configuration file, i.e ~/.gitconfig
329 * </ol>
331 * @param fileName the file name
332 * @return an Ini instance holding the configuration file.
334 private Ini loadFile(String fileName) {
335 // config files from userdir
336 String filePath = getUserConfigPath() + fileName;
337 File file = FileUtil.normalizeFile(new File(filePath));
338 Ini system = null;
339 try {
340 system = new Ini(new FileReader(file));
341 } catch (FileNotFoundException ex) {
342 // ignore
343 } catch (IOException ex) {
344 Git.LOG.log(Level.INFO, null, ex);
347 if(system == null) {
348 system = new Ini();
349 Git.LOG.log(Level.WARNING, "Could not load the file " + filePath + ". Falling back on git defaults."); // NOI18N
352 Ini global = null;
353 try {
354 global = new Ini(new FileReader(getGlobalConfigPath() + File.separator + fileName)); // NOI18N
355 } catch (FileNotFoundException ex) {
356 // just doesn't exist - ignore
357 } catch (IOException ex) {
358 Git.LOG.log(Level.INFO, null, ex);
361 if(global != null) {
362 merge(global, system);
364 return system;
368 * Merges only sections/keys/values into target which are not already present in source
370 * @param source the source ini file
371 * @param target the target ini file in which the values from the source file are going to be merged
373 private void merge(Ini source, Ini target) {
374 for (Iterator<String> itSections = source.keySet().iterator(); itSections.hasNext();) {
375 String sectionName = itSections.next();
376 Ini.Section sourceSection = source.get( sectionName );
377 Ini.Section targetSection = target.get( sectionName );
379 if(targetSection == null) {
380 targetSection = target.add(sectionName);
383 for (Iterator<String> itVariables = sourceSection.keySet().iterator(); itVariables.hasNext();) {
384 String key = itVariables.next();
386 if(!targetSection.containsKey(key)) {
387 targetSection.put(key, sourceSection.get(key));
394 * Return the path for the systemwide command lines configuration directory
396 private static String getGlobalConfigPath () {
397 if(Utilities.isUnix()) {
398 return "/etc/gitconfig"; // NOI18N
399 } else if (Utilities.isWindows()){
400 return WINDOWS_GLOBAL_CONFIG_DIR;
402 return ""; // NOI18N
406 * Returns the value for the %APPDATA% env variable on Windows
408 private static String getAPPDATA() {
409 String appdata = ""; // NOI18N
410 if(Utilities.isWindows()) {
411 appdata = System.getenv("APPDATA");// NOI18N
413 return appdata!= null? appdata: ""; // NOI18N
417 * Returns the value for the %ALLUSERSPROFILE% + the last folder segment
418 * from %APPDATA% env variables on Windows
420 private static String getGlobalAPPDATA() {
421 if(Utilities.isWindows()) {
422 String globalProfile = System.getenv("ALLUSERSPROFILE"); // NOI18N
423 if(globalProfile == null || globalProfile.trim().equals("")) { // NOI18N
424 globalProfile = ""; // NOI18N
426 String appdataPath = WINDOWS_USER_APPDATA;
427 if(appdataPath == null || appdataPath.equals("")) { // NOI18N
428 return ""; // NOI18N
430 String appdata = ""; // NOI18N
431 int idx = appdataPath.lastIndexOf("\\"); // NOI18N
432 if(idx > -1) {
433 appdata = appdataPath.substring(idx + 1);
434 if(appdata.trim().equals("")) { // NOI18N
435 int previdx = appdataPath.lastIndexOf("\\", idx); // NOI18N
436 if(idx > -1) {
437 appdata = appdataPath.substring(previdx + 1, idx);
440 } else {
441 return ""; // NOI18N
443 return globalProfile + "/" + appdata; // NOI18N
445 return ""; // NOI18N