summaryrefslogtreecommitdiff
path: root/portato/session.py
blob: 5d1a640174d3f8774aba2316703b3cb3d23d10d0 (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# -*- coding: utf-8 -*-
#
# File: portato/session.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
# Copyright (C) 2007 René 'Necoro' Neumann
# This is free software.  You may redistribute copies of it under the terms of
# the GNU General Public License version 2.
# There is NO WARRANTY, to the extent permitted by law.
#
# Written by René 'Necoro' Neumann <necoro@necoro.net>

from __future__ import absolute_import, with_statement

import os, os.path

from .config_parser import ConfigParser, SectionNotFoundException
from .constants import SESSION_DIR
from .helper import debug, info

class Session (object):
	"""
	A small class allowing to save certain states of a program.
	This class works in a quite abstract manner, as it works with handlers, which
	define what options to use out of the config file and how to apply them to the program.

	Note: This class currently does not work with boolean config options. If you
	want to define boolean values, use 0 and 1. This is future proof.
	"""

	# the current session format version
	VERSION = 1

	def __init__ (self, file):
		"""
		Initialize a session with a certain file inside L{SESSION_DIR}.

		@param file: the file in L{SESSION_DIR}, where the options will be saved.
		"""

		self._cfg = None
		self._handlers = []

		if not (os.path.exists(SESSION_DIR) and os.path.isdir(SESSION_DIR)):
			os.mkdir(SESSION_DIR)
		self._cfg = ConfigParser(os.path.join(SESSION_DIR, file))
		info(_("Loading session from '%s'.") % self._cfg.file)
		try:
			self._cfg.parse()
		except IOError, e:
			if e.errno == 2: pass
			else: raise

		# add version check
		self.add_handler(([("version", "session")], self.check_version, lambda: self.VERSION))

	def add_handler (self, (options, load_fn, save_fn), default = None):
		"""
		Adds a handler to this session. A handler is a three-tuple consisting of:
			- a list of (key,section) values
			- a function getting number of option arguments and applying them to the program
			- a function returning the number of option return values - getting them out of the program
		"""
		self._handlers.append((options, load_fn, save_fn, default))

	def load (self):
		"""
		Loads and applies all values of the session.
		"""
		for options, lfn, sfn, default in self._handlers:
			try:
				loaded = [self._cfg.get(*x) for x in options]
			except KeyError: # does not exist -> ignore
				debug("No values for %s.", options)
			else:
				debug("Loading %s with values %s.", options, loaded)
				lfn(*loaded)
				continue

			if default:
				debug("Loading %s with defaults %s.", options, default)
				lfn(*default)

	def save (self):
		"""
		Saves all options into the file.
		"""

		for options, lfn, sfn, default in self._handlers:
			vals = sfn()
			
			# map into list if necessairy
			if not hasattr(vals, "__iter__"):
				vals = [vals]
			debug("Saving %s with values %s", options, vals)

			for value, (option, section) in zip(vals, options):
				self.set(option, str(value), section)
		
		self._cfg.write()

	def set (self, key, value, section):
		try:
			self._cfg.add(key, value, section, with_blankline = False)
		except SectionNotFoundException:
			self._cfg.add_section(section)
			self._cfg.add(key, value, section, with_blankline = False)
	
	def get (self, key, section):
		try:
			return self._cfg.get(key, section)
		except KeyError:
			return None
	
	def get_boolean (self, key, section):
		try:
			return self._cfg.get_boolean(key, section)
		except KeyError:
			return None

	def check_version (self, vers):
		pass # do nothing atm