Changeset - dcab422615ca
[Not reviewed]
default
0 5 0
drewp@bigasterisk.com - 12 years ago 2013-06-11 05:48:10
drewp@bigasterisk.com
working on local->global sub action. creation of new file in rdfdb is still a problem
Ignore-this: 28a0b0754f5fca6bef118f7e14758053
5 files changed with 125 insertions and 25 deletions:
0 comments (0 inline, 0 general)
bin/rdfdb
Show inline comments
 
@@ -196,6 +196,7 @@ class WatchedFiles(object):
 

	
 
    def dirChange(self, watch, path, mask):
 
        if mask & IN_CREATE:
 
            log.debug("%s created; consider adding a watch", path)
 
            self.watchFile(path.path)
 
            
 
    def watchFile(self, inFile):
 
@@ -238,8 +239,23 @@ class WatchedFiles(object):
 
        gf = GraphFile(self.notifier, inFile, ctx,
 
                       self.patch, self.getSubgraph)
 
        self.graphFiles[ctx] = gf
 
        log.info("%s do initial read", inFile)
 
        gf.reread()
 

	
 
    def aboutToPatch(self, ctx):
 
        """
 
        warn us that a patch is about to come to this context. it's more
 
        straightforward to create the new file now
 
        """
 
    
 
        g = self.getSubgraph(ctx)
 

	
 
        if ctx not in self.graphFiles:
 
            outFile = self.fileForUri(ctx)
 
            log.info("starting new file %r", outFile)
 
            self.graphFiles[ctx] = GraphFile(self.notifier, outFile, ctx,
 
                                             self.patch, self.getSubgraph)
 

	
 
    def dirtyFiles(self, ctxs):
 
        """mark dirty the files that we watch in these contexts.
 

	
 
@@ -251,12 +267,6 @@ class WatchedFiles(object):
 
        """
 
        for ctx in ctxs:
 
            g = self.getSubgraph(ctx)
 

	
 
            if ctx not in self.graphFiles:
 
                outFile = self.fileForUri(ctx)
 
                self.graphFiles[ctx] = GraphFile(self.notifier, outFile, ctx,
 
                                                 self.patch, self.getSubgraph)
 
            
 
            self.graphFiles[ctx].dirty(g)
 

	
 
    def uriFromFile(self, filename):
 
@@ -301,6 +311,9 @@ class Db(object):
 
        log.info("patching graph %s -%d +%d" % (
 
            ctx, len(p.delQuads), len(p.addQuads)))
 

	
 
        if hasattr(self, 'watchedFiles'): # not during startup
 
            self.watchedFiles.aboutToPatch(ctx)
 
        
 
        patchQuads(self.graph, p.delQuads, p.addQuads, perfect=True)
 
        senderUpdateUri = getattr(p, 'senderUpdateUri', None)
 

	
bin/subcomposer
Show inline comments
 
@@ -18,17 +18,17 @@ subcomposer
 
from __future__ import division, nested_scopes
 
import time, logging
 
from optparse import OptionParser
 
import logging
 
import logging, urllib
 
import Tkinter as tk
 
import louie as dispatcher
 
from twisted.internet import reactor, tksupport, task
 
from rdflib import URIRef, RDF
 
from rdflib import URIRef, RDF, RDFS, Literal
 

	
 
from run_local import log
 
log.setLevel(logging.DEBUG)
 

	
 
from light9.dmxchanedit import Levelbox
 
from light9 import dmxclient, Submaster, prof
 
from light9 import dmxclient, Submaster, prof, showconfig
 
from light9.Patch import get_channel_name
 
from light9.uihelpers import toplevelat
 
from light9.rdfdb.syncedgraph import SyncedGraph
 
@@ -71,7 +71,10 @@ class Subcomposer(tk.Frame):
 
        self.graph = graph
 
        self.session = session
 

	
 
        # this is a URIRef or Local
 
        # this is a URIRef or Local. Strangely, the Local case still
 
        # has a uri, which you can get from
 
        # self.currentSub.uri. Probably that should be on the Local
 
        # object too, or maybe Local should be a subclass of URIRef
 
        self._currentChoice = Observable(Local)
 

	
 
        # this is a PersistentSubmaster (even for local)
 
@@ -82,10 +85,69 @@ class Subcomposer(tk.Frame):
 
            log.info("change viewed sub to %s", val)
 
        self._currentChoice.subscribe(pc)
 

	
 
        EditChoice(self, self.graph, self._currentChoice).frame.pack(side='top')
 
        ec = self.editChoice = EditChoice(self, self.graph, self._currentChoice)
 
        ec.frame.pack(side='top')
 

	
 
        ec.subIcon.bind("<ButtonPress-1>", self.clickSubIcon)
 
        self.setupSubChoiceLinks()
 
        self.setupLevelboxUi()
 
        
 
    def clickSubIcon(self, *args):
 
        box = tk.Toplevel(self.editChoice.frame)
 
        box.wm_transient(self.editChoice.frame)
 
        tk.Label(box, text="Name this sub:").pack()
 
        e = tk.Entry(box)
 
        e.pack()
 
        b = tk.Button(box, text="Make global")
 
        b.pack()
 
        def clicked(*args):
 
            self.makeGlobal(newName=e.get())
 
            box.destroy()
 
            
 
        b.bind("<Button-1>", clicked)
 
        e.focus()
 
        
 
    def makeGlobal(self, newName):
 
        """promote our local submaster into a non-local, named one"""
 
        uri = self.currentSub().uri
 
        newUri = showconfig.showUri() + ("/sub/%s" %
 
                                         urllib.quote(newName, safe=''))
 
        with self.graph.currentState(
 
                tripleFilter=(uri, None, None)) as current:
 
            if (uri, RDF.type, L9['LocalSubmaster']) not in current:
 
                raise ValueError("%s is not a local submaster" % uri)
 
            if (newUri, None, None) in current:
 
                raise ValueError("new uri %s is in use" % newUri)
 
                
 
        # the local submaster was storing in ctx=self.session, but now
 
        # we want it to be in ctx=uri
 

	
 
        self.relocateSub(newUri, newName)
 

	
 
        # these are in separate patches for clarity as i'm debugging this
 
        self.graph.patch(Patch(addQuads=[
 
            (newUri, RDFS.label, Literal(newName), newUri),
 
        ], delQuads=[
 
            (newUri, RDF.type, L9['LocalSubmaster'], newUri),
 
                           ]))
 
        self.graph.patchObject(self.session,
 
                               self.session, L9['currentSub'], newUri)
 
        
 
    def relocateSub(self, newUri, newName):
 
        # maybe this goes in Submaster
 
        uri = self.currentSub().uri
 

	
 
        def repl(u):
 
            if u == uri:
 
                return newUri
 
            return u
 
        delQuads = self.currentSub().allQuads()
 
        addQuads = [(repl(s), p, repl(o), newUri) for s,p,o,c in delQuads]
 
        # patch can't span contexts yet
 
        self.graph.patch(Patch(addQuads=addQuads, delQuads=[]))
 
        #self.graph.patch(Patch(addQuads=[], delQuads=delQuads))
 
        
 
        
 
    def setupSubChoiceLinks(self):
 
        graph = self.graph
 
        def ann():
 
@@ -133,7 +195,9 @@ class Subcomposer(tk.Frame):
 
            self.sendupdate()
 
        
 
    def makeLocal(self):
 
        # todo: put a type on this, so subChanged can identify it right
 
        """
 
        change our display to a local submaster
 
        """
 
        # todo: where will these get stored, or are they local to this
 
        # subcomposer process and don't use PersistentSubmaster at all?
 

	
light9/Submaster.py
Show inline comments
 
@@ -187,6 +187,8 @@ class PersistentSubmaster(Submaster):
 
        typeStmt = (self.uri, RDF.type, L9['Submaster'])
 
        with self.graph.currentState(tripleFilter=typeStmt) as current:
 
            try:
 
                log.debug("submaster's type statement is in %r" %
 
                          list(current.contextsForStatement(typeStmt)))
 
                ctx = current.contextsForStatement(typeStmt)[0]
 
            except IndexError:
 
                log.info("declaring %s to be a submaster" % self.uri)
 
@@ -212,6 +214,17 @@ class PersistentSubmaster(Submaster):
 
        for lev in levs:
 
            self.graph.removeMappingNode(self._saveContext(), lev)
 

	
 
    def allQuads(self):
 
        """all the quads for this sub"""
 
        quads = []
 
        with self.graph.currentState() as current:
 
            quads.extend(current.quads((self.uri, None, None)))
 
            for s,p,o,c in quads:
 
                if p == L9['lightLevel']:
 
                    quads.extend(current.quads((o, None, None)))
 
        return quads
 

	
 

	
 
    def save(self):
 
        raise NotImplementedError("obsolete?")
 
        if self.temporary:
light9/editchoice.py
Show inline comments
 
@@ -7,7 +7,7 @@ class Local(object):
 
    manage. Set resourceObservable to Local to indicate that you're
 
    unlinked"""
 

	
 
class EditChoice(tk.Frame):
 
class EditChoice(object):
 
    """
 
    Observable <-> linker UI
 

	
light9/rdfdb/graphfile.py
Show inline comments
 
@@ -20,6 +20,8 @@ class GraphFile(object):
 
        self.path, self.uri = path, uri
 
        self.patch, self.getSubgraph = patch, getSubgraph
 

	
 
        self.lastWriteTimestamp = 0 # mtime from the last time _we_ wrote
 

	
 
        if not os.path.exists(path):
 
            # can't start notify until file exists
 
            try:
 
@@ -28,11 +30,12 @@ class GraphFile(object):
 
                pass
 
            f = open(path, "w")
 
            f.close()
 
            iolog.info("created %s", path)
 
            iolog.info("%s created", path)
 
            self.lastWriteTimestamp = os.path.getmtime(path)
 

	
 

	
 
        self.flushDelay = 2 # seconds until we have to call flush() when dirty
 
        self.writeCall = None # or DelayedCall
 
        self.lastWriteTimestamp = 0 # mtime from the last time _we_ wrote
 

	
 
        # emacs save comes in as IN_MOVE_SELF, maybe
 
        
 
@@ -49,19 +52,25 @@ class GraphFile(object):
 
      
 
    def notify(self, notifier, filepath, mask):
 
        maskNames = humanReadableMask(mask)
 
        if maskNames[0] in ['open', 'access', 'close_nowrite', 'attrib', 'delete_self']:
 
            log.debug("file %s changed, ignoring %s" % (filepath, maskNames))
 
        if maskNames[0] == 'delete_self':
 
            log.warn("%s delete_self event: need to dump the stmts from "
 
                     "this file", filepath)
 
            # this is happening surprisingly often, even to files that
 
            # are still there
 
            return
 
        if maskNames[0] in ['open', 'access', 'close_nowrite', 'attrib']:
 
            log.debug("%s %s event, ignoring" % (filepath, maskNames))
 
            return
 

	
 
        try:
 
            if filepath.getModificationTime() == self.lastWriteTimestamp:
 
                log.debug("file %s changed, but we did this write", filepath)
 
                log.debug("%s changed, but we did this write", filepath)
 
                return
 
        except OSError as e:
 
            log.error("watched file %s: %r" % (filepath, e))
 
            log.error("%s: %r" % (filepath, e))
 
            return
 
            
 
        log.info("file %s changed (%s)", filepath, maskNames)
 
        log.info("%s needs reread because of %s event", filepath, maskNames)
 
        try:
 
            self.reread()
 
        except Exception:
 
@@ -79,10 +88,10 @@ class GraphFile(object):
 
        except SyntaxError as e:
 
            print e
 
            traceback.print_exc()
 
            log.error("syntax error in %s" % self.path)
 
            log.error("%s syntax error", self.path)
 
            return
 
        except IOError as e:
 
            log.error("rereading %s: %r" % (self.uri, e))
 
            log.error("%s rereading %s: %r", self.path, self.uri, e)
 
            return
 

	
 
        old = inContext(old, self.uri)
 
@@ -90,11 +99,12 @@ class GraphFile(object):
 

	
 
        p = Patch.fromDiff(old, new)
 
        if p:
 
            log.debug("%s applying patch for changes in file", self.path)
 
            self.patch(p, dueToFileChange=True)
 

	
 
    def dirty(self, graph):
 
        """
 
        there are new contents for our file
 
        there are new contents to write to our file
 
        
 
        graph is the rdflib.Graph that contains the contents of the
 
        file. It is allowed to change. Note that dirty() will probably
 
@@ -108,7 +118,7 @@ class GraphFile(object):
 
        going towards a text file editor
 
        
 
        """
 
        log.info("%s dirty, %s stmt" % (self.uri, len(graph)))
 
        log.info("%s dirty, needs write", self.path)
 

	
 
        self.graphToWrite = graph
 
        if self.writeCall:
 
@@ -127,5 +137,5 @@ class GraphFile(object):
 
        f.close()
 
        self.lastWriteTimestamp = os.path.getmtime(tmpOut)
 
        os.rename(tmpOut, self.path)
 
        iolog.info("rewrote %s in %.1f ms", self.path, serializeTime * 1000)
 
        iolog.info("%s rewrote in %.1f ms", self.path, serializeTime * 1000)
 
        
0 comments (0 inline, 0 general)