1104 lines
29 KiB
C
1104 lines
29 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* Licensed under the GNU General Public License Version 2
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/ioctl.h>
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <dbus/dbus-glib.h>
|
|
|
|
#include <pk-debug.h>
|
|
#include <pk-client.h>
|
|
#include <pk-package-id.h>
|
|
#include <pk-enum-list.h>
|
|
#include <pk-common.h>
|
|
#include <pk-connection.h>
|
|
|
|
#define PROGRESS_BAR_PADDING 22
|
|
#define MINIMUM_COLUMNS (PROGRESS_BAR_PADDING + 5)
|
|
|
|
static GMainLoop *loop = NULL;
|
|
static PkEnumList *role_list = NULL;
|
|
static gboolean is_console = FALSE;
|
|
static gboolean has_output = FALSE;
|
|
static gboolean printed_bar = FALSE;
|
|
static guint timer_id = 0;
|
|
static gchar *package_id = NULL;
|
|
|
|
typedef struct {
|
|
gint position;
|
|
gboolean move_forward;
|
|
} PulseState;
|
|
|
|
/**
|
|
* pk_console_package_cb:
|
|
**/
|
|
static void
|
|
pk_console_package_cb (PkClient *client, PkInfoEnum info, const gchar *package_id, const gchar *summary, gpointer data)
|
|
{
|
|
PkPackageId *ident;
|
|
PkPackageId *spacing;
|
|
gchar *info_text;
|
|
guint extra = 0;
|
|
|
|
/* if on console, clear the progress bar line */
|
|
if (is_console == TRUE && printed_bar == TRUE && has_output == FALSE) {
|
|
g_print ("\r");
|
|
}
|
|
|
|
/* pass this out */
|
|
info_text = pk_strpad (pk_info_enum_to_text (info), 12);
|
|
|
|
spacing = pk_package_id_new ();
|
|
ident = pk_package_id_new_from_string (package_id);
|
|
|
|
/* these numbers are guesses */
|
|
extra = 0;
|
|
spacing->name = pk_strpad_extra (ident->name, 20, &extra);
|
|
spacing->arch = pk_strpad_extra (ident->arch, 7, &extra);
|
|
spacing->version = pk_strpad_extra (ident->version, 15, &extra);
|
|
spacing->data = pk_strpad_extra (ident->data, 12, &extra);
|
|
|
|
/* pretty print */
|
|
g_print ("%s %s %s %s %s %s\n", info_text, spacing->name,
|
|
spacing->arch, spacing->version, spacing->data, summary);
|
|
|
|
/* free all the data */
|
|
g_free (info_text);
|
|
pk_package_id_free (ident);
|
|
pk_package_id_free (spacing);
|
|
|
|
/* don't do the percentage bar from now on */
|
|
has_output = TRUE;
|
|
}
|
|
|
|
/**
|
|
* pk_console_transaction_cb:
|
|
**/
|
|
static void
|
|
pk_console_transaction_cb (PkClient *client, const gchar *tid, const gchar *timespec,
|
|
gboolean succeeded, PkRoleEnum role, guint duration,
|
|
const gchar *data, gpointer user_data)
|
|
{
|
|
const gchar *role_text;
|
|
role_text = pk_role_enum_to_text (role);
|
|
g_print ("Transaction : %s\n", tid);
|
|
g_print (" timespec : %s\n", timespec);
|
|
g_print (" succeeded : %i\n", succeeded);
|
|
g_print (" role : %s\n", role_text);
|
|
g_print (" duration : %i (seconds)\n", duration);
|
|
g_print (" data : %s\n", data);
|
|
}
|
|
|
|
/**
|
|
* pk_console_update_detail_cb:
|
|
**/
|
|
static void
|
|
pk_console_update_detail_cb (PkClient *client, const gchar *package_id,
|
|
const gchar *updates, const gchar *obsoletes,
|
|
const gchar *vendor_url, const gchar *bugzilla_url,
|
|
const gchar *cve_url, PkRestartEnum restart,
|
|
const gchar *update_text, gpointer data)
|
|
{
|
|
g_print ("Update detail\n");
|
|
g_print (" package: '%s'\n", package_id);
|
|
if (pk_strzero (updates) == FALSE) {
|
|
g_print (" updates: '%s'\n", updates);
|
|
}
|
|
if (pk_strzero (obsoletes) == FALSE) {
|
|
g_print (" obsoletes: '%s'\n", obsoletes);
|
|
}
|
|
if (pk_strzero (vendor_url) == FALSE) {
|
|
g_print (" vendor URL: '%s'\n", vendor_url);
|
|
}
|
|
if (pk_strzero (bugzilla_url) == FALSE) {
|
|
g_print (" bug URL: '%s'\n", bugzilla_url);
|
|
}
|
|
if (pk_strzero (cve_url) == FALSE) {
|
|
g_print (" cve URL: '%s'\n", cve_url);
|
|
}
|
|
if (restart != PK_RESTART_ENUM_NONE) {
|
|
g_print (" restart: '%s'\n", pk_restart_enum_to_text (restart));
|
|
}
|
|
if (pk_strzero (update_text) == FALSE) {
|
|
g_print (" update_text:'%s'\n", update_text);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pk_console_repo_detail_cb:
|
|
**/
|
|
static void
|
|
pk_console_repo_detail_cb (PkClient *client, const gchar *repo_id,
|
|
const gchar *description, gboolean enabled, gpointer data)
|
|
{
|
|
gchar *repo;
|
|
repo = pk_strpad (repo_id, 28);
|
|
if (enabled == TRUE) {
|
|
g_print (" enabled %s %s\n", repo, description);
|
|
} else {
|
|
g_print (" disabled %s %s\n", repo, description);
|
|
}
|
|
g_free (repo);
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_terminal_columns:
|
|
**/
|
|
static guint
|
|
pk_console_get_terminal_columns (void)
|
|
{
|
|
struct winsize ws;
|
|
|
|
ioctl (1, TIOCGWINSZ, &ws);
|
|
if (ws.ws_col < MINIMUM_COLUMNS) {
|
|
return MINIMUM_COLUMNS;
|
|
}
|
|
|
|
return ws.ws_col;
|
|
}
|
|
|
|
/**
|
|
* pk_console_draw_progress_bar:
|
|
**/
|
|
static void
|
|
pk_console_draw_progress_bar (guint percentage, guint remaining_time)
|
|
{
|
|
guint i;
|
|
guint progress_bar_size = pk_console_get_terminal_columns () - PROGRESS_BAR_PADDING;
|
|
guint progress = (gint) (progress_bar_size * (gfloat) (percentage) / 100);
|
|
guint remaining = progress_bar_size - progress;
|
|
|
|
/* have we already been spinning? */
|
|
if (timer_id != 0) {
|
|
g_source_remove (timer_id);
|
|
timer_id = 0;
|
|
}
|
|
|
|
/* we need to do an extra line */
|
|
printed_bar = TRUE;
|
|
|
|
g_print ("\r [");
|
|
for (i = 0; i < progress; i++) {
|
|
g_print ("=");
|
|
}
|
|
for (i = 0; i < remaining; i++) {
|
|
g_print (".");
|
|
}
|
|
g_print ("] %3i%%", percentage);
|
|
if (remaining_time != 0) {
|
|
if (remaining_time > 60) {
|
|
guint remaining_minutes = remaining_time / 60;
|
|
if (remaining_minutes > 60) {
|
|
guint remaining_hours = remaining_time / 3600;
|
|
g_print (" (%2ih eta)", remaining_hours);
|
|
} else {
|
|
g_print (" (%2im eta)", remaining_minutes);
|
|
}
|
|
} else {
|
|
g_print (" (%2is eta)", remaining_time);
|
|
}
|
|
} else {
|
|
g_print (" ");
|
|
}
|
|
if (percentage == 100) {
|
|
g_print ("\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pk_console_pulse_bar:
|
|
**/
|
|
static gboolean
|
|
pk_console_pulse_bar (PulseState *pulse_state)
|
|
{
|
|
guint i;
|
|
guint progress_bar_size = pk_console_get_terminal_columns () - PROGRESS_BAR_PADDING;
|
|
gchar *padding;
|
|
|
|
/* don't spin if we have had output */
|
|
if (has_output == TRUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
/* we need to do an extra line */
|
|
printed_bar = TRUE;
|
|
|
|
/* the clever pulse code */
|
|
printf("\r [");
|
|
for (i = 0; i < pulse_state->position - 1; i++) {
|
|
g_print (".");
|
|
}
|
|
printf("===");
|
|
for (i = pulse_state->position; i < progress_bar_size - 2; i++) {
|
|
g_print (".");
|
|
}
|
|
g_print ("]");
|
|
|
|
if (pulse_state->move_forward == TRUE) {
|
|
if (pulse_state->position == progress_bar_size - 2) {
|
|
pulse_state->move_forward = FALSE;
|
|
pulse_state->position--;
|
|
} else {
|
|
pulse_state->position++;
|
|
}
|
|
} else if (pulse_state->move_forward == FALSE) {
|
|
if (pulse_state->position == 1) {
|
|
pulse_state->move_forward = TRUE;
|
|
pulse_state->position++;
|
|
} else {
|
|
pulse_state->position--;
|
|
}
|
|
}
|
|
|
|
/* Move the cursor off the screen. */
|
|
padding = g_strnfill (PROGRESS_BAR_PADDING - 6, ' ');
|
|
g_print ("%s", padding);
|
|
g_free (padding);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pk_console_draw_progress_bar:
|
|
**/
|
|
static void
|
|
pk_console_draw_pulse_bar (void)
|
|
{
|
|
static PulseState pulse_state;
|
|
|
|
/* have we already got zero percent? */
|
|
if (timer_id != 0) {
|
|
return;
|
|
}
|
|
has_output = FALSE;
|
|
if (is_console == TRUE) {
|
|
pulse_state.position = 1;
|
|
pulse_state.move_forward = TRUE;
|
|
timer_id = g_timeout_add (40, (GSourceFunc) pk_console_pulse_bar, &pulse_state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pk_console_progress_changed_cb:
|
|
**/
|
|
static void
|
|
pk_console_progress_changed_cb (PkClient *client, guint percentage, guint subpercentage,
|
|
guint elapsed, guint remaining, gpointer data)
|
|
{
|
|
if (is_console == TRUE) {
|
|
if (percentage == PK_CLIENT_PERCENTAGE_INVALID) {
|
|
pk_console_draw_pulse_bar ();
|
|
} else {
|
|
pk_console_draw_progress_bar (percentage, remaining);
|
|
}
|
|
} else {
|
|
g_print ("%i%%\n", percentage);
|
|
}
|
|
}
|
|
|
|
const gchar *summary =
|
|
"PackageKit Console Interface\n"
|
|
"\n"
|
|
"Subcommands:\n"
|
|
" search name|details|group|file data\n"
|
|
" install <package_id>\n"
|
|
" install-file <file>\n"
|
|
" remove <package_id>\n"
|
|
" update <package_id>\n"
|
|
" refresh\n"
|
|
" resolve\n"
|
|
" force-refresh\n"
|
|
" update-system\n"
|
|
" get updates\n"
|
|
" get depends <package_id>\n"
|
|
" get requires <package_id>\n"
|
|
" get description <package_id>\n"
|
|
" get files <package_id>\n"
|
|
" get updatedetail <package_id>\n"
|
|
" get actions\n"
|
|
" get groups\n"
|
|
" get filters\n"
|
|
" get transactions\n"
|
|
" get repos\n"
|
|
" enable-repo <repo_id>\n"
|
|
" disable-repo <repo_id>\n"
|
|
" set-repo-data <repo_id> <parameter> <value>\n"
|
|
"\n"
|
|
" package_id is typically gimp;2:2.4.0-0.rc1.1.fc8;i386;development";
|
|
|
|
/**
|
|
* pk_client_wait:
|
|
**/
|
|
static gboolean
|
|
pk_client_wait (void)
|
|
{
|
|
pk_debug ("starting loop");
|
|
g_main_loop_run (loop);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pk_console_finished_cb:
|
|
**/
|
|
static void
|
|
pk_console_finished_cb (PkClient *client, PkExitEnum exit, guint runtime, gpointer data)
|
|
{
|
|
PkRoleEnum role;
|
|
gchar *blanking;
|
|
const gchar *role_text;
|
|
gfloat time;
|
|
PkRestartEnum restart;
|
|
|
|
/* cancel the spinning */
|
|
if (timer_id != 0) {
|
|
g_source_remove (timer_id);
|
|
}
|
|
|
|
/* if on console, clear the progress bar line */
|
|
if (is_console == TRUE && printed_bar == TRUE && has_output == FALSE) {
|
|
g_print ("\r");
|
|
blanking = g_strnfill (pk_console_get_terminal_columns (), ' ');
|
|
g_print ("%s", blanking);
|
|
g_free (blanking);
|
|
g_print ("\r");
|
|
}
|
|
|
|
pk_client_get_role (client, &role, NULL);
|
|
role_text = pk_role_enum_to_text (role);
|
|
time = (gfloat) runtime / 1000.0;
|
|
g_print ("%s runtime was %.1f seconds\n", role_text, time);
|
|
|
|
/* is there any restart to notify the user? */
|
|
restart = pk_client_get_require_restart (client);
|
|
if (restart != PK_RESTART_ENUM_NONE) {
|
|
g_print ("Requires restart: %s\n", pk_restart_enum_to_text (restart));
|
|
}
|
|
|
|
if (loop != NULL) {
|
|
g_main_loop_quit (loop);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pk_console_perhaps_resolve:
|
|
**/
|
|
static gchar *
|
|
pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gboolean valid;
|
|
PkClient *client_resolve;
|
|
const gchar *filter_text;
|
|
guint i;
|
|
guint length;
|
|
PkPackageItem *item;
|
|
|
|
/* have we passed a complete package_id? */
|
|
valid = pk_package_id_check (package);
|
|
if (valid == TRUE) {
|
|
return g_strdup (package);
|
|
}
|
|
|
|
/* we need to resolve it */
|
|
client_resolve = pk_client_new ();
|
|
g_signal_connect (client_resolve, "finished",
|
|
/* TODO: send local loop */
|
|
G_CALLBACK (pk_console_finished_cb), NULL);
|
|
filter_text = pk_filter_enum_to_text (filter);
|
|
pk_client_set_use_buffer (client_resolve, TRUE);
|
|
ret = pk_client_resolve (client_resolve, filter_text, package);
|
|
if (ret == FALSE) {
|
|
pk_warning ("Resolve is not supported in this backend");
|
|
return NULL;
|
|
} else {
|
|
g_main_loop_run (loop);
|
|
}
|
|
|
|
/* get length of items found */
|
|
length = pk_client_package_buffer_get_size (client_resolve);
|
|
|
|
/* only found one, great! */
|
|
if (length == 1) {
|
|
item = pk_client_package_buffer_get_item (client_resolve, 0);
|
|
return item->package_id;
|
|
}
|
|
|
|
/* else list the options if multiple matches found */
|
|
if (length != 0) {
|
|
g_print ("There are multiple matches\n");
|
|
for (i=0; i<length; i++) {
|
|
item = pk_client_package_buffer_get_item (client_resolve, i);
|
|
g_print ("%i. %s\n", i+1, item->package_id);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* pk_console_install_package:
|
|
**/
|
|
static gboolean
|
|
pk_console_install_package (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_NOT_INSTALLED, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to install\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_install_package (client, package_id);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_remove_only:
|
|
**/
|
|
static gboolean
|
|
pk_console_remove_only (PkClient *client, gboolean force)
|
|
{
|
|
gboolean ret;
|
|
|
|
pk_debug ("remove %s", package_id);
|
|
pk_client_reset (client);
|
|
ret = pk_client_remove_package (client, package_id, force);
|
|
/* ick, we failed so pretend we didn't do the action */
|
|
if (ret == FALSE) {
|
|
pk_warning ("The package could not be removed");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_requires_finished_cb:
|
|
**/
|
|
static void
|
|
pk_console_requires_finished_cb (PkClient *client2, PkStatusEnum status, guint runtime, PkClient *client)
|
|
{
|
|
guint length;
|
|
PkPackageItem *item;
|
|
PkPackageId *ident;
|
|
guint i;
|
|
gboolean remove;
|
|
|
|
/* see how many packages there are */
|
|
length = pk_client_package_buffer_get_size (client2);
|
|
|
|
/* if there are no required packages, just do the remove */
|
|
if (length == 0) {
|
|
pk_debug ("no requires");
|
|
pk_console_remove_only (client, FALSE);
|
|
g_object_unref (client2);
|
|
return;
|
|
}
|
|
|
|
/* present this to the user */
|
|
g_print ("The following packages have to be removed:\n");
|
|
for (i=0; i<length; i++) {
|
|
item = pk_client_package_buffer_get_item (client2, i);
|
|
ident = pk_package_id_new_from_string (item->package_id);
|
|
g_print ("%i\t%s-%s\n", i, ident->name, ident->version);
|
|
pk_package_id_free (ident);
|
|
}
|
|
|
|
/* check for user input */
|
|
g_print ("Okay to remove additional packages? [N/y]\n");
|
|
|
|
/* TODO: prompt the user */
|
|
remove = FALSE;
|
|
|
|
if (remove == FALSE) {
|
|
g_print ("Cancelled!\n");
|
|
if (loop != NULL) {
|
|
g_main_loop_quit (loop);
|
|
pk_debug ("<kjjjjjjjjjjjjjjjjjjjjjjjjjjjjj");
|
|
}
|
|
} else {
|
|
pk_debug ("the user aggreed, remove with deps");
|
|
pk_console_remove_only (client, TRUE);
|
|
}
|
|
g_object_unref (client2);
|
|
}
|
|
|
|
/**
|
|
* pk_console_remove_package:
|
|
**/
|
|
static gboolean
|
|
pk_console_remove_package (PkClient *client, const gchar *package)
|
|
{
|
|
PkClient *client2;
|
|
|
|
g_free (package_id);
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_INSTALLED, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to remove\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* are we dumb and can't check for requires? */
|
|
if (pk_enum_list_contains (role_list, PK_ROLE_ENUM_GET_REQUIRES) == FALSE) {
|
|
/* no, just try to remove it without deps */
|
|
pk_console_remove_only (client, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
/* see if any packages require this one */
|
|
client2 = pk_client_new ();
|
|
pk_client_set_use_buffer (client2, TRUE);
|
|
g_signal_connect (client2, "finished",
|
|
G_CALLBACK (pk_console_requires_finished_cb), client);
|
|
pk_debug ("getting requires for %s", package_id);
|
|
pk_client_get_requires (client2, package_id, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pk_console_update_package:
|
|
**/
|
|
static gboolean
|
|
pk_console_update_package (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_INSTALLED, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to update\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_update_package (client, package_id);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_requires:
|
|
**/
|
|
static gboolean
|
|
pk_console_get_requires (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_NONE, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to get requires\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_requires (client, package_id, TRUE);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_depends:
|
|
**/
|
|
static gboolean
|
|
pk_console_get_depends (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_NONE, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to get depends\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_depends (client, package_id, FALSE);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_description:
|
|
**/
|
|
static gboolean
|
|
pk_console_get_description (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_NONE, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to get description\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_description (client, package_id);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_files:
|
|
**/
|
|
static gboolean
|
|
pk_console_get_files (PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_NONE, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to get files\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_files (client, package_id);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_get_update_detail
|
|
**/
|
|
static gboolean
|
|
pk_console_get_update_detail(PkClient *client, const gchar *package)
|
|
{
|
|
gboolean ret;
|
|
gchar *package_id;
|
|
package_id = pk_console_perhaps_resolve (client, PK_FILTER_ENUM_INSTALLED, package);
|
|
if (package_id == NULL) {
|
|
g_print ("Could not find a package with that name to get update details\n");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_update_detail (client, package_id);
|
|
g_free (package_id);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* pk_console_process_commands:
|
|
**/
|
|
static gboolean
|
|
pk_console_process_commands (PkClient *client, int argc, char *argv[], gboolean wait_override, GError **error)
|
|
{
|
|
const gchar *mode;
|
|
const gchar *value = NULL;
|
|
const gchar *details = NULL;
|
|
const gchar *parameter = NULL;
|
|
gboolean wait = FALSE;
|
|
PkEnumList *elist;
|
|
|
|
mode = argv[1];
|
|
if (argc > 2) {
|
|
value = argv[2];
|
|
}
|
|
if (argc > 3) {
|
|
details = argv[3];
|
|
}
|
|
if (argc > 4) {
|
|
parameter = argv[4];
|
|
}
|
|
|
|
if (strcmp (mode, "search") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search type");
|
|
return FALSE;
|
|
} else if (strcmp (value, "name") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_search_name (client, "none", details);
|
|
}
|
|
} else if (strcmp (value, "details") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_search_details (client, "none", details);
|
|
}
|
|
} else if (strcmp (value, "group") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_search_group (client, "none", details);
|
|
}
|
|
} else if (strcmp (value, "file") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_search_file (client, "none", details);
|
|
}
|
|
} else {
|
|
g_set_error (error, 0, 0, "invalid search type");
|
|
}
|
|
} else if (strcmp (mode, "install") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to install");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_install_package (client, value);
|
|
}
|
|
} else if (strcmp (mode, "install-file") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to install");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_install_file (client, value);
|
|
}
|
|
} else if (strcmp (mode, "remove") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to remove");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_remove_package (client, value);
|
|
}
|
|
} else if (strcmp (mode, "update") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to update");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_update_package (client, value);
|
|
}
|
|
} else if (strcmp (mode, "resolve") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package name to resolve");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_resolve (client, "none", value);
|
|
}
|
|
} else if (strcmp (mode, "enable-repo") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a repo name");
|
|
return FALSE;
|
|
} else {
|
|
pk_client_repo_enable (client, value, TRUE);
|
|
}
|
|
} else if (strcmp (mode, "disable-repo") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a repo name");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_repo_enable (client, value, FALSE);
|
|
}
|
|
} else if (strcmp (mode, "set-repo-data") == 0) {
|
|
if (value == NULL || details == NULL || parameter == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a repo name/parameter and value");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_client_repo_set_data (client, value, details, parameter);
|
|
}
|
|
} else if (strcmp (mode, "get") == 0) {
|
|
if (value == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a get type");
|
|
return FALSE;
|
|
} else if (strcmp (value, "time") == 0) {
|
|
PkRoleEnum role;
|
|
guint time;
|
|
gboolean ret;
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
}
|
|
role = pk_role_enum_from_text (details);
|
|
if (role == PK_ROLE_ENUM_UNKNOWN) {
|
|
g_set_error (error, 0, 0, "you need to specify a correct role");
|
|
return FALSE;
|
|
}
|
|
ret = pk_client_get_time_since_action (client, role, &time);
|
|
if (ret == FALSE) {
|
|
g_set_error (error, 0, 0, "failed to get last time");
|
|
return FALSE;
|
|
}
|
|
g_print ("time since %s is %is\n", details, time);
|
|
} else if (strcmp (value, "depends") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_get_depends (client, details);
|
|
}
|
|
} else if (strcmp (value, "updatedetail") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_get_update_detail (client, details);
|
|
}
|
|
} else if (strcmp (value, "requires") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a search term");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_get_requires (client, details);
|
|
}
|
|
} else if (strcmp (value, "description") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to find the description for");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_get_description (client, details);
|
|
}
|
|
} else if (strcmp (value, "files") == 0) {
|
|
if (details == NULL) {
|
|
g_set_error (error, 0, 0, "you need to specify a package to find the files for");
|
|
return FALSE;
|
|
} else {
|
|
wait = pk_console_get_files (client, details);
|
|
}
|
|
} else if (strcmp (value, "updates") == 0) {
|
|
wait = pk_client_get_updates (client);
|
|
} else if (strcmp (value, "actions") == 0) {
|
|
elist = pk_client_get_actions (client);
|
|
pk_enum_list_print (elist);
|
|
g_object_unref (elist);
|
|
} else if (strcmp (value, "filters") == 0) {
|
|
elist = pk_client_get_filters (client);
|
|
pk_enum_list_print (elist);
|
|
g_object_unref (elist);
|
|
} else if (strcmp (value, "repos") == 0) {
|
|
wait = pk_client_get_repo_list (client);
|
|
} else if (strcmp (value, "groups") == 0) {
|
|
elist = pk_client_get_groups (client);
|
|
pk_enum_list_print (elist);
|
|
g_object_unref (elist);
|
|
} else if (strcmp (value, "transactions") == 0) {
|
|
wait = pk_client_get_old_transactions (client, 10);
|
|
} else {
|
|
g_set_error (error, 0, 0, "invalid get type");
|
|
}
|
|
} else if (strcmp (mode, "update-system") == 0) {
|
|
wait = pk_client_update_system (client);
|
|
} else if (strcmp (mode, "refresh") == 0) {
|
|
wait = pk_client_refresh_cache (client, FALSE);
|
|
} else if (strcmp (mode, "force-refresh") == 0) {
|
|
wait = pk_client_refresh_cache (client, TRUE);
|
|
} else {
|
|
g_set_error (error, 0, 0, "option not yet supported");
|
|
}
|
|
|
|
/* only wait if success */
|
|
if (wait == TRUE && wait_override == TRUE) {
|
|
pk_client_wait ();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pk_console_error_code_cb:
|
|
**/
|
|
static void
|
|
pk_console_error_code_cb (PkClient *client, PkErrorCodeEnum error_code, const gchar *details, gpointer data)
|
|
{
|
|
/* if on console, clear the progress bar line */
|
|
if (is_console == TRUE && printed_bar == TRUE) {
|
|
g_print ("\n");
|
|
}
|
|
g_print ("Error: %s : %s\n", pk_error_enum_to_text (error_code), details);
|
|
}
|
|
|
|
/**
|
|
* pk_console_description_cb:
|
|
**/
|
|
static void
|
|
pk_console_description_cb (PkClient *client, const gchar *package_id,
|
|
const gchar *license, PkGroupEnum group,
|
|
const gchar *description, const gchar *url,
|
|
gulong size, gpointer data)
|
|
{
|
|
/* if on console, clear the progress bar line */
|
|
if (is_console == TRUE && printed_bar == TRUE) {
|
|
g_print ("\n");
|
|
}
|
|
g_print ("Package description\n");
|
|
g_print (" package: '%s'\n", package_id);
|
|
g_print (" license: '%s'\n", license);
|
|
g_print (" group: '%s'\n", pk_group_enum_to_text (group));
|
|
g_print (" description: '%s'\n", description);
|
|
g_print (" size: '%ld' bytes\n", size);
|
|
g_print (" url: '%s'\n", url);
|
|
}
|
|
|
|
/**
|
|
* pk_console_files_cb:
|
|
**/
|
|
static void
|
|
pk_console_files_cb (PkClient *client, const gchar *package_id,
|
|
const gchar *filelist, gpointer data)
|
|
{
|
|
gchar **filevector = g_strsplit (filelist, ";", 0);
|
|
|
|
/* if on console, clear the progress bar line */
|
|
if (is_console == TRUE && printed_bar == TRUE) {
|
|
g_print ("\n");
|
|
}
|
|
|
|
g_print ("Package files\n");
|
|
|
|
if (*filevector != NULL) {
|
|
gchar **current_file = filevector;
|
|
|
|
while (*current_file != NULL) {
|
|
g_print (" %s\n", *current_file);
|
|
current_file++;
|
|
}
|
|
} else {
|
|
g_print (" no files\n");
|
|
}
|
|
|
|
g_strfreev (filevector);
|
|
}
|
|
|
|
/**
|
|
* pk_console_repo_signature_required_cb:
|
|
**/
|
|
static void
|
|
pk_console_repo_signature_required_cb (PkClient *client, const gchar *repository_name, const gchar *key_url,
|
|
const gchar *key_userid, const gchar *key_id, const gchar *key_fingerprint,
|
|
const gchar *key_timestamp, PkSigTypeEnum type, gpointer data)
|
|
{
|
|
g_print ("Signature Required\n");
|
|
g_print (" repo name: '%s'\n", repository_name);
|
|
g_print (" key url: '%s'\n", key_url);
|
|
g_print (" key userid: '%s'\n", key_userid);
|
|
g_print (" key id: '%s'\n", key_id);
|
|
g_print (" key fingerprint: '%s'\n", key_fingerprint);
|
|
g_print (" key timestamp: '%s'\n", key_timestamp);
|
|
g_print (" key type: '%s'\n", pk_sig_type_enum_to_text (type));
|
|
|
|
}
|
|
|
|
/**
|
|
* pk_connection_changed_cb:
|
|
**/
|
|
static void
|
|
pk_connection_changed_cb (PkConnection *pconnection, gboolean connected, gpointer data)
|
|
{
|
|
/* if the daemon crashed, don't hang around */
|
|
if (connected == FALSE && loop != NULL) {
|
|
pk_warning ("The daemon went away...");
|
|
g_main_loop_quit (loop);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* main:
|
|
**/
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
DBusGConnection *system_connection;
|
|
GError *error = NULL;
|
|
PkClient *client;
|
|
PkConnection *pconnection;
|
|
gboolean verbose = FALSE;
|
|
gboolean program_version = FALSE;
|
|
gboolean nowait = FALSE;
|
|
GOptionContext *context;
|
|
gchar *options_help;
|
|
|
|
const GOptionEntry options[] = {
|
|
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
|
|
"Show extra debugging information", NULL },
|
|
{ "version", '\0', 0, G_OPTION_ARG_NONE, &program_version,
|
|
"Show the program version and exit", NULL},
|
|
{ "nowait", 'n', 0, G_OPTION_ARG_NONE, &nowait,
|
|
"Exit without waiting for actions to complete", NULL},
|
|
{ NULL}
|
|
};
|
|
|
|
if (! g_thread_supported ()) {
|
|
g_thread_init (NULL);
|
|
}
|
|
dbus_g_thread_init ();
|
|
g_type_init ();
|
|
|
|
/* check if we are on console */
|
|
if (isatty (fileno (stdout)) == 1) {
|
|
is_console = TRUE;
|
|
}
|
|
|
|
/* check dbus connections, exit if not valid */
|
|
system_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
|
|
if (error) {
|
|
pk_warning ("%s", error->message);
|
|
g_error_free (error);
|
|
g_error ("This program cannot start until you start the dbus system service.");
|
|
}
|
|
|
|
context = g_option_context_new (_("SUBCOMMAND"));
|
|
g_option_context_set_summary (context, summary) ;
|
|
g_option_context_add_main_entries (context, options, NULL);
|
|
g_option_context_parse (context, &argc, &argv, NULL);
|
|
/* Save the usage string in case command parsing fails. */
|
|
options_help = g_option_context_get_help (context, TRUE, NULL);
|
|
g_option_context_free (context);
|
|
|
|
if (program_version == TRUE) {
|
|
g_print (VERSION "\n");
|
|
return 0;
|
|
}
|
|
|
|
if (argc < 2) {
|
|
g_print (options_help);
|
|
return 1;
|
|
}
|
|
|
|
pk_debug_init (verbose);
|
|
loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
pconnection = pk_connection_new ();
|
|
g_signal_connect (pconnection, "connection-changed",
|
|
G_CALLBACK (pk_connection_changed_cb), loop);
|
|
|
|
client = pk_client_new ();
|
|
g_signal_connect (client, "package",
|
|
G_CALLBACK (pk_console_package_cb), NULL);
|
|
g_signal_connect (client, "transaction",
|
|
G_CALLBACK (pk_console_transaction_cb), NULL);
|
|
g_signal_connect (client, "description",
|
|
G_CALLBACK (pk_console_description_cb), NULL);
|
|
g_signal_connect (client, "files",
|
|
G_CALLBACK (pk_console_files_cb), NULL);
|
|
g_signal_connect (client, "repo-signature-required",
|
|
G_CALLBACK (pk_console_repo_signature_required_cb), NULL);
|
|
g_signal_connect (client, "update-detail",
|
|
G_CALLBACK (pk_console_update_detail_cb), NULL);
|
|
g_signal_connect (client, "repo-detail",
|
|
G_CALLBACK (pk_console_repo_detail_cb), NULL);
|
|
g_signal_connect (client, "progress-changed",
|
|
G_CALLBACK (pk_console_progress_changed_cb), NULL);
|
|
g_signal_connect (client, "finished",
|
|
G_CALLBACK (pk_console_finished_cb), NULL);
|
|
g_signal_connect (client, "error-code",
|
|
G_CALLBACK (pk_console_error_code_cb), NULL);
|
|
|
|
role_list = pk_client_get_actions (client);
|
|
pk_debug ("actions=%s", pk_enum_list_to_string (role_list));
|
|
|
|
/* run the commands */
|
|
pk_console_process_commands (client, argc, argv, !nowait, &error);
|
|
if (error != NULL) {
|
|
g_print ("Error:\n %s\n\n", error->message);
|
|
g_error_free (error);
|
|
g_print (options_help);
|
|
}
|
|
|
|
g_free (options_help);
|
|
g_object_unref (client);
|
|
|
|
return 0;
|
|
}
|