2234729c0e | ||
---|---|---|
.gitignore | ||
README.org | ||
mkly | ||
mkly-rules.scm | ||
mkly-tests.scm |
README.org
mkly
A Guile build script for Lilypond (and other) projects
Features
- Provides a default set of rules, so you don't have to.
- Provides a full-blown programming language for writing rules.
- Tiny; trivial to hack on.
- Implemented and configured using the only reasonable language (a Lisp 😏)
Non-goals
- Incremental builds
Installation
Guile must be available at /usr/bin/guile
- Place
mkly
in your $PATH or your project root -
Make it executable -
chmod u+x mkly
- Place
mkly-rules.scm
in your project root. -
In your project root, run -
./mkly
Invocation
mkly can be run without arguments -
mkly
Doing so will execute the action in the first (top-most) defined rule.
You can pass one or more targets -
mkly <target>*
Each target will be checked against the defined patterns, and the actions for all matching patterns will be run.
If a subdirectory is supplied, mkly will descend to it for all following targets (until another subdirectory on the command line is encountered) -
mkly main foo/ dev bar/ main dev
Here, target "main" will be run in the project root, target "dev" will be run in the subdirectory "foo/", and target "main" and "dev" will be run in subdirectory "bar/".
If there is a mkly-rules.scm in the subdirectory, the targets following the subdirectory will be matched against patterns defined in that file. If there isn't such a file, the patterns from the directory mkly was called in will be used instead.
The defaults
The default rules make certain assumptions about your project structure -
- You have a main.ly in the project root containing all musical parts
- Individual parts are contained in part-*.ly files
- Emitted PDF/MIDI/PNG files go into a directory called "output" (or "output-<current branch>" if you use a VCS)
Of course, you can change the rules to suit whatever project structure you want.
Some default variables are defined -
- project-name - by default, the basename of the parent directory
- shell-path - path to the shell you want to use for running your commands
Defining rules
Rules are returned as a list by the procedure rules
, defined in the project-specific mkly-rules.scm
.
Built-in helper functions
(use-dir! DIR)
- creates DIR if it does not exist. DIR must be a string. Raises an error if DIR exists and is not a directory. Returns DIR.(vcs-current-branch)
(parent PATH)
- returns the parent directory component of PATH, or #f if none is present.(getcwd-base)
- returns the basename of the current directory.
TODO
Certain [50%]
- Make it declarative - define options and their effect, and the structure of the command, separately from the code that makes it happen.
- Use regexps to define target names and how the output file name(s) derive from them.
- Name files differently if PAC is on - The upside of this is, you don't accidentally send someone the point-and-click-enabled version of the file. The downside is, it's easy to have file-pacON.pdf open during editing, while the script is actually compiling to file.pdf (or vice-versa) 1, and wonder why your score isn't updating.
- Create output directory if it doesn't exist!
-
Remove duplicate layer of CLI options - currently there's a needless extra layer of CLI options for options which already exist. Should make code simpler, UI familiar.
-
But the Lilypond CLI is ugly - what's better, "pac=off", or "-dno-point-and-click"? :\
- After the revamp, the script doesn't (yet) aim to want to support options like this; the idea is that the user specifies a situation as a target, and all options relevant to that situation are passed (as specified in the rules by the user). It's a "maybe" to-do.
-
- Tab completion of specified target names
- Multiple targets in one command e.g. to compile both the main score and the parts in one command.
-
Targets containing other targets.
- I've tried calling the script itself with the required targets - not sure if that actually works. Especially considering that #7 - multiple targets in one command - isn't implemented yet.
- If mkly is not in the user's $PATH and is invoked as
./mkly
, the shell won't be able to find it if it calls itself. We can try constructing the path to the script (usinggetcwd
- if(first (command-line))
is "./mkly", it's in the current working directory)
-
Shell globs, both in targets and in actions.
- Document shell-path as a user variable
- Use shell-path to run commands
-
Sub-project operations
-
Specify targets for sub*-project(s), instead of project in current working directory.
- The current way is somewhat inelegant, though - you either modify all rules to also work in sub-projects, or you make new rules for sub-projects…why can't the same rule work for both? What if we could specify a subdirectory, followed by the usual targets, resulting in us
cd
ing into that directory and running the usual targets? Same rules working in both situations!
- The current way is somewhat inelegant, though - you either modify all rules to also work in sub-projects, or you make new rules for sub-projects…why can't the same rule work for both? What if we could specify a subdirectory, followed by the usual targets, resulting in us
- Use sub-project-specific mkly-rules.scm if present, else use project-root mkly-rules.scm
- I want to compile a particular target in every subproject. (use globs)
(Old) implementation notes
-
Maybe…if the input file in a target entry is just a "/" (or maybe "->"?), the target name will be understood as being the target to run in either
- all subdirectories directly below the directory containing the current build.scm (in this case, it is an error if any of these subdirectories do not contain a build.scm)
- all subdirectories in which a build.scm can be found, directly below the directory containg the current build.scm
-
- Expand branch detection to include more VCSs.
- Add -h/–help, and -d/–debug or -v/–verbose
Maybe [0%]
- Allow users to define (command-line) options and their effect.
-
VCS branch integration - check what branch you're on. If it's branch X (e.g. "main"), do nothing. If it's something else, add the name to the output file.
- Or to the output directory name, e.g. files from the main branch go to "output/", files from branch "foo" go to "output-foo/", etc.
- Default rules for orchestral projects - for target part-<instrument>.ly, compile <instrument class>/<instrument>.ly
- Make
rules
into a macro -
Implement Scheme expressions as an action.
- one possible way - all actions are Scheme expressions - for shell commands, create a ($ ...) form (with =$= doing what
run
does now) which iseval
-uated if it matches a target. (see branch "$-syntax")
- one possible way - all actions are Scheme expressions - for shell commands, create a ($ ...) form (with =$= doing what
-
Replace regexp patterns with glob patterns?
- more consistent (since targets and actions use globs too), but possibly less powerful.
These are likely to happen if you have a compile-with-last-command-on-save setup, like in my Emacs.