Developing a plugin for meta
In my last post, I introduced meta
and we discussed a need for a templating tool that allows private templates to be created and easily shared between your team.
This post is the how to the why. If you are interested in developing your own meta
plugin, then read ahead!
Setting up meta for development
The best way to get started is to do the following:
npm i -g meta
meta git clone git@github.com:mateodelnorte/meta.git
cd ./meta
npm install
meta npm install
meta npm link --all
npm link
This above does the following:
- install
meta
globally - clone the meta project, aptly named
meta
- change to the cloned directory
- use
meta
to performnpm install
,npm link --all
in each directory listed inprojects
of the.meta
JSON configuration file - link the version of meta in the current directory to be used as a global command, so when calling
meta
your system will use your in-development version.
You can then write your command and test using meta [subcommand]
.
Authoring the plugin
First thing’s first, I’m heading on over to GitHub to create a meta-template
project. Then I will add it to meta using the following command:
meta project add plugins/meta-template git@github.com:patrickleet/meta-template.git
The goal of this project will ultimately be the following API
> meta project add templates/meta-plugin git@github.com:patrickleet/meta-template-meta-plugin.git> meta project add plugins/meta-xyz git@github.com:patrickleet/meta-xyz.git> meta template apply templates/meta-plugin plugins/meta-xyz
This will allow any git repository to serve as an initial template. I will create a template for building meta-plugins as the first meta-template
template. So meta. Our meta-plugin
template will need to generate the following:
- meta-xyz
— bin/
— meta-xyz
— .gitignore
— LICENSE
— README.md
— index.js
— package.json
I’ve created the repository over at https://github.com/patrickleet/meta-template-meta-plugin.
Let’s add the repository to our metarepo using meta project add
.
meta project add templates/meta-plugin git@github.com:patrickleet/meta-template-meta-plugin.git
Now I’m just going to repurpose the contents of a stub project, meta-docker
which has yet to be implemented into my template. We want everything except the git history. The following process being the inspiration for the plugin, and what we will soon automate.
cp -r plugins/meta-docker templates/tmp && rm -rf templates/tmp/.git && cp -R templates/tmp/* templates/meta-plugin && cp -R templates/tmp/.* templates/meta-plugin && rm -rf templates/tmp
Commit: copy meta-docker placeholder project
Now, we want to replace the docker
strings with a template that we can find and replace later. I did this with a `Find & Replace` in VSCode.
In the end I have the following parameters that should be read when applying the template: {[PLUGIN_NAME]}
, {[GITHUB_USERNAME]}
, {[EMAIL]}
, and {[FULL_NAME]}
Committed, pushed to Github: templatize
Next, we just need a way to apply the template, which will cp the contents of the template project, parse the contents for template variables, and then prompt the user to input each variable.
Unfortunately, since the plugin doesn’t yet exist, we will perform the manual version of the task. Let’s copy the contents of the template into meta-plugin
cd ../../
cp -R templates/meta-plugin/* plugins/meta-template && cp templates/meta-plugin/.* plugins/meta-template
We get an error the `.git` is not an empty directory, and not copied, which is what we want anyway. We will want to address that more gracefully in our automated version.
Find and replace each of the variables, and commit to GitHub. Next step, writing the plugin code to automate the process we just did.
- Copy the source template directory to a tmp directory
- Remove .git directory
- Copy tmp directory contents to destination directory
- Parse contents for variables
- Prompt for variables
- Replace variables with user inputs
- Remove tmp directory
First, let’s uncomment out a placeholder command, save, and then from ./meta
run meta npm link --all
When we run meta
we should now see meta template
as an option in help, and running meta template
should show us our apply
command is available.
➜ meta git:(master) ✗ meta
Usage: meta [options] [command]
Commands:
docker run docker commands for your meta repo and child git repositories
gh github command tool
git manage your meta repo and child git repositories
init initialize a new meta repo
npm run npm commands against your meta and child repositories
project add & remove child repositories
template run template commands for your meta repo and child git repositories
yarn run yarn commands against your meta and child repositories
help [cmd] display help for [cmd]Options: -h, — help output usage information
-V, — version output the version number➜ meta git:(master) ✗ meta templateUsage: meta-template [options] [command]Commands:apply apply a source directory as a template on another destination directory
help [cmd] display help for [cmd]Options:-h, — help output usage information
Alright, let’s write bin/meta-template-apply
. We’ll set the #!
and parse the src and dest directories. If the plugin is used without the correct arguments, we will output the usage
string.
#!/usr/bin/env node
const usage = `\n usage:\n\n meta template apply <srcTemplateDir> <destProjectDir>\n`;if ( ! process.argv[2] || process.argv[2] === ‘ — help’)
return console.log(usage);const srcTemplateDir = process.argv[2] === ‘blank’ ?
process.argv[3] :
process.argv[2];const destProjectDir = process.argv[3] === ‘blank’ ?
process.argv[4] :
process.argv[3];if ( ! srcTemplateDir || ! destProjectDir) return console.log(usage);console.log(`meta template applying \’${srcTemplateDir}\’ to ${destProjectDir}`);
And add it to package.json
so it’s executable.
After another meta npm link --all && npm link
we can see apply
outputting usage
meta git:(master) ✗ meta template applyusage:meta template apply <srcTemplateDir> <destProjectDir>
[meta apply · patrickleet/meta-template@56d5a17 · GitHub]
At this point you hopefully you now have a good sense of what it takes to develop a meta
plugin locally. The fact that meta
provides a way to do this makes it pretty straightforward. The actual implementation is beyond the scope of what I wanted to accomplish with this post, as it would go on for far too long, but I did finish implementing it. I suggest perusing the GitHub history starting at the last commit if you’re interested!
[GitHub — patrickleet/meta-template: Templates for new meta projects](https://github.com/patrickleet/meta-template)