proj /prɔʣ/ – create files and directories based on templates.
Proj is a tool born from the desire to automate the tedious tasks when starting to work on a website. Proj creates files and directories based on so called “templates” which define a directory structure and actions to perform after processing a template, such as initializing a git repository. Templates are general enough to be useful for any kind of task that benefits from any sort of scaffolding.
Proj tries to not break any things and does not overwrite any files by default. Single files can be overwritten in the target directory by explicitly saying so in the template. If anything goes wrong during the processing of a template, all files created so far are deleted in order to not leave the target directory in any inconsistent state.
- Put the contents of the
libdirectory into a location on yourPERL5LIB. - Copy
bin/proj-createto a directory on yourPATH. - Copy
examplesto~/.proj.das a starting point for creating your own templates. - Run
proj-create static-siteto create the skeleton for a static website in the current directory.
Templates are processed with proj-create:
proj-create [[-i|--include] INCLUDE] TEMPLATE [DEFINITION ...]
The option -i adds directory INCLUDE to the list of directories to
search for templates. The -i option can be used more than once.
TEMPLATE is the name of the template to create. DEFINITION is a
key-value pair separated by an equal sign, e.g. title=Foo. All current
environment variables and definitions are made available as variables
within files processed by Template Toolkit.
By default, proj-create looks for templates in $HOME/.proj.d and the
directories given in the environment variable PROJ_PATH. Multiple
directories can be given in that variable by separating them with a
colon (:).
Before running, proj-create evaluates the file $HOME/.proj.pl as
perl code if it exists. Currently this is only useful for adding new
handlers.
Templates are regular perl code that is evaluated when processing a
template. Proj is instrumented by setting certain variables in the
template, but any perl code can be used in a template. Each template
requires an additional directory of the same name suffixed with .d to
exist. This directory contains all the files referenced in the
template.
$tree = [
[ dir => html =>
[ file => 'index.html' ]],
[ dir => template =>
[ file => 'default.html.tt' ]],
[ dir => css =>
[ file => "devel.css" ],
[ file => "yaml" ],],
[ dir => js =>
[ http => 'code.jquery.com/jquery.min.js'],
[ http => 'html5shim.googlecode.com/svn/trunk/html5.js'],
[ http => 'code.jquery.com/jquery.js'],],
[ dir => 'images' ],
[ dir => 'perl' ],
[ dir => 'cgi-bin'],
[ dir => 'log' ],
[ dir => 'tmp' ],
[ dir => 'conf',
[ file => 'lighttpd.conf' ]],
];
$after = [
'git init',
'git add .',
'git commit -m "initial commit"',
];The following variables have a special meaning in templates:
$tree- this variable describes the directory structure that is to
be created. Its value has to be an arrayref of entries,
where each entry is of the form
[ $HANDLER, @ARGS ].$HANDLERnames a function in the packageProj::Handlerand@ARGSare the arguments passed to that function. If any coderefs in an entry are replaced by the value obtained by calling the referenced function without arguments. $before,$after- these variables provide hooks for running code
or shell commands before and after the structure defined in
$treehas been created. Their values are arrayrefs of strings or coderefs. A string is taken as a shell command and executed withsystem, a coderef is called without arguments.
Templates are evaluated within the package Proj::Template, so any
functions defined in that packed can be used in the template without
importing any modules. One function, extends, is defined by default
in that package. It takes a list (NB! not an arrayref) of template
names and creates those in the current directory. This is mainly useful
for extending templates (e.g. to customize shared templates for the
local environment).
The following handlers are defined by default for use in $tree
entries:
dir $name @children- creates directory
$nameand processes child entries@children. The current directory is set to$namewhile processing@children.Example:
$tree = [ [ dir => 'foo', [file => 'bar']], ];
file $name \%options- creates file
$nameby copying it from the template directory. There are four locations relative to the template directory that are checked in order to find the source file for$name(where$CWDis the current directory relative to the template directory):Location Example $name.ttbar.tt$namebar$PWD/$name.ttfoo/bar.tt$PWD/$namefoo/barThe first existing file is used. If the file name equal
$name.tt, then the file will be processed as a Template Toolkit template.If
$options->{overwrite}is set to a true value,$namein the target directory will be overwritten if it exists. http $url $filename- Uses
LWP::Simple::mirror($url)in the template directory before copying the file named in$urlto the target directory. If$filenameis given, it will be used as the target file name instead.Example:
[http => 'code.jquery.com/jquery.js']
It is possible to define own handlers with the function defhandler in
the proj configuration file (~/.proj.pl). defhandler takes two
arguments: the name of the new handler and a coderef to associate with
that name. It is basically just syntactic sugar for installing
functions into Proj::Handler.
A function installed with defhandler is called with a variable number
of arguments. The first argument is always a instance of Proj, all
other arguments are taken from the entry in $tree, excluding the
handler name. The current working directory is set according to the
location in $tree. If the handler creates any files that should be
deleted in case of error, those file names should be registered with the
_register(@filenames) method of the Proj instance. To abort the
processing of the current template, use the _fail($message) method of
the Proj instance. This exits the program with exit code 1 and
removes all files created during this run.
A git handler that clones a repository if it doesn’t exist already
and otherwise pulls the newest version could look like this:
# in file ~/.proj.pl
defhandler git => sub {
my ($proj,$repo_url,$opts) = @_;
my $repo_name = (split '/',$repo_url)[-1];
if (-e $repo_name) {
$proj->_diag("pull $repo_url");
qx{pushd $repo_name; git pull; popd};
}
else {
$proj->_diag("clone $repo_url");
$opts ||= '';
qx{git clone $opts $repo_url};
}
};- add on-line help to proj-create
- add comments to the code
- add “sync” handler for just copying files/directories (maybe with rsync if available)
- make the “http” handler operate on the current directory, not the template source directory
- react to UNIX signals (e.g. clean up on SIGKILL or SIGINT)
Proj requires the following perl modules to be installed:
- Template
- LWP::Simple
The source code for Proj can be found on github: http://github.com/dhamidi/proj.
Copyright (C) 2013 Dario Hamidi <dario.hamidi@gmail.com>.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.