Commit 3babaadb authored by twanvl's avatar twanvl

Fixed/hacked 'no parameter' for 0.2.7 keyword compatability;

Added 'just_header' flag to make stylesheet list load faster;
Added versioning and dependency support to packages
parent 54ebec06
...@@ -60,6 +60,9 @@ void read_compat(Reader& tag, Keyword* k) { ...@@ -60,6 +60,9 @@ void read_compat(Reader& tag, Keyword* k) {
if (start != String::npos && end != String::npos) { if (start != String::npos && end != String::npos) {
k->match += separator.substr(start + 1, end - start - 1); k->match += separator.substr(start + 1, end - start - 1);
} }
if (parameter == _("no parameter")) {
parameter.clear(); // was used for magic to indicate absence of parameter
}
if (!parameter.empty()) { if (!parameter.empty()) {
k->match += _("<atom-param>") + parameter + _("</atom-param>"); k->match += _("<atom-param>") + parameter + _("</atom-param>");
} }
......
...@@ -52,7 +52,7 @@ void PackageList::showData(const String& pattern) { ...@@ -52,7 +52,7 @@ void PackageList::showData(const String& pattern) {
while (!f.empty()) { while (!f.empty()) {
// try to open the package // try to open the package
// try { // try {
PackagedP package = ::packages.openAny(f); PackagedP package = ::packages.openAny(f, true);
// open image // open image
InputStreamP stream = package->openIconFile(); InputStreamP stream = package->openIconFile();
Image img; Image img;
......
...@@ -41,6 +41,7 @@ class PackageList : public GalleryList { ...@@ -41,6 +41,7 @@ class PackageList : public GalleryList {
shared_ptr<T> getSelection() const { shared_ptr<T> getSelection() const {
shared_ptr<T> ret = dynamic_pointer_cast<T>(packages.at(selection).package); shared_ptr<T> ret = dynamic_pointer_cast<T>(packages.at(selection).package);
if (!ret) throw InternalError(_("PackageList: Selected package has the wrong type")); if (!ret) throw InternalError(_("PackageList: Selected package has the wrong type"));
ret->loadFully();
return ret; return ret;
} }
......
...@@ -8,22 +8,38 @@ ...@@ -8,22 +8,38 @@
#include <gui/update_checker.hpp> #include <gui/update_checker.hpp>
#include <data/settings.hpp> #include <data/settings.hpp>
#include <util/io/package_manager.hpp>
#include <util/version.hpp> #include <util/version.hpp>
#include <script/value.hpp> // for some strange reason the profile build needs this :( #include <script/value.hpp> // for some strange reason the profile build needs this :(
#include <wx/dialup.h> #include <wx/dialup.h>
#include <wx/url.h> #include <wx/url.h>
#include <wx/html/htmlwin.h> #include <wx/html/htmlwin.h>
DECLARE_POINTER_TYPE(PackageVersionData);
DECLARE_POINTER_TYPE(VersionData); DECLARE_POINTER_TYPE(VersionData);
// ----------------------------------------------------------------------------- : Update data // ----------------------------------------------------------------------------- : Update data
/// Information on available packages
class PackageVersionData {
public:
PackageVersionData() : is_installer(true) {}
String name; ///< Name of the package
String description; ///< html description
String url; ///< Where can the package be downloaded?
bool is_installer; ///< Download url refers to a .mse-installer
Version version; ///< Version number of the download
vector<PackageDependencyP> depends; ///< Packages this depends on
};
/// Information on the latest availible version /// Information on the latest availible version
class VersionData { class VersionData {
public: public:
Version version; ///< Latest version number Version version; ///< Latest version number of MSE
String description; ///< html description String description; ///< html description of the latest MSE release
String new_updates_url; ///< updates url has moved? String new_updates_url; ///< updates url has moved?
vector<PackageVersionDataP> packages; ///< Available packages
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
......
...@@ -9,12 +9,14 @@ ...@@ -9,12 +9,14 @@
#include <util/io/package.hpp> #include <util/io/package.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <util/error.hpp> #include <util/error.hpp>
#include <script/to_value.hpp> // for reflection
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/zipstrm.h> #include <wx/zipstrm.h>
#include <wx/dir.h> #include <wx/dir.h>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
DECLARE_TYPEOF(Package::FileInfos); DECLARE_TYPEOF(Package::FileInfos);
DECLARE_TYPEOF_COLLECTION(PackageDependencyP);
// ----------------------------------------------------------------------------- : Package : outside // ----------------------------------------------------------------------------- : Package : outside
...@@ -400,15 +402,23 @@ String Package::toStandardName(const String& name) { ...@@ -400,15 +402,23 @@ String Package::toStandardName(const String& name) {
// ----------------------------------------------------------------------------- : Packaged // ----------------------------------------------------------------------------- : Packaged
IMPLEMENT_REFLECTION(PackageDependency) {
REFLECT(package);
REFLECT(version);
}
// note: reflection must be declared before it is used // note: reflection must be declared before it is used
IMPLEMENT_REFLECTION(Packaged) { IMPLEMENT_REFLECTION(Packaged) {
REFLECT(short_name); REFLECT(short_name);
REFLECT(full_name); REFLECT(full_name);
REFLECT_N("icon", icon_filename); REFLECT_N("icon", icon_filename);
REFLECT(version);
REFLECT_N("depends ons", dependencies); // hack for singular_form
} }
Packaged::Packaged() { Packaged::Packaged()
} : fully_loaded(true)
{}
InputStreamP Packaged::openIconFile() { InputStreamP Packaged::openIconFile() {
if (!icon_filename.empty()) { if (!icon_filename.empty()) {
...@@ -417,8 +427,36 @@ InputStreamP Packaged::openIconFile() { ...@@ -417,8 +427,36 @@ InputStreamP Packaged::openIconFile() {
return InputStreamP(); return InputStreamP();
} }
} }
void Packaged::open(const String& package) {
// proxy object, that reads just WITHOUT using the overloaded behaviour
struct JustAsPackageProxy {
JustAsPackageProxy(Packaged* that) : that(that) {}
Packaged* that;
};
template <> void Reader::handle(JustAsPackageProxy& object) {
object.that->Packaged::reflect_impl(*this);
}
void Packaged::open(const String& package, bool just_header) {
Package::open(package); Package::open(package);
fully_loaded = false;
if (just_header) {
// Read just the header (the part common to all Packageds)
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName(), true);
try {
JustAsPackageProxy proxy(this);
reader.handle_greedy(proxy);
Packaged::validate(reader.file_app_version);
} catch (const ParseError& err) {
throw FileParseError(err.what(), absoluteFilename() + _("/") + typeName()); // more detailed message
}
} else {
loadFully();
}
}
void Packaged::loadFully() {
if (fully_loaded) return;
fully_loaded = true;
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName()); Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName());
try { try {
reader.handle_greedy(*this); reader.handle_greedy(*this);
...@@ -427,6 +465,7 @@ void Packaged::open(const String& package) { ...@@ -427,6 +465,7 @@ void Packaged::open(const String& package) {
throw FileParseError(err.what(), absoluteFilename() + _("/") + typeName()); // more detailed message throw FileParseError(err.what(), absoluteFilename() + _("/") + typeName()); // more detailed message
} }
} }
void Packaged::save() { void Packaged::save() {
WITH_DYNAMIC_ARG(writing_package, this); WITH_DYNAMIC_ARG(writing_package, this);
writeFile(typeName(), *this); writeFile(typeName(), *this);
...@@ -443,4 +482,8 @@ void Packaged::saveAs(const String& package) { ...@@ -443,4 +482,8 @@ void Packaged::saveAs(const String& package) {
void Packaged::validate(Version) { void Packaged::validate(Version) {
// a default for the short name // a default for the short name
if (short_name.empty()) short_name = name(); if (short_name.empty()) short_name = name();
// check dependencies
FOR_EACH(dep, dependencies) {
packages.checkDependency(*dep, true);
}
} }
...@@ -17,6 +17,7 @@ class Package; ...@@ -17,6 +17,7 @@ class Package;
class wxFileInputStream; class wxFileInputStream;
class wxZipInputStream; class wxZipInputStream;
class wxZipEntry; class wxZipEntry;
DECLARE_POINTER_TYPE(PackageDependency);
/// The package that is currently being written to /// The package that is currently being written to
DECLARE_DYNAMIC_ARG(Package*, writing_package); DECLARE_DYNAMIC_ARG(Package*, writing_package);
...@@ -175,6 +176,15 @@ class Package { ...@@ -175,6 +176,15 @@ class Package {
// ----------------------------------------------------------------------------- : Packaged // ----------------------------------------------------------------------------- : Packaged
/// Dependencies of a package
class PackageDependency {
public:
String package; ///< Name of the package someone depends on
Version version; ///< Minimal required version of that package
DECLARE_REFLECTION();
};
/// Utility class for data types that are always stored in a package. /// Utility class for data types that are always stored in a package.
/** When the package is opened/saved a file describing the data object is read/written /** When the package is opened/saved a file describing the data object is read/written
*/ */
...@@ -183,15 +193,21 @@ class Packaged : public Package { ...@@ -183,15 +193,21 @@ class Packaged : public Package {
Packaged(); Packaged();
virtual ~Packaged() {} virtual ~Packaged() {}
Version version; ///< Version number of this package
String short_name; ///< Short name of this package String short_name; ///< Short name of this package
String full_name; ///< Name of this package, for menus etc. String full_name; ///< Name of this package, for menus etc.
String icon_filename; ///< Filename of icon to use in package lists String icon_filename; ///< Filename of icon to use in package lists
vector<PackageDependencyP> dependencies; ///< Dependencies of this package
/// Get an input stream for the package icon, if there is any /// Get an input stream for the package icon, if there is any
InputStreamP openIconFile(); InputStreamP openIconFile();
/// Open a package, and read the data /// Open a package, and read the data
void open(const String& package); /** if just_header is true, then the package is not fully parsed.
*/
void open(const String& package, bool just_header = false);
/// Ensure the package is fully loaded.
void loadFully();
void save(); void save();
void saveAs(const String& package); void saveAs(const String& package);
...@@ -202,6 +218,10 @@ class Packaged : public Package { ...@@ -202,6 +218,10 @@ class Packaged : public Package {
virtual void validate(Version file_app_version); virtual void validate(Version file_app_version);
DECLARE_REFLECTION_VIRTUAL(); DECLARE_REFLECTION_VIRTUAL();
private:
bool fully_loaded; ///< Is the package fully loaded?
friend struct JustAsPackageProxy;
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -58,7 +58,7 @@ void PackageManager::init() { ...@@ -58,7 +58,7 @@ void PackageManager::init() {
data_directory += _("/data"); data_directory += _("/data");
} }
PackagedP PackageManager::openAny(const String& name) { PackagedP PackageManager::openAny(const String& name, bool just_header) {
wxFileName fn( wxFileName fn(
(wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString)) (wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString))
+ name); + name);
...@@ -79,7 +79,7 @@ PackagedP PackageManager::openAny(const String& name) { ...@@ -79,7 +79,7 @@ PackagedP PackageManager::openAny(const String& name) {
else { else {
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name); throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
} }
p->open(filename); p->open(filename, just_header);
return p; return p;
} }
} }
...@@ -101,6 +101,20 @@ InputStreamP PackageManager::openFileFromPackage(const String& name) { ...@@ -101,6 +101,20 @@ InputStreamP PackageManager::openFileFromPackage(const String& name) {
return p->openIn(n.substr(pos+1)); return p->openIn(n.substr(pos+1));
} }
bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) {
String name = data_directory + _("/") + dep.package;
if (!wxFileExists(name) && !wxDirExists(name)) {
handle_warning(_ERROR_1_("package not found", dep.package),false);
return false;
}
PackagedP package = openAny(dep.package, true);
if (package->version < dep.version) {
handle_warning(_ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString()),false);
return false;
}
return true;
}
void PackageManager::destroy() { void PackageManager::destroy() {
loaded_packages.clear(); loaded_packages.clear();
} }
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <wx/filename.h> #include <wx/filename.h>
DECLARE_POINTER_TYPE(Packaged); DECLARE_POINTER_TYPE(Packaged);
class PackageDependency;
// ----------------------------------------------------------------------------- : PackageManager // ----------------------------------------------------------------------------- : PackageManager
...@@ -40,9 +41,10 @@ class PackageManager { ...@@ -40,9 +41,10 @@ class PackageManager {
PackagedP& p = loaded_packages[filename]; PackagedP& p = loaded_packages[filename];
shared_ptr<T> typedP = dynamic_pointer_cast<T>(p); shared_ptr<T> typedP = dynamic_pointer_cast<T>(p);
if (typedP) { if (typedP) {
typedP->loadFully();
return typedP; return typedP;
} else { } else {
// not loaded, or loaded with wrong type // not loaded, or loaded with wrong type (i.e. with just_header)
p = typedP = new_shared<T>(); p = typedP = new_shared<T>();
typedP->open(filename); typedP->open(filename);
return typedP; return typedP;
...@@ -50,7 +52,9 @@ class PackageManager { ...@@ -50,7 +52,9 @@ class PackageManager {
} }
/// Open a package with the specified name, the type of package is determined by its extension! /// Open a package with the specified name, the type of package is determined by its extension!
PackagedP openAny(const String& name); /** @param if just_header is true, then the package is not fully parsed.
*/
PackagedP openAny(const String& name, bool just_header = false);
/// Find a package whos name matches a pattern /// Find a package whos name matches a pattern
/** Find more using wxFindNextFile(). /** Find more using wxFindNextFile().
...@@ -58,9 +62,12 @@ class PackageManager { ...@@ -58,9 +62,12 @@ class PackageManager {
*/ */
String findFirst(const String& pattern); String findFirst(const String& pattern);
// Open a file from a package, with a name encoded as "package/file" /// Open a file from a package, with a name encoded as "package/file"
InputStreamP openFileFromPackage(const String& name); InputStreamP openFileFromPackage(const String& name);
/// Check if the given dependency is currently installed
bool checkDependency(const PackageDependency& dep, bool report_errors = false);
private: private:
map<String, PackagedP> loaded_packages; map<String, PackagedP> loaded_packages;
String data_directory; String data_directory;
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
// ----------------------------------------------------------------------------- : Reader // ----------------------------------------------------------------------------- : Reader
Reader::Reader(const InputStreamP& input, const String& filename) Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_invalid)
: indent(0), expected_indent(0), just_opened(false) : indent(0), expected_indent(0), just_opened(false)
, filename(filename), line_number(0) , filename(filename), line_number(0)
, ignore_invalid(ignore_invalid)
, input(input), stream(*input) , input(input), stream(*input)
{ {
moveNext(); moveNext();
...@@ -125,6 +126,13 @@ void Reader::readLine() { ...@@ -125,6 +126,13 @@ void Reader::readLine() {
} }
void Reader::unknownKey() { void Reader::unknownKey() {
// ignore?
if (ignore_invalid) {
do {
moveNext();
} while (indent > expected_indent);
return;
}
// aliasses? // aliasses?
map<String,Alias>::const_iterator it = aliasses.find(key); map<String,Alias>::const_iterator it = aliasses.find(key);
if (it != aliasses.end()) { if (it != aliasses.end()) {
......
...@@ -36,7 +36,7 @@ class Reader { ...@@ -36,7 +36,7 @@ class Reader {
/// Construct a reader that reads from the given input stream /// Construct a reader that reads from the given input stream
/** filename is used only for error messages /** filename is used only for error messages
*/ */
Reader(const InputStreamP& input, const String& filename = wxEmptyString); Reader(const InputStreamP& input, const String& filename = wxEmptyString, bool ignore_invalid = false);
/// Construct a reader that reads a file in a package /// Construct a reader that reads a file in a package
/** Used for "include file" keys. */ /** Used for "include file" keys. */
...@@ -127,6 +127,8 @@ class Reader { ...@@ -127,6 +127,8 @@ class Reader {
}; };
/// Aliasses for compatability /// Aliasses for compatability
map<String, Alias> aliasses; map<String, Alias> aliasses;
/// Should all invalid keys be ignored?
bool ignore_invalid;
/// Filename for error messages /// Filename for error messages
String filename; String filename;
......
...@@ -14,15 +14,24 @@ ...@@ -14,15 +14,24 @@
UInt Version::toNumber() const { return version; } UInt Version::toNumber() const { return version; }
String Version::toString() const { String Version::toString() const {
return String() << if (version > 20000000) {
((version / 10000) % 100) << // major > 2000, the version is a date, use ISO notation
_(".") << ((version / 100) % 100) << return String::Format(_("%04d-%02d-%02d"),
_(".") << ((version / 1) % 100); (version / 10000) ,
(version / 100) % 100,
(version / 1) % 100);
} else {
return String::Format(_("%d.%d.%d"),
(version / 10000) ,
(version / 100) % 100,
(version / 1) % 100);
}
} }
Version Version::fromString(const String& version) { Version Version::fromString(const String& version) {
UInt major = 0, minor = 0, build = 0; UInt major = 0, minor = 0, build = 0;
wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build); if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build)<=1) // a.b.c style
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &build); // date style
return Version(major * 10000 + minor * 100 + build); return Version(major * 10000 + minor * 100 + build);
} }
...@@ -40,7 +49,7 @@ template <> void GetDefaultMember::handle(const Version& v) { ...@@ -40,7 +49,7 @@ template <> void GetDefaultMember::handle(const Version& v) {
// ----------------------------------------------------------------------------- : Versions // ----------------------------------------------------------------------------- : Versions
// NOTE: Don't use leading zeroes, they mean octal // NOTE: Don't use leading zeroes, they mean octal
const Version app_version = 301; // 0.3.1 const Version app_version = 302; // 0.3.2
const Char* version_suffix = _(" (beta)"); const Char* version_suffix = _(" (beta)");
/* Changes: /* Changes:
...@@ -50,5 +59,6 @@ const Char* version_suffix = _(" (beta)"); ...@@ -50,5 +59,6 @@ const Char* version_suffix = _(" (beta)");
* 0.2.7 : new tag system, different style of close tags * 0.2.7 : new tag system, different style of close tags
* 0.3.0 : port of code to C++ * 0.3.0 : port of code to C++
* 0.3.1 : new keyword system, some new style options * 0.3.1 : new keyword system, some new style options
* 0.3.2 : package dependencies
*/ */
const Version file_version = 301; // 0.3.1 const Version file_version = 302; // 0.3.2
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