diff --git a/linuxdeployqt/main.cpp b/linuxdeployqt/main.cpp index 60a2458..d5aaf29 100644 --- a/linuxdeployqt/main.cpp +++ b/linuxdeployqt/main.cpp @@ -95,7 +95,7 @@ int main(int argc, char **argv) QFile::link(appBinaryPath, appDir + "/AppRun"); bool plugins = true; - bool dmg = false; + bool appimage = false; extern bool runStripEnabled; extern bool alwaysOwerwriteEnabled; extern QStringList librarySearchPath; @@ -108,9 +108,9 @@ int main(int argc, char **argv) if (argument == QByteArray("-no-pluginss")) { LogDebug() << "Argument found:" << argument; plugins = false; - } else if (argument == QByteArray("-dmg")) { + } else if (argument == QByteArray("-appimage")) { LogDebug() << "Argument found:" << argument; - dmg = true; + appimage = true; } else if (argument == QByteArray("-no-strip")) { LogDebug() << "Argument found:" << argument; runStripEnabled = false; @@ -154,6 +154,11 @@ int main(int argc, char **argv) } } + if (appimage) { + if(checkAppImagePrerequisites(appDirPath) == false) + return 1; + } + DeploymentInfo deploymentInfo = deployQtLibraries(appDirPath, additionalExecutables); // Convenience: Look for .qml files in the current directoty if no -qmldir specified. @@ -185,8 +190,7 @@ int main(int argc, char **argv) if (runStripEnabled) stripAppBinary(appDirPath); - if (dmg) { - LogNormal(); + if (appimage) { createAppImage(appDirPath); } diff --git a/shared/shared.cpp b/shared/shared.cpp index 382c1e4..b3d8908 100644 --- a/shared/shared.cpp +++ b/shared/shared.cpp @@ -980,32 +980,70 @@ void changeQtLibraries(const QString appPath, const QString &qtPath) } } -void createAppImage(const QString &appDirPath) +bool checkAppImagePrerequisites(const QString &appDirPath) { - QString appBaseName = appDirPath; - appBaseName.chop(4); // remove ".app" from end + QDirIterator iter(appDirPath, QStringList() << QString::fromLatin1("*.desktop"), + QDir::Files, QDirIterator::Subdirectories); + if (!iter.hasNext()) { + LogError() << "Desktop file missing, cannot create AppImage"; + // TODO: Create a generic desktop file (never overwrite an existing one though!) + return false; + } - QString dmgName = appBaseName + ".dmg"; + // TODO: Compare whether the icon filename matches the Icon= entry without ending in the *.desktop file above + QDirIterator iter2(appDirPath, QStringList() << QString::fromLatin1("*.png"), + QDir::Files, QDirIterator::Subdirectories); + if (!iter2.hasNext()) { + LogError() << "Icon file missing, cannot create AppImage"; + // TODO: Create a generic icon (never overwrite an existing one though!) + return false; + } + return true; +} - QFile dmg(dmgName); +void createAppImage(const QString &appDirPath) +{ + QString appImagePath = appDirPath + ".AppImage"; - if (dmg.exists() && alwaysOwerwriteEnabled) - dmg.remove(); + QFile appImage(appImagePath); + LogDebug() << "appImageName:" << appImagePath; - if (dmg.exists()) { - LogNormal() << "Disk image already exists, skipping .dmg creation for" << dmg.fileName(); + if (appImage.exists() && alwaysOwerwriteEnabled) + appImage.remove(); + + if (appImage.exists()) { + LogNormal() << "AppImage already exists, skipping .AppImage creation for" << appImage.fileName(); + LogNormal() << "use -always-overwrite to overwrite"; } else { - LogNormal() << "Creating disk image (.dmg) for" << appDirPath; + LogNormal() << "Creating AppImage for" << appDirPath; } - // More dmg options can be found in the hdiutil man page. - QStringList options = QStringList() - << "create" << dmgName - << "-srcfolder" << appDirPath - << "-format" << "UDZO" - << "-volname" << appBaseName; + QStringList options = QStringList() << appDirPath << appImagePath; + + QProcess appImageAssistant; + appImageAssistant.start("AppImageAssistant", options); + appImageAssistant.waitForFinished(-1); + + // FIXME: How to get the output to appear on the console as it happens rather than after the fact? + QString output = appImageAssistant.readAllStandardError(); + QStringList outputLines = output.split("\n", QString::SkipEmptyParts); + + for (const QString &outputLine : outputLines) { + // xorriso spits out a lot of WARNINGs which in the context of AppImage can be safely ignored + if(!outputLine.contains("WARNING")) { + LogNormal() << outputLine; + } + } - QProcess hdutil; - hdutil.start("hdiutil", options); - hdutil.waitForFinished(-1); + // AppImageAssistant doesn't always give nonzero error codes, so we check for the presence of the AppImage file + // This should eventually be fixed in AppImageAssistant + if (!QFile(appDirPath).exists()) { + LogError() << "FIXME: TODO: Check for the presence of AppImageAssistant on the $PATH"; + if(appImageAssistant.readAllStandardOutput().isEmpty() == false) + LogError() << "AppImageAssistant:" << appImageAssistant.readAllStandardOutput(); + if(appImageAssistant.readAllStandardError().isEmpty() == false) + LogError() << "AppImageAssistant:" << appImageAssistant.readAllStandardError(); + } else { + LogNormal() << "Created AppImage at" << appImagePath; + } } diff --git a/shared/shared.h b/shared/shared.h index 641b212..0a67ecb 100644 --- a/shared/shared.h +++ b/shared/shared.h @@ -125,6 +125,6 @@ void stripAppBinary(const QString &bundlePath); QString findAppBinary(const QString &appDirPath); QStringList findAppLibraries(const QString &appDirPath); void createAppImage(const QString &appBundlePath); - +bool checkAppImagePrerequisites(const QString &appBundlePath); #endif