opencode_theme 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3e2995bdcd55b2874d519fb2f4653ddac6441471
4
+ data.tar.gz: 7ac1b792ea2f5f8b5bbe589def50a308781430ba
5
+ SHA512:
6
+ metadata.gz: 7fc3f4a94ba2841bd2b9401e8c932d50872de8e5bf569b614e2f40c357e4648e00b104f78a1ffe9cb1ef0423d1a12a75ed3a7a5231b428e0424d523a951ae4a8
7
+ data.tar.gz: 83c17ca7ea25b31c3c74fa63f25e6d2137fd95976b438168c961b5f7ce31ba21a870c3769e82f3b3df79d7134f97bde14a893aadd7a6a15b452dbf10dacf2f3e
@@ -0,0 +1,19 @@
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
18
+ config.yml
19
+ *.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in opencode_theme.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Rafael Takashi
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.
@@ -0,0 +1,29 @@
1
+ # OpencodeTheme
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'opencode_theme'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install opencode_theme
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ task :default => [:spec]
6
+
7
+ Rake::TestTask.new 'spec' do |t|
8
+ ENV['test'] = 'true'
9
+ t.libs = ['lib', 'spec']
10
+ t.ruby_opts << '-rubygems'
11
+ t.verbose = true
12
+ t.test_files = FileList['spec/**/*_spec.rb']
13
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This allows opencode_theme to run easily from a git checkout without install.
4
+ # Hat tip to chriseppstein of Compass fame for the code for this
5
+ def fallback_load_path(path)
6
+ retried = false
7
+ begin
8
+ yield
9
+ rescue LoadError
10
+ unless retried
11
+ $: << path
12
+ retried = true
13
+ retry
14
+ end
15
+ raise
16
+ end
17
+ end
18
+ fallback_load_path(File.join(File.dirname(__FILE__), '..', 'lib')) do
19
+ require 'opencode_theme'
20
+ require 'opencode_theme/cli'
21
+ end
22
+ OpencodeTheme::Cli.start(ARGV)
@@ -0,0 +1,74 @@
1
+ require "opencode_theme/version"
2
+ require 'opencode_theme/base_service'
3
+
4
+ module OpencodeTheme
5
+
6
+ NOOPParser = Proc.new {|data, format| {} }
7
+ TIMER_RESET = 10
8
+ PERMIT_LOWER_LIMIT = 3
9
+ CONFIG_FILE = 'config.yml'
10
+
11
+ def self.test?
12
+ ENV['test']
13
+ end
14
+
15
+ def self.critical_permits?
16
+ @@total_api_calls.to_i - @@current_api_call_count.to_i < PERMIT_LOWER_LIMIT
17
+ end
18
+
19
+ def self.passed_api_refresh?
20
+ delta_seconds > TIMER_RESET
21
+ end
22
+
23
+ def self.delta_seconds
24
+ Time.now.to_i - @@current_timer.to_i
25
+ end
26
+
27
+ def self.needs_sleep?
28
+ critical_permits? && !passed_api_refresh?
29
+ end
30
+
31
+ def self.sleep
32
+ if needs_sleep?
33
+ Kernel.sleep(TIMER_RESET - delta_seconds)
34
+ @current_timer = nil
35
+ end
36
+ end
37
+
38
+ def self.config
39
+ @config ||= if File.exist? CONFIG_FILE
40
+ config = YAML.load(File.read(CONFIG_FILE))
41
+ config
42
+ else
43
+ puts "#{CONFIG_FILE} does not exist!" unless test?
44
+ {}
45
+ end
46
+ end
47
+
48
+ def self.config=(config)
49
+ @config = config
50
+ end
51
+
52
+
53
+ def self.is_binary_data?(string)
54
+ if string.respond_to?(:encoding)
55
+ string.encoding == "US-ASCII"
56
+ else
57
+ ( string.count( "^ -~", "^\r\n" ).fdiv(string.size) > 0.3 || string.index( "\x00" ) ) unless string.empty?
58
+ end
59
+ end
60
+
61
+ def self.path(type = nil)
62
+ @path ||= config[:theme_id] ? "/api/themes/#{config[:theme_id]}/assets" : "/api/themes/assets"
63
+ end
64
+
65
+
66
+ def self.ignore_files
67
+ (config[:ignore_files] || []).compact.map { |r| Regexp.new(r) }
68
+ end
69
+
70
+ def self.whitelist_files
71
+ (config[:whitelist_files] || []).compact
72
+ end
73
+
74
+ end
@@ -0,0 +1,69 @@
1
+ require 'httparty'
2
+ module OpencodeTheme
3
+ include HTTParty
4
+ default_options.update(verify: false)
5
+ @@current_api_call_count = 0
6
+ @@total_api_calls = 40
7
+ URL_API = "https://opencode.tray.com.br"
8
+
9
+ def self.api_usage
10
+ "[API Limit: #{@@current_api_call_count || "??"}/#{@@total_api_calls || "??"}]"
11
+ end
12
+
13
+ def self.check_config
14
+ response = opencode_theme.post("/api/check", :query => {:theme_id => config[:theme_id] })
15
+ return {success: response.success?, response: JSON.parse(response.body)}
16
+ end
17
+
18
+ def self.list
19
+ response = opencode_theme.get("/api/list")
20
+ return {success: response.success?, response: JSON.parse(response.body)}
21
+ end
22
+
23
+ def self.clean
24
+ response = opencode_theme.post("/api/clean_cache", :query => {:theme_id => config[:theme_id] })
25
+ return {success: response.success?, response: JSON.parse(response.body)}
26
+ end
27
+
28
+ def self.theme_delete(theme_id)
29
+ response = opencode_theme.delete("/api/themes/#{theme_id}", :parser => NOOPParser)
30
+ return {success: response.success?, response: JSON.parse(response.body)}
31
+ end
32
+
33
+ def self.theme_new(theme_base, theme_name)
34
+ response = opencode_theme.post("/api/themes", :body => {:theme => {:theme_base => theme_name, :name => theme_name}}.to_json,
35
+ :headers => { 'Content-Type' => 'application/json'}, :parser => NOOPParser)
36
+ assets = response.code == 200 ? JSON.parse(response.body)["assets"] : {}
37
+ return {success: response.success?, assets: assets, response: JSON.parse(response.body)}
38
+ end
39
+
40
+ def self.asset_list
41
+ response = opencode_theme.get(path, :parser => NOOPParser)
42
+ assets = response.code == 200 ? JSON.parse(response.body)["assets"].collect {|a| a['key'][1..a['key'].length] } : {}
43
+ assets
44
+ end
45
+
46
+ def self.get_asset(asset)
47
+ response = opencode_theme.get(path, :query => {:key => "/#{asset}"}, :parser => NOOPParser)
48
+ asset = response.code == 200 ? JSON.parse(response.body) : ""
49
+ asset
50
+ end
51
+
52
+ def self.send_asset(data)
53
+ response = opencode_theme.put(path, :body => data)
54
+ response
55
+ end
56
+
57
+ def self.delete_asset(asset)
58
+ response = opencode_theme.delete(path, :body => {:key => "/#{asset}"})
59
+ response
60
+ end
61
+
62
+ private
63
+ def self.opencode_theme
64
+ base_uri URL_API
65
+ headers "Authorization" => "Token token=#{config[:api_key]}_#{config[:password]}"
66
+ OpencodeTheme
67
+ end
68
+
69
+ end
@@ -0,0 +1,319 @@
1
+ # encoding: utf-8
2
+ require 'thor'
3
+ require 'yaml'
4
+ YAML::ENGINE.yamler = 'syck' if defined? Syck
5
+ require 'abbrev'
6
+ require 'base64'
7
+ require 'fileutils'
8
+ require 'json'
9
+ require 'filewatcher'
10
+ require 'launchy'
11
+ require 'mimemagic'
12
+ MimeMagic.add('application/json', extensions: %w(json js), parents: 'text/plain')
13
+ MimeMagic.add('application/x-pointplus', extensions: %w(scss), parents: 'text/css')
14
+ MimeMagic.add('application/vnd.ms-fontobject', extensions: %w(eot), parents: 'font/opentype')
15
+
16
+
17
+ module OpencodeTheme
18
+ class Cli < Thor
19
+ include Thor::Actions
20
+
21
+ IGNORE = %w(config.yml)
22
+ DEFAULT_WHITELIST = %w(configs/ css/ elements/ img/ layouts/ pages/ js/)
23
+ TIMEFORMAT = "%H:%M:%S"
24
+
25
+ tasks.keys.abbrev.each do |shortcut, command|
26
+ map shortcut => command.to_sym
27
+ end
28
+
29
+ desc "configure API_KEY PASSWORD THEME_ID", "Configura o tema que sera modificado"
30
+ def configure(api_key=nil, password=nil, theme_id=nil)
31
+ config = {:api_key => api_key, :password => password, :theme_id => theme_id}
32
+ OpencodeTheme.config = config
33
+ response = OpencodeTheme.check_config
34
+ if response[:success]
35
+ config.merge!(:preview_url => response[:response]['preview'])
36
+ create_file('config.yml', config.to_yaml, :force => true)
37
+ say("Configuration [OK]", :green)
38
+ else
39
+ say("Configuration [FAIL]", :red)
40
+ end
41
+ end
42
+
43
+ desc "list", "Lista todos os temas da loja"
44
+ def list
45
+ config = OpencodeTheme.config
46
+ response = OpencodeTheme.list
47
+ if response[:success]
48
+ say("\n")
49
+ response[:response]["themes"].each do |theme|
50
+ color = theme['published'] == "1" ? :green : :red
51
+ say("Theme name: ", color)
52
+ say("#{theme['name']}\n", color)
53
+ say("Theme ID: ", color)
54
+ say("#{theme['id']}\n", color)
55
+ say("Theme status: ", color)
56
+ say("#{(theme['published'])}\n\n", color)
57
+ end
58
+ else
59
+ report_error(Time.now, "Could not list now", response[:response])
60
+ end
61
+ end
62
+
63
+ desc "clean", "Limpa o cache de arquivos estáticos"
64
+ def clean
65
+ config = OpencodeTheme.config
66
+ response = OpencodeTheme.clean
67
+ if response[:success]
68
+ say("Clean cache [OK]\n", :green)
69
+ else
70
+ say("Clean cache [FAIL]", :red)
71
+ end
72
+ end
73
+
74
+ desc "bootstrap API_KEY PASSWORD THEME_NAME THEME_BASE", "Cria um novo tema com o nome informado"
75
+ method_option :master, :type => :boolean, :default => false
76
+ def bootstrap(api_key=nil, password=nil, theme_name='default', theme_base='default')
77
+ OpencodeTheme.config = {:api_key => api_key, :password => password}
78
+
79
+ check_config = OpencodeTheme.check_config
80
+
81
+ if check_config[:success]
82
+ say("Configuration [OK]", :green)
83
+ else
84
+ report_error(Time.now, "Configuration [FAIL]", check_config[:response])
85
+ return
86
+ end
87
+
88
+ response = OpencodeTheme.theme_new(theme_base, theme_name)
89
+
90
+ if response[:success]
91
+ say("Create #{theme_name} theme on store", :green)
92
+ else
93
+ report_error(Time.now, "Could not create a new theme", response[:response])
94
+ return
95
+ end
96
+
97
+ say("Creating directory named #{theme_name}", :green)
98
+ empty_directory(theme_name)
99
+
100
+ say("Saving configuration to #{theme_name}", :green)
101
+ OpencodeTheme.config.merge!(theme_id: response[:response]['theme_id'], preview_url: response[:response]['preview'])
102
+ create_file("#{theme_name}/config.yml", OpencodeTheme.config.to_yaml)
103
+
104
+ say("Downloading #{theme_name} assets from Opencode")
105
+ Dir.chdir(theme_name)
106
+ download()
107
+ end
108
+
109
+ desc "open", "Abre a loja no navegador"
110
+ def open(*keys)
111
+ if Launchy.open opencode_theme_url
112
+ say("Done.", :green)
113
+ end
114
+ end
115
+
116
+ desc "download FILE", "Baixa o arquivo informado ou todos se FILE for omitido"
117
+ method_option :quiet, :type => :boolean, :default => false
118
+ method_option :exclude
119
+ def download(*keys)
120
+ assets = keys.empty? ? OpencodeTheme.asset_list : keys
121
+ if options['exclude']
122
+ assets = assets.delete_if { |asset| asset =~ Regexp.new(options['exclude']) }
123
+ end
124
+
125
+ assets.each do |asset|
126
+ asset = URI.decode(asset)
127
+ download_asset(asset)
128
+ say("#{OpencodeTheme.api_usage} Downloaded: #{asset}", :green) unless options['quiet']
129
+ end
130
+ say("Done.", :green) unless options['quiet']
131
+ end
132
+
133
+ desc "upload FILE", "Sobe o arquivo informado ou todos se FILE for omitido"
134
+ method_option :quiet, :type => :boolean, :default => false
135
+ def upload(*keys)
136
+ assets = keys.empty? ? local_assets_list : keys
137
+ assets.each do |asset|
138
+ send_asset("#{asset}", options['quiet'])
139
+ end
140
+ say("Done.", :green) unless options['quiet']
141
+ end
142
+
143
+ desc "remove FILE", "Remove um arquivo do tema (apenas se o tema nao estiver publicado)"
144
+ method_option :quiet, :type => :boolean, :default => false
145
+ def remove(*keys)
146
+ keys.each do |key|
147
+ delete_asset(key, options['quiet'])
148
+ end
149
+ say("Done.", :green) unless options['quiet']
150
+ end
151
+
152
+ desc "watch", "Baixa e sobe um arquivo sempre que ele for salvo"
153
+ method_option :quiet, :type => :boolean, :default => false
154
+ method_option :keep_files, :type => :boolean, :default => false
155
+ def watch
156
+ watcher do |filename, event|
157
+ filename = filename.gsub("#{Dir.pwd}/", '')
158
+ unless local_assets_list.include?(filename)
159
+ say("Unknown file [#{filename}]", :red)
160
+ next
161
+ end
162
+ action = if [:changed, :new].include?(event)
163
+ :send_asset
164
+ elsif event == :delete
165
+ :delete_asset
166
+ else
167
+ raise NotImplementedError, "Unknown event -- #{event} -- #{filename}"
168
+ end
169
+ send(action, filename, options['quiet'])
170
+ end
171
+ end
172
+
173
+ desc "systeminfo", "Mostra informacoes do sistema"
174
+ def systeminfo
175
+ ruby_version = "#{RUBY_VERSION}"
176
+ ruby_version += "-p#{RUBY_PATCHLEVEL}" if RUBY_PATCHLEVEL
177
+ puts "Ruby: v#{ruby_version}"
178
+ puts "Operating System: #{RUBY_PLATFORM}"
179
+ %w(Listen HTTParty Launchy).each do |lib|
180
+ require "#{lib.downcase}/version"
181
+ puts "#{lib}: v" + Kernel.const_get("#{lib}::VERSION")
182
+ end
183
+ end
184
+
185
+
186
+ protected
187
+
188
+ def config
189
+ @config ||= YAML.load_file 'config.yml'
190
+ end
191
+
192
+ private
193
+
194
+ def notify_and_sleep(message)
195
+ say(message, :red)
196
+ OpencodeTheme.sleep
197
+ end
198
+
199
+ def binary_file?(path)
200
+ !MimeMagic.by_path(path).text?
201
+ end
202
+
203
+ def opencode_theme_url
204
+ config[:preview_url]
205
+ end
206
+
207
+
208
+ def send_asset(asset, quiet = false)
209
+ if valid_name?(asset)
210
+ return unless valid?(asset)
211
+ data = { key: "/#{asset}" }
212
+ content = File.read("#{asset}")
213
+ if binary_file?(asset) || OpencodeTheme.is_binary_data?(content)
214
+ content = File.open("#{asset}", "rb") { |io| io.read }
215
+ data.merge!(attachment: Base64.encode64(content))
216
+ else
217
+ data.merge!(value: Base64.encode64(content))
218
+ end
219
+ response = show_during("[#{timestamp}] Uploading: #{asset}", quiet) do
220
+ OpencodeTheme.send_asset(data)
221
+ end
222
+ if response.success?
223
+ say("[#{timestamp}] Uploaded: #{asset}", :green) unless quiet
224
+ else
225
+ report_error(Time.now, "Could not upload #{asset}", response)
226
+ end
227
+ end
228
+ end
229
+
230
+ def delete_asset(key, quiet=false)
231
+ return unless valid?(key)
232
+ response = show_during("[#{timestamp}] Removing: #{key}", quiet) do
233
+ OpencodeTheme.delete_asset(key)
234
+ end
235
+ if response.success?
236
+ say("[#{timestamp}] Removed: #{key}", :green) unless quiet
237
+ else
238
+ report_error(Time.now, "Could not remove #{key}", response)
239
+ end
240
+ end
241
+
242
+ def watcher
243
+ FileWatcher.new(Dir.pwd).watch() do |filename, event|
244
+ yield("#{filename}", event)
245
+ end
246
+ end
247
+
248
+ def local_assets_list
249
+ local_files.reject do |p|
250
+ @permitted_files ||= (DEFAULT_WHITELIST | OpencodeTheme.whitelist_files).map{|pattern| Regexp.new(pattern)}
251
+ @permitted_files.none? { |regex| regex =~ p } || OpencodeTheme.ignore_files.any? { |regex| regex =~ p }
252
+ end
253
+ end
254
+
255
+ def local_files
256
+ Dir.glob(File.join('**', '*')).reject do |f|
257
+ File.directory?(f)
258
+ end
259
+ end
260
+
261
+ def valid?(key)
262
+ return true
263
+ #return true if DEFAULT_WHITELIST.include?(key.split('/').first + "/")
264
+ # say("'#{key}' is not in a valid file for theme uploads", :yellow)
265
+ # say("Files need to be in one of the following subdirectories: #{DEFAULT_WHITELIST.join(' ')}", :yellow)
266
+ # false
267
+ end
268
+
269
+ def timestamp(time = Time.now)
270
+ time.strftime(TIMEFORMAT)
271
+ end
272
+
273
+ def valid_name?(key)
274
+ name = key.split("/").last
275
+ if name =~ /^[0-9a-zA-Z\-_.]+\.(ttf|eot|svg|woff|css|scss|html|js|jpg|gif|png|json|TTF|EOT|SVG|WOFF|CSS|SCSS|HTML|JS|PNG|GIF|JPG|JSON)$/
276
+ valid = true
277
+ else
278
+ report_error(Time.now, "INVALID NAME #{name}", key)
279
+ end
280
+ valid
281
+ end
282
+
283
+ def download_asset(key)
284
+ if valid_name?(key)
285
+ return unless valid?(key)
286
+ notify_and_sleep("Approaching limit of API permits. Naptime until more permits become available!") if OpencodeTheme.needs_sleep?
287
+ asset = OpencodeTheme.get_asset(URI.encode(key))
288
+ unless asset['key']
289
+ report_error(Time.now, "Could not download #{key}", asset)
290
+ return
291
+ end
292
+ if asset['content']
293
+ content = Base64.decode64(asset['content'])
294
+ content = content.force_encoding("UTF-8")
295
+ format = "w+b:ISO-8859-1"
296
+ elsif asset['attachment']
297
+ content = Base64.decode64(asset['attachment'])
298
+ format = "w+b"
299
+ end
300
+ FileUtils.mkdir_p(File.dirname(URI.decode(key)))
301
+ File.open(key, format) {|f| f.write content} if content
302
+ end
303
+ end
304
+
305
+ def show_during(message = '', quiet = false, &block)
306
+ print(message) unless quiet
307
+ result = yield
308
+ print("\r#{' ' * message.length}\r") unless quiet
309
+ result
310
+ end
311
+
312
+ def report_error(time, message, response)
313
+ say("[#{timestamp(time)}] Error: #{message}", :red)
314
+ say("Error Details: #{response}", :yellow)
315
+ end
316
+
317
+ end
318
+
319
+ end
@@ -0,0 +1,3 @@
1
+ module OpencodeTheme
2
+ VERSION = "0.0.5"
3
+ 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 'opencode_theme/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "opencode_theme"
8
+ spec.version = OpencodeTheme::VERSION
9
+ spec.authors = ["Rafael Takashi Tanaka"]
10
+ spec.email = ["rtanaka@tray.net.br"]
11
+ spec.description = %q{Command Line tool for developing themes in Tray E-commerce}
12
+ spec.summary = %q{Provides simple commands to upload and donwload files from a themes}
13
+ spec.homepage = "http://tray-tecnologia.github.io/theme-template/"
14
+ spec.license = "MIT"
15
+
16
+ spec.add_dependency('thor', '>= 0.14.4')
17
+ spec.add_dependency('httparty', '~> 0.13.0')
18
+ spec.add_dependency('json', '~> 1.8.0')
19
+ spec.add_dependency('mimemagic')
20
+ spec.add_dependency('filewatcher')
21
+ spec.add_dependency('launchy')
22
+
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'pry'
26
+ spec.add_development_dependency 'http_logger'
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.3"
29
+
30
+
31
+ spec.files = `git ls-files`.split("\n")
32
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
33
+ spec.executables << 'opencode'
34
+ spec.require_paths = ['lib']
35
+ end
@@ -0,0 +1,153 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe OpencodeTheme::Cli, :functional do
4
+
5
+ STORE_ID = '430692'
6
+ FILE_NAME = 'layouts/default.html'
7
+ API_KEY = '11451c354c1f95fe60f80d7672bf184a'
8
+ PASSWORD = '14ae838d9e971465af45b35803b8f0a4'
9
+
10
+ after(:all) do
11
+ # clearing generated and downloaded files
12
+ FileUtils.rm 'config.yml'
13
+ FileUtils.rm_rf 'default'
14
+ end
15
+
16
+ context 'Invalid or Inexistent Configuration' do
17
+ it 'does not list when the config is invalid' do
18
+ output = capture(:stdout) { subject.list }
19
+ expect(File.exists? 'config.yml').to eq false
20
+ expect(output).to include 'config.yml does not exist!'
21
+ expect(output).to include 'Error: Could not list now'
22
+ expect(output).to include 'Error Details: {"authentication"=>false}'
23
+ end
24
+
25
+ it 'does not clean cache when the config is invalid' do
26
+ output = capture(:stdout) { subject.clean }
27
+ expect(File.exists? 'config.yml').to eq false
28
+ expect(output).to include 'Clean cache [FAIL]'
29
+ end
30
+
31
+ it 'does not upload any file when the config is invalid' do
32
+ output = capture(:stdout) { subject.upload }
33
+ expect(output).not_to include 'Uploaded'
34
+ expect(output).to include 'Done.'
35
+ end
36
+ end
37
+
38
+ context 'Configure' do
39
+ it 'fails to create config.yml file when called with no arguments' do
40
+ output = capture(:stdout) { subject.configure }
41
+ expect(output).to include 'Configuration [FAIL]'
42
+ expect(File.exists? 'config.yml').to eq false
43
+ end
44
+
45
+ it 'creates config.yml when called with parameters' do
46
+ output = capture(:stdout) { subject.configure API_KEY, PASSWORD }
47
+ expect(output).to include 'Configuration [OK]'
48
+ expect(File.exists? 'config.yml').to eq true
49
+ end
50
+ end
51
+
52
+ context 'Bootstrap' do
53
+ it 'create new theme' do
54
+ output = capture(:stdout) { subject.bootstrap API_KEY, PASSWORD }
55
+ FileUtils.cd '..'
56
+ expect(output).to include 'Configuration [OK]'
57
+ expect(output).to include 'Create default theme on store'
58
+ expect(output).to include 'Saving configuration to default'
59
+ expect(output).to include 'Downloading default assets from Opencode'
60
+ expect(output).to include "Downloaded: #{ FILE_NAME }"
61
+ expect(output).to include 'Done.'
62
+ end
63
+ end
64
+
65
+ context 'List' do
66
+ it 'lists all the themes from the store' do
67
+ output = capture(:stdout) { subject.list }
68
+ expect(output).to include 'Theme name:'
69
+ expect(output).to include 'Theme ID:'
70
+ expect(output).to include 'Theme status:'
71
+ end
72
+ end
73
+
74
+ context 'Cleaning cache' do
75
+ it 'cleans the cache' do
76
+ FileUtils.cd 'default'
77
+ output = capture(:stdout) { subject.clean }
78
+ FileUtils.cd '..'
79
+ expect(output).to include 'Clean cache [OK]'
80
+ end
81
+ end
82
+
83
+ context 'Download' do
84
+ it 'downloads all files' do
85
+ FileUtils.cd 'default'
86
+ output = capture(:stdout) { subject.download }
87
+ FileUtils.cd '..'
88
+ expect(output).to include 'Downloaded'
89
+ expect(output).to include "Downloaded: #{ FILE_NAME }"
90
+ expect(output).not_to include 'Error'
91
+ expect(output).to include 'Done.'
92
+ end
93
+
94
+ it 'downloads a single file' do
95
+ FileUtils.cd 'default'
96
+ output = capture(:stdout) { subject.download FILE_NAME }
97
+ FileUtils.cd '..'
98
+ expect(output).to include "Downloaded: #{ FILE_NAME }"
99
+ expect(output).to include 'Done.'
100
+ expect(output).not_to include 'Error'
101
+ end
102
+ end
103
+
104
+ context 'Upload' do
105
+ it 'uploads all files' do
106
+ FileUtils.cd 'default'
107
+ output = capture(:stdout) { subject.upload }
108
+ FileUtils.cd '..'
109
+ expect(output).to include 'Uploaded'
110
+ expect(output).to include "Uploaded: #{ FILE_NAME }"
111
+ expect(output).not_to include 'Error'
112
+ expect(output).to include 'Done.'
113
+ end
114
+
115
+ it 'uploads a single file' do
116
+ FileUtils.cd 'default'
117
+ output = capture(:stdout) { subject.upload FILE_NAME }
118
+ FileUtils.cd '..'
119
+ expect(output).to include "Uploaded: #{ FILE_NAME }"
120
+ expect(output).to include 'Done.'
121
+ expect(output).not_to include 'Error'
122
+ end
123
+ end
124
+
125
+ context 'System Information' do
126
+ let(:output) { capture(:stdout) { subject.systeminfo } }
127
+
128
+ it 'displays system information' do
129
+ pending 'redmine issue 37576'
130
+ expect(output).not_to be_nil
131
+ end
132
+ end
133
+
134
+ context 'Help' do
135
+ let(:output) { capture(:stdout) { subject.help } }
136
+
137
+ it 'displays help about each command' do
138
+ expect(output).to include 'Commands:'
139
+ expect(output).to include 'bootstrap API_KEY PASSWORD THEME_NAME THEME_BASE'
140
+ expect(output).to include 'clean'
141
+ expect(output).to include 'configure API_KEY PASSWORD THEME_ID'
142
+ expect(output).to include 'download FILE'
143
+ expect(output).to include 'help [COMMAND]'
144
+ expect(output).to include 'list'
145
+ expect(output).to include 'open'
146
+ expect(output).to include 'remove FILE'
147
+ expect(output).to include 'systeminfo'
148
+ expect(output).to include 'upload FILE'
149
+ expect(output).to include 'watch'
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,27 @@
1
+ require 'rspec'
2
+ require 'opencode_theme'
3
+ require 'opencode_theme/cli'
4
+
5
+ def capture(stream)
6
+ begin
7
+ stream = stream.to_s
8
+ eval "$#{stream} = StringIO.new"
9
+ yield
10
+ result = eval("$#{stream}").string
11
+ ensure
12
+ eval("$#{stream} = #{stream.upcase}")
13
+ end
14
+
15
+ result
16
+ end
17
+
18
+ require 'logger'
19
+ require 'http_logger'
20
+
21
+ File.truncate('http.log', 0) if File.exists? 'http.log'
22
+ HttpLogger.logger = Logger.new 'http.log'
23
+ HttpLogger.colorize = false
24
+ HttpLogger.log_headers = true
25
+ HttpLogger.log_request_body = true
26
+ HttpLogger.log_response_body = true
27
+ HttpLogger.level = :info
@@ -0,0 +1,65 @@
1
+ module OpencodeTheme
2
+ class CliDouble < Cli
3
+ attr_writer :local_files, :mock_config
4
+
5
+ def configure(api_key=nil, password=nil, theme_id=nil)
6
+ super(api_key, password, theme_id)
7
+ end
8
+
9
+ def list
10
+ super
11
+ end
12
+
13
+ def clean
14
+ super
15
+ end
16
+
17
+ def bootstrap
18
+ super
19
+ end
20
+
21
+ def open
22
+
23
+ end
24
+
25
+ def download
26
+
27
+ end
28
+
29
+ def upload
30
+
31
+ end
32
+
33
+ def remove
34
+
35
+ end
36
+
37
+ def watch
38
+
39
+ end
40
+
41
+ def systeminfo
42
+
43
+ end
44
+
45
+ ##########################################
46
+
47
+ no_commands do
48
+ def config
49
+ @mock_config || super
50
+ end
51
+
52
+ def opencode_theme_url
53
+ super
54
+ end
55
+
56
+ def binary_file?(file)
57
+ super
58
+ end
59
+
60
+ def local_files
61
+ @local_files
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../spec_helper'
2
+ require_relative 'cli_double'
3
+
4
+ describe 'Cli' do
5
+
6
+ before do
7
+ @cli = OpencodeTheme::CliDouble.new
8
+ OpencodeTheme.config = {}
9
+ end
10
+
11
+ it 'should report binary files as binary' do
12
+ extensions = %w(png gif jpg jpeg eot ttf woff otf swf ico pdf)
13
+ extensions.each do |ext|
14
+ expect(@cli.binary_file? "hello.#{ext}").to eq(true), ext
15
+ end
16
+ end
17
+
18
+ it 'should not report text based files as binary' do
19
+ expect(@cli.binary_file? 'style.css').to eq false
20
+ expect(@cli.binary_file? 'application.js').to eq false
21
+ expect(@cli.binary_file? 'settings_data.json').to eq false
22
+ end
23
+
24
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opencode_theme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Rafael Takashi Tanaka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.14.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.14.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.13.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.13.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.8.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.8.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: mimemagic
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: filewatcher
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: launchy
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: http_logger
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: bundler
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.3'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.3'
167
+ description: Command Line tool for developing themes in Tray E-commerce
168
+ email:
169
+ - rtanaka@tray.net.br
170
+ executables:
171
+ - opencode
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".gitignore"
176
+ - ".rspec"
177
+ - Gemfile
178
+ - LICENSE.txt
179
+ - README.md
180
+ - Rakefile
181
+ - bin/opencode
182
+ - lib/opencode_theme.rb
183
+ - lib/opencode_theme/base_service.rb
184
+ - lib/opencode_theme/cli.rb
185
+ - lib/opencode_theme/version.rb
186
+ - opencode_theme.gemspec
187
+ - spec/functional/functional_spec.rb
188
+ - spec/spec_helper.rb
189
+ - spec/unit/cli_double.rb
190
+ - spec/unit/cli_spec.rb
191
+ homepage: http://tray-tecnologia.github.io/theme-template/
192
+ licenses:
193
+ - MIT
194
+ metadata: {}
195
+ post_install_message:
196
+ rdoc_options: []
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubyforge_project:
211
+ rubygems_version: 2.2.5
212
+ signing_key:
213
+ specification_version: 4
214
+ summary: Provides simple commands to upload and donwload files from a themes
215
+ test_files: []