Beam::Make - Recipes to declare and resolve dependencies between things


version 0.003


    ### container.yml
    # This Beam::Wire container stores shared objects for our recipes
        $class: DBI
        $method: connect
            - dbi:SQLite:RECENT.db

    ### Beamfile
    # This file contains our recipes
    # Download a list of recent changes to CPAN
            - curl -O

    # Parse that JSON file into a CSV using an external program
            - RECENT-6h.json
            - yfrom json RECENT-6h.json | yq '.recent.[]' | yto csv > RECENT-6h.csv

    # Build a SQLite database to hold the recent data
        $class: Beam::Make::DBI::Schema
        dbh: { $ref: 'container.yml:dbh' }
            - table: recent
                - path: VARCHAR(255)
                - epoch: DOUBLE
                - type: VARCHAR(10)

    # Load the recent data CSV into the SQLite database
        $class: Beam::Make::DBI::CSV
            - RECENT.db
            - RECENT-6h.csv
        dbh: { $ref: 'container.yml:dbh' }
        table: recent
        file: RECENT-6h.csv

    ### Load the recent data into our database
    $ beam make cpan-recent


Beam::Make allows an author to describe how to build some thing (a file, some data in a database, an image, a container, etc...) and the relationships between things. This is similar to the classic make program used to build some software packages.

Each thing is a recipe and can depend on other recipes. A user runs the beam make command to build the recipes they want, and Beam::Make ensures that the recipe's dependencies are satisfied before building the recipe.

This class is a Beam::Runnable object and can be embedded in other Beam::Wire containers.

Recipe Classes

Unlike make, Beam::Make recipes can do more than just execute a series of shell scripts. Each recipe is a Perl class that describes how to build the desired thing and how to determine if that thing needs to be rebuilt.

These recipe classes come with Beam::Make:

  • File - The default recipe class that creates a file using one or more shell commands (a la make)

  • DBI - Write data to a database

  • DBI::Schema - Create a database schema

  • DBI::CSV - Load data from a CSV into a database table

  • Docker::Image - Build or pull a Docker image

  • Docker::Container - Build a Docker container

Future recipe class ideas are:

  • Template rendering: Files could be generated from a configuration file or database and a template.

  • Docker compose: An entire docker-compose network could be rebuilt.

  • System services (init daemon, systemd service, etc...): Services could depend on their configuration files (built with a template) and be restarted when their configuration file is updated.


The Beamfile defines the recipes. To avoid the pitfalls of Makefile, this is a YAML file containing a mapping of recipe names to recipe configuration. Each recipe configuration is a mapping containing the attributes for the recipe class. The $class special configuration key declares the recipe class to use. If no $class is specified, the default Beam::Wire::File recipe class is used. All recipe classes inherit from Beam::Class::Recipe and have the name and requires attributes.

For examples, see the Beam::Wire examples directory on Github.

Object Containers

For additional configuration, create a Beam::Wire container and reference the objects inside using $ref: "<container>:<service>" as the value for a recipe attribute.


Target names in Beamfile should be regular expressions

This would work like Make's wildcard recipes, but with Perl regexp. The recipe object's name is the real name, but the recipe chosen is the one the matches the regexp.

Environment variables should interpolate into all attributes

Right now, the NAME=VALUE arguments to beam make only work in recipes that use shell scripts (like Beam::Make::File). It would be nice if they were also interpolated into other recipe attributes.

Recipes should be able to require wildcards and directories

Recipe requirements should be able to depend on patterns, like all *.conf files in a directory. It should also be able to depend on a directory, which would be the same as depending on every file, recursively, in that directory.

This would allow rebuilding a ZIP file when something changes, or rebuilding a Docker image when needed.

Beam::Wire should support the <container>:<service> syntax for references

The Beam::Wire class should handle the BEAM_PATH environment variable directly and be able to resolve services from other files without building another Beam::Wire object in the container.

Beam::Wire should support resolving objects in arbitrary data structures

Beam::Wire should have a class method that one can pass in a hash and get back a hash with any Beam::Wire object references resolved, including $ref or $class object.




Doug Bell <>


This software is copyright (c) 2020 by Doug Bell.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.