*.o
*.lo
*.la
+*.ico
+*.exe
+*.exe.manifest
plover/plover.pc
plover-gtk/plover-gtk.pc
setup/resources.rc
setup/setup
+setup/setup.js
+setup/icon*.pnm
update/resources.rc
update/update
+update/update.js
+update/icon*.pnm
+pre-inst/resources.rc
+pre-inst/pre-inst
+pre-inst/icon*.pnm
app-manager/resources.rc
+app-manager/fetch
+app-manager/app-manager
+app-manager/plover-applications*.pgm
+app-manager/plover-applications*.pnm
+app-manager/24x24
+app-manager/48x48
-SUBDIRS=plover setup update plover-gtk app-manager
+SUBDIRS=plover setup update pre-inst plover-gtk app-manager
bin_PROGRAMS=app-manager fetch
app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \
- localmedia.c localmedia.h
+ localmedia.c localmedia.h setup.c update.c
fetch_SOURCES=fetch.c
fetch_LDADD=$(LDADD) $(FETCH_LIBS)
if HAVE_WINDRES
app_manager_SOURCES+=resources.rc app-manager.exe.manifest
endif
+if PLOVER_MINGW
+app_manager_LDFLAGS=-mwindows
+endif
uidir=$(pkgdatadir)
ui_DATA=app-manager.ui
desktopdir=$(datadir)/applications
bigicondir=$(datadir)/icons/hicolor/48x48/apps
bigicon_DATA=48x48/plover-applications.png
+# PLOVER_V_SKIP: Don't echo anything for this command if V=0
+PLOVER_V_SKIP = $(PLOVER_V_SKIP_$(V))
+PLOVER_V_SKIP_ = $(PLOVER_V_SKIP_$(AM_DEFAULT_VERBOSITY))
+PLOVER_V_SKIP_0 = @
+
.rc.$(OBJEXT):
- $(WINDRES) $< $@
+ $(AM_V_GEN)$(WINDRES) $< $@
resources.$(OBJEXT): app-manager.ico app-manager.exe.manifest
plover-applications%.pnm: plover-applications.svg
- rsvg -w $* -h $* -f png $< temp.png
- pngtopnm temp.png | pnmquant 256 > $@
- $(RM) temp.png
+ $(PLOVER_V_SKIP)rsvg -w $* -h $* -f png $< temp.png
+ $(AM_V_GEN)pngtopnm temp.png | pnmquant -quiet 256 > $@
+ $(PLOVER_V_SKIP)$(RM) temp.png
plover-applications%.pgm: plover-applications.svg
- rsvg -w $* -h $* -f png $< temp.png
- pngtopnm -alpha temp.png > $@
- $(RM) temp.png
+ $(PLOVER_V_SKIP)rsvg -w $* -h $* -f png $< temp.png
+ $(AM_V_GEN)pngtopnm -alpha temp.png > $@
+ $(PLOVER_V_SKIP)$(RM) temp.png
24x24/plover-applications.png: plover-applications.svg
- mkdir -p 24x24
- rsvg -w 24 -h 24 -f png $< $@
+ $(PLOVER_V_SKIP)mkdir -p 24x24
+ $(AM_V_GEN)rsvg -w 24 -h 24 -f png $< $@
48x48/plover-applications.png: plover-applications.svg
- mkdir -p 48x48
- rsvg -w 48 -h 48 -f png $< $@
+ $(PLOVER_V_SKIP)mkdir -p 48x48
+ $(AM_V_GEN)rsvg -w 48 -h 48 -f png $< $@
app-manager.ico: plover-applications16.pnm plover-applications16.pgm \
plover-applications22.pnm plover-applications22.pgm \
plover-applications32.pnm plover-applications32.pgm \
plover-applications46.pnm plover-applications46.pgm
- ppmtowinicon -andpgms -output=$@ $^
+ $(AM_V_GEN)ppmtowinicon -andpgms -output=$@ $^
clean-local:
-rm -rf 24x24 48x48
#include "config.h"
#include <stdlib.h>
#include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#endif /* WIN32 */
+#include <lua.h>
#include <glib.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
-#include <plover-gtk/packageset.h>
+#include <whelk/whelk.h>
+#include <plover/packageset.h>
+#include <plover-gtk/stockicons.h>
#include "app-manager.h"
#include "localmedia.h"
+LUALIB_API int luaopen_posix(lua_State *L);
+
#define LOGO_NAME "plover-applications"
GtkBuilder *ui;
}
}
+#if 0
/* Checks whether a loader for SVG files has been registered
* with GdkPixbuf.
*/
icon_set=gtk_icon_factory_lookup_default(LOGO_NAME);
gtk_window_set_default_icon_name(LOGO_NAME);
}
+#endif
+
+static void install_icons(void)
+{
+ GtkIconSet *icon_set;
+ plover_icons_add_to_stock("apps",LOGO_NAME);
+ icon_set=gtk_icon_factory_lookup_default(LOGO_NAME);
+ gtk_window_set_default_icon_name(LOGO_NAME);
+}
int main(int argc,char **argv)
{
GError *err=0;
GtkWidget *w;
gchar *s,*contents;
+ gchar *setup_base=NULL,*update_base=NULL;
gsize len;
PloverPackageSet *set;
+ GSList *objects,*lnk;
+ gboolean started;
GOptionEntry options[]={
+ {"setup",0,0,G_OPTION_ARG_FILENAME,&setup_base,
+ "Setup from installation media","path"},
+ {"update",0,0,G_OPTION_ARG_FILENAME,&update_base,
+ "Update from upgrade media","path"},
{NULL}
};
+#ifdef WIN32
+ /*
+ * app-manager is normally a GUI application, but rpm scripts may well
+ * call console applications and it looks ugly if console windows keep
+ * popping up. Avoid this by allocating our own console and hiding it.
+ * Note:
+ * - If app-manager is a console application (typically for debugging),
+ * then skip this step.
+ * - Call ShowWindow twice to negate special handling on first call.
+ */
+ if (!GetConsoleWindow())
+ {
+ AllocConsole();
+ ShowWindow(GetConsoleWindow(),SW_HIDE);
+ ShowWindow(GetConsoleWindow(),SW_HIDE);
+ }
+#endif
+ razor_set_lua_loader("posix",luaopen_posix);
+ razor_set_lua_loader("whelk",luaopen_whelk);
if (!gtk_init_with_args(&argc,&argv,NULL,options,NULL,&err))
{
- g_printerr("%s",err->message);
- exit(0);
+ g_printerr("%s\n",err->message);
+ exit(1);
+ }
+ if (setup_base && update_base)
+ {
+ g_printerr("--setup and --update are mutually exclusive\n");
+ exit(1);
}
#ifdef WIN32
prefix=g_win32_get_package_installation_directory_of_module(NULL);
gtk_builder_connect_signals(ui,NULL);
gtk_link_button_set_uri_hook(show_uri,NULL,NULL);
installed=GTK_TREE_MODEL(plover_package_store_new());
- set=plover_package_set_new_from_installed("",NULL);
- if (set)
+ set=plover_package_set_new();
+ (void)plover_package_set_open(set,"",TRUE,NULL);
+ plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set);
+ if (plover_package_set_get_no_details(set))
{
- plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set);
- if (plover_package_set_get_no_details(set))
- {
- w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles"));
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),TRUE);
- }
+ w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles"));
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),TRUE);
}
applications=plover_applications_model_new(installed);
set_package_model(applications);
- gtk_main();
- g_object_unref(ui);
+ if (setup_base)
+ started=setup(set,setup_base);
+ else if (update_base)
+ started=update(set,update_base);
+ else
+ {
+ w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
+ gtk_widget_show(w);
+ started=TRUE;
+ }
+ if (started)
+ gtk_main();
+ g_clear_object(&set);
+ objects=gtk_builder_get_objects(ui);
+ for(lnk=objects;lnk;lnk=lnk->next)
+ if (GTK_IS_WIDGET(lnk->data) &&
+ gtk_widget_is_toplevel(GTK_WIDGET(lnk->data)))
+ gtk_widget_destroy(GTK_WIDGET(lnk->data));
+ g_slist_free(objects);
+ g_clear_object(&ui);
+ g_clear_object(&installed);
+ g_clear_object(&applications);
+ g_clear_object(&location);
+ g_clear_object(&local_media);
if (relocations)
razor_relocations_destroy(relocations);
g_free(prefix);
+ g_free(setup_base);
+ g_free(update_base);
exit(0);
}
{
show_busy_cursor(TRUE);
path=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
- set=plover_package_set_new_from_repository(path,relocations,&err);
+ set=plover_package_set_new_from_yum(path,relocations,&err);
if (set)
{
if (!location)
GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
gtk_show_about_dialog(GTK_WINDOW(w),"name",PACKAGE_NAME,
"version",PACKAGE_VERSION,"comments","Application Manager",
- "copyright","Copyright © 2010 J. Ali Harlow","logo-icon-name",LOGO_NAME,
+ "copyright","Copyright © 2010, 2014 J. Ali Harlow",
+ "logo-icon-name",LOGO_NAME,
NULL);
}
#include <razor.h>
#include <gtk/gtk.h>
-#include <plover-gtk/package.h>
+#include <plover/package.h>
extern GtkBuilder *ui;
extern struct razor_relocations *relocations;
GtkTreeModel *plover_applications_model_new(GtkTreeModel *installed);
void set_package_model(GtkTreeModel *model);
PloverPackage *get_active_package(void);
+gboolean setup(PloverPackageSet *current,const char *base);
+gboolean update(PloverPackageSet *current,const char *base);
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy toplevel-contextual -->
+ <!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="MainWindow">
- <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="title" translatable="yes">Application Manager</property>
<property name="default_width">600</property>
</packing>
</child>
<child>
- <object class="GtkAlignment" id="alignment2">
+ <object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">6</property>
<property name="right_padding">6</property>
#include <glib.h>
#include <gtk/gtk.h>
#include <plover-gtk/packagestore.h>
+#include <plover-gtk/packagefilestore.h>
#include "app-manager.h"
#ifdef WIN32
gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&package,-1);
if (package)
{
- file_store=GTK_TREE_MODEL(plover_package_get_file_store(package));
+ file_store=
+ GTK_TREE_MODEL(plover_package_file_store_new_from_package(package));
if (gtk_tree_model_get_iter_first(file_store,&fi))
{
do
g_free(name);
} while(!visible && gtk_tree_model_iter_next(file_store,&fi));
}
+ g_object_unref(file_store);
}
g_object_unref(package);
return visible;
const char *name;
char *install_root;
struct razor_set *set;
- struct razor_atomic *atomic;
+ struct razor_error *error=NULL;
struct razor_package *package;
struct razor_package_iterator *pi;
struct razor_file_iterator *fi;
install_root=getenv("RAZOR_ROOT");
if (!install_root)
install_root="";
- atomic=razor_atomic_open("Query packages");
- set=razor_root_open_read_only(install_root,atomic);
+ set=razor_root_open_read_only(install_root,&error);
if (set)
{
pi=razor_package_iterator_create(set);
razor_package_iterator_destroy(pi);
razor_set_unref(set);
}
- razor_atomic_destroy(atomic);
+ if (error)
+ razor_error_free(error);
return retval;
}
#endif
if (path)
{
- set=plover_package_set_new_from_repository(path,relocations,NULL);
+ set=plover_package_set_new_from_yum(path,relocations,NULL);
if (set)
{
g_object_set_data(G_OBJECT(mount),"plover-local-media-set",set);
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
-#include <plover-gtk/package.h>
-#include <plover-gtk/packageset.h>
+#include <plover/package.h>
+#include <plover/packageset.h>
#include <plover-gtk/packagestore.h>
#include <plover-gtk/packagefilestore.h>
#include "app-manager.h"
const char *text,*t;
GtkWidget *w;
GtkTextBuffer *buf;
+ PloverPackageFileStore *store;
buf=GTK_TEXT_BUFFER(gtk_builder_get_object(ui,"description"));
if (package)
{
{
gtk_widget_hide(w);
w=GTK_WIDGET(gtk_builder_get_object(ui,"Files"));
- gtk_tree_view_set_model(GTK_TREE_VIEW(w),
- GTK_TREE_MODEL(plover_package_get_file_store(package)));
+ store=plover_package_file_store_new_from_package(package);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(w),GTK_TREE_MODEL(store));
+ g_object_unref(store);
}
else
{
#include <winver.h>
#include <winuser.h>
+#pragma code_page(65001)
+
MAINICON ICON "app-manager.ico"
VS_VERSION_INFO VERSIONINFO
VALUE "Translation",0x809,0x4B0
}
}
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app-manager.exe.manifest"
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <plover/plover.h>
+#include <plover/transaction.h>
+#include <plover/packageset.h>
+#include <plover-gtk/transactionhelper.h>
+#include "app-manager.h"
+
+gboolean setup(PloverPackageSet *installed,const char *base)
+{
+ gchar *s;
+ const char *prefix;
+ GError *error=NULL;
+ static PloverTransactionHelper *helper=NULL;
+ if (!helper)
+ {
+ helper=plover_transaction_helper_new(ui);
+ plover_transaction_helper_set_installed(helper,installed);
+ plover_transaction_helper_set_base(helper,base);
+ prefix=plover_transaction_helper_get_prefix(helper,&error);
+ if (error)
+ g_clear_error(&error);
+ else
+ {
+ s=g_strconcat(prefix?prefix:"","/var/log/setup",NULL);
+ plover_log_open(s);
+ g_free(s);
+ }
+ plover_transaction_helper_set_check_vendor(helper,TRUE);
+ g_signal_connect(helper,"close",G_CALLBACK(gtk_main_quit),NULL);
+ }
+ if (!plover_transaction_helper_get_visible(helper))
+ {
+ if (!plover_transaction_helper_install_group(helper,"base",&error))
+ {
+ if (g_error_matches(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK))
+ {
+ g_error_free(error);
+ error=g_error_new_literal(PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK,
+ "All packages already installed");
+ plover_transaction_helper_set_error(helper,error,
+ "Software installation");
+ }
+ else if (g_error_matches(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET))
+ {
+ g_error_free(error);
+ error=g_error_new_literal(PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
+ "Software cannot be installed because of missing updates. "
+ "Installing all updates first should resolve this problem");
+ plover_transaction_helper_set_error(helper,error,
+ "Software installation failed");
+ }
+ else
+ plover_transaction_helper_set_error(helper,error,
+ "Software installation failed");
+ g_error_free(error);
+ }
+ }
+ plover_transaction_helper_present(helper);
+ return TRUE;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <plover/plover.h>
+#include <plover/transaction.h>
+#include <plover/packageset.h>
+#include <plover-gtk/transactionhelper.h>
+#include "app-manager.h"
+
+gboolean update(PloverPackageSet *installed,const char *base)
+{
+ gchar *s;
+ const char *prefix;
+ GError *error=NULL;
+ static PloverTransactionHelper *helper=NULL;
+ if (!helper)
+ {
+ helper=plover_transaction_helper_new(ui);
+ plover_transaction_helper_set_installed(helper,installed);
+ plover_transaction_helper_set_base(helper,base);
+ prefix=plover_transaction_helper_get_prefix(helper,&error);
+ if (error)
+ g_clear_error(&error);
+ else
+ {
+ s=g_strconcat(prefix?prefix:"","/var/log/update",NULL);
+ plover_log_open(s);
+ g_free(s);
+ }
+ plover_transaction_helper_set_check_vendor(helper,TRUE);
+ g_signal_connect(helper,"close",G_CALLBACK(gtk_main_quit),NULL);
+ }
+ if (!plover_transaction_helper_get_visible(helper))
+ {
+ if (!plover_transaction_helper_update(helper,&error))
+ {
+ if (g_error_matches(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK))
+ {
+ g_error_free(error);
+ error=g_error_new_literal(PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK,
+ "All relevant updates already applied");
+ plover_transaction_helper_set_error(helper,error,
+ "Software update");
+ }
+ else if (g_error_matches(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET))
+ {
+ g_error_free(error);
+ error=g_error_new_literal(PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
+ "Updates cannot be applied because some earlier updates are "
+ "missing. Installing updates in sequence should resolve this "
+ "problem");
+ plover_transaction_helper_set_error(helper,error,
+ "Software update failed");
+ }
+ else
+ plover_transaction_helper_set_error(helper,error,
+ "Software update failed");
+ g_error_free(error);
+ }
+ }
+ plover_transaction_helper_present(helper);
+ return TRUE;
+}
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_INIT([plover],[0.4.3],[ali@juiblex.co.uk])
+AC_INIT([plover],[0.4.50],[ali@juiblex.co.uk])
AC_PREREQ(2.59)
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_SRCDIR([plover/plover.h])
setup/resources.rc
update/Makefile
update/resources.rc
+pre-inst/Makefile
+pre-inst/resources.rc
app-manager/Makefile
app-manager/resources.rc
])
PLOVER_MSWIN_MANIFEST([setup/setup.exe.manifest:setup/manifest.xml.in
update/update.exe.manifest:update/manifest.xml.in
+pre-inst/pre-inst.exe.manifest:pre-inst/manifest.xml.in
app-manager/app-manager.exe.manifest:app-manager/manifest.xml.in
])
AM_INIT_AUTOMAKE(no-define)
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
case $VERSION in
*.*.*)
AC_SUBST(PLOVER_MAJOR_VERSION,[[`echo $VERSION | sed 's/\..*//'`]])
AC_CANONICAL_HOST
AC_SUBST(HOST_OS,$host_os)
AC_SUBST(HOST_CPU,$host_cpu)
+case $host_os in
+ mingw*)
+ host_mingw="yes"
+ ;;
+ *)
+ host_mingw=""
+ ;;
+esac
+AM_CONDITIONAL(PLOVER_MINGW,[test -n "$host_mingw"])
# libtool versioning for libplover. For a release one of the following
# must apply:
# increment CURRENT and set AGE and REVISION to 0.
# - If the interface is the same as the previous version, increment REVISION.
#
-lt_current=2
+lt_current=3
lt_revision=0
lt_age=0
LIBPLOVER_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age"
##################################################
# Checks for libraries.
##################################################
+PKG_CHECK_MODULES(WHELK,[whelk])
PKG_CHECK_MODULES(RAZOR,[razor >= 0.5.4],[:],[RAZOR_LIBS=-lrazor])
PKG_CHECK_MODULES(EXPAT,[expat],[:],[EXPAT_LIBS=-lexpat])
PKG_CHECK_MODULES(ZLIB,[zlib],[:],[ZLIB_LIBS=-lz])
PKG_CHECK_MODULES(GIO,[gio-2.0])
PKG_CHECK_MODULES(GTK,[gtk+-2.0])
PKG_CHECK_MODULES(GMODULE_EXPORT,[gmodule-export-2.0])
-LIBPLOVER_CFLAGS="$RAZOR_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS"
-LIBPLOVER_LIBS="$RAZOR_LIBS $EXPAT_LIBS $ZLIB_LIBS"
+LIBPLOVER_CFLAGS="$RAZOR_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $GIO_CFLAGS"
+LIBPLOVER_LIBS="$RAZOR_LIBS $EXPAT_LIBS $ZLIB_LIBS $GIO_LIBS"
AC_SUBST(LIBPLOVER_CFLAGS)
AC_SUBST(LIBPLOVER_LIBS)
PLOVER_GTK_CFLAGS="$GTK_CFLAGS $RAZOR_CFLAGS"
PLOVER_GTK_LIBS="$GTK_LIBS $RAZOR_LIBS"
AC_SUBST(PLOVER_GTK_CFLAGS)
AC_SUBST(PLOVER_GTK_LIBS)
-GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $GIO_CFLAGS $PLOVER_GTK_CFLAGS $LIBPLOVER_CFLAGS"
-GUI_LIBS="$GMODULE_EXPORT_LIBS $GIO_LIBS $PLOVER_GTK_LIBS $LIBPLOVER_LIBS"
+save_LIBS="$LIBS"
+AC_SEARCH_LIBS([crypt],[crypt])
+GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $WHELK_CFLAGS $PLOVER_GTK_CFLAGS \
+ $LIBPLOVER_CFLAGS"
+GUI_LIBS="-llua-posix $GMODULE_EXPORT_LIBS $WHELK_LIBS $PLOVER_GTK_LIBS \
+ $LIBPLOVER_LIBS $LIBS"
+LIBS="$save_LIBS"
AC_SUBST(GUI_CFLAGS)
AC_SUBST(GUI_LIBS)
save_PKG_CONFIG="$PKG_CONFIG"
PKG_CONFIG="$PKG_CONFIG --static"
-PKG_CHECK_MODULES(SETUP,[whelk])
+PKG_CHECK_MODULES(SETUP,[whelk razor >= 0.5.4 expat zlib gio-2.0])
+if test -n "$host_mingw"; then
+ # Hack: -liconv is required for mingw. This probably stems from our use of
+ # libiconv rather than win-iconv that Fedora uses, but should be addressed
+ # somewhere in the stack below us.
+ SETUP_LIBS="$SETUP_LIBS -liconv"
+fi
PKG_CONFIG="$save_PKG_CONFIG"
save_LIBS="$LIBS"
AC_SEARCH_LIBS([crypt],[crypt])
-SETUP_LIBS="-llua-posix $SETUP_LIBS $RAZOR_LIBS $LIBS"
-SETUP_CFLAGS="$SETUP_CFLAGS $RAZOR_CFLAGS"
+SETUP_LIBS="-llua-posix $SETUP_LIBS $LIBS"
+SETUP_CFLAGS="$SETUP_CFLAGS"
AC_SUBST(SETUP_LIBS)
AC_SUBST(SETUP_CFLAGS)
LIBS="$save_LIBS"
##################################################
# Checks for library functions.
##################################################
-AC_CHECK_FUNCS_ONCE([fchdir])
+AC_CHECK_FUNCS_ONCE([fchdir fpathconf dirfd])
##################################################
# Checks for processor independent files.
-AM_CFLAGS=-g $(PLOVER_GTK_CFLAGS)
+AM_CFLAGS=-g $(PLOVER_GTK_CFLAGS) -DPLOVER_DATADIR=\""$(pkgdatadir)"\"
LIBS=../plover/libplover.la $(PLOVER_GTK_LIBS)
INCLUDES=-I$(top_srcdir)
AM_LDFLAGS=-no-undefined -version-info $(PLOVER_GTK_LT_VERSION_INFO)
-pkginclude_HEADERS=error.h package.h packageset.h packagestore.h \
- packagefilestore.h
+uidir=$(pkgdatadir)
+ui_DATA=software-installation.ui
+
+pkginclude_HEADERS=\
+ transactionhelper.h packagestore.h packagefilestore.h stockicons.h
lib_LTLIBRARIES=libplover-gtk.la
libplover_gtk_la_SOURCES=$(pkginclude_HEADERS) \
- error.c package.c packageset.c packagestore.c \
- packagefilestore.c
+ transactionhelper.c packagestore.c packagefilestore.c stockicons.c
pkgconfigdir=$(libdir)/pkgconfig
pkgconfig_DATA=plover-gtk.pc
+
+EXTRA_DIST=software-installation.ui
+++ /dev/null
-/*
- * Copyright (C) 2010 J. Ali Harlow <ali@juiblex.co.uk>
- *
- * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include <stdlib.h>
-#include <glib.h>
-
-GQuark plover_razor_error_quark(void)
-{
- static GQuark quark=0;
- if (!quark)
- quark=g_quark_from_static_string("plover-razor-error-quark");
- return quark;
-}
-
+++ /dev/null
-#ifndef __PLOVER_ERROR_H__
-#define __PLOVER_ERROR_H__
-
-#define PLOVER_RAZOR_ERROR plover_razor_error_quark()
-
-typedef enum {
- PLOVER_RAZOR_ERROR_FAILED
-} PloverRazorError;
-
-GQuark plover_razor_error_quark(void);
-
-#endif /* __PLOVER_ERROR_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2010 J. Ali Harlow <ali@juiblex.co.uk>
- *
- * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include <stdlib.h>
-#include <string.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-#include <razor.h>
-#include "plover-gtk/package.h"
-
-G_DEFINE_TYPE(PloverPackage,plover_package,G_TYPE_OBJECT);
-
-typedef struct _PloverPackagePrivate {
- struct razor_set *set;
- struct razor_package *pkg;
- PloverPackageFileStore *file_store;
-} PloverPackagePrivate;
-
-#define PLOVER_PACKAGE_GET_PRIVATE(obj)\
- G_TYPE_INSTANCE_GET_PRIVATE(obj,\
- PLOVER_TYPE_PACKAGE,PloverPackagePrivate)
-
-enum {
- CHANGED=0,
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS];
-
-static void plover_package_dispose(GObject *obj)
-{
- PloverPackagePrivate *priv=PLOVER_PACKAGE_GET_PRIVATE(obj);
- if (priv->file_store)
- {
- g_object_unref(priv->file_store);
- priv->file_store=NULL;
- }
- if (G_OBJECT_CLASS(plover_package_parent_class)->dispose)
- G_OBJECT_CLASS(plover_package_parent_class)->dispose(obj);
-}
-
-static void plover_package_class_init(PloverPackageClass *klass)
-{
- GObjectClass *oclass=G_OBJECT_CLASS(klass);
- oclass->dispose=plover_package_dispose;
- g_type_class_add_private(klass,sizeof(PloverPackagePrivate));
- signals[CHANGED]=g_signal_newv("changed",
- G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
- g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
-}
-
-static void plover_package_init(PloverPackage *package)
-{
-}
-
-PloverPackage *plover_package_new(struct razor_set *set,
- struct razor_package *pkg)
-{
- PloverPackage *package;
- PloverPackagePrivate *priv;
- package=g_object_new(PLOVER_TYPE_PACKAGE,NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- priv->set=set;
- priv->pkg=pkg;
- return package;
-}
-
-const char *plover_package_get_name(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *name=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_NAME,&name,
- RAZOR_DETAIL_LAST);
- return name;
-}
-
-const char *plover_package_get_summary(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *summary=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_SUMMARY,&summary,
- RAZOR_DETAIL_LAST);
- return summary;
-}
-
-const char *plover_package_get_version(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *version=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_VERSION,&version,
- RAZOR_DETAIL_LAST);
- return version;
-}
-
-const char *plover_package_get_license(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *license=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_LICENSE,&license,
- RAZOR_DETAIL_LAST);
- return license;
-}
-
-const char *plover_package_get_arch(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *arch=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_ARCH,&arch,
- RAZOR_DETAIL_LAST);
- return arch;
-}
-
-const char *plover_package_get_description(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *description=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_DESCRIPTION,
- &description,RAZOR_DETAIL_LAST);
- return description;
-}
-
-const char *plover_package_get_URL(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- const char *URL=NULL;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_URL,&URL,
- RAZOR_DETAIL_LAST);
- return URL;
-}
-
-GdkPixbuf *plover_package_get_icon(PloverPackage *package)
-{
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- return NULL;
-}
-
-PloverPackageFileStore *plover_package_get_file_store(PloverPackage *package)
-{
- PloverPackagePrivate *priv;
- struct razor_file_iterator *iter;
- g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
- priv=PLOVER_PACKAGE_GET_PRIVATE(package);
- if (!priv->file_store)
- {
- iter=razor_file_iterator_create(priv->set,priv->pkg,0);
- priv->file_store=plover_package_file_store_new(iter);
- razor_file_iterator_destroy(iter);
- }
- return priv->file_store;
-}
gtk_tree_path_free(path);
return store;
}
+
+PloverPackageFileStore *
+ plover_package_file_store_new_from_package(PloverPackage *package)
+{
+ PloverPackageFileStore *store;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ struct razor_file_iterator *iter;
+ iter=plover_package_file_iterator_create(package,FALSE);
+ store=GTK_TREE_MODEL(plover_package_file_store_new(iter));
+ razor_file_iterator_destroy(iter);
+ return store;
+}
#define __PLOVER_PACKAGE_FILE_STORE_H__
#include <glib-object.h>
+#include <plover/package.h>
#include <razor.h>
G_BEGIN_DECLS
GType plover_package_file_store_get_type(void) G_GNUC_CONST;
PloverPackageFileStore *
plover_package_file_store_new(struct razor_file_iterator *files);
+PloverPackageFileStore *
+ plover_package_file_store_new_from_package(PloverPackage *package);
G_END_DECLS
+++ /dev/null
-/*
- * Copyright (C) 2010-2012 J. Ali Harlow <ali@juiblex.co.uk>
- *
- * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <glib-object.h>
-#include <razor.h>
-#include "plover/plover.h"
-#include "plover-gtk/error.h"
-#include "plover-gtk/packageset.h"
-#include "plover-gtk/package.h"
-
-G_DEFINE_TYPE(PloverPackageSet,plover_package_set,G_TYPE_OBJECT);
-
-typedef struct _PloverPackageSetPrivate {
- struct razor_root *root;
- struct razor_set *set;
- GSList *packages;
- int no_details;
-} PloverPackageSetPrivate;
-
-#define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\
- G_TYPE_INSTANCE_GET_PRIVATE(obj,\
- PLOVER_TYPE_PACKAGE_SET,\
- PloverPackageSetPrivate)
-
-enum {
- CHANGED=0,
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS];
-
-static void plover_package_set_finalize(GObject *obj)
-{
- PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
- if (priv->root)
- razor_root_close(priv->root);
- if (G_OBJECT_CLASS(plover_package_set_parent_class)->finalize)
- G_OBJECT_CLASS(plover_package_set_parent_class)->finalize(obj);
-}
-
-static void plover_package_set_dispose(GObject *obj)
-{
- PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
- if (priv->set)
- {
- razor_set_unref(priv->set);
- priv->set=NULL;
- }
- if (G_OBJECT_CLASS(plover_package_set_parent_class)->dispose)
- G_OBJECT_CLASS(plover_package_set_parent_class)->dispose(obj);
-}
-
-static void plover_package_set_class_init(PloverPackageSetClass *klass)
-{
- GObjectClass *oclass=G_OBJECT_CLASS(klass);
- oclass->finalize=plover_package_set_finalize;
- oclass->dispose=plover_package_set_dispose;
- g_type_class_add_private(klass,sizeof(PloverPackageSetPrivate));
- signals[CHANGED]=g_signal_newv("changed",
- G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
- g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
-}
-
-static void plover_package_set_init(PloverPackageSet *set)
-{
- PloverPackageSetPrivate *priv;
- priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
- priv->no_details=-1;
-}
-
-PloverPackageSet *plover_package_set_new(void)
-{
- return g_object_new(PLOVER_TYPE_PACKAGE_SET,NULL);
-}
-
-PloverPackageSet *plover_package_set_new_from_installed(const char *root,
- GError **err)
-{
- PloverPackageSet *set;
- PloverPackageSetPrivate *priv;
- struct razor_error *error=NULL;
- set=plover_package_set_new();
- priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
- priv->root=razor_root_open(root,&error);
- if (!priv->root)
- {
- g_set_error_literal(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
- razor_error_get_msg(error));
- razor_error_free(error);
- g_object_unref(set);
- return NULL;
- }
- priv->set=razor_set_ref(razor_root_get_system_set(priv->root));
- if (!priv->set)
- {
- g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
- "Failed to get system set from %s",root);
- g_object_unref(set);
- return NULL;
- }
- return set;
-}
-
-PloverPackageSet *plover_package_set_new_from_repository(const char *base,
- struct razor_relocations *relocations,GError **err)
-{
-#if HAVE_FCHDIR
- int fd;
-#else
- size_t wd_len;
- char *wd;
-#endif
- gchar *s;
- struct razor_set *reloc;
- struct razor_error *error=NULL;
- PloverPackageSet *set;
- PloverPackageSetPrivate *priv;
- set=plover_package_set_new();
- priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
-#if HAVE_FCHDIR
- fd=open(".",O_RDONLY);
-#else
- wd_len=32;
- wd=malloc(wd_len);
- while (!getcwd(wd,wd_len) && errno==ERANGE)
- {
- free(wd);
- wd_len*=2;
- wd=malloc(wd_len);
- }
-#endif
- s=g_build_filename(base,"repodata",NULL);
- if (chdir(s)<0)
- {
- g_set_error(err,G_FILE_ERROR,g_file_error_from_errno(errno),
- "%s: %s",s,g_strerror(errno));
- g_object_unref(set);
-#if HAVE_FCHDIR
- close(fd);
-#else
- free(wd);
-#endif
- return NULL;
- }
- g_free(s);
- priv->set=plover_razor_set_create_from_yum("..");
-#if HAVE_FCHDIR
- (void)fchdir(fd);
- close(fd);
-#else
- chdir(wd);
- free(wd);
-#endif
- if (priv->set && relocations)
- {
- reloc=plover_relocate_packages(priv->set,base,relocations,&error);
- if (!reloc)
- {
- g_set_error_literal(err,PLOVER_RAZOR_ERROR,
- PLOVER_RAZOR_ERROR_FAILED,razor_error_get_msg(error));
- razor_error_free(error);
- g_object_unref(set);
- return NULL;
- }
- razor_set_unref(priv->set);
- priv->set=reloc;
- }
- if (!priv->set)
- {
- g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
- "Failed to create package set from repository %s",base);
- g_object_unref(set);
- return NULL;
- }
- return set;
-}
-
-GSList *plover_package_set_get_packages(PloverPackageSet *set)
-{
- struct razor_package_iterator *iter;
- struct razor_package *pkg;
- PloverPackageSetPrivate *priv;
- PloverPackage *package;
- g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
- priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
- if (priv->set && !priv->packages)
- {
- iter=razor_package_iterator_create(priv->set);
- while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_LAST))
- {
- package=plover_package_new(priv->set,pkg);
- priv->packages=g_slist_prepend(priv->packages,package);
- }
- razor_package_iterator_destroy(iter);
- }
- return priv->packages;
-}
-
-/*
- * Some versions of razor have a bug which causes all detail strings
- * to be discarded. If such a version of razor is used to install or
- * update a package, then all the detail strings for the installed
- * set will be lost. This function tests for this condition and can
- * be used to present something more useful than blank details.
- */
-
-gboolean plover_package_set_get_no_details(PloverPackageSet *set)
-{
- PloverPackageSetPrivate *priv;
- PloverPackage *package;
- GSList *packages,*link;
- g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
- priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
- if (priv->no_details<0)
- {
- packages=plover_package_set_get_packages(set);
- if (packages)
- {
- priv->no_details=0;
- for(link=packages;link;link=link->next)
- {
- package=link->data;
- priv->no_details+=2;
- if (*plover_package_get_summary(package))
- priv->no_details--;
- if (*plover_package_get_license(package))
- priv->no_details--;
- if (*plover_package_get_description(package))
- priv->no_details--;
- if (*plover_package_get_URL(package))
- priv->no_details--;
- }
- if (priv->no_details<0) /* More than 50% of strings present */
- priv->no_details=0;
- }
- }
- return priv->no_details>0;
-}
+++ /dev/null
-#ifndef __PLOVER_PACKAGE_SET_H__
-#define __PLOVER_PACKAGE_SET_H__
-
-#include <razor.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define PLOVER_TYPE_PACKAGE_SET plover_package_set_get_type()
-#define PLOVER_PACKAGE_SET(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\
- PLOVER_TYPE_PACKAGE_SET,PloverPackageSet)
-#define PLOVER_PACKAGE_SET_CLASS(klass)\
- G_TYPE_CHECK_CLASS_CAST(klass,\
- PLOVER_TYPE_PACKAGE_SET,\
- PloverPackageSetClass)
-#define PLOVER_IS_PACKAGE_SET(obj)\
- G_TYPE_CHECK_INSTANCE_TYPE(obj,\
- PLOVER_TYPE_PACKAGE_SET)
-#define PLOVER_IS_PACKAGE_SET_CLASS(klass)\
- G_TYPE_CHECK_CLASS_TYPE(obj,\
- PLOVER_TYPE_PACKAGE_SET)
-#define PLOVER_PACKAGE_SET_GET_CLASS(obj)\
- G_TYPE_INSTANCE_GET_CLASS(obj,\
- PLOVER_TYPE_PACKAGE_SET,\
- PloverPackageSetClass)
-
-typedef struct _PloverPackageSet {
- GObject parent_instance;
-} PloverPackageSet;
-
-typedef struct _PloverPackageSetClass {
- GObjectClass parent_class;
-} PloverPackageSetClass;
-
-GType plover_package_set_get_type(void) G_GNUC_CONST;
-PloverPackageSet *plover_package_set_new(void);
-PloverPackageSet *plover_package_set_new_from_installed(const char *root,
- GError **err);
-PloverPackageSet *plover_package_set_new_from_repository(const char *base,
- struct razor_relocations *relocations,GError **err);
-GSList *plover_package_set_get_packages(PloverPackageSet *set);
-gboolean plover_package_set_get_no_details(PloverPackageSet *set);
-
-G_END_DECLS
-
-#endif /* __PLOVER_PACKAGE_SET_H__ */
#include <gtk/gtk.h>
#include <razor.h>
#include "plover/plover.h"
-#include "plover-gtk/package.h"
+#include "plover/package.h"
#include "plover-gtk/packagestore.h"
#define VALID_ITER(iter,store) ((iter) && (iter)->user_data && \
char *s;
PloverPackageStore *store=(PloverPackageStore *)tree_model;
PloverPackage *package;
+ GInputStream *stream;
+ GdkPixbuf *icon;
g_return_if_fail(column>=0 && column<PLOVER_PACKAGE_STORE_NO_COLUMNS);
g_return_if_fail(VALID_ITER(iter,store));
package=PLOVER_PACKAGE(g_sequence_get(iter->user_data));
case PLOVER_PACKAGE_STORE_INSTALLED_COLUMN:
break;
case PLOVER_PACKAGE_STORE_ICON_COLUMN:
- g_value_set_object(value,plover_package_get_icon(package));
+ stream=plover_package_read_icon(package,NULL);
+ if (stream)
+ {
+ icon=gdk_pixbuf_new_from_stream(stream,NULL,NULL);
+ g_object_unref(stream);
+ }
+ else
+ icon=NULL;
+ g_value_set_object(value,icon);
break;
case PLOVER_PACKAGE_STORE_NAME_COLUMN:
g_value_set_string(value,plover_package_get_name(package));
#define __PLOVER_PACKAGE_STORE_H__
#include <glib-object.h>
-#include <plover-gtk/packageset.h>
+#include <plover/packageset.h>
G_BEGIN_DECLS
--- /dev/null
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkAssistant" id="SoftwareInstallation">
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Software Installation</property>
+ <signal name="delete_event" handler="gtk_main_quit"/>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkLabel" id="SIIntroduction">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">16</property>
+ <property name="ypad">16</property>
+ <property name="label" translatable="yes"><b>Welcome to the Installation Assistant</b>
+
+The Installation Assistant will install the software.
+To continue, click Forward.</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="page_type">intro</property>
+ <property name="title" translatable="yes">Software Installation</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="SIConfirm">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkVBox" id="SIIncompatibleInstallation">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="SIIncompatibleInstallationLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">16</property>
+ <property name="ypad">16</property>
+ <property name="label" translatable="yes"><b>Incompatible Installation</b>
+
+The existing installation is not from %s
+In order to continue, all the existing packages must be removed.</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="left_padding">16</property>
+ <property name="right_padding">16</property>
+ <child>
+ <object class="GtkCheckButton" id="SIRemoveExisting">
+ <property name="label" translatable="yes">Remove all existing packages</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="SISummaryOfWork">
+ <property name="width_request">450</property>
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">16</property>
+ <property name="ypad">16</property>
+ <property name="label" translatable="yes"><b>Installation Summary</b>
+
+Packages to be installed or updated: ... plus dependencies.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="page_type">confirm</property>
+ <property name="title" translatable="yes">Software Installation (2 of 4)</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="SIProgress">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">16</property>
+ <property name="ypad">16</property>
+ <property name="label" translatable="yes"><b>Installing the Software</b>
+
+Please wait while the Installation Assistant installs the software.
+This may take several minutes.</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="bottom_padding">16</property>
+ <property name="left_padding">16</property>
+ <property name="right_padding">16</property>
+ <child>
+ <object class="GtkProgressBar" id="SIProgressBar">
+ <property name="visible">True</property>
+ <property name="activity_mode">True</property>
+ <property name="show_text">True</property>
+ <property name="text" translatable="yes">Unpacking files</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="page_type">progress</property>
+ <property name="title" translatable="yes">Software Installation (3 of 4)</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="SISummary">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">16</property>
+ <property name="ypad">16</property>
+ <property name="label" translatable="yes"><b>Installation Assistant Completed</b>
+
+The Installation Assistant has successfully completed.
+Click Close to exit the Assistant.</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="page_type">summary</property>
+ <property name="title" translatable="yes">Software Installation (4 of 4)</property>
+ </packing>
+ </child>
+ </object>
+</interface>
--- /dev/null
+/*
+ * Copyright (C) 2010 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#ifdef WIN32
+#include <windows.h>
+#endif /* WIN32 */
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <plover-gtk/stockicons.h>
+
+/* Checks whether a loader for SVG files has been registered
+ * with GdkPixbuf.
+ */
+static gboolean plover_pixbuf_supports_svg(void)
+{
+ GSList *formats;
+ GSList *tmp_list;
+ static gint found_svg=-1;
+ gchar **mime_types,**mime_type;
+ if (found_svg!=-1)
+ return found_svg;
+ formats=gdk_pixbuf_get_formats();
+ found_svg=FALSE;
+ for (tmp_list=formats;tmp_list && !found_svg;tmp_list=tmp_list->next)
+ {
+ mime_types=gdk_pixbuf_format_get_mime_types(tmp_list->data);
+ for (mime_type=mime_types;*mime_type && !found_svg;mime_type++)
+ if (!strcmp(*mime_type,"image/svg"))
+ found_svg=TRUE;
+ g_strfreev(mime_types);
+ }
+ g_slist_free(formats);
+ return found_svg;
+}
+
+static void plover_install_icon_at_size(const char *icon_name,
+ GtkIconSet *icon_set,GtkIconSize size,const char *filename)
+{
+ int w,h;
+ GdkPixbuf *pixbuf;
+ GtkIconSource *source;
+ if (gtk_icon_size_lookup(size,&w,&h))
+ {
+ pixbuf=gdk_pixbuf_new_from_file_at_size(filename,w,h,NULL);
+ if (pixbuf)
+ {
+ source=gtk_icon_source_new();
+ gtk_icon_source_set_size_wildcarded(source,FALSE);
+ gtk_icon_source_set_size(source,size);
+ gtk_icon_source_set_pixbuf(source,pixbuf);
+ gtk_icon_set_add_source(icon_set,source);
+ gtk_icon_source_free(source);
+ g_object_unref(pixbuf);
+ }
+ }
+}
+
+/**
+ * plover_icons_add_to_stock:
+ * @type: The icon type, typically "apps" or "mimetype"
+ * @name: The icon name (the basename of files containing the icons)
+ *
+ * Find icons in <datadir>/icons/hicolor and add them to the stock images
+ * so that, for example, gtk_image_new_from_stock() will be able find them.
+ *
+ * If there is an SVG loader registered with GdkPixbuf, then:
+ * <datadir>/icons/hicolor/scalable/@type/@name.svg will be used. Otherwise,
+ * <datadir>/icons/hicolor/24x24/@type/@name.png and
+ * <datadir>/icons/hicolor/48x48/@type/@name.png will be used.
+ */
+void plover_icons_add_to_stock(const char *type,const char *name)
+{
+ gchar *prefix,*s,*filename;
+ GtkIconSource *source;
+ GtkIconSet *icon_set;
+ GtkIconFactory *factory;
+ factory=gtk_icon_factory_new();
+ icon_set=gtk_icon_set_new();
+#ifdef WIN32
+ prefix=g_win32_get_package_installation_directory_of_module(NULL);
+#else
+ prefix=NULL;
+#endif
+ if (plover_pixbuf_supports_svg())
+ {
+ source=gtk_icon_source_new();
+ s=g_strconcat(name,".svg");
+ filename=g_build_filename(prefix?prefix:"/usr",
+ "share/icons/hicolor/scalable",type,s,NULL);
+ g_free(s);
+ gtk_icon_source_set_filename(source,filename);
+ g_free(filename);
+ gtk_icon_set_add_source(icon_set,source);
+ gtk_icon_source_free(source);
+ }
+ else
+ {
+ s=g_strconcat(name,".png");
+ filename=g_build_filename(prefix?prefix:"/usr",
+ "share/icons/hicolor/24x24",type,s,NULL);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_MENU,
+ filename);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_BUTTON,
+ filename);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_SMALL_TOOLBAR,
+ filename);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_LARGE_TOOLBAR,
+ filename);
+ g_free(filename);
+ filename=g_build_filename(prefix?prefix:"/usr",
+ "share/icons/hicolor/48x48",type,s,NULL);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_DND,
+ filename);
+ plover_install_icon_at_size(name,icon_set,GTK_ICON_SIZE_DIALOG,
+ filename);
+ g_free(filename);
+ g_free(s);
+ }
+ gtk_icon_factory_add(factory,name,icon_set);
+ gtk_icon_set_unref(icon_set);
+ //icon_set=gtk_icon_factory_lookup(factory,name);
+ gtk_icon_factory_add_default(factory);
+ g_object_unref(factory);
+}
--- /dev/null
+#ifndef __PLOVER_STOCK_ICONS_H__
+#define __PLOVER_STOCK_ICONS_H__
+
+void plover_icons_add_to_stock(const char *type,const char *name);
+
+#endif /* __PLOVER_STOCK_ICONS_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include <plover/plover.h>
+#include <plover/transaction.h>
+#include <plover-gtk/transactionhelper.h>
+
+/*
+ * A PloverTransactionHelper uses a GtkAssistant to help a user run a
+ * transaction.
+ */
+
+G_DEFINE_TYPE(PloverTransactionHelper,plover_transaction_helper,G_TYPE_OBJECT)
+
+enum {
+ CLOSE=0,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
+{
+ g_free(helper->error_primary_text);
+ g_free(helper->base);
+ g_free(helper->unsatisfied);
+ if (helper->comps)
+ plover_comps_free(helper->comps);
+ plover_vector_free(helper->report_adding);
+ plover_vector_free(helper->report_removing);
+}
+
+static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
+{
+ g_clear_error(&helper->error);
+ if (helper->error_dialog)
+ {
+ g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
+ gtk_widget_destroy(helper->error_dialog);
+ helper->error_dialog=NULL;
+ }
+ if (helper->assistant)
+ {
+ g_signal_handlers_disconnect_by_data(helper->assistant,helper);
+ g_clear_object(&helper->assistant);
+ }
+ g_clear_object(&helper->ui);
+ g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
+ g_slist_free(helper->transactions);
+ helper->transactions=NULL;
+ g_clear_object(&helper->installed);
+ g_clear_object(&helper->upstream);
+ g_clear_object(&helper->relocated_upstream);
+}
+
+static void
+ plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
+{
+ GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
+ gobject_class->finalize=
+ (void (*)(GObject *))plover_transaction_helper_finalize;
+ gobject_class->dispose=
+ (void (*)(GObject *))plover_transaction_helper_dispose;
+ signals[CLOSE]=g_signal_newv("close",
+ G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
+ g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
+}
+
+static void plover_transaction_helper_init(PloverTransactionHelper *helper)
+{
+ helper->report_adding=plover_vector_new();
+ helper->report_removing=plover_vector_new();
+}
+
+static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
+ PloverTransactionHelper *helper)
+{
+ gtk_widget_hide(GTK_WIDGET(helper->assistant));
+ gtk_assistant_set_current_page(helper->assistant,0);
+ g_signal_emit(helper,signals[CLOSE],0);
+}
+
+static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
+ PloverTransactionHelper *helper)
+{
+ gtk_widget_hide(GTK_WIDGET(helper->assistant));
+ gtk_assistant_set_current_page(helper->assistant,0);
+ g_signal_emit(helper,signals[CLOSE],0);
+}
+
+static void
+ plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
+{
+ gchar *package_list,*add,*remove,*s;
+ GtkLabel *label;
+ struct plover_vector *report;
+ if (helper->report_adding->len)
+ {
+ plover_vector_sort(helper->report_adding);
+ if (helper->report_adding_dependencies)
+ {
+ report=plover_vector_dup(helper->report_adding);
+ if (helper->report_adding->len==1)
+ plover_vector_append(report,"its dependencies");
+ else
+ plover_vector_append(report,"their dependencies");
+ package_list=plover_vector_format_for_display(report);
+ plover_vector_free(report);
+ }
+ else
+ package_list=
+ plover_vector_format_for_display(helper->report_adding);
+ add=g_strconcat("Packages to be installed or updated: ",package_list,
+ ".",NULL);
+ g_free(package_list);
+ }
+ else
+ add=NULL;
+ if (helper->report_removing->len)
+ {
+ plover_vector_sort(helper->report_removing);
+ if (helper->report_removing_dependants)
+ {
+ report=plover_vector_dup(helper->report_removing);
+ if (helper->report_adding->len==1)
+ plover_vector_append(report,"its dependants");
+ else
+ plover_vector_append(report,"their dependants");
+ package_list=plover_vector_format_for_display(report);
+ plover_vector_free(report);
+ }
+ else
+ package_list=
+ plover_vector_format_for_display(helper->report_removing);
+ remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
+ g_free(package_list);
+ }
+ else
+ remove=NULL;
+ label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
+ if (add && remove)
+ s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
+ else if (add || remove)
+ s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
+ else
+ s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
+ gtk_label_set_markup(label,s);
+ g_free(s);
+ g_free(add);
+ g_free(remove);
+}
+
+static void plover_transaction_helper_run(PloverTransactionHelper *helper);
+
+static void plover_transaction_helper_callback(GObject *source,
+ GAsyncResult *result,gpointer user_data)
+{
+ GError *error=NULL;
+ PloverTransactionHelper *helper=user_data;
+ PloverTransaction *transaction=PLOVER_TRANSACTION(source);
+ if (!plover_transaction_commit_finish(transaction,result,&error))
+ {
+ plover_transaction_helper_set_error(helper,error,
+ "Software installation failed");
+ g_error_free(error);
+ }
+ else
+ plover_transaction_helper_run(helper);
+ g_signal_handlers_disconnect_by_data(transaction,helper);
+ g_object_unref(transaction);
+}
+
+static void plover_transaction_helper_transaction_status_changed(
+ PloverTransaction *transaction,const char *status,
+ PloverTransactionHelper *helper)
+{
+ GtkProgressBar *bar;
+ bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
+ gtk_progress_bar_set_text(bar,status);
+}
+
+static void plover_transaction_helper_run(PloverTransactionHelper *helper)
+{
+ PloverTransaction *transaction;
+ GtkWidget *page;
+ page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
+ if (helper->transactions)
+ {
+ if (helper->assistant)
+ gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
+ transaction=helper->transactions->data;
+ helper->transactions=g_slist_delete_link(helper->transactions,
+ helper->transactions);
+ g_signal_connect(transaction,"status-changed",
+ G_CALLBACK(plover_transaction_helper_transaction_status_changed),
+ helper);
+ plover_transaction_commit_async(transaction,NULL,
+ plover_transaction_helper_callback,helper);
+ }
+ else if (helper->assistant)
+ gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
+}
+
+static gboolean plover_transaction_helper_pulse(gpointer user_data)
+{
+ PloverTransactionHelper *helper=user_data;
+ GtkWidget *w;
+ GtkProgressBar *bar;
+ if (!helper->assistant)
+ return FALSE;
+ w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
+ bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
+ if (gtk_assistant_get_page_complete(helper->assistant,w))
+ {
+ gtk_progress_bar_set_fraction(bar,1.0);
+ helper->pulse_handler=0;
+ return FALSE;
+ }
+ else
+ {
+ gtk_progress_bar_pulse(bar);
+ return TRUE;
+ }
+}
+
+static void
+ plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
+{
+ GError *error=NULL;
+ GtkToggleButton *button;
+ PloverTransaction *transaction;
+ button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
+ "SIRemoveExisting"));
+ if (gtk_toggle_button_get_active(button))
+ {
+ transaction=plover_transaction_new_remove(NULL,&error);
+ if (!transaction)
+ {
+ if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
+ g_clear_error(&error);
+ if (error)
+ {
+ plover_transaction_helper_set_error(helper,error,
+ "Software installation failed");
+ g_error_free(error);
+ return;
+ }
+ }
+ else
+ helper->transactions=
+ g_slist_prepend(helper->transactions,transaction);
+ }
+ /*
+ * Note that PloverTransaction does support cancelling a transaction, but
+ * there are a number of challenges with using it:
+ * - cancellation is only supported during the file phase if razor
+ * has atomic rollback,
+ * - cancellation is not supported during post-transaction scripts at all
+ * (since by the time the first script is started the atomic has already
+ * been committed) and these can take quite some time,
+ * - where a transaction has an embedded COMMIT, any rollback won't
+ * go back beyond this point.
+ * To support user-cancel, then, we would need some mechanism to:
+ * - Comunicate that the operation is being cancelled and this may take
+ * some time,
+ * - Not allow cancellation at all after the last post-transaction script
+ * phase is started,
+ * - Report the partially completed transaction where cancellation
+ * occurred after a COMMIT point.
+ * At present, this doesn't appear worth the effort.
+ */
+ if (helper->assistant)
+ gtk_assistant_commit(helper->assistant);
+ plover_transaction_helper_run(helper);
+ helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
+ helper);
+}
+
+static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
+ GtkWidget *page,PloverTransactionHelper *helper)
+{
+ if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
+ plover_transaction_helper_prepare_confirm(helper);
+ else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
+ plover_transaction_helper_prepare_progress(helper);
+}
+
+static void
+ plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
+ PloverTransactionHelper *helper)
+{
+ GtkWidget *w;
+ if (helper->assistant)
+ {
+ w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
+ gtk_assistant_set_page_complete(helper->assistant,w,
+ gtk_toggle_button_get_active(button));
+ }
+}
+
+PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
+{
+ gsize len;
+ gchar *s,*directory,*contents;
+ GError *error=NULL;
+ GtkWidget *w;
+ PloverTransactionHelper *helper;
+ g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
+ helper=PLOVER_TRANSACTION_HELPER(
+ g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
+ if (ui)
+ helper->ui=g_object_ref(ui);
+ else
+ helper->ui=gtk_builder_new();
+ helper->assistant=
+ GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
+ if (!helper->assistant)
+ {
+ directory=g_strdup(g_getenv("PLOVER_DATADIR"));
+ if (!directory)
+ {
+#ifdef WIN32
+ s=g_win32_get_package_installation_directory_of_module(NULL);
+ directory=g_build_filename(s,"share","plover",NULL);
+ g_free(s);
+#else
+ directory=g_strdup(PLOVER_DATADIR);
+#endif
+ }
+ s=g_build_filename(directory,"software-installation.ui",NULL);
+ g_free(directory);
+ (void)g_file_get_contents(s,&contents,&len,&error);
+ g_free(s);
+ if (!error)
+ {
+ (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
+ g_free(contents);
+ }
+ if (error)
+ {
+ g_critical("software-installation.ui: %s",error->message);
+ g_clear_error(&error);
+ g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error (no user interface)");
+ plover_transaction_helper_set_error(helper,error,
+ "Can't start installer");
+ return helper;
+ }
+ helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
+ "SoftwareInstallation"));
+ }
+ if (!helper->assistant)
+ {
+ g_critical("\"SoftwareInstallation\" object not found");
+ g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error (missing wizard)");
+ plover_transaction_helper_set_error(helper,error,
+ "Can't start installer");
+ g_error_free(error);
+ return helper;
+ }
+ else
+ g_object_ref(helper->assistant);
+ if (!GTK_IS_ASSISTANT(helper->assistant))
+ {
+ g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
+ g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error (unexpected wizard type)");
+ plover_transaction_helper_set_error(helper,error,
+ "Can't start installer");
+ g_error_free(error);
+ return helper;
+ }
+ g_signal_connect(helper->assistant,"cancel",
+ G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
+ g_signal_connect(helper->assistant,"close",
+ G_CALLBACK(plover_transaction_helper_assistant_close),helper);
+ g_signal_connect(helper->assistant,"prepare",
+ G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
+ w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
+ if (w)
+ g_signal_connect(w,"toggled",
+ G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
+ w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
+ if (w)
+ gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
+ return helper;
+}
+
+PloverPackageSet *
+ plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ return helper->installed;
+}
+
+void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
+ PloverPackageSet *installed)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
+ g_return_if_fail(helper->installed == NULL);
+ helper->installed=g_object_ref(installed);
+}
+
+PloverRepository *
+ plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
+ GError **error)
+{
+ const char *base;
+#if 0
+ const char *prefix;
+ struct razor_relocations *relocations=NULL;
+#endif
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ if (!helper->upstream)
+ {
+#if 0
+ prefix=plover_transaction_helper_get_prefix(helper,error);
+ if (!prefix)
+ return NULL;
+#endif
+ base=plover_transaction_helper_get_base(helper);
+#if 0
+ if (prefix)
+ {
+ relocations=razor_relocations_create();
+ razor_relocations_add(relocations,"/usr",prefix);
+ }
+#endif
+ helper->upstream=plover_repository_new_from_yum(base,error);
+#if 0
+ if (relocations)
+ razor_relocations_destroy(relocations);
+#endif
+ }
+ return helper->upstream;
+}
+
+static PloverPackageSet *plover_transaction_helper_get_relocated_upstream(
+ PloverTransactionHelper *helper,GError **error)
+{
+ const char *prefix;
+ struct razor_relocations *relocations=NULL;
+ GError *tmp_error=NULL;
+ PloverRepository *upstream;
+ PloverPackageSet *set;
+ if (!helper->relocated_upstream)
+ {
+ upstream=plover_transaction_helper_get_upstream(helper,error);
+ if (!upstream)
+ return NULL;
+ prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error(error,tmp_error);
+ return NULL;
+ }
+ set=plover_repository_get_package_set(upstream);
+ if (prefix)
+ {
+ relocations=razor_relocations_create();
+ razor_relocations_add(relocations,"/usr",prefix);
+ helper->relocated_upstream=
+ plover_package_set_new_from_repository(upstream,relocations,
+ error);
+ if (relocations)
+ razor_relocations_destroy(relocations);
+ }
+ else
+ helper->relocated_upstream=g_object_ref(set);
+ }
+ return helper->relocated_upstream;
+}
+
+void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
+ PloverRepository *upstream)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
+ g_return_if_fail(helper->upstream == NULL);
+ helper->upstream=g_object_ref(upstream);
+}
+
+const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ return helper->base;
+}
+
+void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
+ const char *base)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ g_return_if_fail(helper->transactions == NULL);
+ g_free(helper->base);
+ helper->base=g_strdup(base);
+}
+
+struct comps *
+ plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
+ GError **error)
+{
+ gchar *s;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ g_return_val_if_fail(helper->base != NULL,NULL);
+ if (!helper->comps)
+ {
+ s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
+ helper->comps=plover_comps_new_from_file(s);
+ if (!helper->comps)
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
+ g_free(s);
+ }
+ return helper->comps;
+}
+
+const char *
+ plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
+ GError **error)
+{
+ const char *prefix;
+ struct comps *comps;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ g_return_val_if_fail(helper->base != NULL || helper->installed != NULL,NULL);
+ if (helper->base)
+ {
+ comps=plover_transaction_helper_get_comps(helper,error);
+ if (!comps)
+ return NULL;
+ return plover_default_prefix_for_vendor(comps->vendor);
+ }
+ prefix=plover_package_set_guess_prefix(helper->installed,error);
+ return prefix;
+}
+
+static int plover_transaction_helper_package_count(void)
+{
+ int count=0;
+ char *install_root;
+ struct razor_set *set;
+ struct razor_package *package;
+ struct razor_package_iterator *pi;
+ install_root=getenv("RAZOR_ROOT");
+ if (!install_root)
+ install_root="";
+ set=razor_root_open_read_only(install_root,NULL);
+ if (set)
+ {
+ pi=razor_package_iterator_create(set);
+ while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
+ count++;
+ razor_package_iterator_destroy(pi);
+ razor_set_unref(set);
+ }
+ return count;
+}
+
+static gboolean
+ plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
+ GError **error)
+{
+ int i;
+ gchar *prefix=NULL,*s;
+ struct comps *comps=NULL;
+ GtkWidget *container,*page;
+ GtkButton *button;
+ GtkLabel *label;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ if (helper->check_vendor)
+ {
+ comps=plover_transaction_helper_get_comps(helper,error);
+ if (!comps)
+ return FALSE;
+ prefix=plover_default_prefix_for_vendor(comps->vendor);
+ }
+ button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
+ container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
+ "SIIncompatibleInstallation"));
+ page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
+ if (helper->check_vendor && prefix &&
+ !plover_installed_files_match_prefix(prefix))
+ {
+ label=GTK_LABEL(gtk_builder_get_object(helper->ui,
+ "SIIncompatibleInstallationLabel"));
+ s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
+ "The existing installation is not from %s.\n"
+ "In order to continue, all the existing packages must be removed.",
+ comps->vendor);
+ gtk_label_set_markup(label,s);
+ g_free(s);
+ i=plover_transaction_helper_package_count();
+ s=g_strdup_printf("Remove %d existing package%s",i,i==1?"":"s");
+ gtk_button_set_label(button,s);
+ g_free(s);
+ gtk_widget_show(container);
+ if (helper->assistant)
+ gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
+ }
+ else
+ {
+ gtk_widget_hide(container);
+ if (helper->assistant)
+ gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
+ }
+ return TRUE;
+}
+
+void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
+ gboolean check_vendor)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ if (helper->check_vendor!=check_vendor)
+ {
+ helper->check_vendor=check_vendor;
+ if (helper->transactions)
+ plover_transaction_helper_check_vendor(helper,NULL);
+ }
+}
+
+/*
+ * If plover_transaction_helper_add_transaction() failes with an error
+ * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
+ * then plover_transaction_helper_get_unsatisfied() can be used to
+ * retrieve a textual description of the problem.
+ */
+
+const char *
+ plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ return helper->unsatisfied;
+}
+
+gboolean
+ plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
+ PloverTransaction *transaction,struct plover_vector *report_packages,
+ enum razor_install_action report_action,GError **error)
+{
+ int i,count;
+ gboolean other_packages;
+ const char *s,*name;
+ enum razor_install_action action;
+ struct razor_install_iterator *ii;
+ struct razor_set *next;
+ struct razor_package *package;
+ struct plover_vector *tasked_packages;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(report_action==RAZOR_INSTALL_ACTION_ADD || report_action==RAZOR_INSTALL_ACTION_REMOVE,FALSE);
+ g_free(helper->unsatisfied);
+ helper->unsatisfied=NULL;
+ if (!plover_transaction_resolve(transaction,error))
+ {
+ s=plover_transaction_get_unsatisfied(transaction);
+ helper->unsatisfied=g_strdup(s);
+ return FALSE;
+ }
+ ii=plover_transaction_get_install_iterator(transaction,error);
+ if (!ii)
+ return FALSE;
+ next=plover_transaction_get_next_set(transaction,error);
+ if (!next)
+ return FALSE;
+ tasked_packages=plover_vector_new();
+ other_packages=FALSE;
+ while (razor_install_iterator_next(ii,&package,&action,&count))
+ {
+ if (action==report_action)
+ {
+ razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_LAST);
+ if (!report_packages ||
+ plover_vector_contains(report_packages,name))
+ plover_vector_append(tasked_packages,name);
+ else
+ other_packages=TRUE;
+ }
+ }
+ if (!tasked_packages->len)
+ {
+ /*
+ * If there are no reportable packages tasked for action there
+ * shouldn't by any packages at all, but let's be paranoid.
+ */
+ other_packages=FALSE;
+ razor_install_iterator_rewind(ii);
+ while (razor_install_iterator_next(ii,&package,&action,&count))
+ {
+ if (action==report_action)
+ {
+ razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_LAST);
+ plover_vector_append(tasked_packages,name);
+ }
+ }
+ }
+ if (!tasked_packages->len)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
+ report_action==RAZOR_INSTALL_ACTION_ADD?"add":"remove");
+ plover_vector_free(tasked_packages);
+ return FALSE;
+ }
+ if (!helper->transactions)
+ plover_transaction_helper_check_vendor(helper,error);
+ g_object_ref(transaction);
+ helper->transactions=g_slist_append(helper->transactions,transaction);
+ if (report_action==RAZOR_INSTALL_ACTION_ADD)
+ {
+ for(i=0;i<tasked_packages->len;i++)
+ {
+ s=tasked_packages->strings[i];
+ if (!plover_vector_contains(helper->report_adding,s))
+ plover_vector_append(helper->report_adding,s);
+ }
+ helper->report_adding_dependencies|=other_packages;
+ }
+ else
+ {
+ for(i=0;i<tasked_packages->len;i++)
+ {
+ s=tasked_packages->strings[i];
+ if (!plover_vector_contains(helper->report_removing,s))
+ plover_vector_append(helper->report_removing,s);
+ }
+ helper->report_removing_dependants|=other_packages;
+ }
+ plover_vector_free(tasked_packages);
+ return TRUE;
+}
+
+static PloverTransaction *
+ plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
+ GError **error)
+{
+ gboolean ok;
+ const char *base,*prefix;
+ GError *tmp_error=NULL;
+ PloverTransaction *transaction;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
+ prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error(error,tmp_error);
+ return NULL;
+ }
+ transaction=plover_transaction_new();
+ plover_transaction_set_prefix(transaction,prefix);
+ plover_transaction_set_installed(transaction,helper->installed);
+ if (helper->upstream)
+ ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
+ else
+ {
+ base=plover_transaction_helper_get_base(helper);
+ ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
+ }
+ if (!ok)
+ {
+ g_object_unref(transaction);
+ transaction=NULL;
+ }
+ return transaction;
+}
+
+struct plover_vector *plover_transaction_helper_group_get_default_packages(
+ PloverTransactionHelper *helper,const char *group,GError **error)
+{
+ gboolean changed;
+ struct comps *comps;
+ struct comps_group *grp;
+ struct comps_requirement *pkg;
+ struct plover_vector *default_packages;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ comps=plover_transaction_helper_get_comps(helper,error);
+ if (!comps)
+ return NULL;
+ grp=plover_comps_lookup_group(comps,group);
+ if (!grp)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
+ return NULL;
+ }
+ default_packages=plover_vector_new();
+ do
+ {
+ changed=FALSE;
+ for(pkg=grp->packages;pkg;pkg=pkg->next)
+ {
+ if (plover_vector_contains(default_packages,pkg->name))
+ continue;
+ if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
+ pkg->type==COMPS_REQUIREMENT_MANDATORY ||
+ pkg->type==COMPS_REQUIREMENT_CONDITIONAL &&
+ plover_vector_contains(default_packages,pkg->requires))
+ {
+ changed=TRUE;
+ plover_vector_append(default_packages,pkg->name);
+ }
+ }
+ } while(changed);
+ return default_packages;
+}
+
+/*
+ * Returns TRUE if there is work to be done or FALSE if the packages are
+ * already installed or on error.
+ */
+gboolean
+ plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
+ struct plover_vector *packages,GError **error)
+{
+ gboolean retval;
+ PloverTransaction *transaction;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ g_return_val_if_fail(packages != NULL,FALSE);
+ if (!packages->len)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
+ return FALSE;
+ }
+ transaction=plover_transaction_helper_new_transaction(helper,error);
+ if (!transaction)
+ return FALSE;
+ if (!plover_transaction_install(transaction,packages->strings,error))
+ {
+ g_object_unref(transaction);
+ return FALSE;
+ }
+ retval=plover_transaction_helper_add_transaction(helper,transaction,
+ packages,RAZOR_INSTALL_ACTION_ADD,error);
+ g_object_unref(transaction);
+ return retval;
+}
+
+/*
+ * Returns TRUE if there is work to be done or FALSE if the group is
+ * already installed or on error.
+ */
+gboolean
+ plover_transaction_helper_install_group(PloverTransactionHelper *helper,
+ const char *group,GError **error)
+{
+ gboolean retval;
+ struct plover_vector *selected_packages;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ selected_packages=plover_transaction_helper_group_get_default_packages(
+ helper,group,error);
+ if (!selected_packages)
+ return FALSE;
+ if (!selected_packages->len)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
+ plover_vector_free(selected_packages);
+ return FALSE;
+ }
+ retval=plover_transaction_helper_install_packages(helper,selected_packages,
+ error);
+ plover_vector_free(selected_packages);
+ return retval;
+}
+
+/*
+ * Returns TRUE if there is work to be done or FALSE if the group is
+ * not installed or on error.
+ */
+gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
+ const char *group,GError **error)
+{
+ gboolean retval;
+ struct plover_vector *selected_packages;
+ PloverTransaction *transaction;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ selected_packages=plover_transaction_helper_group_get_default_packages(
+ helper,group,error);
+ if (!selected_packages)
+ return FALSE;
+ if (!selected_packages->len)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
+ plover_vector_free(selected_packages);
+ return FALSE;
+ }
+ transaction=plover_transaction_new();
+ plover_transaction_set_installed(transaction,helper->installed);
+ if (!plover_transaction_remove(transaction,selected_packages->strings,
+ error))
+ {
+ plover_vector_free(selected_packages);
+ g_object_unref(transaction);
+ return FALSE;
+ }
+ retval=plover_transaction_helper_add_transaction(helper,transaction,
+ NULL,RAZOR_INSTALL_ACTION_REMOVE,error);
+ g_object_unref(transaction);
+ plover_vector_free(selected_packages);
+ return retval;
+}
+
+/*
+ * Returns TRUE if there is work to be done or FALSE if all updates have
+ * already been applied or on error.
+ */
+gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
+ GError **error)
+{
+ gboolean retval;
+ PloverTransaction *transaction;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ transaction=plover_transaction_helper_new_transaction(helper,error);
+ if (!transaction)
+ return FALSE;
+ if (!plover_transaction_update(transaction,NULL,error))
+ {
+ g_object_unref(transaction);
+ return FALSE;
+ }
+ retval=plover_transaction_helper_add_transaction(helper,transaction,
+ NULL,RAZOR_INSTALL_ACTION_ADD,error);
+ g_object_unref(transaction);
+ return retval;
+}
+
+gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
+ if (helper->error_dialog)
+ return TRUE;
+ else if (!helper->assistant)
+ return FALSE;
+ else
+ return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
+}
+
+void plover_transaction_helper_present(PloverTransactionHelper *helper)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ if (helper->error_dialog)
+ gtk_window_present(GTK_WINDOW(helper->error_dialog));
+ else if (helper->assistant)
+ gtk_window_present(GTK_WINDOW(helper->assistant));
+}
+
+static void
+ plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
+ int response_id,PloverTransactionHelper *helper)
+{
+ g_signal_handlers_disconnect_by_data(error_dialog,helper);
+ if ((GtkWidget *)error_dialog==helper->error_dialog)
+ {
+ gtk_widget_destroy(helper->error_dialog);
+ helper->error_dialog=NULL;
+ if (helper->assistant)
+ {
+ gtk_widget_hide(GTK_WIDGET(helper->assistant));
+ gtk_assistant_set_current_page(helper->assistant,0);
+ }
+ g_signal_emit(helper,signals[CLOSE],0);
+ }
+}
+
+const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
+ const GError **error)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ if (!helper->error_dialog)
+ return NULL;
+ if (error)
+ *error=helper->error;
+ return helper->error_primary_text;
+}
+
+void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
+ const GError *error,const char *primary_text)
+{
+ GtkMessageType type;
+ GtkWindow *window;
+ g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
+ g_return_if_fail(error != NULL);
+ g_return_if_fail(primary_text != NULL);
+ if (helper->pulse_handler)
+ {
+ g_source_remove(helper->pulse_handler);
+ helper->pulse_handler=0;
+ }
+ if (helper->error_dialog)
+ {
+ gtk_widget_destroy(helper->error_dialog);
+ helper->error_dialog=NULL;
+ }
+ g_free(helper->error_primary_text);
+ helper->error_primary_text=g_strdup(primary_text);
+ g_clear_error(&helper->error);
+ helper->error=g_error_copy(error);
+ if (g_error_matches(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_WORK))
+ type=GTK_MESSAGE_INFO;
+ else
+ type=GTK_MESSAGE_ERROR;
+ if (helper->assistant)
+ window=GTK_WINDOW(helper->assistant);
+ else
+ window=NULL;
+ helper->error_dialog=gtk_message_dialog_new(window,
+ GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
+ gtk_message_dialog_format_secondary_text(
+ GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
+ gtk_widget_show(helper->error_dialog);
+ g_signal_connect(helper->error_dialog,"response",
+ G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);
+}
--- /dev/null
+#ifndef __PLOVER_TRANSACTION_HELPER_H__
+#define __PLOVER_TRANSACTION_HELPER_H__
+
+#include <gtk/gtk.h>
+#include <plover/packageset.h>
+#include <plover/repository.h>
+#include <plover/transaction.h>
+
+#define PLOVER_TYPE_TRANSACTION_HELPER plover_transaction_helper_get_type()
+#define PLOVER_TRANSACTION_HELPER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\
+ PLOVER_TYPE_TRANSACTION_HELPER,\
+ PloverTransactionHelper)
+#define PLOVER_TRANSACTION_HELPER_CLASS(klass) \
+ G_TYPE_CHECK_CLASS_CAST(klass,\
+ PLOVER_TYPE_TRANSACTION_HELPER,\
+ PloverTransactionHelperClass)
+#define PLOVER_IS_TRANSACTION_HELPER(obj) \
+ G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+ PLOVER_TYPE_TRANSACTION_HELPER)
+#define PLOVER_IS_TRANSACTION_HELPER_CLASS(klass) \
+ G_TYPE_CHECK_CLASS_TYPE(obj,\
+ PLOVER_TYPE_TRANSACTION_HELPER)
+#define PLOVER_TRANSACTION_HELPER_GET_CLASS(obj) \
+ G_TYPE_INSTANCE_GET_CLASS(obj,\
+ PLOVER_TYPE_TRANSACTION_HELPER,\
+ PloverTransactionHelperClass)
+
+typedef struct _PloverTransactionHelper {
+ GObject parent_instance;
+ PloverPackageSet *installed;
+ PloverRepository *upstream;
+ PloverPackageSet *relocated_upstream;
+ gchar *base;
+ gchar *unsatisfied;
+ struct comps *comps;
+ gboolean check_vendor;
+ gboolean report_adding_dependencies;
+ gboolean report_removing_dependants;
+ struct plover_vector *report_adding,*report_removing;
+ GSList *transactions;
+ GtkBuilder *ui;
+ GtkAssistant *assistant;
+ guint pulse_handler;
+ GError *error;
+ gchar *error_primary_text;
+ GtkWidget *error_dialog;
+} PloverTransactionHelper;
+
+typedef struct _PloverTransactionHelperClass {
+ GObjectClass parent_class;
+} PloverTransactionHelperClass;
+
+GType plover_transaction_helper_get_type(void);
+PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui);
+PloverPackageSet *
+ plover_transaction_helper_get_installed(PloverTransactionHelper *helper);
+void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
+ PloverPackageSet *installed);
+PloverRepository *
+ plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
+ GError **error);
+void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
+ PloverRepository *upstream);
+const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper);
+void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
+ const char *base);
+struct comps *
+ plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
+ GError **error);
+const char *
+ plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
+ GError **error);
+void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
+ gboolean check_vendor);
+const char *
+ plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper);
+gboolean
+ plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
+ PloverTransaction *transaction,struct plover_vector *report_packages,
+ enum razor_install_action report_action,GError **error);
+struct plover_vector *plover_transaction_helper_group_get_default_packages(
+ PloverTransactionHelper *helper,const char *group,GError **error);
+gboolean
+ plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
+ struct plover_vector *packages,GError **error);
+gboolean
+ plover_transaction_helper_install_group(PloverTransactionHelper *helper,
+ const char *group,GError **error);
+gboolean
+ plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
+ const char *group,GError **error);
+gboolean
+ plover_transaction_helper_update(PloverTransactionHelper *helper,
+ GError **error);
+gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper);
+void plover_transaction_helper_present(PloverTransactionHelper *helper);
+const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
+ const GError **error);
+void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
+ const GError *error,const char *primary_text);
+
+#endif /* __PLOVER_TRANSACTION_HELPER_H__ */
INCLUDES=-I$(top_srcdir)
AM_LDFLAGS=-no-undefined -version-info $(LIBPLOVER_LT_VERSION_INFO)
-pkginclude_HEADERS=plover.h
+pkginclude_HEADERS=plover.h transaction.h package.h packageset.h repository.h
lib_LTLIBRARIES=libplover.la
-libplover_la_SOURCES=$(pkginclude_HEADERS) util.c import-yum.c razor.c comps.c
+libplover_la_SOURCES=$(pkginclude_HEADERS) util.c import-yum.c razor.c comps.c \
+ log.c vector.c transaction.c package.c packageset.c repository.c
pkgconfigdir=$(libdir)/pkgconfig
pkgconfig_DATA=plover.pc
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011, 2014 J. Ali Harlow <ali@juiblex.co.uk>
*
* 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
#include <fcntl.h>
#include <errno.h>
+#include <glib.h>
#include <expat.h>
#include <zlib.h>
#include <razor.h>
#define XML_BUFFER_SIZE 4096
-struct razor_set *
-plover_razor_set_create_from_yum(const char *base)
+struct razor_set *plover_razor_set_create_from_yum(const char *base,
+ GError **error)
{
- struct yum_context ctx;
- void *buf;
- int len;
- gzFile primary, filelists;
- XML_ParsingStatus status;
- struct razor_set *set;
-
- ctx.importer = razor_importer_create();
- ctx.state = YUM_STATE_BEGIN;
-
- ctx.primary_parser = XML_ParserCreate(NULL);
- XML_SetUserData(ctx.primary_parser, &ctx);
- XML_SetElementHandler(ctx.primary_parser,
- yum_primary_start_element,
- yum_primary_end_element);
- XML_SetCharacterDataHandler(ctx.primary_parser,
- yum_character_data);
-
- ctx.filelists_parser = XML_ParserCreate(NULL);
- XML_SetUserData(ctx.filelists_parser, &ctx);
- XML_SetElementHandler(ctx.filelists_parser,
- yum_filelists_start_element,
- yum_filelists_end_element);
- XML_SetCharacterDataHandler(ctx.filelists_parser,
- yum_character_data);
-
- primary = gzopen("primary.xml.gz", "rb");
- if (primary == NULL)
- return NULL;
- filelists = gzopen("filelists.xml.gz", "rb");
- if (filelists == NULL)
- return NULL;
-
- ctx.current_parser = ctx.primary_parser;
-
- ctx.current = 0;
-
- do {
- XML_GetParsingStatus(ctx.current_parser, &status);
- switch (status.parsing) {
- case XML_SUSPENDED:
- XML_ResumeParser(ctx.current_parser);
- break;
- case XML_PARSING:
- case XML_INITIALIZED:
- buf = XML_GetBuffer(ctx.current_parser,
- XML_BUFFER_SIZE);
- if (ctx.current_parser == ctx.primary_parser)
- len = gzread(primary, buf, XML_BUFFER_SIZE);
- else
- len = gzread(filelists, buf, XML_BUFFER_SIZE);
- if (len < 0) {
- fprintf(stderr,
- "couldn't read input: %s\n",
- strerror(errno));
- return NULL;
- }
-
- XML_ParseBuffer(ctx.current_parser, len, len == 0);
- break;
- case XML_FINISHED:
- break;
+ struct yum_context ctx;
+ gchar *s;
+ void *buf;
+ int len;
+ gzFile primary, filelists;
+ XML_ParsingStatus status;
+ struct razor_set *set;
+ int errnum;
+ const char *errstr,*errobj;
+ ctx.importer=razor_importer_create();
+ ctx.state=YUM_STATE_BEGIN;
+ ctx.primary_parser=XML_ParserCreate(NULL);
+ XML_SetUserData(ctx.primary_parser,&ctx);
+ XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element,
+ yum_primary_end_element);
+ XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data);
+ ctx.filelists_parser=XML_ParserCreate(NULL);
+ XML_SetUserData(ctx.filelists_parser,&ctx);
+ XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element,
+ yum_filelists_end_element);
+ XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data);
+ errno=0;
+ s=g_build_filename(base,"repodata","primary.xml.gz",NULL);
+ primary=gzopen(s,"rb");
+ if (!primary)
+ {
+ g_set_error(error,RAZOR_POSIX_ERROR,errno?errno:ENOMEM,
+ "%s: %s",s,strerror(errno));
+ g_free(s);
+ return NULL;
+ }
+ g_free(s);
+ s=g_build_filename(base,"repodata","filelists.xml.gz",NULL);
+ filelists=gzopen(s,"rb");
+ if (!filelists)
+ {
+ g_set_error(error,RAZOR_POSIX_ERROR,errno?errno:ENOMEM,
+ "%s: %s",s,strerror(errno));
+ g_free(s);
+ return NULL;
+ }
+ g_free(s);
+ ctx.current_parser=ctx.primary_parser;
+ ctx.current=0;
+ do
+ {
+ XML_GetParsingStatus(ctx.current_parser,&status);
+ switch (status.parsing)
+ {
+ case XML_SUSPENDED:
+ XML_ResumeParser(ctx.current_parser);
+ break;
+ case XML_PARSING:
+ case XML_INITIALIZED:
+ buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE);
+ if (ctx.current_parser==ctx.primary_parser)
+ len=gzread(primary,buf,XML_BUFFER_SIZE);
+ else
+ len=gzread(filelists,buf,XML_BUFFER_SIZE);
+ if (len<0)
+ {
+ if (ctx.current_parser==ctx.primary_parser)
+ {
+ errstr=gzerror(primary,&errnum);
+ errobj="primary.xml.gz";
+ }
+ else
+ {
+ errstr=gzerror(filelists,&errnum);
+ errobj="filelists.xml.gz";
+ }
+ if (errnum==Z_ERRNO)
+ g_set_error(error,PLOVER_POSIX_ERROR,errno,"%s: %s",
+ errobj,strerror(errno));
+ else
+ g_set_error(error,RAZOR_ZLIB_ERROR,errnum,"%s: %s",
+ errobj,errstr);
+ return NULL;
}
- } while (status.parsing != XML_FINISHED);
-
-
- XML_ParserFree(ctx.primary_parser);
- XML_ParserFree(ctx.filelists_parser);
-
- gzclose(primary);
- gzclose(filelists);
-
- set = razor_importer_finish(ctx.importer);
-#if RAZOR_HEADER_VERSION_MIN <= 1
- /*
- * Header version 1 is supported by plover v0.3 and is used on
- * 32-bit intel machines which allows the setup and update
- * applications from v0.3 to work. On other machines, we don't
- * want these old applications to work (since they would do
- * the wrong thing) and so we use the current header version
- * which they don't support.
- */
- if (plover_system_arch_is_x86())
- razor_set_set_header_version(set, 1);
+ XML_ParseBuffer(ctx.current_parser,len,!len);
+ break;
+ case XML_FINISHED:
+ break;
+ }
+ } while (status.parsing!=XML_FINISHED);
+ XML_ParserFree(ctx.primary_parser);
+ XML_ParserFree(ctx.filelists_parser);
+ gzclose(primary);
+ gzclose(filelists);
+ set=razor_importer_finish(ctx.importer);
+#if RAZOR_HEADER_VERSION_MIN<=1
+ /*
+ * Header version 1 is supported by plover v0.3 and is used on
+ * 32-bit intel machines which allows the setup and update
+ * applications from v0.3 to work. On other machines, we don't
+ * want these old applications to work (since they would do
+ * the wrong thing) and so we use the current header version
+ * which they don't support.
+ */
+ if (plover_system_arch_is_x86())
+ razor_set_set_header_version(set,1);
#endif
-
- return set;
+ return set;
}
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef WIN32
+#include <windows.h>
+#include <io.h>
+#else
+#include <dirent.h>
+#endif
+#include "config.h"
+#include "plover.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define MAX_OLD_LOGFILES 4 /* (5 including the current) */
+
+#ifdef WIN32
+
+struct find_suffixed_data {
+ HANDLE handle;
+ WIN32_FIND_DATA wfd;
+ int base_len;
+ char *suffix;
+};
+
+static int find_suffixed_first(const char *path,struct find_suffixed_data *data)
+{
+ const char *t1,*t2;
+ gchar *s;
+ s=g_strconcat(path,"-*",NULL);
+ data->handle=FindFirstFile(s,&data->wfd);
+ g_free(s);
+ if (data->handle==INVALID_HANDLE_VALUE)
+ return FALSE;
+ t1=strrchr(path,'/');
+ t2=strrchr(t1?t1:path,'\\');
+ if (t2)
+ data->base_len=strlen(t2+1);
+ else if (t1)
+ data->base_len=strlen(t1+1);
+ else
+ data->base_len=strlen(path);
+ data->suffix=strdup(data->wfd.cFileName+data->base_len);
+ return TRUE;
+}
+
+static int find_suffixed_next(struct find_suffixed_data *data)
+{
+ if (!FindNextFile(data->handle,&data->wfd))
+ return FALSE;
+ free(data->suffix);
+ data->suffix=strdup(data->wfd.cFileName+data->base_len);
+ return TRUE;
+}
+
+static void find_suffixed_close(struct find_suffixed_data *data)
+{
+ free(data->suffix);
+ FindClose(data->handle);
+}
+
+#else /* WIN32 */
+
+struct find_suffixed_data {
+ DIR *dir;
+ struct dirent *entry;
+ char *base;
+ int base_len;
+ char *suffix;
+};
+
+static int find_suffixed_next(struct find_suffixed_data *data)
+{
+ struct dirent *entry_result;
+ while (!readdir_r(data->dir,data->entry,&entry_result) && entry_result)
+ {
+ if (strncmp(data->entry->d_name,data->base,data->base_len) ||
+ data->entry->d_name[data->base_len]!='-')
+ continue;
+ free(data->suffix);
+ data->suffix=strdup(data->entry->d_name+data->base_len);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * From http://womble.decadent.org.uk/readdir_r-advisory.html
+ *
+ * Calculate the required buffer size (in bytes) for directory
+ * entries read from the given directory handle. Return -1 if this
+ * this cannot be done.
+ *
+ * This code does not trust values of NAME_MAX that are less than
+ * 255, since some systems (including at least HP-UX) incorrectly
+ * define it to be a smaller value.
+ *
+ * If you use autoconf, include fpathconf and dirfd in your
+ * AC_CHECK_FUNCS list. Otherwise use some other method to detect
+ * and use them where available.
+ */
+
+static size_t dirent_buf_size(DIR * dirp)
+{
+ long name_max;
+ size_t name_end;
+#if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
+ name_max=fpathconf(dirfd(dirp),_PC_NAME_MAX);
+ if (name_max==-1)
+#if defined(NAME_MAX)
+ name_max=(NAME_MAX>255)?NAME_MAX:255;
+#else
+ return (size_t)-1;
+#endif /* NAME_MAX */
+#else
+#if defined(NAME_MAX)
+ name_max=(NAME_MAX>255)?NAME_MAX:255;
+#else
+#error "buffer size for readdir_r cannot be determined"
+#endif /* NAME_MAX */
+#endif /* HAVE_FPATHCONF && HAVE_DIRFD && _PC_NAME_MAX */
+ name_end=(size_t)offsetof(struct dirent,d_name)+name_max+1;
+ return (name_end>sizeof(struct dirent)?name_end:sizeof(struct dirent));
+}
+
+static int find_suffixed_first(const char *path,struct find_suffixed_data *data)
+{
+ int len;
+ char *s,*base;
+ base=strrchr(path,'/');
+ if (base)
+ {
+ if (base==path)
+ data->dir=opendir("/");
+ else
+ {
+ s=strndup(path,base-path);
+ data->dir=opendir(s);
+ free(s);
+ }
+ data->base=strdup(path+1);
+ }
+ else
+ {
+ data->dir=opendir(".");
+ data->base=strdup(path);
+ }
+ if (!data->dir)
+ {
+ free(data->base);
+ return FALSE;
+ }
+ data->base_len=strlen(data->base);
+ len=dirent_buf_size(data->dir);
+ if (len<0)
+ {
+ closedir(data->dir);
+ return FALSE;
+ }
+ data->entry=malloc(len);
+ if (!data->entry)
+ {
+ closedir(data->dir);
+ return FALSE;
+ }
+ if (find_suffixed_next(data))
+ return TRUE;
+ free(data->entry);
+ closedir(data->dir);
+ return FALSE;
+}
+
+static void find_suffixed_close(struct find_suffixed_data *data)
+{
+ free(data->suffix);
+ free(data->entry);
+ closedir(data->dir);
+}
+
+#endif /* WIN32 */
+
+static int prune_old_logfiles(const char *path)
+{
+ int i,n_suffixes;
+ gchar *s;
+ char *suffix,*suffixes[MAX_OLD_LOGFILES];
+ struct find_suffixed_data fsd;
+ if (find_suffixed_first(path,&fsd))
+ {
+ n_suffixes=0;
+ do
+ {
+ suffix=strdup(fsd.suffix);
+ if (n_suffixes<MAX_OLD_LOGFILES)
+ suffixes[n_suffixes++]=suffix;
+ else
+ {
+ for(i=0;i<MAX_OLD_LOGFILES;i++)
+ if (strcmp(suffix,suffixes[i])>0)
+ {
+ s=suffixes[i];
+ suffixes[i]=suffix;
+ suffix=s;
+ }
+ s=g_strconcat(path,suffix,NULL);
+ (void)remove(s);
+ g_free(s);
+ free(suffix);
+ }
+ } while(find_suffixed_next(&fsd));
+ find_suffixed_close(&fsd);
+ for(i=0;i<n_suffixes;i++)
+ free(suffixes[i]);
+ }
+ return 0;
+}
+
+static int rotate_logfile(const char *path,struct tm *modified)
+{
+ gchar *s;
+ char serial;
+ char suffix[11]; /* -yyyymmdd or -yyyymmdds */
+ sprintf(suffix,"-%04d%02d%02d",modified->tm_year+1900,modified->tm_mon+1,
+ modified->tm_mday);
+ s=g_strconcat(path,suffix,NULL);
+ if (rename(path,s))
+ {
+ suffix[10]='\0';
+ for(serial='a';serial<='z';serial++)
+ {
+ if (errno!=EACCES || serial=='z')
+ {
+ perror(s);
+ free(s);
+ return -1;
+ }
+ free(s);
+ suffix[9]=serial;
+ s=g_strconcat(path,suffix,NULL);
+ if (!rename(path,s))
+ break;
+ }
+ }
+ g_free(s);
+ return prune_old_logfiles(path);
+}
+
+int plover_log_open(const char *path)
+{
+ int retval;
+ char *root;
+ gchar *filename;
+ struct stat sb;
+ time_t t;
+ struct tm today,modified;
+ struct razor_atomic *atomic;
+ FILE *fp;
+ root=getenv("RAZOR_ROOT");
+ if (root)
+ filename=g_strconcat(root,path,NULL);
+ else
+ filename=g_strdup(path);
+ atomic=razor_atomic_open("Open log");
+ razor_atomic_make_dirs(atomic,"",filename);
+ retval=razor_atomic_commit(atomic);
+ if (retval)
+ fprintf(stderr,"Can't open log: %s\n",
+ razor_atomic_get_error_msg(atomic));
+ razor_atomic_destroy(atomic);
+ if (retval)
+ return retval;
+ if (stat(filename,&sb)<0)
+ {
+ if (errno!=ENOENT)
+ {
+ fprintf(stderr,"Can't open log: ");
+ perror(filename);
+ g_free(filename);
+ return -1;
+ }
+ }
+ else if (!S_ISREG(sb.st_mode))
+ {
+ fprintf(stderr,"Can't open log: %s: Not a regular file\n",filename);
+ g_free(filename);
+ return -1;
+ }
+ else
+ {
+ time(&t);
+#ifdef WIN32
+ localtime_s(&today,&t);
+ localtime_s(&modified,&sb.st_mtime);
+#else
+ localtime_r(&t,&today);
+ localtime_r(&sb.st_mtime,&modified);
+#endif
+ if (modified.tm_yday!=today.tm_yday || modified.tm_year!=today.tm_year)
+ rotate_logfile(filename,&modified);
+ }
+ fp=fopen(filename,"a");
+ if (!fp)
+ {
+ fprintf(stderr,"Can't open log: ");
+ perror(filename);
+ g_free(filename);
+ return -1;
+ }
+ g_free(filename);
+#ifdef WIN32
+ /*
+ * The situation under MS-Windows is a little complicated. If standard
+ * output and standard error are valid then the normal code will work.
+ * This applies in console applications and even in GUI applications
+ * if standard output and standard error are redirected by the parent
+ * process (eg., by cmd.exe). However GUI applications started in
+ * typical fashion will have invalid standard output and standard error.
+ * See http://support.microsoft.com/kb/105305 for some more detail.
+ * NB: This solution assumes that fd 1 and 2 are either used for
+ * standard output/error or are unused.
+ */
+ fclose(stdout);
+ fclose(stderr);
+#else
+ fflush(stdout);
+ fflush(stderr);
+#endif
+ if (dup2(fileno(fp),1)<0 || dup2(fileno(fp),2)<0)
+ {
+ perror("Failed to redirect standard error/output");
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+#ifdef WIN32
+ *stdout=*fdopen(1,"a");
+ setvbuf(stdout,NULL,_IONBF,0);
+ *stderr=*fdopen(2,"a");
+ setvbuf(stderr,NULL,_IONBF,0);
+ SetStdHandle(STD_OUTPUT_HANDLE,(HANDLE)_get_osfhandle(1));
+ SetStdHandle(STD_ERROR_HANDLE,(HANDLE)_get_osfhandle(2));
+#endif
+ time(&t);
+ printf("Run started on %s",ctime(&t));
+ fflush(stdout);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+#include <razor.h>
+#include "plover/package.h"
+
+G_DEFINE_TYPE(PloverPackage,plover_package,G_TYPE_OBJECT);
+
+typedef struct _PloverPackagePrivate {
+ struct razor_set *set;
+ struct razor_package *pkg;
+ GObject *file_store;
+ const char **prefixes;
+} PloverPackagePrivate;
+
+#define PLOVER_PACKAGE_GET_PRIVATE(obj)\
+ G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+ PLOVER_TYPE_PACKAGE,PloverPackagePrivate)
+
+enum {
+ CHANGED=0,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_package_finalize(GObject *obj)
+{
+ PloverPackagePrivate *priv=PLOVER_PACKAGE_GET_PRIVATE(obj);
+ g_free(priv->prefixes);
+ G_OBJECT_CLASS(plover_package_parent_class)->finalize(obj);
+}
+
+static void plover_package_dispose(GObject *obj)
+{
+ PloverPackagePrivate *priv=PLOVER_PACKAGE_GET_PRIVATE(obj);
+ if (priv->file_store)
+ {
+ g_object_unref(priv->file_store);
+ priv->file_store=NULL;
+ }
+ G_OBJECT_CLASS(plover_package_parent_class)->dispose(obj);
+}
+
+static void plover_package_class_init(PloverPackageClass *klass)
+{
+ GObjectClass *oclass=G_OBJECT_CLASS(klass);
+ oclass->finalize=plover_package_finalize;
+ oclass->dispose=plover_package_dispose;
+ g_type_class_add_private(klass,sizeof(PloverPackagePrivate));
+ signals[CHANGED]=g_signal_newv("changed",
+ G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
+ g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
+}
+
+static void plover_package_init(PloverPackage *package)
+{
+}
+
+PloverPackage *plover_package_new(struct razor_set *set,
+ struct razor_package *pkg)
+{
+ PloverPackage *package;
+ PloverPackagePrivate *priv;
+ package=g_object_new(PLOVER_TYPE_PACKAGE,NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ priv->set=set;
+ priv->pkg=pkg;
+ return package;
+}
+
+struct razor_set *plover_package_get_razor_set(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ return priv->set;
+}
+
+struct razor_package *plover_package_get_razor_package(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ return priv->pkg;
+}
+
+const char *plover_package_get_name(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *name=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_LAST);
+ return name;
+}
+
+const char *plover_package_get_summary(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *summary=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_SUMMARY,&summary,
+ RAZOR_DETAIL_LAST);
+ return summary;
+}
+
+const char *plover_package_get_version(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *version=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_VERSION,&version,
+ RAZOR_DETAIL_LAST);
+ return version;
+}
+
+const char *plover_package_get_license(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *license=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_LICENSE,&license,
+ RAZOR_DETAIL_LAST);
+ return license;
+}
+
+const char *plover_package_get_arch(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *arch=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_ARCH,&arch,
+ RAZOR_DETAIL_LAST);
+ return arch;
+}
+
+const char *plover_package_get_description(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *description=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_DESCRIPTION,
+ &description,RAZOR_DETAIL_LAST);
+ return description;
+}
+
+const char *plover_package_get_URL(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ const char *URL=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_URL,&URL,
+ RAZOR_DETAIL_LAST);
+ return URL;
+}
+
+/**
+ * plover_package_read_icon:
+ * @package: #PloverPackage to read icon from
+ * @error: a #GError, or %NULL
+ *
+ * Opens an icon for reading. The result is a #GInputStream that
+ * can be used to read the contents of the file.
+ *
+ * If the icon does not exist, the %G_IO_ERROR_NOT_FOUND error will be
+ * returned. Other errors are possible too.
+ *
+ * Returns: (transfer full): #GInputStream or %NULL on error.
+ * Free the returned object with g_object_unref().
+ */
+GInputStream *plover_package_read_icon(PloverPackage *package,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ g_set_error_literal(error,G_IO_ERROR,G_IO_ERROR_NOT_SUPPORTED,
+ "Operation not supported");
+ return NULL;
+}
+
+/**
+ * plover_package_property_iterator_create:
+ * @package: #PloverPackage to create property iterator for
+ *
+ * Creates a property iterator for package. The result is a
+ * #struct razor_property_iterator that can be used to iterate over the
+ * properties of a package.
+ *
+ * Returns: (transfer full): #struct razor_property_iterator or %NULL on error.
+ * Free the returned iterator with razor_property_iterator_destroy().
+ */
+struct razor_property_iterator *
+ plover_package_property_iterator_create(PloverPackage *package)
+{
+ PloverPackagePrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ return razor_property_iterator_create(priv->set,priv->pkg);
+}
+
+/**
+ * plover_package_file_iterator_create:
+ * @package: #PloverPackage to create file iterator for
+ * @reverse: %TRUE if the files should be iterated in reverse order
+ *
+ * Creates a file iterator for package. The result is a
+ * #struct razor_file_iterator that can be used to iterate over the files
+ * in a package.
+ *
+ * Returns: (transfer full): #struct razor_file_iterator or %NULL on error.
+ * Free the returned iterator with razor_file_iterator_destroy().
+ */
+struct razor_file_iterator *
+ plover_package_file_iterator_create(PloverPackage *package,gboolean reverse)
+{
+ PloverPackagePrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ return razor_file_iterator_create(priv->set,priv->pkg,reverse);
+}
+
+/**
+ * plover_package_get_prefixes:
+ * @package: #PloverPackage to get prefixes for
+ *
+ * Retrieve the prefixes for a relocatable package.
+ *
+ * Returns: (transfer none): NULL-terminated array of prefixes.
+ */
+const char *const *plover_package_get_prefixes(PloverPackage *package)
+{
+ const char *prefix;
+ struct razor_string_iterator *si;
+ GPtrArray *prefixes;
+ PloverPackagePrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+ if (!priv->prefixes)
+ {
+ prefixes=g_ptr_array_new();
+ si=razor_install_prefix_iterator_create(priv->set,priv->pkg);
+ while (razor_string_iterator_next(si,&prefix))
+ g_ptr_array_add(prefixes,prefix);
+ razor_string_iterator_destroy(si);
+ g_ptr_array_add(prefixes,NULL);
+ priv->prefixes=g_ptr_array_free(prefixes,FALSE);
+ }
+ return priv->prefixes;
+}
#include <razor.h>
#include <glib-object.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <plover-gtk/packageset.h>
-#include <plover-gtk/packagefilestore.h>
+#include <gio/gio.h>
G_BEGIN_DECLS
GObjectClass parent_class;
} PloverPackageClass;
+#include <plover/packageset.h>
+
GType plover_package_get_type(void) G_GNUC_CONST;
PloverPackage *plover_package_new(struct razor_set *set,
struct razor_package *pkg);
+struct razor_set *plover_package_get_razor_set(PloverPackage *package);
+struct razor_package *plover_package_get_razor_package(PloverPackage *package);
const char *plover_package_get_name(PloverPackage *package);
const char *plover_package_get_summary(PloverPackage *package);
const char *plover_package_get_version(PloverPackage *package);
const char *plover_package_get_arch(PloverPackage *package);
const char *plover_package_get_description(PloverPackage *package);
const char *plover_package_get_URL(PloverPackage *package);
-GdkPixbuf *plover_package_get_icon(PloverPackage *package);
-PloverPackageFileStore *plover_package_get_file_store(PloverPackage *package);
+GInputStream *plover_package_get_icon_stream(PloverPackage *package);
+struct razor_property_iterator *
+ plover_package_property_iterator_create(PloverPackage *package);
+struct razor_file_iterator *
+ plover_package_file_iterator_create(PloverPackage *package,gboolean reverse);
+const char *const *plover_package_get_prefixes(PloverPackage *package);
G_END_DECLS
--- /dev/null
+/*
+ * Copyright (C) 2010-2012, 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <glib-object.h>
+#include <razor.h>
+#include "plover/plover.h"
+#include "plover/package.h"
+#include "plover/packageset.h"
+
+G_DEFINE_TYPE(PloverPackageSet,plover_package_set,G_TYPE_OBJECT);
+
+typedef struct _PloverPackageSetPrivate {
+ gchar *install_root;
+ struct razor_root *root;
+ struct razor_set *set;
+ GSList *packages;
+ int no_details;
+ gchar *guessed_prefix;
+} PloverPackageSetPrivate;
+
+#define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\
+ G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+ PLOVER_TYPE_PACKAGE_SET,\
+ PloverPackageSetPrivate)
+
+enum {
+ CHANGED=0,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_package_set_finalize(GObject *obj)
+{
+ PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
+ g_free(priv->guessed_prefix);
+ G_OBJECT_CLASS(plover_package_set_parent_class)->finalize(obj);
+}
+
+static void plover_package_set_dispose(GObject *obj)
+{
+ PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
+ if (priv->set)
+ {
+ razor_set_unref(priv->set);
+ priv->set=NULL;
+ }
+ if (priv->root)
+ {
+ g_free(priv->install_root);
+ priv->install_root=NULL;
+ razor_root_close(priv->root);
+ priv->root=NULL;
+ }
+ G_OBJECT_CLASS(plover_package_set_parent_class)->dispose(obj);
+}
+
+static void plover_package_set_class_init(PloverPackageSetClass *klass)
+{
+ GObjectClass *oclass=G_OBJECT_CLASS(klass);
+ oclass->finalize=plover_package_set_finalize;
+ oclass->dispose=plover_package_set_dispose;
+ g_type_class_add_private(klass,sizeof(PloverPackageSetPrivate));
+ signals[CHANGED]=g_signal_newv("changed",
+ G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
+ g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
+}
+
+static void plover_package_set_init(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ priv->no_details=-1;
+}
+
+PloverPackageSet *plover_package_set_new(void)
+{
+ return g_object_new(PLOVER_TYPE_PACKAGE_SET,NULL);
+}
+
+void plover_package_set_close(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->root)
+ {
+ razor_root_close(priv->root);
+ priv->root=NULL;
+ }
+}
+
+gboolean plover_package_set_open(PloverPackageSet *set,const char *install_root,
+ gboolean exclusive,GError **err)
+{
+ struct razor_root *root=NULL;
+ struct razor_set *system=NULL;
+ PloverPackageSetPrivate *priv;
+ struct razor_error *error=NULL;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+ if (exclusive)
+ {
+ root=razor_root_open(install_root,NULL);
+ if (!root)
+ {
+ if (razor_root_create(install_root,&error))
+ {
+ if (razor_error_get_domain(error)==RAZOR_GENERAL_ERROR &&
+ razor_error_get_code(error)==
+ RAZOR_GENERAL_ERROR_DATABASE_EXISTS)
+ {
+ razor_error_free(error);
+ error=NULL;
+ root=razor_root_open(install_root,&error);
+ }
+ }
+ else
+ root=razor_root_open(install_root,&error);
+ if (!root)
+ {
+ plover_propagate_razor_error(err,error);
+ return FALSE;
+ }
+ }
+ system=razor_root_get_system_set(root);
+ if (system)
+ razor_set_ref(system);
+ }
+ else
+ system=razor_root_open_read_only(install_root,&error);
+ if (error)
+ {
+ g_set_error_literal(err,PLOVER_RAZOR_ERROR,RAZOR_GENERAL_ERROR_FAILED,
+ razor_error_get_msg(error));
+ razor_error_free(error);
+ return FALSE;
+ }
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->set)
+ {
+ razor_set_unref(priv->set);
+ priv->set=NULL;
+ }
+ if (priv->root)
+ {
+ razor_root_close(priv->root);
+ priv->root=NULL;
+ }
+ g_free(priv->install_root);
+ priv->install_root=g_strdup(install_root);
+ priv->root=root;
+ priv->set=system;
+ return TRUE;
+}
+
+const char *plover_package_set_get_install_root(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ return priv->install_root;
+}
+
+gboolean plover_package_set_get_exclusive(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ return !!priv->root;
+}
+
+gboolean plover_package_set_update(PloverPackageSet *set,struct razor_set *next,
+ struct razor_atomic *atomic)
+{
+ gboolean retval;
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+ g_return_val_if_fail(plover_package_set_get_exclusive(set) != FALSE,FALSE);
+ g_return_val_if_fail(next != NULL,FALSE);
+ g_return_val_if_fail(atomic != NULL,FALSE);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ retval=!razor_root_update(priv->root,next,atomic);
+ if (retval)
+ {
+ razor_set_unref(priv->set);
+ priv->set=razor_root_get_system_set(priv->root);
+ if (priv->set)
+ razor_set_ref(priv->set);
+ }
+ return retval;
+}
+
+PloverPackageSet *plover_package_set_new_from_installed(const char *root,
+ GError **err)
+{
+ PloverPackageSet *set;
+ set=plover_package_set_new();
+ if (!plover_package_set_open(set,root,FALSE,err))
+ {
+ g_object_unref(set);
+ return NULL;
+ }
+ return set;
+}
+
+PloverPackageSet *plover_package_set_new_from_razor(struct razor_set *razor)
+{
+ PloverPackageSet *set;
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(razor != NULL,NULL);
+ set=plover_package_set_new();
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ priv->set=razor;
+ razor_set_ref(priv->set);
+ return set;
+}
+
+static gboolean
+ plover_package_set_import_package(PloverRepository *repository,
+ struct razor_relocations *relocations,struct razor_importer *importer,
+ PloverPackage *package,GError **error)
+{
+ struct razor_property_iterator *prop_iter;
+ struct razor_file_iterator *file_iter;
+ struct razor_rpm *rpm;
+ struct razor_property *prop;
+ const char *name,*version,*arch,*summary,*desc,*url,*license;
+ uint32_t flags;
+ rpm=plover_repository_open_rpm(repository,package,error);
+ if (!rpm)
+ return FALSE;
+ razor_relocations_set_rpm(relocations,rpm);
+ razor_rpm_close(rpm);
+ name=plover_package_get_name(package);
+ version=plover_package_get_version(package);
+ arch=plover_package_get_arch(package);
+ razor_importer_begin_package(importer,name,version,arch);
+ summary=plover_package_get_summary(package);
+ desc=plover_package_get_description(package);
+ url=plover_package_get_URL(package);
+ license=plover_package_get_license(package);
+ razor_importer_add_details(importer,summary,desc,url,license);
+ prop_iter=plover_package_property_iterator_create(package);
+ while (razor_property_iterator_next(prop_iter,&prop,&name,&flags,&version))
+ razor_importer_add_property(importer,name,flags,version);
+ razor_property_iterator_destroy(prop_iter);
+ file_iter=plover_package_file_iterator_create(package,FALSE);
+ while (razor_file_iterator_next(file_iter,&name))
+ {
+ name=razor_relocations_apply(relocations,name);
+ razor_importer_add_file(importer,name);
+ }
+ razor_file_iterator_destroy(file_iter);
+ razor_importer_finish_package(importer);
+ return TRUE;
+}
+
+PloverPackageSet *
+ plover_package_set_new_from_repository(PloverRepository *repository,
+ struct razor_relocations *relocations,GError **error)
+{
+ struct razor_importer *importer;
+ uint32_t header_version;
+ GSList *packages,*lnk;
+ PloverPackageSet *unrelocated,*set;
+ PloverPackageSetPrivate *priv;
+ PloverPackage *package;
+ g_return_val_if_fail(PLOVER_IS_REPOSITORY(repository),NULL);
+ unrelocated=plover_repository_get_package_set(repository);
+ set=plover_package_set_new();
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (relocations)
+ {
+ importer=razor_importer_create();
+ packages=plover_package_set_get_packages(unrelocated);
+ for(lnk=packages;lnk;lnk=lnk->next)
+ {
+ package=lnk->data;
+ if (!plover_package_set_import_package(repository,relocations,
+ importer,package,error))
+ {
+ razor_importer_destroy(importer);
+ g_object_unref(set);
+ return NULL;
+ }
+ }
+ priv->set=razor_importer_finish(importer);
+ if (!priv->set)
+ {
+ g_object_unref(set);
+ return NULL;
+ }
+ header_version=plover_package_set_get_header_version(unrelocated);
+ if (header_version)
+ plover_package_set_set_header_version(set,header_version);
+ }
+ else
+ {
+ priv->set=plover_package_set_get_razor(unrelocated);
+ razor_set_ref(priv->set);
+ }
+ return set;
+}
+
+PloverPackageSet *plover_package_set_new_from_yum(const char *base,
+ struct razor_relocations *relocations,GError **error)
+{
+ PloverPackageSet *set;
+ PloverRepository *repository;
+ repository=plover_repository_new_from_yum(base,error);
+ if (!repository)
+ return NULL;
+ set=plover_package_set_new_from_repository(repository,relocations,error);
+ g_object_unref(repository);
+ return set;
+}
+
+PloverPackageSet *plover_package_set_new_from_rpms(const char **filenames,
+ GError **error)
+{
+ int i;
+ PloverPackageSet *set;
+ PloverPackageSetPrivate *priv;
+ struct razor_importer *importer;
+ struct razor_rpm *rpm;
+ struct razor_error *tmp_error=NULL;
+ importer=razor_importer_create();
+ for(i=0;filenames[i];i++)
+ {
+ rpm=razor_rpm_open(filenames[i],&tmp_error);
+ if (!rpm)
+ {
+ razor_importer_destroy(importer);
+ plover_propagate_razor_error(error,tmp_error);
+ return NULL;
+ }
+ if (razor_importer_add_rpm(importer,rpm))
+ {
+ g_set_error(error,PLOVER_RAZOR_ERROR,RAZOR_GENERAL_ERROR_FAILED,
+ "%s: failed to import",filenames[i]);
+ razor_importer_destroy(importer);
+ return NULL;
+ }
+ razor_rpm_close(rpm);
+ }
+ set=plover_package_set_new();
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ priv->set=razor_importer_finish(importer);
+ return set;
+}
+
+uint32_t plover_package_set_get_header_version(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),0);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->set)
+ return razor_set_get_header_version(priv->set);
+ else
+ return 0;
+}
+
+gboolean plover_package_set_set_header_version(PloverPackageSet *set,
+ uint32_t header_version)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->set)
+ return !razor_set_set_header_version(priv->set,header_version);
+ else
+ return FALSE;
+}
+
+struct razor_set *plover_package_set_get_razor(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ return priv->set;
+}
+
+GSList *plover_package_set_get_packages(PloverPackageSet *set)
+{
+ struct razor_package_iterator *iter;
+ struct razor_package *pkg;
+ PloverPackageSetPrivate *priv;
+ PloverPackage *package;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->set && !priv->packages)
+ {
+ iter=razor_package_iterator_create(priv->set);
+ while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_LAST))
+ {
+ package=plover_package_new(priv->set,pkg);
+ priv->packages=g_slist_prepend(priv->packages,package);
+ }
+ razor_package_iterator_destroy(iter);
+ priv->packages=g_slist_reverse(priv->packages);
+ }
+ return priv->packages;
+}
+
+PloverPackage *plover_package_set_lookup(PloverPackageSet *set,
+ struct razor_package *razor_package)
+{
+ GSList *packages,*lnk;
+ PloverPackage *package;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ packages=plover_package_set_get_packages(set);
+ for(lnk=packages;lnk;lnk=lnk->next)
+ {
+ package=lnk->data;
+ if (plover_package_get_razor_package(package)==razor_package)
+ return package;
+ }
+ return NULL;
+}
+
+PloverPackage *plover_package_set_find_custom(PloverPackageSet *set,
+ gconstpointer data,GCompareFunc func)
+{
+ GSList *packages,*lnk;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ packages=plover_package_set_get_packages(set);
+ lnk=g_slist_find_custom(packages,data,func);
+ return lnk?lnk->data:NULL;
+}
+
+static gint plover_package_set_compare(gconstpointer a,gconstpointer b)
+{
+ PloverPackage *pa=(void *)a,*pb=(void *)b;
+ const char *sa,*sb;
+ sa=plover_package_get_name(pa);
+ sb=plover_package_get_name(pb);
+ if (g_strcmp0(sa,sb))
+ return 1;
+ sa=plover_package_get_arch(pa);
+ sb=plover_package_get_arch(pb);
+ if (g_strcmp0(sa,sb))
+ return 1;
+ sa=plover_package_get_version(pa);
+ sb=plover_package_get_version(pb);
+ return !!g_strcmp0(sa,sb);
+}
+
+PloverPackage *plover_package_set_find_matching(PloverPackageSet *set,
+ PloverPackage *template)
+{
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ return plover_package_set_find_custom(set,template,
+ plover_package_set_compare);
+}
+
+/*
+ * Some versions of razor have a bug which causes all detail strings
+ * to be discarded. If such a version of razor is used to install or
+ * update a package, then all the detail strings for the installed
+ * set will be lost. This function tests for this condition and can
+ * be used to present something more useful than blank details.
+ */
+
+gboolean plover_package_set_get_no_details(PloverPackageSet *set)
+{
+ PloverPackageSetPrivate *priv;
+ PloverPackage *package;
+ GSList *packages,*link;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (priv->no_details<0)
+ {
+ packages=plover_package_set_get_packages(set);
+ if (packages)
+ {
+ priv->no_details=0;
+ for(link=packages;link;link=link->next)
+ {
+ package=link->data;
+ priv->no_details+=2;
+ if (*plover_package_get_summary(package))
+ priv->no_details--;
+ if (*plover_package_get_license(package))
+ priv->no_details--;
+ if (*plover_package_get_description(package))
+ priv->no_details--;
+ if (*plover_package_get_URL(package))
+ priv->no_details--;
+ }
+ if (priv->no_details<0) /* More than 50% of strings present */
+ priv->no_details=0;
+ }
+ }
+ return priv->no_details>0;
+}
+
+struct plover_package_set_prefix {
+ gchar *path;
+ guint count;
+};
+
+static GArray *plover_package_set_popchart_new(void)
+{
+ GArray *prefixes;
+ prefixes=g_array_new(FALSE,FALSE,sizeof(struct plover_package_set_prefix));
+ return prefixes;
+}
+
+static void plover_package_set_popchart_free(GArray *popchart)
+{
+ int i;
+ struct plover_package_set_prefix *prefix;
+ for(i=0;i<popchart->len;i++)
+ {
+ prefix=&g_array_index(popchart,struct plover_package_set_prefix,i);
+ g_free(prefix->path);
+ }
+ g_array_free(popchart,TRUE);
+}
+
+static void plover_package_set_popchart_add(GArray *popchart,const char *path)
+{
+ int i;
+ struct plover_package_set_prefix *prefix;
+ for(i=popchart->len-1;i>=0;i--)
+ {
+ prefix=&g_array_index(popchart,struct plover_package_set_prefix,i);
+ if (!strcmp(prefix->path,path))
+ {
+ prefix->count++;
+ return;
+ }
+ }
+ g_array_set_size(popchart,popchart->len+1);
+ prefix=&g_array_index(popchart,struct plover_package_set_prefix,
+ popchart->len-1);
+ prefix->path=g_strdup(path);
+ prefix->count=1;
+}
+
+static const char *plover_package_set_popchart_get_popular(GArray *popchart)
+{
+ int i;
+ struct plover_package_set_prefix *prefix,*popular;
+ if (!popchart->len)
+ return NULL;
+ popular=&g_array_index(popchart,struct plover_package_set_prefix,0);
+ for(i=1;i<popchart->len;i++)
+ {
+ prefix=&g_array_index(popchart,struct plover_package_set_prefix,i);
+ if (prefix->count>popular->count)
+ popular=prefix;
+ }
+ return popular->path;
+}
+
+static void plover_package_set_popchart_add_prefixes(PloverPackageSet *set,
+ GArray *popchart)
+{
+ int i;
+ PloverPackage *package;
+ GSList *packages,*lnk;
+ const char *const *prefixes;
+ packages=plover_package_set_get_packages(set);
+ for(lnk=packages;lnk;lnk=lnk->next)
+ {
+ package=lnk->data;
+ prefixes=plover_package_get_prefixes(package);
+ for(i=0;prefixes[i];i++)
+ plover_package_set_popchart_add(popchart,prefixes[i]);
+ }
+}
+
+static void plover_package_set_popchart_add_from_files(PloverPackageSet *set,
+ GArray *popchart)
+{
+ int len;
+ const char *name,*s;
+ gchar *default_prefix,*path;
+ struct razor_file_iterator *fi;
+ GSList *packages,*lnk;
+ PloverPackage *package;
+ default_prefix=plover_default_prefix_for_vendor("");
+ if (!default_prefix)
+ return;
+ len=strlen(default_prefix);
+ packages=plover_package_set_get_packages(set);
+ for(lnk=packages;lnk;lnk=lnk->next)
+ {
+ package=lnk->data;
+ fi=plover_package_file_iterator_create(package,FALSE);
+ while (razor_file_iterator_next(fi,&name))
+ {
+ if (g_str_has_prefix(name,default_prefix))
+ {
+ for(s=name+len;*s;s++)
+ if (G_IS_DIR_SEPARATOR(*s))
+ break;
+ path=g_strndup(name,s-name);
+ plover_package_set_popchart_add(popchart,path);
+ g_free(path);
+ }
+ }
+ razor_file_iterator_destroy(fi);
+ }
+ g_free(default_prefix);
+}
+
+const char *plover_package_set_guess_prefix(PloverPackageSet *set,
+ GError **error)
+{
+ GArray *popchart;
+ const char *prefix;
+ PloverPackageSetPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+ priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+ if (!priv->guessed_prefix)
+ {
+ popchart=plover_package_set_popchart_new();
+ plover_package_set_popchart_add_prefixes(set,popchart);
+ prefix=plover_package_set_popchart_get_popular(popchart);
+ if (prefix)
+ priv->guessed_prefix=g_strdup(prefix);
+ else
+ {
+ plover_package_set_popchart_add_from_files(set,popchart);
+ prefix=plover_package_set_popchart_get_popular(popchart);
+ if (prefix)
+ priv->guessed_prefix=g_strdup(prefix);
+ }
+ plover_package_set_popchart_free(popchart);
+ }
+ if (!priv->guessed_prefix)
+ priv->guessed_prefix=
+ plover_default_prefix_for_vendor("Acme Corporation");
+ return priv->guessed_prefix;
+}
--- /dev/null
+#ifndef __PLOVER_PACKAGE_SET_H__
+#define __PLOVER_PACKAGE_SET_H__
+
+#include <razor.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_PACKAGE_SET plover_package_set_get_type()
+#define PLOVER_PACKAGE_SET(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\
+ PLOVER_TYPE_PACKAGE_SET,PloverPackageSet)
+#define PLOVER_PACKAGE_SET_CLASS(klass)\
+ G_TYPE_CHECK_CLASS_CAST(klass,\
+ PLOVER_TYPE_PACKAGE_SET,\
+ PloverPackageSetClass)
+#define PLOVER_IS_PACKAGE_SET(obj)\
+ G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+ PLOVER_TYPE_PACKAGE_SET)
+#define PLOVER_IS_PACKAGE_SET_CLASS(klass)\
+ G_TYPE_CHECK_CLASS_TYPE(obj,\
+ PLOVER_TYPE_PACKAGE_SET)
+#define PLOVER_PACKAGE_SET_GET_CLASS(obj)\
+ G_TYPE_INSTANCE_GET_CLASS(obj,\
+ PLOVER_TYPE_PACKAGE_SET,\
+ PloverPackageSetClass)
+
+typedef struct _PloverPackageSet {
+ GObject parent_instance;
+} PloverPackageSet;
+
+typedef struct _PloverPackageSetClass {
+ GObjectClass parent_class;
+} PloverPackageSetClass;
+
+#include <plover/repository.h>
+
+GType plover_package_set_get_type(void) G_GNUC_CONST;
+PloverPackageSet *plover_package_set_new(void);
+void plover_package_set_close(PloverPackageSet *set);
+gboolean plover_package_set_open(PloverPackageSet *set,const char *install_root,
+ gboolean exclusive,GError **err);
+gboolean plover_package_set_update(PloverPackageSet *set,struct razor_set *next,
+ struct razor_atomic *atomic);
+const char *plover_package_set_get_install_root(PloverPackageSet *set);
+gboolean plover_package_set_get_exclusive(PloverPackageSet *set);
+PloverPackageSet *plover_package_set_new_from_installed(const char *root,
+ GError **err);
+PloverPackageSet *plover_package_set_new_from_razor(struct razor_set *razor);
+PloverPackageSet *
+ plover_package_set_new_from_repository(PloverRepository *repository,
+ struct razor_relocations *relocations,GError **err);
+PloverPackageSet *plover_package_set_new_from_yum(const char *base,
+ struct razor_relocations *relocations,GError **err);
+PloverPackageSet *plover_package_set_new_from_rpms(const char **filenames,
+ GError **error);
+uint32_t plover_package_set_get_header_version(PloverPackageSet *set);
+gboolean plover_package_set_set_header_version(PloverPackageSet *set,
+ uint32_t header_version);
+struct razor_set *plover_package_set_get_razor(PloverPackageSet *set);
+GSList *plover_package_set_get_packages(PloverPackageSet *set);
+PloverPackage *plover_package_set_lookup(PloverPackageSet *set,
+ struct razor_package *razor_package);
+PloverPackage *plover_package_set_find_custom(PloverPackageSet *set,
+ gconstpointer data,GCompareFunc func);
+PloverPackage *plover_package_set_find_matching(PloverPackageSet *set,
+ PloverPackage *template);
+gboolean plover_package_set_get_no_details(PloverPackageSet *set);
+const char *plover_package_set_guess_prefix(PloverPackageSet *set,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __PLOVER_PACKAGE_SET_H__ */
#define __PLOVER_H__
#include <razor.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <plover/packageset.h>
+#include <plover/repository.h>
+
+#define PLOVER_GENERAL_ERROR RAZOR_ERROR_DOMAIN('P','l','v',0)
+#define PLOVER_SCRIPTLET_ERROR RAZOR_ERROR_DOMAIN('P','l','v',1)
+#define PLOVER_RAZOR_ERROR plover_razor_error_quark()
+#define PLOVER_POSIX_ERROR plover_posix_error_quark()
+#define PLOVER_MSWIN_ERROR plover_mswin_error_quark()
+#define PLOVER_ZLIB_ERROR plover_zlib_error_quark()
+
+enum plover_general_error
+{
+ PLOVER_GENERAL_ERROR_FAILED,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,
+ PLOVER_GENERAL_ERROR_NO_WORK,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
+ PLOVER_GENERAL_ERROR_CANCELLED,
+};
enum comps_requirement_type
{
struct comps_group *groups;
};
-char *plover_strconcat(const char *string,...);
-char *plover_default_prefix_for_vendor(const char *vendor);
+struct plover_vector
+{
+ int len,alloc;
+ char **strings;
+};
+
+gchar *plover_default_prefix_for_vendor(const char *vendor);
+gchar *plover_pre_install_prefix(void);
char *plover_get_program_directory(const char *argv0);
+GQuark plover_razor_error_quark(void);
+GQuark plover_posix_error_quark(void);
+GQuark plover_mswin_error_quark(void);
+GQuark plover_zlib_error_quark(void);
+void plover_propagate_razor_error_dup(GError **dest,struct razor_error *src);
+void plover_propagate_razor_error(GError **dest,struct razor_error *src);
+void plover_propagate_g_error(struct razor_error **dest,GError *src);
-struct razor_set *plover_razor_set_create_from_yum(const char *base);
+struct razor_set *plover_razor_set_create_from_yum(const char *base,
+ GError **error);
-struct razor_set *plover_relocate_packages(struct razor_set *set,
- const char *base,struct razor_relocations *relocations,
- struct razor_error **error);
int plover_run_transaction(struct razor_transaction *trans,
- struct razor_install_iterator *ii,const char *base,const char *install_root,
- struct razor_set *system,struct razor_set *next,struct razor_atomic *atomic,
- struct razor_relocations *relocations,enum razor_stage_type stage);
-int plover_commit_transaction(struct razor_transaction *trans,const char *base,
- const char *install_root,struct razor_root *root,
- struct razor_relocations *relocations);
-int plover_install(const char *base,const char *prefix,char **pkgs);
-int plover_update(const char *base,const char *prefix,char **pkgs);
-int plover_remove(char **pkgs);
+ struct razor_install_iterator *ii,const char *install_root,
+ struct razor_set *system,PloverPackageSet *next,PloverRepository *upstream,
+ struct razor_atomic *atomic,struct razor_relocations *relocations,
+ enum razor_stage_type stage,GCancellable *cancellable);
+gboolean plover_install(const char *base,const char *prefix,char **pkgs,
+ GError **error);
+gboolean plover_update(const char *base,const char *prefix,char **pkgs,
+ GError **error);
+gboolean plover_remove(char **pkgs,GError **error);
int plover_installed_files_match_prefix(const char *prefix);
struct comps *plover_comps_new(void);
struct comps_group *plover_comps_lookup_group(struct comps *comps,
const char *id);
+int plover_log_open(const char *path);
+
+struct plover_vector *plover_vector_new(void);
+struct plover_vector *plover_vector_dup(struct plover_vector *old);
+void plover_vector_append(struct plover_vector *vector,const char *str);
+int plover_vector_contains(struct plover_vector *vector,const char *str);
+int plover_vector_remove(struct plover_vector *vector,const char *str);
+void plover_vector_sort(struct plover_vector *vector);
+char *plover_vector_format_for_display(struct plover_vector *vector);
+void plover_vector_free(struct plover_vector *vector);
+
#endif /* __PLOVER_H__ */
Name: plover
Description: Plover packaging system
Version: @VERSION@
-Requires: razor expat zlib
+Requires: razor expat zlib glib2
Libs: -L${libdir} -lplover
Cflags: -I${includedir}
/*
* Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
* Copyright (C) 2008 Red Hat, Inc
- * Copyright (C) 2009, 2011, 2012 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow <ali@juiblex.co.uk>
*
* 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
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <razor.h>
+#include <glib.h>
+#include <gio/gio.h>
#include "config.h"
#include "plover/plover.h"
+#include "plover/transaction.h"
static char *rpm_filename(const char *name,const char *version,const char *arch)
{
v++;
else
v=version;
- return plover_strconcat(name,"-",v,".",arch,".rpm",NULL);
-}
-
-struct razor_set *plover_relocate_packages(struct razor_set *set,
- const char *base,struct razor_relocations *relocations,
- struct razor_error **error)
-{
- struct razor_importer *importer;
- struct razor_property_iterator *prop_iter;
- struct razor_package_iterator *pkg_iter;
- struct razor_file_iterator *file_iter;
- struct razor_package *package;
- struct razor_property *property;
- struct razor_rpm *rpm;
- struct razor_set *new;
- const char *name,*version,*arch,*summary,*desc,*url,*license;
- char *s,*file;
- uint32_t flags;
- importer=razor_importer_create();
- pkg_iter=razor_package_iterator_create(set);
- while (razor_package_iterator_next(pkg_iter,&package,RAZOR_DETAIL_NAME,
- &name,RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,
- RAZOR_DETAIL_SUMMARY,&summary,RAZOR_DETAIL_DESCRIPTION,&desc,
- RAZOR_DETAIL_URL,&url,RAZOR_DETAIL_LICENSE,&license,RAZOR_DETAIL_LAST))
- {
- s=rpm_filename(name,version,arch);
- file=plover_strconcat(base,"/rpms/",s,NULL);
- free(s);
- rpm=razor_rpm_open(file,error);
- free(file);
- if (!rpm)
- {
- razor_package_iterator_destroy(pkg_iter);
- razor_importer_destroy(importer);
- return NULL;
- }
- razor_relocations_set_rpm(relocations,rpm);
- razor_rpm_close(rpm);
- razor_importer_begin_package(importer,name,version,arch);
- razor_importer_add_details(importer,summary,desc,url,license);
- prop_iter=razor_property_iterator_create(set,package);
- while (razor_property_iterator_next(prop_iter,&property,&name,&flags,
- &version))
- razor_importer_add_property(importer,name,flags,version);
- razor_property_iterator_destroy(prop_iter);
- file_iter=razor_file_iterator_create(set,package,0);
- while (razor_file_iterator_next(file_iter,&name))
- {
- name=razor_relocations_apply(relocations,name);
- razor_importer_add_file(importer,name);
- }
- razor_file_iterator_destroy(file_iter);
- razor_importer_finish_package(importer);
- }
- razor_package_iterator_destroy(pkg_iter);
- new=razor_importer_finish(importer);
- if (new)
- razor_set_set_header_version(new,razor_set_get_header_version(set));
- return new;
+ return g_strconcat(name,"-",v,".",arch,".rpm",NULL);
}
/*
* is met (in which case the action is consumed).
*/
int plover_run_transaction(struct razor_transaction *trans,
- struct razor_install_iterator *ii,const char *base,const char *install_root,
- struct razor_set *system,struct razor_set *next,struct razor_atomic *atomic,
- struct razor_relocations *relocations,enum razor_stage_type stage)
+ struct razor_install_iterator *ii,const char *install_root,
+ struct razor_set *system,PloverPackageSet *next,PloverRepository *upstream,
+ struct razor_atomic *atomic,struct razor_relocations *relocations,
+ enum razor_stage_type stage,GCancellable *cancellable)
{
- struct razor_package *package;
+ struct razor_package *pkg;
enum razor_install_action action;
struct razor_rpm *rpm;
struct razor_error *error=NULL;
const char *name,*version,*arch;
- char *s,*file;
+ gchar *t;
int r,count;
+ GError *tmp_error=NULL;
+ PloverPackage *package;
switch(stage)
{
case RAZOR_STAGE_SCRIPTS_PRE:
/* Keep the compiler happy */
break;
}
- while (razor_install_iterator_next(ii,&package,&action,&count))
+ while (razor_install_iterator_next(ii,&pkg,&action,&count))
{
+ if (g_cancellable_is_cancelled(cancellable))
+ {
+ razor_atomic_abort(atomic,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_CANCELLED,"Operation was cancelled");
+ return -1;
+ }
if (action==RAZOR_INSTALL_ACTION_REMOVE)
{
- razor_package_get_details(system,package,RAZOR_DETAIL_NAME,&name,
+ razor_package_get_details(system,pkg,RAZOR_DETAIL_NAME,&name,
RAZOR_DETAIL_LAST);
if (stage==RAZOR_STAGE_FILES)
printf(" Removing : %s ",name);
- r=razor_package_remove(system,next,atomic,package,install_root,
- count,stage);
+ r=razor_package_remove(system,plover_package_set_get_razor(next),
+ atomic,pkg,install_root,count,stage);
if (stage==RAZOR_STAGE_FILES)
printf("\n");
}
else if (action==RAZOR_INSTALL_ACTION_ADD)
{
- razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name,
- RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,
- RAZOR_DETAIL_LAST);
- s=rpm_filename(name,version,arch);
- file=plover_strconcat(base,"/rpms/",s,NULL);
- free(s);
- rpm=razor_rpm_open(file,&error);
- free(file);
+ package=plover_package_set_lookup(next,pkg);
+ rpm=plover_repository_open_rpm(upstream,package,&tmp_error);
if (!rpm)
{
- razor_atomic_abort(atomic,razor_error_get_msg(error));
+ plover_propagate_g_error(&error,tmp_error);
+ razor_atomic_propagate_error(atomic,error,NULL);
razor_error_free(error);
return -1;
}
if (stage==RAZOR_STAGE_FILES)
- printf(" Installing : %s ",name);
+ printf(" Installing : %s ",plover_package_get_name(package));
if (relocations)
razor_rpm_set_relocations(rpm,relocations);
- razor_transaction_fixup_package(trans,package,rpm);
+ razor_transaction_fixup_package(trans,pkg,rpm);
r=razor_rpm_install(rpm,atomic,install_root,1,stage);
razor_rpm_close(rpm);
if (stage==RAZOR_STAGE_FILES)
return -1;
else if (r)
{
- razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name,
- RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,
- RAZOR_DETAIL_LAST);
+ package=plover_package_set_lookup(next,pkg);
+ name=plover_package_get_name(package);
+ version=plover_package_get_version(package);
+ arch=plover_package_get_arch(package);
/*
* If a pre or preun script fails, then we should
* treat that as a fatal error. post and postun
*/
if (stage==RAZOR_STAGE_SCRIPTS_PRE)
{
- fprintf(stderr,
- "error: %s(%s-%s.%s) scriptlet failed, exit status %d\n",
- action==RAZOR_INSTALL_ACTION_ADD?"%pre":"%preun",
- name,version,arch,r);
+ t=g_strconcat(action==RAZOR_INSTALL_ACTION_ADD?
+ "%pre":"%preun","(",name,"-",version,".",arch,
+ ") scriptlet failed",NULL);
+ fprintf(stderr,"error: %s, exit status %d\n",t,r);
+ razor_atomic_abort(atomic,PLOVER_SCRIPTLET_ERROR,r,t);
+ g_free(t);
return -1;
}
else
return 0;
}
-int plover_commit_transaction(struct razor_transaction *trans,const char *base,
- const char *install_root,struct razor_root *root,
- struct razor_relocations *relocations)
+gboolean plover_install(const char *base,const char *prefix,char **pkgs,
+ GError **error)
{
- int r,retval;
- size_t pos;
- struct razor_set *system,*next,*set;
- struct razor_install_iterator *ii;
- struct razor_atomic *atomic;
- razor_transaction_resolve(trans);
- if (razor_transaction_describe(trans)>0)
- return -1;
- next=razor_transaction_commit(trans);
- system=razor_set_ref(razor_root_get_system_set(root));
- ii=razor_set_create_install_iterator(system,next);
- do
- {
- pos=razor_install_iterator_tell(ii);
- atomic=razor_atomic_open("package transaction");
- r=plover_run_transaction(trans,ii,base,install_root,system,next,atomic,
- relocations,RAZOR_STAGE_SCRIPTS_PRE);
- if (r<0)
- fprintf(stderr,"Transaction aborted\n");
- else
- {
- razor_install_iterator_seek(ii,pos);
- r=plover_run_transaction(trans,ii,base,install_root,system,next,
- atomic,relocations,RAZOR_STAGE_FILES);
- if (r==1)
- {
- set=razor_install_iterator_commit_set(ii);
- razor_root_update(root,set,atomic);
- razor_set_unref(set);
- }
- else if (!r)
- razor_root_update(root,next,atomic);
- retval=razor_atomic_commit(atomic);
- if (retval)
- fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
- else
- {
- razor_install_iterator_seek(ii,pos);
- plover_run_transaction(trans,ii,base,install_root,system,next,
- atomic,relocations,RAZOR_STAGE_SCRIPTS_POST);
- }
- }
- razor_atomic_destroy(atomic);
- } while(!retval && r==1);
- razor_set_unref(system);
- razor_set_unref(next);
- razor_install_iterator_destroy(ii);
+ gboolean retval;
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new_install(base,prefix,pkgs,error);
+ if (!transaction)
+ return FALSE;
+ retval=plover_transaction_commit(transaction,NULL,error);
+ g_object_unref(transaction);
return retval;
}
-static int plover_mark_package_for_update(struct razor_transaction *trans,
- struct razor_set *set,const char *pkg)
+gboolean plover_update(const char *base,const char *prefix,char **pkgs,
+ GError **error)
{
- struct razor_package_iterator *pi;
- struct razor_package *package;
- const char *name;
- int retval=-1;
- pi=razor_package_iterator_create(set);
- while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
- RAZOR_DETAIL_LAST))
+ gboolean retval;
+ GError *tmp_error=NULL;
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new_update(base,prefix,pkgs,&tmp_error);
+ if (!transaction)
{
- if (!strcmp(name,pkg))
- {
- razor_transaction_update_package(trans,package);
- retval=0;
- break;
- }
- }
- razor_package_iterator_destroy(pi);
- return retval;
-}
-
-int plover_install(const char *base,const char *prefix,char **pkgs)
-{
- int i,retval;
- char *s;
- char *install_root;
- struct razor_set *system,*set,*upstream;
- struct razor_transaction *trans;
- struct razor_relocations *relocations;
- struct razor_root *root;
- struct razor_error *error=NULL;
- install_root=getenv("RAZOR_ROOT");
- if (!install_root)
- install_root="";
- if (prefix)
- {
- relocations=razor_relocations_create();
- razor_relocations_add(relocations,"/usr",prefix);
- }
- else
- relocations=NULL;
- root=razor_root_open(install_root,NULL);
- if (!root)
- {
- if (razor_root_create(install_root,&error))
- root=NULL;
+ retval=g_error_matches(tmp_error,PLOVER_POSIX_ERROR,ENOENT);
+ if (retval)
+ g_error_free(tmp_error);
else
- root=razor_root_open(install_root,&error);
- if (!root)
- {
- fprintf(stderr,"%s\n",razor_error_get_msg(error));
- razor_error_free(error);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
- }
- }
- system=razor_root_get_system_set(root);
- if (!system)
- {
- fprintf(stderr,"Internal error: No system set\n");
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
- }
- s=plover_strconcat(base,"/repodata",NULL);
- if (s)
- {
- retval=chdir(s);
- if (retval<0)
- perror(s);
- }
- else
- {
- fprintf(stderr,"Not enough memory\n");
- retval=-1;
- }
- free(s);
- if (retval<0)
- {
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
- }
- set=plover_razor_set_create_from_yum(base);
- if (set)
- {
- upstream=plover_relocate_packages(set,base,relocations,&error);
- if (!upstream)
- {
- fprintf(stderr,"%s\n",razor_error_get_msg(error));
- razor_error_free(error);
- }
- razor_set_unref(set);
+ g_propagate_error(error,tmp_error);
}
else
- upstream=NULL;
- if (!upstream)
{
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
+ retval=plover_transaction_commit(transaction,NULL,error);
+ g_object_unref(transaction);
}
- trans=razor_transaction_create(system,upstream);
- razor_set_unref(upstream);
- for(i=0;pkgs[i];i++)
- if (plover_mark_package_for_update(trans,system,pkgs[i]) &&
- plover_mark_package_for_update(trans,upstream,pkgs[i]))
- {
- fprintf(stderr,"%s: Package not found\n",pkgs[i]);
- retval=-1;
- break;
- }
- if (!retval)
- retval=plover_commit_transaction(trans,base,install_root,root,
- relocations);
- razor_transaction_destroy(trans);
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
return retval;
}
-int plover_update(const char *base,const char *prefix,char **pkgs)
+gboolean plover_remove(char **pkgs,GError **error)
{
- int i,retval;
- char *install_root,*s;
- struct razor_set *system,*set,*upstream;
- struct razor_transaction *trans;
- struct razor_relocations *relocations;
- struct razor_root *root;
- struct razor_error *error=NULL;
- install_root=getenv("RAZOR_ROOT");
- if (!install_root)
- install_root="";
- if (prefix)
+ gboolean retval;
+ GError *tmp_error=NULL;
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new_remove(pkgs,&tmp_error);
+ if (!transaction)
{
- relocations=razor_relocations_create();
- razor_relocations_add(relocations,"/usr",prefix);
- }
- else
- relocations=NULL;
- root=razor_root_open(install_root,&error);
- if (!root)
- {
- fprintf(stderr,"%s\n",razor_error_get_msg(error));
- razor_error_free(error);
- if (relocations)
- razor_relocations_destroy(relocations);
- return 0;
- }
- system=razor_root_get_system_set(root);
- s=plover_strconcat(base,"/repodata",NULL);
- if (s)
- {
- retval=chdir(s);
+ retval=g_error_matches(tmp_error,PLOVER_POSIX_ERROR,ENOENT);
if (retval)
- perror(s);
- }
- else
- {
- fprintf(stderr,"Not enough memory");
- retval=-1;
- }
- free(s);
- if (retval)
- {
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
- }
- set=plover_razor_set_create_from_yum(base);
- if (set)
- {
- upstream=plover_relocate_packages(set,base,relocations,&error);
- if (!upstream)
{
- fprintf(stderr,"%s\n",razor_error_get_msg(error));
- razor_error_free(error);
- }
- razor_set_unref(set);
- }
- else
- upstream=NULL;
- if (!upstream)
- {
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return -1;
- }
- trans=razor_transaction_create(system,upstream);
- razor_set_unref(upstream);
- if (pkgs)
- for(i=0;pkgs[i];i++)
- {
- if (plover_mark_package_for_update(trans,system,pkgs[i]))
+ g_error_free(tmp_error);
+ if (pkgs)
{
- fprintf(stderr,"%s: Package not found\n",pkgs[i]);
- retval=-1;
- break;
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[0],
+ "Package not found");
+ retval=FALSE;
}
}
- else
- razor_transaction_update_all(trans);
- if (!retval)
- retval=plover_commit_transaction(trans,base,install_root,root,
- relocations);
- razor_transaction_destroy(trans);
- razor_root_close(root);
- if (relocations)
- razor_relocations_destroy(relocations);
- return retval;
-}
-
-static int plover_mark_packages_for_removal(struct razor_transaction *trans,
- struct razor_set *set,const char *pkg)
-{
- struct razor_package_iterator *pi;
- struct razor_package *package;
- const char *name;
- int retval=pkg?-1:0;
- pi=razor_package_iterator_create(set);
- while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
- RAZOR_DETAIL_LAST))
- {
- if (!pkg || !strcmp(name,pkg))
- {
- razor_transaction_remove_package(trans,package);
- retval=0;
- }
+ else
+ g_propagate_error(error,tmp_error);
}
- razor_package_iterator_destroy(pi);
- return retval;
-}
-
-int plover_remove(char **pkgs)
-{
- int i,retval=0;
- char *install_root;
- struct razor_set *system,*upstream;
- struct razor_transaction *trans;
- struct razor_root *root;
- struct razor_error *error=NULL;
- install_root=getenv("RAZOR_ROOT");
- if (!install_root)
- install_root="";
- root=razor_root_open(install_root,&error);
- if (!root)
+ else
{
- fprintf(stderr,"%s\n",razor_error_get_msg(error));
- razor_error_free(error);
- return 0;
+ retval=plover_transaction_commit(transaction,NULL,error);
+ g_object_unref(transaction);
}
- system=razor_root_get_system_set(root);
- upstream=razor_set_create_without_root();
- trans=razor_transaction_create(system,upstream);
- razor_set_unref(upstream);
- if (pkgs)
- for(i=0;pkgs[i];i++)
- {
- if (plover_mark_packages_for_removal(trans,system,pkgs[i]))
- {
- fprintf(stderr,"%s: Package not found\n",pkgs[i]);
- retval=-1;
- break;
- }
- }
- else
- plover_mark_packages_for_removal(trans,system,NULL);
- if (!retval)
- retval=plover_commit_transaction(trans,NULL,install_root,root,NULL);
- razor_transaction_destroy(trans);
- razor_root_close(root);
return retval;
}
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+#include <razor.h>
+#include <plover/plover.h>
+#include <plover/repository.h>
+
+G_DEFINE_TYPE(PloverRepository,plover_repository,G_TYPE_OBJECT);
+
+typedef struct _PloverRepositoryPrivate {
+ PloverPackageSet *set;
+ gchar **filenames;
+} PloverRepositoryPrivate;
+
+#define PLOVER_REPOSITORY_GET_PRIVATE(obj)\
+ G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+ PLOVER_TYPE_REPOSITORY,\
+ PloverRepositoryPrivate)
+
+static void plover_repository_finalize(GObject *obj)
+{
+ PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj);
+ g_strfreev(priv->filenames);
+ if (G_OBJECT_CLASS(plover_repository_parent_class)->finalize)
+ G_OBJECT_CLASS(plover_repository_parent_class)->finalize(obj);
+}
+
+static void plover_repository_dispose(GObject *obj)
+{
+ PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj);
+ g_clear_object(&priv->set);
+ if (G_OBJECT_CLASS(plover_repository_parent_class)->dispose)
+ G_OBJECT_CLASS(plover_repository_parent_class)->dispose(obj);
+}
+
+static void plover_repository_class_init(PloverRepositoryClass *klass)
+{
+ GObjectClass *oclass=G_OBJECT_CLASS(klass);
+ oclass->finalize=plover_repository_finalize;
+ oclass->dispose=plover_repository_dispose;
+ g_type_class_add_private(klass,sizeof(PloverRepositoryPrivate));
+}
+
+static void plover_repository_init(PloverRepository *repository)
+{
+}
+
+PloverRepository *plover_repository_new_from_files(const char **filenames,
+ GError **error)
+{
+ PloverPackageSet *set;
+ PloverRepository *repository;
+ PloverRepositoryPrivate *priv;
+ set=plover_package_set_new_from_rpms(filenames,error);
+ if (!set)
+ return NULL;
+ repository=g_object_new(PLOVER_TYPE_REPOSITORY,NULL);
+ priv=PLOVER_REPOSITORY_GET_PRIVATE(repository);
+ priv->filenames=g_strdupv((gchar **)filenames);
+ priv->set=set;
+ return repository;
+}
+
+static char *rpm_filename(const char *name,const char *version,const char *arch)
+{
+ const char *v;
+ v=strchr(version,':'); /* Skip epoch */
+ if (v)
+ v++;
+ else
+ v=version;
+ return g_strconcat(name,"-",v,".",arch,".rpm",NULL);
+}
+
+PloverRepository *plover_repository_new_from_yum(const char *base,
+ GError **error)
+{
+ char *s;
+ const char *name,*version,*arch;
+ GPtrArray *filenames;
+ struct razor_set *imported;
+ struct razor_package *package;
+ struct razor_package_iterator *pi;
+ PloverPackageSet *set;
+ PloverRepository *repository;
+ PloverRepositoryPrivate *priv;
+ imported=plover_razor_set_create_from_yum(base,error);
+ if (!imported)
+ return NULL;
+ set=plover_package_set_new_from_razor(imported);
+ razor_set_unref(imported);
+ repository=g_object_new(PLOVER_TYPE_REPOSITORY,NULL);
+ priv=PLOVER_REPOSITORY_GET_PRIVATE(repository);
+ filenames=g_ptr_array_new();
+ pi=razor_package_iterator_create(plover_package_set_get_razor(set));
+ while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST))
+ {
+ s=rpm_filename(name,version,arch);
+ g_ptr_array_add(filenames,g_build_filename(base,"rpms",s,NULL));
+ free(s);
+ }
+ razor_package_iterator_destroy(pi);
+ g_ptr_array_add(filenames,NULL);
+ priv->filenames=(gchar **)g_ptr_array_free(filenames,FALSE);
+ priv->set=set;
+ return repository;
+}
+
+PloverPackageSet *
+ plover_repository_get_package_set(PloverRepository *repository)
+{
+ PloverRepositoryPrivate *priv;
+ g_return_val_if_fail(PLOVER_IS_REPOSITORY(repository),NULL);
+ priv=PLOVER_REPOSITORY_GET_PRIVATE(repository);
+ return priv->set;
+}
+
+struct razor_rpm *plover_repository_open_rpm(PloverRepository *repository,
+ PloverPackage *package,GError **error)
+{
+ int nth;
+ struct razor_rpm *rpm;
+ struct razor_error *tmp_error=NULL;
+ PloverRepositoryPrivate *priv;
+ PloverPackage *internal;
+ g_return_val_if_fail(PLOVER_IS_REPOSITORY(repository),NULL);
+ g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+ priv=PLOVER_REPOSITORY_GET_PRIVATE(repository);
+ nth=g_slist_index(plover_package_set_get_packages(priv->set),package);
+ if (nth<0)
+ {
+ internal=plover_package_set_find_matching(priv->set,package);
+ nth=g_slist_index(plover_package_set_get_packages(priv->set),internal);
+ }
+ if (nth<0)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,
+ "%s-%s.%s: Package not in repository",
+ plover_package_get_name(package),plover_package_get_version(package),
+ plover_package_get_arch(package));
+ return NULL;
+ }
+ rpm=razor_rpm_open(priv->filenames[nth],&tmp_error);
+ if (!rpm)
+ plover_propagate_razor_error(error,tmp_error);
+ return rpm;
+}
--- /dev/null
+#ifndef __PLOVER_REPOSITORY_H__
+#define __PLOVER_REPOSITORY_H__
+
+#include <razor.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_REPOSITORY plover_repository_get_type()
+#define PLOVER_REPOSITORY(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\
+ PLOVER_TYPE_REPOSITORY,PloverRepository)
+#define PLOVER_REPOSITORY_CLASS(klass)\
+ G_TYPE_CHECK_CLASS_CAST(klass,\
+ PLOVER_TYPE_REPOSITORY,PloverRepositoryClass)
+#define PLOVER_IS_REPOSITORY(obj)\
+ G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+ PLOVER_TYPE_REPOSITORY)
+#define PLOVER_IS_REPOSITORY_CLASS(klass)\
+ G_TYPE_CHECK_CLASS_TYPE(obj,\
+ PLOVER_TYPE_REPOSITORY)
+#define PLOVER_REPOSITORY_GET_CLASS(obj)\
+ G_TYPE_INSTANCE_GET_CLASS(obj,\
+ PLOVER_TYPE_REPOSITORY,PloverRepositoryClass)
+
+typedef struct _PloverRepository {
+ GObject parent_instance;
+} PloverRepository;
+
+typedef struct _PloverRepositoryClass {
+ GObjectClass parent_class;
+} PloverRepositoryClass;
+
+#include <plover/package.h>
+#include <plover/packageset.h>
+
+GType plover_repository_get_type(void) G_GNUC_CONST;
+PloverRepository *plover_repository_new_from_files(const char **filenames,
+ GError **error);
+PloverRepository *plover_repository_new_from_yum(const char *base,
+ GError **error);
+PloverPackageSet *
+ plover_repository_get_package_set(PloverRepository *repository);
+struct razor_rpm *plover_repository_open_rpm(PloverRepository *repository,
+ PloverPackage *package,GError **error);
+
+G_END_DECLS
+
+#endif /* __PLOVER_REPOSITORY_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <glib-object.h>
+#include "plover/transaction.h"
+#include "plover/plover.h"
+
+G_DEFINE_TYPE(PloverTransaction,plover_transaction,G_TYPE_OBJECT);
+
+enum {
+ STATUS_CHANGED=0,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_transaction_finalize(PloverTransaction *transaction)
+{
+ g_free(transaction->base);
+ g_free(transaction->prefix);
+ g_free(transaction->unsatisfied);
+ if (transaction->trans)
+ razor_transaction_destroy(transaction->trans);
+ if (transaction->relocations)
+ razor_relocations_destroy(transaction->relocations);
+ if (transaction->install_iterator)
+ razor_install_iterator_destroy(transaction->install_iterator);
+ if (transaction->next)
+ razor_set_unref(transaction->next);
+ if (transaction->system)
+ razor_set_unref(transaction->system);
+}
+
+static void plover_transaction_dispose(PloverTransaction *transaction)
+{
+ g_clear_object(&transaction->installed);
+ g_clear_object(&transaction->relocated);
+ g_clear_object(&transaction->upstream);
+}
+
+static void plover_transaction_class_init(PloverTransactionClass *klass)
+{
+ GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
+ gobject_class->finalize=(void (*)(GObject *))plover_transaction_finalize;
+ gobject_class->dispose=(void (*)(GObject *))plover_transaction_dispose;
+ signals[STATUS_CHANGED]=g_signal_new("status-changed",
+ G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,0,NULL,NULL,
+ g_cclosure_marshal_VOID__STRING,G_TYPE_NONE,1,G_TYPE_STRING);
+}
+
+static void plover_transaction_init(PloverTransaction *transaction)
+{
+}
+
+gboolean plover_transaction_resolve(PloverTransaction *transaction,
+ GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ if (!(transaction->flags&PLOVER_TRANSACTION_RESOLVED))
+ {
+ razor_transaction_resolve(transaction->trans);
+ transaction->flags|=PLOVER_TRANSACTION_RESOLVED;
+ g_free(transaction->unsatisfied);
+ transaction->unsatisfied=NULL;
+ if (razor_transaction_describe(transaction->trans)>0)
+ transaction->flags|=PLOVER_TRANSACTION_UNSATISFIED;
+ }
+ if (transaction->flags&PLOVER_TRANSACTION_UNSATISFIED)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
+ "Package requirements not met");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void plover_transaction_unsatisfied_callback(const char *requirement,
+ struct razor_package *package,const char *name,const char *version,
+ const char *arch,void *data)
+{
+ GString *string=data;
+ g_string_append_printf(string,"%s is needed by %s-%s.%s\n",requirement,name,
+ version,arch);
+}
+
+const char *plover_transaction_get_unsatisfied(PloverTransaction *transaction)
+{
+ GString *unsatisfied;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
+ if (plover_transaction_resolve(transaction,NULL))
+ return NULL;
+ else if (!transaction->unsatisfied)
+ {
+ unsatisfied=g_string_new(NULL);
+ if (!razor_transaction_unsatisfied(transaction->trans,
+ plover_transaction_unsatisfied_callback,unsatisfied))
+ /* Impossible */
+ g_string_assign(unsatisfied,
+ "Unknown package requirements unsatisfied");
+ transaction->unsatisfied=g_string_free(unsatisfied,FALSE);
+ }
+ return transaction->unsatisfied;
+}
+
+struct razor_set *plover_transaction_get_system_set(
+ PloverTransaction *transaction)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
+ if (!transaction->system && transaction->installed)
+ {
+ transaction->system=
+ plover_package_set_get_razor(transaction->installed);
+ if (transaction->system)
+ razor_set_ref(transaction->system);
+ }
+ return transaction->system;
+}
+
+struct razor_set *plover_transaction_get_next_set(
+ PloverTransaction *transaction,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
+ if (!transaction->next)
+ {
+ if (!plover_transaction_resolve(transaction,error))
+ return NULL;
+ transaction->next=razor_transaction_commit(transaction->trans);
+ }
+ return transaction->next;
+}
+
+struct razor_install_iterator *plover_transaction_get_install_iterator(
+ PloverTransaction *transaction,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
+ if (!transaction->install_iterator)
+ {
+ if (!plover_transaction_get_next_set(transaction,error))
+ return NULL;
+ (void)plover_transaction_get_system_set(transaction);
+ transaction->install_iterator=
+ razor_set_create_install_iterator(transaction->system,
+ transaction->next);
+ }
+ razor_install_iterator_rewind(transaction->install_iterator);
+ return transaction->install_iterator;
+}
+
+gboolean plover_transaction_commit(PloverTransaction *transaction,
+ GCancellable *cancellable,GError **error)
+{
+ int r;
+ gboolean retval;
+ size_t pos;
+ struct razor_set *set;
+ struct razor_install_iterator *ii;
+ struct razor_atomic *atomic;
+ PloverPackageSet *next;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ if (g_cancellable_set_error_if_cancelled(cancellable,error))
+ return FALSE;
+ ii=plover_transaction_get_install_iterator(transaction,error);
+ if (!ii)
+ return FALSE;
+ do
+ {
+ if (g_cancellable_set_error_if_cancelled(cancellable,error))
+ return FALSE;
+ pos=razor_install_iterator_tell(ii);
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,
+ "Running pre-transaction scripts");
+ atomic=razor_atomic_open("package transaction");
+ next=plover_package_set_new_from_razor(transaction->next);
+ r=plover_run_transaction(transaction->trans,ii,
+ plover_package_set_get_install_root(transaction->installed),
+ transaction->system,next,transaction->upstream,atomic,
+ transaction->relocations,RAZOR_STAGE_SCRIPTS_PRE,cancellable);
+ if (r<0)
+ {
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,
+ "Failed in pre-transaction scripts");
+ plover_propagate_razor_error_dup(error,
+ razor_atomic_get_error(atomic));
+ razor_atomic_destroy(atomic);
+ g_object_unref(next);
+ return FALSE;
+ }
+ else
+ {
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,
+ "Unpacking files");
+ razor_install_iterator_seek(ii,pos);
+ r=plover_run_transaction(transaction->trans,ii,
+ plover_package_set_get_install_root(transaction->installed),
+ transaction->system,next,transaction->upstream,
+ atomic,transaction->relocations,RAZOR_STAGE_FILES,
+#if RAZOR_HAVE_ATOMIC_ROLLBACK
+ cancellable);
+#else
+ NULL);
+#endif
+ if (r==1)
+ {
+ set=razor_install_iterator_commit_set(ii);
+ plover_package_set_update(transaction->installed,set,atomic);
+ razor_set_unref(set);
+ }
+ else if (!r)
+ plover_package_set_update(transaction->installed,
+ transaction->next,atomic);
+ retval=!razor_atomic_commit(atomic);
+ if (!retval)
+ {
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,
+ "Failed to unpack all files correctly");
+ plover_propagate_razor_error_dup(error,
+ razor_atomic_get_error(atomic));
+ }
+ else
+ {
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,
+ "Running post-transaction scripts");
+ razor_install_iterator_seek(ii,pos);
+ plover_run_transaction(transaction->trans,ii,
+ plover_package_set_get_install_root(transaction->installed),
+ transaction->system,next,transaction->upstream,
+ atomic,transaction->relocations,RAZOR_STAGE_SCRIPTS_POST,
+ NULL);
+ }
+ }
+ razor_atomic_destroy(atomic);
+ g_object_unref(next);
+ } while(retval && r==1);
+ g_signal_emit(transaction,signals[STATUS_CHANGED],0,"Completed");
+ return retval;
+}
+
+static void plover_transaction_commit_async_thread(GTask *task,
+ gpointer source_object,gpointer task_data,GCancellable *cancellable)
+{
+ PloverTransaction *transaction=source_object;
+ GError *error=NULL;
+ if (!plover_transaction_commit(transaction,cancellable,&error))
+ g_task_return_error(task,error);
+ else
+ g_task_return_boolean(task,TRUE);
+ g_object_unref(task);
+}
+
+void plover_transaction_commit_async(PloverTransaction *transaction,
+ GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data)
+{
+ GTask *task;
+ g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
+ task=g_task_new(transaction,cancellable,callback,user_data);
+ g_task_run_in_thread(task,plover_transaction_commit_async_thread);
+}
+
+gboolean plover_transaction_commit_finish(PloverTransaction *transaction,
+ GAsyncResult *result,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(g_task_is_valid(result,transaction),FALSE);
+ return g_task_propagate_boolean(G_TASK(result),error);
+}
+
+static int plover_mark_package_for_update(struct razor_transaction *trans,
+ struct razor_set *set,const char *pkg)
+{
+ struct razor_package_iterator *pi;
+ struct razor_package *package;
+ const char *name;
+ int retval=-1;
+ pi=razor_package_iterator_create(set);
+ while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_LAST))
+ {
+ if (!strcmp(name,pkg))
+ {
+ razor_transaction_update_package(trans,package);
+ retval=0;
+ break;
+ }
+ }
+ razor_package_iterator_destroy(pi);
+ return retval;
+}
+
+PloverTransaction *plover_transaction_new(void)
+{
+ return PLOVER_TRANSACTION(g_object_new(PLOVER_TYPE_TRANSACTION,NULL));
+}
+
+void plover_transaction_set_prefix(PloverTransaction *transaction,
+ const char *prefix)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
+ g_return_if_fail(transaction->upstream == NULL);
+ if (!g_strcmp0(prefix,transaction->prefix))
+ return;
+ if (transaction->relocations)
+ razor_relocations_destroy(transaction->relocations);
+ g_free(transaction->prefix);
+ if (prefix)
+ {
+ transaction->relocations=razor_relocations_create();
+ razor_relocations_add(transaction->relocations,"/usr",prefix);
+ }
+ else
+ transaction->relocations=NULL;
+ transaction->prefix=g_strdup(prefix);
+}
+
+void plover_transaction_set_installed(PloverTransaction *transaction,
+ PloverPackageSet *installed)
+{
+ g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
+ g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
+ if (transaction->installed)
+ g_object_unref(transaction->installed);
+ transaction->installed=g_object_ref(installed);
+}
+
+gboolean plover_transaction_root_open(PloverTransaction *transaction,
+ const char *install_root,GError **error)
+{
+ PloverPackageSet *installed;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ if (!install_root)
+ install_root=g_getenv("RAZOR_ROOT");
+ if (!install_root)
+ install_root="";
+ if (transaction->installed && !g_strcmp0(install_root,
+ plover_package_set_get_install_root(transaction->installed)))
+ return TRUE;
+ installed=plover_package_set_new();
+ if (!plover_package_set_open(installed,install_root,TRUE,error))
+ {
+ g_object_unref(installed);
+ return FALSE;
+ }
+ if (transaction->installed)
+ g_object_unref(transaction->installed);
+ transaction->installed=installed;
+ return TRUE;
+}
+
+struct razor_set *plover_transaction_import_yum(PloverTransaction *transaction,
+ const char *base,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
+ g_return_val_if_fail(transaction->base == NULL,NULL);
+ transaction->base=g_strdup(base);
+ return plover_razor_set_create_from_yum(base,error);
+}
+
+gboolean plover_transaction_set_upstream(PloverTransaction *transaction,
+ PloverRepository *upstream,GError **error)
+{
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(PLOVER_IS_REPOSITORY(upstream),FALSE);
+ g_return_val_if_fail(transaction->upstream == NULL,FALSE);
+ transaction->relocated=plover_package_set_new_from_repository(upstream,
+ transaction->relocations,error);
+ if (transaction->relocated)
+ transaction->upstream=g_object_ref(upstream);
+ return !!transaction->relocated;
+}
+
+gboolean
+ plover_transaction_set_upstream_from_yum(PloverTransaction *transaction,
+ const char *base,GError **error)
+{
+ gboolean retval;
+ PloverRepository *upstream;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(transaction->upstream == NULL,FALSE);
+ upstream=plover_repository_new_from_yum(base,error);
+ if (!upstream)
+ return FALSE;
+ retval=plover_transaction_set_upstream(transaction,upstream,error);
+ g_object_unref(upstream);
+ return retval;
+}
+
+gboolean plover_transaction_install(PloverTransaction *transaction,
+ char **pkgs,GError **error)
+{
+ int i;
+ struct razor_set *system,*upstream;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(transaction->upstream != NULL,FALSE);
+ g_return_val_if_fail(transaction->trans == NULL,FALSE);
+ if (!plover_transaction_root_open(transaction,NULL,error))
+ return FALSE;
+ system=plover_transaction_get_system_set(transaction);
+ if (!system)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error: No system set");
+ return FALSE;
+ }
+ upstream=plover_package_set_get_razor(transaction->relocated);
+ transaction->trans=razor_transaction_create(system,upstream);
+ for(i=0;pkgs[i];i++)
+ if (plover_mark_package_for_update(transaction->trans,system,pkgs[i]) &&
+ plover_mark_package_for_update(transaction->trans,upstream,pkgs[i]))
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
+ "Package not found");
+ razor_transaction_destroy(transaction->trans);
+ transaction->trans=NULL;
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+gboolean plover_transaction_update(PloverTransaction *transaction,
+ char **pkgs,GError **error)
+{
+ int i;
+ struct razor_set *system,*upstream;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(transaction->upstream != NULL,FALSE);
+ g_return_val_if_fail(transaction->trans == NULL,FALSE);
+ if (!plover_transaction_root_open(transaction,NULL,error))
+ return FALSE;
+ system=plover_transaction_get_system_set(transaction);
+ if (!system)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error: No system set");
+ return FALSE;
+ }
+ upstream=plover_package_set_get_razor(transaction->relocated);
+ transaction->trans=razor_transaction_create(system,upstream);
+ if (!pkgs)
+ razor_transaction_update_all(transaction->trans);
+ else
+ for(i=0;pkgs[i];i++)
+ if (plover_mark_package_for_update(transaction->trans,system,
+ pkgs[i]))
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
+ "Package not found");
+ razor_transaction_destroy(transaction->trans);
+ transaction->trans=NULL;
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+PloverTransaction *plover_transaction_new_install(const char *base,
+ const char *prefix,char **pkgs,GError **error)
+{
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new();
+ plover_transaction_set_prefix(transaction,prefix);
+ if (!plover_transaction_set_upstream_from_yum(transaction,base,error))
+ {
+ g_object_unref(transaction);
+ return NULL;
+ }
+ if (!plover_transaction_install(transaction,pkgs,error))
+ {
+ g_object_unref(transaction);
+ return NULL;
+ }
+ return transaction;
+}
+
+PloverTransaction *plover_transaction_new_update(const char *base,
+ const char *prefix,char **pkgs,GError **error)
+{
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new();
+ plover_transaction_set_prefix(transaction,prefix);
+ if (!plover_transaction_set_upstream_from_yum(transaction,base,error))
+ {
+ g_object_unref(transaction);
+ return NULL;
+ }
+ if (!plover_transaction_update(transaction,pkgs,error))
+ {
+ g_object_unref(transaction);
+ return NULL;
+ }
+ return transaction;
+}
+
+static int plover_mark_packages_for_removal(struct razor_transaction *trans,
+ struct razor_set *set,const char *pkg)
+{
+ struct razor_package_iterator *pi;
+ struct razor_package *package;
+ const char *name;
+ int retval=pkg?-1:0;
+ pi=razor_package_iterator_create(set);
+ while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
+ RAZOR_DETAIL_LAST))
+ {
+ if (!pkg || !strcmp(name,pkg))
+ {
+ razor_transaction_remove_package(trans,package);
+ retval=0;
+ }
+ }
+ razor_package_iterator_destroy(pi);
+ return retval;
+}
+
+gboolean plover_transaction_remove(PloverTransaction *transaction,
+ char **pkgs,GError **error)
+{
+ int i;
+ struct razor_set *system,*empty;
+ g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
+ g_return_val_if_fail(transaction->trans == NULL,FALSE);
+ if (!plover_transaction_root_open(transaction,NULL,error))
+ return FALSE;
+ system=plover_transaction_get_system_set(transaction);
+ if (!system)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
+ "Internal error: No system set");
+ return FALSE;
+ }
+ empty=razor_set_create_without_root();
+ transaction->trans=razor_transaction_create(system,empty);
+ razor_set_unref(empty);
+ if (!pkgs)
+ plover_mark_packages_for_removal(transaction->trans,system,NULL);
+ else
+ for(i=0;pkgs[i];i++)
+ if (plover_mark_packages_for_removal(transaction->trans,system,
+ pkgs[i]))
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
+ "Package not found");
+ razor_transaction_destroy(transaction->trans);
+ transaction->trans=NULL;
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+PloverTransaction *plover_transaction_new_remove(char **pkgs,GError **error)
+{
+ PloverTransaction *transaction;
+ transaction=plover_transaction_new();
+ if (!plover_transaction_remove(transaction,pkgs,error))
+ {
+ g_object_unref(transaction);
+ return NULL;
+ }
+ return transaction;
+}
+
+static GList *plover_what_requires(struct razor_set *set,const char *ref_name)
+{
+ const char *name,*version;
+ uint32_t flags;
+ GList *list=NULL;
+ struct razor_property *property;
+ struct razor_package *package;
+ struct razor_package_iterator *what_requires;
+ struct razor_property_iterator *all_props;
+ all_props=razor_property_iterator_create(set,NULL);
+ while (razor_property_iterator_next(all_props,&property,&name,&flags,
+ &version))
+ {
+ if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=RAZOR_PROPERTY_REQUIRES)
+ continue;
+ if (strcmp(name,ref_name))
+ continue;
+ what_requires=razor_package_iterator_create_for_property(set,property);
+ while(razor_package_iterator_next(what_requires,&package,
+ RAZOR_DETAIL_LAST))
+ list=g_list_prepend(list,package);
+ razor_package_iterator_destroy(what_requires);
+ }
+ razor_property_iterator_destroy(all_props);
+ return list;
+}
+
+/*
+ * Warning: This code is untested and probably wrong.
+ */
+PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs,
+ GError **error)
+{
+ int i,changed,is_leaf;
+ uint32_t flags;
+ const char *install_root;
+ const char *name,*version,*maybe_unused_name;
+ struct razor_set *system,*upstream;
+ struct razor_transaction *trans;
+ PloverPackageSet *installed;
+ PloverTransaction *transaction;
+ if (!pkgs)
+ return plover_transaction_new_remove(NULL,error);
+ installed=plover_package_set_new();
+ install_root=g_getenv("RAZOR_ROOT");
+ if (!install_root)
+ install_root="";
+ if (!plover_package_set_open(installed,install_root,TRUE,error))
+ {
+ g_object_unref(installed);
+ return NULL;
+ }
+ system=plover_package_set_get_razor(installed);
+ struct plover_vector *package_names;
+ GList *to_remove,*lnk,*what_requires;
+ struct razor_package *package,*maybe_unused_package;
+ struct razor_property *property;
+ struct razor_package_query *query;
+ struct razor_package_iterator *all_packages,*removed,*maybe_unused;
+ struct razor_property_iterator *removed_props;
+ package_names=plover_vector_new();
+ for(i=0;pkgs[i];i++)
+ plover_vector_append(package_names,pkgs[i]);
+ to_remove=NULL;
+ all_packages=razor_package_iterator_create(system);
+ while (razor_package_iterator_next(all_packages,&package,
+ RAZOR_DETAIL_NAME,&name,RAZOR_DETAIL_LAST))
+ if (plover_vector_remove(package_names,name))
+ to_remove=g_list_prepend(to_remove,package);
+ razor_package_iterator_destroy(all_packages);
+ if (package_names->len)
+ {
+ g_set_error(error,PLOVER_GENERAL_ERROR,
+ PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",
+ package_names->strings[0],"Package not found");
+ plover_vector_free(package_names);
+ g_list_free(to_remove);
+ g_object_unref(installed);
+ return NULL;
+ }
+ plover_vector_free(package_names);
+ do
+ {
+ changed=FALSE;
+ query=razor_package_query_create(system);
+ for(lnk=to_remove;lnk;lnk=lnk->next)
+ razor_package_query_add_package(query,lnk->data);
+ removed=razor_package_query_finish(query);
+ while(razor_package_iterator_next(removed,&package,RAZOR_DETAIL_LAST))
+ {
+ removed_props=razor_property_iterator_create(system,package);
+ while (razor_property_iterator_next(removed_props,&property,&name,
+ &flags,&version))
+ {
+ if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=RAZOR_PROPERTY_REQUIRES)
+ continue;
+ maybe_unused=razor_package_iterator_create_for_property(system,
+ property);
+ while(razor_package_iterator_next(maybe_unused,
+ &maybe_unused_package,RAZOR_DETAIL_NAME,&maybe_unused_name,
+ RAZOR_DETAIL_LAST))
+ {
+ if (g_list_find(to_remove,maybe_unused_package))
+ continue;
+ is_leaf=TRUE;
+ what_requires=plover_what_requires(system,
+ maybe_unused_name);
+ for(lnk=what_requires;lnk;lnk=lnk->next)
+ if (!g_list_find(to_remove,lnk->data))
+ {
+ is_leaf=FALSE;
+ break;
+ }
+ g_list_free(what_requires);
+ if (is_leaf)
+ {
+ to_remove=g_list_prepend(to_remove,
+ maybe_unused_package);
+ changed=TRUE;
+ }
+ }
+ razor_package_iterator_destroy(maybe_unused);
+ }
+ razor_property_iterator_destroy(removed_props);
+ }
+ razor_package_iterator_destroy(removed);
+ } while(changed);
+ upstream=razor_set_create_without_root();
+ trans=razor_transaction_create(system,upstream);
+ razor_set_unref(upstream);
+ for(lnk=to_remove;lnk;lnk=lnk->next)
+ razor_transaction_remove_package(trans,lnk->data);
+ transaction=plover_transaction_new();
+ transaction->trans=trans;
+ transaction->installed=installed;
+ return transaction;
+}
--- /dev/null
+#ifndef __PLOVER_TRANSACTION_H__
+#define __PLOVER_TRANSACTION_H__
+
+#include <razor.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <plover/packageset.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_TRANSACTION plover_transaction_get_type()
+#define PLOVER_TRANSACTION(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\
+ PLOVER_TYPE_TRANSACTION,\
+ PloverTransaction)
+#define PLOVER_IS_TRANSACTION(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+ PLOVER_TYPE_TRANSACTION)
+
+typedef enum {
+ PLOVER_TRANSACTION_RESOLVED=1<<0,
+ PLOVER_TRANSACTION_UNSATISFIED=1<<1,
+} PloverTransactionFlags;
+
+typedef struct _PloverTransaction {
+ GObject parent_instance;
+ PloverTransactionFlags flags;
+ struct razor_transaction *trans;
+ char *prefix;
+ char *base;
+ char *install_root;
+ char *unsatisfied;
+ PloverPackageSet *installed,*relocated;
+ PloverRepository *upstream;
+ struct razor_relocations *relocations;
+ struct razor_set *next,*system;
+ struct razor_install_iterator *install_iterator;
+} PloverTransaction;
+
+typedef struct _PloverTransactionClass {
+ GObjectClass parent_class;
+} PloverTransactionClass;
+
+GType plover_transaction_get_type(void) G_GNUC_CONST;
+void plover_transaction_commit_async(PloverTransaction *transaction,
+ GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);
+gboolean plover_transaction_commit_finish(PloverTransaction *transaction,
+ GAsyncResult *result,GError **error);
+PloverTransaction *plover_transaction_new();
+void plover_transaction_set_prefix(PloverTransaction *transaction,
+ const char *prefix);
+void plover_transaction_set_installed(PloverTransaction *transaction,
+ PloverPackageSet *installed);
+gboolean plover_transaction_root_open(PloverTransaction *transaction,
+ const char *install_root,GError **error);
+struct razor_set *plover_transaction_import_yum(PloverTransaction *transaction,
+ const char *base,GError **error);
+gboolean plover_transaction_set_upstream(PloverTransaction *transaction,
+ PloverRepository *upstream,GError **error);
+gboolean
+ plover_transaction_set_upstream_from_yum(PloverTransaction *transaction,
+ const char *base,GError **error);
+gboolean plover_transaction_install(PloverTransaction *transaction,
+ char **pkgs,GError **error);
+PloverTransaction *plover_transaction_new_install(const char *base,
+ const char *prefix,char **pkgs,GError **error);
+gboolean plover_transaction_update(PloverTransaction *transaction,
+ char **pkgs,GError **error);
+PloverTransaction *plover_transaction_new_update(const char *base,
+ const char *prefix,char **pkgs,GError **error);
+gboolean plover_transaction_remove(PloverTransaction *transaction,
+ char **pkgs,GError **error);
+PloverTransaction *plover_transaction_new_remove(char **pkgs,
+ GError **error);
+gboolean plover_transaction_resolve(PloverTransaction *transaction,
+ GError **error);
+const char *plover_transaction_get_unsatisfied(PloverTransaction *transaction);
+struct razor_set *plover_transaction_get_system_set(
+ PloverTransaction *transaction);
+struct razor_set *plover_transaction_get_next_set(
+ PloverTransaction *transaction,GError **error);
+struct razor_install_iterator *plover_transaction_get_install_iterator(
+ PloverTransaction *transaction,GError **error);
+gboolean plover_transaction_commit(PloverTransaction *transaction,
+ GCancellable *cancellable,GError **error);
+void plover_transaction_commit_async(PloverTransaction *transaction,
+ GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data);
+
+#endif /* __PLOVER_TRANSACTION_H__ */
/*
- * Copyright (C) 2009, 2011 J. Ali Harlow <ali@juiblex.co.uk>
+ * Copyright (C) 2009, 2011, 2014 J. Ali Harlow <ali@juiblex.co.uk>
*
* 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
#include "config.h"
#include "plover.h"
-char *plover_strconcat(const char *string,...)
-{
- va_list ap,aq;
- size_t n;
- char *result=NULL,*t;
- const char *s;
- if (string)
- {
- va_start(ap,string);
- va_copy(aq,ap);
- n=strlen(string);
- while((s=va_arg(aq,const char *)))
- n+=strlen(s);
- va_end(aq);
- result=malloc(n+1);
- if (result)
- {
- strcpy(result,string);
- t=result+strlen(result);
- while((s=va_arg(ap,const char *)))
- {
- strcpy(t,s);
- t+=strlen(t);
- }
- }
- va_end(ap);
- }
- return result;
-}
-
-char *plover_default_prefix_for_vendor(const char *vendor)
+gchar *plover_default_prefix_for_vendor(const char *vendor)
{
#ifdef WIN32
/*
buf);
program_files=buf;
}
- return plover_strconcat(program_files,"\\",vendor?vendor:"Plover",NULL);
+ return g_strconcat(program_files,"\\",vendor?vendor:"Plover",NULL);
#else
return NULL;
#endif
}
+gchar *plover_pre_install_prefix(void)
+{
+#ifdef WIN32
+ {
+ HRESULT result;
+ HKEY key;
+ DWORD type,nb;
+ int len;
+ gunichar2 *str2;
+ gchar *root=NULL;
+ result=RegOpenKeyW(HKEY_LOCAL_MACHINE,L"Software\\Plover",&key);
+ if (result==ERROR_SUCCESS)
+ {
+ result=RegQueryValueExW(key,L"Root",0,&type,0,&nb);
+ if (result==ERROR_SUCCESS && type==REG_SZ)
+ {
+ str2=malloc(nb);
+ result=RegQueryValueExW(key,L"Root",0,NULL,(void *)str2,&nb);
+ len=nb/2;
+ if (!str2[len-1]) /* Cope with unterminated strings */
+ len--;
+ root=g_utf16_to_utf8(str2,len,NULL,NULL,NULL);
+ free(str2);
+ }
+ RegCloseKey(key);
+ }
+ if (!root)
+ {
+ root=plover_default_prefix_for_vendor("Plover Root");
+ result=RegCreateKeyExW(HKEY_LOCAL_MACHINE,L"Software\\Plover",0,
+ NULL,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&key,NULL);
+ if (result==ERROR_SUCCESS)
+ {
+ str2=g_utf8_to_utf16(root,-1,NULL,NULL,NULL);
+ RegSetValueExW(key,L"Root",0,REG_SZ,(void *)str2,
+ (strlen(root)+1)*sizeof(gunichar2));
+ g_free(str2);
+ RegCloseKey(key);
+ }
+ }
+ return root;
+ }
+#else
+ return g_strdup("/var/lib/plover/root");
+#endif
+}
+
/*
* Get the directory containing the program executable.
*/
return strdup(".");
#endif
}
+
+G_DEFINE_QUARK(plover-razor-error-quark,plover_razor_error)
+G_DEFINE_QUARK(plover-mswin-error-quark,plover_mswin_error)
+G_DEFINE_QUARK(plover-posix-error-quark,plover_posix_error)
+G_DEFINE_QUARK(plover-zlib-error-quark,plover_zlib_error)
+
+void plover_propagate_razor_error_dup(GError **dest,struct razor_error *src)
+{
+ GQuark domain;
+ int code;
+ if (dest)
+ {
+ code=razor_error_get_code(src);
+ switch(razor_error_get_domain(src))
+ {
+ case RAZOR_GENERAL_ERROR:
+ domain=PLOVER_RAZOR_ERROR;
+ break;
+ case RAZOR_POSIX_ERROR:
+ domain=PLOVER_POSIX_ERROR;
+ break;
+ case RAZOR_MSWIN_ERROR:
+ domain=PLOVER_MSWIN_ERROR;
+ break;
+ case RAZOR_ZLIB_ERROR:
+ domain=PLOVER_ZLIB_ERROR;
+ break;
+ case PLOVER_GENERAL_ERROR:
+ if (code==PLOVER_GENERAL_ERROR_CANCELLED)
+ {
+ domain=G_IO_ERROR;
+ code=G_IO_ERROR_CANCELLED;
+ break;
+ }
+ /* else fall though */
+ default:
+ domain=PLOVER_RAZOR_ERROR;
+ code=RAZOR_GENERAL_ERROR_FAILED;
+ }
+ *dest=g_error_new_literal(domain,code,razor_error_get_msg(src));
+ }
+}
+
+void plover_propagate_razor_error(GError **dest,struct razor_error *src)
+{
+ plover_propagate_razor_error_dup(dest,src);
+ razor_error_free(src);
+}
+
+void plover_propagate_g_error(struct razor_error **dest,GError *src)
+{
+ int domain,code;
+ if (dest)
+ {
+ code=src->code;
+ if (src->domain==PLOVER_RAZOR_ERROR)
+ domain=RAZOR_GENERAL_ERROR;
+ else if (src->domain==PLOVER_POSIX_ERROR)
+ domain=RAZOR_POSIX_ERROR;
+ else if (src->domain==PLOVER_MSWIN_ERROR)
+ domain=RAZOR_MSWIN_ERROR;
+ else if (src->domain==PLOVER_ZLIB_ERROR)
+ domain=RAZOR_ZLIB_ERROR;
+ else if (src->domain==G_IO_ERROR && code==G_IO_ERROR_CANCELLED)
+ {
+ domain=PLOVER_GENERAL_ERROR;
+ code=PLOVER_GENERAL_ERROR_CANCELLED;
+ }
+ else
+ {
+ domain=RAZOR_GENERAL_ERROR;
+ code=RAZOR_GENERAL_ERROR_FAILED;
+ }
+ *dest=razor_error_new_str(domain,code,NULL,src->message);
+ }
+ g_error_free(src);
+}
--- /dev/null
+/*
+ * Copyright (C) 2009, 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "plover.h"
+
+struct plover_vector *plover_vector_new(void)
+{
+ struct plover_vector *vector;
+ vector=malloc(sizeof(*vector));
+ vector->len=0;
+ vector->alloc=16;
+ vector->strings=calloc(vector->alloc,sizeof(char *));
+ return vector;
+}
+
+struct plover_vector *plover_vector_dup(struct plover_vector *old)
+{
+ int i;
+ struct plover_vector *vector;
+ vector=malloc(sizeof(*vector));
+ vector->len=old->len;
+ vector->alloc=old->alloc;
+ vector->strings=calloc(vector->alloc,sizeof(char *));
+ for(i=0;i<old->len;i++)
+ vector->strings[i]=strdup(old->strings[i]);
+ vector->strings[i]=NULL;
+ return vector;
+}
+
+void plover_vector_append(struct plover_vector *vector,const char *str)
+{
+ if (++(vector->len)>=vector->alloc)
+ {
+ vector->alloc*=2;
+ vector->strings=realloc(vector->strings,vector->alloc*sizeof(char *));
+ }
+ vector->strings[vector->len-1]=strdup(str);
+ vector->strings[vector->len]=NULL;
+}
+
+int plover_vector_contains(struct plover_vector *vector,const char *str)
+{
+ int i;
+ for(i=0;i<vector->len;i++)
+ if (!strcmp(vector->strings[i],str))
+ return 1;
+ return 0;
+}
+
+int plover_vector_remove(struct plover_vector *vector,const char *str)
+{
+ int i;
+ for(i=0;i<vector->len;i++)
+ if (!strcmp(vector->strings[i],str))
+ {
+ free(vector->strings[i]);
+ vector->len--;
+ vector->strings[i]=vector->strings[vector->len];
+ vector->strings[vector->len]=NULL;
+ return 1;
+ }
+ return 0;
+}
+
+static int string_compar(const void *p1,const void *p2)
+{
+ return strcmp(*(char * const *)p1,*(char * const *)p2);
+}
+
+void plover_vector_sort(struct plover_vector *vector)
+{
+ qsort(vector->strings,vector->len,sizeof(char *),string_compar);
+}
+
+char *plover_vector_format_for_display(struct plover_vector *vector)
+{
+ int i,len;
+ char *s,*p;
+ if (!vector->len)
+ return strdup("none");
+ else if (vector->len==1)
+ return strdup(vector->strings[0]);
+ else
+ {
+ len=(vector->len-1)*2+5+1;
+ for(i=0;i<vector->len;i++)
+ len+=strlen(vector->strings[i]);
+ s=malloc(len);
+ strcpy(s,vector->strings[0]);
+ p=s+strlen(s);
+ for(i=1;i<vector->len-1;i++)
+ {
+ *p++=',';
+ *p++=' ';
+ strcpy(p,vector->strings[i]);
+ p+=strlen(p);
+ }
+ strcpy(p," and ");
+ p+=5;
+ strcpy(p,vector->strings[i]);
+ return s;
+ }
+}
+
+void plover_vector_free(struct plover_vector *vector)
+{
+ int i;
+ for(i=0;i<vector->len;i++)
+ free(vector->strings[i]);
+ free(vector->strings);
+ free(vector);
+}
--- /dev/null
+AM_CFLAGS=-g $(SETUP_CFLAGS)
+LDADD=../plover/libplover.la $(SETUP_LIBS)
+if PLOVER_MINGW
+LDADD+=-lcomctl32
+# pre-inst is not intended to produce any output (and any that is produced
+# can be safely junked). Thus -mwindows is appropriate since if called with
+# a console window attached no output should be visible anyway and if called
+# when no console window is attached we don't want one to be created.
+AM_LDFLAGS=-mwindows
+endif
+INCLUDES=-I$(top_srcdir) -I$(srcdir)
+
+bin_PROGRAMS=pre-inst
+
+pre_inst_SOURCES=pre-inst.c
+pre_inst_LDFLAGS=$(AM_LDFLAGS) -all-static
+if HAVE_WINDRES
+pre_inst_SOURCES+=resources.rc pre-inst.exe.manifest resource.h
+endif
+
+.rc.$(OBJEXT):
+ $(AM_V_GEN)$(WINDRES) $(INCLUDES) $< $@
+
+resources.$(OBJEXT): resources.rc resource.h pre-inst.exe.manifest pre-inst.ico
+
+.png.pnm:
+ $(AM_V_GEN)pngtopnm $< | pnmquant -quiet 256 > $@
+
+pre-inst.ico: icon16.pnm icon22.pnm icon32.pnm
+ $(AM_V_GEN)ppmtowinicon -output=$@ $^
+
+EXTRA_DIST=icon16.png icon22.png icon32.png
--- /dev/null
+changequote([,])dnl
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity
+ version="@PLOVER_MAJOR_VERSION@.@PLOVER_MINOR_VERSION@.@PLOVER_MICRO_VERSION@.0"
+ name="The plover development team.plover.pre-inst" type="win32"
+ processorArchitecture="ifelse([@HOST_CPU@],[x86_64],[ia64],[x86])" />
+ <description>Plover pre-inst program</description>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 7 functionality -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0" processorArchitecture="*"
+ publicKeyToken="6595b64144ccf1df" language="*"/>
+ </dependentAssembly>
+ </dependency>
+</assembly>
--- /dev/null
+/*
+ * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * References:
+ * http://www.transmissionzero.co.uk/computing/win32-apps-with-mingw/
+ */
+
+#include "config.h"
+#ifndef WIN32
+#define _XOPEN_SOURCE 500
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <lua.h>
+#include <razor.h>
+#include <plover/plover.h>
+#include <whelk/whelk.h>
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#include <commctrl.h>
+#include "resource.h"
+
+#ifndef FOF_NO_UI
+#define FOF_NO_UI (FOF_SILENT|FOF_NOCONFIRMATION|FOF_NOERRORUI|\
+ FOF_NOCONFIRMMKDIR)
+#endif
+
+#else /* WIN32 */
+#include <ftw.h>
+#endif /* WIN32 */
+
+#ifdef WIN32
+/* Under WIN32, g_spawn requires a helper program which we'd rather avoid */
+#undef USE_G_SPAWN
+#else
+#define USE_G_SPAWN
+#endif
+
+LUALIB_API int luaopen_posix(lua_State *L);
+
+#ifdef WIN32
+DWORD main_thread_id;
+#endif
+
+gchar *prefix;
+
+int verify_and_fix(const char *root)
+{
+ return 0;
+}
+
+#ifdef WIN32
+INT_PTR CALLBACK ProgressDialogProc(HWND dialog,UINT msg,WPARAM w_param,
+ LPARAM l_param)
+{
+ HWND progress;
+ DWORD style;
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ progress=GetDlgItem(dialog,IDC_PROGRESS);
+ style=GetWindowLong(progress,GWL_STYLE);
+ SetWindowLong(progress,GWL_STYLE,style|PBS_MARQUEE);
+ SendMessage(progress,PBM_SETMARQUEE,(WPARAM)TRUE,(LPARAM)30);
+ return (INT_PTR)TRUE;
+ }
+ return (INT_PTR)FALSE;
+}
+#endif
+
+#ifdef WIN32
+__stdcall
+#endif
+unsigned pre_install_thread(void *data)
+{
+ int retval;
+ char *path=data;
+ gchar *s;
+ char *install[]={"plover-gtkui",NULL};
+ GError *error=NULL;
+ prefix=plover_pre_install_prefix();
+ s=g_strconcat(prefix,"/var/log/pre-install",NULL);
+ plover_log_open(s);
+ g_free(s);
+ s=g_strconcat(prefix,"/var/lib/razor",NULL);
+ razor_set_database_path(s);
+ g_free(s);
+ if (verify_and_fix(prefix))
+ {
+ free(path);
+ g_free(prefix);
+ return -1;
+ }
+ retval=!plover_install(path,prefix,install,&error);
+ if (!retval)
+ retval=!plover_update(path,prefix,NULL,&error);
+ if (error)
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ }
+ free(path);
+#ifdef WIN32
+ PostQuitMessage(retval);
+ PostThreadMessage(main_thread_id,WM_QUIT,retval,0);
+ _endthreadex(retval);
+#endif
+ return retval;
+}
+
+/*
+ * The idea is that if pre_install() fails, update/setup should fall back
+ * to console interfaces.
+ */
+#ifdef WIN32
+HANDLE
+#else
+void *
+#endif
+pre_install(const char *argv0)
+{
+#ifdef WIN32
+ HANDLE retval;
+#else
+ void *retval;
+#endif
+ char *path;
+ razor_set_lua_loader("posix",luaopen_posix);
+ razor_set_lua_loader("whelk",luaopen_whelk);
+ path=plover_get_program_directory(argv0);
+#ifdef WIN32
+ retval=(HANDLE)_beginthreadex(NULL,0,pre_install_thread,path,0,NULL);
+#else
+ if (pre_install_thread(path))
+ retval=NULL;
+ else
+ retval=(void *)1; /* Non-NULL to indicate success */
+#endif
+ return retval;
+}
+
+#ifndef WIN32
+int remove_ignore(const char *fpath,const struct stat *sb,int typeflag,
+ struct FTW *ftwbuf)
+{
+ (void)remove(fpath);
+ return 0;
+}
+#endif
+
+gboolean deltree(const char *path)
+{
+#ifdef WIN32
+ /* Based on g_local_file_trash() */
+ SHFILEOPSTRUCTW op={0};
+ gboolean success;
+ wchar_t *wfilename;
+ long len;
+ wfilename=g_utf8_to_utf16(path,-1,NULL,&len,NULL);
+ /* SHFILEOPSTRUCT.pFrom is double-zero-terminated */
+ wfilename=g_renew(wchar_t,wfilename,len+2);
+ wfilename[len+1]=0;
+ op.wFunc=FO_DELETE;
+ op.pFrom=wfilename;
+ op.fFlags=FOF_NO_UI;
+ success=!SHFileOperationW(&op);
+ if (success && op.fAnyOperationsAborted)
+ success=FALSE;
+ g_free(wfilename);
+ return success;
+#else
+ return nftw(path,remove_ignore,64,FTW_DEPTH|FTW_PHYS);
+#endif
+}
+
+gboolean pre_uninstall(void)
+{
+ gboolean success;
+ gchar *s;
+ GError *error=NULL;
+ razor_set_lua_loader("posix",luaopen_posix);
+ razor_set_lua_loader("whelk",luaopen_whelk);
+ prefix=plover_pre_install_prefix();
+ s=g_strconcat(prefix,"/var/lib/razor",NULL);
+ razor_set_database_path(s);
+ g_free(s);
+ success=plover_remove(NULL,&error);
+ if (error)
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ }
+ deltree(prefix);
+ return success;
+}
+
+#if defined(WIN32) && !defined(USE_G_SPAWN)
+/* Based on glib's g_spawn_win32.c */
+
+static gchar *
+win32_cmdline_quote(const char *string)
+{
+ const gchar *p=string;
+ gchar *retval,*q;
+ gint len=0;
+ gboolean need_dblquotes=FALSE;
+ while (*p)
+ {
+ if (*p==' ' || *p=='\t')
+ need_dblquotes=TRUE;
+ else if (*p=='"')
+ len++;
+ else if (*p=='\\')
+ {
+ const gchar *pp=p;
+ while (*pp && *pp=='\\')
+ pp++;
+ if (*pp=='"')
+ len++;
+ }
+ len++;
+ p++;
+ }
+ q=retval=g_malloc(len+need_dblquotes*2+1);
+ p=string;
+ if (need_dblquotes)
+ *q++='"';
+ while (*p)
+ {
+ if (*p=='"')
+ *q++='\\';
+ else if (*p=='\\')
+ {
+ const gchar *pp=p;
+ while (*pp && *pp=='\\')
+ pp++;
+ if (*pp=='"')
+ *q++='\\';
+ }
+ *q++=*p;
+ p++;
+ }
+ if (need_dblquotes)
+ *q++='"';
+ *q++='\0';
+ return retval;
+}
+
+/* Create a win32-style wide-character argv with suitable quoting */
+wchar_t **win32_argv_import(char **argv,GError **error)
+{
+ int i,n;
+ gchar *s;
+ wchar_t **wargv;
+ GError *tmp_error=NULL;
+ n=g_strv_length(argv);
+ wargv=g_new(wchar_t *,n+1);
+ for(i=0;i<n;i++)
+ {
+ s=win32_cmdline_quote(argv[i]);
+ wargv[i]=g_utf8_to_utf16(s,-1,NULL,NULL,&tmp_error);
+ g_free(s);
+ if (!wargv[i])
+ {
+ g_set_error(error,G_SPAWN_ERROR,G_SPAWN_ERROR_FAILED,
+ "Invalid argument #%d: %s",i,tmp_error->message);
+ g_error_free(tmp_error);
+ for(i--;i>=0;i--)
+ g_free(wargv[i]);
+ g_free(wargv);
+ return FALSE;
+ }
+ }
+ wargv[i]=NULL;
+ return wargv;
+}
+
+gboolean spawn_sync(char **argv,GError **error)
+{
+ wchar_t *wargv0,**wargv;
+ gintptr rc;
+ GError *tmp_error=NULL;
+ wargv0=g_utf8_to_utf16(argv[0],-1,NULL,NULL,&tmp_error);
+ if (!wargv0)
+ {
+ fprintf(stderr,"Conversion error in post\n");
+ g_set_error(error,G_SPAWN_ERROR,G_SPAWN_ERROR_FAILED,
+ "Invalid program name: %s",tmp_error->message);
+ g_error_free(tmp_error);
+ return FALSE;
+ }
+ wargv=win32_argv_import(argv,error);
+ if (!wargv)
+ {
+ fprintf(stderr,"Conversion error in post\n");
+ g_free(wargv0);
+ return FALSE;
+ }
+ errno=0;
+ rc=_wspawnvp(P_WAIT,wargv0,(const wchar_t **)wargv);
+ g_free(wargv0);
+ g_strfreev((gchar **)wargv);
+ if (rc==-1 && errno!=0)
+ {
+ fprintf(stderr,"Failed to start post command (%s)\n",g_strerror(errno));
+ g_set_error(error,G_SPAWN_ERROR,G_SPAWN_ERROR_FAILED,
+ "Failed to execute post command: %s",g_strerror(errno));
+ return FALSE;
+ }
+ if (rc!=EXIT_SUCCESS)
+ {
+ fprintf(stderr,"post command failed (%ld)\n",(long)rc);
+ g_set_error(error,G_SPAWN_ERROR,G_SPAWN_ERROR_FAILED,
+ "Post command exited with code %ld",(long)rc);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#endif /* defined(WIN32) && !defined(USE_G_SPAWN) */
+
+/*
+ * Run a command after completing request.
+ *
+ * Command may refer to %INSTALL_PREFIX% which will be replaced by the
+ * (first) install prefix used and/or %TEST_RESULT% which will be replaced
+ * bu either "pass" or "fail" depending as to whether the request succeeded
+ * or not. Command may also include double quotes which will be used to
+ * affect how the command is split into arguments much like a shell does.
+ */
+gboolean run_post(int argc,char **argv,gboolean test_result,GError **error)
+{
+ int i,post_argc;
+ char *s;
+ gchar *expanded;
+ gchar **post_argv;
+#ifdef USE_G_SPAWN
+ gchar *standard_output,*standard_error;
+ int exit_status;
+#endif
+ GError *tmp_error=NULL;
+ if (argc<1)
+ {
+ g_set_error_literal(error,G_FILE_ERROR,G_FILE_ERROR_NOENT,
+ "--post: No command given");
+ return FALSE;
+ }
+ printf("Running post command: %s\n",argv[1]);
+ if (!g_shell_parse_argv(argv[1],&post_argc,&post_argv,&tmp_error))
+ {
+ g_propagate_prefixed_error(error,tmp_error,"%s: ",argv[1]);
+ return FALSE;
+ }
+ for(i=0;i<post_argc;i++)
+ {
+ s=strstr(post_argv[i],"%INSTALL_PREFIX%");
+ if (s)
+ {
+ *s='\0';
+ s+=strlen("%INSTALL_PREFIX%");
+ expanded=g_strconcat(post_argv[i],prefix,s,NULL);
+ g_free(post_argv[i]);
+ post_argv[i]=expanded;
+ }
+ s=strstr(post_argv[i],"%TEST_RESULT%");
+ if (s)
+ {
+ *s='\0';
+ s+=strlen("%TEST_RESULT%");
+ expanded=g_strconcat(post_argv[i],test_result?"pass":"fail",s,NULL);
+ g_free(post_argv[i]);
+ post_argv[i]=expanded;
+ }
+ }
+#ifdef USE_G_SPAWN
+ if (!g_spawn_sync(NULL,post_argv,NULL,G_SPAWN_SEARCH_PATH,NULL,NULL,
+ &standard_output,&standard_error,&exit_status,&tmp_error))
+ {
+ fprintf(stderr,"Failed to start post command\n");
+ g_propagate_prefixed_error(error,tmp_error,"%s: ",post_argv[0]);
+ return FALSE;
+ }
+ if (standard_output && *standard_output)
+ {
+ printf("Output from post command %s:\n",post_argv[0]);
+ fputs(standard_output,stdout);
+ }
+ g_free(standard_output);
+ if (standard_error && *standard_error)
+ {
+ printf("Error output from post command %s:\n",post_argv[0]);
+ fputs(standard_error,stdout);
+ }
+ g_free(standard_error);
+ if (!g_spawn_check_exit_status(exit_status,&tmp_error))
+ {
+ fprintf(stderr,"post command failed\n");
+ g_propagate_prefixed_error(error,tmp_error,"%s: ",post_argv[0]);
+ return FALSE;
+ }
+#else
+ if (!spawn_sync(post_argv,&tmp_error))
+ {
+ g_propagate_prefixed_error(error,tmp_error,"%s: ",post_argv[0]);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+#ifdef WIN32
+DWORD win32_pre_install_gui(char *argv0)
+{
+ HANDLE thread;
+ INITCOMMONCONTROLSEX icc={0,};
+ MSG msg;
+ DWORD retval;
+ main_thread_id=GetCurrentThreadId();
+ thread=(HANDLE)pre_install(argv0);
+ if (!thread)
+ return EXIT_FAILURE;
+ icc.dwSize=sizeof(icc);
+ icc.dwICC=ICC_WIN95_CLASSES;
+ InitCommonControlsEx(&icc);
+ DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_PROGRESSDIALOG),NULL,
+ &ProgressDialogProc);
+ while(GetMessage(&msg,NULL,0,0)>0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ WaitForSingleObject(thread,INFINITE);
+ GetExitCodeThread(thread,&retval);
+ CloseHandle(thread);
+ return retval;
+}
+#endif /* WIN32 */
+
+int main(int argc,char **argv)
+{
+ gboolean success;
+ GError *error=NULL;
+#ifdef WIN32
+ /*
+ * pre-inst is normally a GUI application, but rpm scripts may well
+ * call console applications and it looks ugly if console windows keep
+ * popping up. Avoid this by allocating our own console and hiding it.
+ * Note:
+ * - If pre-inst is a console application (typically for debugging),
+ * then skip this step.
+ * - Call ShowWindow twice to negate special handling on first call.
+ */
+ if (!GetConsoleWindow())
+ {
+ AllocConsole();
+ ShowWindow(GetConsoleWindow(),SW_HIDE);
+ ShowWindow(GetConsoleWindow(),SW_HIDE);
+ }
+#endif
+ if (argc>1 && !strcmp(argv[1],"-u"))
+ {
+ success=pre_uninstall();
+ argc--;
+ argv++;
+ }
+ else
+#ifdef WIN32
+ success=win32_pre_install_gui(argv[0])==EXIT_SUCCESS;
+#else
+ success=!!pre_install(argv[0]);
+#endif
+ if (argc>1 && !strcmp(argv[1],"--post") &&
+ !run_post(argc-1,argv+1,success,&error))
+ {
+#ifndef WIN32
+ fprintf(stderr,"Error in post: %s\n",error->message);
+#else
+ MessageBox(NULL,error->message,"Error in post",MB_ICONERROR|MB_OK);
+#endif
+ g_error_free(error);
+ success=FALSE;
+ }
+#ifdef WIN32
+ return success?EXIT_SUCCESS:EXIT_FAILURE;
+#else
+ return success?0:1;
+#endif
+}
--- /dev/null
+#define IDD_PROGRESSDIALOG 100
+#define IDC_PROGRESS 1000
+
+#ifndef IDC_STATIC
+#define IDC_STATIC -1
+#endif
--- /dev/null
+#include <windows.h>
+#include "resource.h"
+
+#pragma code_page(65001)
+
+MAINICON ICON "pre-inst.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+ @PLOVER_MICRO_VERSION@,0
+ PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+ @PLOVER_MICRO_VERSION@,0
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ {
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "080904B0"
+ {
+ VALUE "CompanyName","The plover development team"
+ VALUE "FileDescription","Plover pre-inst program"
+ VALUE "FileVersion","@PACKAGE_VERSION@"
+ VALUE "InternalName","pre-inst"
+ VALUE "LegalCopyright",
+ "Copyright © 2014 J. Ali Harlow et al"
+ VALUE "OriginalFilename","pre-inst.exe"
+ VALUE "ProductName","plover"
+ VALUE "ProductVersion","@PACKAGE_VERSION@"
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation",0x809,0x4B0
+ }
+ }
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "pre-inst.exe.manifest"
+
+IDD_PROGRESSDIALOG DIALOGEX 0,0,167,67
+ STYLE DS_SETFONT|DS_MODALFRAME|DS_FIXEDSYS|WS_POPUP|WS_CAPTION
+ CAPTION "Preparing to install..."
+ FONT 8,"MS Shell Dlg",400,0,0x1
+ {
+ ICON MAINICON,IDC_STATIC,10,17,20,20
+ LTEXT "Unpacking installation program.",IDC_STATIC,45,16,106,8
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,45,28,106,8
+ }
INCLUDES=-I$(top_srcdir)
bin_PROGRAMS=setup
+bin_SCRIPTS=setup.js
setup_SOURCES=setup.c
setup_LDFLAGS=-all-static
setup_SOURCES+=resources.rc setup.exe.manifest
endif
-.png.pnm:
- pngtopnm $< | pnmquant 256 > $@
+.rc.$(OBJEXT):
+ $(AM_V_GEN)$(WINDRES) resources.rc $@
resources.$(OBJEXT): resources.rc setup.exe.manifest setup.ico
- $(WINDRES) resources.rc $@
+
+%.js: $(srcdir)/%.js.in
+ $(AM_V_GEN)sed -e 's/$$/\r/' $(srcdir)/$@.in > $@
+
+.png.pnm:
+ $(AM_V_GEN)pngtopnm $< | pnmquant -quiet 256 > $@
setup.ico: icon16.pnm icon22.pnm icon32.pnm
- ppmtowinicon -output=$@ $^
+ $(AM_V_GEN)ppmtowinicon -output=$@ $^
-EXTRA_DIST=icon16.png icon22.png icon32.png
+EXTRA_DIST=icon16.png icon22.png icon32.png setup.js.in
+CLEANFILES=setup.js
#include <winver.h>
#include <winuser.h>
+#pragma code_page(65001)
+
MAINICON ICON "setup.ico"
VS_VERSION_INFO VERSIONINFO
VALUE "FileVersion","@PACKAGE_VERSION@"
VALUE "InternalName","setup"
VALUE "LegalCopyright",
- "Copyright (c) 2009,2011,2012 J. Ali Harlow et al"
+ "Copyright © 2009,2011,2012 J. Ali Harlow et al"
VALUE "OriginalFilename","setup.exe"
VALUE "ProductName","plover"
VALUE "ProductVersion","@PACKAGE_VERSION@"
LUALIB_API int luaopen_posix(lua_State *L);
-struct vector {
- int len,alloc;
- char **strings;
-};
-
-struct vector *vector_new(void)
-{
- struct vector *vector;
- vector=malloc(sizeof(*vector));
- vector->len=0;
- vector->alloc=16;
- vector->strings=calloc(vector->alloc,sizeof(char *));
- return vector;
-}
-
-void vector_append(struct vector *vector,const char *str)
-{
- if (++(vector->len)>=vector->alloc)
- {
- vector->alloc*=2;
- vector->strings=realloc(vector->strings,vector->alloc*sizeof(char *));
- }
- vector->strings[vector->len-1]=strdup(str);
- vector->strings[vector->len]=NULL;
-}
-
-int vector_contains(struct vector *vector,const char *str)
-{
- int i;
- for(i=0;i<vector->len;i++)
- if (!strcmp(vector->strings[i],str))
- return 1;
- return 0;
-}
-
-void vector_free(struct vector *vector)
-{
- int i;
- for(i=0;i<vector->len;i++)
- free(vector->strings[i]);
- free(vector->strings);
- free(vector);
-}
-
void setup(const char *argv0)
{
- char *path,*s,*prefix;
+ char *path;
+ gchar *s,*prefix;
int ch,changed;
struct comps *comps;
struct comps_group *group;
struct comps_requirement *pkg;
- struct vector *packages=NULL;
+ struct plover_vector *packages=NULL;
+ GError *error=NULL;
path=plover_get_program_directory(argv0);
- s=plover_strconcat(path,"/repodata/comps.xml",NULL);
+ s=g_strconcat(path,"/repodata/comps.xml",NULL);
comps=plover_comps_new_from_file(s);
if (!comps)
{
perror(s);
exit(1);
}
- free(s);
+ g_free(s);
prefix=plover_default_prefix_for_vendor(comps->vendor);
if (!plover_installed_files_match_prefix(prefix))
{
exit(1);
while(ch!='\n' && ch!=EOF)
ch=getchar();
- plover_remove(NULL);
+ if (plover_remove(NULL,&error))
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ exit(1);
+ }
}
group=plover_comps_lookup_group(comps,"base");
if (!group)
fprintf(stderr,"No base group found in comps.xml\n");
exit(1);
}
- packages=vector_new();
+ packages=plover_vector_new();
do
{
changed=0;
for(pkg=group->packages;pkg;pkg=pkg->next)
{
- if (vector_contains(packages,pkg->name))
+ if (plover_vector_contains(packages,pkg->name))
continue;
if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
pkg->type==COMPS_REQUIREMENT_MANDATORY ||
pkg->type==COMPS_REQUIREMENT_CONDITIONAL &&
- vector_contains(packages,pkg->requires))
+ plover_vector_contains(packages,pkg->requires))
{
changed++;
- vector_append(packages,pkg->name);
+ plover_vector_append(packages,pkg->name);
}
}
} while(changed);
fprintf(stderr,"No packages to install\n");
exit(1);
}
- plover_install(path,prefix,packages->strings);
- vector_free(packages);
- free(prefix);
+ if (!plover_install(path,prefix,packages->strings,&error))
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ exit(1);
+ }
+ plover_vector_free(packages);
+ g_free(prefix);
free(path);
}
int main(int argc,char **argv)
{
+ GError *error=NULL;
razor_set_lua_loader("posix",luaopen_posix);
razor_set_lua_loader("whelk",luaopen_whelk);
if (argc>1 && !strcmp(argv[1],"-u"))
- plover_remove(NULL);
+ {
+ if (!plover_remove(NULL,&error))
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ exit(1);
+ }
+ }
else
setup(argv[0]);
exit(0);
--- /dev/null
+var WshShell = WScript.CreateObject("WScript.Shell");
+var ScriptPath = WScript.ScriptFullName.replace(/\\[^\\]*$/, "");
+var FileSystemObject = new ActiveXObject("Scripting.FileSystemObject");
+
+function RunSetup(args)
+{
+ var OKButton = 0, ErrorIcon = 16, ForReading = 1;
+ var path, command, i, ExecObject, text;
+ path = FileSystemObject.BuildPath(ScriptPath, "setup.exe");
+ command = "\"" + path + "\"";
+ for(i = 0; i < args.Length; i++)
+ command += " \"" + args.Item(i) + "\"";
+ ExecObject = WshShell.Exec(command);
+ if (!ExecObject.StdErr.AtEndOfStream)
+ {
+ text = "Setup failed for an unexpected reason. Please report "
+ + "the following error to support@city-occupational.co.uk:\n\n"
+ + ExecObject.StdErr.ReadAll();
+ WshShell.Popup(text, 0, "Setup failed", OKButton + ErrorIcon);
+ return false;
+ }
+ else if (ExecObject.ExitCode)
+ {
+ text = "Setup failed without giving a reason. Please report "
+ + "this to support@city-occupational.co.uk";
+ WshShell.Popup(text, 0, "Setup failed", OKButton + ErrorIcon);
+ return false;
+ }
+ return true;
+}
+
+function Install()
+{
+ var path;
+ path = FileSystemObject.BuildPath(ScriptPath, "pre-inst.exe");
+ WshShell.Run("\"" + path + "\"" + " --post \"wscript.exe"
+ + " \\\"" + WScript.ScriptFullName + "\\\""
+ + " --post %INSTALL_PREFIX% %TEST_RESULT%\"",
+ 7, true);
+}
+
+function Uninstall()
+{
+ var path;
+ path = FileSystemObject.BuildPath(ScriptPath, "pre-inst.exe");
+ WshShell.Run("\"" + path + "\"" + " -u --post \"wscript.exe"
+ + " \\\"" + WScript.ScriptFullName + "\\\"" + " --postun\"", 7, true);
+}
+
+function PostInstall()
+{
+ var OKButton = 0, InfoIcon = 64, text;
+ var test_result, install_prefix, path, args;
+ install_prefix = WScript.Arguments.Item(1);
+ test_result = WScript.Arguments.Item(2);
+ if (test_result == "pass")
+ {
+ path = FileSystemObject.BuildPath(install_prefix,
+ "bin\\app-manager.exe");
+ WshShell.Run("\"" + path + "\" --setup \"" + ScriptPath + "\"");
+ }
+ else
+ {
+ args = { Length:0, Item:function(){return nil} };
+ if (RunSetup(args))
+ {
+ text = "Software installation completed successfully.";
+ WshShell.Popup(text, 0, "Software Installation",
+ OKButton + InfoIcon);
+ }
+ }
+}
+
+function PostUninstall()
+{
+ var args = { Length:1, Item:function(){return "-u"} };
+ var OKButton = 0, InfoIcon = 64, text;
+ if (RunSetup(args))
+ {
+ text = "Uninstall completed successfully.";
+ WshShell.Popup(text, 0, "Uninstall", OKButton + InfoIcon);
+ }
+}
+
+if (WScript.Arguments.Length < 1)
+ Install()
+else if (WScript.Arguments.Item(0) == "-u")
+ Uninstall()
+else if (WScript.Arguments.Length >= 3 && WScript.Arguments.Item(0) == "--post")
+ PostInstall()
+else if (WScript.Arguments.Item(0) == "--postun")
+ PostUninstall()
INCLUDES=-I$(top_srcdir)
bin_PROGRAMS=update
+bin_SCRIPTS=update.js
update_SOURCES=update.c
update_LDFLAGS=-all-static
update_SOURCES+=resources.rc update.exe.manifest
endif
-.png.pnm:
- pngtopnm $< | pnmquant 256 > $@
+.rc.$(OBJEXT):
+ $(AM_V_GEN)$(WINDRES) resources.rc $@
resources.$(OBJEXT): resources.rc update.exe.manifest update.ico
- $(WINDRES) resources.rc $@
+
+%.js: $(srcdir)/%.js.in
+ $(AM_V_GEN)sed -e 's/$$/\r/' $(srcdir)/$@.in > $@
+
+.png.pnm:
+ $(AM_V_GEN)pngtopnm $< | pnmquant -quiet 256 > $@
update.ico: icon16.pnm icon22.pnm icon32.pnm
- ppmtowinicon -output=$@ $^
+ $(AM_V_GEN)ppmtowinicon -output=$@ $^
-EXTRA_DIST=icon16.png icon22.png icon32.png
+EXTRA_DIST=icon16.png icon22.png icon32.png update.js.in
+CLEANFILES=update.js
#include <winver.h>
#include <winuser.h>
+#pragma code_page(65001)
+
MAINICON ICON "update.ico"
VS_VERSION_INFO VERSIONINFO
VALUE "FileVersion","@PACKAGE_VERSION@"
VALUE "InternalName","update"
VALUE "LegalCopyright",
- "Copyright (c) 2009,2011,2012 J. Ali Harlow et al"
+ "Copyright © 2009,2011,2012 J. Ali Harlow et al"
VALUE "OriginalFilename","update.exe"
VALUE "ProductName","plover"
VALUE "ProductVersion","@PACKAGE_VERSION@"
void update(const char *argv0)
{
- char *path,*s,*prefix;
+ char *path;
+ gchar *s,*prefix;
int ch;
struct comps *comps;
+ GError *error=NULL;
path=plover_get_program_directory(argv0);
- s=plover_strconcat(path,"/repodata/comps.xml",NULL);
+ s=g_strconcat(path,"/repodata/comps.xml",NULL);
comps=plover_comps_new_from_file(s);
if (!comps)
{
perror(s);
exit(1);
}
- free(s);
+ g_free(s);
prefix=plover_default_prefix_for_vendor(comps->vendor);
if (!plover_installed_files_match_prefix(prefix))
{
exit(1);
while(ch!='\n' && ch!=EOF)
ch=getchar();
- plover_remove(NULL);
+ if (plover_remove(NULL,&error))
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ exit(1);
+ }
}
plover_comps_free(comps);
- plover_update(path,prefix,NULL);
- free(prefix);
+ if (!plover_update(path,prefix,NULL,&error))
+ {
+ fprintf(stderr,"%s\n",error->message);
+ g_error_free(error);
+ exit(1);
+ }
+ g_free(prefix);
free(path);
}
--- /dev/null
+var WshShell = WScript.CreateObject("WScript.Shell");
+var ScriptPath = WScript.ScriptFullName.replace(/\\[^\\]*$/, "");
+var FileSystemObject = new ActiveXObject("Scripting.FileSystemObject");
+
+function RunUpdate(args)
+{
+ var OKButton = 0, ErrorIcon = 16, ForReading = 1;
+ var path, command, i, ExecObject, text;
+ path = FileSystemObject.BuildPath(ScriptPath, "update.exe");
+ command = "\"" + path + "\"";
+ for(i = 0; i < args.Length; i++)
+ command += " \"" + args.Item(i) + "\"";
+ ExecObject = WshShell.Exec(command);
+ if (!ExecObject.StdErr.AtEndOfStream)
+ {
+ text = "Update failed for an unexpected reason. Please report "
+ + "the following error to support@city-occupational.co.uk:\n\n"
+ + ExecObject.StdErr.ReadAll();
+ WshShell.Popup(text, 0, "Update failed", OKButton + ErrorIcon);
+ return false;
+ }
+ else if (ExecObject.ExitCode)
+ {
+ text = "Update failed without giving a reason. Please report "
+ + "this to support@city-occupational.co.uk";
+ WshShell.Popup(text, 0, "Update failed", OKButton + ErrorIcon);
+ return false;
+ }
+ return true;
+}
+
+function Update()
+{
+ var path;
+ path = FileSystemObject.BuildPath(ScriptPath, "pre-inst.exe");
+ WshShell.Run("\"" + path + "\"" + " --post \"wscript.exe"
+ + " \\\"" + WScript.ScriptFullName + "\\\""
+ + " --post %INSTALL_PREFIX% %TEST_RESULT%\"",
+ 7, true);
+}
+
+function PostUpdate()
+{
+ var OKButton = 0, InfoIcon = 64, text;
+ var test_result, install_prefix, path, args;
+ install_prefix = WScript.Arguments.Item(1);
+ test_result = WScript.Arguments.Item(2);
+ if (test_result == "pass")
+ {
+ path = FileSystemObject.BuildPath(install_prefix,
+ "bin\\app-manager.exe");
+ WshShell.Run("\"" + path + "\" --update \"" + ScriptPath + "\"");
+ }
+ else
+ {
+ args = { Length:0, Item:function(){return nil} };
+ if (RunUpdate(args))
+ {
+ text = "Software update completed successfully.";
+ WshShell.Popup(text, 0, "Software Update", OKButton + InfoIcon);
+ }
+ }
+}
+
+if (WScript.Arguments.Length < 1)
+ Update()
+else if (WScript.Arguments.Length >= 3 && WScript.Arguments.Item(0) == "--post")
+ PostUpdate()