[Sugar-devel] journal backup

Esteban Arias earias at plan.ceibal.edu.uy
Fri May 21 10:43:11 EDT 2010


Hi,

I attach patch and the script process (copy to /usr/bin)


---
 src/jarabe/journal/backup.py          |  231
+++++++++++++++++++++++++++++++++
 src/jarabe/model/processmanagement.py |   84 ++++++++++++
 2 files changed, 315 insertions(+), 0 deletions(-)
 create mode 100755 src/jarabe/journal/backup.py
 create mode 100644 src/jarabe/model/processmanagement.py

diff --git a/src/jarabe/journal/backup.py b/src/jarabe/journal/backup.py
new file mode 100755
index 0000000..f509f2c
--- /dev/null
+++ b/src/jarabe/journal/backup.py
@@ -0,0 +1,231 @@
+#!/usr/bin/env python
+# Journal - Backup
+# Copyright (C) 2010 Plan Ceibal
+#
+# Author: Esteban Arias <earias at plan.ceibal.edu.uy>
+# Contact information: comunidad at plan.ceibal.edu.uy
+# Plan Ceibal http://www.ceibal.edu.uy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import gtk
+import gobject
+import gconf
+import logging
+
+from gettext import gettext as _
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.model.processmanagement import ProcessManagement
+
+PATH_BACKUP = '/usr/bin/sugar-journal-backup'
+PATH_RESTORE = '/usr/bin/sugar-journal-restore'
+
+class Backup(gtk.Window):
+
+    __gtype_name__ = 'SugarJournalBackup'
+
+    def __init__(self, type_ps, mount_path):
+
+        self._type_ps = type_ps
+        self._mount_path = mount_path
+
+        if self._isValidType(self._type_ps):
+            if ((not self._mount_path == "") and (not self._mount_path ==
None)):
+                self._progressBarHandler = None
+
+                gtk.Window.__init__(self)
+
+                self.set_border_width(style.LINE_WIDTH)
+                offset = style.GRID_CELL_SIZE
+                width = gtk.gdk.screen_width() - offset * 2
+                height = gtk.gdk.screen_height() - offset * 2
+                self.set_size_request(width, height)
+                self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+                self.set_decorated(False)
+                self.set_resizable(False)
+                self.set_modal(True)
+
+                self._main_view = gtk.EventBox()
+                self._vbox = gtk.VBox()
+                self._vbox.set_spacing(style.DEFAULT_SPACING)
+                self._vbox.set_border_width(style.GRID_CELL_SIZE)
+                self._main_view.modify_bg(gtk.STATE_NORMAL,
+
style.COLOR_BLACK.get_gdk_color())
+                self._main_view.add(self._vbox)
+                self._vbox.show()
+
+                client = gconf.client_get_default()
+                color =
XoColor(client.get_string('/desktop/sugar/user/color'))
+
+                icon = Icon(icon_name='activity-journal',
+                            pixel_size=style.XLARGE_ICON_SIZE,
+                            xo_color=color)
+                self._vbox.pack_start(icon, False)
+                icon.show()
+
+                self._title = gtk.Label()
+                self._title.modify_fg(gtk.STATE_NORMAL,
+                                      style.COLOR_WHITE.get_gdk_color())
+                self._title.set_markup('<b>%s</b>' % _(self._type_ps))
+                self._vbox.pack_start(self._title, False)
+                self._title.show()
+
+                if self._type_ps == 'backup':
+                    lbl_txt = "Close all activities and do not remove the
external device during the process. \n\n"+\
+                              "To make the backup of the Journal, a restart
is required. \n\n"+\
+                              "The backup can only be restore from this
computer " + self._get_serial_number()
+                elif self._type_ps == 'restore':
+                    lbl_txt = "The content you restore will overwrite the
current contents of the Journal. \n\n"+\
+                              "Do not remove the external device during the
process. \n\n"+\
+                              "To implement the restoration of the Journal,
a restart is required. \n\n"+\
+                              "It will restore the backup done for this
computer " + self._get_serial_number()
+
+                self._message = gtk.Label(_(lbl_txt))
+                self._message.modify_fg(gtk.STATE_NORMAL,
+                                      style.COLOR_WHITE.get_gdk_color())
+                self._vbox.pack_start(self._message, True)
+                self._message.show()
+
+
+                vbox = gtk.VBox(False, 5)
+                vbox.show()
+                hbox = gtk.HBox(True, 3)
+                hbox.show()
+
+                valign = gtk.Alignment(0, 1, 0, 0)
+                valign.show()
+                vbox.pack_start(valign)
+
+                self._accept = gtk.Button()
+                self._accept.set_label(_('Accept'))
+                self._accept.show()
+                self._accept.connect('clicked', self.__accept_cb)
+
+                self._show_journal = gtk.Button()
+                self._show_journal.set_label(_('Close'))
+                self._show_journal.show()
+                self._show_journal.connect('clicked',
self.__show_journal_cb)
+
+                self._restart = gtk.Button()
+                self._restart.set_label(_('Restart'))
+                self._restart.hide()
+                self._restart.connect('clicked', self.__restart_cb)
+
+                hbox.add(self._accept)
+                hbox.add(self._show_journal)
+                hbox.add(self._restart)
+
+                halign = gtk.Alignment(1, 0, 0, 0)
+                halign.show()
+                halign.add(hbox)
+
+                vbox.pack_start(halign, False, False, 3)
+
+                self._vbox.add(vbox)
+
+
+                self.add(self._main_view)
+                self._main_view.show()
+
+                self.connect("realize", self.__realize_cb)
+
+                self._process_management = ProcessManagement()
+
self._process_management.connect('process-management-running',
self._set_update_log)
+
self._process_management.connect('process-management-started',
self._set_status_started)
+
self._process_management.connect('process-management-finished',
self._set_status_finished)
+
self._process_management.connect('process-management-failed',
self._set_status_failed)
+
+    def __realize_cb(self, widget):
+        self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+        self.window.set_accept_focus(True)
+
+    def __show_journal_cb(self, button):
+        self.destroy()
+
+    def __accept_cb(self, *args):
+        if ((not self._mount_path == "") and (not self._mount_path ==
None)):
+            if self._isValidType(self._type_ps):
+                if self._type_ps == 'backup':
+                    self._process_management.do_process([PATH_BACKUP,
self._mount_path, self._get_serial_number()])
+                elif self._type_ps == 'restore':
+                    self._process_management.do_process([PATH_RESTORE,
self._mount_path, self._get_serial_number()])
+
+    def _set_status_started(self, model, data=None):
+        self._message.set_text(_("Is running, Please wait"))
+        self._accept.hide()
+        self._show_journal.hide()
+        self._showProgress()
+
+    def _set_update_log(self, model, data):
+        pass
+
+    def _set_status_finished(self, model, data=None):
+        pass
+
+    def _set_status_failed(self, model, data=None):
+        logging.error(data)
+        self._showMsgError(data)
+
+    def __restart_cb(self, *args):
+        os.system('pkill -f -x "python /usr/bin/sugar-session"')
+
+    def _showProgress(self):
+        self._progress_bar = gtk.ProgressBar(adjustment=None)
+        self._progress_bar.set_fraction(0.0)
+        self._progress_bar.show()
+        self._vbox.add(self._progress_bar)
+        if (self._progressBarHandler == None):
+            self._progressBarHandler = gobject.timeout_add(1000,
self._timerProgressBar)
+
+    def _timerProgressBar(self):
+        self._progress_bar.pulse()
+        return True
+
+    def _showMsgError(self, msg):
+        self._title.set_markup('<b>%s</b>' % _("Error"))
+        self._message.set_text(msg)
+        self._restart.show()
+        self._accept.hide()
+        self._progress_bar.hide()
+
+    def _isValidType(self, type_ps):
+        return (type_ps == 'backup') | (type_ps == 'restore')
+
+    def _get_serial_number(self):
+        serial_no = self._read_file('/ofw/serial-number')
+        if serial_no is None:
+            serial_no = self._get_nick()
+        return serial_no
+
+    def _read_file(self, path):
+        if os.access(path, os.R_OK) == 0:
+            return None
+
+        fd = open(path, 'r')
+        value = fd.read()
+        fd.close()
+        if value:
+            value = value.strip('\n')
+            return value
+        else:
+            logging.error('No information in file or directory: %s' % path)
+            return None
+
+    def _get_nick(self):
+        client = gconf.client_get_default()
+        return client.get_string("/desktop/sugar/user/nick")
diff --git a/src/jarabe/model/processmanagement.py
b/src/jarabe/model/processmanagement.py
new file mode 100644
index 0000000..102bdca
--- /dev/null
+++ b/src/jarabe/model/processmanagement.py
@@ -0,0 +1,84 @@
+# Copyright (C) 2010, Plan Ceibal <comunidad at plan.ceibal.edu.uy>
+# Copyright (C) 2010 Paraguay Educa, Martin Abente, Bernie Innocenti
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
USA
+
+import os
+import gobject
+import glib
+import gio
+
+from gettext import gettext as _
+
+BYTES_TO_READ = 100
+
+class ProcessManagement(gobject.GObject):
+
+    __gtype_name__ = 'ProcessManagement'
+
+    __gsignals__ = {
+        'process-management-running'    : (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([str])),
+        'process-management-started'    : (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])),
+        'process-management-finished'    : (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([])),
+        'process-management-failed'    : (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, ([str]))
+    }
+
+    def __init__(self):
+        gobject.GObject.__init__(self)
+        self._running = False
+
+    def do_process(self, cmd):
+        self._run_cmd_async(cmd)
+
+    def _report_process_status(self, stream, result):
+        data = stream.read_finish(result)
+
+        if len(data):
+            self.emit('process-management-running', data)
+            stream.read_async(BYTES_TO_READ, self._report_process_status)
+
+    def _report_process_error(self, stream, result):
+        data = stream.read_finish(result)
+        if len(data):
+                self.emit('process-management-failed', data)
+
+    def _notify_error(self, stderr):
+        stdin_stream = gio.unix.InputStream(stderr, True)
+        stdin_stream.read_async(BYTES_TO_READ, self._report_process_error)
+
+    def _notify_process_status(self, stdout):
+        stdin_stream = gio.unix.InputStream(stdout, True)
+        stdin_stream.read_async(BYTES_TO_READ, self._report_process_status)
+
+    def _run_cmd_async(self, cmd):
+        if self._running == False:
+            try:
+                pid, stdin, stdout, stderr = glib.spawn_async(cmd,
flags=glib.SPAWN_DO_NOT_REAP_CHILD, standard_output=True,
standard_error=True)
+                gobject.child_watch_add(pid, _handle_process_end, (self,
stderr))
+            except Exception:
+                self.emit('process-management-failed', _("Error - Call
process: ") + str(cmd))
+            else:
+                self._notify_process_status(stdout)
+                self._running  = True
+                self.emit('process-management-started')
+
+def _handle_process_end(pid, condition, (myself, stderr)):
+    myself._running = False
+
+    if os.WIFEXITED(condition) and\
+        os.WEXITSTATUS(condition) == 0:
+            myself.emit('process-management-finished')
+    else:
+        myself._notify_error(stderr)
-- 
1.6.2.5


-- 
   Esteban Arias
   Plan Ceibal - Área Técnica
   Avda. Italia 6201
   Montevideo - Uruguay.
   Tel.: 601.57.73 Interno 2228
   E-mail : earias at plan.ceibal.edu.uy
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.sugarlabs.org/archive/sugar-devel/attachments/20100521/25eb7887/attachment-0001.htm 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Journal-Backup.patch
Type: application/octet-stream
Size: 13419 bytes
Desc: not available
Url : http://lists.sugarlabs.org/archive/sugar-devel/attachments/20100521/25eb7887/attachment-0003.obj 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sugar-journal-backup
Type: application/octet-stream
Size: 1573 bytes
Desc: not available
Url : http://lists.sugarlabs.org/archive/sugar-devel/attachments/20100521/25eb7887/attachment-0004.obj 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sugar-journal-restore
Type: application/octet-stream
Size: 1858 bytes
Desc: not available
Url : http://lists.sugarlabs.org/archive/sugar-devel/attachments/20100521/25eb7887/attachment-0005.obj 


More information about the Sugar-devel mailing list