config.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # ============================================================================
  2. # This file is part of Pwman3.
  3. #
  4. # Pwman3 is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License, version 2
  6. # as published by the Free Software Foundation;
  7. #
  8. # Pwman3 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
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with Pwman3; if not, write to the Free Software
  15. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. # ============================================================================
  17. # Copyright (C) 2018 Oz N Tiram <nahumoz@gmail.com>
  18. # ============================================================================
  19. # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
  20. # ============================================================================
  21. import os
  22. import platform
  23. import sys
  24. from functools import lru_cache
  25. if sys.version_info.major > 2: # pragma: no cover
  26. from configparser import (ConfigParser, ParsingError, NoOptionError,
  27. NoSectionError, MissingSectionHeaderError)
  28. else: # pragma: no cover
  29. from ConfigParser import (ConfigParser, ParsingError, NoOptionError,
  30. NoSectionError, MissingSectionHeaderError)
  31. # XDG code taken from xdg.py
  32. # https://github.com/srstevenson/xdg/blob/master/xdg.py
  33. # Copyright © 2016-2018 Scott Stevenson <scott@stevenson.io>
  34. def _getenv(variable: str, default: str) -> str:
  35. """Get an environment variable.
  36. Parameters
  37. ----------
  38. variable : str
  39. The environment variable.
  40. default : str
  41. A default value that will be returned if the environment
  42. variable is unset or empty.
  43. Returns
  44. -------
  45. str
  46. The value of the environment variable, or the default value.
  47. """
  48. return os.environ.get(variable) or default
  49. XDG_CACHE_HOME = _getenv('XDG_CACHE_HOME',
  50. os.path.expandvars(os.path.join('$HOME', '.cache')))
  51. XDG_CONFIG_DIRS = _getenv('XDG_CONFIG_DIRS', '/etc/xdg').split(':')
  52. XDG_CONFIG_HOME = _getenv('XDG_CONFIG_HOME',
  53. os.path.expandvars(os.path.join('$HOME', '.config')))
  54. XDG_DATA_DIRS = _getenv('XDG_DATA_DIRS',
  55. '/usr/local/share/:/usr/share/').split(':')
  56. XDG_DATA_HOME = _getenv('XDG_DATA_HOME',
  57. os.path.expandvars(
  58. os.path.join('$HOME', '.local', 'share')))
  59. XDG_RUNTIME_DIR = os.getenv('XDG_RUNTIME_DIR')
  60. @lru_cache(maxsize=None)
  61. def find_config_dir(appname):
  62. """
  63. Backward compatibly config dir finder
  64. If ~/.appname is not found define a new XDG compat one
  65. """
  66. config_dir = os.path.expanduser("~/.%s" % appname)
  67. if os.path.exists(config_dir):
  68. return config_dir, config_dir
  69. elif platform.system() == 'Windows':
  70. app_data = os.path.expandvars(os.path.join('$APPDATA', appname))
  71. return app_data, app_data
  72. else:
  73. return (os.path.join(XDG_CONFIG_HOME, appname),
  74. os.path.join(XDG_DATA_HOME, appname))
  75. config_dir, data_dir = find_config_dir('pwman')
  76. default_config = {'Global': {'umask': '0100', 'colors': 'yes',
  77. 'cls_timeout': '10', 'cp_timeout': '5',
  78. 'save': 'True', 'supress_version_check': 'no',
  79. 'lock_timeout': '600'
  80. },
  81. 'Database': {
  82. 'dburi': 'sqlite://' + os.path.join(data_dir,
  83. 'pwman.db')},
  84. 'Readline': {'history': os.path.join(data_dir,
  85. 'history')},
  86. 'Crypto': {'supress_warning': 'no'},
  87. 'Updater': {'supress_version_check': 'no'}
  88. }
  89. if 'win' in sys.platform:
  90. default_config['Database']['dburi'] = default_config['Database']['dburi'].replace("\\", "/") # noqa
  91. class ConfigException(Exception):
  92. """Basic exception for config."""
  93. def __init__(self, message):
  94. self.message = message
  95. def __str__(self):
  96. return "{}: {}".format(self.__class__.__name__,
  97. self.message) # pragma: no cover
  98. class ConfigNoConfigException(ConfigException):
  99. pass
  100. class Config(object):
  101. def __init__(self, filename=None, defaults=None, **kwargs):
  102. self.filename = filename
  103. self.parser = self._load(defaults)
  104. def _load(self, defaults):
  105. defaults = defaults or default_config
  106. parser = ConfigParser()
  107. try:
  108. with open(self.filename) as f:
  109. try:
  110. try:
  111. parser.read_file(f)
  112. except AttributeError:
  113. parser.readfp(f)
  114. except (ParsingError, MissingSectionHeaderError) as e:
  115. raise ConfigException(e)
  116. except IOError:
  117. self._self_write_new_conf(self.filename, defaults, parser)
  118. self._add_defaults(defaults, parser)
  119. return parser
  120. def _self_write_new_conf(self, filename, defaults, parser):
  121. self.parser = parser
  122. self._add_defaults(defaults, parser)
  123. self.save()
  124. def _add_defaults(self, defaults, parser):
  125. for section, options in defaults.items():
  126. if not parser.has_section(section):
  127. parser.add_section(section)
  128. for key, value in options.items():
  129. if not parser.has_option(section, key):
  130. parser.set(section, key, value)
  131. def get_value(self, section, name):
  132. try:
  133. return self.parser.get(section, name)
  134. except (NoOptionError, NoSectionError): # pragma: no cover
  135. return ''
  136. def set_value(self, section, name, value):
  137. self.parser.set(section, name, value)
  138. def save(self):
  139. if "False" not in self.get_value("Global", "Save"):
  140. with open(self.filename, "w") as fp:
  141. self.parser.write(fp)
  142. def get_pass_conf(config):
  143. ascii_lowercase = config.get_value("Generator",
  144. "ascii_lowercase").lower() == 'true'
  145. ascii_uppercase = config.get_value("Generator",
  146. "ascii_uppercase").lower() == 'true'
  147. ascii_digits = config.get_value("Generator",
  148. "ascii_digits").lower() == 'true'
  149. ascii_punctuation = config.get_value("Generator",
  150. "ascii_punctuation").lower() == 'true'
  151. return ascii_lowercase, ascii_uppercase, ascii_digits, ascii_punctuation