capistrano-template 0.0.1

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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +22 -0
  5. data/.rubocop_todo.yml +8 -0
  6. data/.travis.yml +4 -0
  7. data/.versions.conf +4 -0
  8. data/CHANGELOG.md +0 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +66 -0
  12. data/Rakefile +16 -0
  13. data/capistrano-template.gemspec +35 -0
  14. data/lib/capistrano/capistrano_plugin_template.rb +5 -0
  15. data/lib/capistrano/template.rb +11 -0
  16. data/lib/capistrano/template/helpers/dsl.rb +61 -0
  17. data/lib/capistrano/template/helpers/paths_lookup.rb +33 -0
  18. data/lib/capistrano/template/helpers/renderer.rb +30 -0
  19. data/lib/capistrano/template/helpers/template_digester.rb +19 -0
  20. data/lib/capistrano/template/helpers/uploader.rb +94 -0
  21. data/lib/capistrano/template/tasks/template_defaults.cap +13 -0
  22. data/lib/capistrano/template/version.rb +5 -0
  23. data/spec/integration/capistrano/template/helpers/dsl_spec.rb +117 -0
  24. data/spec/integration/capistrano/template/helpers/paths_lookup_spec.rb +46 -0
  25. data/spec/integration/capistrano/template/helpers/uploader_spec.rb +100 -0
  26. data/spec/spec_helper.rb +42 -0
  27. data/spec/unit/capistrano/template/helpers/dsl_spec.rb +60 -0
  28. data/spec/unit/capistrano/template/helpers/paths_lookup_spec.rb +54 -0
  29. data/spec/unit/capistrano/template/helpers/renderer_spec.rb +43 -0
  30. data/spec/unit/capistrano/template/helpers/template_digester_spec.rb +36 -0
  31. data/spec/unit/capistrano/template/helpers/uploader_spec.rb +103 -0
  32. data/spec/unit/capistrano/template_spec.rb +7 -0
  33. metadata +186 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9069d7f7aba60eb93dbe6cd252321ae37b76fc0
4
+ data.tar.gz: e78c5df43dc90a425fe35c65b4a8314ef98a8156
5
+ SHA512:
6
+ metadata.gz: 70f3144f5b14657ee87859ec9033872329c20ee8f2630090f236082e5e59d10f267cacee5a826fd132a499c34332d82ec4ca147b403b2b932ac74f35990748b5
7
+ data.tar.gz: 8c9b1a43320b332d7daa5a7071d02954e73b28acedd4abdda0af71c1acd0fc304f079015bb1177029c7ab44172b62da9e72244589b7c0610ad1fd48ed0d67710
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,22 @@
1
+
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+
5
+ LineLength:
6
+ Max: 160
7
+
8
+ Documentation:
9
+ Enabled: false
10
+
11
+ ParameterLists:
12
+ Max: 15
13
+
14
+ MethodLength:
15
+ Max: 50
16
+
17
+ # @see http://www.rubytapas.com/episodes/24-Incidental-Change
18
+ TrailingComma:
19
+ Enabled: false
20
+
21
+ RegexpLiteral:
22
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,8 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2014-05-26 11:14:26 +0200 using RuboCop version 0.22.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.0
data/.versions.conf ADDED
@@ -0,0 +1,4 @@
1
+ ruby=ruby-2.1.0
2
+ ruby-gemset=capistrano-template
3
+ #ruby-gem-install=bundler rake
4
+ #ruby-bundle-install=true
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-template.gemspec
4
+ gemspec
5
+
6
+ gem 'simplecov', require: false, group: :test
7
+ gem 'coveralls', require: false
8
+ gem 'rubocop', require: false
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dieter Späth
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Capistrano::Template
2
+
3
+ A capistrano 3 plugin that aids in rendering erb templates and
4
+ uploads the content to the server if the file does not exists at
5
+ the remote host or the content did change.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'capistrano-template'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install capistrano-template
20
+
21
+ ## Usage
22
+
23
+ In your Capfile:
24
+
25
+ ```ruby
26
+ require 'capistrano/capistrano_plugin_template'
27
+
28
+ ```
29
+
30
+ In your task or stage file:
31
+
32
+ ```ruby
33
+
34
+ desc 'Upload a rendered erb-template'
35
+ task :setup do
36
+ on roles :all
37
+ template 'assets.host.site'
38
+ end
39
+
40
+ on roles :all
41
+ template 'other.template.name', 'execute_some_thing.sh', 0750
42
+ end
43
+
44
+ end
45
+
46
+ ```
47
+
48
+ ## Settings
49
+
50
+ This settings can be changed in your Capfile, deploy.rb or stage file.
51
+
52
+ | Variable | Default | Description |
53
+ |-----------------------|:--------------------:|-----------------------------------------------------------------------|
54
+ |`templating_digster` | `templating_digster` | Checksum algorythmous for rendered template to check for remote diffs |
55
+ |`templating_digest_cmd`| `%Q{test "Z$(openssl md5 %<path>s| sed "s/^.*= *//")" = "Z%<digest>s" }` | Remote command to validate a digest. Format placeholders path is replaces by full `path to the remote file and `digest` with the digest calculated in capistrano. |
56
+ |`templating_mode_test_cmd`| `%Q{ [ "Z$(printf "%%.4o" 0$(stat -c "%%a" %<path>s 2>/dev/null || stat -f "%%A" %<path>s))" != "Z%<mode>s" ] } | Test command to check the remote file permissions. |
57
+ | `templating_paths`| `["config/deploy/templates/#{fetch(:stage)}/%<host>s","config/deploy/templates/#{fetch(:stage)}", "config/deploy/templates/shared/%<host>s","config/deploy/templates/shared"]`| Folder to look for a template to render. |
58
+
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it ( http://github.com/<my-github-username>/capistrano-template/fork )
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ Rubocop::RakeTask.new
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task default: :spec
10
+ task test: :spec
11
+
12
+ desc 'Run RSpec with code coverage'
13
+ task :coverage do
14
+ ENV['SIMPLE_COVERAGE'] = 'true'
15
+ Rake::Task['spec'].execute
16
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capistrano/template/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'capistrano-template'
8
+ spec.version = Capistrano::Template::VERSION
9
+ spec.authors = ['Dieter Späth']
10
+ spec.email = ['d.spaeth@faber.de']
11
+ spec.summary = %q(Erb-Template rendering and upload for capistrano 3)
12
+ spec.description = %q(A capistrano 3 plugin that aids in rendering erb templates and
13
+ uploads the content to the server if the file does not exists at
14
+ the remote host or the content did change)
15
+ spec.homepage = ''
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.required_ruby_version = '>= 2.0.0'
24
+ spec.add_dependency 'capistrano', '~> 3.0'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.5'
27
+ spec.add_development_dependency 'rake'
28
+
29
+ spec.add_development_dependency 'rspec', '2.99.0.rc1'
30
+ # show nicely how many specs have to be run
31
+ spec.add_development_dependency 'fuubar'
32
+ # extended console
33
+ spec.add_development_dependency 'pry'
34
+ spec.add_development_dependency 'pry-remote'
35
+ end
@@ -0,0 +1,5 @@
1
+ require 'capistrano/template'
2
+
3
+ include Capistrano::Template::Helpers::DSL
4
+
5
+ import File.join(__dir__, 'template', 'tasks', 'template_defaults.cap')
@@ -0,0 +1,11 @@
1
+ require 'delegate'
2
+ require 'capistrano/template/version'
3
+
4
+ module Capistrano
5
+ module Template
6
+ end
7
+ end
8
+
9
+ require 'capistrano/template/helpers/uploader'
10
+ require 'capistrano/template/helpers/paths_lookup'
11
+ require 'capistrano/template/helpers/dsl'
@@ -0,0 +1,61 @@
1
+ module Capistrano
2
+ module Template
3
+ module Helpers
4
+ module DSL
5
+ def template(from, to = nil, mode = 0640)
6
+ fail ::ArgumentError, "template #{from} not found Paths: #{template_paths_lookup.paths_for_file(from).join(':')}" unless template_exists?(from)
7
+
8
+ to ||= "#{release_path}/#{File.basename(from, '.erb')}"
9
+ to = remote_path_for(to, true)
10
+
11
+ template = _template_factory.call(template_file(from), self, fetch(:templating_digster))
12
+
13
+ _uploader_factory.call(to, self,
14
+ digest: template.digest,
15
+ digest_cmd: fetch(:templating_digest_cmd),
16
+ mode_test_cmd: fetch(:templating_mode_test_cmd),
17
+ mode: mode,
18
+ io: template.as_io
19
+ ).call
20
+ end
21
+
22
+ def template_exists?(template)
23
+ template_paths_lookup.template_exists?(template)
24
+ end
25
+
26
+ def template_file(template)
27
+ template_paths_lookup.template_file(template)
28
+ end
29
+
30
+ def template_paths_lookup
31
+ _paths_factory.call(fetch(:templating_paths), self)
32
+ end
33
+
34
+ def _uploader_factory
35
+ ->(*args) { Uploader.new(*args) }
36
+ end
37
+
38
+ def _paths_factory
39
+ ->(*args) { PathsLookup.new(*args) }
40
+ end
41
+
42
+ def remote_path_for(path, includes_filename = false)
43
+ filename = nil
44
+
45
+ if includes_filename
46
+ filename = File.basename(path)
47
+ path = File.dirname(path)
48
+ end
49
+
50
+ remote_path = capture("(cd #{path} && pwd -P) || readlink -sf #{path}").chomp
51
+
52
+ includes_filename ? File.join(remote_path, filename) : remote_path
53
+ end
54
+
55
+ def _template_factory
56
+ ->(from, context, digester) {TemplateDigester.new(Renderer.new(from, context), digester) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,33 @@
1
+ module Capistrano
2
+ module Template
3
+ module Helpers
4
+ class PathsLookup < SimpleDelegator
5
+ attr_accessor :paths
6
+
7
+ def initialize(paths, context)
8
+ super context
9
+ self.paths = paths
10
+ end
11
+
12
+ def template_exists?(filename)
13
+ !template_file(filename).nil?
14
+ end
15
+
16
+ def template_file(filename)
17
+ paths_for_file(filename).find { |path| existence_check(path) }
18
+ end
19
+
20
+ def existence_check(path)
21
+ File.exist?(path)
22
+ end
23
+
24
+ def paths_for_file(filename)
25
+ paths.map do |path|
26
+ path = path % { host: host }
27
+ ["#{path}/#{filename}.erb", "#{path}/#{filename}"]
28
+ end.flatten
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ module Capistrano
2
+ module Template
3
+ module Helpers
4
+ class Renderer < SimpleDelegator
5
+ attr_accessor :from, :reader
6
+
7
+ def initialize(from, context, reader: File)
8
+ super context
9
+
10
+ self.from = from
11
+ self.reader = reader
12
+ end
13
+
14
+ def as_str
15
+ @rendered_template ||= ERB.new(template_content).result(binding)
16
+ end
17
+
18
+ def as_io
19
+ StringIO.new(as_str)
20
+ end
21
+
22
+ protected
23
+
24
+ def template_content
25
+ reader.read(from)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ module Capistrano
2
+ module Template
3
+ module Helpers
4
+ class TemplateDigester < SimpleDelegator
5
+ attr_accessor :digest_algo
6
+
7
+ def initialize(renderer, digest_algo)
8
+ super renderer
9
+
10
+ self.digest_algo = digest_algo
11
+ end
12
+
13
+ def digest
14
+ digest_algo.call(as_str)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,94 @@
1
+ module Capistrano
2
+ module Template
3
+ module Helpers
4
+ require 'capistrano/template/helpers/renderer'
5
+ require 'capistrano/template/helpers/template_digester'
6
+
7
+ class Uploader
8
+ attr_accessor :io,
9
+ :digest,
10
+ :full_to_path,
11
+ :digest_cmd,
12
+ :mode,
13
+ :remote_handler,
14
+ :mode_test_cmd
15
+
16
+ def initialize(full_to_path, remote_handler,
17
+ mode: 0640,
18
+ mode_test_cmd: nil,
19
+ digest: nil,
20
+ digest_cmd: nil,
21
+ io: nil
22
+ )
23
+ self.remote_handler = remote_handler
24
+
25
+ self.full_to_path = full_to_path
26
+
27
+ self.digest_cmd = digest_cmd
28
+ self.mode = mode
29
+ self.mode_test_cmd = mode_test_cmd
30
+
31
+ self.io = io
32
+ self.digest = digest
33
+ end
34
+
35
+ def call
36
+ upload_as_file
37
+ set_mode
38
+ end
39
+
40
+ def upload_as_file
41
+ if file_changed?
42
+ remote_handler.info "copying to: #{full_to_path}"
43
+ remote_handler.upload! io, full_to_path
44
+ else
45
+ remote_handler.info "File #{full_to_path} on host #{host} not changed"
46
+ end
47
+ end
48
+
49
+ def host
50
+ remote_handler.host
51
+ end
52
+
53
+ def set_mode
54
+ if permission_changed?
55
+ remote_handler.info "permission changed for file #{full_to_path} on #{host} set new permissions"
56
+ remote_handler.execute 'chmod', octal_mode_str, full_to_path
57
+ else
58
+ remote_handler.info "permission not changed for file #{full_to_path} on #{host}"
59
+ end
60
+ end
61
+
62
+ def file_changed?
63
+ !__check__(digest_cmd)
64
+ end
65
+
66
+ def permission_changed?
67
+ __check__(mode_test_cmd)
68
+ end
69
+
70
+ protected
71
+
72
+ def __check__(*args)
73
+ remote_handler.test(*args)
74
+ end
75
+
76
+ def octal_mode_str
77
+ format '%.4o' , mode
78
+ end
79
+
80
+ def digest_cmd
81
+ @digest_cmd % { digest: digest,
82
+ path: full_to_path }
83
+ end
84
+
85
+ def mode_test_cmd
86
+ @mode_test_cmd % {
87
+ path: full_to_path,
88
+ mode: octal_mode_str
89
+ }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end