voog-kit 0.1.8
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +142 -0
- data/Rakefile +1 -0
- data/bin/kit +212 -0
- data/lib/voog/dtk/filemanager.rb +784 -0
- data/lib/voog/dtk/guard.rb +147 -0
- data/lib/voog/dtk/notifier.rb +34 -0
- data/lib/voog/dtk/version.rb +5 -0
- data/lib/voog/dtk.rb +131 -0
- data/spec/fixtures/.DS_Store +0 -0
- data/spec/fixtures/.voog +3 -0
- data/spec/fixtures/.voog2 +7 -0
- data/spec/fixtures/images/bullet.png +0 -0
- data/spec/fixtures/layout.json +12 -0
- data/spec/fixtures/layout_asset.json +15 -0
- data/spec/fixtures/layout_assets.json +7 -0
- data/spec/fixtures/layouts.json +9 -0
- data/spec/fixtures/manifest.json +17 -0
- data/spec/models/dtk/config_spec.rb +82 -0
- data/spec/models/dtk/filemanager_spec.rb +524 -0
- data/spec/spec_helper.rb +38 -0
- data/voog-kit.gemspec +34 -0
- metadata +238 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'guard'
|
2
|
+
require 'guard/guard'
|
3
|
+
require 'guard/plugin'
|
4
|
+
|
5
|
+
module Guard
|
6
|
+
class Shell < Guard
|
7
|
+
VERSION = '0.5.2'
|
8
|
+
|
9
|
+
# Calls #run_all if the :all_on_start option is present.
|
10
|
+
def start
|
11
|
+
run_all if options[:all_on_start]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Call #run_on_change for all files which match this guard.
|
15
|
+
def run_all
|
16
|
+
run_on_modifications(Watcher.match_files(self, Dir.glob('{,**/}*{,.*}').uniq))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Print the result of the command(s), if there are results to be printed.
|
20
|
+
def run_on_modifications(res)
|
21
|
+
puts res if res
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Voog::Dtk
|
27
|
+
class ::Guard::Watchman < ::Guard::Plugin
|
28
|
+
attr_accessor :options, :filemanager
|
29
|
+
|
30
|
+
# Initializes a Guard plugin.
|
31
|
+
# Don't do any work here, especially as Guard plugins get initialized even if they are not in an active group!
|
32
|
+
#
|
33
|
+
# @param [Hash] options the custom Guard plugin options
|
34
|
+
# @option options [Array<Guard::Watcher>] watchers the Guard plugin file watchers
|
35
|
+
# @option options [Symbol] group the group this Guard plugin belongs to
|
36
|
+
# @option options [Boolean] any_return allow any object to be returned from a watcher
|
37
|
+
#
|
38
|
+
def initialize(options = {})
|
39
|
+
super
|
40
|
+
@options = options
|
41
|
+
end
|
42
|
+
|
43
|
+
# Called once when Guard starts. Please override initialize method to init stuff.
|
44
|
+
#
|
45
|
+
# @raise [:task_has_failed] when start has failed
|
46
|
+
# @return [Object] the task result
|
47
|
+
#
|
48
|
+
def start
|
49
|
+
::Guard::UI.info 'Guard::Voog is running'
|
50
|
+
# run_all
|
51
|
+
end
|
52
|
+
|
53
|
+
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
|
54
|
+
#
|
55
|
+
# @raise [:task_has_failed] when stop has failed
|
56
|
+
# @return [Object] the task result
|
57
|
+
#
|
58
|
+
def stop
|
59
|
+
::Guard::UI.info 'Guard::Voog stopped'
|
60
|
+
end
|
61
|
+
|
62
|
+
# Called when `reload|r|z + enter` is pressed.
|
63
|
+
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
64
|
+
#
|
65
|
+
# @raise [:task_has_failed] when reload has failed
|
66
|
+
# @return [Object] the task result
|
67
|
+
#
|
68
|
+
# def reload
|
69
|
+
# end
|
70
|
+
|
71
|
+
# Called when just `enter` is pressed
|
72
|
+
# This method should be principally used for long action like running all specs/tests/...
|
73
|
+
#
|
74
|
+
# @raise [:task_has_failed] when run_all has failed
|
75
|
+
# @return [Object] the task result
|
76
|
+
#
|
77
|
+
# def run_all
|
78
|
+
# end
|
79
|
+
|
80
|
+
# Default behaviour on file(s) changes that the Guard plugin watches.
|
81
|
+
# @param [Array<String>] paths the changes files or paths
|
82
|
+
# @raise [:task_has_failed] when run_on_change has failed
|
83
|
+
# @return [Object] the task result
|
84
|
+
#
|
85
|
+
# def run_on_changes(paths)
|
86
|
+
# end
|
87
|
+
|
88
|
+
# Called on file(s) additions that the Guard plugin watches.
|
89
|
+
#
|
90
|
+
# @param [Array<String>] paths the changes files or paths
|
91
|
+
# @raise [:task_has_failed] when run_on_additions has failed
|
92
|
+
# @return [Object] the task result
|
93
|
+
#
|
94
|
+
def run_on_additions(paths)
|
95
|
+
@filemanager.add_to_manifest paths
|
96
|
+
@filemanager.upload_files paths
|
97
|
+
rescue => e
|
98
|
+
@filemanager.notifier.newline
|
99
|
+
Voog::Dtk.handle_exception e, @filemanager.notifier
|
100
|
+
end
|
101
|
+
|
102
|
+
# Called on file(s) removals that the Guard plugin watches.
|
103
|
+
#
|
104
|
+
# @param [Array<String>] paths the changes files or paths
|
105
|
+
# @raise [:task_has_failed] when run_on_removals has failed
|
106
|
+
# @return [Object] the task result
|
107
|
+
#
|
108
|
+
def run_on_removals(paths)
|
109
|
+
@filemanager.remove_from_manifest paths
|
110
|
+
# @filemanager.delete_remote_files paths
|
111
|
+
rescue => e
|
112
|
+
@filemanager.notifier.newline
|
113
|
+
Voog::Dtk.handle_exception e, @filemanager.notifier
|
114
|
+
end
|
115
|
+
|
116
|
+
# Called on file(s) modifications that the Guard plugin watches.
|
117
|
+
#
|
118
|
+
# @param [Array<String>] paths the changes files or paths
|
119
|
+
# @raise [:task_has_failed] when run_on_modifications has failed
|
120
|
+
# @return [Object] the task result
|
121
|
+
#
|
122
|
+
def run_on_modifications(paths)
|
123
|
+
@filemanager.upload_files paths
|
124
|
+
@filemanager.notifier.newline
|
125
|
+
rescue => e
|
126
|
+
@filemanager.notifier.newline
|
127
|
+
Voog::Dtk.handle_exception e, @filemanager.notifier
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Guuard
|
132
|
+
def initialize(filemanager)
|
133
|
+
@filemanager = filemanager
|
134
|
+
end
|
135
|
+
|
136
|
+
def run
|
137
|
+
guardfile = <<-EOF
|
138
|
+
guard 'watchman' do
|
139
|
+
watch(%r{^(layout|component|image|asset|javascript|stylesheet)s/.*})
|
140
|
+
end
|
141
|
+
EOF
|
142
|
+
|
143
|
+
::Guard.start(guardfile_contents: guardfile)
|
144
|
+
::Guard.guards('watchman').first.filemanager = @filemanager
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
module Voog::Dtk
|
4
|
+
class Notifier
|
5
|
+
def initialize(output=$stderr, silent=false)
|
6
|
+
@output = output
|
7
|
+
@silent = silent
|
8
|
+
end
|
9
|
+
|
10
|
+
def normal(message)
|
11
|
+
@output.print(message) unless @silent
|
12
|
+
end
|
13
|
+
|
14
|
+
def info(message)
|
15
|
+
@output.print(message.white + ' ') unless @silent
|
16
|
+
end
|
17
|
+
|
18
|
+
def success(message)
|
19
|
+
@output.print(message.green) unless @silent
|
20
|
+
end
|
21
|
+
|
22
|
+
def error(message)
|
23
|
+
@output.print(message.red) unless @silent
|
24
|
+
end
|
25
|
+
|
26
|
+
def warning(message)
|
27
|
+
@output.print(message.yellow) unless @silent
|
28
|
+
end
|
29
|
+
|
30
|
+
def newline
|
31
|
+
@output.print("\n") unless @silent
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/voog/dtk.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'voog/dtk/version'
|
2
|
+
require 'parseconfig'
|
3
|
+
require 'prettyprint'
|
4
|
+
|
5
|
+
module Voog
|
6
|
+
module Dtk
|
7
|
+
|
8
|
+
CONFIG_FILENAME = '.voog'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def config_exists?(filename=CONFIG_FILENAME)
|
12
|
+
filename && !filename.empty? && File.exists?(filename)
|
13
|
+
end
|
14
|
+
|
15
|
+
def global_config_exists?(filename=CONFIG_FILENAME)
|
16
|
+
filename && !filename.empty? && File.exists?([ENV['HOME'], filename].join('/'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def read_config(block = nil, file = CONFIG_FILENAME)
|
20
|
+
config = {
|
21
|
+
:host => nil,
|
22
|
+
:api_token => nil
|
23
|
+
}
|
24
|
+
local_config = config_exists?(file) ? ParseConfig.new(File.expand_path(file)).params : {}
|
25
|
+
global_config = global_config_exists?(file) ? ParseConfig.new(File.expand_path([ENV['HOME'], file].join('/'))).params : {}
|
26
|
+
|
27
|
+
options = global_config.merge(local_config)
|
28
|
+
|
29
|
+
unless options.empty?
|
30
|
+
@block = if block.nil?
|
31
|
+
options.keys.first
|
32
|
+
else
|
33
|
+
if options.key?(block)
|
34
|
+
block
|
35
|
+
else
|
36
|
+
fail "Site '#{block}' not found in the configuration file!".red
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
config[:host] = options[@block].fetch("host")
|
41
|
+
config[:api_token] = options[@block].fetch("api_token")
|
42
|
+
end
|
43
|
+
config
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_config(host, api_token, block, silent=false)
|
47
|
+
@file = if config_exists?
|
48
|
+
CONFIG_FILENAME
|
49
|
+
elsif global_config_exists?
|
50
|
+
[ENV['HOME'], CONFIG_FILENAME].join('/')
|
51
|
+
else
|
52
|
+
File.new(CONFIG_FILENAME)
|
53
|
+
CONFIG_FILENAME
|
54
|
+
end
|
55
|
+
|
56
|
+
options = ParseConfig.new(File.expand_path(@file))
|
57
|
+
|
58
|
+
if options.params.key?(block)
|
59
|
+
puts "Writing new configuration options to existing config block.".white unless silent
|
60
|
+
options.params[block]['host'] = host unless host.empty?
|
61
|
+
options.params[block]['api_token'] = api_token unless api_token.empty?
|
62
|
+
else
|
63
|
+
puts "Writing configuration options to new config block.".white unless silent
|
64
|
+
options.params[block] = {
|
65
|
+
'host' => host,
|
66
|
+
'api_token' => api_token
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
File.open(@file, 'w+') do |file|
|
71
|
+
file.truncate(0)
|
72
|
+
file << "\n"
|
73
|
+
options.params.each do |param|
|
74
|
+
file << "[#{param[0]}]\n"
|
75
|
+
param[1].keys.each do |key|
|
76
|
+
file << " #{key}=#{param[1][key]}\n"
|
77
|
+
end
|
78
|
+
file << "\n"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_api_error?(exception)
|
84
|
+
[
|
85
|
+
Faraday::ClientError,
|
86
|
+
Faraday::ConnectionFailed,
|
87
|
+
Faraday::ParsingError,
|
88
|
+
Faraday::TimeoutError,
|
89
|
+
Faraday::ResourceNotFound
|
90
|
+
].include? exception.class
|
91
|
+
end
|
92
|
+
|
93
|
+
def print_debug_info(exception)
|
94
|
+
puts
|
95
|
+
puts "Exception: #{exception.class}"
|
96
|
+
if is_api_error?(exception) && exception.respond_to?(:response) && exception.response
|
97
|
+
pp exception.response
|
98
|
+
end
|
99
|
+
puts exception.backtrace
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_exception(exception, debug, notifier=nil)
|
103
|
+
error_msg = if is_api_error?(exception)
|
104
|
+
if exception.respond_to?(:response) && exception.response
|
105
|
+
if exception.response.fetch(:headers, {}).fetch(:content_type, '') =~ /application\/json/
|
106
|
+
body = JSON.parse(exception.response.fetch(:body))
|
107
|
+
"#{body.fetch('message', '')} #{("Errors: " + body.fetch('errors', '').inspect) if body.fetch('errors', nil)}".red
|
108
|
+
else
|
109
|
+
exception.response.fetch(:body)
|
110
|
+
end + "(error code #{exception.response[:status]})".red
|
111
|
+
else
|
112
|
+
"#{exception}"
|
113
|
+
end
|
114
|
+
else
|
115
|
+
"#{exception}"
|
116
|
+
end
|
117
|
+
|
118
|
+
if notifier
|
119
|
+
notifier.newline
|
120
|
+
notifier.error error_msg
|
121
|
+
notifier.newline
|
122
|
+
else
|
123
|
+
puts error_msg
|
124
|
+
end
|
125
|
+
print_debug_info(exception) if debug
|
126
|
+
rescue => e
|
127
|
+
handle_exception e, debug, notifier
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
Binary file
|
data/spec/fixtures/.voog
ADDED
Binary file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"id": 14,
|
3
|
+
"parent_id": null,
|
4
|
+
"title": "Test",
|
5
|
+
"layout_name": "component",
|
6
|
+
"content_type": "component",
|
7
|
+
"component": true,
|
8
|
+
"url": "http://voog.local/admin/api/layouts/14",
|
9
|
+
"created_at": "2010-09-09 14:24:43 UTC",
|
10
|
+
"updated_at": "2010-09-14 14:49:51 UTC",
|
11
|
+
"body": "test body"
|
12
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"id": 22,
|
3
|
+
"filename": "test.css",
|
4
|
+
"asset_type": "stylesheet",
|
5
|
+
"content_type": "text/css",
|
6
|
+
"size": 180,
|
7
|
+
"width": null,
|
8
|
+
"height": null,
|
9
|
+
"editable": true,
|
10
|
+
"url": "http://voog.local/admin/api/layout_assets/22",
|
11
|
+
"public_url": "http://localhost/stylesheets/test.css",
|
12
|
+
"created_at": "2010-09-09 15:03:06 UTC",
|
13
|
+
"updated_at": "2010-09-16 14:19:28 UTC",
|
14
|
+
"data": "test data"
|
15
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
{
|
2
|
+
"layouts": [
|
3
|
+
{
|
4
|
+
"component": true,
|
5
|
+
"content_type": "component",
|
6
|
+
"file": "test_component.tpl",
|
7
|
+
"layout_name": "test_component",
|
8
|
+
"title": "test_component"
|
9
|
+
}
|
10
|
+
],
|
11
|
+
"assets": [{
|
12
|
+
"content_type": "application/javascript",
|
13
|
+
"kind": "javascripts",
|
14
|
+
"file": "javascripts/test.js",
|
15
|
+
"filename": "test.js"
|
16
|
+
}]
|
17
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Voog::Dtk do
|
4
|
+
|
5
|
+
describe '.read_config' do
|
6
|
+
|
7
|
+
context 'when a config file is provided' do
|
8
|
+
|
9
|
+
let(:config) { Voog::Dtk.read_config nil, 'spec/fixtures/.voog' }
|
10
|
+
|
11
|
+
it 'api_token should be exactly as configured' do
|
12
|
+
expect(config[:api_token]).to eq('afcf30182aecfc8155d390d7d4552d14')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'host should be exactly as configured' do
|
16
|
+
expect(config[:host]).to eq('voog.local')
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when there are multiple blocks' do
|
20
|
+
let(:block1) { Voog::Dtk.read_config nil, 'spec/fixtures/.voog2' }
|
21
|
+
let(:block2) { Voog::Dtk.read_config 'testblock', 'spec/fixtures/.voog2' }
|
22
|
+
|
23
|
+
it 'should default to the first one if block is not provided' do
|
24
|
+
expect(block1[:host]).to eq('voog.local')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should read the correct options when a block is provided' do
|
28
|
+
expect(block2[:api_token]).to eq('123')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should fail when a non-existant block is provided' do
|
32
|
+
expect{
|
33
|
+
block3 = Voog::Dtk.read_config 'wrongname', 'spec/fixtures/.voog2'
|
34
|
+
}.to raise_error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when the provided filename is empty' do
|
41
|
+
|
42
|
+
let(:config) { Voog::Dtk.read_config nil, '' }
|
43
|
+
|
44
|
+
it 'api_token should be nil' do
|
45
|
+
expect(config[:api_token]).to eq(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'host should be nil' do
|
49
|
+
expect(config[:host]).to eq(nil)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when a filename is not provided' do
|
55
|
+
|
56
|
+
let(:config) { Voog::Dtk.read_config nil, nil }
|
57
|
+
|
58
|
+
it 'api_token should be nil' do
|
59
|
+
expect(config[:api_token]).to eq(nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'host should be nil' do
|
63
|
+
expect(config[:host]).to eq(nil)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when the provided filename is invalid' do
|
69
|
+
|
70
|
+
let(:config) { Voog::Dtk.read_config nil, 'foo.bar' }
|
71
|
+
|
72
|
+
it 'api_token should be nil' do
|
73
|
+
expect(config[:api_token]).to eq(nil)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'host should be nil' do
|
77
|
+
expect(config[:host]).to eq(nil)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|