324 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "MMCJson.h"
 | 
						|
using namespace MMCJson;
 | 
						|
 | 
						|
#include "RawLibrary.h"
 | 
						|
#include <pathutils.h>
 | 
						|
 | 
						|
RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &filename)
 | 
						|
{
 | 
						|
	RawLibraryPtr out(new RawLibrary());
 | 
						|
	if (!libObj.contains("name"))
 | 
						|
	{
 | 
						|
		throw JSONValidationError(filename +
 | 
						|
								  "contains a library that doesn't have a 'name' field");
 | 
						|
	}
 | 
						|
	out->m_name = libObj.value("name").toString();
 | 
						|
 | 
						|
	auto readString = [libObj, filename](const QString & key, QString & variable) -> bool
 | 
						|
	{
 | 
						|
		if (!libObj.contains(key))
 | 
						|
			return false;
 | 
						|
		QJsonValue val = libObj.value(key);
 | 
						|
 | 
						|
		if (!val.isString())
 | 
						|
		{
 | 
						|
			qWarning() << key << "is not a string in" << filename << "(skipping)";
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		variable = val.toString();
 | 
						|
		return true;
 | 
						|
	};
 | 
						|
 | 
						|
	QString urlStr;
 | 
						|
	readString("url", urlStr);
 | 
						|
	out->m_base_url = urlStr;
 | 
						|
	readString("MMC-hint", out->m_hint);
 | 
						|
	readString("MMC-absulute_url", out->m_absolute_url);
 | 
						|
	readString("MMC-absoluteUrl", out->m_absolute_url);
 | 
						|
	if (libObj.contains("extract"))
 | 
						|
	{
 | 
						|
		out->applyExcludes = true;
 | 
						|
		auto extractObj = ensureObject(libObj.value("extract"));
 | 
						|
		for (auto excludeVal : ensureArray(extractObj.value("exclude")))
 | 
						|
		{
 | 
						|
			out->extract_excludes.append(ensureString(excludeVal));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (libObj.contains("natives"))
 | 
						|
	{
 | 
						|
		QJsonObject nativesObj = ensureObject(libObj.value("natives"));
 | 
						|
		for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
 | 
						|
		{
 | 
						|
			if (!it.value().isString())
 | 
						|
			{
 | 
						|
				qWarning() << filename << "contains an invalid native (skipping)";
 | 
						|
			}
 | 
						|
			OpSys opSys = OpSys_fromString(it.key());
 | 
						|
			if (opSys != Os_Other)
 | 
						|
			{
 | 
						|
				out->m_native_classifiers[opSys] = it.value().toString();
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (libObj.contains("rules"))
 | 
						|
	{
 | 
						|
		out->applyRules = true;
 | 
						|
		out->m_rules = rulesFromJsonV4(libObj);
 | 
						|
	}
 | 
						|
	return out;
 | 
						|
}
 | 
						|
 | 
						|
RawLibraryPtr RawLibrary::fromJsonPlus(const QJsonObject &libObj, const QString &filename)
 | 
						|
{
 | 
						|
	auto lib = RawLibrary::fromJson(libObj, filename);
 | 
						|
	if (libObj.contains("insert"))
 | 
						|
	{
 | 
						|
		QJsonValue insertVal = ensureExists(libObj.value("insert"), "library insert rule");
 | 
						|
		if (insertVal.isString())
 | 
						|
		{
 | 
						|
			// it's just a simple string rule. OK.
 | 
						|
			QString insertString = insertVal.toString();
 | 
						|
			if (insertString == "apply")
 | 
						|
			{
 | 
						|
				lib->insertType = RawLibrary::Apply;
 | 
						|
			}
 | 
						|
			else if (insertString == "prepend")
 | 
						|
			{
 | 
						|
				lib->insertType = RawLibrary::Prepend;
 | 
						|
			}
 | 
						|
			else if (insertString == "append")
 | 
						|
			{
 | 
						|
				lib->insertType = RawLibrary::Append;
 | 
						|
			}
 | 
						|
			else if (insertString == "replace")
 | 
						|
			{
 | 
						|
				lib->insertType = RawLibrary::Replace;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				throw JSONValidationError("A '+' library in " + filename +
 | 
						|
										" contains an invalid insert type");
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (insertVal.isObject())
 | 
						|
		{
 | 
						|
			// it's a more complex rule, specifying what should be:
 | 
						|
			//   * replaced (for now only this)
 | 
						|
			// this was never used, AFAIK. tread carefully.
 | 
						|
			QJsonObject insertObj = insertVal.toObject();
 | 
						|
			if (insertObj.isEmpty())
 | 
						|
			{
 | 
						|
				throw JSONValidationError("Empty compound insert rule in " + filename);
 | 
						|
			}
 | 
						|
			QString insertString = insertObj.keys().first();
 | 
						|
			// really, only replace makes sense in combination with
 | 
						|
			if(insertString != "replace")
 | 
						|
			{
 | 
						|
				throw JSONValidationError("Compound insert rule is not 'replace' in " + filename);
 | 
						|
			}
 | 
						|
			lib->insertData = insertObj.value(insertString).toString();
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			throw JSONValidationError("A '+' library in " + filename +
 | 
						|
						" contains an unknown/invalid insert rule");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (libObj.contains("MMC-depend"))
 | 
						|
	{
 | 
						|
		const QString dependString = ensureString(libObj.value("MMC-depend"));
 | 
						|
		if (dependString == "hard")
 | 
						|
		{
 | 
						|
			lib->dependType = RawLibrary::Hard;
 | 
						|
		}
 | 
						|
		else if (dependString == "soft")
 | 
						|
		{
 | 
						|
			lib->dependType = RawLibrary::Soft;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			throw JSONValidationError("A '+' library in " + filename +
 | 
						|
									  " contains an invalid depend type");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return lib;
 | 
						|
}
 | 
						|
 | 
						|
QJsonObject RawLibrary::toJson() const
 | 
						|
{
 | 
						|
	QJsonObject libRoot;
 | 
						|
	libRoot.insert("name", (QString)m_name);
 | 
						|
	if (m_absolute_url.size())
 | 
						|
		libRoot.insert("MMC-absoluteUrl", m_absolute_url);
 | 
						|
	if (m_hint.size())
 | 
						|
		libRoot.insert("MMC-hint", m_hint);
 | 
						|
	if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
 | 
						|
		m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
 | 
						|
		m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
 | 
						|
	{
 | 
						|
		libRoot.insert("url", m_base_url);
 | 
						|
	}
 | 
						|
	if (isNative())
 | 
						|
	{
 | 
						|
		QJsonObject nativeList;
 | 
						|
		auto iter = m_native_classifiers.begin();
 | 
						|
		while (iter != m_native_classifiers.end())
 | 
						|
		{
 | 
						|
			nativeList.insert(OpSys_toString(iter.key()), iter.value());
 | 
						|
			iter++;
 | 
						|
		}
 | 
						|
		libRoot.insert("natives", nativeList);
 | 
						|
		if (extract_excludes.size())
 | 
						|
		{
 | 
						|
			QJsonArray excludes;
 | 
						|
			QJsonObject extract;
 | 
						|
			for (auto exclude : extract_excludes)
 | 
						|
			{
 | 
						|
				excludes.append(exclude);
 | 
						|
			}
 | 
						|
			extract.insert("exclude", excludes);
 | 
						|
			libRoot.insert("extract", extract);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (m_rules.size())
 | 
						|
	{
 | 
						|
		QJsonArray allRules;
 | 
						|
		for (auto &rule : m_rules)
 | 
						|
		{
 | 
						|
			QJsonObject ruleObj = rule->toJson();
 | 
						|
			allRules.append(ruleObj);
 | 
						|
		}
 | 
						|
		libRoot.insert("rules", allRules);
 | 
						|
	}
 | 
						|
	return libRoot;
 | 
						|
}
 | 
						|
 | 
						|
QStringList RawLibrary::files() const
 | 
						|
{
 | 
						|
	QStringList retval;
 | 
						|
	QString storage = storageSuffix();
 | 
						|
	if (storage.contains("${arch}"))
 | 
						|
	{
 | 
						|
		QString cooked_storage = storage;
 | 
						|
		cooked_storage.replace("${arch}", "32");
 | 
						|
		retval.append(cooked_storage);
 | 
						|
		cooked_storage = storage;
 | 
						|
		cooked_storage.replace("${arch}", "64");
 | 
						|
		retval.append(cooked_storage);
 | 
						|
	}
 | 
						|
	else
 | 
						|
		retval.append(storage);
 | 
						|
	return retval;
 | 
						|
}
 | 
						|
 | 
						|
bool RawLibrary::filesExist(const QDir &base) const
 | 
						|
{
 | 
						|
	auto libFiles = files();
 | 
						|
	for(auto file: libFiles)
 | 
						|
	{
 | 
						|
		QFileInfo info(base, file);
 | 
						|
		qWarning() << info.absoluteFilePath() << "doesn't exist";
 | 
						|
		if (!info.exists())
 | 
						|
			return false;
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
QString RawLibrary::url() const
 | 
						|
{
 | 
						|
	if (!m_absolute_url.isEmpty())
 | 
						|
	{
 | 
						|
		return m_absolute_url;
 | 
						|
	}
 | 
						|
 | 
						|
	if (m_base_url.isEmpty())
 | 
						|
	{
 | 
						|
		return QString("https://" + URLConstants::LIBRARY_BASE) + storageSuffix();
 | 
						|
	}
 | 
						|
 | 
						|
	if(m_base_url.endsWith('/'))
 | 
						|
	{
 | 
						|
		return m_base_url + storageSuffix();
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		return m_base_url + QChar('/') + storageSuffix();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool RawLibrary::isActive() const
 | 
						|
{
 | 
						|
	bool result = true;
 | 
						|
	if (m_rules.empty())
 | 
						|
	{
 | 
						|
		result = true;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		RuleAction ruleResult = Disallow;
 | 
						|
		for (auto rule : m_rules)
 | 
						|
		{
 | 
						|
			RuleAction temp = rule->apply(this);
 | 
						|
			if (temp != Defer)
 | 
						|
				ruleResult = temp;
 | 
						|
		}
 | 
						|
		result = result && (ruleResult == Allow);
 | 
						|
	}
 | 
						|
	if (isNative())
 | 
						|
	{
 | 
						|
		result = result && m_native_classifiers.contains(currentSystem);
 | 
						|
	}
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
void RawLibrary::setStoragePrefix(QString prefix)
 | 
						|
{
 | 
						|
	m_storagePrefix = prefix;
 | 
						|
}
 | 
						|
 | 
						|
QString RawLibrary::defaultStoragePrefix()
 | 
						|
{
 | 
						|
	return "libraries/";
 | 
						|
}
 | 
						|
 | 
						|
QString RawLibrary::storagePrefix() const
 | 
						|
{
 | 
						|
	if(m_storagePrefix.isEmpty())
 | 
						|
	{
 | 
						|
		return defaultStoragePrefix();
 | 
						|
	}
 | 
						|
	return m_storagePrefix;
 | 
						|
}
 | 
						|
 | 
						|
QString RawLibrary::storageSuffix() const
 | 
						|
{
 | 
						|
	// non-native? use only the gradle specifier
 | 
						|
	if (!isNative())
 | 
						|
	{
 | 
						|
		return m_name.toPath();
 | 
						|
	}
 | 
						|
 | 
						|
	// otherwise native, override classifiers. Mojang HACK!
 | 
						|
	GradleSpecifier nativeSpec = m_name;
 | 
						|
	if (m_native_classifiers.contains(currentSystem))
 | 
						|
	{
 | 
						|
		nativeSpec.setClassifier(m_native_classifiers[currentSystem]);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		nativeSpec.setClassifier("INVALID");
 | 
						|
	}
 | 
						|
	return nativeSpec.toPath();
 | 
						|
}
 | 
						|
 | 
						|
QString RawLibrary::storagePath() const
 | 
						|
{
 | 
						|
	return PathCombine(storagePrefix(), storageSuffix());
 | 
						|
}
 | 
						|
 | 
						|
bool RawLibrary::storagePathIsDefault() const
 | 
						|
{
 | 
						|
	return m_storagePrefix.isEmpty();
 | 
						|
}
 |