Index: source/main.cpp
===================================================================
--- source/main.cpp (revision 19029)
+++ source/main.cpp (working copy)
@@ -49,6 +49,7 @@
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Loader.h"
+#include "ps/ModInstaller.h"
#include "ps/Profile.h"
#include "ps/Profiler2.h"
#include "ps/Pyrogenesis.h"
@@ -443,7 +444,24 @@
return;
}
}
+
+ const bool isModInstallation = args.Has("install-mod");
+ const CStr modPath = isModInstallation ? args.Get("install-mod") : "";
+ if (isModInstallation)
+ {
+ if (!FileExists(OsPath(modPath)))
+ {
+ debug_printf("ERROR: The mod file '%s' does not exist!\n", modPath.c_str());
+ return;
+ }
+ if (DirectoryExists(OsPath(modPath)))
+ {
+ debug_printf("ERROR: The mod file '%s' is a directory!\n", modPath.c_str());
+ return;
+ }
+ }
+
// We need to initialize SpiderMonkey and libxml2 in the main thread before
// any thread uses them. So initialize them here before we might run Atlas.
ScriptEngine scriptEngine;
@@ -483,7 +501,20 @@
CXeromyces::Terminate();
return;
}
+
+ if (isModInstallation)
+ {
+ Paths paths(args);
+
+ CModInstaller installer(paths.UserData() / "mods", paths.Cache());
+ // Creates a directory with the name extracted from a `mod.json`
+ installer.Install(modPath);
+
+ CXeromyces::Terminate();
+ return;
+ }
+
// run in archive-building mode if requested
if (args.Has("archivebuild"))
{
Index: source/ps/ModInstaller.cpp
===================================================================
--- source/ps/ModInstaller.cpp (revision 0)
+++ source/ps/ModInstaller.cpp (working copy)
@@ -0,0 +1,88 @@
+/* Copyright (C) 2016 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "ModInstaller.h"
+
+#include "lib/file/vfs/vfs_util.h"
+#include "lib/sysdep/sysdep.h"
+#include "ps/Filesystem.h"
+#include "ps/XML/Xeromyces.h"
+
+#include
+
+CModInstaller::CModInstaller(const OsPath& modsdir, const OsPath& tempdir) :
+ m_ModsDir(modsdir), m_TempDir(tempdir / "_modscache"), m_CacheDir("cache/")
+{
+ m_VFS = CreateVfs(20 * MiB);
+
+ CreateDirectories(m_TempDir, 0700);
+
+ const int runtimeSize = 64 * MiB;
+ const int heapGrowthBytesGCTrigger = 16 * MiB;
+ m_ScriptRuntime = ScriptInterface::CreateRuntime(std::shared_ptr(), runtimeSize, heapGrowthBytesGCTrigger);
+}
+
+CModInstaller::~CModInstaller()
+{
+ m_VFS.reset();
+
+ m_ScriptRuntime.reset();
+
+ DeleteDirectory(m_TempDir);
+}
+
+void CModInstaller::Install(const OsPath& mod)
+{
+ const OsPath modTemp = m_TempDir / mod.Filename().ChangeExtension(L".zip");
+ // TODO: move the file, not copy
+ boost::filesystem::copy_file(
+ mod.string8(),
+ modTemp.string8(),
+ boost::filesystem::copy_option::overwrite_if_exists
+ );
+
+ m_VFS->Mount(m_CacheDir, m_TempDir / "");
+ CVFSFile modinfo;
+ if (modinfo.Load(m_VFS, m_CacheDir / "mod.json", false) != PSRETURN_OK)
+ return;
+ m_VFS->Clear();
+
+ ScriptInterface scriptInterface("Engine", "ModInstaller", m_ScriptRuntime);
+ JSContext* cx = scriptInterface.GetContext();
+ JS::RootedValue json_val(cx);
+ if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val))
+ return;
+ JS::RootedObject json_obj(cx, json_val.toObjectOrNull());
+ JS::RootedValue name_val(cx);
+ JS_GetProperty(cx, json_obj, "name", &name_val);
+ std::string modName;
+ ScriptInterface::FromJSVal(cx, name_val, modName);
+
+ const OsPath modDir = m_ModsDir / modName;
+ const OsPath modPath = modDir / (modName + ".zip");
+
+ DeleteDirectory(modDir);
+ CreateDirectories(modDir, 0700);
+
+ boost::filesystem::rename(modTemp.string8(), modPath.string8());
+
+#ifdef OS_WIN
+ // TODO: copy mod.json to the path
+#endif
+}
Index: source/ps/ModInstaller.h
===================================================================
--- source/ps/ModInstaller.h (revision 0)
+++ source/ps/ModInstaller.h (working copy)
@@ -0,0 +1,56 @@
+/* Copyright (C) 2016 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_MODINSTALLER
+#define INCLUDED_MODINSTALLER
+
+#include "lib/file/vfs/vfs.h"
+#include "scriptinterface/ScriptInterface.h"
+
+/**
+ * Install a mod into the mods directory.
+ */
+class CModInstaller
+{
+public:
+ /**
+ * Initialise the mod installer for processing the given mod.
+ *
+ * @param modsdir path to the data directory, containing mods
+ * @param tempdir path to a writable directory for temporary files
+ */
+ CModInstaller(const OsPath& modsdir, const OsPath& tempdir);
+
+ ~CModInstaller();
+
+ /**
+ * Do all the processing and unpacking.
+ * @param mod path of .pyromod file of mod
+ */
+ void Install(const OsPath& mod);
+
+private:
+
+ PIVFS m_VFS;
+ OsPath m_ModsDir;
+ OsPath m_TempDir;
+ VfsPath m_CacheDir;
+
+ std::shared_ptr m_ScriptRuntime;
+};
+
+#endif // INCLUDED_MODINSTALLER