Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Anderson <tony_anderson@usa.net>2009-08-20 05:57:36 (GMT)
committer Tony Anderson <tony_anderson@usa.net>2009-08-20 05:57:36 (GMT)
commitfc18bb8c4b5262e1a6a1b4483f4855c227b3912b (patch)
treef26bceb1093fdc0f314ec3808ba26bff5f3b9956
parentcc347df7be9fa906f8f9f431257edf8c48fdb626 (diff)
further developlent
-rw-r--r--datamanager.py384
-rwxr-xr-xicons/btncancel.pngbin0 -> 3684 bytes
-rwxr-xr-xicons/btngo.pngbin0 -> 1141 bytes
3 files changed, 310 insertions, 74 deletions
diff --git a/datamanager.py b/datamanager.py
index e6daf25..548b262 100644
--- a/datamanager.py
+++ b/datamanager.py
@@ -21,12 +21,15 @@
from sugar.activity import activity
from sugar.datastore import datastore
from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.alert import Alert
from sugar.graphics.menuitem import MenuItem
import os, sys
import subprocess
import gtk
from path import path
+from datetime import datetime
+from time import strftime
import urllib2
from BeautifulSoup import BeautifulSoup
@@ -35,24 +38,32 @@ ACTIVITYPATH = path(activity.get_bundle_path())
DATAPATH = path(activity.get_activity_root()) / "data"
WORKPATH = DATAPATH / 'work'
KEYPATH = ACTIVITYPATH / '.ssh'
-STOREPATH = path("/library/Datastore/")
-COMMONSPATH = path("/library/Commons/")
+STOREPATH = path("/library/Datastore")
+COMMONSPATH = path("/library/Commons")
+LOCALPATH = path("/home/olpc/.sugar/default/datastore/store")
+DATEFORMAT = "%Y-%m-%d %H:%M:%S"
-SERIALNUMBER = '/ofw/serial-number'
USAGETOOLBAR = 1
class DataManager(activity.Activity):
def __init__(self, handle):
+ print 'activity started'
+ global SERIALNUMBER
activity.Activity.__init__(self, handle)
- print 'activity initialized'
self.set_title("Datamanager")
f = open('/ofw/serial-number', 'r')
t = f.read()
- self.xoserial = t[:11]
+ f.close()
+ SERIALNUMBER = t[:11]
+ print 'serial-number', SERIALNUMBER
subprocess.call("mkdir -p " + WORKPATH, shell=True)
+ #set up alert
+ #self.alert = Alert()
+ #self.alert.props.title='Updating Datastore'
+ #self.alert.props.msg='Please be patient - updating store'
#Create the usage toolbar
- self.usageTB = UsageToolbar(self.xoserial)
+ self.usageTB = UsageToolbar(self)
#Create the standard activity toolbox
toolbox = activity.ActivityToolbox(self)
toolbox.add_toolbar("Usage", self.usageTB)
@@ -60,18 +71,154 @@ class DataManager(activity.Activity):
self.set_toolbox(toolbox)
toolbox.show()
self.viewer = Listview()
- self.child.pack_start(self.viewer, True, True, 0)
- treeView = self.viewer.get_treeView()
- treeView.set_model(self.viewer.create_model(self.usageTB, self.xoserial))
+ #treeView = self.viewer.get_treeView()
+ #treeView.set_model(self.viewer.create_model(self.usageTB))
+ #set up main screen
+ self.main_screen = gtk.VBox()
+ #self.main_screen.pack_start(self.alert, False, False, 0)
+ self.main_screen.pack_start(self.viewer, True, True, 0)
+ self.set_canvas(self.main_screen)
+ print 'canvas set'
self.show_all()
+ self.viewer.set_label('canvas set')
+ #self.alert.hide()
+
+ def start_cb(self, widget):
+ treeView = self.viewer.get_treeView()
+ treeView.set_model(self.viewer.create_model(self.usageTB))
+
+ def close_cb(self, widget):
+ #debug switch to cancel uploads
+ #return True
+ global SERIALNUMBER
+ global store
+ global online
+ action_request = 5
+ status = 4
+ if not online:
+ return True
+ self.viewer.set_label('closing - online')
+ self.logger('')
+ self.logger('can_close_online')
+ print 'can_close online'
+ #now the real work begins
+ #self.alert.show()
+ self.logger('showing alert')
+ remove_list = []
+ for row in store:
+ self.viewer.set_label('reviewing status: ' + row[0])
+ #action_request = 0: no action
+ #action_request = +2: download
+ #action_request = +1: upload
+ #action_request = -1: remove
+ if row[status] == 'White':
+ row[action_request] = -1
+ if row[status] == 'Red':
+ row[action_request] = +1
+ if row[action_request] < 0:
+ remove_list.append(row[0])
+ if row[action_request] == 1:
+ #upload it
+ self.viewer.set_label('reviewing status: ' + row[0] + ' upload')
+ self.logger('upload' + row[0] + '.metadata')
+ mname = row[0] + '.metadata'
+ fname = row[0]
+ src = LOCALPATH / mname
+ pfx = SERIALNUMBER + '@schoolserver:'
+ dst = STOREPATH / SERIALNUMBER
+ cmd = 'scp ' + src + ' ' + pfx + dst
+ print 'metadata upload', cmd
+ self.logger('call scp')
+ subprocess.call(cmd, shell=True)
+ self.logger('metadata uploaded')
+ src = LOCALPATH / fname
+ cmd = 'scp ' + src + ' ' + pfx + dst
+ if src.exists():
+ print 'file upload', cmd
+ subprocess.call(cmd, shell=True)
+ self.logger('file uploaded')
+ else:
+ print 'src path does not exist', src
+ if row[action_request] > 1 and row[status] == "light green":
+ #download from schoolserver
+ self.viewer.set_label('reviewing status: ' + row[0] + ' download')
+ self.logger('download ' + row[0] )
+ mname = row[0] + '.metadata'
+ fname = row[0]
+ dst = LOCALPATH
+ pfx = SERIALNUMBER + '@schoolserver:'
+ src = STOREPATH / SERIALNUMBER / mname
+ cmd = 'scp ' + pfx + src + ' ' + dst
+ print 'metadata download', cmd
+ subprocess.call(cmd, shell=True)
+ self.logger('metadata downloaded')
+ src = STOREPATH / SERIALNUMBER / fname
+ cmd = 'scp ' + pfx + src + ' ' + dst
+ subprocess.call(cmd, shell=True)
+ self.logger('file downloaded')
+ if row[action_request] > 1 and row[status] == "cyan":
+ #download from Commons
+ self.viewer.set_label('reviewing status: ' + row[0] + ' download')
+ self.logger('download from Commons: ' + row[0])
+ #if mime_type is activity - install it
+ mname = row[0] + '.metadata'
+ fname = row[0]
+ dst = LOCALPATH
+ pfx = SERIALNUMBER + '@schoolserver:'
+ src = COMMONSPATH / SERIALNUMBER / mname
+ cmd = 'scp ' + pfx + src + ' ' + dst
+ print 'metadata download', cmd
+ subprocess.call(cmd, shell=True)
+ src = COMMONSPATH / SERIALNUMBER / fname
+ cmd = 'scp ' + pfx + src + ' ' + dst
+ subprocess.call(cmd, shell=True)
+ #now remove
+ self.logger('now remove')
+ try:
+ ds_objects,num_objects = datastore.find(dict())
+ except:
+ print 'datastore.find failed', sys.exc_info()[0]
+ num_objects = 0
+ #self.logger(str(num_objects) + ', ' + str(len(remove_list)))
+ self.logger('datastore.find complete')
+ print 'remove_list', len(remove_list), remove_list
+ for i in xrange(0, num_objects, 1):
+ ds_objects[i].destroy()
+ obj = ds_objects[i].object_id
+ self.viewer.set_label('checking files ' + obj)
+ if str(obj) in remove_list:
+ datastore.delete(obj)
+ self.logger(obj + ' deleted')
+ txt = 'deleted ' + obj
+ self.viewer.set_label('checking files ' + obj + ' deleted')
+ #self.remove_alert(self.alert)
+ self.logger('done')
+ self.viewer.set_label('done')
+ return
+
+ def logger(self, log):
+ l = ''
+ logpth = path('/tmp/log')
+ if logpth.exists():
+ f = open(logpth,'r')
+ l = f.read()
+ f.close()
+ l = l + log + '\n'
+ if len(log) == 0:
+ l = ''
+ f = open(logpth, 'w')
+ f.write(l)
+ f.close()
# based on PyGTK tutorial by jan bodnar, zetcode.com, February 2009
class Listview(gtk.VBox):
def __init__(self):
+ global online
print 'Listview init'
gtk.VBox.__init__(self)
self.connect("destroy", gtk.main_quit)
self.online = False
+ online = False
sw = gtk.ScrolledWindow()
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
@@ -98,49 +245,103 @@ class Listview(gtk.VBox):
def get_treeView(self):
return self.treeView
- def create_model(self, tb, xoserial):
+ def set_label(self, txt):
+ self.label.set_text(txt)
+
+ def create_model(self, tb):
global online
+ global store
+ global SERIALNUMBER
+ action_request = 5
+ status = 4
#object is object_id, str = title, str = mime_type or activity,
- #str is color of col 1, str is source color of col 0
- store = gtk.ListStore(object, str, str, str, str)
+ #str is color of col 1 (status), str is source color of col 0 (source)
+ store = gtk.ListStore(object, str, str, str, str, int)
#let's display objects from the schoolserver
#temp for testing
url = "http://schoolserver/Commons/"
- response = urllib2.urlopen(url)
+ try:
+ response = urllib2.urlopen(url)
+ except:
+ response = None
if response:
self.online = True
- self.addentries(store, response, "Blue", xoserial)
- url = "http://schoolserver/Datastore/" + xoserial
- response = urllib2.urlopen(url)
+ online = True
+ self.addentries(store, response, "cyan")
+ url = "http://schoolserver/Datastore/" + SERIALNUMBER
+ try:
+ response = urllib2.urlopen(url)
+ except:
+ response = None
if response:
- print 'response'
self.online = True
- self.addentries(store, response, "Green", xoserial)
+ online = True
+ self.addentries(store, response, "light green")
if self.online:
print 'online'
else:
tb.item2.remove(tb.fuelguage2)
tb.lbl2.set_text("not connected")
#objects from the local datastore
- results, count = datastore.find(dict())
- print 'number of datastore items', count
- for f in results:
- obj = datastore.get(f.object_id)
- f.destroy()
- if len(obj.get_file_path()) > 0:
- color1 = "Red"
- color2 = "Green"
- else:
- color1 = "White"
- color2 = "Green"
- itm = obj.metadata['mime_type']
- if len(itm) <= 0:
- itm = obj.metadata['activity']
- store.append([obj, obj.metadata['title'], obj.metadata['mime_type'], color1, color2 ])
+ #new strategy - get directly - not through datastore
+ #we want to compare items in store with items in LOCALPATH
+ #if there is a match - set status
+ storelist = []
+ for row in store:
+ storelist.append(row[0])
+ fn = row[0] + '.metadata'
+ pth = LOCALPATH / fn
+ if pth.exists():
+ if row[status] == 'cyan':
+ row[status] = 'Blue'
+ else:
+ row[status] = 'Green'
+ for f in LOCALPATH.files():
+ #is this file already on the schoolserver?
+ if f.namebase not in storelist and f.ext == '.metadata':
+ m = open(f, 'r')
+ metadata = eval(m.read())
+ m.close()
+ obj = f.namebase
+ try:
+ title = metadata['title']
+ except:
+ try:
+ title = metadata['title:text']
+ except:
+ title = 'not given'
+ try:
+ mime_type = metadata['mime_type']
+ except:
+ mime_type = ''
+ if len(mime_type) <= 0:
+ try:
+ mime_type = metadata['activity']
+ except:
+ mime_type = 'not given'
+ try:
+ mtime = metadata['mtime']
+ except:
+ mtime = ""
+ #tm = datetime.fromtimestamp(mtime)
+ #date = tm.strftime(DATEFORMAT)
+ temp = mtime.replace('T',' ')
+ pos = mtime.find('.')
+ date = temp[:pos]
+ fpath = LOCALPATH / obj
+ if fpath.exists():
+ color = 'Red'
+ else:
+ color = 'White'
+ store.append([obj, title, mime_type, date, color, 0])
+ store.set_sort_column_id(3, gtk.SORT_DESCENDING)
print 'return store'
return store
- def addentries(self, store, response, color, xoserial):
+ def addentries(self, store, response, source):
+ global SERIALNUMBER
+ print 'addentries:', SERIALNUMBER, source
+ treeView = self.get_treeView()
soup = BeautifulSoup(response)
entry_candidates = soup.findAll('a')
for entry in entry_candidates:
@@ -148,57 +349,67 @@ class Listview(gtk.VBox):
pos = t.find('metadata')
if pos > 0:
pos2 = t.find('href=')
- print color, t[pos2+6:pos+8]
obj = t[pos2+6:pos-1]
fn = t[pos2+6:pos+8]
- if color == "green":
+ if source == "blue":
pth = COMMONSPATH / fn
else:
- pth = STOREPATH / xoserial / fn
- cmd = "sftp " + xoserial + "@schoolserver: " + pth
- print 'get metadata:', cmd
- subprocess.call(cmd, shell=True, cwd=WORKPATH)
+ pth = STOREPATH / SERIALNUMBER / fn
+ cmd = "scp " + SERIALNUMBER + "@schoolserver:" + pth
+ cmd = cmd + " " + WORKPATH
+ subprocess.call(cmd, shell=True)
pth = WORKPATH / fn
f = open(pth, 'r')
t = f.read()
f.close()
- metadata = dict(t)
- title = metadata['title']
- activity = metadata['activity']
+ subprocess.call("rm -rf pth", shell=True)
+ metadata = eval(t)
+ try:
+ title = metadata['title']
+ except:
+ try:
+ title = metadata['title:text']
+ except:
+ title = ''
mime_type = metadata['mime_type']
- store.append([obj, title, mime_type, color, color])
- print 'new row', store[len(store) - 1]
+ mtime = metadata['mtime'].replace('T',' ')
+ pos = mtime.find('.')
+ date = mtime[:pos]
+ store.append([obj, title, mime_type, date, source, 0])
+ treeView.set_model(store)
def create_columns(self, treeView):
+ status = 4
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Title", rendererText, text=1)
- column.add_attribute(rendererText, "cell-background", 3)
- column.set_sort_column_id(0)
+ column.add_attribute(rendererText, "cell-background", status)
+ column.set_sort_column_id(1)
treeView.append_column(column)
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Mime_type", rendererText, text=2)
- column.set_sort_column_id(1)
+ column.set_sort_column_id(2)
+ treeView.append_column(column)
+
+ rendererText = gtk.CellRendererText()
+ column = gtk.TreeViewColumn("Date", rendererText, text=3)
+ column.set_sort_column_id(3)
treeView.append_column(column)
def on_activated(self, widget, row, col):
+ #what we really want to do
+ #is define a request to upload/remove/download an entry
+ print 'on_activated', widget, row, col
model = widget.get_model()
- model[row][3] = "cyan"
obj = model[row][0]
- pth = obj.get_file_path()
- print 'pth', pth
- if len(pth) > 0:
- f = open(pth,'r')
- text = f.read()
- f.close()
- tpllist = []
- metakeys = obj.metadata.keys()
- for metakey in metakeys:
- metavalue = obj.metadata[metakey]
- tpllist.append((metakey, metavalue))
- metadata = dict(tpllist)
+ fn = obj + '.metadata'
+ pth = LOCALPATH / fn
+ print 'on_activated:', pth
+ f = open(pth,'r')
+ metadata = eval(f.read())
+ f.close()
tstr = ""
for k, v in metadata.iteritems():
@@ -208,14 +419,15 @@ class Listview(gtk.VBox):
except:
tstr = tstr + k + ':' + "" + '\n'
self.label.set_text(tstr)
+ print 'on_activated', tstr
class UsageToolbar(gtk.Toolbar):
- def __init__(self, xoserial):
-
+ def __init__(self, activity):
+ global SERIALNUMBER
gtk.Toolbar.__init__(self)
- self.lbl1 = gtk.Label("XO")
+ self.lbl1 = gtk.Label("XO ")
self.lbl1.show()
self.item0 = gtk.ToolItem()
self.item0.add(self.lbl1)
@@ -223,14 +435,28 @@ class UsageToolbar(gtk.Toolbar):
self.fuelguage1 = gtk.ProgressBar(adjustment=None)
style = self.fuelguage1.get_style().copy()
- style.bg[gtk.STATE_NORMAL] = gtk.gdk.color_parse('Blue')
+ style.bg[gtk.STATE_NORMAL] = gtk.gdk.color_parse('White')
style.bg[gtk.STATE_PRELIGHT] = gtk.gdk.color_parse('Red')
self.fuelguage1.set_style(style)
- cmd = 'df -h /home/olpc/.sugar/default/datastore'
+ cmd = 'du -h /home/olpc/.sugar/default/datastore > /tmp/rslt'
#need way to return stdout to get rslt
- #subprocess.call(cmd, shell=True)
- rslt = 0.69
- self.fuelguage1.set_fraction(rslt)
+ subprocess.call(cmd, shell=True)
+ f = open('/tmp/rslt','r')
+ storesize = f.read()
+ f.close()
+ print 'du datastore', len(storesize), storesize
+ cmd = 'df -h > /tmp/rslt1'
+ subprocess.call(cmd, shell=True)
+ f = open('/tmp/rslt1', 'r')
+ t = f.read()
+ f.close()
+ print 'df', len(t), t
+ totalsize = t.split('\n')
+ t1 = totalsize[1]
+ pos = t1.find('%')
+ rslt = t1[pos-4:pos].strip()
+ print 'rslt', float(rslt) * .01
+ self.fuelguage1.set_fraction(float(rslt) * .01)
self.fuelguage1.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
self.fuelguage1.show()
self.item1 = gtk.ToolItem()
@@ -241,7 +467,7 @@ class UsageToolbar(gtk.Toolbar):
self.spacer.set_expand(True)
self.insert(self.spacer, -1)
- self.lbl2 = gtk.Label("schoolserver")
+ self.lbl2 = gtk.Label("Schoolserver ")
self.lbl2.show()
self.item3 = gtk.ToolItem()
self.item3.add(self.lbl2)
@@ -249,17 +475,27 @@ class UsageToolbar(gtk.Toolbar):
self.fuelguage2 = gtk.ProgressBar(adjustment=None)
style = self.fuelguage2.get_style().copy()
- style.bg[gtk.STATE_NORMAL] = gtk.gdk.color_parse('Green')
+ style.bg[gtk.STATE_NORMAL] = gtk.gdk.color_parse('White')
style.bg[gtk.STATE_PRELIGHT] = gtk.gdk.color_parse('Red')
self.fuelguage2.set_style(style)
#need a way to know if schoolserver not online
#need a way to return rslt from stdout
- cmd = "ssh -i " + KEYPATH + xoserial + "@schoolserver "
- cmd = cmd + "du -h /library/datastore/" + xoserial
+ cmd = "ssh -i " + KEYPATH + SERIALNUMBER + "@schoolserver "
+ cmd = cmd + "du -h /library/datastore/" + SERIALNUMBER
#subprocess.call(cmd, shell=True)
- rslt = 0.01
+ rslt = 0.1
self.fuelguage2.set_fraction(rslt)
self.fuelguage2.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
self.item2 = gtk.ToolItem()
self.item2.add(self.fuelguage2)
self.insert(self.item2, -1)
+
+ self.startbtn = ToolButton('btngo')
+ self.startbtn.connect('clicked', activity.start_cb)
+ self.startbtn.show()
+ self.insert(self.startbtn, -1)
+
+ self.closebtn = ToolButton("btncancel")
+ self.closebtn.connect('clicked', activity.close_cb)
+ self.closebtn.show()
+ self.insert(self.closebtn, -1)
diff --git a/icons/btncancel.png b/icons/btncancel.png
new file mode 100755
index 0000000..fb13ad5
--- /dev/null
+++ b/icons/btncancel.png
Binary files differ
diff --git a/icons/btngo.png b/icons/btngo.png
new file mode 100755
index 0000000..b67609b
--- /dev/null
+++ b/icons/btngo.png
Binary files differ