Add HMS subsystem. Does anyone know how to gracefully deal with remote git repo clone in subdir?

portnov [2008-06-07 17:47:55]
Add HMS subsystem. Does anyone know how to gracefully deal with remote git repo clone in subdir?
Filename
mgmt/hms/.gitignore
mgmt/hms/debug.py
mgmt/hms/generate.py
mgmt/hms/hooks.py
mgmt/hms/modules.py
mgmt/hms/modules/blocks.py
mgmt/hms/modules/node.py
mgmt/hms/modules/test1.py
mgmt/hms/modules/test2.py
mgmt/hms/modules/testblock.py
mgmt/hms/test.py
mgmt/hms/th1.py
mgmt/hms/themes.py
mgmt/hms/themes/default/theme.py
mgmt/models.py
diff --git a/mgmt/hms/.gitignore b/mgmt/hms/.gitignore
new file mode 100644
index 0000000..4e72520
--- /dev/null
+++ b/mgmt/hms/.gitignore
@@ -0,0 +1,3 @@
+.*.swp
+*.swp
+*.pyc
diff --git a/mgmt/hms/debug.py b/mgmt/hms/debug.py
new file mode 100644
index 0000000..11c39d1
--- /dev/null
+++ b/mgmt/hms/debug.py
@@ -0,0 +1,9 @@
+
+DEBUG = 0
+
+if DEBUG:
+  def debug(s):
+    print "| "+s
+else:
+  def debug(s):
+    pass
diff --git a/mgmt/hms/generate.py b/mgmt/hms/generate.py
new file mode 100644
index 0000000..fb45085
--- /dev/null
+++ b/mgmt/hms/generate.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+"""
+Support of generated content.
+You mark some function with @generates('some_type'). It must return an instance of Generated class.
+"""
+
+generated = dict()
+
+def generates(cls):
+  "Mark function that generates content of some class."
+  def decorator(func):
+    global generated
+    name = func.__name__
+    if cls in generated:
+      generated[cls].append(func)
+    else:
+      generated[cls] = [func]
+    return func
+  return decorator
+
+def generate(cls):
+  "Generate all content of given class."
+  r = []
+  for b in generated[cls]:
+    r.append(b())
+  return r
+
+class Generated(object):
+  name = ""
+  description = ""
+  def show(self):
+    return ""
+  def settings(self):
+    return
diff --git a/mgmt/hms/hooks.py b/mgmt/hms/hooks.py
new file mode 100755
index 0000000..f991423
--- /dev/null
+++ b/mgmt/hms/hooks.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+"""
+Each `hook' is actually event. You mark some function with @hook decorator, then call that function when you need it. Other modules can intercept that event, marking function with @intercept('hook_name') decorator. When you call function `hook_name()', all functions, marked with @intercept('hook_name'), will be called.
+"""
+
+from debug import *
+
+hooks = dict()
+
+def call_hooks(hook,*args):
+  "Call all functions, intercepting given hook."
+  global hooks
+  debug("Test <%s> in %s" % (hook,hooks))
+  if hook in hooks:
+    debug("Calling hooks for %s" % hook)
+    r = args
+    for h in hooks[hook]:
+      prev = r
+      debug("Calling %s (%s)" % (h,r))
+      r = h(*r)
+      if not r:
+        return prev
+    return r
+  else:
+    return args
+
+def hook(func):
+  "Mark given function as a hook."
+  global hooks
+  name = func.__name__
+  def wrapper(*args):
+    r = call_hooks(name,*args)
+    if type(r) in [str,unicode]:
+      return func(r)
+    else:
+      return func(*r)
+  wrapper.__name__ = name
+  return wrapper
+
+
+def intercept(hook):
+  "Intercept some hook."
+  def decorator(func):
+    global hooks
+    if hook in hooks:
+      hooks[hook].append(func)
+    else:
+      hooks[hook] = [func]
+    debug("Now hooks = %s" % hooks)
+    return func
+  return decorator
+
+if __name__ == "__main__":
+
+  @hook
+  def one(x,y):
+    print "Op One called: (%s,%s)" % (x,y)
+
+  @intercept('one')
+  def i1(x,y):
+    print "Intercepting one."
+    return (x,y+1)
+
+  @intercept('one')
+  def i2(x,y):
+    print "Intercepting one: %s,%s" % (x,y)
+    return x+3,y
+
+
+  print one(2,3)
+  print hooks
diff --git a/mgmt/hms/modules.py b/mgmt/hms/modules.py
new file mode 100644
index 0000000..495a4c9
--- /dev/null
+++ b/mgmt/hms/modules.py
@@ -0,0 +1,53 @@
+
+"""
+This module imports all mods from modules/ directory. Each module must be a *.py file of form:
+
+def init():
+  ... Here goes definitions.
+"""
+
+import os
+import os.path
+
+from hooks import *
+from themes import *
+from generate import *
+
+MODS_DIR = "modules"
+modules = {}
+exports = ['export', 'export_as', 'hook', 'intercept','themeable','theme',
+           'generates', 'generate', 'Generated']
+
+def export(func):
+  "Mark this function to export."
+  global exports
+  globals()[func.__name__] = func
+  exports.append(func.__name__)
+  return func
+
+def export_as(obj,name):
+  "Export some object"
+  global exports
+  globals()[name] = obj
+  exports.append(name)
+  print globals().keys()
+
+@hook
+def module_load(name):
+  global modules
+  global exports
+  mod = modules[name]
+  for n in exports:
+    setattr(mod,n,globals()[n])
+  modules[name].init()
+
+def init():
+  for name in modules:
+    module_load(name)
+
+for dirpath, dirs, files in os.walk(MODS_DIR):
+  for file in files:
+    if file[-3:] == ".py":
+      name = os.path.join(dirpath,file[:-3])
+      module = __import__(name)
+      modules[name] = module
diff --git a/mgmt/hms/modules/blocks.py b/mgmt/hms/modules/blocks.py
new file mode 100644
index 0000000..95732a6
--- /dev/null
+++ b/mgmt/hms/modules/blocks.py
@@ -0,0 +1,25 @@
+
+def init():
+
+  print "Blocks module loaded."
+
+  block = generates('block')
+  export_as(block,'block')
+
+  @themeable
+  def block(blk):
+    return """<div class='block'>
+    <h3>%s</h3>
+    <div class='content'>
+    %s
+    </div>
+    </div>""" % (blk.title,blk.content)
+
+  class Block(Generated):
+    name = "Block"
+    title = "<none>"
+    content = "<empty>"
+    def show(self):
+      return theme('block', self)
+
+  export_as(Block,'Block')
diff --git a/mgmt/hms/modules/node.py b/mgmt/hms/modules/node.py
new file mode 100644
index 0000000..ebea2b0
--- /dev/null
+++ b/mgmt/hms/modules/node.py
@@ -0,0 +1,19 @@
+
+def init():
+
+  class Node(object):
+    author=""
+    title = ""
+    content = ""
+    fields = {}
+
+  @themeable
+  def node(nd):
+    return """<div class='node'>
+    <h2>%s</h2>
+    <div class='content'>
+    %s
+    </div>
+    </div>""" % (nd.title, nd.content)
+
+  export_as(Node,"Node")
diff --git a/mgmt/hms/modules/test1.py b/mgmt/hms/modules/test1.py
new file mode 100644
index 0000000..dccef22
--- /dev/null
+++ b/mgmt/hms/modules/test1.py
@@ -0,0 +1,15 @@
+
+def init():
+  print "Module <Test> imported."
+
+  @intercept('do_something')
+  def func(s):
+    print "Intercepted."
+    return s
+
+  @hook
+  def my_hook():
+    print "Some event."
+
+
+  my_hook()
diff --git a/mgmt/hms/modules/test2.py b/mgmt/hms/modules/test2.py
new file mode 100644
index 0000000..f5d3524
--- /dev/null
+++ b/mgmt/hms/modules/test2.py
@@ -0,0 +1,7 @@
+
+def init():
+  print "Test 2 loaded"
+
+  @intercept('my_hook')
+  def on_hook():
+    print "<myhook> intercepted."
diff --git a/mgmt/hms/modules/testblock.py b/mgmt/hms/modules/testblock.py
new file mode 100644
index 0000000..be49e4f
--- /dev/null
+++ b/mgmt/hms/modules/testblock.py
@@ -0,0 +1,10 @@
+
+def init():
+
+  @block
+  def testblk():
+    b = Block()
+    b.name = "testblk"
+    b.title = "Test block"
+    b.content = "Content of test block."
+    return b
diff --git a/mgmt/hms/test.py b/mgmt/hms/test.py
new file mode 100755
index 0000000..8fbf658
--- /dev/null
+++ b/mgmt/hms/test.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import os.path
+
+import modules
+from hooks import *
+from themes import *
+from generate import generate
+modules.init()
+
+THEME = "default"
+
+@hook
+def do_something(s):
+  print "Doing something with",s
+
+
+@themeable
+def page(path):
+  return "Content for "+path
+
+print "All modules loaded."
+
+th= __import__(os.path.join("themes",THEME,"theme"))
+th.override = override
+th.init()
+
+print theme('page','/')
+
+for b in generate('block'):
+  print b.show()
diff --git a/mgmt/hms/th1.py b/mgmt/hms/th1.py
new file mode 100755
index 0000000..095473b
--- /dev/null
+++ b/mgmt/hms/th1.py
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+
+from themes import theme,override
+
+@override
+def Test(x,y):
+  return "Some vars: [%s, %s]" % (x,y)
+
+
+print theme('Test',2,3)
diff --git a/mgmt/hms/themes.py b/mgmt/hms/themes.py
new file mode 100644
index 0000000..8b642c8
--- /dev/null
+++ b/mgmt/hms/themes.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+themed = dict()
+
+def themeable(func):
+  global themed
+  name = func.__name__
+  themed[name] = func
+  def wrapper(*args,**kwargs):
+    return (themed[name])(*args,**kwargs)
+  wrapper.__name__ = name
+  return wrapper
+
+def override(func):
+  global themed
+  themed[func.__name__] = func
+  return func
+
+def theme(name,*args,**kwargs):
+  global themed
+  f = themed[name]
+  return f(*args,**kwargs)
+
+
+@themeable
+def Test(x,y):
+  return "<%s, %s>" % (x,y)
diff --git a/mgmt/hms/themes/default/theme.py b/mgmt/hms/themes/default/theme.py
new file mode 100644
index 0000000..1a8e10b
--- /dev/null
+++ b/mgmt/hms/themes/default/theme.py
@@ -0,0 +1,11 @@
+
+def init():
+  @override
+  def page(path):
+    return """<html>
+    <title>%s</title>
+    <body>
+    Some content.
+    </body>
+    </html>""" % path
+
diff --git a/mgmt/models.py b/mgmt/models.py
index 76fde06..f09f103 100644
--- a/mgmt/models.py
+++ b/mgmt/models.py
@@ -5,6 +5,8 @@ class Object(models.Model):
   name = models.CharField(max_length=64)
   text = models.TextField()
   created = models.DateTimeField()
+  def __unicode__(self):
+    return self.name

 class Project(Object):
   repo = models.CharField(max_length=64)
@@ -24,8 +26,6 @@ class Bug(Object):
   confirmed = models.ForeignKey(User,related_name='confirmed_bugs',null=True)
   responsible = models.ForeignKey(User,related_name='resp_bugs',null=True)
   status = models.IntegerField()
-  def __unicode__(self):
-    return self.name
   class Meta:
     ordering = ("-created",)
   class Admin:
@@ -34,8 +34,6 @@ class Bug(Object):
 class Document(Object):
   project = models.ForeignKey(Project)
   author = models.ForeignKey(User)
-  def __unicode__(self):
-    return self.name
   class Meta:
     ordering = ("-created",)
   class Admin:
ViewGit