diff --git a/helper.py b/helper.py index c03b4c7d..0dae63e5 100755 --- a/helper.py +++ b/helper.py @@ -39,33 +39,15 @@ def slug_to_identifier(slug): return slug -def usage(script): - text = f"""Usage: {script} ... -Run commands without arguments for command help. - -Commands: - createplugin - createmodule - createmanifest -""" - print(text) - - -def usage_create_plugin(script): - text = f"""Usage: {script} createplugin - -A directory will be created in the current working directory and seeded with initial files. -""" - print(text) - - -def create_plugin(slug): +def create_plugin(slug, plugin_dir=None): # Check slug if not is_valid_slug(slug): raise UserException("Slug must only contain ASCII letters, numbers, '-', and '_'.") + if not plugin_dir: + plugin_dir = os.path.join(slug, '') + # Check if plugin directory exists - plugin_dir = os.path.join(slug, '') if os.path.exists(plugin_dir): raise UserException(f"Directory {plugin_dir} already exists") @@ -74,7 +56,7 @@ def create_plugin(slug): # Create manifest try: - create_manifest(plugin_dir, slug) + create_manifest(slug, plugin_dir) except Exception as e: os.rmdir(plugin_dir) raise e @@ -120,6 +102,7 @@ using namespace rack; extern Plugin *pluginInstance; // Declare each Model, defined in each module source file +// extern Model *modelMyModule; """ with open(os.path.join(plugin_dir, "src/plugin.hpp"), "w") as f: f.write(plugin_hpp) @@ -159,58 +142,57 @@ void init(Plugin *p) { print(f"You may use `make`, `make clean`, `make dist`, `make install`, etc in the {plugin_dir} directory.") -def create_manifest(plugin_dir, slug=None): - manifest = {} +def create_manifest(slug, plugin_dir="."): + # Default manifest + manifest = { + 'slug': slug, + } + + # Try to load existing manifest file + manifest_filename = os.path.join(plugin_dir, 'plugin.json') + try: + with open(manifest_filename, "r") as f: + manifest = json.load(f) + except: + pass # Query manifest information - if not slug: - slug = input_default("Plugin slug (unique identifier)") - manifest['slug'] = slug - manifest['name'] = input_default("Plugin name", slug) - manifest['version'] = input_default("Version", "1.0.0") - manifest['license'] = input_default("License (if open-source, use license identifier from https://spdx.org/licenses/)", "proprietary") - manifest['author'] = input_default("Author") - manifest['authorEmail'] = input_default("Author email (optional)") - manifest['authorUrl'] = input_default("Author website URL (optional)") - manifest['pluginUrl'] = input_default("Plugin website URL (optional)") - manifest['manualUrl'] = input_default("Manual website URL (optional)") - manifest['sourceUrl'] = input_default("Source code URL (optional)") - manifest['donateUrl'] = input_default("Donate URL (optional)") - manifest['modules'] = [] + manifest['name'] = input_default("Plugin name", manifest.get('name', slug)) + manifest['version'] = input_default("Version", manifest.get('version', "1.0.0")) + manifest['license'] = input_default("License (if open-source, use license identifier from https://spdx.org/licenses/)", manifest.get('license', "proprietary")) + manifest['author'] = input_default("Author", manifest.get('author', "")) + manifest['authorEmail'] = input_default("Author email (optional)", manifest.get('authorEmail', "")) + manifest['authorUrl'] = input_default("Author website URL (optional)", manifest.get('authorUrl', "")) + manifest['pluginUrl'] = input_default("Plugin website URL (optional)", manifest.get('pluginUrl', "")) + manifest['manualUrl'] = input_default("Manual website URL (optional)", manifest.get('manualUrl', "")) + manifest['sourceUrl'] = input_default("Source code URL (optional)", manifest.get('sourceUrl', "")) + manifest['donateUrl'] = input_default("Donate URL (optional)", manifest.get('donateUrl', "")) + + if 'modules' not in manifest: + manifest['modules'] = [] # Dump JSON - manifest_filename = os.path.join(plugin_dir, 'plugin.json') with open(manifest_filename, "w") as f: - json.dump(manifest, f, indent="\t") - print(f"Manifest created at {manifest_filename}") - - -def usage_create_module(script): - text = f"""Usage: {script} createmodule + json.dump(manifest, f, indent=" ") + print(f"Manifest written to {manifest_filename}") -Must be called in a plugin directory. -A panel file must exist in res/.svg. -A source file will be created at src/.cpp. -See https://vcvrack.com/manual/PanelTutorial.html for creating SVG panel files. -""" - print(text) - - -def create_module(slug): +def create_module(slug, panel_filename=None, source_filename=None): # Check slug if not is_valid_slug(slug): raise UserException("Slug must only contain ASCII letters, numbers, '-', and '_'.") # Read manifest manifest_filename = 'plugin.json' - manifest = None with open(manifest_filename, "r") as f: manifest = json.load(f) # Check if module manifest exists module_manifest = find(lambda m: m['slug'] == slug, manifest['modules']) - if not module_manifest: + if module_manifest: + print(f"Module {slug} already exists in plugin.json. Edit this file to modify the module manifest.") + + else: # Add module to manifest module_manifest = {} module_manifest['slug'] = slug @@ -227,50 +209,44 @@ def create_module(slug): # Write manifest with open(manifest_filename, "w") as f: - json.dump(manifest, f, indent="\t") + json.dump(manifest, f, indent=" ") print(f"Added {slug} to plugin.json") - else: - print(f"Module {slug} already exists in plugin.json. Edit this file to modify the module manifest.") - # Check filenames - panel_filename = f"res/{slug}.svg" - source_filename = f"src/{slug}.cpp" + if panel_filename and source_filename: + if not os.path.exists(panel_filename): + raise UserException(f"Panel not found at {panel_filename}.") - if not os.path.exists(panel_filename): - print(f"Panel not found at {panel_filename}. If you wish to automatically generate a source file, run this command with no arguments for instructions for creating a panel file.") - return - - print(f"Panel found at {panel_filename}. Generating source file.") + print(f"Panel found at {panel_filename}. Generating source file.") - if os.path.exists(source_filename): - if input_default(f"{source_filename} already exists. Overwrite?", "n").lower() != "y": - return + if os.path.exists(source_filename): + if input_default(f"{source_filename} already exists. Overwrite?", "n").lower() != "y": + return - # Read SVG XML - tree = xml.etree.ElementTree.parse(panel_filename) + # Read SVG XML + tree = xml.etree.ElementTree.parse(panel_filename) - components = panel_to_components(tree) - print(f"Components extracted from {panel_filename}") + components = panel_to_components(tree) + print(f"Components extracted from {panel_filename}") - # Write source - source = components_to_source(components, slug) + # Write source + source = components_to_source(components, slug) - with open(source_filename, "w") as f: - f.write(source) - print(f"Source file generated at {source_filename}") + with open(source_filename, "w") as f: + f.write(source) + print(f"Source file generated at {source_filename}") - # Append model to plugin.hpp - identifier = slug_to_identifier(slug) + # Append model to plugin.hpp + identifier = slug_to_identifier(slug) - # Tell user to add model to plugin.hpp and plugin.cpp - print(f"") - print(f"To enable the module, add") - print(f"extern Model *model{identifier};") - print(f"to plugin.hpp, and add") - print(f"p->addModel(model{identifier});") - print(f"to the init() function in plugin.cpp.") + # Tell user to add model to plugin.hpp and plugin.cpp + print(f""" +To enable the module, add +extern Model *model{identifier}; +to plugin.hpp, and add +p->addModel(model{identifier}); +to the init() function in plugin.cpp.""") def panel_to_components(tree): @@ -498,24 +474,49 @@ Model *model{identifier} = createModel<{identifier}, {identifier}Widget>("{slug} return source +def usage(script): + text = f"""VCV Rack Plugin Helper Utility + +Usage: {script} ... +Commands: + +createplugin [plugin dir] + + A directory will be created and initialized with a minimal plugin template. + If no plugin directory is given, the slug is used. + +createmanifest [plugin dir] + + Creates a `plugin.json` manifest file in an existing plugin directory. + If no plugin directory is given, the current directory is used. + +createmodule [panel file] [source file] + + Adds a new module to the plugin manifest in the current directory. + If a panel and source file are given, generates a template source file initialized with components from a panel file. + Example: + {script} createmodule MyModule res/MyModule.svg src/MyModule.cpp + + See https://vcvrack.com/manual/PanelTutorial.html for creating SVG panel files. +""" + print(text) + + def parse_args(args): - if len(args) >= 2: - if args[1] == 'createplugin': - if len(args) >= 3: - create_plugin(args[2]) - return - usage_create_plugin(args[0]) - return - if args[1] == 'createmodule': - if len(args) >= 3: - create_module(args[2]) - return - usage_create_module(args[0]) - return - if args[1] == 'createmanifest': - create_manifest('.') - return - usage(args[0]) + script = args.pop(0) + if len(args) == 0: + usage(script) + return + + cmd = args.pop(0) + if cmd == 'createplugin': + create_plugin(*args) + elif cmd == 'createmodule': + create_module(*args) + elif cmd == 'createmanifest': + create_manifest(*args) + else: + print(f"Command not found: {cmd}") if __name__ == "__main__":