summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-07-16 02:03:52 +0200
committerPetr Mrázek <peterix@gmail.com>2014-07-16 02:03:52 +0200
commit8a56ab6780f525472dce4dccdd53fec41390d586 (patch)
treef7d2ecf90a404e3ef0768890c85cb2101d948445
parent71575a5022a4e682a9960256ade7ea5672d1210d (diff)
downloadMultiMC-8a56ab6780f525472dce4dccdd53fec41390d586.tar
MultiMC-8a56ab6780f525472dce4dccdd53fec41390d586.tar.gz
MultiMC-8a56ab6780f525472dce4dccdd53fec41390d586.tar.lz
MultiMC-8a56ab6780f525472dce4dccdd53fec41390d586.tar.xz
MultiMC-8a56ab6780f525472dce4dccdd53fec41390d586.zip
Implement gradle spec reader/writer
-rw-r--r--CMakeLists.txt4
-rw-r--r--logic/DefaultVariable.h35
-rw-r--r--logic/InstanceList.cpp24
-rw-r--r--logic/minecraft/GradleSpecifier.h83
-rw-r--r--logic/minecraft/OneSixLibrary.cpp5
-rw-r--r--logic/minecraft/RawLibrary.cpp22
-rw-r--r--logic/minecraft/RawLibrary.h5
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/tst_gradlespecifier.cpp77
9 files changed, 241 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8f84b28..ac497f46 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -427,6 +427,9 @@ SET(MULTIMC_SOURCES
# RW lock protected map
logic/RWStorage.h
+ # A variable that has an implicit default value and keeps track of changes
+ logic/DefaultVariable.h
+
# network stuffs
logic/net/NetAction.h
logic/net/MD5EtagDownload.h
@@ -493,6 +496,7 @@ SET(MULTIMC_SOURCES
logic/OneSixInstance_p.h
# OneSix version json infrastructure
+ logic/minecraft/GradleSpecifier.h
logic/minecraft/InstanceVersion.cpp
logic/minecraft/InstanceVersion.h
logic/minecraft/JarMod.cpp
diff --git a/logic/DefaultVariable.h b/logic/DefaultVariable.h
new file mode 100644
index 00000000..38d7ecc2
--- /dev/null
+++ b/logic/DefaultVariable.h
@@ -0,0 +1,35 @@
+#pragma once
+
+template <typename T>
+class DefaultVariable
+{
+public:
+ DefaultVariable(const T & value)
+ {
+ defaultValue = value;
+ }
+ DefaultVariable<T> & operator =(const T & value)
+ {
+ currentValue = value;
+ is_default = currentValue == defaultValue;
+ is_explicit = true;
+ return *this;
+ }
+ operator const T &() const
+ {
+ return is_default ? defaultValue : currentValue;
+ }
+ bool isDefault() const
+ {
+ return is_default;
+ }
+ bool isExplicit() const
+ {
+ return is_explicit;
+ }
+private:
+ T currentValue;
+ T defaultValue;
+ bool is_default = true;
+ bool is_explicit = false;
+};
diff --git a/logic/InstanceList.cpp b/logic/InstanceList.cpp
index 8a68c334..650f5c80 100644
--- a/logic/InstanceList.cpp
+++ b/logic/InstanceList.cpp
@@ -331,7 +331,29 @@ QSet<FTBRecord> InstanceList::discoverFTBInstances()
continue;
record.name = attrs.value("name").toString();
record.logo = attrs.value("logo").toString();
- record.mcVersion = attrs.value("mcVersion").toString();
+ auto customVersions = attrs.value("customMCVersions");
+ if(!customVersions.isNull())
+ {
+ QMap<QString, QString> versionMatcher;
+ QString customVersionsStr = customVersions.toString();
+ QStringList list = customVersionsStr.split(';');
+ for(auto item: list)
+ {
+ auto segment = item.split('^');
+ if(segment.size() != 2)
+ {
+ QLOG_ERROR() << "FTB: Segment of size < 2 in " << customVersionsStr;
+ continue;
+ }
+ versionMatcher[segment[0]] = segment[1];
+ }
+ auto actualVersion = attrs.value("version").toString();
+ record.mcVersion = versionMatcher[actualVersion];
+ }
+ else
+ {
+ record.mcVersion = attrs.value("mcVersion").toString();
+ }
record.description = attrs.value("description").toString();
records.insert(record);
}
diff --git a/logic/minecraft/GradleSpecifier.h b/logic/minecraft/GradleSpecifier.h
new file mode 100644
index 00000000..3ee40b86
--- /dev/null
+++ b/logic/minecraft/GradleSpecifier.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <QString>
+#include <QStringList>
+#include "logic/DefaultVariable.h"
+
+struct GradleSpecifier
+{
+ GradleSpecifier()
+ {
+ m_valid = false;
+ }
+ GradleSpecifier(QString value)
+ {
+ operator=(value);
+ }
+ GradleSpecifier & operator =(const QString & value)
+ {
+ /*
+ org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar
+ DEBUG 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar"
+ DEBUG 1 "org.gradle.test.classifiers"
+ DEBUG 2 "service"
+ DEBUG 3 "1.0"
+ DEBUG 4 ":jdk15"
+ DEBUG 5 "jdk15"
+ DEBUG 6 "@jar"
+ DEBUG 7 "jar"
+ */
+ QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(:([^:@]+))?" "(@([^:@]+))?");
+ m_valid = matcher.exactMatch(value);
+ auto elements = matcher.capturedTexts();
+ groupId = elements[1];
+ artifactId = elements[2];
+ version = elements[3];
+ classifier = elements[5];
+ if(!elements[7].isEmpty())
+ {
+ extension = elements[7];
+ }
+ return *this;
+ }
+ operator QString() const
+ {
+ if(!m_valid)
+ return "INVALID";
+ QString retval = groupId + ":" + artifactId + ":" + version;
+ if(!classifier.isEmpty())
+ {
+ retval += ":" + classifier;
+ }
+ if(extension.isExplicit())
+ {
+ retval += "@" + extension;
+ }
+ return retval;
+ }
+ QString toPath() const
+ {
+ if(!m_valid)
+ return "INVALID";
+ QString path = groupId;
+ path.replace('.', '/');
+ path += '/' + artifactId + '/' + version + '/' + artifactId + '-' + version;
+ if(!classifier.isEmpty())
+ {
+ path += "-" + classifier;
+ }
+ path += "." + extension;
+ return path;
+ }
+ bool valid()
+ {
+ return m_valid;
+ }
+private:
+ QString groupId;
+ QString artifactId;
+ QString version;
+ QString classifier;
+ DefaultVariable<QString> extension = DefaultVariable<QString>("jar");
+ bool m_valid = false;
+};
diff --git a/logic/minecraft/OneSixLibrary.cpp b/logic/minecraft/OneSixLibrary.cpp
index 7f69d9f8..f9a274bd 100644
--- a/logic/minecraft/OneSixLibrary.cpp
+++ b/logic/minecraft/OneSixLibrary.cpp
@@ -65,7 +65,10 @@ void OneSixLibrary::finalize()
m_decentname = parts[1];
m_decentversion = minVersion = parts[2];
m_storage_path = relative;
- m_download_url = m_base_url + relative;
+ if(m_base_url.isEmpty())
+ m_download_url = QString("https://" + URLConstants::LIBRARY_BASE) + relative;
+ else
+ m_download_url = m_base_url + relative;
if (m_rules.empty())
{
diff --git a/logic/minecraft/RawLibrary.cpp b/logic/minecraft/RawLibrary.cpp
index 7e0ebff0..3351268a 100644
--- a/logic/minecraft/RawLibrary.cpp
+++ b/logic/minecraft/RawLibrary.cpp
@@ -13,20 +13,20 @@ RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &fil
}
out->m_name = libObj.value("name").toString();
- auto readString = [libObj, filename](const QString & key, QString & variable)
+ auto readString = [libObj, filename](const QString & key, QString & variable) -> bool
{
- if (libObj.contains(key))
+ if (!libObj.contains(key))
+ return false;
+ QJsonValue val = libObj.value(key);
+
+ if (!val.isString())
{
- QJsonValue val = libObj.value(key);
- if (!val.isString())
- {
- QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
- }
- else
- {
- variable = val.toString();
- }
+ QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
+ return false;
}
+
+ variable = val.toString();
+ return true;
};
readString("url", out->m_base_url);
diff --git a/logic/minecraft/RawLibrary.h b/logic/minecraft/RawLibrary.h
index f5a28c61..583c34d2 100644
--- a/logic/minecraft/RawLibrary.h
+++ b/logic/minecraft/RawLibrary.h
@@ -28,10 +28,11 @@ public: /* methods */
public: /* data */
QString m_name;
- QString m_base_url = "https://" + URLConstants::LIBRARY_BASE;
+ QString m_base_url;
+
/// type hint - modifies how the library is treated
QString m_hint;
- /// absolute URL. takes precedence over m_download_path, if defined
+ /// DEPRECATED: absolute URL. takes precedence over m_download_path, if defined
QString m_absolute_url;
bool applyExcludes = false;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3b2b8b74..d56988e0 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -22,6 +22,7 @@ endmacro()
# Tests START #
add_unit_test(pathutils tst_pathutils.cpp)
+add_unit_test(gradlespecifier tst_gradlespecifier.cpp)
add_unit_test(userutils tst_userutils.cpp)
add_unit_test(inifile tst_inifile.cpp)
add_unit_test(UpdateChecker tst_UpdateChecker.cpp)
diff --git a/tests/tst_gradlespecifier.cpp b/tests/tst_gradlespecifier.cpp
new file mode 100644
index 00000000..69dd54f7
--- /dev/null
+++ b/tests/tst_gradlespecifier.cpp
@@ -0,0 +1,77 @@
+#include <QTest>
+#include "TestUtil.h"
+
+#include "logic/minecraft/GradleSpecifier.h"
+
+class GradleSpecifierTest : public QObject
+{
+ Q_OBJECT
+private
+slots:
+ void initTestCase()
+ {
+
+ }
+ void cleanupTestCase()
+ {
+
+ }
+
+ void test_Positive_data()
+ {
+ QTest::addColumn<QString>("through");
+
+ QTest::newRow("3 parter") << "org.gradle.test.classifiers:service:1.0";
+ QTest::newRow("classifier") << "org.gradle.test.classifiers:service:1.0:jdk15";
+ QTest::newRow("jarextension") << "org.gradle.test.classifiers:service:1.0@jar";
+ QTest::newRow("jarboth") << "org.gradle.test.classifiers:service:1.0:jdk15@jar";
+ QTest::newRow("packxz") << "org.gradle.test.classifiers:service:1.0:jdk15@jar.pack.xz";
+ }
+ void test_Positive()
+ {
+ QFETCH(QString, through);
+
+ QString converted = GradleSpecifier(through);
+
+ QCOMPARE(converted, through);
+ }
+
+ void test_Path_data()
+ {
+ QTest::addColumn<QString>("spec");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("3 parter") << "group.id:artifact:1.0" << "group/id/artifact/1.0/artifact-1.0.jar";
+ QTest::newRow("doom") << "id.software:doom:1.666:demons@wad" << "id/software/doom/1.666/doom-1.666-demons.wad";
+ }
+ void test_Path()
+ {
+ QFETCH(QString, spec);
+ QFETCH(QString, expected);
+
+ QString converted = GradleSpecifier(spec).toPath();
+
+ QCOMPARE(converted, expected);
+ }
+ void test_Negative_data()
+ {
+ QTest::addColumn<QString>("input");
+
+ QTest::newRow("too many :") << "org:gradle.test:class:::ifiers:service:1.0::";
+ QTest::newRow("nonsense") << "I like turtles";
+ QTest::newRow("empty string") << "";
+ QTest::newRow("missing version") << "herp.derp:artifact";
+ }
+ void test_Negative()
+ {
+ QFETCH(QString, input);
+
+ GradleSpecifier spec(input);
+ QVERIFY(!spec.valid());
+ QCOMPARE(spec.operator QString(), QString("INVALID"));
+ }
+};
+
+QTEST_GUILESS_MAIN_MULTIMC(GradleSpecifierTest)
+
+#include "tst_gradlespecifier.moc"