Commits

jjacky  committed 5e7ff3e Merge

merging latest

  • Participants
  • Parent commits 4e005aa, 92a9fef
  • Branches stable
  • Tags 1.0.0

Comments (0)

Files changed (12)

+
+# 05/10/2012, v1.0.0
+
+- Preferences: kalu's updater: added option to disable confirmation before
+starting PostSysUpgrade processes.
+
+- PostSysUpgrade: now you can use variable $PACKAGES in the command line, to be
+replaced by the list of upgraded packages.
+
+Note that the list actually is of all packages involved in the sysupgrade, i.e.
+also those removed or added (e.g. when a package is replaced by another one).
+
+- When buttons for Upgrades & AUR were both used/clicked at the same time,
+kalu would run a check after each, fixed
+
+- Parsing config file was broken for lines with more than 255 characters, fixed
+
+- News parser: added support for lists and "
+
+- Other minor fixes.
+
+- Bumped to 1.0.0 to follow semantic versioning
+
 
 # 04/19/2012, v0.1.5.1
 
 kalu_dbus_SOURCES = updater-dbus.h kupdater.h kalu-dbus.c
 endif
 
-_bindir = $(subst /,\/,$(bindir))
 org.jjk.kalu.service: org.jjk.kalu.service.tpl
-	@sed 's/@BINDIR@/$(_bindir)/' org.jjk.kalu.service.tpl > org.jjk.kalu.service
+	sed 's|@BINDIR@|$(bindir)|' org.jjk.kalu.service.tpl > org.jjk.kalu.service
 
 kalu.1: kalu.pod
 	pod2man --center='Keeping Arch Linux Up-to-date' --section=1 --release=$(PACKAGE_VERSION) kalu.pod kalu.1
 
 Of course you don't have to use all of this, and you can define which of those checks kalu should do. Besides maintaining lists of watched (AUR) packages, you can also define a list of foreign packages that kalu should not check the AUR for. Since there's no reason to check for packages you know aren't from the AUR (e.g. packages of your own making).
 
+## More than a notifier: kalu's updater
+
+When a notification is shown, it will feature an action button. This button can be used to simply trigger a process of your choosing, e.g. you could have it start pacman with something like `urxvt -e sudo pacman -Syu`
+
+However, **kalu comes with an integrated system upgrader**, which does exactly the same, only in a GTK GUI. Before being able to synchronize your databases (and possibly upgrade the system) the updater needs root privileges, obviously.
+
+The way it works is: **kalu itself only contains the GUI**, and the part that does interact with libalpm (to actually upgrade your system) is in a secondary binary (`kalu-dbus`). This binary only will require root privileges, and will rely on PolicyKit to ensure you are authorized before doing anything.
+
+You can also define one or more processes to be run after completing a system upgrade (to start e.g. [localepurge](https://aur.archlinux.org/packages.php?ID=11975 "AUR: localepurge: Script to remove disk space wasted for unneeded localizations") and/or [PkgClip](http://mywaytoarch.tumblr.com/post/16005116198/pkgclip-does-your-pacman-cache-need-a-trim "PkgClip: Does your pacman cache need a trim?")), and kalu will start them after each succesfull sysupgrade (and an optional confirmation, which for multiple processes will feature the full list so you can specify which (if any) to start).
+
+Note that if you're not interested in this, you can remove it by specifying `--disable-updater` on the `configure` command line.
+
 ## Want to know more?
 
 Some useful links if you're looking for more info:
 
-- blog post about kalu: http://mywaytoarch.tumblr.com/post/19350380240/keep-arch-linux-up-to-date-with-kalu
+- [blog post about kalu](http://mywaytoarch.tumblr.com/post/19350380240/keep-arch-linux-up-to-date-with-kalu "Keep Arch Linux Up-to-date with kalu")
 
-- source code & issue tracker: https://bitbucket.org/jjacky/kalu
+- [source code & issue tracker](https://bitbucket.org/jjacky/kalu "kalu @ BitBucket.org")
 
-- PKGBUILD in AUR: https://aur.archlinux.org/packages.php?ID=56673
+- [PKGBUILD in AUR](https://aur.archlinux.org/packages.php?ID=56673 "AUR: kalu")
 
 Plus, kalu comes with a man page.
                    conf_file_t       conf_file,
                    GError          **error)
 {
-	FILE       *fp              = NULL;
-	char        line[MAX_PATH];
+	char       *data            = NULL;
+	char       *line;
+    gchar     **lines           = NULL;
+    gchar     **l;
 	int         linenum         = 0;
     char       *section         = NULL;
 	int         success         = TRUE;
     GString    *err_msg         = NULL;
+    GError     *local_err       = NULL;
 
 	debug ("config: attempting to read file %s", file);
-	fp = fopen (file, "r");
-	if (fp == NULL)
+    if (!g_file_get_contents (file, &data, NULL, &local_err))
     {
         /* not an error if file does not exists */
-        if (errno != ENOENT)
+        if (local_err->domain != G_FILE_ERROR || local_err->code != G_FILE_ERROR_NOENT)
         {
-            g_set_error (error, KALU_ERROR, 1, "Config file %s could not be read", file);
             success = FALSE;
+            g_set_error (error, KALU_ERROR, 1, "Config file %s could not be read: %s",
+                         file, local_err->message);
         }
-		goto cleanup;
-	}
-
-	while (fgets (line, MAX_PATH, fp))
+        g_clear_error (&local_err);
+        goto cleanup;
+    }
+    
+    lines = g_strsplit (data, "\n", 0);
+    g_free (data);
+    for (l = lines; *l; ++l)
     {
 		char *key, *value, *ptr;
 		size_t line_len;
 
+        line = *l;
 		++linenum;
 		strtrim (line);
 		line_len = strlen(line);
                         strdup (value));
                     debug ("config: postsysupgrade: %s", value);
                 }
+                else if (strcmp (key, "ConfirmPostSysUpgrade") == 0)
+                {
+                    config->confirm_post = (*value == '1');
+                    debug ("config: confirm postsysupgrade: %d", config->confirm_post);
+                }
                 #endif
                 else if (strcmp (key, "AurIgnore") == 0)
                 {
 	}
 
 cleanup:
-	if (fp)
-    {
-		fclose(fp);
-	}
+	g_strfreev (lines);
     free (section);
     if (config->action == UPGRADE_ACTION_CMDLINE && config->cmdline == NULL)
     {

File configure.ac

 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.68])
-AC_INIT([kalu], [0.1.5.1], [i.am.jack.mail@gmail.com])
+AC_INIT([kalu], [1.0.0], [i.am.jack.mail@gmail.com])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign])
 AC_CONFIG_SRCDIR([kalu.h])
 AC_CONFIG_HEADERS([config.h])
 AC_PROG_CC_C99
 AC_PROG_INSTALL
 AC_PROG_LN_S
+AM_PROG_CC_C_O
 
 # Option for News URL
 AC_ARG_WITH([news-rss-url],
     char            *cmdline_aur;
     #ifndef DISBALE_UPDATER
     alpm_list_t     *cmdline_post;
+    gboolean         confirm_post;
     #endif
     gboolean         sane_sort_order;
     gboolean         check_pacman_conflict;
 } kalu_package_t;
 
 typedef struct _kalpm_state_t {
-    gboolean    is_busy;
+    gint        is_busy;
     guint       timeout;
     guint       timeout_icon;
     GDateTime  *last_check;
 
 When using kalu's updater, you can define one or more processes to be ran after
 a system upgrade was completed. Specify their command-line in the list, and
-after a succesful system upgrade kalu will ask whether to start them or not.
+they'll be started after a succesful system upgrade.
 
-In case you specify more than one, the full list will be featured and you will
-be able to determine which (if any) to start each time.
+You can use B<$PACKAGES> in the command line, which will be replaced by the
+list of all packages involved in the sysupgrade (i.e. packages upgraded, as well
+as those added or removed, for instance when a package is replaced by another one).
+
+=item I<Ask confirmation before starting anything>
+
+If enabled, a confirmation will be asked before any process is started after the
+sysupgrade. In case you specify more than one, the full list will be featured
+and you will be able to determine which (if any) to start each time.
 
 =item I<Notification template>
 
 static void icon_popup_cb (GtkStatusIcon *icon, guint button, guint activate_time, gpointer data);
 static void free_config (void);
 
-static kalpm_state_t kalpm_state = { FALSE, 0, 0, NULL, 0, 0, 0, 0, 0, 0 };
+static kalpm_state_t kalpm_state = { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0 };
 
 static gboolean
 show_error_cmdline (gchar *arg[])
     GError *error = NULL;
     
     notify_notification_close (notification, NULL);
+    set_kalpm_busy (TRUE);
     if (!news_show (xml_news, TRUE, &error))
     {
         show_error ("Unable to show the news", error->message, NULL);
     templates_t template;
     const char *unit;
     double      size_h;
-    replacement_t *replacements[6];
+    replacement_t *replacements[7];
     
     templates_t *t, *tt;
     /* tpl_upgrades is the ref/fallback for pretty much everything */
     t = config->tpl_upgrades;
+    tt = NULL;
     if (type & CHECK_UPGRADES)
     {
         tt = config->tpl_upgrades;
         tt = config->tpl_news;
     }
     /* set the templates to use */
-    template.title = (tt->title) ? tt->title : t->title;
-    template.package = (tt->package) ? tt->package : t->package;
-    template.sep = (tt->sep) ? tt->sep : t->sep;
+    template.title = (tt && tt->title) ? tt->title : t->title;
+    template.package = (tt && tt->package) ? tt->package : t->package;
+    template.sep = (tt && tt->sep) ? tt->sep : t->sep;
     /* watched-aur might have fallen back to aur, which itself needs to fallback */
     if (type & CHECK_WATCHED_AUR)
     {
 void
 set_kalpm_busy (gboolean busy)
 {
-    if (busy == kalpm_state.is_busy)
+    gint old = kalpm_state.is_busy;
+    
+    /* we use an counter because when using a cmdline for both upgrades & AUR,
+     * and both are triggered at the same time (from notifications) then we
+     * should only bo back to not busy when *both* are done; fixes #8 */
+    if (busy)
+    {
+        ++kalpm_state.is_busy;
+    }
+    else if (kalpm_state.is_busy > 0)
+    {
+        --kalpm_state.is_busy;
+    }
+    
+    /* make sure the state changed/there's something to do */
+    if ((old > 0  && kalpm_state.is_busy > 0)
+     || (old == 0 && kalpm_state.is_busy == 0))
     {
         return;
     }
         /* set timeout for status icon */
         kalpm_state.timeout_icon = g_timeout_add (420,
             (GSourceFunc) switch_status_icon, NULL);
-        
-        kalpm_state.is_busy = TRUE;
     }
     else
     {
         {
             GDateTime *now, *begin, *end, *next;
             gint year, month, day;
-            gboolean is_within_skip;
+            gboolean is_within_skip = FALSE;
             
             now = g_date_time_new_now_local ();
             /* create GDateTime for begin & end of skip period */
             /* ensure icon is right */
             set_kalpm_nb (0, 0);
         }
-        
-        kalpm_state.is_busy = FALSE;
     }
 }
 
                             | CHECK_WATCHED_AUR | CHECK_NEWS;
     #ifndef DISABLE_UPDATER
     config->action = UPGRADE_ACTION_KALU;
+    config->confirm_post = TRUE;
     #else
     config->action = UPGRADE_NO_ACTION;
     #endif
     gchar       *s, *ss, *start, *end;
     gchar        buf[10];
     gint         c, margin;
+    gint         in_ordered_list = -1;
     
     s = malloc ((text_len + 2) * sizeof (gchar));
     snprintf (s, text_len + 1, "%s", text);
         start = ss + 4;
         memmove (++ss, start, strlen (start) + 1);
     }
+    while ((ss = strstr (s, "&quot;")))
+    {
+        *ss = '"';
+        start = ss + 6;
+        memmove (++ss, start, strlen (start) + 1);
+    }
     
     gtk_text_buffer_get_end_iter (buffer, &iter);
     mark = gtk_text_buffer_create_mark (buffer, "mark", &iter, TRUE);
             insert_text_with_tags ();
             tags = alpm_list_remove_str (tags, "italic", NULL);
         }
+        else if (strcmp (start + 1, "ul") == 0)
+        {
+            *start = '\0';
+            insert_text_with_tags ();
+            gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+        }
+        else if (strcmp (start + 1, "ol") == 0)
+        {
+            *start = '\0';
+            insert_text_with_tags ();
+            gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+            in_ordered_list = 0;
+        }
+        else if (strcmp (start + 1, "li") == 0)
+        {
+            *start = '\0';
+            insert_text_with_tags ();
+            gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+            tags = alpm_list_add (tags, (void *) "listitem");
+            if (in_ordered_list == -1)
+            {
+                ss = (gchar *) "• ";
+            }
+            else
+            {
+                ++in_ordered_list;
+                snprintf (buf, 10, "%d. ", in_ordered_list);
+                ss = buf;
+            }
+            insert_text_with_tags ();
+        }
+        else if (strcmp (start + 1, "/li") == 0)
+        {
+            *start = '\0';
+            insert_text_with_tags ();
+            gtk_text_buffer_insert (buffer, &iter, "\n", -1);
+            tags = alpm_list_remove_str (tags, "listitem", NULL);
+        }
+        else if (strcmp (start + 1, "/ol") == 0)
+        {
+            *start = '\0';
+            insert_text_with_tags ();
+            in_ordered_list = -1;
+        }
         else if (strcmp (start + 1, "lt") == 0)
         {
             *start = '\0';
     gtk_text_buffer_create_tag (buffer, "italic",
         "style",            PANGO_STYLE_ITALIC,
         NULL);
+    
+    gtk_text_buffer_create_tag (buffer, "listitem",
+        "left-margin",      15,
+        NULL);
 }
 
 static gboolean
     /* scrolled window for the textview */
     GtkWidget *scrolled;
     scrolled = gtk_scrolled_window_new (
-        gtk_text_view_get_hadjustment (GTK_TEXT_VIEW (*textview)),
-        gtk_text_view_get_vadjustment (GTK_TEXT_VIEW (*textview)));
+        gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*textview)),
+        gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (*textview)));
     gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
     gtk_widget_show (scrolled);
     

File preferences.c

 #ifndef DISABLE_UPDATER
 static GtkWidget *cmdline_post_hbox         = NULL;
 static GtkListStore *cmdline_post_store     = NULL;
+static GtkWidget *confirm_post              = NULL;
 #endif
 static GtkWidget *upg_title_entry           = NULL;
 static GtkWidget *upg_package_entry         = NULL;
     gtk_widget_set_sensitive (cmdline_entry, is_active);
     #ifndef DISABLE_UPDATER
     gtk_widget_set_sensitive (cmdline_post_hbox, is_active);
+    gtk_widget_set_sensitive (confirm_post, is_active);
     #endif
 }
 
         gtk_widget_hide (cmdline_entry);
         #ifndef DISABLE_UPDATER
         gtk_widget_show (cmdline_post_hbox);
+        gtk_widget_show (confirm_post);
         #endif
     }
     else if (choice == 1)
         gtk_widget_show (cmdline_entry);
         #ifndef DISABLE_UPDATER
         gtk_widget_hide (cmdline_post_hbox);
+        gtk_widget_hide (confirm_post);
         #endif
     }
 }
             }
         } while (gtk_tree_model_iter_next (model, &iter));
     }
+    new_config.confirm_post = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (confirm_post));
+    add_to_conf ("ConfirmPostSysUpgrade = %d\n", new_config.confirm_post);
     #endif
     
     /* AUR */
           GtkListStore **store,
           GtkWidget    **hbox,
           const char    *column_title,
+          const char    *tooltip_list,
           const char    *tooltip_add,
           const char    *tooltip_edit,
           const char    *tooltip_remove,
     tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (*store));
     g_object_set_data (G_OBJECT (tree), "store", (gpointer) *store);
     g_object_unref (*store);
+    if (tooltip_list)
+    {
+        gtk_widget_set_tooltip_markup (tree, tooltip_list);
+    }
     
     /* vbox - sort of a toolbar but vertical */
     GtkWidget *vbox_tb;
     /* a scrolledwindow for the tree */
     GtkWidget *scrolled;
     scrolled = gtk_scrolled_window_new (
-        gtk_tree_view_get_hadjustment (GTK_TREE_VIEW (tree)),
-        gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree)));
+        gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (tree)),
+        gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (tree)));
     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
         GTK_SHADOW_OUT);
     gtk_widget_show (scrolled);
     ++top;
     /* PostSysUpgrade */
     add_list (grid, top, &cmdline_post_store, &cmdline_post_hbox,
-              "After completing a system upgrade, ask whether to start the following :",
+              "After completing a system upgrade, start the following :",
+              "You can use <b>$PACKAGES</b> to be replaced by the list of upgraded packages",
               "Add a new command-line",
               "Edit selected command-line",
               "Remove selected command-line",
               config->cmdline_post);
     gtk_widget_set_sensitive (cmdline_post_hbox, config->action != UPGRADE_NO_ACTION);
+    ++top;
+    /* ConfirmPostSysUpgrade */
+    confirm_post = gtk_check_button_new_with_label ("Ask confirmation before starting anything");
+    gtk_widget_set_tooltip_text (confirm_post, "Confirmation will be asked before starting those processes. With multiple ones, you'll be able to select which one(s) to start.");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (confirm_post), config->confirm_post);
+    gtk_grid_attach (GTK_GRID (grid), confirm_post, 0, top, 2, 1);
+    gtk_widget_show (confirm_post);
     
     /* doing this now otherwise it's triggered with non-yet-existing widgets to hide/show */
     g_signal_connect (G_OBJECT (upg_action_combo), "changed",
     ++top;
     add_list (grid, top, &aur_ignore_store, &hbox,
               "Package name",
+              NULL,
               "Add a new package",
               "Edit selected package",
               "Remove selected package",
     
     if (NULL != updater->cmdline_post)
     {
-        GError *error = NULL;
-        size_t count = alpm_list_count (updater->cmdline_post);
+        GError      *error = NULL;
+        size_t       count = alpm_list_count (updater->cmdline_post);
+        alpm_list_t *cmdlines = NULL, *i;
         
         if (count == 1)
         {
-            add_log (LOGTYPE_INFO, "Do you want to run the post-sysupgrade process ?");
-            if (confirm ("Do you want to run the post-sysupgrade process ?",
-                    updater->cmdline_post->data,
-                    "Yes, Start it now", NULL,
+            if (config->confirm_post)
+            {
+                add_log (LOGTYPE_INFO, "Do you want to run the post-sysupgrade process ?");
+                if (confirm ("Do you want to run the post-sysupgrade process ?",
+                        updater->cmdline_post->data,
+                        "Yes, Start it now", NULL,
+                        "No", NULL,
+                        updater->window))
+                {
+                    add_log (LOGTYPE_INFO, " Yes\n");
+                    cmdlines = alpm_list_add (cmdlines, updater->cmdline_post->data);
+                }
+                else
+                {
+                    add_log (LOGTYPE_INFO, " No\n");
+                }
+            }
+            else
+            {
+                cmdlines = alpm_list_add (cmdlines, updater->cmdline_post->data);
+            }
+        }
+        else
+        {
+            if (config->confirm_post)
+            {
+                add_log (LOGTYPE_INFO, "Do you want to run the post-sysupgrade processes ?");
+                cmdlines = confirm_choices (
+                "Do you want to run the following post-sysupgrade processes ?",
+                    "Only checked processes will be launch.",
+                    "Yes, run checked processes now", NULL,
                     "No", NULL,
-                    updater->window))
+                    "Run",
+                    "Command-line",
+                    updater->cmdline_post,
+                    updater->window);
+                if (NULL != cmdlines)
+                {
+                    add_log (LOGTYPE_INFO, " Yes\n");
+                }
+                else
+                {
+                    add_log (LOGTYPE_INFO, " No\n");
+                }
+            }
+            else
             {
-                add_log (LOGTYPE_INFO, " Yes\n");
-                add_log (LOGTYPE_NORMAL, "Starting: '%s' ..", updater->cmdline_post->data);
-                if (!g_spawn_command_line_async (updater->cmdline_post->data, &error))
+                cmdlines = alpm_list_copy (updater->cmdline_post);
+            }
+        }
+        
+        if (cmdlines)
+        {
+            /* construct list of "upgraded" packages */
+            GtkTreeIter iter;
+            GtkTreeModel *model = GTK_TREE_MODEL (updater->store);
+            GString *string;
+            char *s;
+            
+            string = g_string_sized_new (255);
+            gtk_tree_model_get_iter_first (model, &iter);
+            do
+            {
+                gtk_tree_model_get (model, &iter, UCOL_PACKAGE, &s, -1);
+                string = g_string_append (string, s);
+                string = g_string_append_c (string, ' ');
+            } while (gtk_tree_model_iter_next (model, &iter));
+            
+            /* start */
+            for (i = cmdlines; i; i = alpm_list_next (i))
+            {
+                s = strreplace (i->data, "$PACKAGES", string->str);
+                
+                add_log (LOGTYPE_NORMAL, "Starting: '%s' ..", s);
+                if (!g_spawn_command_line_async (s, &error))
                 {
                     add_log (LOGTYPE_NORMAL, " failed\n");
                     _show_error ("Unable to start post-sysupgrade process.",
                         "Command-line: %s\nError: %s",
-                        updater->cmdline_post->data, error->message);
+                        s, error->message);
                     g_clear_error (&error);
                 }
                 else
                 {
                     add_log (LOGTYPE_NORMAL, " ok\n");
                 }
+                free (s);
             }
-            else
-            {
-                add_log (LOGTYPE_INFO, " No\n");
-            }
-        }
-        else
-        {
-            alpm_list_t *cmdlines, *i;
-            add_log (LOGTYPE_INFO, "Do you want to run the post-sysupgrade processes ?");
-            cmdlines = confirm_choices (
-            "Do you want to run the following post-sysupgrade processes ?",
-                "Only checked processes will be launch.",
-                "Yes, run checked processes now", NULL,
-                "No", NULL,
-                "Run",
-                "Command-line",
-                updater->cmdline_post,
-                updater->window);
-            if (NULL != cmdlines)
-            {
-                add_log (LOGTYPE_INFO, " Yes\n");
-                for (i = cmdlines; i; i = alpm_list_next (i))
-                {
-                    add_log (LOGTYPE_NORMAL, "Starting: '%s' ..", i->data);
-                    if (!g_spawn_command_line_async (i->data, &error))
-                    {
-                        add_log (LOGTYPE_NORMAL, " failed\n");
-                        _show_error ("Unable to start post-sysupgrade process.",
-                            "Command-line: %s\nError: %s",
-                            i->data, error->message);
-                        g_clear_error (&error);
-                    }
-                    else
-                    {
-                        add_log (LOGTYPE_NORMAL, " ok\n");
-                    }
-                }
-                FREELIST (cmdlines);
-            }
-            else
-            {
-                add_log (LOGTYPE_INFO, " No\n");
-            }
+            
+            alpm_list_free (cmdlines);
+            g_string_free (string, TRUE);
         }
     }
 }
     /* a scrolledwindow for the list */
     GtkWidget *scrolled;
     scrolled = gtk_scrolled_window_new (
-        gtk_tree_view_get_hadjustment (GTK_TREE_VIEW (list)),
-        gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (list)));
+        gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (list)),
+        gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (list)));
     gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
+    gtk_widget_set_size_request (scrolled, -1, 108);
     gtk_widget_show (scrolled);
     
     /* cell renderer & column(s) */