capitate 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.1.9 2008-02-23
2
+
3
+ * Adding config_script to mongrel_cluster recipe
4
+ * Creating upload plugin that streams data
5
+
1
6
  == 0.1.8 2008-02-22
2
7
 
3
8
  * Fixing up documentation
data/Manifest.txt CHANGED
@@ -17,6 +17,7 @@ lib/capitate/plugins/package.rb
17
17
  lib/capitate/plugins/profiles.rb
18
18
  lib/capitate/plugins/script.rb
19
19
  lib/capitate/plugins/templates.rb
20
+ lib/capitate/plugins/upload.rb
20
21
  lib/capitate/plugins/wget.rb
21
22
  lib/capitate/plugins/yum.rb
22
23
  lib/capitate/recipes.rb
@@ -77,6 +78,7 @@ tasks/deployment.rake
77
78
  tasks/environment.rake
78
79
  tasks/website.rake
79
80
  test/test_helper.rb
81
+ test/test_plugin_upload.rb
80
82
  test/test_recipes.rb
81
83
  test/test_templates.rb
82
84
  website/index.html
@@ -1,3 +1,10 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2007, Gabriel Handford (gabrielh@gmail.com)
4
+ # All rights reserved.
5
+ # =============================================================================
6
+ #++
7
+
1
8
  require 'erb'
2
9
  require 'yaml'
3
10
 
@@ -0,0 +1,58 @@
1
+ module Capitate::Plugins::Upload
2
+
3
+ # Upload file with source path.
4
+ # Data is streamed.
5
+ #
6
+ # ==== Options
7
+ # +src_path+:: Source path
8
+ # +dest_path:: Remote destination path
9
+ # +options+:: Options (see capistrano 'put')
10
+ #
11
+ def file(src_path, dest_path, options = {})
12
+ data = FileData.new(src_path)
13
+ put(data, dest_path, options)
14
+ end
15
+
16
+ # Stream data with Net::SFTP by looking like an Array
17
+ class FileData
18
+
19
+ def initialize(path)
20
+ @path = path
21
+ @next_start = 0
22
+ end
23
+
24
+ def [](start, length)
25
+
26
+ if start != @next_start
27
+ raise <<-EOS
28
+
29
+ Can only access data sequentially; so we can stream it (The next start position should have been: #{@next_start})
30
+
31
+ EOS
32
+ end
33
+
34
+ data = file.read(length)
35
+
36
+ @next_start = start + length
37
+ close if @next_start >= self.length
38
+
39
+ data
40
+ end
41
+
42
+ def length
43
+ @file_size ||= File.size(@path)
44
+ end
45
+
46
+ def file
47
+ @file ||= File.open(@path, "r")
48
+ end
49
+
50
+ def close
51
+ @file.close if @file
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ Capistrano.plugin :upload, Capitate::Plugins::Upload
@@ -1,10 +1,18 @@
1
- # TODO: Document this class
1
+ # Task node in the capistrano namespace, task hierarchy.
2
+ #
2
3
  class Capitate::TaskNode
3
4
 
4
5
  include Capitate::Plugins::Base
5
6
 
6
7
  attr_reader :name, :nodes, :tasks, :parent
7
-
8
+
9
+ # Create task node with name and parent
10
+ # For root not use name = "top"
11
+ #
12
+ # ==== Options
13
+ # +name+:: Node name (namespace name)
14
+ # +parent+:: Parent node
15
+ #
8
16
  def initialize(name, parent = nil)
9
17
  @name = name
10
18
  @parent = parent
@@ -12,10 +20,20 @@ class Capitate::TaskNode
12
20
  @tasks = []
13
21
  end
14
22
 
23
+ # Add "child" node.
24
+ #
25
+ # ==== Options
26
+ # +task_node+:: Node
27
+ #
15
28
  def add_node(task_node)
16
29
  @nodes << task_node
17
30
  end
18
31
 
32
+ # Find node with name (namespace).
33
+ #
34
+ # ==== Options
35
+ # +name+:: Name to look for
36
+ #
19
37
  def find(name)
20
38
  @nodes.each do |node|
21
39
  return node if node.name == name
@@ -23,15 +41,27 @@ class Capitate::TaskNode
23
41
  nil
24
42
  end
25
43
 
44
+ # Add task to this node.
45
+ #
46
+ # ==== Options
47
+ # +task+:: Add task associated with this node (namespace).
48
+ #
26
49
  def add_task(task)
27
50
  @tasks << task
28
51
  end
29
52
 
53
+ # Get "child" nodes (sorted).
54
+ #
30
55
  def sorted_nodes
31
56
  nodes.sort_by(&:name)
32
57
  end
33
58
 
34
- # Depth first iteration
59
+ # Iterate over ALL "child" nodes, depth first.
60
+ # Yields |node, level|.
61
+ #
62
+ # ==== Options
63
+ # +level+:: Current level
64
+ #
35
65
  def each_node(level = 0, &block)
36
66
  sorted_nodes.each do |node|
37
67
  yield(node, level)
@@ -39,6 +69,14 @@ class Capitate::TaskNode
39
69
  end
40
70
  end
41
71
 
72
+ # Get the full name, using delimeter
73
+ #
74
+ # ==== Options
75
+ # +delimeter+:: Delimeter
76
+ #
77
+ # ==== Examples
78
+ # node.full_name(":") => "mysql:centos" # On node mysql centos node (top -> mysql -> centos)
79
+ #
42
80
  def full_name(delimeter = "-")
43
81
  if parent
44
82
  parent_name = parent.full_name
@@ -50,6 +88,13 @@ class Capitate::TaskNode
50
88
  end
51
89
 
52
90
  # Write doc for node (recursively)
91
+ #
92
+ # ==== Options
93
+ # +dir+:: Dir to write to
94
+ # +file_name+:: File name to write to, defaults to full name
95
+ # +title+:: Title and h1 for page, defaults to name
96
+ # +options+:: Options
97
+ #
53
98
  def write_doc(dir, file_name = nil, title = nil, options = {}, &block)
54
99
 
55
100
  file_name ||= full_name
@@ -115,6 +160,8 @@ class Capitate::TaskNode
115
160
  end
116
161
  end
117
162
 
163
+ # Node to string.
164
+ #
118
165
  def to_s(level = 0)
119
166
  spaces = " "
120
167
  indent = (0...level).collect { spaces }.join("")
@@ -133,9 +180,20 @@ class Capitate::TaskNode
133
180
  end
134
181
  s
135
182
  end
136
-
183
+
184
+ # Class methods
137
185
  class << self
138
186
 
187
+ # Create nodes and and task to node.
188
+ #
189
+ # If task is "mysql:centos:install", the nodes will look like:
190
+ #
191
+ # (top node) -> (mysql node) -> (centos node; w/ tasks: install)
192
+ #
193
+ # ==== Options
194
+ # +top_node+:: Node to start at
195
+ # +task+:: Task to add
196
+ #
139
197
  def populate_with_task(top_node, task)
140
198
  node_names = task.namespace.fully_qualified_name.split(":")
141
199
 
@@ -2,7 +2,7 @@ module Capitate #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 8
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/capitate.rb CHANGED
@@ -22,6 +22,8 @@ require 'capitate/plugins/templates'
22
22
  require 'capitate/plugins/wget'
23
23
  require 'capitate/plugins/yum'
24
24
 
25
+ require 'capitate/plugins/upload'
26
+
25
27
  require "capitate/cap_ext/connections"
26
28
  require "capitate/cap_ext/extension_proxy"
27
29
  require "capitate/cap_ext/variables"
data/lib/recipes/docs.rb CHANGED
@@ -4,8 +4,6 @@ namespace :docs do
4
4
  task :recipes do
5
5
  top_node = capitate.task_tree
6
6
 
7
- puts "Tree:\n#{}"
8
-
9
7
  dir = "docs/recipes"
10
8
  FileUtils.rm_rf(dir)
11
9
  FileUtils.mkdir_p(dir)
@@ -13,6 +13,10 @@ namespace :mongrel_cluster do
13
13
 
14
14
  set :mongrel_port, 9000
15
15
 
16
+ mongrel_config_script: Config script to load with mongrel.
17
+
18
+ set :mongrel_config_script, "config/mongrel_handler.rb"
19
+
16
20
  DESC
17
21
  task :setup_monit do
18
22
 
@@ -24,13 +28,30 @@ namespace :mongrel_cluster do
24
28
  # Settings
25
29
  fetch(:mongrel_size)
26
30
  fetch(:mongrel_port)
31
+ fetch_or_default(:mongrel_config_script, nil)
27
32
 
28
33
  processes = []
29
34
  ports = (0...mongrel_size).collect { |i| mongrel_port + i }
30
35
  ports.each do |port|
31
36
 
32
37
  pid_path = "#{shared_path}/pids/mongrel.#{port}.pid"
33
- start_options = "-d -e production -a 127.0.0.1 -c #{current_path} --user #{user} --group #{user} -p #{port} -P #{pid_path} -l log/mongrel.#{port}.log"
38
+
39
+ default_options = [
40
+ [ "-d" ],
41
+ [ "-e", "production" ],
42
+ [ "-a", "127.0.0.1" ],
43
+ [ "-c", current_path ],
44
+ [ "--user", user ],
45
+ [ "--group", user ],
46
+ [ "-p", port ],
47
+ [ "-P", pid_path ],
48
+ [ "-l", "log/mongrel.#{port}.log" ]
49
+ ]
50
+
51
+ default_options << [ "-S", mongrel_config_script ] if mongrel_config_script
52
+
53
+ start_options = default_options.collect { |a| a.join(" ") }.join(" ")
54
+ #start_options = "-d -e production -a 127.0.0.1 -c #{current_path} --user #{user} --group #{user} -p #{port} -P #{pid_path} -l log/mongrel.#{port}.log"
34
55
  stop_options = "-p #{port} -P #{pid_path}"
35
56
 
36
57
  processes << { :port => port, :start_options => start_options, :stop_options => stop_options, :name => "/usr/bin/mongrel_rails", :pid_path => pid_path }
@@ -8,3 +8,4 @@ pid_file: <%= pid_path %>/mongrel.pid
8
8
  servers: <%= mongrel_size %>
9
9
  user: <%= user %>
10
10
  group: <%= user %>
11
+ config_script: <%= mongrel_config_script %>
@@ -4,10 +4,18 @@
4
4
  # See vhost conf for site specific stuff.
5
5
  #
6
6
  # ==== References:
7
+ # http://brainspl.at/articles/2006/08/23/nginx-my-new-favorite-front-end-for-mongrel-cluster
7
8
  # http://brainspl.at/articles/2007/01/03/new-nginx-conf-with-optimizations
8
9
  # http://topfunky.net/svn/shovel/nginx
9
10
  # http://robsanheim.com/2008/02/07/beware-the-default-nginx-config-old-ie6-hates-gzip/
10
11
  #
12
+ # Nginx + memcached:
13
+ # http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/
14
+ # http://blog.kovyrin.net/2007/08/05/using-nginx-ssi-and-memcache-to-make-your-web-applications-faster/
15
+ #
16
+ # Fair balancing:
17
+ # http://brainspl.at/articles/2007/11/09/a-fair-proxy-balancer-for-nginx-and-mongrel
18
+
11
19
 
12
20
  # user and group to run as
13
21
  user nginx nginx;
data/script/txt2html CHANGED
@@ -40,35 +40,41 @@ def convert_syntax(syntax, source)
40
40
  return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
41
41
  end
42
42
 
43
- if ARGV.length >= 1
44
- src, template = ARGV
45
- template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')
46
-
43
+ if ARGV.length >= 3
44
+ src_glob, template, output_dir = ARGV
45
+ src_files = Dir[src_glob]
47
46
  else
48
- puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
47
+ puts("Usage: #{File.split($0).last} path/to/source*.txt template.rhtml output_dir")
49
48
  exit!
50
49
  end
51
50
 
52
51
  template = ERB.new(File.open(template).read)
53
52
 
54
- title = nil
55
- body = nil
56
- File.open(src) do |fsrc|
57
- title_text = fsrc.readline
58
- body_text = fsrc.read
59
- syntax_items = []
60
- body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
61
- ident = syntax_items.length
62
- element, syntax, source = $1, $2, $3
63
- syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
64
- "syntax-temp-#{ident}"
65
- }
66
- title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
67
- body = RedCloth.new(body_text).to_html
68
- body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
69
- end
70
- stat = File.stat(src)
71
- created = stat.ctime
72
- modified = stat.mtime
53
+ src_files.each do |src|
54
+ title = nil
55
+ body = nil
56
+ File.open(src) do |fsrc|
57
+ title_text = fsrc.readline
58
+ body_text = fsrc.read
59
+ syntax_items = []
60
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
61
+ ident = syntax_items.length
62
+ element, syntax, source = $1, $2, $3
63
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
64
+ "syntax-temp-#{ident}"
65
+ }
66
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
67
+ body = RedCloth.new(body_text).to_html
68
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
69
+ end
70
+ stat = File.stat(src)
71
+ created = stat.ctime
72
+ modified = stat.mtime
73
73
 
74
- $stdout << template.result(binding)
74
+ #$stdout << template.result(binding)
75
+ output_file_path = src.split("/").last.gsub(/txt$/, "html")
76
+ output_path = output_dir + "/" + output_file_path
77
+ puts " create #{output_path}"
78
+ File.open(output_path, "w") { |file| file.puts template.result(binding) }
79
+
80
+ end
data/tasks/website.rake CHANGED
@@ -1,17 +1,14 @@
1
1
  desc 'Generate website files'
2
2
  task :website_generate => :ruby_env do
3
- (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
- sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
- end
3
+ template = File.join(File.dirname(__FILE__), '/../website/template.rhtml')
4
+ sh %{ #{RUBY_APP} script/txt2html "website/**/*.txt" #{template} website }
6
5
 
7
6
  # Clean and re-create
8
7
  FileUtils.rm_rf("website/recipes")
9
8
  FileUtils.mkdir_p("website/recipes")
10
9
  sh "cap docs:recipes"
11
10
  template = File.join(File.dirname(__FILE__), '/../website/template_recipe.rhtml')
12
- Dir['docs/recipes/**/*.txt'].each do |txt|
13
- sh %{ #{RUBY_APP} script/txt2html #{txt} #{template} > website/recipes/#{txt.split("/").last.gsub(/txt$/,'html')} }
14
- end
11
+ sh %{ #{RUBY_APP} script/txt2html "docs/recipes/**/*.txt" #{template} website/recipes }
15
12
  end
16
13
 
17
14
  desc 'Upload website files to rubyforge'
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestPluginUpload < Test::Unit::TestCase
4
+
5
+ include Capitate::Plugins::Upload
6
+
7
+ # Mocked put
8
+ def put(data, dest_path, options)
9
+ start = 0
10
+ length = 4096
11
+
12
+ @mock_put << data[start, length]
13
+ end
14
+
15
+ # Test upload streamed
16
+ def test_upload
17
+ @mock_put = ""
18
+
19
+ # Use this file for data
20
+ path = __FILE__
21
+
22
+ file(path, "mocked")
23
+
24
+ data = nil
25
+ File.open(__FILE__) { |f| data = f.readlines }
26
+ data = data.join
27
+
28
+ assert_equal data, @mock_put
29
+ end
30
+
31
+ end
32
+
data/website/index.html CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
  <div id="version" class="clickable box" onclick='document.location = "http://rubyforge.org/projects/capitate"; return false'>
40
40
  <p>Get Version</p>
41
- <a href="http://rubyforge.org/projects/capitate" class="numbers">0.1.8</a>
41
+ <a href="http://rubyforge.org/projects/capitate" class="numbers">0.1.9</a>
42
42
  </div>
43
43
 
44
44
  <div id="recipes" class="box">
@@ -65,10 +65,9 @@
65
65
  <p>Add capitate to your Capfile. Copy this somewhere near the top:</p>
66
66
 
67
67
 
68
- <p><pre class='syntax'>
69
- <span class="ident">set</span> <span class="symbol">:project_root</span><span class="punct">,</span> <span class="constant">File</span><span class="punct">.</span><span class="ident">dirname</span><span class="punct">(</span><span class="constant">__FILE__</span><span class="punct">)</span>
70
- <span class="ident">require</span> <span class="punct">'</span><span class="string">capitate</span><span class="punct">'</span>
71
- <span class="ident">require</span> <span class="punct">'</span><span class="string">capitate/recipes</span><span class="punct">'</span>
68
+ <p><pre class='syntax'><span class="ident">require</span> <span class="punct">'</span><span class="string">capitate</span><span class="punct">'</span>
69
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">capitate/recipes</span><span class="punct">'</span>
70
+ <span class="ident">set</span> <span class="symbol">:project_root</span><span class="punct">,</span> <span class="constant">File</span><span class="punct">.</span><span class="ident">dirname</span><span class="punct">(</span><span class="constant">__FILE__</span><span class="punct">)</span>
72
71
  </pre></p>
73
72
 
74
73
 
@@ -152,7 +151,7 @@
152
151
  <p>Comments are welcome. Send an email to <a href="mailto:gabrielh@gmail.com">Gabriel Handford</a> via the <a href="http://groups.google.com/group/capitate">forum</a></p>
153
152
  </div>
154
153
  <p class="coda">
155
- <a href="FIXME email">Gabriel Handford</a>, 21st February 2008<br>
154
+ <a href="FIXME email">Gabriel Handford</a>, 22nd February 2008<br>
156
155
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
157
156
  </p>
158
157
  </div>
data/website/index.txt CHANGED
@@ -13,10 +13,9 @@ h2. Running
13
13
 
14
14
  Add capitate to your Capfile. Copy this somewhere near the top:
15
15
 
16
- <pre syntax="ruby">
17
- set :project_root, File.dirname(__FILE__)
18
- require 'capitate'
19
- require 'capitate/recipes'
16
+ <pre syntax="ruby">require 'capitate'
17
+ require 'capitate/recipes'
18
+ set :project_root, File.dirname(__FILE__)
20
19
  </pre>
21
20
 
22
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capitate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ""
6
6
  authors:
7
7
  - Gabriel Handford
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-21 00:00:00 -05:00
12
+ date: 2008-02-22 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -54,6 +54,7 @@ files:
54
54
  - lib/capitate/plugins/profiles.rb
55
55
  - lib/capitate/plugins/script.rb
56
56
  - lib/capitate/plugins/templates.rb
57
+ - lib/capitate/plugins/upload.rb
57
58
  - lib/capitate/plugins/wget.rb
58
59
  - lib/capitate/plugins/yum.rb
59
60
  - lib/capitate/recipes.rb
@@ -114,6 +115,7 @@ files:
114
115
  - tasks/environment.rake
115
116
  - tasks/website.rake
116
117
  - test/test_helper.rb
118
+ - test/test_plugin_upload.rb
117
119
  - test/test_recipes.rb
118
120
  - test/test_templates.rb
119
121
  - website/index.html
@@ -151,5 +153,6 @@ specification_version: 2
151
153
  summary: Capistrano recipes, plugins and templates.
152
154
  test_files:
153
155
  - test/test_helper.rb
156
+ - test/test_plugin_upload.rb
154
157
  - test/test_recipes.rb
155
158
  - test/test_templates.rb