Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/extensions/cpsection/updater
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/cpsection/updater')
-rw-r--r--extensions/cpsection/updater/Makefile.am8
-rw-r--r--extensions/cpsection/updater/Makefile.in645
-rw-r--r--extensions/cpsection/updater/__init__.py22
-rw-r--r--extensions/cpsection/updater/backends/Makefile.am5
-rw-r--r--extensions/cpsection/updater/backends/Makefile.in441
-rw-r--r--extensions/cpsection/updater/backends/__init__.py16
-rw-r--r--extensions/cpsection/updater/backends/aslo.py164
-rwxr-xr-xextensions/cpsection/updater/model.py354
-rw-r--r--extensions/cpsection/updater/view.py391
9 files changed, 2046 insertions, 0 deletions
diff --git a/extensions/cpsection/updater/Makefile.am b/extensions/cpsection/updater/Makefile.am
new file mode 100644
index 0000000..897dbf3
--- /dev/null
+++ b/extensions/cpsection/updater/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = backends
+
+sugardir = $(pkgdatadir)/extensions/cpsection/updater
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/extensions/cpsection/updater/Makefile.in b/extensions/cpsection/updater/Makefile.in
new file mode 100644
index 0000000..dd9b2ec
--- /dev/null
+++ b/extensions/cpsection/updater/Makefile.in
@@ -0,0 +1,645 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = extensions/cpsection/updater
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(sugar_PYTHON)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile)
+am__installdirs = "$(DESTDIR)$(sugardir)"
+py_compile = $(top_srcdir)/py-compile
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GCONFTOOL = @GCONFTOOL@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHELL_CFLAGS = @SHELL_CFLAGS@
+SHELL_LIBS = @SHELL_LIBS@
+STRIP = @STRIP@
+SUCROSE_VERSION = @SUCROSE_VERSION@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = backends
+sugardir = $(pkgdatadir)/extensions/cpsection/updater
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign extensions/cpsection/updater/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign extensions/cpsection/updater/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-sugarPYTHON: $(sugar_PYTHON)
+ @$(NORMAL_INSTALL)
+ test -z "$(sugardir)" || $(MKDIR_P) "$(DESTDIR)$(sugardir)"
+ @list='$(sugar_PYTHON)'; dlist=; list2=; test -n "$(sugardir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
+ if test -f $$b$$p; then \
+ $(am__strip_dir) \
+ dlist="$$dlist $$f"; \
+ list2="$$list2 $$b$$p"; \
+ else :; fi; \
+ done; \
+ for file in $$list2; do echo $$file; done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sugardir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(sugardir)" || exit $$?; \
+ done || exit $$?; \
+ if test -n "$$dlist"; then \
+ $(am__py_compile) --destdir "$(DESTDIR)" \
+ --basedir "$(sugardir)" $$dlist; \
+ else :; fi
+
+uninstall-sugarPYTHON:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sugar_PYTHON)'; test -n "$(sugardir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ dir='$(DESTDIR)$(sugardir)'; \
+ filesc=`echo "$$files" | sed 's|$$|c|'`; \
+ fileso=`echo "$$files" | sed 's|$$|o|'`; \
+ st=0; \
+ for files in "$$files" "$$filesc" "$$fileso"; do \
+ $(am__uninstall_files_from_dir) || st=$$?; \
+ done; \
+ exit $$st
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(sugardir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-sugarPYTHON
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-sugarPYTHON
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic ctags \
+ ctags-recursive distclean distclean-generic distclean-tags \
+ distdir dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip install-sugarPYTHON installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-sugarPYTHON
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/extensions/cpsection/updater/__init__.py b/extensions/cpsection/updater/__init__.py
new file mode 100644
index 0000000..6010615
--- /dev/null
+++ b/extensions/cpsection/updater/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2008, OLPC
+#
+# 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
+
+from gettext import gettext as _
+
+CLASS = 'ActivityUpdater'
+ICON = 'module-updater'
+TITLE = _('Software update')
+KEYWORDS = ['software', 'activity', 'update']
diff --git a/extensions/cpsection/updater/backends/Makefile.am b/extensions/cpsection/updater/backends/Makefile.am
new file mode 100644
index 0000000..e280a07
--- /dev/null
+++ b/extensions/cpsection/updater/backends/Makefile.am
@@ -0,0 +1,5 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/updater/backends
+
+sugar_PYTHON = \
+ aslo.py \
+ __init__.py
diff --git a/extensions/cpsection/updater/backends/Makefile.in b/extensions/cpsection/updater/backends/Makefile.in
new file mode 100644
index 0000000..49e509c
--- /dev/null
+++ b/extensions/cpsection/updater/backends/Makefile.in
@@ -0,0 +1,441 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = extensions/cpsection/updater/backends
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(sugar_PYTHON)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile)
+am__installdirs = "$(DESTDIR)$(sugardir)"
+py_compile = $(top_srcdir)/py-compile
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GCONFTOOL = @GCONFTOOL@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHELL_CFLAGS = @SHELL_CFLAGS@
+SHELL_LIBS = @SHELL_LIBS@
+STRIP = @STRIP@
+SUCROSE_VERSION = @SUCROSE_VERSION@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+sugardir = $(pkgdatadir)/extensions/cpsection/updater/backends
+sugar_PYTHON = \
+ aslo.py \
+ __init__.py
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign extensions/cpsection/updater/backends/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign extensions/cpsection/updater/backends/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-sugarPYTHON: $(sugar_PYTHON)
+ @$(NORMAL_INSTALL)
+ test -z "$(sugardir)" || $(MKDIR_P) "$(DESTDIR)$(sugardir)"
+ @list='$(sugar_PYTHON)'; dlist=; list2=; test -n "$(sugardir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
+ if test -f $$b$$p; then \
+ $(am__strip_dir) \
+ dlist="$$dlist $$f"; \
+ list2="$$list2 $$b$$p"; \
+ else :; fi; \
+ done; \
+ for file in $$list2; do echo $$file; done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sugardir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(sugardir)" || exit $$?; \
+ done || exit $$?; \
+ if test -n "$$dlist"; then \
+ $(am__py_compile) --destdir "$(DESTDIR)" \
+ --basedir "$(sugardir)" $$dlist; \
+ else :; fi
+
+uninstall-sugarPYTHON:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sugar_PYTHON)'; test -n "$(sugardir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ dir='$(DESTDIR)$(sugardir)'; \
+ filesc=`echo "$$files" | sed 's|$$|c|'`; \
+ fileso=`echo "$$files" | sed 's|$$|o|'`; \
+ st=0; \
+ for files in "$$files" "$$filesc" "$$fileso"; do \
+ $(am__uninstall_files_from_dir) || st=$$?; \
+ done; \
+ exit $$st
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+ for dir in "$(DESTDIR)$(sugardir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-sugarPYTHON
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-sugarPYTHON
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip install-sugarPYTHON installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+ uninstall-am uninstall-sugarPYTHON
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/extensions/cpsection/updater/backends/__init__.py b/extensions/cpsection/updater/backends/__init__.py
new file mode 100644
index 0000000..0dd0174
--- /dev/null
+++ b/extensions/cpsection/updater/backends/__init__.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+# Copyright (C) 2009, Sugar Labs
+#
+# 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
diff --git a/extensions/cpsection/updater/backends/aslo.py b/extensions/cpsection/updater/backends/aslo.py
new file mode 100644
index 0000000..6504e9e
--- /dev/null
+++ b/extensions/cpsection/updater/backends/aslo.py
@@ -0,0 +1,164 @@
+#!/usr/bin/python
+# Copyright (C) 2009, Sugar Labs
+#
+# 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
+
+"""Activity information microformat parser.
+
+Activity information is embedded in HTML/XHTML/XML pages using a
+Resource Description Framework (RDF) http://www.w3.org/RDF/ .
+
+An example::
+
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+<RDF:Description about="urn:mozilla:extension:bounce">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li resource="urn:mozilla:extension:bounce:7"/>
+ </RDF:Seq>
+ </em:updates>
+</RDF:Description>
+
+<RDF:Description about="urn:mozilla:extension:bounce:7">
+ <em:version>7</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{3ca105e0-2280-4897-99a0-c277d1b733d2}</em:id>
+ <em:minVersion>0.82</em:minVersion>
+ <em:maxVersion>0.84</em:maxVersion>
+ <em:updateLink>http://foo.xo</em:updateLink>
+ <em:updateSize>7</em:updateSize>
+ <em:updateHash>sha256:816a7c43b4f1ea4769c61c03ea4..</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+</RDF:Description></RDF:RDF>
+"""
+
+import logging
+from xml.etree.ElementTree import XML
+import traceback
+
+import gio
+
+from sugar.bundle.bundleversion import NormalizedVersion
+from sugar.bundle.bundleversion import InvalidVersionError
+
+from jarabe import config
+
+_FIND_DESCRIPTION = \
+ './/{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description'
+_FIND_VERSION = './/{http://www.mozilla.org/2004/em-rdf#}version'
+_FIND_LINK = './/{http://www.mozilla.org/2004/em-rdf#}updateLink'
+_FIND_SIZE = './/{http://www.mozilla.org/2004/em-rdf#}updateSize'
+
+_UPDATE_PATH = 'http://activities.sugarlabs.org/services/update-aslo.php'
+
+_fetcher = None
+
+
+class _UpdateFetcher(object):
+
+ _CHUNK_SIZE = 10240
+
+ def __init__(self, bundle, completion_cb):
+ # ASLO knows only about stable SP releases
+ major, minor = config.version.split('.')[0:2]
+ sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2)
+
+ url = '%s?id=%s&appVersion=%s' % \
+ (_UPDATE_PATH, bundle.get_bundle_id(), sp_version)
+
+ logging.debug('Fetch %s', url)
+
+ self._completion_cb = completion_cb
+ self._file = gio.File(url)
+ self._stream = None
+ self._xml_data = ''
+ self._bundle = bundle
+
+ self._file.read_async(self.__file_read_async_cb)
+
+ def __file_read_async_cb(self, gfile, result):
+ try:
+ self._stream = self._file.read_finish(result)
+ except:
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(None, None, None, None, traceback.format_exc())
+ return
+
+ self._stream.read_async(self._CHUNK_SIZE, self.__stream_read_async_cb)
+
+ def __stream_read_async_cb(self, stream, result):
+ xml_data = self._stream.read_finish(result)
+ if xml_data is None:
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(self._bundle, None, None, None,
+ 'Error reading update information for %s from '
+ 'server.' % self._bundle.get_bundle_id())
+ return
+ elif not xml_data:
+ self._process_result()
+ else:
+ self._xml_data += xml_data
+ self._stream.read_async(self._CHUNK_SIZE,
+ self.__stream_read_async_cb)
+
+ def _process_result(self):
+ document = XML(self._xml_data)
+
+ if document.find(_FIND_DESCRIPTION) is None:
+ logging.debug('Bundle %s not available in the server for the '
+ 'version %s', self._bundle.get_bundle_id(), config.version)
+ version = None
+ link = None
+ size = None
+ else:
+ try:
+ version = NormalizedVersion(document.find(_FIND_VERSION).text)
+ except InvalidVersionError:
+ logging.exception('Exception occured while parsing version')
+ version = '0'
+
+ link = document.find(_FIND_LINK).text
+
+ try:
+ size = long(document.find(_FIND_SIZE).text) * 1024
+ except ValueError:
+ logging.exception('Exception occured while parsing size')
+ size = 0
+
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(self._bundle, version, link, size, None)
+
+
+def fetch_update_info(bundle, completion_cb):
+ """Queries the server for a newer version of the ActivityBundle.
+
+ completion_cb receives bundle, version, link, size and possibly an error
+ message:
+
+ def completion_cb(bundle, version, link, size, error_message):
+ """
+ global _fetcher
+
+ if _fetcher is not None:
+ raise RuntimeError('Multiple simultaneous requests are not supported')
+
+ _fetcher = _UpdateFetcher(bundle, completion_cb)
diff --git a/extensions/cpsection/updater/model.py b/extensions/cpsection/updater/model.py
new file mode 100755
index 0000000..7ea445f
--- /dev/null
+++ b/extensions/cpsection/updater/model.py
@@ -0,0 +1,354 @@
+# Copyright (C) 2009, Sugar Labs
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# 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
+"""Sugar bundle updater: model.
+
+This module implements the non-GUI portions of the bundle updater, including
+list of installed bundls, whether updates are needed, and the URL at which to
+find the bundle updated.
+"""
+
+import os
+import logging
+import tempfile
+from urlparse import urlparse
+import traceback
+
+import gobject
+import gio
+
+from sugar import env
+from sugar.datastore import datastore
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.bundle.bundleversion import NormalizedVersion
+
+from jarabe.model import bundleregistry
+
+from backends import aslo
+
+
+class UpdateModel(gobject.GObject):
+ __gtype_name__ = 'SugarUpdateModel'
+
+ __gsignals__ = {
+ 'progress': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([int, str, float, int])),
+ }
+
+ ACTION_CHECKING = 0
+ ACTION_UPDATING = 1
+ ACTION_DOWNLOADING = 2
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self.updates = None
+ self._bundles_to_check = None
+ self._bundles_to_update = None
+ self._total_bundles_to_update = 0
+ self._downloader = None
+ self._cancelling = False
+
+ def check_updates(self):
+ self.updates = []
+ self._bundles_to_check = list(bundleregistry.get_registry())
+ self._check_next_update()
+
+ def _check_next_update(self):
+ total = len(bundleregistry.get_registry())
+ current = total - len(self._bundles_to_check)
+
+ if not self._bundles_to_check:
+ return False
+
+ bundle = self._bundles_to_check.pop()
+ self.emit('progress', UpdateModel.ACTION_CHECKING, bundle.get_name(),
+ current, total)
+
+ aslo.fetch_update_info(bundle, self.__check_completed_cb)
+
+ def __check_completed_cb(self, bundle, version, link, size, error_message):
+ if error_message is not None:
+ logging.error('Error getting update information from server:\n'
+ '%s' % error_message)
+
+ if version is not None and \
+ version > NormalizedVersion(bundle.get_activity_version()):
+ self.updates.append(BundleUpdate(bundle, version, link, size))
+
+ if self._cancelling:
+ self._cancel_checking()
+ elif self._bundles_to_check:
+ gobject.idle_add(self._check_next_update)
+ else:
+ total = len(bundleregistry.get_registry())
+ if bundle is None:
+ name = ''
+ else:
+ name = bundle.get_name()
+ self.emit('progress', UpdateModel.ACTION_CHECKING, name, total,
+ total)
+
+ def update(self, bundle_ids):
+ self._bundles_to_update = []
+ for bundle_update in self.updates:
+ if bundle_update.bundle.get_bundle_id() in bundle_ids:
+ self._bundles_to_update.append(bundle_update)
+
+ self._total_bundles_to_update = len(self._bundles_to_update)
+ self._download_next_update()
+
+ def _download_next_update(self):
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ bundle_update = self._bundles_to_update.pop()
+
+ total = self._total_bundles_to_update * 2
+ current = total - len(self._bundles_to_update) * 2 - 2
+
+ self.emit('progress', UpdateModel.ACTION_DOWNLOADING,
+ bundle_update.bundle.get_name(), current, total)
+
+ self._downloader = _Downloader(bundle_update)
+ self._downloader.connect('progress', self.__downloader_progress_cb)
+ self._downloader.connect('error', self.__downloader_error_cb)
+
+ def __downloader_progress_cb(self, downloader, progress):
+ logging.debug('__downloader_progress_cb %r', progress)
+
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ total = self._total_bundles_to_update * 2
+ current = total - len(self._bundles_to_update) * 2 - 2 + progress
+
+ self.emit('progress', UpdateModel.ACTION_DOWNLOADING,
+ self._downloader.bundle_update.bundle.get_name(),
+ current, total)
+
+ if progress == 1:
+ self._install_update(self._downloader.bundle_update,
+ self._downloader.get_local_file_path())
+ self._downloader = None
+
+ def __downloader_error_cb(self, downloader, error_message):
+ logging.error('Error downloading update:\n%s', error_message)
+
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ total = self._total_bundles_to_update
+ current = total - len(self._bundles_to_update)
+ self.emit('progress', UpdateModel.ACTION_UPDATING, '', current, total)
+
+ if self._bundles_to_update:
+ # do it in idle so the UI has a chance to refresh
+ gobject.idle_add(self._download_next_update)
+
+ def _install_update(self, bundle_update, local_file_path):
+
+ total = self._total_bundles_to_update
+ current = total - len(self._bundles_to_update) - 0.5
+
+ self.emit('progress', UpdateModel.ACTION_UPDATING,
+ bundle_update.bundle.get_name(),
+ current, total)
+
+ # TODO: Should we first expand the zip async so we can provide progress
+ # and only then copy to the journal?
+ jobject = datastore.create()
+ try:
+ title = '%s-%s' % (bundle_update.bundle.get_name(),
+ bundle_update.version)
+ jobject.metadata['title'] = title
+ jobject.metadata['mime_type'] = ActivityBundle.MIME_TYPE
+ jobject.file_path = local_file_path
+ datastore.write(jobject, transfer_ownership=True)
+ finally:
+ jobject.destroy()
+
+ self.emit('progress', UpdateModel.ACTION_UPDATING,
+ bundle_update.bundle.get_name(),
+ current + 0.5, total)
+
+ if self._bundles_to_update:
+ # do it in idle so the UI has a chance to refresh
+ gobject.idle_add(self._download_next_update)
+
+ def cancel(self):
+ self._cancelling = True
+
+ def _cancel_checking(self):
+ logging.debug('UpdateModel._cancel_checking')
+ total = len(bundleregistry.get_registry())
+ current = total - len(self._bundles_to_check)
+ self.emit('progress', UpdateModel.ACTION_CHECKING, '', current,
+ current)
+ self._bundles_to_check = None
+ self._cancelling = False
+
+ def _cancel_updating(self):
+ logging.debug('UpdateModel._cancel_updating')
+ current = (self._total_bundles_to_update -
+ len(self._bundles_to_update) - 1)
+ self.emit('progress', UpdateModel.ACTION_UPDATING, '', current,
+ current)
+
+ if self._downloader is not None:
+ self._downloader.cancel()
+ file_path = self._downloader.get_local_file_path()
+ if file_path is not None and os.path.exists(file_path):
+ os.unlink(file_path)
+ self._downloader = None
+
+ self._total_bundles_to_update = 0
+ self._bundles_to_update = None
+ self._cancelling = False
+
+
+class BundleUpdate(object):
+
+ def __init__(self, bundle, version, link, size):
+ self.bundle = bundle
+ self.version = version
+ self.link = link
+ self.size = size
+
+
+class _Downloader(gobject.GObject):
+ _CHUNK_SIZE = 10240 # 10K
+ __gsignals__ = {
+ 'progress': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([float])),
+ 'error': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, bundle_update):
+ gobject.GObject.__init__(self)
+
+ self.bundle_update = bundle_update
+ self._input_stream = None
+ self._output_stream = None
+ self._pending_buffers = []
+ self._input_file = gio.File(bundle_update.link)
+ self._output_file = None
+ self._downloaded_size = 0
+ self._cancelling = False
+
+ self._input_file.read_async(self.__file_read_async_cb)
+
+ def cancel(self):
+ self._cancelling = True
+
+ def __file_read_async_cb(self, gfile, result):
+ if self._cancelling:
+ return
+
+ try:
+ self._input_stream = self._input_file.read_finish(result)
+ except:
+ self.emit('error', traceback.format_exc())
+ return
+
+ temp_file_path = self._get_temp_file_path(self.bundle_update.link)
+ self._output_file = gio.File(temp_file_path)
+ self._output_stream = self._output_file.create()
+
+ self._input_stream.read_async(self._CHUNK_SIZE, self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+
+ def __read_async_cb(self, input_stream, result):
+ if self._cancelling:
+ return
+
+ data = input_stream.read_finish(result)
+
+ if data is None:
+ # TODO
+ pass
+ elif not data:
+ logging.debug('closing input stream')
+ self._input_stream.close()
+ self._check_if_finished_writing()
+ else:
+ self._pending_buffers.append(data)
+ self._input_stream.read_async(self._CHUNK_SIZE,
+ self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+
+ self._write_next_buffer()
+
+ def __write_async_cb(self, output_stream, result, user_data):
+ if self._cancelling:
+ return
+
+ count = output_stream.write_finish(result)
+
+ self._downloaded_size += count
+ progress = self._downloaded_size / float(self.bundle_update.size)
+ self.emit('progress', progress)
+
+ self._check_if_finished_writing()
+
+ if self._pending_buffers:
+ self._write_next_buffer()
+
+ def _write_next_buffer(self):
+ if self._pending_buffers and not self._output_stream.has_pending():
+ data = self._pending_buffers.pop(0)
+ # TODO: we pass the buffer as user_data because of
+ # http://bugzilla.gnome.org/show_bug.cgi?id=564102
+ self._output_stream.write_async(data, self.__write_async_cb,
+ gobject.PRIORITY_LOW,
+ user_data=data)
+
+ def _get_temp_file_path(self, uri):
+ # TODO: Should we use the HTTP headers for the file name?
+ scheme_, netloc_, path, params_, query_, fragment_ = \
+ urlparse(uri)
+ path = os.path.basename(path)
+
+ if not os.path.exists(env.get_user_activities_path()):
+ os.makedirs(env.get_user_activities_path())
+
+ base_name, extension_ = os.path.splitext(path)
+ fd, file_path = tempfile.mkstemp(dir=env.get_user_activities_path(),
+ prefix=base_name, suffix='.xo')
+ os.close(fd)
+ os.unlink(file_path)
+
+ return file_path
+
+ def get_local_file_path(self):
+ return self._output_file.get_path()
+
+ def _check_if_finished_writing(self):
+ if not self._pending_buffers and \
+ not self._output_stream.has_pending() and \
+ self._input_stream.is_closed():
+
+ logging.debug('closing output stream')
+ self._output_stream.close()
+
+ self.emit('progress', 1.0)
diff --git a/extensions/cpsection/updater/view.py b/extensions/cpsection/updater/view.py
new file mode 100644
index 0000000..814658f
--- /dev/null
+++ b/extensions/cpsection/updater/view.py
@@ -0,0 +1,391 @@
+# Copyright (C) 2008, One Laptop Per Child
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# 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
+
+from gettext import gettext as _
+from gettext import ngettext
+import locale
+import logging
+
+import gobject
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon, CellRendererIcon
+
+from jarabe.controlpanel.sectionview import SectionView
+
+from model import UpdateModel
+
+_DEBUG_VIEW_ALL = True
+
+
+class ActivityUpdater(SectionView):
+
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = UpdateModel()
+ self._model.connect('progress', self.__progress_cb)
+
+ self.set_spacing(style.DEFAULT_SPACING)
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+
+ self._top_label = gtk.Label()
+ self._top_label.set_line_wrap(True)
+ self._top_label.set_justify(gtk.JUSTIFY_LEFT)
+ self._top_label.props.xalign = 0
+ self.pack_start(self._top_label, expand=False)
+ self._top_label.show()
+
+ separator = gtk.HSeparator()
+ self.pack_start(separator, expand=False)
+ separator.show()
+
+ bottom_label = gtk.Label()
+ bottom_label.set_line_wrap(True)
+ bottom_label.set_justify(gtk.JUSTIFY_LEFT)
+ bottom_label.props.xalign = 0
+ bottom_label.set_markup(
+ _('Software updates correct errors, eliminate security ' \
+ 'vulnerabilities, and provide new features.'))
+ self.pack_start(bottom_label, expand=False)
+ bottom_label.show()
+
+ self._update_box = None
+ self._progress_pane = None
+
+ self._refresh()
+
+ def _switch_to_update_box(self):
+ if self._update_box in self.get_children():
+ return
+
+ if self._progress_pane in self.get_children():
+ self.remove(self._progress_pane)
+ self._progress_pane = None
+
+ if self._update_box is None:
+ self._update_box = UpdateBox(self._model)
+ self._update_box.refresh_button.connect('clicked',
+ self.__refresh_button_clicked_cb)
+ self._update_box.install_button.connect('clicked',
+ self.__install_button_clicked_cb)
+
+ self.pack_start(self._update_box, expand=True, fill=True)
+ self._update_box.show()
+
+ def _switch_to_progress_pane(self):
+ if self._progress_pane in self.get_children():
+ return
+
+ if self._update_box in self.get_children():
+ self.remove(self._update_box)
+ self._update_box = None
+
+ if self._progress_pane is None:
+ self._progress_pane = ProgressPane()
+ self._progress_pane.cancel_button.connect('clicked',
+ self.__cancel_button_clicked_cb)
+
+ self.pack_start(self._progress_pane, expand=True, fill=False)
+ self._progress_pane.show()
+
+ def _clear_center(self):
+ if self._progress_pane in self.get_children():
+ self.remove(self._progress_pane)
+ self._progress_pane = None
+
+ if self._update_box in self.get_children():
+ self.remove(self._update_box)
+ self._update_box = None
+
+ def __progress_cb(self, model, action, bundle_name, current, total):
+ if current == total and action == UpdateModel.ACTION_CHECKING:
+ self._finished_checking()
+ return
+ elif current == total:
+ self._finished_updating(int(current))
+ return
+
+ if action == UpdateModel.ACTION_CHECKING:
+ message = _('Checking %s...') % bundle_name
+ elif action == UpdateModel.ACTION_DOWNLOADING:
+ message = _('Downloading %s...') % bundle_name
+ elif action == UpdateModel.ACTION_UPDATING:
+ message = _('Updating %s...') % bundle_name
+
+ self._switch_to_progress_pane()
+ self._progress_pane.set_message(message)
+ self._progress_pane.set_progress(current / float(total))
+
+ def _finished_checking(self):
+ logging.debug('ActivityUpdater._finished_checking')
+ available_updates = len(self._model.updates)
+ if not available_updates:
+ top_message = _('Your software is up-to-date')
+ else:
+ top_message = ngettext('You can install %s update',
+ 'You can install %s updates',
+ available_updates)
+ top_message = top_message % available_updates
+ top_message = gobject.markup_escape_text(top_message)
+
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+
+ if not available_updates:
+ self._clear_center()
+ else:
+ self._switch_to_update_box()
+ self._update_box.refresh()
+
+ def __refresh_button_clicked_cb(self, button):
+ self._refresh()
+
+ def _refresh(self):
+ top_message = _('Checking for updates...')
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+ self._model.check_updates()
+
+ def __install_button_clicked_cb(self, button):
+ text = '<big>%s</big>' % _('Installing updates...')
+ self._top_label.set_markup(text)
+ self._model.update(self._update_box.get_bundles_to_update())
+
+ def __cancel_button_clicked_cb(self, button):
+ self._model.cancel()
+
+ def _finished_updating(self, installed_updates):
+ logging.debug('ActivityUpdater._finished_updating')
+ top_message = ngettext('%s update was installed',
+ '%s updates were installed', installed_updates)
+ top_message = top_message % installed_updates
+ top_message = gobject.markup_escape_text(top_message)
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+ self._clear_center()
+
+ def undo(self):
+ self._model.cancel()
+
+
+class ProgressPane(gtk.VBox):
+ """Container which replaces the `ActivityPane` during refresh or
+ install."""
+
+ def __init__(self):
+ gtk.VBox.__init__(self)
+ self.set_spacing(style.DEFAULT_PADDING)
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+
+ self._progress = gtk.ProgressBar()
+ self.pack_start(self._progress)
+ self._progress.show()
+
+ self._label = gtk.Label()
+ self._label.set_line_wrap(True)
+ self._label.set_property('xalign', 0.5)
+ self._label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_BUTTON_GREY.get_gdk_color())
+ self.pack_start(self._label)
+ self._label.show()
+
+ alignment_box = gtk.Alignment(xalign=0.5, yalign=0.5)
+ self.pack_start(alignment_box)
+ alignment_box.show()
+
+ self.cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL)
+ alignment_box.add(self.cancel_button)
+ self.cancel_button.show()
+
+ def set_message(self, message):
+ self._label.set_text(message)
+
+ def set_progress(self, fraction):
+ self._progress.props.fraction = fraction
+
+
+class UpdateBox(gtk.VBox):
+
+ def __init__(self, model):
+ gtk.VBox.__init__(self)
+
+ self._model = model
+
+ self.set_spacing(style.DEFAULT_PADDING)
+
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.pack_start(scrolled_window)
+ scrolled_window.show()
+
+ self._update_list = UpdateList(model)
+ self._update_list.props.model.connect('row-changed',
+ self.__row_changed_cb)
+ scrolled_window.add(self._update_list)
+ self._update_list.show()
+
+ bottom_box = gtk.HBox()
+ bottom_box.set_spacing(style.DEFAULT_SPACING)
+ self.pack_start(bottom_box, expand=False)
+ bottom_box.show()
+
+ self._size_label = gtk.Label()
+ self._size_label.props.xalign = 0
+ self._size_label.set_justify(gtk.JUSTIFY_LEFT)
+ bottom_box.pack_start(self._size_label, expand=True)
+ self._size_label.show()
+
+ self.refresh_button = gtk.Button(stock=gtk.STOCK_REFRESH)
+ bottom_box.pack_start(self.refresh_button, expand=False)
+ self.refresh_button.show()
+
+ self.install_button = gtk.Button(_('Install selected'))
+ self.install_button.props.image = Icon(icon_name='emblem-downloads',
+ icon_size=gtk.ICON_SIZE_BUTTON)
+ bottom_box.pack_start(self.install_button, expand=False)
+ self.install_button.show()
+
+ self._update_total_size_label()
+
+ def refresh(self):
+ self._update_list.refresh()
+
+ def __row_changed_cb(self, list_model, path, iterator):
+ self._update_total_size_label()
+ self._update_install_button()
+
+ def _update_total_size_label(self):
+ total_size = 0
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ total_size += row[UpdateListModel.SIZE]
+
+ markup = _('Download size: %s') % _format_size(total_size)
+ self._size_label.set_markup(markup)
+
+ def _update_install_button(self):
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ self.install_button.props.sensitive = True
+ return
+ self.install_button.props.sensitive = False
+
+ def get_bundles_to_update(self):
+ bundles_to_update = []
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ bundles_to_update.append(row[UpdateListModel.BUNDLE_ID])
+ return bundles_to_update
+
+
+class UpdateList(gtk.TreeView):
+
+ def __init__(self, model):
+ list_model = UpdateListModel(model)
+ gtk.TreeView.__init__(self, list_model)
+
+ self.set_reorderable(False)
+ self.set_enable_search(False)
+ self.set_headers_visible(False)
+
+ toggle_renderer = gtk.CellRendererToggle()
+ toggle_renderer.props.activatable = True
+ toggle_renderer.props.xpad = style.DEFAULT_PADDING
+ toggle_renderer.props.indicator_size = style.zoom(26)
+ toggle_renderer.connect('toggled', self.__toggled_cb)
+
+ toggle_column = gtk.TreeViewColumn()
+ toggle_column.pack_start(toggle_renderer)
+ toggle_column.add_attribute(toggle_renderer, 'active',
+ UpdateListModel.SELECTED)
+ self.append_column(toggle_column)
+
+ icon_renderer = CellRendererIcon(self)
+ icon_renderer.props.width = style.STANDARD_ICON_SIZE
+ icon_renderer.props.height = style.STANDARD_ICON_SIZE
+ icon_renderer.props.size = style.STANDARD_ICON_SIZE
+ icon_renderer.props.xpad = style.DEFAULT_PADDING
+ icon_renderer.props.ypad = style.DEFAULT_PADDING
+ icon_renderer.props.stroke_color = style.COLOR_TOOLBAR_GREY.get_svg()
+ icon_renderer.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+
+ icon_column = gtk.TreeViewColumn()
+ icon_column.pack_start(icon_renderer)
+ icon_column.add_attribute(icon_renderer, 'file-name',
+ UpdateListModel.ICON_FILE_NAME)
+ self.append_column(icon_column)
+
+ text_renderer = gtk.CellRendererText()
+
+ description_column = gtk.TreeViewColumn()
+ description_column.pack_start(text_renderer)
+ description_column.add_attribute(text_renderer, 'markup',
+ UpdateListModel.DESCRIPTION)
+ self.append_column(description_column)
+
+ def __toggled_cb(self, cell_renderer, path):
+ row = self.props.model[path]
+ row[UpdateListModel.SELECTED] = not row[UpdateListModel.SELECTED]
+
+ def refresh(self):
+ pass
+
+
+class UpdateListModel(gtk.ListStore):
+
+ BUNDLE_ID = 0
+ SELECTED = 1
+ ICON_FILE_NAME = 2
+ DESCRIPTION = 3
+ SIZE = 4
+
+ def __init__(self, model):
+ gtk.ListStore.__init__(self, str, bool, str, str, int)
+
+ for bundle_update in model.updates:
+ row = [None] * 5
+ row[self.BUNDLE_ID] = bundle_update.bundle.get_bundle_id()
+ row[self.SELECTED] = True
+ row[self.ICON_FILE_NAME] = bundle_update.bundle.get_icon()
+
+ details = _('From version %(current)s to %(new)s (Size: %(size)s)')
+ details = details % \
+ {'current': bundle_update.bundle.get_activity_version(),
+ 'new': bundle_update.version,
+ 'size': _format_size(bundle_update.size)}
+
+ row[self.DESCRIPTION] = '<b>%s</b>\n%s' % \
+ (bundle_update.bundle.get_name(), details)
+
+ row[self.SIZE] = bundle_update.size
+
+ self.append(row)
+
+
+def _format_size(size):
+ """Convert a given size in bytes to a nicer better readable unit"""
+ if size == 0:
+ # TRANS: download size is 0
+ return _('None')
+ elif size < 1024:
+ # TRANS: download size of very small updates
+ return _('1 KB')
+ elif size < 1024 * 1024:
+ # TRANS: download size of small updates, e.g. '250 KB'
+ return locale.format_string(_('%.0f KB'), size / 1024.0)
+ else:
+ # TRANS: download size of updates, e.g. '2.3 MB'
+ return locale.format_string(_('%.1f MB'), size / 1024.0 / 1024)