| @@ -65,7 +65,7 @@ endif | |||||
| ifdef ARCH_MAC | ifdef ARCH_MAC | ||||
| rsync -rR $(DISTRIBUTABLES) dist/$(SLUG)/ | rsync -rR $(DISTRIBUTABLES) dist/$(SLUG)/ | ||||
| else | else | ||||
| cp -R --parents $(DISTRIBUTABLES) dist/$(SLUG)/ | |||||
| cp -r --parents $(DISTRIBUTABLES) dist/$(SLUG)/ | |||||
| endif | endif | ||||
| @# Create ZIP package | @# Create ZIP package | ||||
| cd dist && zip -q -9 -r $(SLUG)-$(VERSION)-$(ARCH).zip $(SLUG) | cd dist && zip -q -9 -r $(SLUG)-$(VERSION)-$(ARCH).zip $(SLUG) | ||||
| @@ -132,46 +132,12 @@ static Plugin *loadPlugin(std::string path) { | |||||
| // Load manifest | // Load manifest | ||||
| plugin->fromJson(rootJ); | plugin->fromJson(rootJ); | ||||
| // Check slug | |||||
| if (!isSlugValid(plugin->slug)) { | |||||
| throw UserException(string::f("Plugin slug \"%s\" is invalid", plugin->slug.c_str())); | |||||
| } | |||||
| // Reject plugin if slug already exists | // Reject plugin if slug already exists | ||||
| Plugin *oldPlugin = getPlugin(plugin->slug); | Plugin *oldPlugin = getPlugin(plugin->slug); | ||||
| if (oldPlugin) { | if (oldPlugin) { | ||||
| throw UserException(string::f("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str())); | throw UserException(string::f("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str())); | ||||
| } | } | ||||
| // Remove models without names | |||||
| for (auto it = plugin->models.begin(); it != plugin->models.end();) { | |||||
| Model *model = *it; | |||||
| if (model->name == "") { | |||||
| it = plugin->models.erase(it); | |||||
| continue; | |||||
| } | |||||
| it++; | |||||
| } | |||||
| // Normalize tags | |||||
| for (Model *model : plugin->models) { | |||||
| std::vector<std::string> normalizedTags; | |||||
| for (const std::string &tag : model->tags) { | |||||
| std::string normalizedTag = normalizeTag(tag); | |||||
| if (!normalizedTag.empty()) | |||||
| normalizedTags.push_back(normalizedTag); | |||||
| } | |||||
| model->tags = normalizedTags; | |||||
| } | |||||
| // Search for presets | |||||
| for (Model *model : plugin->models) { | |||||
| std::string presetDir = asset::plugin(plugin, "presets/" + model->slug); | |||||
| for (const std::string &presetPath : system::getEntries(presetDir)) { | |||||
| model->presetPaths.push_back(presetPath); | |||||
| } | |||||
| } | |||||
| INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), path.c_str()); | INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), path.c_str()); | ||||
| plugins.push_back(plugin); | plugins.push_back(plugin); | ||||
| @@ -1,4 +1,8 @@ | |||||
| #include <plugin/Model.hpp> | #include <plugin/Model.hpp> | ||||
| #include <plugin.hpp> | |||||
| #include <asset.hpp> | |||||
| #include <system.hpp> | |||||
| #include <string.hpp> | |||||
| namespace rack { | namespace rack { | ||||
| @@ -6,23 +10,39 @@ namespace plugin { | |||||
| void Model::fromJson(json_t *rootJ) { | void Model::fromJson(json_t *rootJ) { | ||||
| assert(plugin); | |||||
| json_t *nameJ = json_object_get(rootJ, "name"); | json_t *nameJ = json_object_get(rootJ, "name"); | ||||
| if (nameJ) | if (nameJ) | ||||
| name = json_string_value(nameJ); | name = json_string_value(nameJ); | ||||
| if (name == "") | |||||
| throw UserException(string::f("No module name for slug %s", slug.c_str())); | |||||
| json_t *descriptionJ = json_object_get(rootJ, "description"); | json_t *descriptionJ = json_object_get(rootJ, "description"); | ||||
| if (descriptionJ) | if (descriptionJ) | ||||
| description = json_string_value(descriptionJ); | description = json_string_value(descriptionJ); | ||||
| // Tags | |||||
| tags.clear(); | |||||
| json_t *tagsJ = json_object_get(rootJ, "tags"); | json_t *tagsJ = json_object_get(rootJ, "tags"); | ||||
| if (tagsJ) { | if (tagsJ) { | ||||
| size_t i; | size_t i; | ||||
| json_t *tagJ; | json_t *tagJ; | ||||
| json_array_foreach(tagsJ, i, tagJ) { | json_array_foreach(tagsJ, i, tagJ) { | ||||
| std::string tag = json_string_value(tagJ); | std::string tag = json_string_value(tagJ); | ||||
| tags.push_back(tag); | |||||
| // Normalize tag | |||||
| tag = normalizeTag(tag); | |||||
| if (tag != "") | |||||
| tags.push_back(tag); | |||||
| } | } | ||||
| } | } | ||||
| // Preset paths | |||||
| presetPaths.clear(); | |||||
| std::string presetDir = asset::plugin(plugin, "presets/" + slug); | |||||
| for (const std::string &presetPath : system::getEntries(presetDir)) { | |||||
| presetPaths.push_back(presetPath); | |||||
| } | |||||
| } | } | ||||
| @@ -32,18 +32,30 @@ Model *Plugin::getModel(std::string slug) { | |||||
| } | } | ||||
| void Plugin::fromJson(json_t *rootJ) { | void Plugin::fromJson(json_t *rootJ) { | ||||
| // Slug | |||||
| json_t *slugJ = json_object_get(rootJ, "slug"); | json_t *slugJ = json_object_get(rootJ, "slug"); | ||||
| if (slugJ) | if (slugJ) | ||||
| slug = json_string_value(slugJ); | slug = json_string_value(slugJ); | ||||
| if (slug == "") | |||||
| throw UserException("No plugin slug"); | |||||
| if (!isSlugValid(slug)) | |||||
| throw UserException(string::f("Plugin slug \"%s\" is invalid", slug.c_str())); | |||||
| // Version | |||||
| json_t *versionJ = json_object_get(rootJ, "version"); | json_t *versionJ = json_object_get(rootJ, "version"); | ||||
| if (versionJ) | if (versionJ) | ||||
| version = json_string_value(versionJ); | version = json_string_value(versionJ); | ||||
| if (version == "") | |||||
| throw UserException("No plugin version"); | |||||
| // Name | |||||
| json_t *nameJ = json_object_get(rootJ, "name"); | json_t *nameJ = json_object_get(rootJ, "name"); | ||||
| if (nameJ) | if (nameJ) | ||||
| name = json_string_value(nameJ); | name = json_string_value(nameJ); | ||||
| if (name == "") | |||||
| throw UserException("No plugin name"); | |||||
| // Brand | |||||
| json_t *brandJ = json_object_get(rootJ, "brand"); | json_t *brandJ = json_object_get(rootJ, "brand"); | ||||
| if (brandJ) | if (brandJ) | ||||
| brand = json_string_value(brandJ); | brand = json_string_value(brandJ); | ||||
| @@ -116,6 +128,18 @@ void Plugin::fromJson(json_t *rootJ) { | |||||
| model->fromJson(moduleJ); | model->fromJson(moduleJ); | ||||
| } | } | ||||
| } | } | ||||
| // Remove models without names | |||||
| // This is a hacky way of matching JSON models with C++ models. | |||||
| for (auto it = models.begin(); it != models.end();) { | |||||
| Model *model = *it; | |||||
| if (model->name == "") { | |||||
| it = models.erase(it); | |||||
| delete model; | |||||
| continue; | |||||
| } | |||||
| it++; | |||||
| } | |||||
| } | } | ||||