Commit 5e583dd3 authored by twanvl's avatar twanvl

Added an option to create an installer package.

parent aa9de1c3
...@@ -7,7 +7,11 @@ ...@@ -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) { ...@@ -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 { ...@@ -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;
......
...@@ -12,6 +12,7 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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 (...) {
......
...@@ -9,10 +9,8 @@ ...@@ -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
......
...@@ -56,6 +56,11 @@ String Package::name() const { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment