PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/mercurial/config.py

https://bitbucket.org/mirror/mercurial/
Python | 159 lines | 148 code | 3 blank | 8 comment | 8 complexity | 4de0b2fc038efc8a81e729ab8fbd661b MD5 | raw file
Possible License(s): GPL-2.0
  1. # config.py - configuration parsing for Mercurial
  2. #
  3. # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
  4. #
  5. # This software may be used and distributed according to the terms of the
  6. # GNU General Public License version 2 or any later version.
  7. from i18n import _
  8. import error, util
  9. import os, errno
  10. class config(object):
  11. def __init__(self, data=None):
  12. self._data = {}
  13. self._source = {}
  14. self._unset = []
  15. if data:
  16. for k in data._data:
  17. self._data[k] = data[k].copy()
  18. self._source = data._source.copy()
  19. def copy(self):
  20. return config(self)
  21. def __contains__(self, section):
  22. return section in self._data
  23. def __getitem__(self, section):
  24. return self._data.get(section, {})
  25. def __iter__(self):
  26. for d in self.sections():
  27. yield d
  28. def update(self, src):
  29. for s, n in src._unset:
  30. if s in self and n in self._data[s]:
  31. del self._data[s][n]
  32. del self._source[(s, n)]
  33. for s in src:
  34. if s not in self:
  35. self._data[s] = util.sortdict()
  36. self._data[s].update(src._data[s])
  37. self._source.update(src._source)
  38. def get(self, section, item, default=None):
  39. return self._data.get(section, {}).get(item, default)
  40. def backup(self, section, item):
  41. """return a tuple allowing restore to reinstall a previous value
  42. The main reason we need it is because it handles the "no data" case.
  43. """
  44. try:
  45. value = self._data[section][item]
  46. source = self.source(section, item)
  47. return (section, item, value, source)
  48. except KeyError:
  49. return (section, item)
  50. def source(self, section, item):
  51. return self._source.get((section, item), "")
  52. def sections(self):
  53. return sorted(self._data.keys())
  54. def items(self, section):
  55. return self._data.get(section, {}).items()
  56. def set(self, section, item, value, source=""):
  57. if section not in self:
  58. self._data[section] = util.sortdict()
  59. self._data[section][item] = value
  60. if source:
  61. self._source[(section, item)] = source
  62. def restore(self, data):
  63. """restore data returned by self.backup"""
  64. if len(data) == 4:
  65. # restore old data
  66. section, item, value, source = data
  67. self._data[section][item] = value
  68. self._source[(section, item)] = source
  69. else:
  70. # no data before, remove everything
  71. section, item = data
  72. if section in self._data:
  73. del self._data[section][item]
  74. self._source.pop((section, item), None)
  75. def parse(self, src, data, sections=None, remap=None, include=None):
  76. sectionre = util.compilere(r'\[([^\[]+)\]')
  77. itemre = util.compilere(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
  78. contre = util.compilere(r'\s+(\S|\S.*\S)\s*$')
  79. emptyre = util.compilere(r'(;|#|\s*$)')
  80. commentre = util.compilere(r'(;|#)')
  81. unsetre = util.compilere(r'%unset\s+(\S+)')
  82. includere = util.compilere(r'%include\s+(\S|\S.*\S)\s*$')
  83. section = ""
  84. item = None
  85. line = 0
  86. cont = False
  87. for l in data.splitlines(True):
  88. line += 1
  89. if line == 1 and l.startswith('\xef\xbb\xbf'):
  90. # Someone set us up the BOM
  91. l = l[3:]
  92. if cont:
  93. if commentre.match(l):
  94. continue
  95. m = contre.match(l)
  96. if m:
  97. if sections and section not in sections:
  98. continue
  99. v = self.get(section, item) + "\n" + m.group(1)
  100. self.set(section, item, v, "%s:%d" % (src, line))
  101. continue
  102. item = None
  103. cont = False
  104. m = includere.match(l)
  105. if m:
  106. inc = util.expandpath(m.group(1))
  107. base = os.path.dirname(src)
  108. inc = os.path.normpath(os.path.join(base, inc))
  109. if include:
  110. try:
  111. include(inc, remap=remap, sections=sections)
  112. except IOError, inst:
  113. if inst.errno != errno.ENOENT:
  114. raise error.ParseError(_("cannot include %s (%s)")
  115. % (inc, inst.strerror),
  116. "%s:%s" % (src, line))
  117. continue
  118. if emptyre.match(l):
  119. continue
  120. m = sectionre.match(l)
  121. if m:
  122. section = m.group(1)
  123. if remap:
  124. section = remap.get(section, section)
  125. if section not in self:
  126. self._data[section] = util.sortdict()
  127. continue
  128. m = itemre.match(l)
  129. if m:
  130. item = m.group(1)
  131. cont = True
  132. if sections and section not in sections:
  133. continue
  134. self.set(section, item, m.group(2), "%s:%d" % (src, line))
  135. continue
  136. m = unsetre.match(l)
  137. if m:
  138. name = m.group(1)
  139. if sections and section not in sections:
  140. continue
  141. if self.get(section, name) is not None:
  142. del self._data[section][name]
  143. self._unset.append((section, name))
  144. continue
  145. raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line)))
  146. def read(self, path, fp=None, sections=None, remap=None):
  147. if not fp:
  148. fp = util.posixfile(path)
  149. self.parse(path, fp.read(), sections, remap, self.read)