2009-05-12 01:40:57 +02:00
/*
* Copyright 2008 Aaron Seigo < aseigo @ kde . org >
*
* 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 ,
* 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 Library 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 <iostream>
2011-04-26 20:22:34 +02:00
# include <iomanip>
2009-05-12 01:40:57 +02:00
# include <QDir>
# include <QDBusInterface>
# include <KApplication>
# include <KAboutData>
# include <KCmdLineArgs>
2010-11-10 17:03:55 +01:00
# include <KDebug>
2009-05-12 01:40:57 +02:00
# include <KLocale>
2010-08-09 22:42:50 +02:00
# include <KPluginInfo>
2009-05-12 01:40:57 +02:00
# include <KService>
# include <KServiceTypeTrader>
# include <KShell>
# include <KStandardDirs>
# include <Plasma/PackageStructure>
# include <Plasma/Package>
# include <Plasma/PackageMetadata>
static const char description [ ] = I18N_NOOP ( " Install, list, remove Plasma packages " ) ;
2011-11-09 12:56:49 +01:00
static const char version [ ] = " 0.2 " ;
2009-05-12 01:40:57 +02:00
void output ( const QString & msg )
{
std : : cout < < msg . toLocal8Bit ( ) . constData ( ) < < std : : endl ;
}
void runKbuildsycoca ( )
{
QDBusInterface dbus ( " org.kde.kded " , " /kbuildsycoca " , " org.kde.kbuildsycoca " ) ;
2009-05-12 01:58:03 +02:00
dbus . call ( QDBus : : NoBlock , " recreate " ) ;
2009-05-12 01:40:57 +02:00
}
2009-07-26 16:17:08 +02:00
QStringList packages ( const QStringList & types )
2009-05-12 01:40:57 +02:00
{
QStringList result ;
2010-08-09 22:42:50 +02:00
2009-07-26 16:17:08 +02:00
foreach ( const QString & type , types ) {
2010-08-09 22:42:50 +02:00
const KService : : List services = KServiceTypeTrader : : self ( ) - > query ( type ) ;
foreach ( const KService : : Ptr & service , services ) {
2009-07-26 16:17:08 +02:00
result < < service - > property ( " X-KDE-PluginInfo-Name " , QVariant : : String ) . toString ( ) ;
}
2009-05-12 01:40:57 +02:00
}
2010-08-09 22:42:50 +02:00
2009-05-12 01:40:57 +02:00
return result ;
}
2009-07-26 16:17:08 +02:00
void listPackages ( const QStringList & types )
2009-05-12 01:40:57 +02:00
{
2009-07-26 16:17:08 +02:00
QStringList list = packages ( types ) ;
2009-05-12 01:40:57 +02:00
list . sort ( ) ;
2010-08-09 22:42:50 +02:00
foreach ( const QString & package , list ) {
2009-05-12 01:40:57 +02:00
output ( package ) ;
}
}
2011-04-26 20:53:51 +02:00
void renderTypeTable ( const QMap < QString , QStringList > & plugins )
{
const QString nameHeader = i18n ( " Addon Name " ) ;
const QString pluginHeader = i18n ( " Service Type " ) ;
const QString pathHeader = i18n ( " Path " ) ;
int nameWidth = nameHeader . length ( ) ;
int pluginWidth = pluginHeader . length ( ) ;
int pathWidth = pathHeader . length ( ) ;
QMapIterator < QString , QStringList > pluginIt ( plugins ) ;
while ( pluginIt . hasNext ( ) ) {
pluginIt . next ( ) ;
if ( pluginIt . key ( ) . length ( ) > nameWidth ) {
nameWidth = pluginIt . key ( ) . length ( ) ;
}
if ( pluginIt . value ( ) [ 0 ] . length ( ) > pluginWidth ) {
pluginWidth = pluginIt . value ( ) [ 0 ] . length ( ) ;
}
if ( pluginIt . value ( ) [ 1 ] . length ( ) > pathWidth ) {
pathWidth = pluginIt . value ( ) [ 1 ] . length ( ) ;
}
}
std : : cout < < nameHeader . toLocal8Bit ( ) . constData ( ) < < std : : setw ( nameWidth - nameHeader . length ( ) + 2 ) < < ' '
< < pluginHeader . toLocal8Bit ( ) . constData ( ) < < std : : setw ( pluginWidth - pluginHeader . length ( ) + 2 ) < < ' '
< < pathHeader . toLocal8Bit ( ) . constData ( ) < < std : : endl ;
std : : cout < < std : : setfill ( ' - ' ) < < std : : setw ( nameWidth ) < < ' - ' < < " "
< < std : : setw ( pluginWidth ) < < ' - ' < < " "
< < std : : setw ( pathWidth ) < < ' - ' < < std : : endl ;
std : : cout < < std : : setfill ( ' ' ) ;
pluginIt . toFront ( ) ;
while ( pluginIt . hasNext ( ) ) {
pluginIt . next ( ) ;
std : : cout < < pluginIt . key ( ) . toLocal8Bit ( ) . constData ( ) < < std : : setw ( nameWidth - pluginIt . key ( ) . length ( ) + 2 ) < < ' '
< < pluginIt . value ( ) [ 0 ] . toLocal8Bit ( ) . constData ( ) < < std : : setw ( pluginWidth - pluginIt . value ( ) [ 0 ] . length ( ) + 2 ) < < ' '
< < pluginIt . value ( ) [ 1 ] . toLocal8Bit ( ) . constData ( ) < < std : : endl ;
}
}
2010-08-09 22:46:01 +02:00
void listTypes ( )
{
output ( i18n ( " Package types that are installable with this tool: " ) ) ;
2010-08-14 20:19:03 +02:00
output ( i18n ( " Built in: " ) ) ;
2011-04-26 20:53:51 +02:00
QMap < QString , QStringList > builtIns ;
builtIns . insert ( i18n ( " DataEngine " ) , QStringList ( ) < < " Plasma/DataEngine " < < " plasma/dataengines/ " ) ;
builtIns . insert ( i18n ( " Layout Template " ) , QStringList ( ) < < " Plasma/LayoutTemplate " < < " plasma/layout-templates/ " ) ;
builtIns . insert ( i18n ( " Plasmoid " ) , QStringList ( ) < < " Plasma/Applet " < < " plasma/plasmoids/ " ) ;
builtIns . insert ( i18n ( " Runner " ) , QStringList ( ) < < " Plasma/Runner " < < " plasma/runners/ " ) ;
builtIns . insert ( i18n ( " Theme " ) , QStringList ( ) < < " " < < " desktoptheme/ " ) ;
builtIns . insert ( i18n ( " Wallpaper Images " ) , QStringList ( ) < < " " < < " wallpapers/ " ) ;
builtIns . insert ( i18n ( " Wallpaper Plugin " ) , QStringList ( ) < < " Plasma/Wallpaper " < < " plasma/wallpapers/ " ) ;
renderTypeTable ( builtIns ) ;
2010-08-09 22:46:01 +02:00
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( " Plasma/PackageStructure " ) ;
if ( ! offers . isEmpty ( ) ) {
std : : cout < < std : : endl ;
output ( i18n ( " Provided by plugins: " ) ) ;
2011-04-26 20:22:34 +02:00
QMap < QString , QStringList > plugins ;
2010-08-09 22:46:01 +02:00
foreach ( const KService : : Ptr service , offers ) {
KPluginInfo info ( service ) ;
2011-04-26 20:22:34 +02:00
Plasma : : PackageStructure : : Ptr structure = Plasma : : PackageStructure : : load ( info . pluginName ( ) ) ;
QString name = info . name ( ) ;
QString plugin = info . pluginName ( ) ;
QString path = structure - > defaultPackageRoot ( ) ;
plugins . insert ( name , QStringList ( ) < < plugin < < path ) ;
}
2011-04-26 20:53:51 +02:00
renderTypeTable ( plugins ) ;
2010-08-09 22:46:01 +02:00
}
QStringList desktopFiles = KGlobal : : dirs ( ) - > findAllResources ( " data " , " plasma/packageformats/*rc " , KStandardDirs : : NoDuplicates ) ;
if ( ! desktopFiles . isEmpty ( ) ) {
output ( i18n ( " Provided by .desktop files: " ) ) ;
Plasma : : PackageStructure structure ;
2011-04-26 20:53:51 +02:00
QMap < QString , QStringList > plugins ;
2010-08-09 22:46:01 +02:00
foreach ( const QString & file , desktopFiles ) {
// extract the type
KConfig config ( file , KConfig : : SimpleConfig ) ;
structure . read ( & config ) ;
// get the name based on the rc file name, just as Plasma::PackageStructure does
const QString name = file . left ( file . length ( ) - 2 ) ;
2011-04-26 20:53:51 +02:00
plugins . insert ( name , QStringList ( ) < < structure . type ( ) < < structure . defaultPackageRoot ( ) ) ;
2010-08-09 22:46:01 +02:00
}
}
}
2009-05-12 01:40:57 +02:00
int main ( int argc , char * * argv )
{
KAboutData aboutData ( " plasmapkg " , 0 , ki18n ( " Plasma Package Manager " ) ,
version , ki18n ( description ) , KAboutData : : License_GPL ,
ki18n ( " (C) 2008, Aaron Seigo " ) ) ;
aboutData . addAuthor ( ki18n ( " Aaron Seigo " ) ,
ki18n ( " Original author " ) ,
" aseigo@kde.org " ) ;
KComponentData componentData ( aboutData ) ;
KCmdLineArgs : : init ( argc , argv , & aboutData ) ;
KCmdLineOptions options ;
2011-11-09 12:56:49 +01:00
options . add ( " h " ) ;
options . add ( " hash <path> " , ki18nc ( " Do not translate <path> " , " Generate a SHA1 hash for the package at <path> " ) ) ;
2009-05-12 01:40:57 +02:00
options . add ( " g " ) ;
options . add ( " global " , ki18n ( " For install or remove, operates on packages installed for all users. " ) ) ;
options . add ( " t " ) ;
options . add ( " type <type> " ,
ki18nc ( " theme, wallpaper, etc. are keywords, but they may be translated, as both versions "
" are recognized by the application "
" (if translated, should be same as messages with 'package type' context below) " ,
2010-04-28 01:30:40 +02:00
" The type of package, e.g. theme, wallpaper, plasmoid, dataengine, runner, layout-template, etc. " ) ,
2009-05-12 01:40:57 +02:00
" plasmoid " ) ;
options . add ( " s " ) ;
options . add ( " i " ) ;
options . add ( " install <path> " , ki18nc ( " Do not translate <path> " , " Install the package at <path> " ) ) ;
options . add ( " u " ) ;
options . add ( " upgrade <path> " , ki18nc ( " Do not translate <path> " , " Upgrade the package at <path> " ) ) ;
options . add ( " l " ) ;
options . add ( " list " , ki18n ( " List installed packages " ) ) ;
2010-08-09 22:46:01 +02:00
options . add ( " list-types " , ki18n ( " lists all known Package types that can be installed " ) ) ;
2009-05-12 01:40:57 +02:00
options . add ( " r " ) ;
options . add ( " remove <name> " , ki18nc ( " Do not translate <name> " , " Remove the package named <name> " ) ) ;
options . add ( " p " ) ;
options . add ( " packageroot <path> " , ki18n ( " Absolute path to the package root. If not supplied, then the standard data directories for this KDE session will be searched instead. " ) ) ;
KCmdLineArgs : : addCmdLineOptions ( options ) ;
KApplication app ;
KCmdLineArgs * args = KCmdLineArgs : : parsedArgs ( ) ;
2011-11-09 12:56:49 +01:00
if ( args - > isSet ( " hash " ) ) {
const QString path = args - > getOption ( " hash " ) ;
Plasma : : PackageStructure : : Ptr structure ( new Plasma : : PackageStructure ) ;
Plasma : : Package package ( path , structure ) ;
const QString hash = package . contentsHash ( ) ;
if ( hash . isEmpty ( ) ) {
output ( i18n ( " Failed to generate a Package hash for %1 " , path ) ) ;
exit ( 1 ) ;
}
output ( i18n ( " SHA1 hash for Package at %1: '%2' " , path , hash ) ) ;
exit ( 0 ) ;
}
if ( args - > isSet ( " list-types " ) ) {
listTypes ( ) ;
exit ( 0 ) ;
}
2010-09-05 01:52:38 +02:00
QString type = args - > getOption ( " type " ) ;
2009-05-12 01:40:57 +02:00
QString packageRoot = type ;
QString servicePrefix ;
2009-07-26 16:17:08 +02:00
QStringList pluginTypes ;
2009-05-12 01:40:57 +02:00
Plasma : : PackageStructure * installer = 0 ;
2009-11-03 19:37:30 +01:00
QString package ;
QString packageFile ;
if ( args - > isSet ( " remove " ) ) {
package = args - > getOption ( " remove " ) ;
} else if ( args - > isSet ( " upgrade " ) ) {
package = args - > getOption ( " upgrade " ) ;
} else if ( args - > isSet ( " install " ) ) {
package = args - > getOption ( " install " ) ;
}
if ( ! QDir : : isAbsolutePath ( package ) ) {
packageFile = QDir ( QDir : : currentPath ( ) + ' / ' + package ) . absolutePath ( ) ;
} else {
packageFile = package ;
}
if ( ! packageFile . isEmpty ( ) & & ( ! args - > isSet ( " type " ) | |
2010-09-05 01:52:38 +02:00
type . compare ( i18nc ( " package type " , " wallpaper " ) , Qt : : CaseInsensitive ) = = 0 | |
type . compare ( " wallpaper " , Qt : : CaseInsensitive ) = = 0 ) ) {
2009-11-03 19:37:30 +01:00
// Check type for common plasma packages
Plasma : : PackageStructure package ;
package . setPath ( packageFile ) ;
QString serviceType = package . metadata ( ) . serviceType ( ) ;
if ( ! serviceType . isEmpty ( ) ) {
2011-12-19 15:19:15 +01:00
if ( serviceType . contains ( " Plasma/Applet " ) | |
serviceType . contains ( " Plasma/Containment " ) ) {
2009-11-03 19:37:30 +01:00
type = " plasmoid " ;
} else if ( serviceType = = " Plasma/DataEngine " ) {
type = " dataengine " ;
} else if ( serviceType = = " Plasma/Runner " ) {
type = " runner " ;
} else if ( serviceType = = " Plasma/Wallpaper " ) {
// This also changes type to wallpaperplugin when --type wallpaper
// was specified and we have wallpaper plugin package (instead of
// wallpaper image package)
type = " wallpaperplugin " ;
2010-09-05 01:52:38 +02:00
} else {
type = serviceType ;
kDebug ( ) < < " fallthrough type is " < < serviceType ;
2009-11-03 19:37:30 +01:00
}
}
}
2009-05-12 01:40:57 +02:00
2010-09-05 09:44:38 +02:00
if ( type . compare ( i18nc ( " package type " , " plasmoid " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " plasmoid " , Qt : : CaseInsensitive ) = = 0 ) {
2009-05-12 01:40:57 +02:00
packageRoot = " plasma/plasmoids/ " ;
servicePrefix = " plasma-applet- " ;
2010-08-09 22:42:50 +02:00
pluginTypes < < " Plasma/Applet " ;
pluginTypes < < " Plasma/PopupApplet " ;
pluginTypes < < " Plasma/Containment " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " theme " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " theme " , Qt : : CaseInsensitive ) = = 0 ) {
2009-05-12 01:40:57 +02:00
packageRoot = " desktoptheme/ " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " wallpaper " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " wallpaper " , Qt : : CaseInsensitive ) = = 0 ) {
2009-05-12 01:40:57 +02:00
packageRoot = " wallpapers/ " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " dataengine " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " dataengine " , Qt : : CaseInsensitive ) = = 0 ) {
2009-05-12 01:40:57 +02:00
packageRoot = " plasma/dataengines/ " ;
servicePrefix = " plasma-dataengine- " ;
2010-08-09 22:42:50 +02:00
pluginTypes < < " Plasma/DataEngine " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " runner " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " runner " , Qt : : CaseInsensitive ) = = 0 ) {
2009-05-12 01:40:57 +02:00
packageRoot = " plasma/runners/ " ;
servicePrefix = " plasma-runner- " ;
2010-08-09 22:42:50 +02:00
pluginTypes < < " Plasma/Runner " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " wallpaperplugin " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " wallpaperplugin " , Qt : : CaseInsensitive ) = = 0 ) {
2009-11-03 19:37:30 +01:00
packageRoot = " plasma/wallpapers/ " ;
servicePrefix = " plasma-wallpaper- " ;
2010-08-09 22:42:50 +02:00
pluginTypes < < " Plasma/Wallpaper " ;
2010-09-05 09:44:38 +02:00
} else if ( type . compare ( i18nc ( " package type " , " layout-template " ) , Qt : : CaseInsensitive ) = = 0 | |
2010-09-05 01:52:38 +02:00
type . compare ( " layout-template " , Qt : : CaseInsensitive ) = = 0 ) {
2010-04-28 01:30:40 +02:00
packageRoot = " plasma/layout-templates/ " ;
servicePrefix = " plasma-layout- " ;
2010-08-09 22:42:50 +02:00
pluginTypes < < " Plasma/LayoutTemplate " ;
2009-05-12 01:40:57 +02:00
} else {
2010-09-05 01:52:38 +02:00
const QString constraint = QString ( " [X-KDE-PluginInfo-Name] == '%1' " ) . arg ( type ) ;
2009-05-12 01:40:57 +02:00
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( " Plasma/PackageStructure " , constraint ) ;
if ( offers . isEmpty ( ) ) {
2010-09-05 01:52:38 +02:00
output ( i18n ( " Could not find a suitable installer for package of type %1 " , type ) ) ;
2009-05-12 01:40:57 +02:00
return 1 ;
}
KService : : Ptr offer = offers . first ( ) ;
QString error ;
installer = offer - > createInstance < Plasma : : PackageStructure > ( 0 , QVariantList ( ) , & error ) ;
if ( ! installer ) {
output ( i18n ( " Could not load installer for package of type %1. Error reported was: %2 " ,
2010-08-09 22:42:50 +02:00
args - > getOption ( " type " ) , error ) ) ;
2009-05-12 01:40:57 +02:00
return 1 ;
}
2010-08-09 22:42:50 +02:00
2009-05-12 01:40:57 +02:00
packageRoot = installer - > defaultPackageRoot ( ) ;
2009-07-26 16:17:08 +02:00
pluginTypes < < installer - > type ( ) ;
2010-09-05 09:44:38 +02:00
kDebug ( ) < < " we have: " < < packageRoot < < pluginTypes ;
2009-05-12 01:40:57 +02:00
}
if ( args - > isSet ( " list " ) ) {
2009-07-26 16:17:08 +02:00
listPackages ( pluginTypes ) ;
2009-05-12 01:40:57 +02:00
} else {
// install, remove or upgrade
if ( ! installer ) {
installer = new Plasma : : PackageStructure ( ) ;
installer - > setServicePrefix ( servicePrefix ) ;
}
2009-07-20 14:59:50 +02:00
if ( args - > isSet ( " packageroot " ) & & args - > isSet ( " global " ) ) {
KCmdLineArgs : : usageError ( i18nc ( " The user entered conflicting options packageroot and global, this is the error message telling the user he can use only one " , " The packageroot and global options conflict each other, please select only one. " ) ) ;
} else if ( args - > isSet ( " packageroot " ) ) {
2009-05-12 01:40:57 +02:00
packageRoot = args - > getOption ( " packageroot " ) ;
} else if ( args - > isSet ( " global " ) ) {
packageRoot = KStandardDirs : : locate ( " data " , packageRoot ) ;
} else {
packageRoot = KStandardDirs : : locateLocal ( " data " , packageRoot ) ;
}
if ( args - > isSet ( " remove " ) | | args - > isSet ( " upgrade " ) ) {
installer - > setPath ( packageFile ) ;
Plasma : : PackageMetadata metadata = installer - > metadata ( ) ;
QString pluginName ;
if ( metadata . pluginName ( ) . isEmpty ( ) ) {
// plugin name given in command line
pluginName = package ;
} else {
// Parameter was a plasma package, get plugin name from the package
pluginName = metadata . pluginName ( ) ;
}
2009-07-26 16:17:08 +02:00
QStringList installed = packages ( pluginTypes ) ;
2009-05-12 01:40:57 +02:00
if ( installed . contains ( pluginName ) ) {
if ( installer - > uninstallPackage ( pluginName , packageRoot ) ) {
output ( i18n ( " Successfully removed %1 " , pluginName ) ) ;
} else if ( ! args - > isSet ( " upgrade " ) ) {
output ( i18n ( " Removal of %1 failed. " , pluginName ) ) ;
2009-05-12 01:58:03 +02:00
delete installer ;
2009-05-12 01:40:57 +02:00
return 1 ;
}
} else {
output ( i18n ( " Plugin %1 is not installed. " , pluginName ) ) ;
}
}
if ( args - > isSet ( " install " ) | | args - > isSet ( " upgrade " ) ) {
if ( installer - > installPackage ( packageFile , packageRoot ) ) {
output ( i18n ( " Successfully installed %1 " , packageFile ) ) ;
} else {
output ( i18n ( " Installation of %1 failed. " , packageFile ) ) ;
2009-05-12 01:58:03 +02:00
delete installer ;
2009-05-12 01:40:57 +02:00
return 1 ;
}
}
if ( package . isEmpty ( ) ) {
KCmdLineArgs : : usageError ( i18nc ( " No option was given, this is the error message telling the user he needs at least one, do not translate install, remove, upgrade nor list " , " One of install, remove, upgrade or list is required. " ) ) ;
} else {
runKbuildsycoca ( ) ;
}
}
delete installer ;
return 0 ;
}