buzzville 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 buzzware
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ = buzzville
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 buzzware. See LICENSE for details.
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "buzzville"
8
+ gem.summary = %Q{Capistrano recipes and ruby code relating to deployment}
9
+ gem.description = %Q{Capistrano recipes and ruby code relating to deployment}
10
+ gem.email = "contact@buzzware.com.au"
11
+ gem.homepage = "http://github.com/buzzware/buzzville"
12
+ gem.authors = ["buzzware"]
13
+ gem.rubyforge_project = "buzzware"
14
+ gem.add_dependency('buzzcore', '>= 0.2.5')
15
+ gem.add_dependency('yore', '>= 0.0.5')
16
+ gem.add_dependency('cmdparse', '>= 2.0.2')
17
+ gem.add_development_dependency "thoughtbot-shoulda"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "rdoc"
22
+ end
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/*_test.rb'
39
+ test.verbose = true
40
+ end
41
+ rescue LoadError
42
+ task :rcov do
43
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
44
+ end
45
+ end
46
+
47
+ task :test => :check_dependencies
48
+
49
+ task :default => :test
50
+
51
+ require 'rake/rdoctask'
52
+ Rake::RDocTask.new do |rdoc|
53
+ if File.exist?('VERSION')
54
+ version = File.read('VERSION')
55
+ else
56
+ version = ""
57
+ end
58
+
59
+ rdoc.rdoc_dir = 'rdoc'
60
+ rdoc.title = "buzzville #{version}"
61
+ rdoc.rdoc_files.include('README*')
62
+ rdoc.rdoc_files.include('lib/**/*.rb')
63
+ end
64
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.3
@@ -0,0 +1,93 @@
1
+ <!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
2
+ <Project
3
+ Version="10.0"
4
+ VendorName="SlickEdit"
5
+ WorkingDir=".">
6
+ <Config
7
+ Name="Release"
8
+ OutputFile=""
9
+ CompilerConfigName="Latest Version">
10
+ <Menu>
11
+ <Target
12
+ Name="Compile"
13
+ MenuCaption="&amp;Compile"
14
+ CaptureOutputWith="ProcessBuffer"
15
+ SaveOption="SaveCurrent"
16
+ RunFromDir="%rw">
17
+ <Exec/>
18
+ </Target>
19
+ <Target
20
+ Name="Build"
21
+ MenuCaption="&amp;Build"
22
+ CaptureOutputWith="ProcessBuffer"
23
+ SaveOption="SaveWorkspaceFiles"
24
+ RunFromDir="%rw">
25
+ <Exec/>
26
+ </Target>
27
+ <Target
28
+ Name="Rebuild"
29
+ MenuCaption="&amp;Rebuild"
30
+ CaptureOutputWith="ProcessBuffer"
31
+ SaveOption="SaveWorkspaceFiles"
32
+ RunFromDir="%rw">
33
+ <Exec/>
34
+ </Target>
35
+ <Target
36
+ Name="Debug"
37
+ MenuCaption="&amp;Debug"
38
+ SaveOption="SaveNone"
39
+ RunFromDir="%rw">
40
+ <Exec/>
41
+ </Target>
42
+ <Target
43
+ Name="Execute"
44
+ MenuCaption="E&amp;xecute"
45
+ SaveOption="SaveNone"
46
+ RunFromDir="%rw"
47
+ CaptureOutputWith="ProcessBuffer"
48
+ ClearProcessBuffer="1">
49
+ <Exec CmdLine="source actions.sh execute"/>
50
+ </Target>
51
+ </Menu>
52
+ </Config>
53
+ <CustomFolders>
54
+ <Folder
55
+ Name="Source Files"
56
+ Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl"/>
57
+ <Folder
58
+ Name="Header Files"
59
+ Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if"/>
60
+ <Folder
61
+ Name="Resource Files"
62
+ Filters="*.ico;*.cur;*.dlg"/>
63
+ <Folder
64
+ Name="Bitmaps"
65
+ Filters="*.bmp"/>
66
+ <Folder
67
+ Name="Other Files"
68
+ Filters="">
69
+ </Folder>
70
+ </CustomFolders>
71
+ <Files AutoFolders="DirectoryView">
72
+ <Folder Name="lib">
73
+ <F
74
+ N="lib/*"
75
+ Recurse="1"
76
+ Refilter="0"
77
+ Excludes=""/>
78
+ </Folder>
79
+ <Folder Name="test">
80
+ <F
81
+ N="test/*"
82
+ Recurse="0"
83
+ Refilter="0"
84
+ Excludes=".svn/"/>
85
+ </Folder>
86
+ <F N="buzzville.gemspec"/>
87
+ <F N="History.txt"/>
88
+ <F N="Manifest.txt"/>
89
+ <F N="PostInstall.txt"/>
90
+ <F N="Rakefile"/>
91
+ <F N="README.rdoc"/>
92
+ </Files>
93
+ </Project>
@@ -0,0 +1,93 @@
1
+ <!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
2
+ <Project
3
+ Version="10.0"
4
+ VendorName="SlickEdit"
5
+ WorkingDir=".">
6
+ <Config
7
+ Name="Release"
8
+ OutputFile=""
9
+ CompilerConfigName="Latest Version">
10
+ <Menu>
11
+ <Target
12
+ Name="Compile"
13
+ MenuCaption="&amp;Compile"
14
+ CaptureOutputWith="ProcessBuffer"
15
+ SaveOption="SaveCurrent"
16
+ RunFromDir="%rw">
17
+ <Exec/>
18
+ </Target>
19
+ <Target
20
+ Name="Build"
21
+ MenuCaption="&amp;Build"
22
+ CaptureOutputWith="ProcessBuffer"
23
+ SaveOption="SaveWorkspaceFiles"
24
+ RunFromDir="%rw">
25
+ <Exec/>
26
+ </Target>
27
+ <Target
28
+ Name="Rebuild"
29
+ MenuCaption="&amp;Rebuild"
30
+ CaptureOutputWith="ProcessBuffer"
31
+ SaveOption="SaveWorkspaceFiles"
32
+ RunFromDir="%rw">
33
+ <Exec/>
34
+ </Target>
35
+ <Target
36
+ Name="Debug"
37
+ MenuCaption="&amp;Debug"
38
+ SaveOption="SaveNone"
39
+ RunFromDir="%rw">
40
+ <Exec/>
41
+ </Target>
42
+ <Target
43
+ Name="Execute"
44
+ MenuCaption="E&amp;xecute"
45
+ SaveOption="SaveNone"
46
+ RunFromDir="%rw"
47
+ CaptureOutputWith="ProcessBuffer"
48
+ ClearProcessBuffer="1">
49
+ <Exec CmdLine="source actions.sh execute"/>
50
+ </Target>
51
+ </Menu>
52
+ </Config>
53
+ <CustomFolders>
54
+ <Folder
55
+ Name="Source Files"
56
+ Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl"/>
57
+ <Folder
58
+ Name="Header Files"
59
+ Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if"/>
60
+ <Folder
61
+ Name="Resource Files"
62
+ Filters="*.ico;*.cur;*.dlg"/>
63
+ <Folder
64
+ Name="Bitmaps"
65
+ Filters="*.bmp"/>
66
+ <Folder
67
+ Name="Other Files"
68
+ Filters="">
69
+ </Folder>
70
+ </CustomFolders>
71
+ <Files AutoFolders="DirectoryView">
72
+ <Folder Name="lib">
73
+ <F
74
+ N="lib/*"
75
+ Recurse="1"
76
+ Refilter="0"
77
+ Excludes=""/>
78
+ </Folder>
79
+ <Folder Name="test">
80
+ <F
81
+ N="test/*"
82
+ Recurse="0"
83
+ Refilter="0"
84
+ Excludes=".svn/"/>
85
+ </Folder>
86
+ <F N="buzzcore.gemspec"/>
87
+ <F N="History.txt"/>
88
+ <F N="Manifest.txt"/>
89
+ <F N="PostInstall.txt"/>
90
+ <F N="Rakefile"/>
91
+ <F N="README.rdoc"/>
92
+ </Files>
93
+ </Project>
@@ -0,0 +1,4 @@
1
+
2
+ Dir.chdir(File.dirname(__FILE__)) { Dir['buzzville/*'] }.each {|f| require f }
3
+
4
+
@@ -0,0 +1,323 @@
1
+ # use "extend CapUtils" inside a task to use this
2
+ require 'buzzcore/misc_utils'
3
+ require 'buzzcore/string_utils'
4
+ require 'buzzcore/xml_utils'
5
+ require 'buzzcore/shell_extras'
6
+ require 'net/ssh'
7
+ require 'net/sftp'
8
+
9
+ module CapUtils
10
+
11
+ # upload the given local file to the remote server and set the given mode.
12
+ # 0644 is the default mode
13
+ #
14
+ # Unix file modes :
15
+ # 4: read
16
+ # 2: write
17
+ # 1: execute
18
+ # 0[owner][group][other]
19
+ def upload_file(aLocalFilePath,aRemoteFilePath,aMode = 0644)
20
+ puts "* uploading #{aLocalFilePath} to #{aRemoteFilePath}"
21
+ s = nil
22
+ File.open(aLocalFilePath, "rb") { |f| s = f.read }
23
+ put(s,aRemoteFilePath,:mode => aMode)
24
+ end
25
+
26
+ def render_template_file(aTemplateFile,aXmlConfig,aOutputFile,aMoreConfig=nil)
27
+ template = MiscUtils.string_from_file(aTemplateFile)
28
+ values = XmlUtils.read_config_values(aXmlConfig)
29
+ values = values ? values.merge(aMoreConfig || {}) : aMoreConfig
30
+ result = StringUtils.render_template(template, values)
31
+ MiscUtils.string_to_file(result, aOutputFile)
32
+ end
33
+
34
+ def get_ip
35
+ run "ifconfig eth0 |grep \"inet addr\"" do |channel,stream,data|
36
+ return data.scan(/inet addr:([0-9.]+)/).flatten.pop
37
+ end
38
+ end
39
+
40
+ # check if file exists. Relies on remote ruby
41
+ def remote_file_exists?(aPath)
42
+ remote_ruby("puts File.exists?('#{aPath}').to_s")=="true\n"
43
+ end
44
+
45
+ def remote_ruby(aRubyString)
46
+ run 'ruby -e "'+aRubyString+'"' do |channel,stream,data|
47
+ return data
48
+ end
49
+ end
50
+
51
+ def sudo_run(aString)
52
+ # as = fetch(:runner, "app")
53
+ # via = fetch(:run_method, :sudo)
54
+ # invoke_command(aString, :via => via, :as => as)
55
+ # if aUseSudo
56
+ # run "sudo "+aString
57
+ # else
58
+ run aString
59
+ # end
60
+ end
61
+
62
+ def upload_file_anywhere(aSourceFile,aDestHost,aDestUser,aDestPassword,aDestFile,aDestPort=22)
63
+ Net::SSH.start(aDestHost, aDestUser, {:port => aDestPort, :password => aDestPassword, :verbose =>Logger::DEBUG}) do |ssh|
64
+ File.open(aSourceFile, "rb") { |f| ssh.sftp.upload!(f, aDestFile) }
65
+ end
66
+ end
67
+
68
+ def branch_name_from_svn_url(aURL)
69
+ prot_domain = (aURL.scan(/[^:]+:\/\/[^\/]+\//)).first
70
+ without_domain = aURL[prot_domain.length..-1]
71
+ return 'trunk' if without_domain =~ /^trunk\//
72
+ return (without_domain.scan(/branches\/(.+?)(\/|$)/)).flatten.first
73
+ end
74
+
75
+ # give block with |aText,aStream,aState| that returns response or nil
76
+ def run_respond(aCommand)
77
+ run(aCommand) do |ch,stream,text|
78
+ ch[:state] ||= { :channel => ch }
79
+ output = yield(text,stream,ch[:state])
80
+ ch.send_data(output) if output
81
+ end
82
+ end
83
+
84
+ # pass prompt to user, and return their response
85
+ def run_prompt(aCommand)
86
+ run_respond aCommand do |text,stream,state|
87
+ Capistrano::CLI.password_prompt(text)+"\n"
88
+ end
89
+ end
90
+
91
+ def ensure_link(aTo,aFrom,aDir=nil,aUserGroup=nil,aSudo='')
92
+ cmd = []
93
+ cmd << "cd #{aDir}" if aDir
94
+ cmd << "#{sudo} rm -rf #{aFrom}"
95
+ cmd << "#{sudo} ln -sf #{aTo} #{aFrom}"
96
+ cmd << "#{sudo} chown -h #{aUserGroup} #{aFrom}" if aUserGroup
97
+ run cmd.join(' && ')
98
+ end
99
+
100
+
101
+ def file_exists?(path)
102
+ result = nil
103
+ run "if [[ -e #{path} ]]; then echo 'true'; else echo 'false'; fi", :shell => false do |ch,stream,text|
104
+ result = (text.strip! == 'true')
105
+ end
106
+ result
107
+ end
108
+
109
+ # Used in deployment to maintain folder contents between deployments.
110
+ # Normally the shared path exists and will be linked into the release.
111
+ # If it doesn't exist and the release path does, it will be moved into the shared path
112
+ # aFolder eg. "vendor/extensions/design"
113
+ # aSharedFolder eg. "design"
114
+ def preserve_folder(aReleaseFolder,aSharedFolder)
115
+ aReleaseFolder = File.join(release_path,aReleaseFolder)
116
+ aSharedFolder = File.join(shared_path,aSharedFolder)
117
+ release_exists = file_exists?(aReleaseFolder)
118
+ shared_exists = file_exists?(aSharedFolder)
119
+ if shared_exists
120
+ run "rm -rf #{aReleaseFolder}" if release_exists
121
+ else
122
+ run "mv #{aReleaseFolder} #{aSharedFolder}" if release_exists
123
+ end
124
+ ensure_link("#{aSharedFolder}","#{aReleaseFolder}",nil,"#{user}:#{apache_user}")
125
+ end
126
+
127
+ def select_target_file(aFile)
128
+ ext = MiscUtils.file_extension(aFile,false)
129
+ no_ext = MiscUtils.file_no_extension(aFile,false)
130
+ dir = File.dirname(aFile)
131
+ run "#{sudo} mv -f #{no_ext}.#{target}.#{ext} #{aFile}"
132
+ run "#{sudo} rm -f #{no_ext}.*.#{ext}"
133
+ end
134
+
135
+ def shell(aCommandline,&aBlock)
136
+ result = block_given? ? POpen4::shell(aCommandline,nil,nil,&aBlock) : POpen4::shell(aCommandline)
137
+ return result[:stdout]
138
+ end
139
+
140
+ def run_local(aString)
141
+ `#{aString}`
142
+ end
143
+
144
+
145
+ def run_for_all(aCommand,aPath,aFilesOrDirs,aPattern=nil,aInvertPattern=false,aSudo=true)
146
+ #run "#{sudo} find . -wholename '*/.svn' -prune -o -type d -print0 |xargs -0 #{sudo} chmod 750"
147
+ #sudo find . -type f -exec echo {} \;
148
+ cmd = []
149
+ cmd << "sudo" if aSudo
150
+ cmd << "find #{aPath}"
151
+ cmd << "-wholename '#{aPattern}'" if aPattern
152
+ cmd << "-prune -o" if aInvertPattern
153
+ cmd << case aFilesOrDirs.to_s[0,1]
154
+ when 'f' then '-type f'
155
+ when 'd' then '-type d'
156
+ else ''
157
+ end
158
+ cmd << "-exec"
159
+ cmd << aCommand
160
+ cmd << '{} \;'
161
+ cmd = cmd.join(' ')
162
+ run cmd
163
+ end
164
+
165
+ #run_for_all("chmod g+s #{File.expand_path(dir,public_dir)}",public_dir,:dirs)
166
+
167
+ def set_dir_permissions_r(aStartPath,aUser=nil,aGroup=nil,aMode=nil,aSetGroupId=false)
168
+ cmd = []
169
+ if aGroup
170
+ cmd << (aUser ? "chown #{aUser}:#{aGroup}" : "chgrp #{aGroup}")
171
+ else
172
+ cmd << "chown #{aUser}" if aUser
173
+ end
174
+ cmd << "chmod #{aMode.to_s}" if aMode
175
+ cmd << "chmod g+s" if aSetGroupId
176
+ cmd.each do |c|
177
+ run_for_all(c,aStartPath,:dirs)
178
+ end
179
+ end
180
+
181
+ def set_permissions_cmd(aFilepath,aUser=nil,aGroup=nil,aMode=nil,aSetGroupId=false,aSudo=true)
182
+ cmd = []
183
+ if aGroup
184
+ cmd << (aUser ? "#{aSudo ? sudo : ''} chown #{aUser}:#{aGroup}" : "#{aSudo ? sudo : ''} chgrp #{aGroup}") + " #{aFilepath}"
185
+ else
186
+ cmd << "#{aSudo ? sudo : ''} chown #{aUser} #{aFilepath}" if aUser
187
+ end
188
+ cmd << "#{aSudo ? sudo : ''} chmod #{aMode.to_s} #{aFilepath}" if aMode
189
+ cmd << "#{aSudo ? sudo : ''} chmod g+s #{aFilepath}" if aSetGroupId
190
+ cmd.join(' && ')
191
+ end
192
+
193
+ def set_permissions(aFilepath,aUser=nil,aGroup=nil,aMode=nil,aSetGroupId=false,aSudo=true)
194
+ cmd = set_permissions_cmd(aFilepath,aUser,aGroup,aMode,aSetGroupId,aSudo)
195
+ run cmd
196
+ end
197
+
198
+ def mkdir_permissions(aStartPath,aUser=nil,aGroup=nil,aMode=nil,aSetGroupId=false,aSudo=true)
199
+ run "#{sudo} mkdir -p #{aStartPath}"
200
+ set_permissions(aStartPath,aUser,aGroup,aMode,aSetGroupId,aSudo)
201
+ end
202
+
203
+ # if aGroup is given, that will be the users only group
204
+ def adduser(aNewUser,aPassword,aGroup=nil)
205
+ run "#{sudo} adduser --gecos '' #{aGroup ? '--ingroup '+aGroup : ''} #{aNewUser}" do |ch, stream, out|
206
+ ch.send_data aPassword+"\n" if out =~ /UNIX password:/
207
+ end
208
+ end
209
+
210
+ def add_user_to_group(aUser,aGroup)
211
+ run "#{sudo} usermod -a -G #{aGroup} #{aUser}"
212
+ end
213
+
214
+ # returns 'buzzware-logikal' from 'git@git.assembla.com:buzzware/logikal.git'
215
+ def project_name_from_git_commit_url(aGitUrl)
216
+ parts = aGitUrl.split(/[@:\/]/) # eg ["git", "git.assembla.com", "buzzware", "logikal.git"]
217
+ return File.basename(parts[2..-1].join('-'),'.git')
218
+ end
219
+
220
+ # returns from git://github.com/buzzware/spree.git
221
+ def project_name_from_git_public_url(aGitUrl)
222
+ prot,url = aGitUrl.split(/\:\/\//)
223
+ url_parts = url.split('/')
224
+ host = url_parts.shift
225
+ File.basename(url_parts.join('-'),'.git')
226
+ end
227
+
228
+ def update_remote_git_cache(aGitUrl,aBranchOrTag=nil)
229
+ proj = project_name_from_git_public_url(aGitUrl)
230
+ cache_path = File.join(shared_path,'extra_cache')
231
+ run "mkdir -p #{cache_path}"
232
+ dest = File.join(cache_path,proj)
233
+ revision = ''
234
+ sub_mods = false
235
+
236
+ run "git clone #{aGitUrl} #{dest}" if !file_exists?(dest)
237
+ run "cd #{dest} && git checkout -f #{aBranchOrTag ? aBranchOrTag : ''} #{revision} && git reset --hard && git clean -dfqx"
238
+ if sub_mods
239
+ run "cd #{dest} && git submodule init && git submodule update"
240
+ end
241
+ return dest
242
+ end
243
+
244
+ def force_copy_mode_cmd(aFrom,aTo,aChmod=nil)
245
+ cmd = []
246
+ cmd << "rm -rf #{aTo}"
247
+ cmd << "cp -f #{aFrom} #{aTo}"
248
+ cmd << "chmod #{aChmod.to_s} #{aTo}" if aChmod
249
+ cmd.join(' && ')
250
+ end
251
+
252
+ def ensure_link_cmd(aTo,aFrom,aDir=nil,aUserGroup=nil,aSudo=nil)
253
+ aSudo ||= ''
254
+ cmd = []
255
+ cmd << "cd #{aDir}" if aDir
256
+ cmd << "#{aSudo} rm -rf #{aFrom}"
257
+ cmd << "#{aSudo} ln -sf #{aTo} #{aFrom}"
258
+ cmd << "#{aSudo} chown -h #{aUserGroup} #{aFrom}" if aUserGroup
259
+ cmd.join(' && ')
260
+ end
261
+
262
+ def ensure_folder(aPath,aOwner=nil,aGroup=nil,aMode=nil,aSudo=nil)
263
+ aSudo ||= ''
264
+ cmd = []
265
+ cmd << "#{aSudo} mkdir -p #{aPath}"
266
+ if aOwner || aGroup
267
+ cmd << "#{aSudo} chown #{aOwner} #{aPath}" if !aGroup
268
+ cmd << "#{aSudo} chgrp #{aGroup} #{aPath}" if !aOwner
269
+ cmd << "#{aSudo} chown #{aOwner}:#{aGroup} #{aPath}" if aOwner && aGroup
270
+ end
271
+ cmd << "chmod #{aMode} #{aPath}" if aMode
272
+ cmd.join(' && ')
273
+ end
274
+
275
+ # This means :
276
+ # * designers can ftp in to the server and upload/edit templates and partials
277
+ # * templates are Rails-style eg. erb but can be whatever you have Rails handlers for
278
+ # * designers can upload assets into a design folder that will be available publicly under /design
279
+ # * designers templates and assets are not affected by redeploys
280
+
281
+ def setup_designer_filesystem_cmd(aBrowserCmsRoot,aSharedDesignPath,aFtpPath,aUser,aApacheUser)
282
+
283
+ cmd = []
284
+
285
+ cmd << ensure_folder(aSharedDesignPath,aUser,aApacheUser,750)
286
+ cmd << ensure_folder(aSharedDesignPath+'/design',aUser,aApacheUser,750)
287
+ design_views = "#{aSharedDesignPath}/views"
288
+
289
+ cmd << ensure_folder(design_views,aUser,aApacheUser,750)
290
+ # copy files from database to shared/design
291
+ cmd << "cp -rf #{aBrowserCmsRoot}/tmp/views/* #{design_views}/"
292
+ cmd << ensure_folder(design_views+'/layouts/templates',aUser,aApacheUser,750)
293
+ cmd << ensure_folder(design_views+'/partials',aUser,aApacheUser,750)
294
+
295
+ #convert tmp views folder into a link to shared/design
296
+ cmd << ensure_link_cmd(design_views,'views',aBrowserCmsRoot+'/tmp',"#{aUser}:#{aApacheUser}")
297
+
298
+ # copy files from aBrowserCmsRoot to shared/design and make readonly
299
+ cmd << "cp -rf #{aBrowserCmsRoot}/app/views/* #{design_views}/"
300
+
301
+ # link design/public into public folder
302
+ cmd << ensure_link_cmd(aSharedDesignPath+'/design','design',aBrowserCmsRoot+'/public',"#{aUser}:#{aApacheUser}")
303
+
304
+ ## link shared/design/design into ftp folder
305
+ cmd << ensure_link_cmd(aSharedDesignPath+'/design','design',aFtpPath,"#{aUser}:#{aApacheUser}")
306
+ ## link templates into ftp folder
307
+ cmd << ensure_link_cmd(design_views,'views',aFtpPath,"#{aUser}:#{aApacheUser}")
308
+ #run "#{sudo} chgrp -h www-data #{deploy_to}/current" # this is to change owner of link, not target
309
+ cmd_s = cmd.join(" && ")
310
+ end
311
+
312
+ def install_script_from_string(aScriptString,aFilepath)
313
+ temp_path = File.join(deploy_to,File.basename(aFilepath))
314
+ put(aScriptString,temp_path)
315
+ run "#{sudo} mv #{temp_path} #{aFilepath}"
316
+ set_permissions(aFilepath,'root',user,750,false,true)
317
+ end
318
+
319
+ end
320
+
321
+ class CapUtilsClass
322
+ self.extend CapUtils
323
+ end
@@ -0,0 +1,188 @@
1
+ require 'net/ftp'
2
+
3
+ #this_path = File.dirname(__FILE__)
4
+ #require this_path+'/misc_utils'
5
+
6
+ String.class_eval do
7
+ def bite!(aValue=$/,aString=self)
8
+ if aString[0,aValue.length] == aValue
9
+ aString[0,aValue.length] = ''
10
+ return aString
11
+ else
12
+ return aString
13
+ end
14
+ end
15
+
16
+ def bite(aValue=$/)
17
+ bite!(aValue,self.clone)
18
+ end
19
+ end
20
+
21
+
22
+ module Net
23
+ class FTP
24
+ def FTP.with_connect(aHost,aUsername,aPassword,aDir=nil)
25
+ open(aHost,aUsername,aPassword) do |f|
26
+ f.passive = true
27
+ f.chdir(aDir) if aDir
28
+ yield f
29
+ end
30
+ end
31
+
32
+ def self.crack_file_line(aString)
33
+ values = aString.scan(/(.{10}).{28}(.{13})(.*)$/).flatten
34
+ {
35
+ :bits => values[0],
36
+ :date => values[1],
37
+ :name => values[2]
38
+ }
39
+ end
40
+
41
+ # BEGIN BUGFIXES
42
+
43
+ #
44
+ # Returns the size of the given (remote) filename.
45
+ #
46
+ def size(filename)
47
+ voidcmd("TYPE I")
48
+ resp = sendcmd("SIZE " + filename)
49
+ code = resp[0, 3]
50
+ if code != "213" && code != "220"
51
+ raise FTPReplyError, resp
52
+ end
53
+ return resp[3..-1].strip.to_i
54
+ end
55
+
56
+ # END BUGFIXES
57
+
58
+ def subdirs(aPath)
59
+ list.delete_if {|line| line[0,1]=='d'}
60
+ return list
61
+ end
62
+
63
+ def files(aPath)
64
+ list.delete_if {|line| line[0,1]!='d'}
65
+ return list
66
+ end
67
+
68
+ def expand_dir(aPath,aBase=nil)
69
+ return aPath if aPath=='/'
70
+ return MiscUtils::path_relative?(aPath) ? File.expand_path(aPath,aBase || pwd()) : File.expand_path(aPath)
71
+ end
72
+
73
+ def dir_exists?(aPath)
74
+ aPath = expand_dir(aPath)
75
+ return true if aPath=='/'
76
+ dirname = File.basename(aPath)
77
+ parent = MiscUtils.path_parent(aPath)
78
+ dirname!='' && nlst(parent).include?(dirname)
79
+ end
80
+
81
+ def file_exists?(aPath)
82
+ aPath = expand_dir(aPath)
83
+ filename = File.basename(aPath)
84
+ parent = File.dirname(aPath)
85
+ filename!='' && nlst(parent).include?(filename)
86
+ end
87
+
88
+ def filelist_recurse(aPath=nil,aResult=nil,&block)
89
+ #puts "filelist_recurse: #{aPath.to_s} #{aResult.inspect}"
90
+ orig_dir = !aResult ? pwd : nil # assigned if called at top with aResult=nil
91
+ aResult ||= []
92
+ aPath ||= ''
93
+ chdir(aPath)
94
+ list('*').each do |f|
95
+ is_dir = f[0,1]=='d'
96
+ details = FTP::crack_file_line(f)
97
+ full = File.join(aPath,details[:name])
98
+ if !block_given? || yield(full)
99
+ if is_dir
100
+ filelist_recurse(full,aResult)
101
+ else
102
+ aResult << full
103
+ end
104
+ end
105
+ end
106
+ chdir(orig_dir) if orig_dir
107
+ return aResult
108
+ end
109
+
110
+ def get_files(aRemoteDir,aLocalDir,aFiles,aOptions=nil)
111
+ aOptions = {:overwrite => true}.merge(aOptions || {})
112
+ aFiles.each do |r|
113
+ relative = r.bite(MiscUtils::append_slash(aRemoteDir))
114
+ d = File.join(aLocalDir,relative)
115
+ puts "getting #{relative}"
116
+ getbinaryfile(r, d) unless !aOptions[:overwrite] && File.exists?(d)
117
+ end
118
+ end
119
+
120
+ def get_dir(aRemoteDir,aLocalDir,aOptions=nil,&block)
121
+ remote_files = block_given? ? filelist_recurse(aRemoteDir,nil,&block) : filelist_recurse(aRemoteDir)
122
+ get_files(aRemoteDir,aLocalDir,remote_files,aOptions)
123
+ end
124
+
125
+ def highest_existing(aPath)
126
+ sep = MiscUtils::sniff_seperator(aPath)
127
+ path = MiscUtils::path_parts(File.expand_path(aPath)) if aPath.is_a?(String)
128
+ # now assume path is an Array
129
+ depth = path.length-1
130
+ depth.downto(0) do |i| # from full path up to root
131
+ curr = (path[0]=='' && i==0) ? '/' : path[0..i].join(sep)
132
+ return curr if dir_exists?(curr)
133
+ end
134
+ return sep # root
135
+ end
136
+
137
+ def ensure_dir(aPath,aThorough=false)
138
+ if !aThorough
139
+ mkdir(aPath) unless dir_exists?(aPath)
140
+ else
141
+ return if dir_exists?(aPath)
142
+ path = expand_dir(aPath)
143
+ hi_existing = highest_existing(path)
144
+ # path to create under hi_existing
145
+ to_create = MiscUtils::path_debase(path,hi_existing)
146
+ parts = MiscUtils::path_parts(to_create)
147
+ curr_path = hi_existing
148
+
149
+ parts.each do |part|
150
+ curr_path = File.join(curr_path,part)
151
+ mkdir(curr_path)
152
+ end
153
+ end
154
+ end
155
+
156
+ def put_files(aLocalDir,aRemoteDir,aFiles,aOptions=nil)
157
+ aOptions = {:overwrite => true}.merge(aOptions || {})
158
+
159
+ # convert all files to relative to aLocalDir
160
+ aFiles = aFiles.map { |f| f.bite(MiscUtils::append_slash(aLocalDir)) }.sort
161
+
162
+ filelist = nil
163
+ this_dir = last_dir = nil
164
+ aFiles.each do |r|
165
+ d = File.expand_path(r,aRemoteDir)
166
+ this_dir = File.dirname(d)
167
+ if this_dir!=last_dir
168
+ ensure_dir(this_dir,true)
169
+ filelist = files(this_dir) - ['.','..','.svn']
170
+ end
171
+ if aOptions[:overwrite] || !filelist.member?(File.basename(r))
172
+ puts "Putting #{r}"
173
+ putbinaryfile(File.expand_path(r,aLocalDir), d)
174
+ else
175
+ puts "Skipping #{relative}"
176
+ end
177
+ last_dir = this_dir
178
+ end
179
+ end
180
+
181
+ def put_dir(aLocalDir,aRemoteDir,&block)
182
+ local_files = block_given? ? MiscUtils::recursive_file_list(aLocalDir,true,&block) : MiscUtils::recursive_file_list(aLocalDir)
183
+ put_files(aLocalDir,aRemoteDir,local_files)
184
+ end
185
+
186
+ end
187
+ end
188
+
@@ -0,0 +1,16 @@
1
+ # can :
2
+ # require 'buzzville/recipes' or
3
+ # require 'buzzville/recipes/data'
4
+
5
+ require 'ruby-debug'; debugger
6
+
7
+ require 'capistrano'
8
+ require 'capistrano/cli'
9
+
10
+ @@cap_config = Capistrano::Configuration.respond_to?(:instance) ?
11
+ Capistrano::Configuration.instance(:must_exist) :
12
+ Capistrano.configuration(:must_exist)
13
+
14
+ #Dir.glob(File.join(File.dirname(__FILE__), '/recipes/*.rb')).each { |f| load f }
15
+ Dir.chdir(File.dirname(__FILE__)+'/..') { Dir['buzzville/recipes/*'] }.each {|f| load f }
16
+
@@ -0,0 +1,80 @@
1
+ require 'yore/yore_core'
2
+
3
+ require 'ruby-debug'; debugger
4
+
5
+ @@cap_config.load do
6
+ # cap stage -Dapp=spree yore:pull:p_to_d
7
+ # cap stage -Dapp=spree yore:push:d_to_p
8
+ # cap stage -Dapp=spree yore:save:p
9
+ # cap stage -Dapp=spree -Darchive=spree.tgz yore:load:p
10
+ #desc <<-DESC
11
+ # Save
12
+ #DESC
13
+
14
+ namespace :bv do
15
+ namespace :data do
16
+
17
+ def cap
18
+ @@cap_config
19
+ end
20
+
21
+ def pull_internal(aRemoteEnv,aLocalEnv)
22
+ remote_app_path = ''
23
+ local_app_path = ''
24
+ remote_file = 'blah'
25
+ local_file = 'something'
26
+ # assume yore installed remotely
27
+ cmd = "cd #{remote_app_path}; yore save"
28
+ cmd += " --kind=#{kind}" if kind
29
+ cmd += " --RAILS_ENV=#{aRemoteEnv} #{remote_file}"
30
+ run cmd
31
+ download(remote_file,local_file,:via => :scp)
32
+ local_yore = YoreCore::Yore.launch(nil,{:kind => kind,:RAILS_ENV => aLocalEnv,:basepath=>ENV['PWD']})
33
+ local_yore.load(local_file)
34
+ end
35
+
36
+ def push_internal(aLocalEnv,aRemoteEnv)
37
+ local_yore = YoreCore::Yore.launch(nil,{:kind => kind,:RAILS_ENV => aLocalEnv,:basepath=>ENV['PWD']})
38
+ remote_app_path = File.join(cap.deploy_to,'current')
39
+ local_app_path = local_yore.config[:basepath]
40
+ filename = cap.unique_app_name+"-"+Time.now.strftime('%Y%m%d-%H%M%S')
41
+ remote_file = File.join("/tmp",filename)
42
+ local_file = File.join("/tmp",filename)
43
+ local_yore.save(local_file)
44
+ upload(local_file,remote_file,:via => :scp)
45
+
46
+ run "echo $PATH"
47
+ # assume yore installed remotely
48
+ cmd = "cd #{remote_app_path}; yore load"
49
+ cmd += " --kind=#{kind}" if kind
50
+ cmd += " --RAILS_ENV=#{aRemoteEnv} #{remote_file}"
51
+ run cmd
52
+ end
53
+
54
+ namespace :pull do
55
+ task :p2d do
56
+ pull_internal('production','development')
57
+ end
58
+ task :p2p do
59
+ end
60
+ end
61
+ namespace :push do
62
+ task :d2p do
63
+ push_internal('development','production')
64
+ files.apply_permissions
65
+ deploy.restart
66
+ end
67
+ task :p2p do
68
+ end
69
+ end
70
+ #namespace :load do
71
+ # task :p do
72
+ # end
73
+ #end
74
+ #namespace :save do
75
+ # task :p do
76
+ # end
77
+ #end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,41 @@
1
+ require 'yore/yore_core'
2
+
3
+ @@cap_config.load do
4
+
5
+ namespace :bv do
6
+ namespace :files do
7
+
8
+ def cap
9
+ @@cap_config
10
+ end
11
+
12
+ def internal_permissions
13
+ case kind
14
+ when 'spree' then
15
+
16
+ #puts "set permissions for dirs and files"
17
+ #run_for_all("chmod 750",app_dir,:dirs)
18
+ #run_for_all("chmod 640",app_dir,:files)
19
+ #
20
+ #puts "set permissions for image dirs and files"
21
+ #run_for_all("chmod 770","#{public_dir}/images",:dirs)
22
+ #run_for_all("chmod 660","#{public_dir}/images",:files)
23
+
24
+ run "#{sudo} chgrp -h #{cap.apache_user} #{cap.current_path}" # this is to change owner of link, not target
25
+ run "#{sudo} chown -R #{cap.user}:#{cap.apache_user} #{cap.current_path}/" # the # is reqd to work for symlinks
26
+ run "#{sudo} chmod -R g+w #{cap.current_path}/" # unfortunately necessary as capistrano forgets to do this later with sudo
27
+ run "#{sudo} chown #{cap.apache_user}:#{cap.apache_user} #{cap.current_path}/config/environment.rb" # very important for passenger, which uses the owner of this file to run as
28
+ run "#{sudo} touch #{cap.current_path}/log/production.log"
29
+ run "#{sudo} chmod 666 #{cap.current_path}/log/production.log"
30
+ when 'rails' then
31
+ # dfdsf
32
+ end
33
+ end
34
+
35
+ task :apply_permissions do
36
+ internal_permissions
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,101 @@
1
+ @@cap_config.load do
2
+
3
+ namespace :bv do
4
+ namespace :ssl do
5
+ extend CapUtils
6
+
7
+ def cap
8
+ @@cap_config
9
+ end
10
+
11
+ # should set key_dir
12
+ task :new_key do
13
+ set :local_key_dir,File.expand_path('~/.ssh') unless (local_key_dir rescue false)
14
+ if !(key_name rescue false)
15
+ default_key_name = (new_user rescue nil) || 'new_key'
16
+ key_name_response = Capistrano::CLI.ui.ask("Enter a name for the key without extension (default: #{default_key_name}):").strip!
17
+ set :key_name, (key_name_response.nil? || key_name_response.empty?) ? default_key_name : key_name_response
18
+ end
19
+ pub = File.join(local_key_dir,key_name+'.pub')
20
+ ppk = File.join(local_key_dir,key_name+'.ppk')
21
+ raise StandardError.new("#{pub} or #{ppk} already exists") if File.exists?(pub) || File.exists?(ppk)
22
+ passphrase = Capistrano::CLI.password_prompt("Enter a passphrase (>= 5 characters):")
23
+ # create key - asks for name & passphrase and stores in ~/.ssh
24
+ shell "ssh-keygen -N #{passphrase} -f #{File.join(local_key_dir,key_name)}"
25
+ shell "#{sudo} mv #{File.join(local_key_dir,key_name)} #{ppk}"
26
+ shell "#{sudo} sed -i -e 's/== .*$/== #{key_name}.pub/' #{pub}"
27
+ shell "#{sudo} chown $USER #{pub}"
28
+ shell "#{sudo} chown $USER #{ppk}"
29
+ Capistrano::CLI.ui.say "created #{pub}"
30
+ Capistrano::CLI.ui.say "created #{ppk}"
31
+ Capistrano::CLI.ui.say "Recommended: ssh-add #{ppk}"
32
+ end
33
+
34
+ task :install_key do
35
+ set :new_user,Capistrano::CLI.ui.ask("Enter a username for installing the key :") unless (new_user rescue false)
36
+ set :key_name,Capistrano::CLI.ui.ask("Enter a name for the key eg. user name (without extension):") unless (key_name rescue false)
37
+ set :key_dir,"/home/#{new_user}/.ssh" unless (key_dir rescue false)
38
+ set :local_key_dir,File.expand_path("~/.ssh") unless (local_key_dir rescue false)
39
+
40
+ # prepare key dir for new_user
41
+ auth_keys = File.join(key_dir,'authorized_keys')
42
+ run "#{sudo} mkdir -p #{key_dir}"
43
+ run "#{sudo} touch #{auth_keys}"
44
+ run "#{sudo} chown #{new_user}:#{new_user} #{key_dir}"
45
+ run "#{sudo} chown #{new_user}:#{new_user} #{auth_keys}"
46
+ run "#{sudo} chmod 700 #{key_dir}"
47
+ run "#{sudo} chmod 600 #{auth_keys}"
48
+
49
+ # upload and install in authorized_keys
50
+ if capture("#{sudo} grep -q #{key_name}.pub #{auth_keys};echo $?")=='0'
51
+ puts "Key already installed. Not installing"
52
+ else
53
+ admin_dir = "/home/#{cap.user}"
54
+
55
+ run "#{sudo} rm -f #{File.join(admin_dir,key_name+'.pub')}"
56
+ upload(File.join(local_key_dir,key_name+'.pub'),File.join(admin_dir,key_name+'.pub'),:via => :scp,:mode => 600)
57
+ run "#{sudo} echo '' | #{sudo} tee -a #{auth_keys}" # new line
58
+ run "#{sudo} cat #{File.join(admin_dir,key_name+'.pub')} | #{sudo} tee -a #{auth_keys}"
59
+ run "#{sudo} rm #{File.join(admin_dir,key_name+'.pub')}"
60
+ run "#{sudo} sudo /etc/init.d/ssh restart"
61
+ end
62
+
63
+ # add to sshd_config AllowUsers if not already
64
+ allow_users = []
65
+ allow_str = capture("#{sudo} grep AllowUsers /etc/ssh/sshd_config")
66
+ allow_str.each_line do |line|
67
+ next unless line =~ /^AllowUsers /
68
+ allow_users += line.bite('AllowUsers').split(' ')
69
+ end
70
+ if !allow_users.include?(new_user)
71
+ run "#{sudo} sed -i -e 's/^AllowUsers /AllowUsers #{new_user} /' /etc/ssh/sshd_config"
72
+ end
73
+
74
+ s = <<EOS
75
+
76
+ You probably need to append :
77
+
78
+ Host #{host}
79
+ IdentityFile #{File.join(local_key_dir,key_name+'.ppk')}
80
+ User #{new_user}
81
+ Port #{sessions.values.first.transport.peer[:port]}
82
+
83
+ to your ~/.ssh/config file
84
+
85
+ and run locally :
86
+
87
+ ssh-add -K #{File.join(local_key_dir,key_name+'.ppk')}
88
+
89
+ and then you should be able to :
90
+
91
+ ssh #{new_user}@#{host}
92
+
93
+ without entering a password and the passphrase will be in your keychain.
94
+
95
+ EOS
96
+ Capistrano::CLI.ui.say(s)
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,46 @@
1
+ @@cap_config.load do
2
+
3
+ namespace :bv do
4
+ namespace :user do
5
+ extend CapUtils
6
+
7
+ def cap
8
+ @@cap_config
9
+ end
10
+
11
+ #sudo adduser ffff
12
+ #sudo passwd ffff
13
+ #sudo usermod -a -G www-data ffff
14
+ #cd /home/ffff/
15
+ #sudo ln -s /var/www/ffff/public public
16
+ #sudo chown -h ffff:www-data public
17
+ #sudo /etc/init.d/pure-ftpd restart
18
+
19
+ task :create do
20
+ set :new_user, Capistrano::CLI.ui.ask("Enter a name for the new user:") unless (self.new_user rescue false)
21
+ password = Capistrano::CLI.password_prompt("Enter a password for the new user:") unless (self.new_password rescue false)
22
+ set :user,admin_user
23
+
24
+ adduser(new_user,password)
25
+ add_user_to_group(new_user,apache_user)
26
+
27
+ Capistrano::CLI.ui.say "please run \"sudo sudoedit /etc/sudoers\" add the following line :"
28
+ Capistrano::CLI.ui.say "#{new_user} ALL=(ALL) ALL"
29
+ end
30
+
31
+ task :new_key do
32
+ set :new_user, Capistrano::CLI.ui.ask("Enter the user name:") unless (self.new_user rescue false)
33
+ set :user,admin_user
34
+ bv.ssl.new_key
35
+ bv.ssl.install_key
36
+ end
37
+
38
+ task :delete do
39
+ set :new_user, Capistrano::CLI.ui.ask("Enter the user name:") unless (self.new_user rescue false)
40
+ set :user,admin_user
41
+ run "#{sudo} userdel -rf #{new_user}"
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ # when you want to load the live version of buzzville, not the gem :
2
+ # require File.join(File.dirname(__FILE__),'../../../../../buzzville/lib/buzzville_dev.rb');
3
+ require_paths_first '.'
4
+ require 'buzzville'
5
+
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class BuzzvilleTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'buzzville'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buzzville
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - buzzware
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-06 00:00:00 +08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: buzzcore
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.2.5
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yore
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.5
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: cmdparse
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.2
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: thoughtbot-shoulda
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: Capistrano recipes and ruby code relating to deployment
56
+ email: contact@buzzware.com.au
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ files:
65
+ - .document
66
+ - .gitignore
67
+ - LICENSE
68
+ - README.rdoc
69
+ - Rakefile
70
+ - VERSION
71
+ - buzzville.vpj
72
+ - buzzville.vpw
73
+ - lib/buzzville.rb
74
+ - lib/buzzville/cap_utils.rb
75
+ - lib/buzzville/ftp_extra.rb
76
+ - lib/buzzville/recipes.rb
77
+ - lib/buzzville/recipes/data.rb
78
+ - lib/buzzville/recipes/files.rb
79
+ - lib/buzzville/recipes/ssl.rb
80
+ - lib/buzzville/recipes/user.rb
81
+ - lib/buzzville_dev.rb
82
+ - test/buzzville_test.rb
83
+ - test/test_helper.rb
84
+ has_rdoc: true
85
+ homepage: http://github.com/buzzware/buzzville
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options:
90
+ - --charset=UTF-8
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ version:
105
+ requirements: []
106
+
107
+ rubyforge_project: buzzware
108
+ rubygems_version: 1.3.5
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: Capistrano recipes and ruby code relating to deployment
112
+ test_files:
113
+ - test/buzzville_test.rb
114
+ - test/test_helper.rb