You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
adept/adept/adept/application.cpp

351 lines
11 KiB

/** -*- C++ -*-
@file adept/application.cpp
@author Peter Rockai <me@mornfall.net>
*/
#include <qprocess.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kapplication.h>
#include <kstatusbar.h>
#include <kdebug.h>
#include <apt-front/init.h>
#include <apt-front/cache/component/packages.h>
#include <apt-front/cache/component/state.h>
#include <adept/commitprogress.h>
#include <adept/application.h>
#include <adept/packageinfo.h>
#include <adept/progress.h>
#include <adept/utils.h>
namespace adept {
using namespace cache;
#ifdef KUBUNTU
#include <qstringlist.h>
#define DPKG_FIXER_ARGS QStringList::split(QString(" "), QString("dpkg --configure -a"), false)
DpkgFixer::DpkgFixer(struct Application* parent)
: m_parent(parent)
{
m_fixer = 0;
m_waiter = 0;
m_output = "";
m_done = false;
}
DpkgFixer::~DpkgFixer()
{
if (m_fixer != 0) {
delete m_fixer;
}
if (m_waiter != 0) {
delete m_waiter;
}
std::cout << "Got output " << m_output.latin1() << std::endl;
}
void DpkgFixer::fixDpkgLock()
{
kdDebug() << "Asking user if they would like to fix dpkg lock..." << endl;
int decision = KMessageBox::warningYesNoCancel(m_parent->mainWindow(),
i18n("Another process is using the packaging system database "
"(probably some other Adept application or apt-get or "
"aptitude).\nWould you like to attempt to resolve this problem? "
"No will enter read-only mode and Cancel to quit and resolve "
"this issue yourself."),
i18n( "Database Locked" ) );
switch (decision) {
case KMessageBox::Yes:
kdDebug() << "User opted to fix the dpkg database. Trying to run the process..." << endl;
cache::Global::get().close();
// Call the dpkg fixer.
m_fixer = new QProcess(dynamic_cast<QObject*>(this));
m_fixer->setArguments(DPKG_FIXER_ARGS);
// Handle when the process exits
connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( processExited() ),
dynamic_cast<QObject*>(this), SLOT( retryOpen() ));
// Handle when the process has stdout output
connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( readyReadStdout() ),
dynamic_cast<QObject*>(this), SLOT( handleStdout() ));
// Handle when the process has stderr output
connect(dynamic_cast<QObject*>(m_fixer), SIGNAL( readyReadStderr() ),
dynamic_cast<QObject*>(this), SLOT( handleStderr() ));
// Fire off the waiter...
m_waiter = new KProgressDialog(m_parent->mainWindow(), "waiter",
i18n("Unlocking; Please Wait..."), i18n("Unlocking dpkg database; Please wait..."));
m_waiter->setAllowCancel(false);
m_waiter->show();
m_fixer->start();
kdDebug() << "dpkg fixer fired off." << endl;
break;
case KMessageBox::Cancel:
kdDebug() << "User opted to cancel and repair manually." << endl;
exit(1);
break;
default:
kdDebug() << "User opted to continue in read-only mode." << endl;
m_parent->updateStatusbar();
m_parent->cacheOpenedNowFinishInit();
break;
}
return;
}
void DpkgFixer::retryOpen()
{
kdDebug() << "Retrying the open..." << endl;
m_waiter->setLabel(i18n("Reopening the dpkg database..."));
m_waiter->progressBar()->setValue(50);
try {
if (!m_fixer->normalExit()) {
kdDebug() << "The fixer command did not exit normally. Throwing exception." << endl;
throw 0;
}
kdDebug() << "The fixer command exited normally, trying to reopen the database." << endl;
cache::Global::get().open( m_parent->openFlags() );
} catch (...) {
KMessageBox::information(m_parent->mainWindow(),
i18n( "Failed to unlock the database. "
"Please try to resolve this issue. "
"`sudo dpkg --configure -a` may help." ),
i18n( "Unlock Failed." ) );
exit( 1 );
}
m_waiter->progressBar()->setValue(100);
m_waiter->close();
m_parent->updateStatusbar();
m_parent->cacheOpenedNowFinishInit();
}
void DpkgFixer::outputUpdated()
{
}
void DpkgFixer::handleStdout()
{
// m_output += m_fixer->readStdout();
// outputUpdated();
}
void DpkgFixer::handleStderr()
{
// m_output += m_fixer->readStderr();
// outputUpdated();
}
#endif // KUBUNTU
Application::Application()
: m_acceptReadOnly( false ), m_main( 0 ), m_history( 0 ), m_statusBar( 0 )
{
#ifdef KUBUNTU
m_dpkgfixer = 0;
#endif // KUBUNTU
}
Application::~Application()
{
#ifdef KUBUNTU
if (m_dpkgfixer != 0) {
delete m_dpkgfixer;
}
#endif // KUBUNTU
}
void Application::openCache( unsigned flags )
{
m_flags = flags;
bool ro = m_acceptReadOnly;
bool root = ::getuid() == 0 || ::geteuid() == 0;
try {
cache::Global::get().open( m_flags );
} catch (...) {
try {
cache::Global::get().open( m_flags | Cache::OpenReadOnly );
if ( ro && root ) {
#ifndef KUBUNTU
kdDebug() << "ro && root -- Database locked." << endl;
KMessageBox::information(
m_main, i18n(
"You will not be able to change your system settings "
"in any way (install, remove or upgrade software), "
"because another process is using the packaging system database "
"(probably some other Adept application or apt-get or "
"aptitude). Please close the other application before "
"using this one." ),
i18n( "Read Only mode: Database Locked" ) );
#else
kdDebug() << "Firing off the Kubuntu dpkg database lock fixer..." << endl;
m_dpkgfixer = new DpkgFixer(this);
m_dpkgfixer->fixDpkgLock();
return;
#endif // KUBUNTU
} else if ( !root && ro ) {
kdDebug() << "!root && ro -- Need root privileges." << endl;
KMessageBox::information(
m_main, i18n(
"You will not be able to change your system settings "
"in any way (install, remove or upgrade software), "
"because this application needs special administrator "
"(root) privileges. Please run it as root or "
"through kdesu or sudo programs to be able to perform "
"these actions" ),
i18n( "Read Only mode: Need root privileges" ) );
} else if ( root && !ro ) {
#ifndef KUBUNTU
kdDebug() << "root && !ro -- Database locked." << endl;
KMessageBox::information(m_main,
i18n("Another process is using the packaging system database "
"(probably some other Adept application or apt-get or "
"aptitude). Please close the other application before "
"using this one." ),
i18n( "Read Only mode: Database Locked" ) );
#else
kdDebug() << "Firing off the Kubuntu dpkg database lock fixer..." << endl;
m_dpkgfixer = new DpkgFixer(this);
m_dpkgfixer->fixDpkgLock();
return;
#endif // KUBUNTU
} else if ( !root && !ro ) {
kdDebug() << "!root && !ro -- Needs root privileges." << endl;
KMessageBox::information(
m_main, i18n( "This application needs special administrator "
"(root) privileges. Please run it as root or "
"through kdesu or sudo programs" ),
i18n( "Need root privileges" ) );
}
if ( !ro ) {
kdDebug() << "cannot continue, exiting" << endl;
exit( 1 );
}
} catch (...) {
KMessageBox::sorry(
m_main, i18n(
"The APT Database could not be opened!"
" This may be caused by incorrect APT configuration"
" or some similar problem. Try running apt-setup and"
" apt-get update in terminal and see if it helps"
" to resolve the problem." ), i18n( "Could not open cache" ));
exit( 1 );
}
}
updateStatusbar();
cacheOpenedNowFinishInit();
}
void Application::initHistory() {
cache::Global::get().addComponent(
m_history = new History() );
}
void Application::initKDEDebconf()
{
// xxx unhardcode the package name somehow?
if (cache::Global::get().packages()
.packageByName( "libqt-perl" ).isInstalled())
putenv( "DEBIAN_FRONTEND=kde" );
}
void Application::initialize()
{
CommitProgress::initSystem();
aptFront::init();
openCache();
}
void Application::cacheOpenedNowFinishInit() {
initKDEDebconf();
initHistory();
observeComponent< component::State >();
initFinished();
}
void Application::checkpoint() {
if ( !history() ) return;
setHistoryEnabled( false );
history()->checkpoint();
setHistoryEnabled( true );
}
void Application::undo() {
if ( !history() ) return;
setHistoryEnabled( false );
history()->undo();
setHistoryEnabled( true );
}
void Application::redo() {
if ( !history() ) return;
setHistoryEnabled( false );
history()->redo();
setHistoryEnabled( true );
}
QString Application::changeString() {
component::State &s = cache().state();
return i18n( " Install %1, upgrade %2, remove %3 " )
.arg( s.newInstallCount() ).arg( s.upgradeCount() )
.arg( s.removeCount() );
}
QString Application::statusString() {
component::State &s = cache().state();
return i18n( " %1 installed, %2 upgradable, %3 available " )
.arg( s.installedCount() ).arg( s.upgradableCount() )
.arg( s.availableCount() );
}
QString Application::sizesString() {
QString dl = cache().state().downloadSizeString();
QString inst = cache().state().installSizeString();
return i18n( " download: %1, installation: %2 " ).arg( dl ).arg( inst );
}
void Application::setStatusBar( KStatusBar *s ) {
m_statusBar = s;
if ( s ) {
s->message( i18n( "Initializing..." ) );
s->insertItem( u8( "" ), 0 );
s->insertItem( u8( "" ), 1 );
s->insertItem( u8( "" ), 2 );
adjustFontSize( s, -1 );
adept::Progress *pr = new adept::Progress();
pr->setStatusBar( s );
cache::Global::get().setProgress( pr );
}
}
void Application::notifyPostChange( component::Base * )
{
updateStatusbar();
}
void Application::updateStatusbar()
{
if ( m_statusBar ) {
m_statusBar->changeItem( changeString(), 0 );
m_statusBar->changeItem( statusString(), 1 );
m_statusBar->changeItem( sizesString(), 2 );
}
}
}