El Sun, 16-05-2010 a las 11:30 -0700, Thomas C Gilliard escribió:
> Bernie;
> 
> Will you make a  .xo or rpm of your backup for standalone instances of
> Soas?

All we need is a new control panel item in Sugar and add 3 scripts to
ds-backup-client. I'm attaching patches to do both things.

You can test this functionality in os180py.


The current implementation works, but is way too crude for upstreaming
it. My TODO list contains:

1) Discuss UI refinements proposed by Eben (see his post to sugar-devel)

2) Integrate the USB backup/restore functionality developed by Esteban
   for LATU.

3) Address the concerns of Martin Langhoff regarding destroying the
current journal contents on restore.


> How would I convert it to a .xo file?
> Is there a reference I should consult?
> 
> I am running from the command line now.

Documentation for creating bundles is here:

 http://wiki.sugarlabs.org/go/Development_Team/Almanac/Activity_Bundles

But I feel that backup/restore should be core Sugar functionality, not
implemented as an activity.

-- 
   // Bernie Innocenti - http://codewiz.org/
 \X/  Sugar Labs       - http://sugarlabs.org/

>From 5a83859a66d5fb55e7587e4890b37cae13f39735 Mon Sep 17 00:00:00 2001
From: Martin Abente <mabe...@paraguayeduca.org>
Date: Fri, 9 Apr 2010 14:18:42 -0400
Subject: [PATCH] Backup & Restore front end for control panel
Organization: Paraguay Educa

Backported from 0.88

Signed-off-by: Martin Abente <mabe...@paraguayeduca.org>
---
 configure.ac                                       |    1 +
 data/icons/Makefile.am                             |    1 +
 data/icons/module-journalmanagement.svg            |  127 +++++++++++
 extensions/cpsection/Makefile.am                   |    2 +-
 extensions/cpsection/journalmanagement/Makefile.am |    6 +
 extensions/cpsection/journalmanagement/__init__.py |   22 ++
 extensions/cpsection/journalmanagement/model.py    |   78 +++++++
 extensions/cpsection/journalmanagement/view.py     |  236 ++++++++++++++++++++
 8 files changed, 472 insertions(+), 1 deletions(-)
 create mode 100644 data/icons/module-journalmanagement.svg
 create mode 100644 extensions/cpsection/journalmanagement/Makefile.am
 create mode 100644 extensions/cpsection/journalmanagement/__init__.py
 create mode 100644 extensions/cpsection/journalmanagement/model.py
 create mode 100644 extensions/cpsection/journalmanagement/view.py

diff --git a/configure.ac b/configure.ac
index 479056d..40442c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,7 @@ extensions/cpsection/aboutcomputer/Makef
 extensions/cpsection/aboutme/Makefile
 extensions/cpsection/datetime/Makefile
 extensions/cpsection/frame/Makefile
+extensions/cpsection/journalmanagement/Makefile
 extensions/cpsection/keyboard/Makefile
 extensions/cpsection/language/Makefile
 extensions/cpsection/modemconfiguration/Makefile
diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am
index e1f8fa7..b982f2e 100644
--- a/data/icons/Makefile.am
+++ b/data/icons/Makefile.am
@@ -5,6 +5,7 @@ sugar_DATA =                        \
 	module-about_my_computer.svg    \
 	module-date_and_time.svg        \
 	module-frame.svg                \
+	module-journalmanagement.svg    \
 	module-keyboard.svg             \
 	module-language.svg             \
 	module-modemconfiguration.svg	\
diff --git a/data/icons/module-journalmanagement.svg b/data/icons/module-journalmanagement.svg
new file mode 100644
index 0000000..9250c6f
--- /dev/null
+++ b/data/icons/module-journalmanagement.svg
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   enable-background="new 0 0 55 55"
+   height="55px"
+   id="Layer_1"
+   version="1.1"
+   viewBox="0 0 55 55"
+   width="55px"
+   x="0px"
+   xml:space="preserve"
+   y="0px"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="journalmanagement.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"><sodipodi:namedview
+   inkscape:window-height="827"
+   inkscape:window-width="1440"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="8.9818182"
+   inkscape:cx="7.7378543"
+   inkscape:cy="27.5"
+   inkscape:window-x="0"
+   inkscape:window-y="25"
+   inkscape:current-layer="Layer_1" /><metadata
+   id="metadata35"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs33"><inkscape:perspective
+     sodipodi:type="inkscape:persp3d"
+     inkscape:vp_x="0 : 27.5 : 1"
+     inkscape:vp_y="0 : 1000 : 0"
+     inkscape:vp_z="55 : 27.5 : 1"
+     inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+     id="perspective37" /><inkscape:perspective
+     id="perspective12"
+     inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+     inkscape:vp_z="55 : 27.5 : 1"
+     inkscape:vp_y="0 : 1000 : 0"
+     inkscape:vp_x="0 : 27.5 : 1"
+     sodipodi:type="inkscape:persp3d" /></defs>
+
+<g
+   display="block"
+   id="document-save"
+   transform="matrix(1.2198714,0,0,1.0017443,-2.2062535,-2.4418416)"
+   style="display:block">
+	<g
+   id="g4">
+		<g
+   id="g6">
+			<g
+   id="g8">
+				<path
+   d="M 6.736,49.002 L 31.256,49.002 C 33.481,49.002 34.695,47.555 34.695,45.561 L 34.695,18.281 C 34.695,16.551 32.963,14.84 31.256,14.84 L 26.867,14.84"
+   id="path10"
+   style="fill:#ffffff;stroke:#010101;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round" />
+			</g>
+		</g>
+		<g
+   id="g12">
+			<g
+   id="g14">
+				<path
+   d="M 26.867,38.592 C 26.867,40.428 25.522,41.793 23.426,42.639 L 6.736,49.002 L 6.736,14.84 L 23.426,6.241 C 25.654,5.847 26.867,7.081 26.867,9.075 L 26.867,38.592 z"
+   id="path16"
+   style="fill:#ffffff;stroke:#010101;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round" />
+			</g>
+		</g>
+		<path
+   d="M 9.424,42.607 C 9.424,42.607 8.073,42.064 6.722,42.064 C 5.371,42.064 4.019,42.607 4.019,42.607"
+   id="path18"
+   style="fill:none;stroke:#010101;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round" />
+		<path
+   d="M 9.424,32.006 C 9.424,32.006 8.185,31.463 6.609,31.463 C 5.032,31.463 4.019,32.006 4.019,32.006"
+   id="path20"
+   style="fill:none;stroke:#010101;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round" />
+		<path
+   d="M 9.424,21.678 C 9.424,21.678 8.299,21.134 6.497,21.134 C 4.695,21.134 4.019,21.678 4.019,21.678"
+   id="path22"
+   style="fill:none;stroke:#010101;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round" />
+		
+		<line
+   x1="13.209"
+   x2="13.209"
+   y1="46.533001"
+   y2="11.505"
+   id="line24"
+   style="fill:none;stroke:#010101;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round" />
+		
+		<g
+   id="g26">
+			
+			
+		</g>
+	</g>
+</g><rect
+   y="28.864494"
+   x="28.753164"
+   height="22.87829"
+   width="23.546305"
+   id="rect2668"
+   style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.99260712;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><g
+   id="view-expand"
+   display="block"
+   transform="matrix(0.4680612,0,0,0.4482681,27.768809,28.143274)"
+   style="fill:#000000;display:block">
+	<path
+   id="path5"
+   d="M 4.875,5 L 4.875,50 L 49.875,50 L 49.875,5 L 4.875,5 z M 23.638,44.051 L 12.574,44.051 C 12.503,44.051 12.433,44.038 12.364,44.03 C 12.322,44.025 12.28,44.026 12.238,44.017 C 12.205,44.01 12.174,43.997 12.141,43.989 C 12.062,43.968 11.983,43.949 11.907,43.918 C 11.894,43.912 11.882,43.903 11.869,43.897 C 11.779,43.857 11.691,43.813 11.607,43.757 C 11.511,43.694 11.42,43.62 11.338,43.538 C 11.255,43.455 11.181,43.363 11.116,43.266 C 11.086,43.22 11.065,43.17 11.04,43.122 C 11.012,43.07 10.98,43.02 10.957,42.965 C 10.925,42.889 10.905,42.809 10.885,42.73 C 10.877,42.7 10.864,42.67 10.858,42.639 C 10.839,42.541 10.831,42.443 10.829,42.343 C 10.829,42.328 10.825,42.315 10.825,42.3 L 10.825,31.236 C 10.825,30.267 11.608,29.485 12.574,29.485 C 13.542,29.485 14.325,30.267 14.325,31.236 L 14.325,38.075 L 22.337,30.06 C 23.021,29.378 24.129,29.378 24.813,30.06 C 25.495,30.744 25.495,31.852 24.813,32.537 L 16.8,40.549 L 23.638,40.549 L 23.638,40.552 C 24.604,40.552 25.388,41.334 25.388,42.3 C 25.389,43.267 24.604,44.051 23.638,44.051 z M 42.573,25.114 C 41.605,25.114 40.822,24.331 40.822,23.363 L 40.822,16.523 L 31.809,25.536 C 31.467,25.878 31.019,26.049 30.571,26.049 C 30.124,26.049 29.675,25.878 29.334,25.536 C 28.651,24.852 28.651,23.745 29.334,23.061 L 38.345,14.049 L 31.511,14.049 C 30.545,14.049 29.76,13.264 29.76,12.298 C 29.76,11.332 30.545,10.547 31.511,10.547 L 42.573,10.547 C 42.677,10.547 42.782,10.559 42.885,10.578 C 42.892,10.579 42.9,10.579 42.906,10.58 C 42.961,10.591 43.012,10.611 43.066,10.627 C 43.124,10.644 43.182,10.657 43.238,10.68 C 43.27,10.693 43.3,10.713 43.331,10.729 C 43.402,10.763 43.475,10.796 43.541,10.841 C 43.598,10.878 43.646,10.924 43.697,10.968 C 43.734,10.999 43.774,11.025 43.809,11.059 C 43.856,11.106 43.892,11.16 43.933,11.211 C 43.963,11.25 43.999,11.285 44.027,11.326 C 44.088,11.417 44.137,11.513 44.178,11.611 C 44.181,11.617 44.185,11.622 44.188,11.628 C 44.222,11.711 44.245,11.796 44.265,11.883 C 44.272,11.908 44.283,11.933 44.287,11.959 C 44.299,12.02 44.301,12.083 44.306,12.145 C 44.311,12.196 44.322,12.247 44.322,12.298 L 44.324,23.363 C 44.324,24.332 43.54,25.114 42.573,25.114 z"
+   style="fill:#000000" />
+</g></svg>
\ No newline at end of file
diff --git a/extensions/cpsection/Makefile.am b/extensions/cpsection/Makefile.am
index 73e5164..fe6b46b 100644
@@ -1,5 +1,15 @@
-SUBDIRS = aboutme aboutcomputer datetime frame keyboard language \
-    modemconfiguration network power updater
+SUBDIRS =
+	aboutme \
+	aboutcomputer \
+	datetime \
+	frame \
+	journalmanagement \
+	keyboard \
+	language \
+	modemconfiguration \
+	network \
+	power \
+	updater
 
 sugardir = $(pkgdatadir)/extensions/cpsection
 sugar_PYTHON = __init__.py
diff --git a/extensions/cpsection/journalmanagement/Makefile.am b/extensions/cpsection/journalmanagement/Makefile.am
new file mode 100644
index 0000000..ed68aa7
--- /dev/null
+++ b/extensions/cpsection/journalmanagement/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/journalmanagement
+
+sugar_PYTHON = 		\
+	__init__.py	\
+	model.py	\
+	view.py
diff --git a/extensions/cpsection/journalmanagement/__init__.py b/extensions/cpsection/journalmanagement/__init__.py
new file mode 100644
index 0000000..6eace00
--- /dev/null
+++ b/extensions/cpsection/journalmanagement/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2010 Paraguay Educa, Martin Abente
+#
+# 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  US
+
+from gettext import gettext as _
+
+CLASS = 'JournalManagement'
+ICON = 'module-journalmanagement'
+TITLE = _('Journal Management')
+
diff --git a/extensions/cpsection/journalmanagement/model.py b/extensions/cpsection/journalmanagement/model.py
new file mode 100644
index 0000000..811bdfb
--- /dev/null
+++ b/extensions/cpsection/journalmanagement/model.py
@@ -0,0 +1,78 @@
+# 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  US
+
+import os
+import gobject
+import glib
+import gio
+import logging
+
+BYTES_TO_READ = 100
+
+class JournalManagementModel(gobject.GObject):
+
+    __gtype_name__ = 'JournalManagementModel'
+
+    __gsignals__ = {
+        'journal-management-running'    : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([str])),
+        'journal-management-started'    : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+        'journal-management-finished'    : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
+        'journal-management-failed'    : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
+    }
+
+    def __init__(self):
+        gobject.GObject.__init__(self)
+
+        self._running = False
+        self._backup_script_path = ['/usr/bin/journal-backup']
+        self._restore_script_path = ['/usr/bin/journal-restore']
+
+    def do_backup(self):
+        self.run_cmd_async(self._backup_script_path)
+
+    def do_restore(self):
+        self.run_cmd_async(self._restore_script_path)
+
+    def report_process_status(self, stream, result):
+        data = stream.read_finish(result)
+
+        if len(data):
+            self.emit('journal-management-running', data)
+            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)
+                gobject.child_watch_add(pid, _handle_process_end, (self))
+            except Exception:
+                self.emit('journal-management-failed')
+            else:
+                stdin_stream = gio.unix.InputStream(stdout, True)
+                stdin_stream.read_async(BYTES_TO_READ, self.report_process_status)
+
+                self._running  = True
+                self.emit('journal-management-started')
+
+def _handle_process_end(pid, condition, myself):
+    myself._running = False
+
+    if os.WIFEXITED(condition) and\
+        os.WEXITSTATUS(condition) == 0:
+            myself.emit('journal-management-finished')
+    else:
+        myself.emit('journal-management-failed')
+
diff --git a/extensions/cpsection/journalmanagement/view.py b/extensions/cpsection/journalmanagement/view.py
new file mode 100644
index 0000000..ae3194c
--- /dev/null
+++ b/extensions/cpsection/journalmanagement/view.py
@@ -0,0 +1,236 @@
+# Copyright (C) 2010 Paraguay Educa, Martin Abente
+#
+# 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  US.
+
+import gtk
+import gobject
+import logging
+from gettext import gettext as _
+
+from jarabe.model.session import get_session_manager
+
+from sugar.graphics import style
+from sugar.graphics.alert import Alert
+from sugar.graphics.icon import Icon
+
+from jarabe.controlpanel.sectionview import SectionView
+
+from model import JournalManagementModel
+
+class JournalManagement(SectionView):
+    def __init__(self, model, alerts):
+        SectionView.__init__(self)
+
+        self._model = JournalManagementModel()
+        self._model.connect('journal-management-running', self._set_update_log)
+        self._model.connect('journal-management-started', self._set_status_started)
+        self._model.connect('journal-management-finished', self._set_status_finished)
+        self._model.connect('journal-management-failed', self._set_status_failed)
+
+        self.restart_alerts = alerts
+        self._showing_alert = False
+        self._process_name = None
+        self._needs_restart = True
+
+        self.set_border_width(style.DEFAULT_SPACING)
+        self.set_spacing(style.DEFAULT_SPACING)
+        self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+        self._vbox = gtk.VBox()
+
+        self._setup_options()
+        self._setup_status_info()
+        self._setup_more_info()
+
+        self._vbox.show()
+        self.pack_start(self._vbox, expand=True)
+
+    def _setup_options(self):
+        self._setup_separator(_('Options'))
+
+        self._setup_option(_('Backup'), \
+            _('Save your Journal to the School Server'), \
+                self._pre_start_backup_cb)
+
+        self._setup_option(_('Restore'), \
+            _('Restore your Journal to the last backup'), \
+                self._pre_start_restore_cb)
+
+    def _setup_option(self, button_text, description_text, button_callback):
+        option_hbox = gtk.HBox()
+
+        button = gtk.Button(label=button_text)
+        button.connect('pressed', button_callback)
+        button.show()
+        option_hbox.pack_start(button, expand=True, fill=True)
+
+        label = gtk.Label(description_text)
+        label.show()
+        option_hbox.pack_start(label, expand=True, fill=True)
+
+        option_hbox.show()
+        self._vbox.pack_start(option_hbox, expand=False, padding=5)
+
+    def _setup_expander(self):
+        expander = gtk.Expander(_('Show'))
+        expander.connect("notify::expanded", self._log_menu_control)
+        expander.show()
+
+        self._vbox.pack_start(expander, expand=False)
+
+    def _setup_more_info(self):
+        self._setup_separator(_('Log'))
+        self._setup_expander()
+        self._setup_log()
+
+    def _setup_status_info(self):
+        self._setup_separator(_('Status'))
+
+        self._status_label = gtk.Label(_('No process is running'))
+        self._status_label.show()
+
+        self._vbox.pack_start(self._status_label, expand=False, fill=False)
+
+    def _setup_log(self):
+        self._log_vbox = gtk.VBox()
+
+        scrolled_window = gtk.ScrolledWindow()
+        scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self._log_vbox.pack_start(scrolled_window, expand=True, padding= 10)
+
+        self._log_view = gtk.TextView()
+        self._log_view.set_editable(False)
+        self._log_buffer = self._log_view.get_buffer()
+        scrolled_window.add(self._log_view)
+
+        self._vbox.pack_start(self._log_vbox, expand=True)
+
+    def _setup_separator(self, label_text):
+        separator_vbox = gtk.VBox()
+
+        separator = gtk.HSeparator()
+        separator.show()
+        separator_vbox.pack_start(separator, expand=False)
+
+        label = gtk.Label(label_text)
+        label.set_alignment(0, 0)
+        label.show()
+        separator_vbox.pack_start(label, expand=False)
+
+        separator_vbox.show()
+        self._vbox.pack_start(separator_vbox, expand=False, padding=10)
+
+    def _log_menu_control(self, expander, data= None):
+        if expander.get_expanded():
+            self._log_vbox.show_all()
+        else:
+            self._log_vbox.hide()
+
+    def _pre_start_restore_cb(self, button, data= None):
+        self._show_alert(_('Restore Warning!'), \
+            _('You are about to delete all your journal, are you sure?'), \
+                self._response_restore_cb)
+
+    def _response_restore_cb(self, alert, response_id):
+        if response_id == gtk.RESPONSE_APPLY:
+            self._process_name = _('Restore')
+            self._needs_restart = True
+            self._model.do_restore()
+
+        self._destroy_alert(alert)
+
+    def _pre_start_backup_cb(self, button, data= None):
+        self._show_alert(_('Backup Warning!'), \
+            _('This process could take several minutes, are you sure?'), \
+                self._response_backup_cb)
+
+    def _response_backup_cb(self, alert, response_id):
+        if response_id == gtk.RESPONSE_APPLY:
+            self._process_name = _('Backup')
+            self._needs_restart = False
+            self._model.do_backup()
+
+        self._destroy_alert(alert)
+
+    def _set_update_log(self, model, data):
+        self._log_buffer.insert(self._log_buffer.get_end_iter(), data)
+        self._log_view.scroll_to_iter(self._log_buffer.get_end_iter(), 0)
+
+    def _set_status_started(self, model, data=None):
+        self._status_label.set_text(self._process_name + ' ' +\
+            _('is running, please wait...'))
+
+        self._hack_hide_toolbar_buttons()
+
+    def _set_status_finished(self, model, data=None):
+        self._status_label.set_text(self._process_name + ' ' + \
+            _('has finished, please check the logs.'))
+
+        if self._needs_restart == True:
+            self._show_alert(self._process_name + ' ' + \
+                _('Warning!'), \
+                    _('The process has finished, Sugar will restart now.'), \
+                        self._post_process_restart_cb, \
+                            True)
+        else:
+            self._hack_show_toolbar_buttons()
+
+    def _post_process_restart_cb(self, alert, responde_id):
+        session_manager = get_session_manager()
+        session_manager.logout()
+
+    def _set_status_failed(self, model, data=None):
+        self._status_label.set_text(self._process_name + ' ' +\
+            _('has failed.'))
+
+        self._hack_show_toolbar_buttons()
+
+    def _show_alert(self, title, msg, response_listener_cb, only_yes= False):
+        if self._showing_alert == False and \
+            self._model._running == False:
+                alert = Alert()
+                alert.props.title = title
+                alert.props.msg = msg
+
+                if only_yes == False:
+                    icon = Icon(icon_name='dialog-cancel')
+                    alert.add_button(gtk.RESPONSE_CANCEL, _('No'), icon)
+                    icon.show()
+
+                icon = Icon(icon_name='dialog-ok')
+                alert.add_button(gtk.RESPONSE_APPLY, _('Yes'), icon)
+                icon.show()
+
+                alert.connect('response', response_listener_cb)
+                alert.show()
+
+                self._vbox.pack_start(alert, False)
+                self._vbox.reorder_child(alert, 0)
+                self._showing_alert = True
+
+    def _destroy_alert(self, alert):
+        self._vbox.remove(alert)
+        self._showing_alert = False
+
+    def _hack_show_toolbar_buttons(self):
+        panel_control = self.get_toplevel()
+        panel_control._section_toolbar.cancel_button.show()
+        panel_control._section_toolbar.accept_button.show()
+
+    def _hack_hide_toolbar_buttons(self):
+        panel_control = self.get_toplevel()
+        panel_control._section_toolbar.cancel_button.hide()
+        panel_control._section_toolbar.accept_button.hide()
+
-- 
1.6.0.4

>From 39131d8c3d3e2c5bf069b81e873c9b88b66b87ab Mon Sep 17 00:00:00 2001
From: Bernie Innocenti <ber...@codewiz.org>
Date: Fri, 9 Apr 2010 17:40:12 -0300
Subject: [PATCH] Add journal-{backup,backup-list,restore}
Organization: Sugar Labs Foundation
X-Subversion: sucks


Signed-off-by: Bernie Innocenti <ber...@codewiz.org>
---
 Makefile.build             |    3 +++
 client/journal-backup      |   43 +++++++++++++++++++++++++++++++++++++++++++
 client/journal-backup-list |   38 ++++++++++++++++++++++++++++++++++++++
 client/journal-restore     |   30 ++++++++++++++++++++++++++++++
 ds-backup.spec.in          |    8 +++++++-
 5 files changed, 121 insertions(+), 1 deletions(-)
 create mode 100644 client/journal-backup
 create mode 100644 client/journal-backup-list
 create mode 100644 client/journal-restore

diff --git a/Makefile.build b/Makefile.build
index 2e1712e..f6cd00f 100644
--- a/Makefile.build
+++ b/Makefile.build
@@ -5,6 +5,9 @@ install-client:
 	install -D -d $(DESTDIR)/usr/bin
 	install -D client/ds-backup.py $(DESTDIR)/usr/bin/
 	install -D client/ds-backup.sh $(DESTDIR)/usr/bin/
+	install -D client/journal-backup      $(DESTDIR)/usr/bin/
+	install -D client/journal-backup-list $(DESTDIR)/usr/bin/
+	install -D client/journal-restore     $(DESTDIR)/usr/bin/
 	install -D -d $(DESTDIR)/etc
 	install -D -m 644 client/cron-ds-backup.conf $(DESTDIR)/etc/cron.d/ds-backup
 
diff --git a/client/journal-backup b/client/journal-backup
new file mode 100644
index 0000000..54ca743
--- /dev/null
+++ b/client/journal-backup
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright (C) 2009 Daniel Drake <d...@laptop.org>
+# Copyright (C) 2010 Paraguay Educa <http://paraguayeduca.org>
+#
+# 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  US 
+
+echo "Starting"
+
+# make the lock dir if needed
+# we will keep the (empty) file around
+if [ ! -d ~/.sugar/default/lock ]; then
+	mkdir ~/.sugar/default/lock || exit 1;
+fi
+LOCKFILE=~/.sugar/default/lock/ds-backup.run
+echo "Locking"
+
+# this fails when (this script is) copied to a usb stick 
+#flock -n $LOCKFILE `dirname $0 `/ds-backup.py
+#flock -n $LOCKFILE /usr/bin/ds-backup.py
+echo "Backing up"
+python /usr/bin/ds-backup.py
+
+EXITCODE=$?
+
+if [[ ${EXITCODE} != 0 ]]; then
+        echo "Sorry, it failed";
+        exit -1;
+fi
+
+echo "Great, it is done"
+exit 0
diff --git a/client/journal-backup-list b/client/journal-backup-list
new file mode 100644
index 0000000..da71ce7
--- /dev/null
+++ b/client/journal-backup-list
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright (C) 2009 Daniel Drake <d...@laptop.org>
+# Copyright (C) 2010 Paraguay Educa <http://paraguayeduca.org>
+#
+# 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  US
+
+sn=$(</ofw/mfg-data/SN)
+output=$(echo "ls -1" | sftp -F /dev/null -oPasswordAuthentication=no -oStrictHostKeyChecking=no -oUser=${sn} -oIdentityFile=/home/olpc/.sugar/default/owner.key schoolserver)
+
+EXITCODE=$?
+
+if [[ $? != 0 ]]; then
+	exit ${EXITCODE}
+fi
+
+IFS=""
+
+for line in ${output}; do
+	if [[ ${line:0:10} != "datastore-" || ${line} == "datastore-latest" ]]; then	
+		continue
+	fi
+	echo " - ${line:10}"
+done
+
+exit ${EXITCODE}
+
diff --git a/client/journal-restore b/client/journal-restore
new file mode 100644
index 0000000..c69ac44
--- /dev/null
+++ b/client/journal-restore
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright (C) 2009 Daniel Drake <d...@laptop.org>
+# Copyright (C) 2010 Paraguay Educa <http://paraguayeduca.org>
+#
+# 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  US
+
+to_restore=${1:-current}
+
+pkill -f -x "python /usr/bin/datastore-service"
+
+sn=$(</ofw/mfg-data/SN)
+sshcmd="ssh -F /dev/null -o 'PasswordAuthentication no' -o 'StrictHostKeyChecking no' -i /home/olpc/.sugar/default/owner.key -l ${sn}"
+rsync -z -rlt --delete-before -e "${sshcmd}" --progress \
+	"schoolserver:datastore-${to_restore}/" \
+	"/home/olpc/.sugar/default/datastore/"
+
+exit $?
+
diff --git a/ds-backup.spec.in b/ds-backup.spec.in
index fde1f60..5a94837 100644
--- a/ds-backup.spec.in
+++ b/ds-backup.spec.in
@@ -31,6 +31,9 @@ Requires:       sugar-datastore
 Requires:       sugar
 Requires:       vixie-cron
 
+# For /usr/bin/flock
+Requires:	util-linux-ng
+
 %package server
 
 Summary:        OLPC DS backup & restore server
@@ -78,6 +81,9 @@ chkconfig --level 345 incrond on
 %config %{_sysconfdir}/cron.d/ds-backup
 %{_bindir}/ds-backup.py
 %{_bindir}/ds-backup.sh
+%{_bindir}/journal-backup
+%{_bindir}/journal-backup-list
+%{_bindir}/journal-restore
 
 %files server
 %defattr(-,root,root,-)
@@ -90,7 +96,7 @@ chkconfig --level 345 incrond on
 %{_bindir}/ds-postprocess.py
 %{_bindir}/ds-cleanup.sh
 %{_bindir}/ds-cleanup.py
-/var/www/ds-backup/backup-available.py
+%{_var}/www/ds-backup/backup-available.py*
 %attr(700, apache, apache) %dir %{_localstatedir}/lib/ds-backup/recentclients
 %attr(777, nobody, nobody) %dir %{_localstatedir}/lib/ds-backup/completion
 
-- 
1.7.0.1

_______________________________________________
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel

Reply via email to