diff --git a/code/ryzom/tools/client/ryzom_installer/res/Info.plist b/code/ryzom/tools/client/ryzom_installer/res/Info.plist new file mode 100644 index 000000000..0f34722db --- /dev/null +++ b/code/ryzom/tools/client/ryzom_installer/res/Info.plist @@ -0,0 +1,54 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + shortcut.sh + CFBundleGetInfoString + $NAME + CFBundleIconFile + ryzom.icns + CFBundleIdentifier + $IDENTIFIER + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLocalizations + + en + fr + de + ru + es + + CFBundleLongVersionString + $VERSION + CFBundleName + $NAME + CFBundlePackageType + APPL + CFBundleShortVersionString + $VERSION + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1.0 + CSResourcesFileMapped + + LSApplicationCategoryType + public.app-category.role-playing-games + LSFileQuarantineEnabled + + LSMinimumSystemVersion + 10.6 + LSRequiresCarbon + + NSHumanReadableCopyright + $COPYRIGHT + + diff --git a/code/ryzom/tools/client/ryzom_installer/res/PkgInfo b/code/ryzom/tools/client/ryzom_installer/res/PkgInfo new file mode 100644 index 000000000..bd04210fb --- /dev/null +++ b/code/ryzom/tools/client/ryzom_installer/res/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/code/ryzom/tools/client/ryzom_installer/res/resources.qrc b/code/ryzom/tools/client/ryzom_installer/res/resources.qrc index 31622b6c1..6336b61e1 100644 --- a/code/ryzom/tools/client/ryzom_installer/res/resources.qrc +++ b/code/ryzom/tools/client/ryzom_installer/res/resources.qrc @@ -4,10 +4,13 @@ ryzom.ico - ryzom_installer.png + ryzom.png + ryzom.icns template.desktop ryzom_installer.ini + Info.plist + PkgInfo diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns b/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns new file mode 100644 index 000000000..45e7bace1 Binary files /dev/null and b/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns differ diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom.png b/code/ryzom/tools/client/ryzom_installer/res/ryzom.png new file mode 100644 index 000000000..a51ce87ab Binary files /dev/null and b/code/ryzom/tools/client/ryzom_installer/res/ryzom.png differ diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png b/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png deleted file mode 100644 index 67e3034ef..000000000 Binary files a/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png and /dev/null differ diff --git a/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh b/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh new file mode 100644 index 000000000..014ce6520 --- /dev/null +++ b/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# autogenerated file - do not edit + +$COMMAND diff --git a/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp b/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp index c3eaf3d64..06c525053 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp +++ b/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp @@ -791,15 +791,18 @@ QStringList CConfigFile::getInstallerRequiredFiles() const // unsupported compiler #endif + // include current executable + files << QFileInfo(QApplication::applicationFilePath()).fileName(); #elif defined(Q_OS_MAC) - // TODO: for OS X + // everything is in a directory + files << "Ryzom Installer.app"; #else // icon under Linux files << "ryzom_installer.png"; -#endif // include current executable files << QFileInfo(QApplication::applicationFilePath()).fileName(); +#endif return files; } diff --git a/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp index 513cf1044..7198962ac 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp +++ b/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp @@ -118,16 +118,7 @@ void CInstallDialog::accept() if (succeedsToWrite) { // check if directory is writable by current user - QFile file(m_dstDirectory + "/writable_test_for_ryzom_installer.txt"); - - if (file.open(QFile::WriteOnly)) - { - file.close(); - - // remove it - file.remove(); - } - else + if (!isDirectoryWritable(m_dstDirectory)) { succeedsToWrite = false; } diff --git a/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp index 0527bca1f..22e4f0ad2 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp +++ b/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp @@ -133,16 +133,7 @@ void CMigrateDialog::accept() if (succeedsToWrite) { // check if directory is writable by current user - QFile file(m_dstDirectory + "/writable_test_for_ryzom_installer.txt"); - - if (file.open(QFile::WriteOnly)) - { - file.close(); - - // remove it - file.remove(); - } - else + if (!isDirectoryWritable(m_dstDirectory)) { succeedsToWrite = false; } diff --git a/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp index d5e83037c..9c84f46cf 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp +++ b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp @@ -788,9 +788,17 @@ void COperationDialog::copyInstaller() #ifdef Q_OS_WIN32 // under Windows, icon is included in executable icon = executable; +#elif defined(Q_OS_MAC) + // everything is in bundle #else // icon is in the same directory as installer icon = config->getInstallationDirectory() + "/ryzom_installer.png"; + + // create icon if not exists + if (!QFile::exists(icon) && !writeResource(":/icons/ryzom.png", icon)) + { + qDebug() << "Unable to create" << icon; + } #endif createShortcut(shortcut, name, executable, "", icon, ""); @@ -1072,6 +1080,9 @@ void COperationDialog::deleteComponentsServers() // clear list of all servers to uninstall m_removeComponents.servers.clear(); + // delete Ryzom directory if all files have been deleted + if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively(); + emit done(); } @@ -1142,6 +1153,9 @@ void COperationDialog::deleteComponentsProfiles() // clear list of all profiles to uninstall m_removeComponents.profiles.clear(); + // delete profiles directory if all files have been deleted + if (isDirectoryEmpty(config->getProfileDirectory(), true)) QDir(config->getProfileDirectory()).removeRecursively(); + emit done(); } @@ -1190,6 +1204,9 @@ void COperationDialog::deleteComponentsInstaller() // reset it once it's done m_removeComponents.installer = false; + // delete Ryzom directory if all files have been deleted + if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively(); + emit success(1); emit done(); } @@ -1225,6 +1242,9 @@ void COperationDialog::deleteComponentsDownloadedFiles() // reset it once it's done m_removeComponents.downloadedFiles = false; + // delete Ryzom directory if all files have been deleted + if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively(); + emit success(1); emit done(); } diff --git a/code/ryzom/tools/client/ryzom_installer/src/utils.cpp b/code/ryzom/tools/client/ryzom_installer/src/utils.cpp index c2789f180..de967b4f8 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/utils.cpp +++ b/code/ryzom/tools/client/ryzom_installer/src/utils.cpp @@ -16,6 +16,7 @@ #include "stdpch.h" #include "utils.h" +#include "configfile.h" #include "nel/misc/path.h" @@ -40,6 +41,36 @@ QString qBytesToHumanReadable(qint64 bytes) return QString::fromUtf8(NLMISC::bytesToHumanReadableUnits(bytes, units).c_str()); } +QString nameToId(const QString &name) +{ + QString res; + + // only allows simple characters + QRegExp allowedCharacters("^[0-9a-zA-Z-]$"); + + for (int i = 0, len = name.length(); i < len; ++i) + { + if (allowedCharacters.indexIn(name.at(i)) > -1) + { + // allowed character + res += name[i]; + } + else + { + // not allowed, replace by a space + res += " "; + } + } + + // simplify all spaces + res = res.simplified(); + + // replace spaces by minus + res.replace(" ", "-"); + + return res; +} + bool isDirectoryEmpty(const QString &directory, bool recursize) { bool res = true; @@ -71,6 +102,21 @@ bool isDirectoryEmpty(const QString &directory, bool recursize) return res; } +bool isDirectoryWritable(const QString &directory) +{ + // check if directory is writable by current user + QFile file(directory + "/writable_test_for_ryzom_installer.txt"); + + if (!file.open(QFile::WriteOnly)) return false; + + file.close(); + + // remove it + file.remove(); + + return true; +} + qint64 getDirectorySize(const QString &directory, bool recursize) { qint64 size = 0; @@ -250,37 +296,89 @@ bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pa return SUCCEEDED(hres); } +#elif defined(NL_OS_MAC) + +bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir) +{ + QString appPath(shortcut + ".app"); + + // directories + QString contentsPath(appPath + "/Contents"); + QString binaryPath(contentsPath + "/MacOS"); + QString dataPath(contentsPath + "/Resources"); + + // files + QString binaryFile(binaryPath + "/shortcut.sh"); + QString iconFile(dataPath + "/ryzom.icns"); + QString pkgInfoFile(contentsPath + "/PkgInfo"); + QString plistFile(contentsPath + "/Info.plist"); + + // silently create directories + QDir().mkpath(binaryPath); + QDir().mkpath(dataPath); + + if (!isDirectoryWritable(binaryPath) || !isDirectoryWritable(dataPath)) return false; + + // write icon + if (!writeResource(":/icons/ryzom.icns", iconFile)) return false; + + // write PkgInfo + if (!writeResource(":/templates/PkgInfo", pkgInfoFile)) return false; + + // variables + QMap strings; + + // build command + QString command = QString("open \"%1\"").arg(executable); + if (!arguments.isEmpty()) command += " --args " + arguments; + + strings.clear(); + strings["COMMAND"] = command; + + // write shortcut.sh + if (!writeResourceWithTemplates(":/templates/shortcut.sh", binaryFile, strings)) return false; + + // set executable flags to .sh + QFile::setPermissions(binaryFile, QFile::permissions(binaryFile) | QFile::ExeGroup | QFile::ExeUser | QFile::ExeOther); + + CConfigFile *config = CConfigFile::getInstance(); + + strings.clear(); + strings["NAME"] = name; + strings["COPYRIGHT"] = config->getProductPublisher(); + strings["VERSION"] = QApplication::applicationVersion(); + strings["IDENTIFIER"] = "com.winchgate.Ryzom-" + nameToId(name); + + // write Info.plist + if (!writeResourceWithTemplates(":/templates/Info.plist", plistFile, strings)) return false; + + return true; +} + +bool resolveShortcut(const QWidget &window, const QString &pathLink, QString &pathObj) +{ + return false; +} + #else bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir) { - // open template - QFile file(":/templates/template.desktop"); - - if (!file.open(QFile::ReadOnly)) return false; - - QString data = QString::fromUtf8(file.readAll()); - - file.close(); - // build command QString command = executable; if (!arguments.isEmpty()) command += " " + arguments; - // replace strings - data.replace("$NAME", name); - data.replace("$COMMAND", command); - data.replace("$ICON", icon); + // variables + QMap strings; + strings["NAME"] = name; + strings["COMMAND"] = command; + strings["ICON"] = icon; + // destination file QString path(shortcut + ".desktop"); - // write file - file.setFileName(path); - - if (!file.open(QFile::WriteOnly)) return false; - - file.write(data.toUtf8()); - file.close(); + // replace strings + if (!writeResourceWithTemplates(":/templates/template.desktop", path, strings)) return false; // set executable flags to .desktop QFile::setPermissions(path, QFile::permissions(path) | QFile::ExeGroup | QFile::ExeUser | QFile::ExeOther); @@ -307,7 +405,13 @@ bool removeShortcut(const QString &shortcut) if (!NLMISC::CFile::isExists(qToUtf8(fullPath))) return false; // remove it +#if defined(Q_OS_MAC) + // under OS X, it's a directory + return QDir(fullPath).removeRecursively(); +#else + // a file under other platforms return QFile::remove(fullPath); +#endif } QString appendShortcutExtension(const QString &shortcut) @@ -317,7 +421,7 @@ QString appendShortcutExtension(const QString &shortcut) #if defined(Q_OS_WIN32) extension = ".lnk"; #elif defined(Q_OS_MAC) - // TODO + extension = ".app"; #else extension = ".desktop"; #endif @@ -391,6 +495,75 @@ QString getVersionFromExecutable(const QString &path) return ""; } +bool writeResource(const QString &resource, const QString &path) +{ + // all resources start with :/ + if (!resource.startsWith(":/")) return false; + + // open resource + QFile file(resource); + + // unable to open it + if (!file.open(QFile::ReadOnly)) return false; + + QByteArray data(file.readAll()); + + file.close(); + + // write file + file.setFileName(path); + + // unable to write it + if (!file.open(QFile::WriteOnly)) return false; + + // problem writting + if (file.write(data) != data.length()) return false; + + file.close(); + + return true; +} + +bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap &strings) +{ + // all resources start with :/ + if (!resource.startsWith(":/")) return false; + + // open resource + QFile file(resource); + + // unable to open it + if (!file.open(QFile::ReadOnly)) return false; + + // data are UTF-8 text + QString data = QString::fromUtf8(file.readAll()); + + file.close(); + + // write file + file.setFileName(path); + + // unable to write it + if (!file.open(QFile::WriteOnly)) return false; + + // replace strings + QMap::ConstIterator it = strings.begin(), iend = strings.end(); + + while (it != iend) + { + // replace variables with their value + data.replace("$" + it.key(), it.value()); + + ++it; + } + + // write + file.write(data.toUtf8()); + file.close(); + + return true; +} + CCOMHelper::CCOMHelper() { #ifdef Q_OS_WIN diff --git a/code/ryzom/tools/client/ryzom_installer/src/utils.h b/code/ryzom/tools/client/ryzom_installer/src/utils.h index 0b0bcb170..296c439fd 100644 --- a/code/ryzom/tools/client/ryzom_installer/src/utils.h +++ b/code/ryzom/tools/client/ryzom_installer/src/utils.h @@ -29,8 +29,10 @@ */ QString qBytesToHumanReadable(qint64 bytes); +QString nameToId(const QString &name); bool isDirectoryEmpty(const QString &directory, bool recursize); +bool isDirectoryWritable(const QString &directory); qint64 getDirectorySize(const QString &directory, bool recursize); @@ -57,6 +59,8 @@ bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pa QString appendShortcutExtension(const QString &shortcut); QString getVersionFromExecutable(const QString &path); +bool writeResource(const QString &resource, const QString &path); +bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap &strings); class CCOMHelper {