summaryrefslogtreecommitdiff
path: root/lib/git/config.py
blob: c7f2c3981af87df1203cd1bfbe23a11683146a6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# config.py
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
"""
Module containing module parser implementation able to properly read and write
configuration files
"""

import re
from ConfigParser import RawConfigParser

class _MetaParserBuilder(type):
	"""
	Utlity class wrapping methods into decorators that assure read-only properties
	"""

def _needs_values(func):
	"""Returns method assuring we read values (on demand) before we try to access them"""
	return func
	
def _ensure_writable(non_const_func):
	"""Return method that checks whether given non constant function may be called.
	If so, the instance will be set dirty"""
	
	

class GitConfigParser(RawConfigParser, object):
	"""
	Implements specifics required to read git style configuration files.
	
	This variation behaves much like the git.config command such that the configuration
	will be read on demand based on the filepath given during initialization.
	
	The changes will automatically be written once the instance goes out of scope, but 
	can be triggered manually as well.
	
	The configuration file will be locked if you intend to change values preventing other 
	instances to write concurrently.
	"""
	__metaclass__ = _MetaParserBuilder
	
	OPTCRE = re.compile(
		r'\s?(?P<option>[^:=\s][^:=]*)'		  # very permissive, incuding leading whitespace
		r'\s*(?P<vi>[:=])\s*'				  # any number of space/tab,
											  # followed by separator
											  # (either : or =), followed
											  # by any # space/tab
		r'(?P<value>.*)$'					  # everything up to eol
		)
	
	# list of RawConfigParser methods able to change the instance
	_mutating_methods_ = tuple()	
	
	
	def __init__(self, file_or_files, read_only=True):
		"""
		Initialize a configuration reader to read the given file_or_files and to 
		possibly allow changes to it by setting read_only False 
		"""
		self._file_or_files = file_or_files
		self._read_only = read_only
		self._is_initialized = False
		self._is_dirty = False
	
	def __del__(self):
		"""
		Write pending changes if required and release locks
		"""
	
	def read(self):
		"""
		Read configuration information from our file or files
		"""
		if self._is_initialized:
			return 
		
		self._is_initialized = True
		
	@_ensure_writable
	def write(self):
		"""
		Write our changes to our file
		
		Raise
			AssertionError if this is a read-only writer instance
		"""
		if not self._is_dirty:
			return
		
		self._is_dirty = False
		
	@property
	def read_only(self):
		"""
		Returns
			True if this instance may change the configuration file
		"""
		return self._read_only