mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 13:37:00 -04:00
Added an option to create an installer package.
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@512 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -7,7 +7,11 @@
|
|||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include <data/installer.hpp>
|
#include <data/installer.hpp>
|
||||||
|
#include <util/io/package_manager.hpp>
|
||||||
#include <script/to_value.hpp>
|
#include <script/to_value.hpp>
|
||||||
|
#include <wx/filename.h>
|
||||||
|
|
||||||
|
DECLARE_TYPEOF_COLLECTION(String);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Installer
|
// ----------------------------------------------------------------------------- : Installer
|
||||||
|
|
||||||
@@ -17,3 +21,65 @@ IMPLEMENT_REFLECTION(Installer) {
|
|||||||
REFLECT_BASE(Packaged);
|
REFLECT_BASE(Packaged);
|
||||||
REFLECT(packages);
|
REFLECT(packages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Installing
|
||||||
|
|
||||||
|
void Installer::installFrom(const String& filename, bool message_on_success) {
|
||||||
|
Installer i;
|
||||||
|
i.open(filename);
|
||||||
|
i.install();
|
||||||
|
if (message_on_success) {
|
||||||
|
wxMessageBox(String::Format(_("'%s' successfully installed %d package%s."), i.name(), i.packages.size(), i.packages.size() == 1 ? _("") : _("s")),
|
||||||
|
_("Magic Set Editor"), wxOK | wxICON_INFORMATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Installer::install() {
|
||||||
|
// Walk over all files in this installer
|
||||||
|
const FileInfos& file_infos = getFileInfos();
|
||||||
|
for (FileInfos::const_iterator it = file_infos.begin() ; it != file_infos.end() ; ++it) {
|
||||||
|
// const String& filename = it->first;
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// REMOVE?
|
||||||
|
FOR_EACH(p, packages) {
|
||||||
|
install(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Installer::install(const String& package) {
|
||||||
|
// 1. Make sure the package is not loaded
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Creating
|
||||||
|
|
||||||
|
void Installer::addPackage(const String& package) {
|
||||||
|
wxFileName fn(package);
|
||||||
|
if (fn.GetExt() == _(".mse-installer")) {
|
||||||
|
prefered_filename = package;
|
||||||
|
} else {
|
||||||
|
PackagedP p = ::packages.openAny(package);
|
||||||
|
addPackage(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Installer::addPackage(Packaged& package) {
|
||||||
|
// Add to list of packages
|
||||||
|
String name = package.relativeFilename();
|
||||||
|
if (find(packages.begin(), packages.end(), package.name()) != packages.end()) {
|
||||||
|
return; // already added
|
||||||
|
}
|
||||||
|
if (prefered_filename.empty()) {
|
||||||
|
prefered_filename = package.name() + _(".mse-installer");
|
||||||
|
}
|
||||||
|
packages.push_back(name);
|
||||||
|
// Copy all files from that package to this one
|
||||||
|
const FileInfos& file_infos = package.getFileInfos();
|
||||||
|
for (FileInfos::const_iterator it = file_infos.begin() ; it != file_infos.end() ; ++it) {
|
||||||
|
String file = it->first;
|
||||||
|
InputStreamP is = package.openIn(file);
|
||||||
|
OutputStreamP os = openOut(name + _("/") + file);
|
||||||
|
os->Write(*is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,13 +20,20 @@ class Installer : public Packaged {
|
|||||||
String prefered_filename; ///< What filename should be used (by default)
|
String prefered_filename; ///< What filename should be used (by default)
|
||||||
vector<String> packages; ///< Packages to install
|
vector<String> packages; ///< Packages to install
|
||||||
|
|
||||||
|
/// Load an installer from a file, and run it
|
||||||
|
static void installFrom(const String& filename, bool message_on_success);
|
||||||
/// Install all the packages
|
/// Install all the packages
|
||||||
void install();
|
void install();
|
||||||
|
/// Install a specific package
|
||||||
|
void install(const String& package);
|
||||||
|
|
||||||
|
/// Add a package to the installer (if it is not already added).
|
||||||
|
/** If the package is named *.mse-installer uses it as the filename instead */
|
||||||
|
void addPackage(const String& package);
|
||||||
/// Add a package to the installer (if it is not already added).
|
/// Add a package to the installer (if it is not already added).
|
||||||
/** The first package gives the name of the installer.
|
/** The first package gives the name of the installer.
|
||||||
*/
|
*/
|
||||||
void addPackage(const Packaged& package);
|
void addPackage(Packaged& package);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
String typeName() const;
|
String typeName() const;
|
||||||
|
|||||||
+61
-4
@@ -12,6 +12,7 @@
|
|||||||
#include <data/set.hpp>
|
#include <data/set.hpp>
|
||||||
#include <data/settings.hpp>
|
#include <data/settings.hpp>
|
||||||
#include <data/locale.hpp>
|
#include <data/locale.hpp>
|
||||||
|
#include <data/installer.hpp>
|
||||||
#include <data/format/formats.hpp>
|
#include <data/format/formats.hpp>
|
||||||
#include <gui/welcome_window.hpp>
|
#include <gui/welcome_window.hpp>
|
||||||
#include <gui/update_checker.hpp>
|
#include <gui/update_checker.hpp>
|
||||||
@@ -19,6 +20,8 @@
|
|||||||
#include <gui/symbol/window.hpp>
|
#include <gui/symbol/window.hpp>
|
||||||
#include <gui/thumbnail_thread.hpp>
|
#include <gui/thumbnail_thread.hpp>
|
||||||
#include <wx/fs_inet.h>
|
#include <wx/fs_inet.h>
|
||||||
|
#include <wx/wfstream.h>
|
||||||
|
#include <wx/txtstrm.h>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Main function/class
|
// ----------------------------------------------------------------------------- : Main function/class
|
||||||
|
|
||||||
@@ -37,6 +40,24 @@ class MSE : public wxApp {
|
|||||||
|
|
||||||
IMPLEMENT_APP(MSE)
|
IMPLEMENT_APP(MSE)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : GUI/Console
|
||||||
|
|
||||||
|
/// Write a message to the console if it is available, and to a message box otherwise
|
||||||
|
void write_stdout(const String& str) {
|
||||||
|
bool have_console = false;
|
||||||
|
#ifndef __WXMSW__
|
||||||
|
// somehow detect whether to use console output
|
||||||
|
#endif
|
||||||
|
if (have_console) {
|
||||||
|
wxFileOutputStream file(wxFile::fd_stdout);
|
||||||
|
wxTextOutputStream t(file);
|
||||||
|
t.WriteString(str);
|
||||||
|
} else {
|
||||||
|
// no console, use a message box
|
||||||
|
wxMessageBox(str, _("Magic Set Editor"), wxOK | wxICON_INFORMATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Initialization
|
// ----------------------------------------------------------------------------- : Initialization
|
||||||
|
|
||||||
bool MSE::OnInit() {
|
bool MSE::OnInit() {
|
||||||
@@ -59,6 +80,7 @@ bool MSE::OnInit() {
|
|||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
try {
|
try {
|
||||||
// Command line argument, find its extension
|
// Command line argument, find its extension
|
||||||
|
String arg = argv[1];
|
||||||
wxFileName f(argv[1]);
|
wxFileName f(argv[1]);
|
||||||
if (f.GetExt() == _("mse-symbol")) {
|
if (f.GetExt() == _("mse-symbol")) {
|
||||||
// Show the symbol editor
|
// Show the symbol editor
|
||||||
@@ -70,6 +92,41 @@ bool MSE::OnInit() {
|
|||||||
Window* wnd = new SetWindow(nullptr, import_set(argv[1]));
|
Window* wnd = new SetWindow(nullptr, import_set(argv[1]));
|
||||||
wnd->Show();
|
wnd->Show();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (f.GetExt() == _("mse-installer")) {
|
||||||
|
// Installer; install it
|
||||||
|
Installer::installFrom(argv[1], true);
|
||||||
|
return false;
|
||||||
|
} else if (arg == _("--create-installer")) {
|
||||||
|
// create an installer
|
||||||
|
Installer inst;
|
||||||
|
for (int i = 2 ; i < argc ; ++i) {
|
||||||
|
inst.addPackage(argv[i]);
|
||||||
|
}
|
||||||
|
if (inst.prefered_filename.empty()) {
|
||||||
|
throw Error(_("Specify packages to include in installer"));
|
||||||
|
} else {
|
||||||
|
inst.saveAs(inst.prefered_filename, false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (arg == _("--help") || arg == _("-?")) {
|
||||||
|
// command line help
|
||||||
|
write_stdout( String(_("Magic Set Editor\n\n"))
|
||||||
|
+ _("Usage: ") + argv[0] + _("[OPTIONS]\n\n")
|
||||||
|
+ _(" no options \tStart the MSE user interface showing the welcome window.\n")
|
||||||
|
+ _(" FILE.mse-set,\n")
|
||||||
|
+ _(" FILE.set,\n")
|
||||||
|
+ _(" FILE.mse \tLoad the set file in the MSE user interface.\n")
|
||||||
|
+ _(" FILE.mse-symbol \tLoad the symbol into the MSE symbol editor.\n")
|
||||||
|
+ _(" FILE.mse-installer\tInstall the packages from the installer.\n")
|
||||||
|
+ _(" -? --help \tShows this help screen.\n")
|
||||||
|
+ _(" -v --version \tShow version information.\n")
|
||||||
|
+ _(" --create-installer\n")
|
||||||
|
+ _(" FILE [FILE]...\tCreate an instaler named FILE, containing the listed packges.\n") );
|
||||||
|
return false;
|
||||||
|
} else if (arg == _("--version") || arg == _("-v")) {
|
||||||
|
// dump version
|
||||||
|
write_stdout( _("Magic Set Editor\nVersion ") + app_version.toString() + version_suffix );
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
handle_error(_("Invalid command line argument:\n") + String(argv[1]));
|
handle_error(_("Invalid command line argument:\n") + String(argv[1]));
|
||||||
}
|
}
|
||||||
@@ -82,9 +139,9 @@ bool MSE::OnInit() {
|
|||||||
(new WelcomeWindow())->Show();
|
(new WelcomeWindow())->Show();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (Error e) {
|
} catch (const Error& e) {
|
||||||
handle_error(e, false);
|
handle_error(e, false);
|
||||||
} catch (std::exception e) {
|
} catch (const std::exception& e) {
|
||||||
// we don't throw std::exception ourselfs, so this is probably something serious
|
// we don't throw std::exception ourselfs, so this is probably something serious
|
||||||
handle_error(InternalError(String(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) )), false);
|
handle_error(InternalError(String(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) )), false);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@@ -108,9 +165,9 @@ int MSE::OnExit() {
|
|||||||
bool MSE::OnExceptionInMainLoop() {
|
bool MSE::OnExceptionInMainLoop() {
|
||||||
try {
|
try {
|
||||||
throw; // rethrow the exception, so we can examine it
|
throw; // rethrow the exception, so we can examine it
|
||||||
} catch (Error e) {
|
} catch (const Error& e) {
|
||||||
handle_error(e, false);
|
handle_error(e, false);
|
||||||
} catch (std::exception e) {
|
} catch (const std::exception& e) {
|
||||||
// we don't throw std::exception ourselfs, so this is probably something serious
|
// we don't throw std::exception ourselfs, so this is probably something serious
|
||||||
handle_error(InternalError(String(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) )), false);
|
handle_error(InternalError(String(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) )), false);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -9,10 +9,8 @@
|
|||||||
// -------------------------------------------------------- : Icons
|
// -------------------------------------------------------- : Icons
|
||||||
|
|
||||||
icon/app ICON "icon/app.ico" // has to come first in alphabet!!
|
icon/app ICON "icon/app.ico" // has to come first in alphabet!!
|
||||||
icon/export ICON "icon/set.ico" //todo
|
icon/installer ICON "icon/installer.ico"
|
||||||
icon/game ICON "icon/set.ico" //todo
|
|
||||||
icon/set ICON "icon/set.ico"
|
icon/set ICON "icon/set.ico"
|
||||||
icon/style ICON "icon/set.ico" //todo
|
|
||||||
icon/symbol ICON "icon/symbol.ico"
|
icon/symbol ICON "icon/symbol.ico"
|
||||||
|
|
||||||
// -------------------------------------------------------- : Toolbar
|
// -------------------------------------------------------- : Toolbar
|
||||||
|
|||||||
+20
-12
@@ -56,6 +56,11 @@ String Package::name() const {
|
|||||||
else if ( ext == String::npos) return filename.substr(slash+1);
|
else if ( ext == String::npos) return filename.substr(slash+1);
|
||||||
else return filename.substr(slash+1, ext-slash-1);
|
else return filename.substr(slash+1, ext-slash-1);
|
||||||
}
|
}
|
||||||
|
String Package::relativeFilename() const {
|
||||||
|
size_t slash = filename.find_last_of(_("/\\:"));
|
||||||
|
if (slash == String::npos) return filename;
|
||||||
|
else return filename.substr(slash+1);
|
||||||
|
}
|
||||||
const String& Package::absoluteFilename() const {
|
const String& Package::absoluteFilename() const {
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
@@ -81,17 +86,17 @@ void Package::open(const String& n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::save(bool removeUnused) {
|
void Package::save(bool remove_unused) {
|
||||||
assert(!needSaveAs());
|
assert(!needSaveAs());
|
||||||
saveAs(filename, removeUnused);
|
saveAs(filename, remove_unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::saveAs(const String& name, bool removeUnused) {
|
void Package::saveAs(const String& name, bool remove_unused) {
|
||||||
// type of package
|
// type of package
|
||||||
if (wxDirExists(name)) {
|
if (wxDirExists(name)) {
|
||||||
saveToDirectory(name, removeUnused);
|
saveToDirectory(name, remove_unused);
|
||||||
} else {
|
} else {
|
||||||
saveToZipfile (name, removeUnused);
|
saveToZipfile (name, remove_unused);
|
||||||
}
|
}
|
||||||
filename = name;
|
filename = name;
|
||||||
// cleanup : remove temp files, remove deleted files from the list
|
// cleanup : remove temp files, remove deleted files from the list
|
||||||
@@ -101,7 +106,7 @@ void Package::saveAs(const String& name, bool removeUnused) {
|
|||||||
// remove corresponding temp file
|
// remove corresponding temp file
|
||||||
wxRemoveFile(it->second.tempName);
|
wxRemoveFile(it->second.tempName);
|
||||||
}
|
}
|
||||||
if (!it->second.keep && removeUnused) {
|
if (!it->second.keep && remove_unused) {
|
||||||
// also remove the record of deleted files
|
// also remove the record of deleted files
|
||||||
FileInfos::iterator toRemove = it;
|
FileInfos::iterator toRemove = it;
|
||||||
++it;
|
++it;
|
||||||
@@ -294,6 +299,9 @@ void Package::openSubdir(const String& name) {
|
|||||||
}
|
}
|
||||||
// find subdirs
|
// find subdirs
|
||||||
for(bool ok = d.GetFirst(&f, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN) ; ok ; ok = d.GetNext(&f)) {
|
for(bool ok = d.GetFirst(&f, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN) ; ok ; ok = d.GetNext(&f)) {
|
||||||
|
if (f.empty() || f.GetChar(0) == _('.')) {
|
||||||
|
return; // skip directories starting with '.', like ., .. and .svn
|
||||||
|
}
|
||||||
openSubdir(name+f+_("/"));
|
openSubdir(name+f+_("/"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,10 +326,10 @@ void Package::openZipfile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Package::saveToDirectory(const String& saveAs, bool removeUnused) {
|
void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
|
||||||
// write to a directory
|
// write to a directory
|
||||||
FOR_EACH(f, files) {
|
FOR_EACH(f, files) {
|
||||||
if (!f.second.keep && removeUnused) {
|
if (!f.second.keep && remove_unused) {
|
||||||
// remove files that are not to be kept
|
// remove files that are not to be kept
|
||||||
// ignore failure (new file that is not kept)
|
// ignore failure (new file that is not kept)
|
||||||
wxRemoveFile(saveAs+_("/")+f.first);
|
wxRemoveFile(saveAs+_("/")+f.first);
|
||||||
@@ -342,7 +350,7 @@ void Package::saveToDirectory(const String& saveAs, bool removeUnused) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::saveToZipfile(const String& saveAs, bool removeUnused) {
|
void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
|
||||||
// create a temporary zip file name
|
// create a temporary zip file name
|
||||||
String tempFile = saveAs + _(".tmp");
|
String tempFile = saveAs + _(".tmp");
|
||||||
wxRemoveFile(tempFile);
|
wxRemoveFile(tempFile);
|
||||||
@@ -355,7 +363,7 @@ void Package::saveToZipfile(const String& saveAs, bool removeUnused) {
|
|||||||
// copy everything to a new zip file, unless it's updated or removed
|
// copy everything to a new zip file, unless it's updated or removed
|
||||||
if (zipStream) newZip->CopyArchiveMetaData(*zipStream);
|
if (zipStream) newZip->CopyArchiveMetaData(*zipStream);
|
||||||
FOR_EACH(f, files) {
|
FOR_EACH(f, files) {
|
||||||
if (!f.second.keep && removeUnused) {
|
if (!f.second.keep && remove_unused) {
|
||||||
// to remove a file simply don't copy it
|
// to remove a file simply don't copy it
|
||||||
} else if (f.second.zipEntry && !f.second.wasWritten()) {
|
} else if (f.second.zipEntry && !f.second.wasWritten()) {
|
||||||
// old file, was also in zip, not changed
|
// old file, was also in zip, not changed
|
||||||
@@ -474,11 +482,11 @@ void Packaged::save() {
|
|||||||
referenceFile(typeName());
|
referenceFile(typeName());
|
||||||
Package::save();
|
Package::save();
|
||||||
}
|
}
|
||||||
void Packaged::saveAs(const String& package) {
|
void Packaged::saveAs(const String& package, bool remove_unused) {
|
||||||
WITH_DYNAMIC_ARG(writing_package, this);
|
WITH_DYNAMIC_ARG(writing_package, this);
|
||||||
writeFile(typeName(), *this);
|
writeFile(typeName(), *this);
|
||||||
referenceFile(typeName());
|
referenceFile(typeName());
|
||||||
Package::saveAs(package);
|
Package::saveAs(package, remove_unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packaged::validate(Version) {
|
void Packaged::validate(Version) {
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ class Package : public IntrusivePtrVirtualBase {
|
|||||||
bool needSaveAs() const;
|
bool needSaveAs() const;
|
||||||
/// Determines the short name of this package: the filename without path or extension
|
/// Determines the short name of this package: the filename without path or extension
|
||||||
String name() const;
|
String name() const;
|
||||||
|
/// Return the relative filename of this file, the name and extension
|
||||||
|
String relativeFilename() const;
|
||||||
/// Return the absolute filename of this file
|
/// Return the absolute filename of this file
|
||||||
const String& absoluteFilename() const;
|
const String& absoluteFilename() const;
|
||||||
/// The time this package was last modified
|
/// The time this package was last modified
|
||||||
@@ -71,14 +73,14 @@ class Package : public IntrusivePtrVirtualBase {
|
|||||||
|
|
||||||
/// Saves the package, by default saves as a zip file, unless
|
/// Saves the package, by default saves as a zip file, unless
|
||||||
/// it was already a directory
|
/// it was already a directory
|
||||||
/** If removeUnused=true all files that were in the file and
|
/** If remove_unused=true all files that were in the file and
|
||||||
* are not touched with referenceFile will be deleted from the new archive!
|
* are not touched with referenceFile will be deleted from the new archive!
|
||||||
* This is a form of garbage collection, to get rid of old picture files for example.
|
* This is a form of garbage collection, to get rid of old picture files for example.
|
||||||
*/
|
*/
|
||||||
void save(bool removeUnused = true);
|
void save(bool remove_unused = true);
|
||||||
|
|
||||||
/// Saves the package under a different filename
|
/// Saves the package under a different filename
|
||||||
void saveAs(const String& package, bool removeUnused = true);
|
void saveAs(const String& package, bool remove_unused = true);
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------- : Managing the inside of the package
|
// --------------------------------------------------- : Managing the inside of the package
|
||||||
@@ -157,6 +159,7 @@ class Package : public IntrusivePtrVirtualBase {
|
|||||||
/// Information on files in the package
|
/// Information on files in the package
|
||||||
/** Note: must be public for DECLARE_TYPEOF to work */
|
/** Note: must be public for DECLARE_TYPEOF to work */
|
||||||
typedef map<String, FileInfo> FileInfos;
|
typedef map<String, FileInfo> FileInfos;
|
||||||
|
inline const FileInfos& getFileInfos() const { return files; }
|
||||||
private:
|
private:
|
||||||
/// All files in the package
|
/// All files in the package
|
||||||
FileInfos files;
|
FileInfos files;
|
||||||
@@ -210,7 +213,7 @@ class Packaged : public Package {
|
|||||||
/// Ensure the package is fully loaded.
|
/// Ensure the package is fully loaded.
|
||||||
void loadFully();
|
void loadFully();
|
||||||
void save();
|
void save();
|
||||||
void saveAs(const String& package);
|
void saveAs(const String& package, bool remove_unused = true);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// filename of the data file, and extension of the package file
|
/// filename of the data file, and extension of the package file
|
||||||
|
|||||||
Reference in New Issue
Block a user