posthaven_theme 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ed80c2c7459827fc24ad85f8a2dc41c022b0bd86
4
+ data.tar.gz: 9e5db4f8afb073fe26d361df97988833264369a6
5
+ SHA512:
6
+ metadata.gz: d4e53ab12a6670aa455366f7a68ab5c64d36d5b3e3383b3cea282324b8e4707377194e58d6c84e6f19846b584df2a6f518cb610ca0c658cd4b6383e9c437c4c3
7
+ data.tar.gz: 29c343541e6c298ca40bdbf8196742d64408460e5224def74e30121848c0f1a065f536cd430bff0f9a6c58e414ff0c2d25a34a336c1cf787c7a589df50750d4d
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .project
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in posthaven_theme.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 Shopify
2
+ Copyright (c) 2016 Posthaven
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Posthaven Theme
2
+
3
+ The `posthaven_theme` gem provides command line tools for developing a Posthaven theme on your computer and pushing updates to Posthaven.
4
+
5
+ # Requirements
6
+
7
+ ## Ruby
8
+
9
+ This gem requires Ruby 2.0 or above.
10
+
11
+ ## Posthaven API Key
12
+
13
+ Log in and get your [Posthaven account API key here](https://posthaven.com/account/theme_api_key).
14
+
15
+
16
+ # Installation
17
+
18
+ To install the `posthaven_theme` gem use 'gem install' (you might have use 'sudo gem install')
19
+
20
+ ```
21
+ gem install posthaven_theme
22
+ ```
23
+
24
+ to update to the latest version
25
+
26
+ ```
27
+ gem update posthaven_theme
28
+ ```
29
+
30
+ # Usage
31
+
32
+ The gem installs the `phtheme` CLI program.
33
+
34
+ ### List available commands
35
+ ```
36
+ phtheme help
37
+ ```
38
+
39
+ ### Generate a configuration file. For your API key see [above](#posthaven_account).
40
+
41
+ ```
42
+ phtheme configure api-key
43
+
44
+ ```
45
+ ### Upload all files
46
+
47
+ ```
48
+ phtheme upload
49
+ ```
50
+
51
+ ### Upload a single theme file
52
+
53
+ ```
54
+ phtheme upload layouts/theme.liquid
55
+ ```
56
+
57
+ ### Remove a theme file
58
+
59
+ ```
60
+ phtheme remove assets/layout.liquid
61
+ ```
62
+
63
+ ### Completely remove all old theme files and replace them with current local versions
64
+
65
+ ```
66
+ phtheme replace
67
+ ```
68
+
69
+ ### Watch the current theme directory and upload any files as they change
70
+ ```
71
+ phtheme watch
72
+ ```
73
+
74
+ # Configuration
75
+
76
+ Running `phtheme configure` generates `config.yml` file in the base directory of your theme. If you are storing your theme in version control it is **highly recommended that you DO NOT** store this file in version control, e.g. in git add it to your `.gitignore`.
77
+
78
+ `config.yml` has the following options:
79
+
80
+ * `api_key` – Your Posthaven API key
81
+ * `theme_id` – The ID of the theme to edit. The easiest way to populate the theme id is via the `configure` command above.
82
+
83
+ See the `phtheme configure` command above for one step setup of the `config.yml` file.
84
+
85
+ # Thanks
86
+
87
+ A huge thanks to [Shopify](https://www.shopify.com) for their [shopify_theme](https://github.com/shopify/shopify_theme) gem upon which this is based.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
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
14
+
data/bin/phtheme ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This allows posthaven_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
+
19
+ fallback_load_path(File.join(File.dirname(__FILE__), '..', 'lib')) do
20
+ require 'posthaven_theme'
21
+ require 'posthaven_theme/cli'
22
+ end
23
+
24
+ PosthavenTheme::Cli.start(ARGV)
@@ -0,0 +1,332 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ YAML::ENGINE.yamler = 'syck' if defined? Syck
4
+ require 'abbrev'
5
+ require 'base64'
6
+ require 'fileutils'
7
+ require 'json'
8
+ require 'filewatcher'
9
+ require 'mimemagic'
10
+
11
+ module PosthavenTheme
12
+ EXTENSIONS = [
13
+ {mimetype: 'application/x-liquid', extensions: %w(liquid), parents: 'text/plain'},
14
+ {mimetype: 'application/json', extensions: %w(json), parents: 'text/plain'},
15
+ {mimetype: 'application/js', extensions: %w(map), parents: 'text/plain'},
16
+ {mimetype: 'application/vnd.ms-fontobject', extensions: %w(eot)},
17
+ {mimetype: 'image/svg+xml', extensions: %w(svg svgz)}
18
+ ]
19
+
20
+ def self.configure_mime_magic
21
+ PosthavenTheme::EXTENSIONS.each do |extension|
22
+ MimeMagic.add(extension.delete(:mimetype), extension)
23
+ end
24
+ end
25
+
26
+ class Cli < Thor
27
+ include Thor::Actions
28
+
29
+ IGNORE = %w(config.yml)
30
+ DEFAULT_WHITELIST = %w(layouts/ assets/ config/ snippets/ templates/)
31
+ TIMEFORMAT = "%H:%M:%S"
32
+
33
+ NON_CONFIG_COMMANDS = %w{help configure systeminfo}
34
+
35
+ def initialize(args = [], local_options = {}, config = {})
36
+ unless NON_CONFIG_COMMANDS.include?(config[:current_command].name)
37
+ setup_config
38
+ validate_config!
39
+ end
40
+ super
41
+ end
42
+
43
+ desc "check", "Check configuration"
44
+ def check
45
+ say('Configuration [OK]', :green) if PosthavenTheme.asset_list
46
+ rescue PosthavenTheme::APIError => e
47
+ report_error('Configuration [FAIL]', e)
48
+ end
49
+
50
+ desc 'configure API_KEY',
51
+ 'Generate a config.yml file – See https://github.com/posthaven/posthaven_theme/#posthaven ' +
52
+ 'for information on how to get your api key. Interactively selects (or creates) a theme' +
53
+ 'on your account to edit.'
54
+ def configure(api_key=nil, theme_id=nil)
55
+ if api_key.nil?
56
+ say('An api key is required!', :red)
57
+ help(:configure)
58
+ else
59
+ config = {api_key: api_key, theme_id: theme_id}
60
+ PosthavenTheme.config = config
61
+ themes = PosthavenTheme.theme_list
62
+ config[:theme_id] ||= select_theme(themes)
63
+ create_file('config.yml', config.to_yaml)
64
+ end
65
+ rescue PosthavenTheme::APIError
66
+ say('Configuration Failed – Your API Key is Likely Incorrect', :red)
67
+ end
68
+
69
+ desc 'upload FILE', 'Upload all theme assets to site'
70
+ method_option :quiet, type: :boolean, default: false
71
+ def upload(*paths)
72
+ assets = paths.empty? ? local_assets_list : paths
73
+ assets.each do |asset|
74
+ send_asset(asset, options['quiet'])
75
+ end
76
+ say("Done.", :green) unless options['quiet']
77
+ rescue PosthavenTheme::APIError => e
78
+ report_error('Upload Failed.', e)
79
+ end
80
+
81
+ desc 'replace FILE', 'Completely replace site theme assets with local theme assets'
82
+ method_option :quiet, type: :boolean, default: false
83
+ def replace(*paths)
84
+ say('Are you sure you want to completely replace your site theme assets? ' +
85
+ 'This is not undoable.',
86
+ :yellow)
87
+ if ask('Continue? (Y/N): ') == 'Y'
88
+ # only delete files on remote that are not present locally
89
+ # files present on remote and present locally get overridden anyway
90
+ remote_assets = if paths.empty?
91
+ (PosthavenTheme.asset_list.map { |a| a['path'] } - local_assets_list)
92
+ else
93
+ paths
94
+ end
95
+ remote_assets.each do |asset|
96
+ unless PosthavenTheme.ignore_files.any? { |regex| regex =~ asset }
97
+ delete_asset(asset, options['quiet'])
98
+ end
99
+ end
100
+ local_assets = paths.empty? ? local_assets_list : paths
101
+ local_assets.each do |asset|
102
+ send_asset(asset, options['quiet'])
103
+ end
104
+ say("Done.", :green) unless options['quiet']
105
+ end
106
+ rescue PosthavenTheme::APIError => e
107
+ report_error('Replacement failed.', e)
108
+ end
109
+
110
+ desc 'remove FILE', 'Remove theme asset'
111
+ method_option :quiet, type: :boolean, default: false
112
+ def remove(*paths)
113
+ paths.each do |path|
114
+ delete_asset(path, options['quiet'])
115
+ end
116
+ say("Done.", :green) unless options['quiet']
117
+ rescue PosthavenTheme::APIError => e
118
+ report_error("Could not remove.", e)
119
+ end
120
+
121
+ desc 'watch',
122
+ 'upload and delete individual theme assets as they change, ' +
123
+ 'use the --keep_files flag to disable remote file deletion'
124
+ method_option :quiet, type: :boolean, default: false
125
+ method_option :keep_files, type: :boolean, default: false
126
+ def watch
127
+ puts "Watching current folder: #{Dir.pwd}"
128
+ watcher do |filename, event|
129
+ filename = filename.gsub("#{Dir.pwd}/", '')
130
+
131
+ next unless local_assets_list.include?(filename)
132
+ action = if [:changed, :new].include?(event)
133
+ :send_asset
134
+ elsif event == :delete
135
+ :delete_asset
136
+ else
137
+ raise NotImplementedError, "Unknown event -- #{event} -- #{filename}"
138
+ end
139
+
140
+ begin
141
+ send(action, filename, options['quiet'])
142
+ rescue PosthavenTheme::APIError => e
143
+ verb = action == :send_asset ? 'save' : 'delete'
144
+ report_error("Unable to #{verb} asset.", e)
145
+ end
146
+ end
147
+ end
148
+
149
+ desc 'systeminfo',
150
+ 'print out system information and actively loaded libraries for aiding in submitting bug reports'
151
+ def systeminfo
152
+ ruby_version = "#{RUBY_VERSION}"
153
+ ruby_version += "-p#{RUBY_PATCHLEVEL}" if RUBY_PATCHLEVEL
154
+ puts "Ruby: v#{ruby_version}"
155
+ puts "Operating System: #{RUBY_PLATFORM}"
156
+ %w(Thor Listen HTTParty).each do |lib|
157
+ require "#{lib.downcase}/version"
158
+ puts "#{lib}: v" + Kernel.const_get("#{lib}::VERSION")
159
+ end
160
+ end
161
+
162
+ protected
163
+
164
+ def config
165
+ @config ||= YAML.load_file 'config.yml'
166
+ end
167
+
168
+ def site_theme_url
169
+ url = config[:site]
170
+ url += "?preview_theme_id=#{config[:theme_id]}" if config[:theme_id] && config[:theme_id].to_i > 0
171
+ url
172
+ end
173
+
174
+ private
175
+
176
+ def watcher
177
+ FileWatcher.new(Dir.pwd).watch() do |filename, event|
178
+ yield(filename, event)
179
+ end
180
+ end
181
+
182
+ def local_assets_list
183
+ local_files.reject do |p|
184
+ @permitted_files ||= (DEFAULT_WHITELIST | PosthavenTheme.whitelist_files).map{|pattern| Regexp.new(pattern)}
185
+ @permitted_files.none? { |regex| regex =~ p } || PosthavenTheme.ignore_files.any? { |regex| regex =~ p }
186
+ end
187
+ end
188
+
189
+ def local_files
190
+ Dir.glob(File.join('**', '*')).reject do |f|
191
+ File.directory?(f)
192
+ end
193
+ end
194
+
195
+ def download_asset(path)
196
+ return unless valid?(path)
197
+ asset = PosthavenTheme.get_asset(path)
198
+ if asset['value']
199
+ # For CRLF line endings
200
+ content = asset['value'].gsub("\r", "")
201
+ format = "w"
202
+ elsif asset['attachment']
203
+ content = Base64.decode64(asset['attachment'])
204
+ format = "w+b"
205
+ end
206
+
207
+ FileUtils.mkdir_p(File.dirname(path))
208
+ File.open(path, format) {|f| f.write content} if content
209
+ rescue PosthavenTheme::APIError => e
210
+ report_error(Time.now, "Could not download #{path}", e)
211
+ end
212
+
213
+ def send_asset(asset, quiet=false)
214
+ return unless valid?(asset)
215
+ data = {path: asset}
216
+ content = File.read(asset)
217
+ if binary_file?(asset) || PosthavenTheme.is_binary_data?(content)
218
+ content = File.open(asset, "rb") { |io| io.read }
219
+ data.merge!(attachment: Base64.encode64(content))
220
+ else
221
+ data.merge!(value: content)
222
+ end
223
+
224
+ response = show_during("[#{timestamp}] Uploading: #{asset}", quiet) do
225
+ PosthavenTheme.send_asset(data)
226
+ end
227
+ if response.success?
228
+ say("[#{timestamp}] Uploaded: #{asset}", :green) unless quiet
229
+ end
230
+ end
231
+
232
+ def delete_asset(path, quiet=false)
233
+ return unless valid?(path)
234
+ response = show_during("[#{timestamp}] Removing: #{path}", quiet) do
235
+ PosthavenTheme.delete_asset(path)
236
+ end
237
+ if response.success?
238
+ say("[#{timestamp}] Removed: #{path}", :green) unless quiet
239
+ end
240
+ end
241
+
242
+ def select_theme(existing)
243
+ opt = ask_with_options('Configure the theme to edit:', [
244
+ 'Create a new theme',
245
+ 'Select an existing theme',
246
+ ])
247
+ case opt
248
+ when 0
249
+ create_theme['id']
250
+ when 1
251
+ existing.sort_by! { |t| t['name'] }
252
+ n = ask_with_options("Select from your existing themes:", existing.map { |t| t['name'] })
253
+ existing[n]['id']
254
+ end
255
+ end
256
+
257
+ # Options are strings to be numbered. Index of selected option is returned.
258
+ def ask_with_options(prompt, options)
259
+ say(prompt)
260
+ options.each.with_index do |o, idx|
261
+ say(" %2d: %s" % [idx + 1, o])
262
+ end
263
+ n = ask('Select>', limited_to: (1..options.size).map(&:to_s))
264
+ n.to_i - 1
265
+ end
266
+
267
+ def create_theme
268
+ name = ''
269
+ begin
270
+ if (name = ask('What would you like to name your theme?')).size == 0
271
+ say('Oops, the theme needs a name (you can change it later).', :red)
272
+ end
273
+ end until name.size > 0
274
+ PosthavenTheme.create_theme(name: name)
275
+ end
276
+
277
+ def notify_and_sleep(message)
278
+ say(message, :red)
279
+ PosthavenTheme.sleep
280
+ end
281
+
282
+ def valid?(path)
283
+ return true if DEFAULT_WHITELIST.include?(path.split('/').first + "/")
284
+ say("'#{path}' is not in a valid file for theme uploads", :yellow)
285
+ say("Files need to be in one of the following subdirectories: #{DEFAULT_WHITELIST.join(' ')}", :yellow)
286
+ false
287
+ end
288
+
289
+ def binary_file?(path)
290
+ mime = MimeMagic.by_path(path)
291
+ say("'#{path}' is an unknown file-type, uploading asset as binary", :yellow) if mime.nil? && ENV['TEST'] != 'true'
292
+ mime.nil? || !mime.text?
293
+ end
294
+
295
+ def report_error(message, error)
296
+ say("[#{timestamp(Time.now)}] Error: #{message}", :red)
297
+ say("Error Details: #{error.message}", :yellow)
298
+ end
299
+
300
+ def show_during(message = '', quiet = false, &block)
301
+ print(message) unless quiet
302
+ result = yield
303
+ print("\r#{' ' * message.length}\r") unless quiet
304
+ result
305
+ rescue
306
+ print("\n") unless quiet
307
+ raise
308
+ end
309
+
310
+ def timestamp(time = Time.now)
311
+ time.strftime(TIMEFORMAT)
312
+ end
313
+
314
+ def setup_config
315
+ if File.exist?('config.yml')
316
+ PosthavenTheme.config = YAML.load(File.read('config.yml'))
317
+ end
318
+ end
319
+
320
+ def validate_config!
321
+ if PosthavenTheme.config.empty?
322
+ say 'config.yml does not exist or is empty!', :red
323
+ exit
324
+ elsif %i{api_key theme_id}.any? { |k| PosthavenTheme.config[k].nil? }
325
+ say 'config.yml must include :api_key: and :theme_id:!', :red
326
+ exit
327
+ end
328
+ end
329
+ end
330
+ end
331
+
332
+ PosthavenTheme.configure_mime_magic
@@ -0,0 +1,3 @@
1
+ module PosthavenTheme
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,180 @@
1
+ require 'posthaven_theme/version'
2
+ require 'httparty'
3
+
4
+ module PosthavenTheme
5
+ include HTTParty
6
+ @@current_api_call_count = 0
7
+ @@total_api_calls = 40
8
+
9
+ headers "User-Agent" => "posthaven_theme #{PosthavenTheme::VERSION}"
10
+
11
+ class APIError < StandardError
12
+ attr_accessor :response
13
+
14
+ def initialize(response)
15
+ @response = response
16
+ end
17
+
18
+ def message
19
+ "#{response_message} – #{response_error_message(response)}"
20
+ end
21
+
22
+ private
23
+
24
+ def response_message
25
+ if @response.response && @response.response.message && @response.response.message.size > 0
26
+ @response.response.message
27
+ else
28
+ @response.code
29
+ end
30
+ end
31
+
32
+ def response_error_message(response)
33
+ errors = @response.parsed_response ? @response.parsed_response["errors"] : @response.body
34
+ case errors
35
+ when NilClass
36
+ ''
37
+ when String
38
+ errors.strip
39
+ when Array
40
+ errors.join(", ")
41
+ end
42
+ end
43
+ end
44
+
45
+ TIMER_RESET = 10
46
+ PERMIT_LOWER_LIMIT = 3
47
+
48
+ DEFAULT_API_ENDPOINT = 'https://api.posthaven.com/v1'
49
+
50
+ def self.test?
51
+ ENV['test']
52
+ end
53
+
54
+ def self.manage_timer(response)
55
+ return unless response.headers['x-posthaven-api-call-limit']
56
+ @@current_api_call_count, @@total_api_calls = response.headers['x-posthaven-api-call-limit']
57
+ .split('/')
58
+ @@current_timer = Time.now if @current_timer.nil?
59
+ end
60
+
61
+ def self.critical_permits?
62
+ @@total_api_calls.to_i - @@current_api_call_count.to_i < PERMIT_LOWER_LIMIT
63
+ end
64
+
65
+ def self.passed_api_refresh?
66
+ delta_seconds > TIMER_RESET
67
+ end
68
+
69
+ def self.delta_seconds
70
+ Time.now.to_i - @@current_timer.to_i
71
+ end
72
+
73
+ def self.needs_sleep?
74
+ critical_permits? && !passed_api_refresh?
75
+ end
76
+
77
+ def self.sleep
78
+ if needs_sleep?
79
+ Kernel.sleep(TIMER_RESET - delta_seconds)
80
+ @current_timer = nil
81
+ end
82
+ end
83
+
84
+ def self.api_usage
85
+ "[API Limit: #{@@current_api_call_count || "??"}/#{@@total_api_calls || "??"}]"
86
+ end
87
+
88
+ def self.theme_list
89
+ handle_response(get(themes_path))
90
+ end
91
+
92
+ def self.create_theme(data)
93
+ handle_response(post(themes_path, body: {theme: data}))
94
+ end
95
+
96
+ def self.asset_list
97
+ handle_response(get(assets_path))
98
+ end
99
+
100
+ def self.get_asset(asset)
101
+ handle_response(get(asset_path(asset)))
102
+ end
103
+
104
+ def self.send_asset(data)
105
+ handle_response(put(asset_path(data[:path]), body: {asset: data}))
106
+ end
107
+
108
+ def self.delete_asset(asset)
109
+ handle_response(delete(asset_path(asset)))
110
+ end
111
+
112
+ def self.config
113
+ @config
114
+ end
115
+
116
+ def self.config=(config)
117
+ @config = config && Hash[config.map { |k, v| [k.to_sym, v] }]
118
+ setup
119
+ end
120
+
121
+ def self.themes_path
122
+ '/themes.json'
123
+ end
124
+ def self.theme_path(theme_id = config[:theme_id])
125
+ "/themes/#{theme_id}"
126
+ end
127
+
128
+ def self.assets_path
129
+ theme_path + "/assets.json"
130
+ end
131
+ def self.asset_path(path)
132
+ theme_path + "/asset.json?path=#{path}"
133
+ end
134
+
135
+ def self.ignore_files
136
+ (config[:ignore_files] || []).compact.map { |r| Regexp.new(r) }
137
+ end
138
+
139
+ def self.whitelist_files
140
+ (config[:whitelist_files] || []).compact
141
+ end
142
+
143
+ def self.is_binary_data?(string)
144
+ if string.respond_to?(:encoding)
145
+ string.encoding == "US-ASCII"
146
+ else
147
+ unless string.empty?
148
+ (string.count("^ -~", "^\r\n").fdiv(string.size) > 0.3 || string.index("\x00"))
149
+ end
150
+ end
151
+ end
152
+
153
+ private
154
+
155
+ def self.handle_response(response)
156
+ manage_timer(response)
157
+
158
+ if response.success?
159
+ if response.parsed_response
160
+ response.parsed_response["data"]
161
+ else
162
+ response
163
+ end
164
+ else
165
+ raise APIError.new(response)
166
+ end
167
+ end
168
+
169
+ def self.setup
170
+ # Basics
171
+ headers 'Authorization' => "Token #{config[:api_key]}"
172
+ base_uri (config[:api_endpoint] || ENV['PHTHEME_ENDPOINT'] || DEFAULT_API_ENDPOINT)
173
+
174
+ # Dev
175
+ require 'resolv-replace' if base_uri.include?(':')
176
+
177
+ debug_output $stdout if config[:debug] || ENV['PHTHEME_DEBUG']
178
+ default_options.update(verify: false) if ENV['PHTHEME_IGNORE_SSL_VERIFY']
179
+ end
180
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "posthaven_theme/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "posthaven_theme"
7
+ s.version = PosthavenTheme::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brett Gibson"]
10
+ s.email = ["help@posthaven.com"]
11
+ s.homepage = "https://github.com/posthaven/posthaven_theme"
12
+ s.summary = %q{Command line tool for developing themes}
13
+ s.description = %q{Command line tool to help with developing Posthaven themes. Provides simple commands to download, upload and delete files from a theme. Also includes the watch command to watch a directory and upload files as they change.}
14
+ s.license = 'MIT'
15
+
16
+ s.required_ruby_version = '>= 2.0'
17
+
18
+ s.rubyforge_project = "posthaven_theme"
19
+ s.add_dependency('thor', '>= 0.14.4')
20
+ s.add_dependency('httparty', '~> 0.13.0')
21
+ s.add_dependency('json', '~> 1.8.0')
22
+ s.add_dependency('mimemagic')
23
+ s.add_dependency('filewatcher')
24
+
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'minitest', '>= 5.0.0'
27
+
28
+ s.files = `git ls-files`.split("\n")
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
+ s.require_paths = ['lib']
32
+ end
@@ -0,0 +1,2 @@
1
+ ENV['TEST'] = 'true'
2
+ require 'minitest/autorun'
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+ require 'posthaven_theme'
4
+ require 'posthaven_theme/cli'
5
+
6
+ module PosthavenTheme
7
+ describe "Cli" do
8
+
9
+ class CliDouble < Cli
10
+ attr_writer :local_files, :mock_config
11
+
12
+ desc "",""
13
+ def config
14
+ @mock_config || super
15
+ end
16
+ desc "",""
17
+ def binary_file?(file)
18
+ super
19
+ end
20
+
21
+ desc "", ""
22
+ def local_files
23
+ @local_files
24
+ end
25
+ end
26
+
27
+ let(:command_name) { 'help' }
28
+ let(:command) { Thor::Command.new(command_name, nil, nil, nil, {}) }
29
+ let(:cli) { CliDouble.new([], {}, {current_command: command}) }
30
+
31
+ before { PosthavenTheme.config = {} }
32
+
33
+ it "should remove assets that are not a part of the white list" do
34
+ cli.local_files = ['assets/image.png', 'config.yml', 'layouts/theme.liquid']
35
+ local_assets_list = cli.send(:local_assets_list)
36
+ assert_equal 2, local_assets_list.length
37
+ assert_equal false, local_assets_list.include?('config.yml')
38
+ end
39
+
40
+ it "should remove assets that are part of the ignore list" do
41
+ PosthavenTheme.config = {ignore_files: ['config/settings.html']}
42
+ cli.local_files = ['assets/image.png', 'layouts/theme.liquid', 'config/settings.html']
43
+ local_assets_list = cli.send(:local_assets_list)
44
+ assert_equal 2, local_assets_list.length
45
+ assert_equal false, local_assets_list.include?('config/settings.html')
46
+ end
47
+
48
+ it "should report binary files as such" do
49
+ extensions = %w(png gif jpg jpeg eot svg ttf woff otf swf ico pdf)
50
+ extensions.each do |ext|
51
+ assert cli.binary_file?("hello.#{ext}"), "#{ext.upcase}s are binary files"
52
+ end
53
+ end
54
+
55
+ it "should report unknown files as binary files" do
56
+ assert cli.binary_file?('omg.wut'), "Unknown filetypes are assumed to be binary"
57
+ end
58
+
59
+ it "should not report text based files as binary" do
60
+ refute cli.binary_file?('theme.liquid'), "liquid files are not binary"
61
+ refute cli.binary_file?('style.sass.liquid'), "sass.liquid files are not binary"
62
+ refute cli.binary_file?('style.css'), 'CSS files are not binary'
63
+ refute cli.binary_file?('application.js'), 'Javascript files are not binary'
64
+ refute cli.binary_file?('settings_data.json'), 'JSON files are not binary'
65
+ refute cli.binary_file?('applicaton.js.map'), 'Javascript Map files are not binary'
66
+ end
67
+ end
68
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: posthaven_theme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brett Gibson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-08 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: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
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: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 5.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 5.0.0
111
+ description: Command line tool to help with developing Posthaven themes. Provides
112
+ simple commands to download, upload and delete files from a theme. Also includes
113
+ the watch command to watch a directory and upload files as they change.
114
+ email:
115
+ - help@posthaven.com
116
+ executables:
117
+ - phtheme
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - ".gitignore"
122
+ - Gemfile
123
+ - MIT-LICENSE
124
+ - README.md
125
+ - Rakefile
126
+ - bin/phtheme
127
+ - lib/posthaven_theme.rb
128
+ - lib/posthaven_theme/cli.rb
129
+ - lib/posthaven_theme/version.rb
130
+ - posthaven_theme.gemspec
131
+ - spec/spec_helper.rb
132
+ - spec/unit/cli_spec.rb
133
+ homepage: https://github.com/posthaven/posthaven_theme
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '2.0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project: posthaven_theme
153
+ rubygems_version: 2.6.4
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Command line tool for developing themes
157
+ test_files:
158
+ - spec/spec_helper.rb
159
+ - spec/unit/cli_spec.rb
160
+ has_rdoc: