autobuild

Define and execute build rules and compilation pipelines


Keywords
compile, build, pipeline, autobuild, extensions, processes, tools
License
GPL-3.0

Documentation

Overview

Autobuild is a framework for defining and executing arbitrary build rules.

Autobuild rules contain knowledge about how to carry out a certain type of build under specific contexts.

When an autobuild rule is applicable under the current context in emacs, it generates an action which details how to carry out the build.

Autobuild rule actions may range from simple compile-command strings, to emacs-lisp functions, to pipelines that chain multiple build rules together to create more complete build processes, with individual steps that may be either synchronous or asynchronous.

http://downloads.erjoalgo.com/autobuild-demo.png

Index

autobuild-define-rule

Autobuild rules are zero-ary named functions that contain knowledge about what “build” means under a specific context. A context may involve the current buffer’s major-mode, the name of the current file, the presence of other files in the current directory (for example, “Makefile” or “BUILD”), or any other emacs lisp predicate.

Because most build rules are limited to certain major modes, all rules must specify a list mode-filter, which, if non-nil, restricts the applicability of the rule to the major modes listed.

When a rule generates a non-nil action, it communicates that it knows how to “build” in the current context, and specifies how to do so as part of the action.

An action may be either a string, which is executed with compile, or a zero-ary function.

Examples

(autobuild-define-rule autobuild-el-eval-buffer (emacs-lisp-mode)
  "Evaluate the current emacs-lisp buffer"
  #'eval-buffer)

(autobuild-define-rule autobuild-cl-slime-eval (lisp-mode)
  "Evaluate the current lisp buffer"
  #'slime-compile-and-load-file)

(autobuild-define-rule autobuild-html-browse (html-mode mhtml-mode)
  "Open the current html file in the browser"
  (let ((url (format "file://%s" (buffer-file-name))))
    (apply-partially #'browse-url url)))

(autobuild-define-rule autobuild-run-executable nil
  "Run the current buffer's underlying file as an executable if possible."
  (autobuild-nice 9)
  (let ((filename (buffer-file-name)))
    (when (and filename
               (file-executable-p filename))
      (format "./%s" (f-filename filename)))))

(autobuild-define-rule autobuild-shell-script-syntax-check (sh-mode)
  "Syntax-check a bash script without running it"
  (autobuild-nice 15)
  (let ((fn (f-filename (buffer-file-name))))
    (format "bash -n %s" fn)))

(autobuild-define-rule autobuild-file-local-compile-command-set nil
  "Set and run the file-local compile command"
  (lambda ()
    (autobuild-nice 12)
    (let ((command
           (read-shell-command "enter compile command: "
                               (alist-get 'compile-command file-local-variables-alist))))
      (add-file-local-variable 'compile-command command)
      (setq compile-command command)
      (compile compile-command))))

(autobuild-define-rule autobuild-ispell (text-mode)
  "Do a spell check"
  #'ispell)

autobuild-build

This is the main user-facing command entry-point, and should be bound to a key.

autobuild-build obtains a list of the currently-applicable build rule actions and executes the one with highest priority.

With a prefix argument, the user is prompted to explicitly select a build rule or to change the current one.

autobuild-build remembers the last rule executed at the buffer-local level, and re-executes it if it is known and if prompting was not requested.

autobuild-nice

A rule may specify the priority of its action by setting the value of autobuild-nice, with lower nice values denoting higher priority. autobuild-build defaults to selecting the action with the highest priority, unless prompting was requested via a prefix argument.

The most specific rule under a certain context should strive to have the highest priority in order for autobuild-build to select it as the default.

autobuild-pipeline

Several build rules may be chained together to form compilation-pipelines. (TODO example) Within a pipeline, if a rule’s action is either a string, which denotes a compile-command, or a function whose value is a compilation buffer, the action is considered to be an asynchronous compile command, and any remaining steps in a compilation pipeline are only resumed after the current command has succeeded.

autobuild-notification-function

This function is invoked when an asynchronous compilation command or pipeline has completed. It is subject to autobuild-notify-threshold-secs. It may be used to notify the user in custom ways, for example via notify-send “desktop” notifications, beeps, etc.

Installation and sample usage

  • Add autobuild to the load path and require it, or simply load the file.
  • Bind #'autobuild-build to a key.
  • Define appropriate rules.
    • Optionally, require autobuild-examples to obtain a few commonly-applicable build rules.
  • Invoke autobuild-build to build in the current context.
(require 'autobuild)
(require 'autobuild-examples)
(autobuild-mode)
(global-set-key (kbd "M-c") #'autobuild-build)

Differences with other packages

Autobuild is different from other similar packages in that it provides a menu of various applicable build options, from which the user makes an explicit or implicit choice, as opposed to a providing a single line of hooks that are always implicitly executed. This ability to make an explicit choice about which build rule to apply allows users to switch back-and-forth between several different flows for whatever building/compiling means in the current context.

Autobuild rules are also capable of dynamically determining their own applicability, priority, and are able to customize generated build actions based on the current contex.

More Examples

Example rule definitions