vagrant-solidus 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.
@@ -0,0 +1,334 @@
1
+ module VagrantPlugins
2
+ module Solidus
3
+ module SiteHelpers
4
+ BASE_PORT = 8081
5
+ BASE_LIVERELOAD_PORT = 35730
6
+ SITE_TEMPLATE_GIT_URL = "https://github.com/solidusjs/solidus-site-template.git"
7
+ SITE_STATUS_WATCHER_POLLING_FREQUENCY = 1
8
+ PROVISION_ID = 20140502
9
+
10
+ #########################################################################
11
+ # System Calls
12
+ #########################################################################
13
+
14
+ def host_exec(log_type, *args)
15
+ with_log(log_type) do
16
+ @last_exit_code = Vagrant::Util::Subprocess.execute(*args, {notify: [:stdout, :stderr]}, &method(:log_callback)).exit_code
17
+ @last_exit_code == 0
18
+ end
19
+ end
20
+
21
+ def guest_exec(log_type, command, opts = {})
22
+ with_log(log_type) do
23
+ @last_exit_code = @machine.communicate.execute(command, {error_check: false}.merge(opts), &method(:log_callback))
24
+ @last_exit_code == 0
25
+ end
26
+ end
27
+
28
+ def with_log(log_type)
29
+ @log_type = log_type
30
+ @log_buffer = []
31
+ success = yield
32
+ @log_buffer.each {|args| log(*args)} if @log_type == :log_on_error && !success
33
+ return success
34
+ ensure
35
+ @log_type = nil
36
+ @log_buffer = nil
37
+ end
38
+
39
+ def log_callback(*args)
40
+ case @log_type
41
+ when :log_all
42
+ log(*args)
43
+ when :log_on_error
44
+ @log_buffer << args
45
+ end
46
+ end
47
+
48
+ def log(type, data)
49
+ @env.ui.info(data, prefix: false, new_line: false, channel: type == :stdout ? :out : :error)
50
+ end
51
+
52
+ def with_mutex
53
+ @mutex ||= Mutex.new
54
+ @mutex.synchronize do
55
+ yield
56
+ end
57
+ end
58
+
59
+ #########################################################################
60
+ # Sites Management
61
+ #########################################################################
62
+
63
+ def sites
64
+ @@sites ||= File.exists?(SITES_CONFIGS_FILE_HOST_PATH) ? JSON.load(File.new(SITES_CONFIGS_FILE_HOST_PATH)) : {}
65
+ end
66
+
67
+ def load_site
68
+ @site_host_path = File.join(ROOT_HOST_PATH, @site_name)
69
+ @site_guest_path = File.join(ROOT_GUEST_PATH, @site_name)
70
+ @site_log_file_path = ".vagrant-solidus/log/#{@site_name}.log"
71
+ @site_log_file_guest_path = File.join(ROOT_GUEST_PATH, @site_log_file_path)
72
+
73
+ if config = sites[@site_name]
74
+ @site_port = config['port']
75
+ @site_livereload_port = config['livereload-port']
76
+ end
77
+
78
+ @site_port ||= find_next_available_port('port', BASE_PORT)
79
+ @site_livereload_port ||= find_next_available_port('livereload-port', BASE_LIVERELOAD_PORT)
80
+ end
81
+
82
+ def find_next_available_port(type, port)
83
+ ports = sites.values.map {|config| config[type]}
84
+ loop do
85
+ return port unless ports.index(port)
86
+ port += 1
87
+ end
88
+ end
89
+
90
+ def validate_site
91
+ gruntfile = File.join(@site_host_path, 'Gruntfile.js')
92
+ package = File.join(@site_host_path, 'package.json')
93
+ File.exists?(gruntfile) && File.exists?(package) && File.read(package).index('solidus')
94
+ end
95
+
96
+ def save_site
97
+ config = {'port' => @site_port, 'livereload-port' => @site_livereload_port}
98
+ File.open(SITES_CONFIGS_FILE_HOST_PATH, 'w') do |file|
99
+ file.write(JSON.pretty_generate(sites.merge(@site_name => config)))
100
+ end
101
+ end
102
+
103
+ #########################################################################
104
+ # Site Log
105
+ #########################################################################
106
+
107
+ def follow_site_log
108
+ command = "tail -f -n 0 #{@site_log_file_guest_path}"
109
+ begin
110
+ guest_exec(:log_all, command)
111
+ rescue Interrupt
112
+ # Don't forget to stop tail in the vm
113
+ guest_exec(nil, "kill -s SIGINT `pgrep -f \"#{command}\"`")
114
+ end
115
+ end
116
+
117
+ def log_site_log_tail(lines)
118
+ guest_exec(:log_all, "tail -n #{lines} #{@site_log_file_guest_path}")
119
+ end
120
+
121
+ #########################################################################
122
+ # Site dependencies
123
+ #########################################################################
124
+
125
+ def install_site_dependencies
126
+ # Ruby gems
127
+ if File.exists?(File.join(@site_host_path, 'Gemfile'))
128
+ return unless guest_exec(:log_on_error, "cd #{@site_guest_path} && bundle install")
129
+ else
130
+ # Until all sites use bundler...
131
+ return unless guest_exec(:log_on_error, "gem install sass")
132
+ end
133
+
134
+ # Bower packages
135
+ if File.exists?(File.join(@site_host_path, 'bower.json'))
136
+ return unless guest_exec(:log_on_error, "npm install bower -g")
137
+ return unless guest_exec(:log_on_error, "cd #{@site_guest_path} && bower install")
138
+ end
139
+
140
+ return true
141
+ end
142
+
143
+ #########################################################################
144
+ # Node.js
145
+ #########################################################################
146
+
147
+ def install_site_node_packages
148
+ guest_exec(:log_on_error, "cd #{@site_guest_path} && npm install")
149
+ end
150
+
151
+ #########################################################################
152
+ # Upstart
153
+ #########################################################################
154
+
155
+ def install_site_service
156
+ conf = "exec su - vagrant -c 'cd #{@site_guest_path} && grunt dev -port #{@site_port} -livereloadport #{@site_livereload_port} >> #{@site_log_file_guest_path} 2>&1'"
157
+ guest_exec(:log_on_error, "echo \"#{conf}\" > /etc/init/#{site_service_name}.conf", sudo: true)
158
+ end
159
+
160
+ def uninstall_site_service
161
+ guest_exec(nil, "rm /etc/init/#{site_service_name}.conf", sudo: true)
162
+ end
163
+
164
+ def start_site_service
165
+ guest_exec(:log_on_error, "start #{site_service_name}", sudo: true)
166
+ end
167
+
168
+ def stop_site_service
169
+ guest_exec(nil, "stop #{site_service_name}", sudo: true)
170
+ end
171
+
172
+ def stop_site
173
+ stop_site_service
174
+ wait_for_site_watcher_to_stop
175
+ end
176
+
177
+ def site_started?
178
+ guest_exec(nil, "status #{site_service_name} | grep 'start/running'", sudo: true)
179
+ end
180
+
181
+ def site_responding?
182
+ loop do
183
+ return false unless site_started?
184
+ return true if guest_exec(nil, "curl --head localhost:#{@site_port}/status")
185
+ sleep 0.5
186
+ end
187
+ end
188
+
189
+ def site_service_name
190
+ "site-#{@site_name}"
191
+ end
192
+
193
+ #########################################################################
194
+ # Pow
195
+ #########################################################################
196
+
197
+ def pow_installed?
198
+ File.directory?(File.expand_path("~/.pow"))
199
+ end
200
+
201
+ def install_pow_site
202
+ File.write(File.expand_path("~/.pow/#{@site_name}"), @site_port)
203
+ end
204
+
205
+ def uninstall_pow_site
206
+ File.delete(File.expand_path("~/.pow/#{@site_name}")) if File.exists?(File.expand_path("~/.pow/#{@site_name}"))
207
+ end
208
+
209
+ #########################################################################
210
+ # Site Watcher
211
+ #########################################################################
212
+
213
+ def start_site_watcher
214
+ command = "vagrant site watch -s #{@site_name} -q"
215
+ Process.detach(Process.spawn(command, chdir: ROOT_HOST_PATH))
216
+ end
217
+
218
+ def wait_for_site_watcher_to_stop
219
+ sleep(SITE_STATUS_WATCHER_POLLING_FREQUENCY)
220
+ end
221
+
222
+ #########################################################################
223
+ # Site Template
224
+ #########################################################################
225
+
226
+ def clone_site_template(site_template_git_url)
227
+ site_template_git_url ||= SITE_TEMPLATE_GIT_URL
228
+ FileUtils.rm_rf(SITE_TEMPLATE_HOST_PATH)
229
+ fail("Site template could not be cloned") unless host_exec(:log_on_error, "git", "clone", site_template_git_url, SITE_TEMPLATE_HOST_PATH)
230
+ wait_until_guest_directory_exists(SITE_TEMPLATE_GUEST_PATH)
231
+ end
232
+
233
+ def create_site_from_template(site_template_guest_path)
234
+ site_template_guest_path ||= SITE_TEMPLATE_GUEST_PATH
235
+ fail("Site could not be created") unless guest_exec(:log_on_error, "mkdir -p #{@site_guest_path}")
236
+ fail("Site could not be created") unless guest_exec(:log_on_error, "cd #{@site_guest_path} && grunt-init --default=1 #{site_template_guest_path}")
237
+ end
238
+
239
+ #########################################################################
240
+ # Command Line Options
241
+ #########################################################################
242
+
243
+ def site_name_command_line_option(opts)
244
+ @site_name = Pathname.pwd.relative_path_from(ROOT_HOST_PATH).to_s.split(File::SEPARATOR).first
245
+
246
+ opts.on("-s", "--site <site>", "Site to use, instead of the current directory.") do |site_name|
247
+ raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if !site_name || site_name.empty?
248
+ @site_name = site_name.chomp('/')
249
+ end
250
+ end
251
+
252
+ def help_command_line_option(opts)
253
+ opts.on("-h", "--help", "Print this help") do
254
+ safe_puts(opts.help)
255
+ abort
256
+ end
257
+ end
258
+
259
+ def site_start_command_line_options(opts)
260
+ site_name_command_line_option(opts)
261
+ opts.on("-f", "--fast", "Fast mode. Don't install the site first.") do
262
+ @fast = true
263
+ end
264
+ opts.on("-d", "--deaf", "Don't automatically launch the `watch` command in background (file events will be much slower).") do
265
+ @deaf = true
266
+ end
267
+ end
268
+
269
+ def quiet_command_line_option(opts)
270
+ opts.on("-q", "--quiet", "Quiet mode. Don't output anything.") do
271
+ @quiet = true
272
+ end
273
+ end
274
+
275
+ def site_template_command_line_options(opts)
276
+ opts.on("-g", "--template-git-url <URL>", "URL of the Solidus site template Git repository", "Default: #{SITE_TEMPLATE_GIT_URL}") do |url|
277
+ raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if !url || url.empty?
278
+ @site_template_git_url = url
279
+ end
280
+
281
+ opts.on("-p", "--template-path <path>", "Path of the Solidus site template to use, instead of the Git repository", "Must be relative to the Vagrantfile's directory") do |path|
282
+ raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if !path || path.empty?
283
+ @site_template_host_path = File.join(ROOT_HOST_PATH, path)
284
+ @site_template_guest_path = File.join(ROOT_GUEST_PATH, path)
285
+ end
286
+ end
287
+
288
+ #########################################################################
289
+ # Provision
290
+ #########################################################################
291
+
292
+ def provisioned?
293
+ guest_exec(nil, "echo #{PROVISION_ID} | diff - ~/.vagrant-solidus/provision")
294
+ end
295
+
296
+ def provisioned!
297
+ "mkdir -p ~/.vagrant-solidus && echo #{PROVISION_ID} > ~/.vagrant-solidus/provision"
298
+ end
299
+
300
+ #########################################################################
301
+ # Misc
302
+ #########################################################################
303
+
304
+ def fail(error)
305
+ @env.ui.error(error)
306
+ abort
307
+ end
308
+
309
+ def wait_until_guest_directory_exists(directory)
310
+ until guest_exec(nil, "cd #{directory}") do
311
+ sleep 0.5
312
+ end
313
+ end
314
+
315
+ def directory_exists?(directory)
316
+ File.directory?(directory) && !(Dir.entries(directory) - %w{. ..}).empty?
317
+ end
318
+
319
+ def log_site_urls
320
+ @env.ui.info(" Local URL:")
321
+ @env.ui.info(" http://#{@site_name}.dev") if pow_installed?
322
+ @env.ui.info(" http://lvh.me:#{@site_port}")
323
+ @env.ui.info(" http://localhost:#{@site_port}")
324
+ @env.ui.info(" Network URL:")
325
+ @env.ui.info(" http://#{@site_name}.#{ip_address}.xip.io") if pow_installed?
326
+ @env.ui.info(" http://#{ip_address}.xip.io:#{@site_port}")
327
+ end
328
+
329
+ def ip_address
330
+ @ip_address ||= Socket.ip_address_list.detect(&:ipv4_private?).ip_address
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,30 @@
1
+ # Requirements
2
+ Vagrant.require_version '>= 1.5.0'
3
+ unless Vagrant.has_plugin?('vagrant-solidus')
4
+ abort "\033[31mVagrant needs an additional plugin for this box, run `vagrant plugin install vagrant-solidus` and try again\033[0m"
5
+ end
6
+
7
+ Vagrant.configure('2') do |config|
8
+ # Setup Virtual Box
9
+ config.vm.provider "virtualbox" do |box|
10
+ box.name = "Solidus Box"
11
+ box.customize ["modifyvm", :id, "--memory", "1024"]
12
+ end
13
+
14
+ # Setup the virtual machine
15
+ config.vm.box = "ubuntu-precise64"
16
+ config.vm.box_url = "http://files.vagrantup.com/precise64.box"
17
+ config.vm.hostname = "solidus-box"
18
+ config.vm.synced_folder ".", "/vagrant", nfs: true
19
+
20
+ # TODO: Can't make DHCP work properly (reloading the box results in a "No guest
21
+ # IP was given to the Vagrant core NFS helper." error). So we use a random static
22
+ # IP instead, to hopefully prevent collisions on the network. See:
23
+ # https://github.com/mitchellh/vagrant/issues/2626
24
+ # http://docs.vagrantup.com/v2/networking/private_network.html
25
+ config.vm.network :private_network, ip: "192.168.#{rand(256)}.#{rand(256)}"
26
+
27
+ # The vagrant-solidus plugin handles the rest, see:
28
+ # https://github.com/solidusjs/vagrant-solidus
29
+ config.vm.provision :solidus
30
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../command'
2
+
3
+ module VagrantPlugins
4
+ module Solidus
5
+ module SolidusBox
6
+ class Command < VagrantPlugins::Solidus::Command
7
+ def self.synopsis
8
+ 'manages Solidus box'
9
+ end
10
+
11
+ def command
12
+ 'solidus-box'
13
+ end
14
+
15
+ def subcommands
16
+ %w[init]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ module VagrantPlugins
2
+ module Solidus
3
+ module SolidusBox
4
+ class Init < Vagrant.plugin('2', :command)
5
+ def execute
6
+ parse_arguments
7
+
8
+ source_path = File.join(File.dirname(__FILE__), 'Vagrantfile')
9
+ target_path = File.join(@env.root_path || Dir.pwd, 'Vagrantfile')
10
+
11
+ abort if File.exists?(target_path) && @env.ui.ask("Are you sure you want to replace `#{target_path}`? [y/n] ") != 'y'
12
+ FileUtils.copy(source_path, target_path)
13
+
14
+ @env.ui.success("A `Vagrantfile` prepared for Solidus has been placed here:
15
+ #{target_path}
16
+ Run `vagrant site` to see all the available commands to manage your Solidus sites.".gsub(/^\s*/, ''))
17
+
18
+ # Success, exit status 0
19
+ 0
20
+ end
21
+
22
+ protected
23
+
24
+ def parse_arguments
25
+ opts = OptionParser.new do |opts|
26
+ opts.banner = "Usage: vagrant solidus-box init"
27
+ opts.separator ""
28
+ opts.separator "Create a `Vagrantfile` prepared for Solidus."
29
+ opts.separator ""
30
+ end
31
+
32
+ abort unless argv = parse_options(opts)
33
+ raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp unless argv.size == 0
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module Solidus
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vagrant-solidus/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "vagrant-solidus"
8
+ spec.version = VagrantPlugins::Solidus::VERSION
9
+ spec.authors = ["Joannic Laborde"]
10
+ spec.email = ["joannic@sparkart.com"]
11
+ spec.summary = "This plugin provides a provisioner and a `site` command that allows Solidus sites to be managed by Vagrant."
12
+ spec.homepage = "https://github.com/solidusjs/vagrant-solidus"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake"
22
+ end