147 lines
4.6 KiB
Python
147 lines
4.6 KiB
Python
|
# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||
|
import ulib.base.i_need_py23
|
||
|
|
||
|
__all__ = ('SimpleStore',)
|
||
|
|
||
|
import os, re
|
||
|
from os import path
|
||
|
|
||
|
from ulib.base.uio import _s, _u
|
||
|
from ulib.base.lines import Lines
|
||
|
from ulib.base.paths import mkdirof
|
||
|
from ulib.base.tmpfiles import actemp, cltemp
|
||
|
from ulib.base.flock import rdopen, wropen
|
||
|
from base import *
|
||
|
from consts import *
|
||
|
from store import AbstractStore, UnsavedModificationError
|
||
|
|
||
|
LASTID = 'lastid'
|
||
|
|
||
|
class SimpleStore(AbstractStore):
|
||
|
GENERIC_PROPERTIES = AbstractStore.GENERIC_PROPERTIES + [LASTID]
|
||
|
|
||
|
def __init__(self, inf=None):
|
||
|
AbstractStore.__init__(self)
|
||
|
self.__reset()
|
||
|
if inf is not None: self.load(inf)
|
||
|
|
||
|
def __reset(self):
|
||
|
self._tasks = []
|
||
|
self._lastid = 0
|
||
|
self._tids = {}
|
||
|
|
||
|
_tasks, tasks, get_tasks = make_sprop('_tasks', None, setter=False, deleter=False)
|
||
|
_lastid, lastid, get_lastid, set_lastid, del_lastid = make_suprop('_lastid', 0)
|
||
|
|
||
|
_tids = None
|
||
|
def _nextid(self):
|
||
|
_u = self._uio.u
|
||
|
nextid = int(self._lastid) + 1
|
||
|
while self._tids.has_key(_u(nextid)):
|
||
|
nextid += 1
|
||
|
self._lastid = nextid
|
||
|
return nextid
|
||
|
|
||
|
def _ensure_tid(self, task):
|
||
|
if task._tid is None: task.tid = self._nextid()
|
||
|
|
||
|
def _task_attached(self, task, validate=False):
|
||
|
self._ensure_tid(task)
|
||
|
if not self._tids.has_key(task._tid):
|
||
|
self._tids[task._tid] = task
|
||
|
AbstractStore._task_attached(self, task, validate)
|
||
|
|
||
|
def remove(self, task):
|
||
|
if task not in self._tasks: return False
|
||
|
del self._tids[task._tid]
|
||
|
self._tasks.remove(task)
|
||
|
self._modified = True
|
||
|
return True
|
||
|
|
||
|
_fdn = None
|
||
|
_fd = None
|
||
|
_fn = None
|
||
|
|
||
|
def get_name(self):
|
||
|
u"""Retourner le nom de ce store
|
||
|
"""
|
||
|
return _u(self._fn)
|
||
|
name = property(get_name)
|
||
|
|
||
|
RE_SPROPS = re.compile(r'##\s+sprops:')
|
||
|
def load(self, infdn=None, force=False, **ignored):
|
||
|
if self.is_modified() and not force:
|
||
|
raise UnsavedModificationError
|
||
|
|
||
|
if infdn is None:
|
||
|
infdn = self._fdn
|
||
|
if infdn is None: raise ValueError("Source file is required")
|
||
|
else:
|
||
|
self._fdn = path.abspath(infdn)
|
||
|
self._fd, self._fn = path.split(self._fdn)
|
||
|
self.__reset()
|
||
|
self._valid = False
|
||
|
lines = Lines()
|
||
|
if path.exists(infdn):
|
||
|
lines.readlines(infdn, open_func=rdopen)
|
||
|
for line in lines:
|
||
|
if self.RE_SPROPS.match(line) is not None:
|
||
|
self.set_props(**self._line2props(line, False))
|
||
|
elif not line.strip() or line.startswith(u'#'):
|
||
|
# ignorer lignes vides et commençant par "#"
|
||
|
pass
|
||
|
else:
|
||
|
task = self._tf.build_task(**self._line2props(line))
|
||
|
self.tasks.append(task)
|
||
|
self._task_attached(task, True)
|
||
|
self._modified = False
|
||
|
self._valid = True
|
||
|
|
||
|
def __is_sprop(self, line):
|
||
|
return self.RE_SPROPS.match(line) is not None
|
||
|
|
||
|
def should_reload(self):
|
||
|
infdn = self._fdn
|
||
|
if infdn is None: return False
|
||
|
if not path.exists(infdn): return False
|
||
|
lines = Lines()
|
||
|
lines.readlines(infdn, open_func=rdopen, until=self.__is_sprop)
|
||
|
props = {}
|
||
|
for line in lines:
|
||
|
if self.RE_SPROPS.match(line) is not None:
|
||
|
props = self._line2props(line, False)
|
||
|
break
|
||
|
return self.serial != props.get(SERIAL, None)
|
||
|
|
||
|
ENCODING = u"""## -*- coding: %(encoding)s -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=%(encoding)s"""
|
||
|
SPROP = u"""## sprops:"""
|
||
|
|
||
|
def save(self, outfdn=None, force=False):
|
||
|
if not force and not self.is_modified(): return False
|
||
|
|
||
|
if outfdn is None: outfdn = self._fdn
|
||
|
if outfdn is None: raise ValueError("Destination file is required")
|
||
|
|
||
|
lines = self.get_lines(int(self.serial or 0) + 1)
|
||
|
|
||
|
outf = wropen(outfdn)
|
||
|
try:
|
||
|
tmpfdn = outfdn + '.tmp'
|
||
|
mkdirof(tmpfdn)
|
||
|
li = actemp(tmpfdn)
|
||
|
try:
|
||
|
lines.writelines(tmpfdn)
|
||
|
try:
|
||
|
os.rename(tmpfdn, outfdn)
|
||
|
except OSError:
|
||
|
os.remove(outfdn)
|
||
|
os.rename(tmpfdn, outfdn)
|
||
|
finally:
|
||
|
cltemp(li)
|
||
|
finally:
|
||
|
outf.close()
|
||
|
|
||
|
for task in self._tasks: task.modified = False
|
||
|
self._modified = False
|
||
|
return True
|