Skip to content

Commit

Permalink
Evaluate everything as ERB templates by default. Added "files" folder…
Browse files Browse the repository at this point in the history
…. v1.2.0
  • Loading branch information
kenn committed Apr 13, 2013
1 parent 3cf1bac commit c329b11
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@
.bundle
Gemfile.lock
pkg/*
sandbox
28 changes: 11 additions & 17 deletions README.md
Expand Up @@ -18,6 +18,7 @@ Its design goals are:

### What's new:

* v1.2: Evaluate everything as ERB templates by default. Added "files" folder.
* v1.1: "set -e" by default. apt-get everywhere in place of aptitude. Linode DNS support for DigitalOcean instances.
* v1.0: System functions are refactored into sunzi.mute() and sunzi.install().
* v0.9: Support for [DigitalOcean](https://www.digitalocean.com) setup / teardown.
Expand Down Expand Up @@ -89,25 +90,24 @@ sunzi/
roles/ # when role is specified, scripts here will be concatenated
db.sh # to install.sh in the compile phase
web.sh
files/ # put any files to be transferred
compiled/ # everything under this folder will be transferred to the
# remote server (do not edit directly)
```

How do you pass dynamic values to a recipe?
-------------------------------------------
How do you pass dynamic values?
-------------------------------

In the compile phase, attributes defined in `sunzi.yml` are split into multiple files in `compiled/attributes`, one per attribute. We use filesystem as a sort of key-value storage so that it's easy to use from shell scripts.
There are two ways to pass dynamic values to the script - ruby and bash.

The convention for argument passing to a recipe is to use `$1`, `$2`, etc. and put a comment line for each argument.
**For ruby (recommended)**: Make sure `eval_erb: true` is set in `sunzi.yml`. In the compile phase, attributes defined in `sunzi.yml` are accessible from any files in the form of `<%= @attributes.ruby_version %>`.

For instance, given a recipe `greeting.sh`:
**For bash**: In the compile phase, attributes defined in `sunzi.yml` are split into multiple files in `compiled/attributes`, one per attribute. Now you can refer to it by `$(cat attributes/ruby_version)` in the script.

```bash
# Greeting
# $1: Name for goodbye
# $2: Name for hello
For instance, given the following `install.sh`:

echo "Goodbye $1, Hello $2!"
```bash
echo "Goodbye <%= @attributes.goodbye %>, Hello <%= @attributes.hello %>!"
```

With `sunzi.yml`:
Expand All @@ -118,13 +118,7 @@ attributes:
hello: Sunzi
```

Then, include the recipe in `install.sh`:

```bash
source recipes/greeting.sh $(cat attributes/goodbye) $(cat attributes/hello)
```

Now, you get the following result. Isn't it awesome?
Now, you get the following result.

```
Goodbye Chef, Hello Sunzi!
Expand Down
34 changes: 22 additions & 12 deletions lib/sunzi/cli.rb
@@ -1,4 +1,5 @@
require 'open3'
require 'ostruct'

module Sunzi
class Cli < Thor
Expand Down Expand Up @@ -43,12 +44,13 @@ def self.source_root
end

def do_create(project)
template 'templates/create/.gitignore', "#{project}/.gitignore"
template 'templates/create/sunzi.yml', "#{project}/sunzi.yml"
template 'templates/create/install.sh', "#{project}/install.sh"
template 'templates/create/recipes/sunzi.sh', "#{project}/recipes/sunzi.sh"
template 'templates/create/roles/db.sh', "#{project}/roles/db.sh"
template 'templates/create/roles/web.sh', "#{project}/roles/web.sh"
copy_file 'templates/create/.gitignore', "#{project}/.gitignore"
copy_file 'templates/create/sunzi.yml', "#{project}/sunzi.yml"
copy_file 'templates/create/install.sh', "#{project}/install.sh"
copy_file 'templates/create/recipes/sunzi.sh', "#{project}/recipes/sunzi.sh"
copy_file 'templates/create/roles/db.sh', "#{project}/roles/db.sh"
copy_file 'templates/create/roles/web.sh', "#{project}/roles/web.sh"
copy_file 'templates/create/files/.gitkeep', "#{project}/files/.gitkeep"
end

def do_deploy(target, role, force_sudo)
Expand Down Expand Up @@ -102,7 +104,7 @@ def do_compile(role)
@config = YAML.load(File.read('sunzi.yml'))

# Break down attributes into individual files
(@config['attributes'] || []).each {|key, value| create_file "compiled/attributes/#{key}", value }
(@config['attributes'] || {}).each {|key, value| create_file "compiled/attributes/#{key}", value }

# Retrieve remote recipes via HTTP
cache_remote_recipes = @config['preferences'] && @config['preferences']['cache_remote_recipes']
Expand All @@ -112,15 +114,23 @@ def do_compile(role)
end

# Copy local files
Dir['recipes/*'].each {|file| copy_file File.expand_path(file), "compiled/recipes/#{File.basename(file)}" }
Dir['roles/*'].each {|file| copy_file File.expand_path(file), "compiled/roles/#{File.basename(file)}" }
(@config['files'] || []).each {|file| copy_file File.expand_path(file), "compiled/files/#{File.basename(file)}" }
@attributes = OpenStruct.new(@config['attributes'])
copy_or_template = (@config['preferences'] && @config['preferences']['eval_erb']) ? :template : :copy_file
Dir['recipes/*'].each {|file| send copy_or_template, File.expand_path(file), "compiled/recipes/#{File.basename(file)}" }
Dir['roles/*'].each {|file| send copy_or_template, File.expand_path(file), "compiled/roles/#{File.basename(file)}" }
Dir['files/*'].each {|file| send copy_or_template, File.expand_path(file), "compiled/files/#{File.basename(file)}" }
(@config['files'] || []).each {|file| send copy_or_template, File.expand_path(file), "compiled/files/#{File.basename(file)}" }

# Build install.sh
if role
create_file 'compiled/install.sh', File.binread('install.sh') << "\n" << File.binread("roles/#{role}.sh")
if copy_or_template == :template
template File.expand_path('install.sh'), 'compiled/_install.sh'
create_file 'compiled/install.sh', File.binread('compiled/_install.sh') << "\n" << File.binread("compiled/roles/#{role}.sh")
else
create_file 'compiled/install.sh', File.binread('install.sh') << "\n" << File.binread("roles/#{role}.sh")
end
else
copy_file File.expand_path('install.sh'), 'compiled/install.sh'
send copy_or_template, File.expand_path('install.sh'), 'compiled/install.sh'
end
end

Expand Down
Empty file.
4 changes: 2 additions & 2 deletions lib/templates/create/install.sh
Expand Up @@ -25,7 +25,7 @@ if sunzi.install "sysstat"; then
fi

# Set RAILS_ENV
environment=$(cat attributes/environment)
environment=<%= @attributes.environment %>

if ! grep -Fq "RAILS_ENV" ~/.bash_profile; then
echo 'Setting up RAILS_ENV...'
Expand All @@ -35,7 +35,7 @@ fi

# Install Ruby using RVM
source recipes/rvm.sh
ruby_version=$(cat attributes/ruby_version)
ruby_version=<%= @attributes.ruby_version %>

if [[ "$(which ruby)" != /usr/local/rvm/rubies/ruby-$ruby_version* ]]; then
echo "Installing ruby-$ruby_version"
Expand Down
4 changes: 4 additions & 0 deletions lib/templates/create/sunzi.yml
Expand Up @@ -23,3 +23,7 @@ preferences:
# Skip retrieving remote recipes when local copies already exist. This setting helps
# iterative deploy testing considerably faster, when you have a lot of remote recipes.
cache_remote_recipes: false

# Evaluate files as ERB templates. When enabled, you can pass dynamic values in the form
# of <%= @attributes.environment %> in recipes, roles, files and install.sh.
eval_erb: true
2 changes: 1 addition & 1 deletion sunzi.gemspec
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |spec|
spec.name = 'sunzi'
spec.version = '1.1.2' # retrieve this value by: Gem.loaded_specs['sunzi'].version.to_s
spec.version = '1.2.0' # retrieve this value by: Gem.loaded_specs['sunzi'].version.to_s
spec.authors = ['Kenn Ejima']
spec.email = ['kenn.ejima@gmail.com']
spec.homepage = 'http://github.com/kenn/sunzi'
Expand Down

0 comments on commit c329b11

Please sign in to comment.