capitate 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
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