From 375a030d6a984383643afab2ad33289ff4f35a74 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sun, 12 May 2013 04:09:47 +0200 Subject: [PATCH] Added basic profile handling. --- manga/profile.py | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 manga/profile.py diff --git a/manga/profile.py b/manga/profile.py new file mode 100644 index 0000000..2a82df4 --- /dev/null +++ b/manga/profile.py @@ -0,0 +1,191 @@ +import os +pj = os.path.join + +home = os.getenv("HOME") +if home is None or not os.path.isdir(home): + raise Exception("Could not find home directory for profile keeping") +basedir = pj(home, ".manga", "profiles") + +def openwdir(nm, mode="r"): + if os.path.exists(nm): + return open(nm, mode) + if mode != "r": + d = os.path.dirname(nm) + if not os.path.isdir(d): + os.makedirs(d) + return open(nm, mode) + +def splitline(line): + def bsq(c): + if c == "\\": return "\\" + elif c == '"': return '"' + elif c == " ": return " " + elif c == "n": return "\n" + else: return "" + ret = [] + p = 0 + buf = "" + a = False + while p < len(line): + c = line[p] + if c.isspace(): + p += 1 + else: + while p < len(line): + c = line[p] + p += 1 + if c == '"': + a = True + while p < len(line): + c = line[p] + p += 1 + if c == '"': + break + elif c == "\\" and p < len(line): + buf += bsq(line[p]) + p += 1 + else: + buf += c + elif c.isspace(): + ret.append(buf) + buf = "" + break + elif c == "\\" and p < len(line): + buf += bsq(line[p]) + p += 1 + else: + buf += c + if a or buf != "": + ret.append(buf) + return ret + +def consline(*words): + buf = "" + for w in words: + if any((c == "\\" or c == '"' or c == "\n" for c in w)): + wb = "" + for c in w: + if c == "\\": wb += "\\\\" + elif c == '"': wb += '\\"' + elif c == "\n": wb += "\\n" + else: wb += c + w = wb + if w == "" or any((c.isspace() for c in w)): + w = '"' + w + '"' + if buf != "": + buf += " " + buf += w + return buf + +class manga(object): + def __init__(self, profile, libnm, id, path): + self.profile = profile + self.libnm = libnm + self.id = id + self.path = path + self.props = self.loadprops() + + def loadprops(self): + ret = {} + with openwdir(self.path) as f: + for line in f: + words = splitline(line) + if len(words) < 1: continue + if words[0] == "set" and len(words) > 2: + ret[words[1]] = words[2] + elif words[0] == "lset" and len(words) > 1: + ret[words[1]] = words[2:] + return ret + + def prop(self, key, default=KeyError): + if key not in self.props: + if default is KeyError: + raise KeyError(key) + return default + return self.props[key] + + def setprop(self, key, val): + self.props[key] = val + + def saveprops(self): + with openwdir(self.path, "w") as f: + for key, val in self.props.iteritems(): + if isinstance(val, str): + f.write(consline("set", key, val) + "\n") + else: + f.write(consline("lset", key, *val) + "\n") + + def open(self): + import lib + return lib.findlib(self.libnm).byid(self.id) + +class profile(object): + def __init__(self, dir): + self.dir = dir + self.name = None + + def getmapping(self): + seq = 0 + ret = {} + if os.path.exists(pj(self.dir, "map")): + with openwdir(pj(self.dir, "map")) as f: + for ln in f: + words = splitline(ln) + if len(words) < 1: + continue + if words[0] == "seq" and len(words) > 1: + try: + seq = int(words[1]) + except ValueError: + pass + elif words[0] == "manga" and len(words) > 3: + try: + ret[words[1], words[2]] = int(words[3]) + except ValueError: + pass + return seq, ret + + def savemapping(self, seq, m): + with openwdir(pj(self.dir, "map"), "w") as f: + f.write(consline("seq", str(seq)) + "\n") + for (libnm, id), num in m.iteritems(): + f.write(consline("manga", libnm, id, str(num)) + "\n") + + def getmanga(self, libnm, id, creat=False): + seq, m = self.getmapping() + if (libnm, id) in m: + return manga(self, libnm, id, pj(self.dir, "%i.manga" % m[(libnm, id)])) + if not creat: + raise KeyError("no such manga: (%s, %s)" % (libnm, id)) + while True: + try: + fp = openwdir(pj(self.dir, "%i.manga" % seq), "wx") + except IOError: + seq += 1 + else: + break + fp.close() + m[(libnm, id)] = seq + self.savemapping(seq, m) + return manga(self, libnm, id, pj(self.dir, "%i.manga" % seq)) + + def setlast(self): + if self.name is None: + raise ValueError("profile at " + self.dir + " has no name") + with openwdir(pj(basedir, "last"), "w") as f: + f.write(self.name + "\n") + + @classmethod + def byname(cls, name): + if not name or name == "last" or name[0] == '.': + raise KeyError("invalid profile name: " + name) + ret = cls(pj(basedir, name)) + ret.name = name + return ret + + @classmethod + def last(cls): + if not os.path.exists(pj(basedir, "last")): + raise KeyError("there is no last used profile") + with open(pj(basedir, "last")) as f: + return cls.byname(f.readline().strip()) -- 2.11.0