mirror of
https://github.com/QuasarApp/installer-framework.git
synced 2025-05-20 08:49:34 +00:00
218 lines
7.1 KiB
C++
218 lines
7.1 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt SDK**
|
|
**
|
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
|
|
**
|
|
** Contact: Nokia Corporation qt-info@nokia.com**
|
|
**
|
|
** No Commercial Usage
|
|
**
|
|
** This file contains pre-release code and may not be distributed.
|
|
** You may use this file in accordance with the terms and conditions
|
|
** contained in the Technology Preview License Agreement accompanying
|
|
** this package.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
** Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception version
|
|
** 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** If you are unsure which license is appropriate for your use, please contact
|
|
** (qt-info@nokia.com).
|
|
**
|
|
**************************************************************************/
|
|
#include "macreplaceinstallnamesoperation.h"
|
|
#include "fsengineclient.h"
|
|
|
|
#include <QtCore/QDirIterator>
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QBuffer>
|
|
#include <QtCore/QProcess>
|
|
|
|
using namespace QInstaller;
|
|
|
|
MacReplaceInstallNamesOperation::MacReplaceInstallNamesOperation()
|
|
{
|
|
setName(QLatin1String("ReplaceInstallNames"));
|
|
}
|
|
|
|
void MacReplaceInstallNamesOperation::backup()
|
|
{
|
|
}
|
|
|
|
bool MacReplaceInstallNamesOperation::performOperation()
|
|
{
|
|
// Arguments:
|
|
// 1. indicator to find the original build directory
|
|
// 2. new build directory
|
|
// 3. directory containing frameworks
|
|
|
|
if( arguments().count() != 3 ) {
|
|
setError( InvalidArguments );
|
|
setErrorString( tr("Invalid arguments in %0: %1 arguments given, 3 expected.")
|
|
.arg(name()).arg( arguments().count() ) );
|
|
return false;
|
|
}
|
|
|
|
QString indicator = arguments().at(0);
|
|
QString installationDir = arguments().at(1);
|
|
QString searchDir = arguments().at(2);
|
|
return apply(indicator, installationDir, searchDir);
|
|
}
|
|
|
|
bool MacReplaceInstallNamesOperation::undoOperation()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool MacReplaceInstallNamesOperation::testOperation()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
KDUpdater::UpdateOperation* MacReplaceInstallNamesOperation::clone() const
|
|
{
|
|
return new MacReplaceInstallNamesOperation;
|
|
}
|
|
|
|
bool MacReplaceInstallNamesOperation::apply(const QString& indicator, const QString& installationDir, const QString& searchDir)
|
|
{
|
|
mOriginalBuildDir.clear();
|
|
mIndicator = indicator;
|
|
mInstallationDir = installationDir;
|
|
|
|
{
|
|
QDirIterator dirIterator(searchDir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
|
while (dirIterator.hasNext()) {
|
|
QString dirName = dirIterator.next();
|
|
if (dirName.endsWith(QLatin1String(".framework")))
|
|
relocateFramework(dirName);
|
|
}
|
|
}
|
|
|
|
return error() == NoError;
|
|
}
|
|
|
|
void MacReplaceInstallNamesOperation::extractExecutableInfo(const QString& fileName, QString& frameworkId, QStringList& frameworks)
|
|
{
|
|
QProcess otool;
|
|
otool.start(QLatin1String("otool"), QStringList() << QLatin1String("-l") << fileName);
|
|
if (!otool.waitForStarted()) {
|
|
setError(UserDefinedError, tr("Can't invoke otool."));
|
|
return;
|
|
}
|
|
otool.waitForFinished();
|
|
enum State {
|
|
State_Start,
|
|
State_LC_ID_DYLIB,
|
|
State_LC_LOAD_DYLIB
|
|
};
|
|
State state = State_Start;
|
|
QByteArray outputData = otool.readAllStandardOutput();
|
|
QBuffer output(&outputData);
|
|
output.open(QBuffer::ReadOnly);
|
|
while (!output.atEnd()) {
|
|
QString line = QString::fromLocal8Bit(output.readLine());
|
|
line = line.trimmed();
|
|
// qDebug() << line;
|
|
if (line.startsWith(QLatin1String("cmd "))) {
|
|
line.remove(0, 4);
|
|
if (line == QLatin1String("LC_LOAD_DYLIB"))
|
|
state = State_LC_LOAD_DYLIB;
|
|
else if (line == QLatin1String("LC_ID_DYLIB"))
|
|
state = State_LC_ID_DYLIB;
|
|
else
|
|
state = State_Start;
|
|
} else if (state == State_LC_LOAD_DYLIB && line.startsWith(QLatin1String("name "))) {
|
|
line.remove(0, 5);
|
|
int idx = line.indexOf(QLatin1String("(offset"));
|
|
if (idx > 0)
|
|
line.truncate(idx);
|
|
line = line.trimmed();
|
|
frameworks.append(line);
|
|
} else if (state == State_LC_ID_DYLIB && line.startsWith(QLatin1String("name "))) {
|
|
line.remove(0, 5);
|
|
int idx = line.indexOf(QLatin1String("(offset"));
|
|
if (idx > 0)
|
|
line.truncate(idx);
|
|
line = line.trimmed();
|
|
frameworkId = line;
|
|
|
|
mOriginalBuildDir = frameworkId;
|
|
idx = mOriginalBuildDir.indexOf(mIndicator);
|
|
if (idx < 0) {
|
|
mOriginalBuildDir.clear();
|
|
} else {
|
|
mOriginalBuildDir.truncate(idx);
|
|
}
|
|
if (mOriginalBuildDir.endsWith(QLatin1Char('/')))
|
|
mOriginalBuildDir.chop(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MacReplaceInstallNamesOperation::relocateBinary(const QString& fileName)
|
|
{
|
|
QString frameworkId;
|
|
QStringList frameworks;
|
|
extractExecutableInfo(fileName, frameworkId, frameworks);
|
|
|
|
QStringList args;
|
|
if (frameworkId.contains(mIndicator)) {
|
|
args << QLatin1String("-id") << fileName << fileName;
|
|
execCommand(QLatin1String("install_name_tool"), args);
|
|
}
|
|
|
|
foreach (const QString& fw, frameworks) {
|
|
if (!fw.contains(mOriginalBuildDir))
|
|
continue;
|
|
|
|
QString newPath = fw;
|
|
newPath.replace(mOriginalBuildDir, mInstallationDir);
|
|
|
|
args.clear();
|
|
args << QLatin1String("-change") << fw << newPath << fileName;
|
|
execCommand(QLatin1String("install_name_tool"), args);
|
|
}
|
|
}
|
|
|
|
void MacReplaceInstallNamesOperation::relocateFramework(const QString& directoryName)
|
|
{
|
|
//qDebug() << "relocateFramework" << directoryName;
|
|
QFileInfo fi(directoryName);
|
|
QString frameworkName = fi.baseName();
|
|
fi.setFile(directoryName + QLatin1String("/Versions/Current/") + frameworkName);
|
|
if (fi.exists()) {
|
|
QString fileName = fi.isSymLink() ? fi.symLinkTarget() : fi.absoluteFilePath();
|
|
relocateBinary(fileName);
|
|
}
|
|
fi.setFile(directoryName + QLatin1String("/Versions/Current/") + frameworkName + QLatin1String("_debug"));
|
|
if (fi.exists()) {
|
|
QString fileName = fi.isSymLink() ? fi.symLinkTarget() : fi.absoluteFilePath();
|
|
relocateBinary(fileName);
|
|
}
|
|
}
|
|
|
|
bool MacReplaceInstallNamesOperation::execCommand(const QString& cmd, const QStringList& args)
|
|
{
|
|
//qDebug() << cmd << args;
|
|
|
|
QProcessWrapper process;
|
|
process.start(cmd, args);
|
|
if (!process.waitForStarted()) {
|
|
setError(UserDefinedError, tr("Can't start process %0.").arg(cmd));
|
|
return false;
|
|
}
|
|
process.waitForFinished();
|
|
return true;
|
|
}
|