Kook Users' Guide
Preface
Kook is a software build tool such as Make, Ant, SCons or Cook. It is implemented in PHP and runs any platform PHP support. Basic command (copy, move, rename, mkdir, ...) is also implemented in PHP and allows you to execute platform-depended command.
Kook liken build process to cooking. Input file is called 'ingredient', output is 'product', task is 'recipe', build file is 'cookbook'. Kook generates products from ingredients according to recipes. You describe products, ingredients, and recipes in cookbook.
Features:
- Implemented in pure PHP5 and runs any platfrom which PHP5 supports.
- Input file (called 'cookbook') is named 'Kookbook.yaml', which is equivarent to 'Makefile' of Make or 'build.xml' of Ant.
- Cookbook's format is YAML which is much easier for human to read and write than XML.
- You can write any PHP code in Kookbook: 'if', 'foreach', and so on. It brings the power of PHP to Kook.
Kook is implemented in PHP5 because exception is supported only in PHP5 and not supported in PHP4. You need to install PHP5 before using Kook.
Caution! Kook is currently under experimental. It means that the design and specification of Kook may change frequently.
Table of Contents
Quick guide to YAML
YAML is a text-base format to describe stuctured data. The purpose of YAML is similar to XML but YAML is more friendly for human to read and write than XML.
You should learn about YAML because cookbook ('Kookbook.yaml') is described in YAML format. This chapter will help you to learn YAML in quickly. See the following page for details.
Sequence
Sequence is a list of element.
- aaa - bbb - ccc
[ aaa, bbb, ccc ]
These are equivarent to the following PHP code.
array('aaa', 'bbb', 'ccc')
Mapping
Mapping is a map or hash of pairs of key and value.
one: 1 two: 2 three: 3
{ one: 1, two: 2, three: 3 }
These are equivarent to the following PHP code.
array('one'=>1, 'two'=>2, 'three'=>3)
Combination of Sequence and Mapping
Sequence and mapping are nestable in each other.
The following is an example of a sequence of mappings.
- name: Foo
email: foo@mail.com
age: 30
married: yes
- name: Bar
email: bar@mail.org
gender: F
- { name: Baz, age: 19, married: no }
The above is equivarent to the following PHP code.
array(
array('name'=>'Foo', 'email'=>'foo@mail.com', 'age'=>30, 'married'=>TRUE),
array('name'=>'Bar', 'email'=>'bar@mail.com', 'gender'=>'F'),
array('name'=>'Baz', 'age'=>19, 'married'=>FALSE)
)
The following is an example of a mapping of sequences.
members: - Foo - Bar - Baz tasks: - write code - test code - write documents sub-projects: [ sub1, sub2 ]
The above is equivarent to the following PHP code.
array(
'members'=>array('Foo', 'Bar', 'Baz'),
'tasks'=>array('write code', 'test code', 'write documents'),
'sub-projects'=>array('sub1', 'sub2')
)
Scalar and Data Type
YAML determines data type of elemet automatically.
- foobar # string - 123 # integer - 3.14159 # float - true # boolean (true) - yes # boolean (true) - on # boolean (true) - false # boolean (false) - no # boolean (false) - off # boolean (false) - 2006-01-01 # date - 2006-01-01 00:00:00 # timestamp - 'true' # string - "false" # string
YAML data is represented by the combination of the followings.
- Collection (Sequecne and Mapping)
- Scalar (string, integer, float, boolean, ...)
This feature is similar to JSON. In fact, you can regard YAML's flow-style as JSON.
Block text
'|' means start of block-text. Block-text is convenient if string has several lines.
text1: |
foo
bar
baz
text2: |
foo
bar
baz
This is equivarent to the following PHP code.
array('text1'=>'foo
bar
baz
'),
'text2'=>'foo
bar
baz
')
)
Anchor and Alias
Anchor is feature to mark data. Alias is feature to refer anchored data.
- name: foo
desc: &anchor1 description
text: &anchor2 |
blocktext
blocktext
blocktext
- name: bar
desc: *anchor1
text: *anchor2
This is equivarent to the following PHP code.
$anchor1 = "description";
$anchor2 = <<<END
blocktext
blocktext
blocktext
END;
array(
array(
'name' => 'foo',
'desc' => $anchor1,
'text' => $anchor2,
),
array(
'name' => 'bar',
'desc' => $anchor1,
'text' => $anchor2,
),
);
Comment
YAML comment starts with the '#' character. Between '#' and end of line is YAML comment.
# comment
# comment
members: # comment
- name: Foo # comment
age: 19 # comment
YAML has only line comment.
Special Characters
YAML uses several characters to describe features.
| char | feature |
|---|---|
| [ | start of inline-style sequence |
| ] | end of inline-style sequence |
| { | start of inline-style mapping |
| } | end of inline-style mapping |
| - | sequence element in block-style |
| ? | mapping element in block-style |
| : | separator of key and value in block-style and flow-style |
| * | alias |
| & | anchor |
| ! | data type |
| # | comment |
| | | text in block-style |
| > | text in block-style |
Notice that these characters may cause YAML parse error if you don't quote them with single quotation or double quotation.
## OK - foo *bar* baz ## NG (because '*foo' means alias in YAML) - *foo* bar baz ## OK - '*foo* bar baz'
See YAML Cookbook or YAML specification for details.
Cookbook
Recipes
Cookbook should contains some recipes.
- 'product:' part represents filename which is generated by the recipe.
- 'desc:' part represents the description about the recipe. Description is showed when command-line option '-l' specified.
- 'ingreds:' part represents filenames which are required to generate product. The part takes sequence of ingredient names.
- 'method*:' part represents how to generate the product from the ingredients. The part is described in PHP code (tail asterisk '*' means that "this is PHP code").
In the 'method*:' part, some helper functions provided by Kook are available. For exaple, function 'k_sys()' invokes OS-depend command. See References for details about helper functions.
The following is an example of recipe definitions in cookbook.
recipes:
- product: hello
desc: generates hello command
ingreds: [ hello.o ]
method*: |
k_sys("gcc -g -o hello hello.o");
- product: hello.o
desc: compile 'hello.c' and 'hello.h'
ingreds: [ hello.c, hello.h ]
method*: |
k_sys("gcc -g -c hello.c");
The following is an example of invoking rook command. Command-line option '-l' shows recipes which have 'desc:' part. It means that recipes which have 'desc:' part are public recipes. Command-line option '-L' shows all recipes.
$ kook -l *** ERROR! 'Kookbook1.yaml': not found. $ kook hello *** ERROR! 'Kookbook1.yaml': not found.
One of the aim of Kook is fusion of 'declarative' and 'procedural'. Attributes of recipe are described in declarative format (=YAML) and steps how to generate product are described in procedural format (=PHP).
The benefits of this style are:
- Easy to read and write for human. Readability and Writeability is very important.
- Powerful to write complex logics. You can get power of PHP in YAML.
PHP is easy to read and write but not a little suitable for DSL(Domain Specific Language). Embedding PHP code in YAML is more suitable for DSL.
$product and $ingreds
Product and ingredient names are referable as local variable in recipe's 'method*:' part.
- Variable '$product' represents product.
- Variable '$ingreds' represents ingredients.
- Variable '$ingred' represents the first item of ingredients (= $ingreds[0]).
$product and $ingredsrecipes:
- product: hello
desc: generates hello command
ingreds: [ hello.o ]
method*: |
k_sys("gcc -g -o $product $ingred");
# or k_sys("gcc -g -o $product {$ingreds[0]}");
- product: hello.o
desc: compile 'hello.c' and 'hello.h'
ingreds: [ hello.c, hello.h ]
method*: |
k_sys("gcc -g -c $ingred");
# or k_sys("gcc -g -c {$ingreds[0]}");
$ kook hello *** ERROR! 'Kookbook2.yaml': not found.
Specific recipe and generic recipe
Specific recipe is a recipe which is combined to a certain file. Product name of specific recipe is a concrete file name.
Generic recipe is a recipe which is combined to a pattern of file name. Product name of generic recipe is a pattern with metacharacter or regular expression used by preg_match().
Kook converts file name pattern into regular expression. For example, file name pattern '*.o' is coverted to regular expression '/^(.*)\.o$/', and '*.??.txt' to '/^(.*)\.(.)(.)\.txt$/'. Matched strings with metacharacter ('*' or '?') are accessable by '$(1)', '$(2)', ... in recipe definition and local variable '$m' in 'method*:' part.
recipes:
## specific recipe
- product: hello
desc: generates hello command
ingreds: [ hello.o ]
method*: |
k_sys("gcc -g -o $product $ingred");
## generic recipe
- product: *.o # or /^(.*)\.o$/
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c, $(1).h ]
method*: |
k_sys("gcc -g -c $(1).c");
# or "gcc -g -c {$m[1]}.c"
# or "gcc -g -c $ingred"
$ kook -l *** ERROR! 'Kookbook3.yaml': not found. $ kook hello *** ERROR! 'Kookbook3.yaml': not found.
It is able to specify regular expression instead of filename pattern.
For example, /^(.*)\.o$/ is available as product instead of *.o.
Grouping in regular expression is referable by $(1), $(2), ... in the same way.
Specific recipe is prior to generic recipe. For example, recipe 'hello.o' is used and recipe '*.o' is not used to generate 'hello.o' when target product is 'hello.o' in the following example.
recipes:
- product: hello.o
ingreds: [ hello.c ]
method*: |
k_sys("gcc -g -O2 -o $product $ingred");
- product: *.o
ingreds: [ *.c, *.h ]
method*: |
k_sys("gcc -g -o $product $ingred");
Toppings
There may be a case that ingredient file exists or not. For example, product 'foo.o' depends on 'foo.c' and 'foo.h', while product 'bar.o' depends only on 'bar.c'.
In the case, you can use 'toppings:' part which resolve the problem.
For example when 'toppings: [hello.h]' is specified in recipe definition, Kook detect dependency as following.
- If file 'hello.h' exists, product 'hello.o' depends on ingredients 'hello.c' and 'hello.h'.
- If file 'hello.h' doesn't exist, product 'hello.o' depends on only 'hello.c'.
'toppings:' part is useful especially when used with generic recipes.
recipes:
## specific recipe
- product: hello
desc: generates hello command
ingreds: [ hello.o ]
method*: |
k_sys("gcc -g -o $product $ingred");
## generic recipe
- product: *.o
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: |
k_sys("gcc -g -c $ingred"); # or "gcc -g -c $(1).c"
$ kook hello *** ERROR! 'Kookbook4.yaml': not found.
Symbolic Recipes
Symbolic recipe is a recipe which is not combined with any files. Product name of symbolic recipe starts with colon (':').
For example, symbolic recipe :clean is a recipe to delete '*.o' files and is not combined to file ':clean'.
Also symbolic recipe :all is a recipe to call recipe of 'hello' and is not combined to file ':all'.
recipes:
## specific recipe
- product: hello
desc: generates hello command
ingreds: [ hello.o ]
method*: |
k_sys("gcc -g -O2 -o $product $ingred");
## generic recipe
- product: *.o
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: |
k_sys("gcc -g -O2 -c $ingred"); # or "gcc -g -c $(1).c"
## symbolic recipes
- product: :clean
method*: |
k_delete('*.o'); # remove '*.o' files
- product: :all
ingreds: [ hello ]
$ kook -l *** ERROR! 'Kookbook5.yaml': not found. $ kook :all *** ERROR! 'Kookbook5.yaml': not found. $ ls Kookbook.yaml hello hello.c hello.h hello.o $ kook :clean *** ERROR! 'Kookbook5.yaml': not found. $ ls kookbook.yaml hello hello.c hello.h
Kook have several well-known symbolic product. Symbolic recipes which product is contained in the following list are got public automatically.
- :all
- create all products
- :clean
- remove by-products
- :clear
- remove all products and by-products
- :deploy
- deploy products
- :config
- configure
- :setup
- setup
- :install
- install products
- :test
- do test
Properties
Property is a pair of name and value. You can set properties in cookbook.
You can get property value with '$(name)' notation in property definition and recipe definition. And properties are accessable as local variable in 'method*' part of recipe definition.
Property name should match to regular expression '/^[_a-zA-Z]\w*$/'. Notice that period ('.') or hyphen ('-') are not available as property name character.
properties:
- cc: gcc
- c_flags: -g -O2
- basename: hello
recipes:
## specific recipe
- product: $(basename)
desc: generates $(basename) command
ingreds: [ $(basename).o ]
method*: |
k_sys("$cc $c_flags -o $product $ingred");
## generic recipe
- product: *.o
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: |
k_sys("$cc $c_flags -c $ingred"); # or "$cc $c_flags -c $(1).c"
## symbolic recipes
- product: :clean
method*: |
k_delete('*.o'); # remove '*.o' files
- product: :all
ingreds: [ $basename ]
$ kook hello *** ERROR! 'Kookbook6.yaml': not found.
Properties are shown when command-line option '-l' is specified.
And it is able to overwrite properties in command-line option '--propname=propvalue'.
Properties specified in command-line are prior to that in Kookbook.
$ kook -l *** ERROR! 'Kookbook6.yaml': not found. $ kook -l --basename=foobar *** ERROR! 'Kookbook6.yaml': not found.
Property file is another way to specify properties. If you have create property file 'Kookbook.props' or 'Properties.yaml', kook command automatically read it and set properties.
basename: hello c_flags: -g -O2
Property value can be specified in both YAML format and PHP code. If you append '*' in tail of property name, Kook regard it's value as PHP code. Property value is to be refered by '$(propname)' in YAML and by '$propname' in PHP code.
properties:
- srcdir: src/main/java
- junit_jar: lib/junit.jar
- path_elems: [ '.', $(srcdir), $(junit_jar) ]
- classpath*: join(PATH_SEPARATOR, $path_elems)
recipes:
- product: :echo
method*: |
echo var_export($classpath); #=> '.:src/main/java:lib/junit.jar'
Parameters
Parameters are similar to properties but have the following differences.
- Not able to override parameter value in command-line option nor property file.
- Not shown with command-line option '-l' (but shown with '-L').
You can consider properties as 'global variables' or 'public variable', and parameters as 'local variables' or 'private variable'.
Similar to properties, parameters value can be refered by '$(paramname)' in YAML and by '$paramname' (local variable) in PHP code.
There is a special parameter 'kook_product'. If the parameter is set, kook regard it as the default target product when target product is not specified in command-line.
properties:
- cc: gcc
- c_flags: -g -O2
parameters:
- basename: hello
- kook_product: $(basename) # default product when no product
# specified in command-line
recipes:
## specific recipe
- product: $(basename)
desc: generates $(basename) command
ingreds: [ $(basename).o ]
method*: |
k_sys("$cc $c_flags -o $basename $basename.c");
# or k_sys("$cc $c_flags -o $product $ingred");
## generic recipe
- product: *.o
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: |
k_sys("$cc $c_flags -c $ingred");
## symbolic recipes
- product: :clean
method*: |
k_delete('*.o'); # remove '*.o' files
- product: :all
ingreds: [ $(basename) ]
$ kook -L *** ERROR! 'Kookbook7.yaml': not found. $ kook *** ERROR! 'Kookbook7.yaml': not found.
Material
There is an exception in any case. Assume that you have a file 'optparse.o' which is supplied by other developer and no source. Kook will try to find 'optparse.c' and failed in the result.
Using 'materials:' part, you can tell Kook that 'optparse.o' is not a product .
properties:
- cc: gcc
- c_flags: -g -O2
parameters:
- basename: hello
- kook_product: $(basename)
materials:
- optparse.o
recipes:
## specific recipe
- product: $(basename)
desc: generates $(basename) command
ingreds: [ $(basename).o, optparse.o ]
method*: |
k_sys("$cc $c_flags -o $product $ingred optparse.o");
## generic recipe
- product: *.o
desc: compile '*.c' and '*.h'
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: |
k_sys("$cc $c_flags -c $ingred"); # or "$cc $c_flags -c $(1).c"
## symbolic recipes
- product: :clean
method*: |
k_delete('*.o');
- product: :all
ingreds: [ $(basename) ]
$ kook *** ERROR! 'Kookbook8.yaml': not found.
Other features
Invoke Recipes Forcedly
Command-line option '-F' invokes recipes forcedly, it means that timestamp of files are ignored.
recipes:
- product: hello
ingreds: [ hello.o ]
method*: |
k_sys("gcc -o $product $ingred");
- product: hello.o
ingreds: [ hello.c, hello.h ]
method*: |
k_sys("gcc -c $ingred");
## create 'hello' $ kook hello *** ERROR! 'Kookbook10.yaml': not found. ## 'hello' is newer than 'hello.c' and 'hello.h' $ kook hello *** ERROR! 'Kookbook10.yaml': not found. ## create 'hello' forcedly $ kook -F hello *** ERROR! 'Kookbook10.yaml': not found.
Validation check for Cookbook
Command-line option '-c' do validation checks for cookbook. It checks schema check of cookbook and PHP syntax check.
property: # 'properties:' is correct
- cc: gcc
- c_flags: -g -O2
recipes:
- product: hello
method*: |
k_sys("$cc $c_flags hello.c");
k_rename('a.out', 'hello');
$ kook -c *** ERROR! 'Kookbook11.yaml': not found.
properties:
- cc: gcc
- c_flags: -g -O2
recipes:
- product: hello
method*: |
k_sys("$cc $c_flags hello.c");
k_rename('a.out', 'hello', ); # extra comma
$ kook -c *** ERROR! 'Kookbook12.yaml': not found.
Nested Array
You can specify not only filenames but also array of filenames as ingredient on 'ingreds:', 'toppings:', 'byprods:' and 'coprods:'. In addition, nested arrays are also available. These arrays are flattened by kook.
parameters:
- project: hello
- src_files*: glob('lib/*.php') # array
- text_files: [README, ChangeLog, COPYING] # array (sequence)
- all_files: [$(src_files), $(text_files)] # nested array
recipes:
- product: :inspect
ingreds: [ package.xml, $(all_files) ] # nested array will be flatten
method*: |
# $all_files is a nested sequence
echo "*** \$all_files (nested)\n";
var_export($all_files);
echo "\n";
# $ingreds is flattened
echo "*** \$ingreds (flattened)\n";
var_export($ingreds);
echo "\n";
$ kook :inspect *** ERROR! 'Kookbook13.yaml': not found.
Preparation
It is able to load external PHP scripts and to define functions with 'preparation*:' section. You can write any PHP code in 'preparation*:' section (tail asterisk '*' means that 'this is PHP code').
'preparation*:' section is evaluated by kook before evaluating 'properties:', 'parameters:', and 'recipes:' sections. Functions you defined in 'preparation*:' section are available in 'properties:', 'parameters:', or 'recipe:' section.
preparation*: |
require_once('my-util.php'); # load external PHP script
function my_join_path($array) { # define original function
$buf = array();
foreach ($array as $item) {
if ($item) {
$buf[] = $item;
}
}
return join($buf, PATH_SEPARATOR);
}
parameters:
- path_elems: [ '.', src/main/java, null, '', lib/junit.jar ]
- classpath*: my_join_path($path_elems)
Recipe Listing
Command-line option '-l' shows list of properties and recipes which has description and '-L' shows list of properties, parameters, and all of recipes.
properties:
- cc: gcc
- c_flags: -g -O2
parameters:
- basename: hello
- kook_product: $(basename)
recipes:
# this will be shown with '-l' option because it has 'desc:'
- product: hello
desc: create hello command
# this will not be shown with '-l' option because no 'desc:'
- product: *.o
#desc: no comment
$ kook -l *** ERROR! 'Kookbook14.yaml': not found. $ kook -L *** ERROR! 'Kookbook14.yaml': not found.
Kook set description of symbolic recipe automatically if product name is ':all', ':clean', ':clear', or ':test'. This means that these symbolic recipes are listed automatically even when you omit recipe description.
recipes:
# the following are shown regardless no-description.
- product: :all
#desc: no description
- product: :clean
#desc: no description
- product: :clear
#desc: no description
- product: :test
#desc: no description
$ kook -l *** ERROR! 'Kookbook15.yaml': not found.
Recipe-local Parameters
Recipe can have it's own local parameters. Recipe local parameters cannot be refered by other recipes.
This is convenient to override property or parameter specified in cookbook, and to share method definition with other recipe by YAML anchor and alias.
parameters:
- c_flags: -g -Wall
recipes:
- product: *.o
ingreds: [ $(1).c ]
toppings: [ $(1).h ]
method*: &gcc |
k_sys("gcc $c_flags -c $ingred");
- product: foo.o
ingreds: [ foo.c ]
params:
- c_flags: $(c_flags) -O2
method*: *gcc
$ kook -n hello.o *** ERROR! 'Kookbook16.yaml': not found. $ kook -n foo.o *** ERROR! 'Kookbook16.yaml': not found.
By-Products and Co-Products
'byprods:' and 'coprods:' sections represent by-products and co-products of the recipe. Currently, these section have no feature than description.
Local variables $byprods and $coprods in 'method*:' section represents by-products and co-products of the recipe. Local variable $byprod is equivarent to $byprods[0] and $coprod is equivarent to $coprods[0].
recipes:
- product: *.dvi
ingreds: [ $(1).tex ]
byprods: [ $(1).aux, $(1).log ]
method*: |
k_sys("latex $ingred");
k_delete($byprods);
References
Filesystem Functions
The following functions are available in 'method*:' part of recipes.
- k_copy(path1, path2)
-
Copy a file or direcotry to other file or directory.
Notice that k_copy() cannot copy file or directory to existing directory.
If you want to copy file or directory into a directory, use k_mcopy().
k_copy("file", "file2"); # OK k_copy("file", "newfile"); # OK k_copy("file", "dir1"); # NG - use k_mcopy() instead of k_copy() k_copy("dir", "dir2"); # NG if dir2 already exists k_copy("dir", "newdir"); # OKThe reason why k_copy() cannot copy files to directory is to prevent creating miss-typed filename. For example, unix command 'cp' creates new file if destination file is not exist even when you have typo destination file name. It's not good user-interface.## you are intended to copy 'index.html' to 'public_html/index.html', ## but new file 'pubic_html' will be created because of typo. $ cp index.html pubic_html # 'pubic_html' is typo of 'public_html'
- k_mcopy(dir, path1, path2, ...)
-
Copy several files or directories to the target directory.
Notice that k_mcopy() doesn't allow to change file names.
k_mcopy("dir", "file1", "file2"); # OK k_mcopy("dir/file1", "file1"); # NG - use k_copy() k_mcopy("dir", glob("*.php"), glob("*.html")); # OK
- k_clone(dir, path1, path2, ...)
- Equivarent to k_mcopy().
- k_rename(old_path, new_path)
-
Rename a file or directory to new name.
k_rename("file", "file2"); # OK k_rename("file", "dir"); # NG k_rename("dir", "dir2"); # NG if dir2 already exists k_rename("dir", "newdir"); # OKThe reason why k_rename() cannot move files to directory is to prevent creating miss-typed filename. For example, unix command 'mv' creates new file if destination file is not exist even when you have typo destination file name. It's not good interface.## you are intended to rename 'index.html' to 'public_html/index.html', ## but new file 'pubic_html' will be created because of typo. $ mv index.html pubic_html # 'pubic_html' is typo of 'public_html'
- k_move(dir, path1, path2, ...)
-
Move several files or directories to the target directory.
Notice that k_move() doesn't rename file or directory.
It only moves location of files or directories.
k_move("dir", "file1", "file2"); # OK k_move("dir/file1", "file1"); # NG - use k_rename() k_move("dir", glob("*.php"), glob("*.html")); # OK
- k_delete(path1, path2, .... )
-
Delete files or directories. Direcotry is deleted recursively.
k_move("file1", "file2", "dir1", "dir2"); # OK k_move(glob("src/**/*.o"), glob("tmp/**/*")); # OK
- k_mkdir(dir1, dir2, .... )
-
Make directories. It is equivarent to 'mkdir -p' command.
k_mkdir("src/main/php/Kook"); # OK even if 'src/main/php' doesn't exist
- k_store(dir, path1, path2, ...)
-
Copy files or directories to target directory with path-structure keeped.
# copy "bin/*" and "lib/**/*.php" to "dir/bin/*" and "dir/lib/**/*.php" k_store("dir", "bin/*", "lib/**/*.php");
- k_store2(dir, prefix, path1, path2, ...)
-
Copy files or directories to target directory with path-structure keeped,
and prefix is removed from path.
# copy "/var/tmp/foo/bar/*" to "dir/foo/bar/*" k_store2("dir", "/var/tmp/", "/var/tmp/foo/bar/*")
- k_sys(command-string)
-
Execute platform depended command such as compile command, archive command, and so on.
k_sys("gcc -O2 -ansi -Wall -o hello hello.c");
- k_edit(replacer, file1, file2, ...)
-
Edit content of files according to replacer.
replacer is a list of pair of regular expression and replace-string.
$replacer = array( array('/\$Release\$/', '2.0.1'), array('/\$Copyright\$/', 'copyright(c) 2006 kuwata-lab.com'), ); k_edit($replacer, "src/**/*.php");
- k_touch(path1, path2, ...)
-
Touch files or directories.
k_touch("hello.c");
- k_echo(str)
-
Echo string.
k_echo("comment");
- k_chdir(dir)
-
Change directory. This function returns the directory path which is before changing directory.
$dir = k_chdir("main/src");
- k_backdir(dir)
-
Change direcotry to back. ex:
$cwd = k_chdir('test/'); # change directory k_sys('phpunit FooBarTest'); k_backdir($cwd); # back to the directory
- k_chmod(mode, path1[, path2, ...])
-
Change permission of files or directories.
mode should be octal number.
k_chmod(0777, "lib/**/*.php");
- k_chmod_files(mode, path1[, path2, ...])
-
Change permission of files. If path is directory then ignored.
mode should be octal number.
k_chmod_files(0777, "lib/**/*");
- k_chmod_dirs(mode, path1[, path2, ...])
-
Change permission of directories. If path is not a directory then ignored.
mode should be octal number.
k_chmod_dirs(0777, "lib/**/*");
- k_tar_cf(archive.tar, path1[, path2, ...])
-
Create TAR file.
k_tar_cf("kook.tar", "lib/**/*.php", "bin", "README.txt");
- k_tar_czf(archive.tar.gz, path1[, path2, ...])
-
Create TAR file.
k_tar_czf("kook.tar.gz", "lib/**/*.php", "bin", "README.txt");
- k_tar_cjf(archive.tar.bz2, path1[, path2, ...])
-
Create TAR file.
k_tar_cjf("kook.tar.bz2", "lib/**/*.php", "bin", "README.txt");
The above functions can take arrays as file or directory name. For example, the following code is available.
## specify filenames in strings
k_mcopy('dir', 'file1.txt', 'file2.txt', 'file3.txt');
## specify filenames with filename pattern
k_mcopy('dir', '*.txt');
## specify filenames in array.
$files = array('file1.txt', 'file2.txt', 'file3.txt');
k_mcopy($files, 'dir');
The following file pattern is available.
-
* - Matches sequence of any character.
-
? - Matches a character.
-
{a,b,c} - Matches a or b or c.
-
**/ - Matches directory recursively.
Helper Functions
The following fuctions are available at 'properties:', 'parameters:', 'preparation*:', and 'method*:' in cookbook.
- kook_glob($pattern)
-
Extended glob() function. The difference between kook_glob() and glob() is the following:
- '**/' pattern support. It matches directory recursively.
- '{x,y,z}' pattern support. It is equivarent to GLOB_BRACE option.
example code:$files = kook_glob("lib/**/*.php"); var_export($files);example result:array ( 0 => 'lib/main/foo.php', 1 => 'lib/main/bar.php', 2 => 'lib/baz.php', )
- kook_array_prefix($array, $prefix)
-
Add $prefix to head of each elements in $array.
This is easier to understand than
preg_replace('/^/', $prefix, $array).example code:$arr = array('foo', 'bar', 'baz'); $arr2 = kook_array_prefix($arr, 'lib/'); var_export($arr2);result:array ( 0 => 'lib/foo', 1 => 'lib/bar', 2 => 'lib/baz', )
- kook_array_suffix($array, $suffix)
-
Add $suffix to tail of each elements in $array.
This is easier to understand than
preg_replace('/$/', $suffix, $array).example code:$arr = array('foo', 'bar', 'baz'); $arr2 = kook_array_suffix($arr, '.php'); var_export($arr2);result:array ( 0 => 'foo.php', 1 => 'bar.php', 2 => 'baz.php', )
- kook_array_sandwich($array, $postfix, $suffix)
-
Add $prefix to head and $suffix to tail of each elements in $array.
example code:
$arr = array('foo', 'bar', 'baz'); $arr2 = kook_array_sandwich($arr, 'lib/', '.php'); var_export($arr2);result:array ( 0 => 'lib/foo.php', 1 => 'lib/bar.php', 2 => 'lib/baz.php', )
- kook_array_flatten($array)
-
Flatten nested array to a normal array.
example code:
$nested_arr = array('a', array('b', 'c', array('d'), 'e')); $normal_arr = kook_array_flatten($nested_arr); var_export($normal_arr);result:array ( 0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd', 4 => 'e', )
this is useful especially with 'glob()'.
$arr = array(glob('*.php'), glob('*.html'), 'README'); $files = kook_array_flatten($arr);
- kook_array_matched($array, $regex)
-
Select elements which matches to $regex in $array.
PHP function 'preg_match()' is used internally so that $regex should be perl-style regular expression.
example code:
$arr = array('foo', 'bar', 'baz'); $arr2 = kook_array_matched($arr, '/^ba/'); var_export($arr2);result:array ( 0 => 'bar', 1 => 'baz', )
kook_array_matched() is equivarent to the following code.
function kook_array_matched($array, $regexp) { $array = preg_grep($regexp, $array); return array_values($array); }
- kook_array_unmatched($array, $regex)
-
Select elements which doesn't match to $regex in $array.
PHP function 'preg_match()' is used internally so that $regex should be perl-style regular expression.
example code:
$arr = array('foo', 'bar', 'baz'); $arr2 = kook_array_unmatched($arr, '/^ba/'); var_export($arr2);result:array ( 0 => 'foo', )
This is useful especially exclude 'CVS' directory
$files = kook_glob('**/*'); $files = kook_array_unmatched($files, '/\/CVS\//')kook_array_unmatched() is equivarent to the following code.
function kook_array_unmatched($array, $regexp) { $array = preg_grep($regexp, $array, PREG_GREP_INVERT); return array_values($array); }
Command-line options
Usage: kook [-hvTnqQFlLc] [-b bookname] product
Options:
- -h
- Print help and quit.
- -v
- Print version and quit.
- -l
- List properties and described recipes.
- -L
- List all propeties, parameters, and recipes.
- -q
- Quiet mode.
- -Q
- More quiet mode.
- -F
- Force recipes to execute (ignore timestamps).
- -n
- No execution (print 'k_xxx()' command functions).
- -N
- No execution (print 'method*:' part of recipes).
- -T
- Don't untabify cookbook. In default Kook command expands tab characters in cookbook into spaces, because YAML parser doesn't allow cookbook (= YAML document) to include tab characters. Command-line option '-T' doesn't expand tab characters.
- -c
- Validation check of cookbook.
- -b bookname
- Cookbook filename.
- -P propfile
- Property filename (default is 'Kookbook.props' and 'properties.yaml'). '-P -' means not to read property file.
- --propname=propvalue
- Property name and value.