2 * Copyright (C) 2006 Shawn Pearce <spearce@spearce.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License, version 2, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 package org
.spearce
.jgit
.lib
;
19 import java
.io
.BufferedReader
;
20 import java
.io
.BufferedWriter
;
22 import java
.io
.FileInputStream
;
23 import java
.io
.FileOutputStream
;
24 import java
.io
.IOException
;
25 import java
.io
.InputStreamReader
;
26 import java
.io
.OutputStreamWriter
;
27 import java
.io
.PrintWriter
;
28 import java
.util
.ArrayList
;
29 import java
.util
.HashMap
;
30 import java
.util
.Iterator
;
31 import java
.util
.List
;
34 public class RepositoryConfig
{
35 private final Repository repo
;
37 private final File configFile
;
39 private CoreConfig core
;
45 private Map lastInEntry
;
47 private Map lastInGroup
;
49 private static final String MAGIC_EMPTY_VALUE
= "%%magic%%empty%%";
51 // used for global configs
52 private RepositoryConfig() {
54 configFile
= new File(System
.getProperty("user.home"), ".gitconfig");
56 if (configFile
.exists()) {
59 } catch (IOException e
) {
65 private static RepositoryConfig globalConfig
= null;
67 public static RepositoryConfig
getGlobalConfig() {
68 if (globalConfig
== null)
69 globalConfig
= new RepositoryConfig();
73 protected RepositoryConfig(final Repository r
) {
75 configFile
= new File(repo
.getDirectory(), "config");
79 public CoreConfig
getCore() {
83 public int getInt(final String group
, final String name
,
84 final int defaultValue
) {
85 final String n
= getString(group
, name
);
89 return getGlobalConfig().getInt(group
, name
, defaultValue
);
93 return Integer
.parseInt(n
);
94 } catch (NumberFormatException nfe
) {
95 throw new IllegalArgumentException("Invalid integer value: "
96 + group
+ "." + name
+ "=" + n
);
100 public boolean getBoolean(final String group
, final String name
,
101 final boolean defaultValue
) {
102 String n
= getRawString(group
, name
);
106 return getGlobalConfig().getBoolean(group
, name
, defaultValue
);
110 if (MAGIC_EMPTY_VALUE
.equals(n
) || "yes".equals(n
) || "true".equals(n
) || "1".equals(n
)) {
112 } else if ("no".equals(n
) || "false".equals(n
) || "0".equals(n
)) {
115 throw new IllegalArgumentException("Invalid boolean value: "
116 + group
+ "." + name
+ "=" + n
);
120 public String
getString(final String group
, final String name
) {
121 String val
= getRawString(group
, name
);
122 if (MAGIC_EMPTY_VALUE
.equals(val
)) {
128 private String
getRawString(final String group
, final String name
) {
130 o
= byName
.get(group
.toLowerCase() + "." + name
.toLowerCase());
131 if (o
instanceof List
) {
132 return ((Entry
) ((List
) o
).get(0)).value
;
133 } else if (o
instanceof Entry
) {
134 return ((Entry
) o
).value
;
138 return getGlobalConfig().getString(group
, name
);
142 public void create() {
153 e
.name
= "repositoryformatversion";
163 core
= new CoreConfig(this);
166 public void save() throws IOException
{
167 final File tmp
= new File(configFile
.getParentFile(), configFile
170 final PrintWriter r
= new PrintWriter(new BufferedWriter(
171 new OutputStreamWriter(new FileOutputStream(tmp
),
172 Constants
.CHARACTER_ENCODING
)));
175 final Iterator i
= entries
.iterator();
176 while (i
.hasNext()) {
177 final Entry e
= (Entry
) i
.next();
178 if (e
.prefix
!= null) {
181 if (e
.base
!= null && e
.name
== null) {
184 if (e
.extendedBase
!= null) {
187 r
.print(escapeValue(e
.extendedBase
));
191 } else if (e
.base
!= null && e
.name
!= null) {
192 if (e
.prefix
== null || "".equals(e
.prefix
)) {
196 if (e
.value
!= null) {
197 if (!MAGIC_EMPTY_VALUE
.equals(e
.value
)) {
199 r
.print(escapeValue(e
.value
));
202 if (e
.suffix
!= null) {
206 if (e
.suffix
!= null) {
214 if (!ok
|| !tmp
.renameTo(configFile
)) {
220 public void load() throws IOException
{
222 final BufferedReader r
= new BufferedReader(new InputStreamReader(
223 new FileInputStream(configFile
), Constants
.CHARACTER_ENCODING
));
226 Entry e
= new Entry();
229 int input
= r
.read();
230 final char in
= (char) input
;
233 } else if ('\n' == in
) {
234 // End of this entry.
236 if (e
.base
!= null) {
240 } else if (e
.suffix
!= null) {
241 // Everything up until the end-of-line is in the suffix.
243 } else if (';' == in
|| '#' == in
) {
244 // The rest of this line is a comment; put into suffix.
245 e
.suffix
= String
.valueOf(in
);
246 } else if (e
.base
== null && Character
.isWhitespace(in
)) {
247 // Save the leading whitespace (if any).
248 if (e
.prefix
== null) {
252 } else if ('[' == in
) {
253 // This is a group header line.
254 e
.base
= readBase(r
);
257 e
.extendedBase
= readValue(r
, true, '"');
261 throw new IOException("Bad group header.");
264 } else if (last
!= null) {
267 e
.extendedBase
= last
.extendedBase
;
269 e
.name
= readName(r
);
270 if (e
.name
.endsWith("\n")) {
271 e
.name
= e
.name
.substring(0, e
.name
.length()-1);
272 e
.value
= MAGIC_EMPTY_VALUE
;
274 e
.value
= readValue(r
, false, -1);
276 throw new IOException("Invalid line in config file.");
283 core
= new CoreConfig(this);
286 private void clear() {
287 entries
= new ArrayList();
288 byName
= new HashMap();
289 lastInEntry
= new HashMap();
290 lastInGroup
= new HashMap();
293 private void add(final Entry e
) {
295 if (e
.base
!= null) {
296 final String b
= e
.base
.toLowerCase();
298 if (e
.extendedBase
!= null) {
299 group
= b
+ "." + e
.extendedBase
;
303 if (e
.name
!= null) {
304 final String n
= e
.name
.toLowerCase();
305 final String key
= group
+ "." + n
;
306 final Object o
= byName
.get(key
);
309 } else if (o
instanceof Entry
) {
310 final ArrayList l
= new ArrayList();
314 } else if (o
instanceof List
) {
317 lastInEntry
.put(key
, e
);
319 lastInGroup
.put(group
, e
);
323 private static String
escapeValue(final String x
) {
324 boolean inquote
= false;
326 final StringBuffer r
= new StringBuffer(x
.length());
327 for (int k
= 0; k
< x
.length(); k
++) {
328 final char c
= x
.charAt(k
);
336 lineStart
= r
.length();
358 r
.insert(lineStart
, '"');
365 if (!inquote
&& r
.length() > 0
366 && r
.charAt(r
.length() - 1) == ' ') {
367 r
.insert(lineStart
, '"');
384 private static String
readBase(final BufferedReader r
) throws IOException
{
385 final StringBuffer base
= new StringBuffer();
390 throw new IOException("Unexpected end of config file.");
391 } else if (']' == c
) {
394 } else if (' ' == c
|| '\t' == c
) {
399 throw new IOException("Unexpected end of config file.");
400 } else if ('"' == c
) {
403 } else if (' ' == c
|| '\t' == c
) {
406 throw new IOException("Bad base entry. : " + base
+ "," + c
);
410 } else if (Character
.isLetterOrDigit((char) c
) || '.' == c
|| '-' == c
) {
411 base
.append((char) c
);
413 throw new IOException("Bad base entry. : " + base
+ ", " + c
);
416 return base
.toString();
419 private static String
readName(final BufferedReader r
) throws IOException
{
420 final StringBuffer name
= new StringBuffer();
425 throw new IOException("Unexpected end of config file.");
426 } else if ('=' == c
) {
428 } else if (' ' == c
|| '\t' == c
) {
433 throw new IOException("Unexpected end of config file.");
434 } else if ('=' == c
) {
436 } else if (';' == c
|| '#' == c
|| '\n' == c
) {
439 } else if (' ' == c
|| '\t' == c
) {
442 throw new IOException("Bad entry delimiter.");
446 } else if (Character
.isLetterOrDigit((char) c
)) {
447 name
.append((char) c
);
448 } else if ('\n' == c
) {
450 name
.append((char) c
);
453 throw new IOException("Bad config entry name: " + name
+ (char) c
);
456 return name
.toString();
459 private static String
readValue(final BufferedReader r
, boolean quote
,
460 final int eol
) throws IOException
{
461 final StringBuffer value
= new StringBuffer();
462 boolean space
= false;
467 throw new IOException("Unexpected end of config file.");
471 throw new IOException("Newline in quotes not allowed.");
480 if (Character
.isWhitespace((char) c
)) {
484 if (';' == c
|| '#' == c
) {
490 if (value
.length() > 0) {
499 throw new IOException("End of file in escape.");
518 throw new IOException("Bad escape: " + ((char) c
));
525 value
.append((char) c
);
527 return value
.length() > 0 ? value
.toString() : null;
530 public String
toString() {
531 return "RepositoryConfig[" + configFile
.getPath() + "]";
548 RepositoryConfig(String file
) throws IOException
{
550 configFile
= new File(file
);