@@ -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++; | |||||
} | |||||
} | } | ||||