@@ -65,7 +65,7 @@ endif | |||
ifdef ARCH_MAC | |||
rsync -rR $(DISTRIBUTABLES) dist/$(SLUG)/ | |||
else | |||
cp -R --parents $(DISTRIBUTABLES) dist/$(SLUG)/ | |||
cp -r --parents $(DISTRIBUTABLES) dist/$(SLUG)/ | |||
endif | |||
@# Create ZIP package | |||
cd dist && zip -q -9 -r $(SLUG)-$(VERSION)-$(ARCH).zip $(SLUG) | |||
@@ -132,46 +132,12 @@ static Plugin *loadPlugin(std::string path) { | |||
// Load manifest | |||
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 | |||
Plugin *oldPlugin = getPlugin(plugin->slug); | |||
if (oldPlugin) { | |||
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()); | |||
plugins.push_back(plugin); | |||
@@ -1,4 +1,8 @@ | |||
#include <plugin/Model.hpp> | |||
#include <plugin.hpp> | |||
#include <asset.hpp> | |||
#include <system.hpp> | |||
#include <string.hpp> | |||
namespace rack { | |||
@@ -6,23 +10,39 @@ namespace plugin { | |||
void Model::fromJson(json_t *rootJ) { | |||
assert(plugin); | |||
json_t *nameJ = json_object_get(rootJ, "name"); | |||
if (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"); | |||
if (descriptionJ) | |||
description = json_string_value(descriptionJ); | |||
// Tags | |||
tags.clear(); | |||
json_t *tagsJ = json_object_get(rootJ, "tags"); | |||
if (tagsJ) { | |||
size_t i; | |||
json_t *tagJ; | |||
json_array_foreach(tagsJ, i, 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) { | |||
// Slug | |||
json_t *slugJ = json_object_get(rootJ, "slug"); | |||
if (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"); | |||
if (versionJ) | |||
version = json_string_value(versionJ); | |||
if (version == "") | |||
throw UserException("No plugin version"); | |||
// Name | |||
json_t *nameJ = json_object_get(rootJ, "name"); | |||
if (nameJ) | |||
name = json_string_value(nameJ); | |||
if (name == "") | |||
throw UserException("No plugin name"); | |||
// Brand | |||
json_t *brandJ = json_object_get(rootJ, "brand"); | |||
if (brandJ) | |||
brand = json_string_value(brandJ); | |||
@@ -116,6 +128,18 @@ void Plugin::fromJson(json_t *rootJ) { | |||
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++; | |||
} | |||
} | |||