Hello again! It has been a long time since I published my first article. Things have changed a lot since then. A close friend of mine asked me a simple question –
“What is your favorite part of contributing to openSUSE?”
“Put succinctly, everything!” I said
It is a simple question but with no easy answer. I love the way I am introduced to opensource community through openSUSE. Contributing to openSUSE surely made me feel special. My sincere thanks and genuine appreciation to my mentors Antonio Larrosa, Cornelius Schumacher, and openSUSE team for their constant support and feedback.
The Work I Have Done So Far
It is mid term evaluation already! Let’s swift through the work I done so far.
Milestones Crossed/Achieved
- Port the application to use Qt5 instead of Qt4
- Introduce translation architecture using KF5I18N (KI18n)
- Improve localization
- Replace system calls with library calls to get package information
Git/GitHub Statistics
- 1,307 ++ / 429-- LOC
- 33 Commits
- 6 Pull Requests
The Work I Have Yet To Complete
- Replace system calls with library calls to install packages
- Handle conflicts and dependencies in the back-end
- Better progress interface
- Show which repository each package is coming from
Please click on continue reading below to know more about the work I’ve done. I once again thank my mentors Antonio Larrosa, and Cornelius Schumacher for their guidance and critique. It has been great working on One Click Installer so far and I hope it will be the same in the future as well. Thank you.
Great! Want to know more? Let’s get started!
Porting One Click Installer to Qt 5
Well, porting one click installer from Qt 4 to Qt 5 is seemingly easy. As it is a simple task, I have roughly documented the necessary steps.
1. Finding Qt 5
One of the major changes from Qt 4 to Qt 5 is the increase of modularity.
find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Widgets DBus)
Please note that specifying modules in one command is not available with Qt 5.0. You must use separate commands:
find_package(Qt5Widgets) find_package(Qt5Core)
2. Variables
Qt 4 uses CMake variables ${QT_INCLUDES} to include directories while compiling, and ${QT_LIBRARIES} while linking. The variable ${QT_USE_FILE} may have been used to include required include directories and defines.
However, with the modular Qt 5 system, the variables for each module will instead be
${Qt5Widgets_INCLUDE_DIRS}, ${Qt5Widgets_LIBRARIES}, ${Qt5Widgets_DEFINITIONS}
3. Replace QT4_WRAP_* with QT5_WRAP_*
QT5_WRAP_CPP(oneclickhelper_HEADERS_MOC ${oneclickhelper_HEADERS}) QT5_WRAP_CPP(oneclickinstaller_HEADERS_MOC ${oneclickinstaller_HEADERS})
4. Remove QtGui/ from includes
Remove QtGui/ or QtCore/ from includes to avoid compilation errors.
KF5I18N and Improving Localization
KI18n provides functionality for internationalizing user interface text in applications based on the GNU Gettext translation system. One click installer uses KI18n to provide/output user-visible information in various human languages, or, more precisely, locales.
If you are using CMake, you need to have the following in your CMakeLists.txt file. You also need to link to KF5::I18n
find_package(KF5I18n NO_MODULE)
To read more about KI18n, please read Introduction to KDE Gettext-based UI text internationalization
Library Calls To Get Package Information
Ever wondered how zypper finds information about a package (zypper info <package>) ? Be it querying meta-data, installing packages, or adding repositories, always initialize repositories, and refresh them (if not already).
To find meta-data of a package, we use PoolQuery API from libzypp. It returns solvables of specified kinds from specified repositories with attributes matching the specified search strings. The search strings can be specified via addString() and addAttribute() methods. Here’s an example:
PoolItem ZypperUtils::queryMetadataForPackage( const string& packageName ) { PoolQuery q; q.addKind( ResKind::package ); q.addAttribute( sat::SolvAttr::name, packageName ); q.setMatchExact(); return packageObject( q ); } PoolItem ZypperUtils::packageObject(const PoolQuery& q ) { PoolItem item; for( PoolQuery::Selectable_iterator it = q.selectableBegin(); it != q.selectableEnd(); ++it ) { const ui::Selectable& s = *(*it); // An update candidate object is better than any installed object PoolItem updateObject( s.updateCandidateObj() ); if ( updateObject ) item = updateObject; else item = s.installedObj(); } return item; }
From the [returned] PoolItem object, we can simply query required information as follows.
PoolItem packageObj = ZypperUtils::queryMetadataForPackage(packageName.toStdString()); if (!packageObj) cout << "Package Not Found!" << endl; m_version = packageObj.edition().asString(); m_size = packageObj.installSize().asString();
Getting package information is relatively easy when compared to installing packages (obviously 🙂 ). I’m working on it right now. I will post a detailed article explaining how problems of various complexities were tackled while installing packages as soon as possible.
Once again, it has been great working on One Click Installer and I hope it will be the same in the future as well. Thank you for your time.