205 lines
6.3 KiB
C++
205 lines
6.3 KiB
C++
#include "fixtures.h"
|
|
|
|
#include "minecraftversion.h"
|
|
|
|
#include <QBuffer>
|
|
#include <QCryptographicHash>
|
|
#include <QDir>
|
|
#include <QDirIterator>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QProcess>
|
|
#include <QTemporaryDir>
|
|
#include <QtCore/private/qzipreader_p.h>
|
|
#include <QtCore/private/qzipwriter_p.h>
|
|
|
|
QString Fixtures::path(const QString &relative)
|
|
{
|
|
return QStringLiteral(BILAUNCHER_FIXTURES_DIR) + u'/' + relative;
|
|
}
|
|
|
|
QByteArray Fixtures::read(const QString &relative)
|
|
{
|
|
QFile file(path(relative));
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
qFatal("Нет фикстуры %s", qPrintable(file.fileName()));
|
|
return file.readAll();
|
|
}
|
|
|
|
QJsonObject Fixtures::readJson(const QString &relative)
|
|
{
|
|
return QJsonDocument::fromJson(read(relative)).object();
|
|
}
|
|
|
|
QString Fixtures::otherOsName()
|
|
{
|
|
return VersionLoader::osName() == QLatin1String("windows") ? QStringLiteral("linux")
|
|
: QStringLiteral("windows");
|
|
}
|
|
|
|
QByteArray Fixtures::applyTemplate(QByteArray text)
|
|
{
|
|
text.replace("%OS%", VersionLoader::osName().toUtf8());
|
|
text.replace("%OTHER%", otherOsName().toUtf8());
|
|
text.replace("%ARCH%", VersionLoader::osArch().toUtf8());
|
|
text.replace("%NATIVE%", VersionLoader::nativeClassifier().toUtf8());
|
|
return text;
|
|
}
|
|
|
|
QByteArray Fixtures::readTemplate(const QString &relative)
|
|
{
|
|
return applyTemplate(read(relative));
|
|
}
|
|
|
|
bool Fixtures::write(const QString &filePath, const QByteArray &data)
|
|
{
|
|
QDir().mkpath(QFileInfo(filePath).absolutePath());
|
|
QFile file(filePath);
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
|
return false;
|
|
return file.write(data) == data.size();
|
|
}
|
|
|
|
bool Fixtures::writeJson(const QString &filePath, const QJsonObject &object)
|
|
{
|
|
return write(filePath, QJsonDocument(object).toJson(QJsonDocument::Indented));
|
|
}
|
|
|
|
QByteArray Fixtures::readFile(const QString &filePath)
|
|
{
|
|
QFile file(filePath);
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
return {};
|
|
return file.readAll();
|
|
}
|
|
|
|
QJsonObject Fixtures::readJsonFile(const QString &filePath)
|
|
{
|
|
return QJsonDocument::fromJson(readFile(filePath)).object();
|
|
}
|
|
|
|
QByteArray Fixtures::zipBytes(const QMap<QString, QByteArray> &entries)
|
|
{
|
|
QBuffer buffer;
|
|
buffer.open(QIODevice::WriteOnly);
|
|
{
|
|
QZipWriter writer(&buffer);
|
|
writer.setCompressionPolicy(QZipWriter::AutoCompress);
|
|
for (auto it = entries.cbegin(); it != entries.cend(); ++it) {
|
|
if (it.key().endsWith(u'/'))
|
|
writer.addDirectory(it.key());
|
|
else
|
|
writer.addFile(it.key(), it.value());
|
|
}
|
|
writer.close();
|
|
}
|
|
return buffer.data();
|
|
}
|
|
|
|
bool Fixtures::makeZip(const QString &zipPath, const QMap<QString, QByteArray> &entries)
|
|
{
|
|
return write(zipPath, zipBytes(entries));
|
|
}
|
|
|
|
QStringList Fixtures::zipEntries(const QString &zipPath)
|
|
{
|
|
QZipReader reader(zipPath);
|
|
QStringList result;
|
|
for (const QZipReader::FileInfo &info : reader.fileInfoList()) {
|
|
if (info.isFile)
|
|
result << info.filePath;
|
|
}
|
|
result.sort();
|
|
return result;
|
|
}
|
|
|
|
bool Fixtures::makeTarGz(const QString &archivePath, const QMap<QString, QByteArray> &entries)
|
|
{
|
|
QTemporaryDir staging;
|
|
if (!staging.isValid())
|
|
return false;
|
|
QStringList tops;
|
|
for (auto it = entries.cbegin(); it != entries.cend(); ++it) {
|
|
if (!write(staging.path() + u'/' + it.key(), it.value()))
|
|
return false;
|
|
const QString top = it.key().section(u'/', 0, 0);
|
|
if (!tops.contains(top))
|
|
tops << top;
|
|
}
|
|
QDir().mkpath(QFileInfo(archivePath).absolutePath());
|
|
|
|
QProcess tar;
|
|
tar.setWorkingDirectory(staging.path());
|
|
#if defined(Q_OS_WIN)
|
|
// Системный bsdtar по полному пути: GNU tar из Git, который бывает раньше в PATH,
|
|
// принимает «C:» за имя удалённого хоста (та же история в release.yml).
|
|
const QString program = qEnvironmentVariable("SystemRoot") + QStringLiteral("\\System32\\tar.exe");
|
|
#else
|
|
const QString program = QStringLiteral("tar");
|
|
#endif
|
|
tar.start(program,
|
|
QStringList{QStringLiteral("-czf"), QDir::toNativeSeparators(archivePath)} + tops);
|
|
return tar.waitForFinished(30000) && tar.exitStatus() == QProcess::NormalExit
|
|
&& tar.exitCode() == 0;
|
|
}
|
|
|
|
QString Fixtures::sha1(const QByteArray &data)
|
|
{
|
|
return QString::fromLatin1(QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex());
|
|
}
|
|
|
|
QString Fixtures::sha256(const QByteArray &data)
|
|
{
|
|
return QString::fromLatin1(QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex());
|
|
}
|
|
|
|
QStringList Fixtures::listTree(const QString &dir)
|
|
{
|
|
QStringList result;
|
|
QDirIterator it(dir, QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot,
|
|
QDirIterator::Subdirectories);
|
|
const QDir base(dir);
|
|
while (it.hasNext())
|
|
result << base.relativeFilePath(it.next());
|
|
result.sort();
|
|
return result;
|
|
}
|
|
|
|
QString Fixtures::javaExecutableName()
|
|
{
|
|
#if defined(Q_OS_WIN)
|
|
return QStringLiteral("java.exe");
|
|
#else
|
|
return QStringLiteral("java");
|
|
#endif
|
|
}
|
|
|
|
void Fixtures::configureFakeJava(const QString &javaPath, const QString &version,
|
|
const QStringList &config)
|
|
{
|
|
QStringList lines{QStringLiteral("version=") + version};
|
|
lines += config;
|
|
write(QFileInfo(javaPath).absolutePath() + QStringLiteral("/fake-java.cfg"),
|
|
lines.join(u'\n').toUtf8() + '\n');
|
|
}
|
|
|
|
QString Fixtures::installFakeJava(const QString &dir, const QString &version,
|
|
const QStringList &config)
|
|
{
|
|
const QString binDir = dir + QStringLiteral("/bin");
|
|
QDir().mkpath(binDir);
|
|
const QString java = binDir + u'/' + javaExecutableName();
|
|
QFile::remove(java);
|
|
if (!QFile::copy(QStringLiteral(BILAUNCHER_FAKE_JAVA), java))
|
|
qFatal("Не удалось скопировать fake_java в %s", qPrintable(java));
|
|
QFile::setPermissions(java, QFile::permissions(java) | QFileDevice::ExeOwner
|
|
| QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
|
#if defined(Q_OS_WIN)
|
|
const QString javaw = binDir + QStringLiteral("/javaw.exe");
|
|
QFile::remove(javaw);
|
|
QFile::copy(java, javaw);
|
|
#endif
|
|
configureFakeJava(java, version, config);
|
|
return java;
|
|
}
|