thin_service 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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ *.o
4
+ *.a
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in thin_service.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,53 @@
1
+ Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw
2
+ <zedshaw at zedshaw dot com> and contributors. You can redistribute it
3
+ and/or modify it under either the terms of the GPL2 or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise make them
13
+ Freely Available, such as by posting said modifications to Usenet or an
14
+ equivalent medium, or by allowing the author to include your
15
+ modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict with
21
+ standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent) on where
30
+ to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of the
33
+ software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ 5. The scripts and library files supplied as input to or produced as
45
+ output from the software do not automatically fall under the
46
+ copyright of the software, but belong to whomever generated them,
47
+ and may be sold commercially, and may be aggregated with this
48
+ software.
49
+
50
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
51
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
52
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
+ PURPOSE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # ThinService
2
+
3
+ Run Thin as a Windows Service - based on mongrel_service by Luis Lavena
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'thin_service'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install thin_service
18
+
19
+ ## Usage
20
+
21
+ Use the following commands to get more help:
22
+
23
+ thin_service install --help
24
+ thin_service remove --help
25
+
26
+
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/clean"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ task :default => :spec
9
+ task :test => :spec
10
+ task :package => [:compile]
11
+ task :build => [:compile]
12
+
13
+ CLOBBER.include('pkg')
14
+
15
+ load 'tasks/native_lib.rake'
16
+ load 'tasks/native_service.rake'
17
+
data/bin/thin_service ADDED
@@ -0,0 +1,17 @@
1
+ #!C:/Ruby193/bin/ruby.exe
2
+
3
+
4
+ if ARGV.first == "start"
5
+ ARGV.shift
6
+ ARGV = ["exec", "thin", "start"] + ARGV
7
+ p ARGV
8
+ Dir.chdir( "C:/Users/Owner/Documents/NetBeansProjects/hgcs" )
9
+ gem 'bundler', version
10
+ p 'aa'
11
+
12
+ load Gem.bin_path('bundler', 'bundle', version)
13
+ else
14
+ require 'thin_service'
15
+ ThinService::Service.new(ARGV).run!
16
+ end
17
+
@@ -0,0 +1,15 @@
1
+ require_relative "thin_service/version.rb"
2
+ require_relative "thin_service/command.rb"
3
+
4
+ module ThinService
5
+ class Service
6
+ def initialize( args )
7
+ @args = args
8
+ end
9
+
10
+ def run!
11
+ ThinService::Command::Registry.new.run( @args )
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,343 @@
1
+ # Mongrel Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+ #
7
+ # Adapted for thin_service by Garth Smedley
8
+
9
+ require 'optparse'
10
+ require 'fileutils'
11
+ require 'thin_service/service_manager'
12
+
13
+
14
+ module ThinService
15
+
16
+ module Command
17
+
18
+ BANNER = "Usage: thin_service <command> [options]"
19
+ COMMANDS = ['start', 'install', 'remove']
20
+
21
+ class Base
22
+
23
+ attr_reader :valid, :done_validating
24
+
25
+ # Called by the implemented command to set the options for that command.
26
+ # Every option has a short and long version, a description, a variable to
27
+ # set, and a default value. No exceptions.
28
+ def options(opts)
29
+ opts.each do |short, long, help, variable, default|
30
+ self.instance_variable_set(variable, default)
31
+ @opt.on(short, long, help) do |arg|
32
+ self.instance_variable_set(variable, arg)
33
+ end
34
+ end
35
+ end
36
+
37
+ # Called by the subclass to setup the command and parse the argv arguments.
38
+ # The call is destructive on argv since it uses the OptionParser#parse! function.
39
+ def initialize(options={})
40
+ argv = options[:argv] || []
41
+ @opt = OptionParser.new
42
+ @opt.banner = ThinService::Command::BANNER
43
+ @valid = true
44
+ @done_validating = false
45
+
46
+ configure
47
+
48
+ @opt.on_tail("-h", "--help", "Show this message") do
49
+ @done_validating = true
50
+ puts(@opt)
51
+ end
52
+
53
+ # I need to add my own -v definition to prevent the -v from exiting by default as well.
54
+ @opt.on_tail("--version", "Show version") do
55
+ @done_validating = true
56
+ puts("Version #{ThinService::VERSION}")
57
+ end
58
+
59
+ @opt.parse! argv
60
+ end
61
+
62
+ def configure
63
+ options []
64
+ end
65
+
66
+ # Returns true/false depending on whether the command is configured properly.
67
+ def validate
68
+ return @valid
69
+ end
70
+
71
+ # Returns a help message. Defaults to OptionParser#help which should be good.
72
+ def help
73
+ @opt.help
74
+ end
75
+
76
+ # Runs the command doing it's job. You should implement this otherwise it will
77
+ # throw a NotImplementedError as a reminder.
78
+ def run
79
+ raise NotImplementedError
80
+ end
81
+
82
+
83
+ # Validates the given expression is true and prints the message if not, exiting.
84
+ def valid?(exp, message)
85
+ if !@done_validating && !exp
86
+ failure message
87
+ @valid = false
88
+ @done_validating = true
89
+ end
90
+ end
91
+
92
+ # Validates that a file exists and if not displays the message
93
+ def valid_exists?(file, message)
94
+ valid?(file != nil && File.exist?(file), message)
95
+ end
96
+
97
+
98
+ # Validates that the file is a file and not a directory or something else.
99
+ def valid_file?(file, message)
100
+ valid?(file != nil && File.file?(file), message)
101
+ end
102
+
103
+ # Validates that the given directory exists
104
+ def valid_dir?(file, message)
105
+ valid?(file != nil && File.directory?(file), message)
106
+ end
107
+
108
+ # Just a simple method to display failure until something better is developed.
109
+ def failure(message)
110
+ STDERR.puts "!!! #{message}"
111
+ end
112
+ end
113
+
114
+ module Commands
115
+ class Install < ThinService::Command::Base
116
+
117
+ def configure
118
+ options [
119
+ ['-N', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
120
+ ['-D', '--display SVC_DISPLAY', "Adjust the display name of the service.", :@svc_display, nil],
121
+ ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
122
+ ['-p', '--port PORT', "Which port to bind to", :@port, 3000],
123
+ ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
124
+ ['-t', '--timeout TIME', "Timeout for requests in seconds", :@timeout, 30],
125
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
126
+ ['-D', '--debug', "Enable debugging mode", :@debug, false],
127
+ ['' , '--max-persistent-conns INT', "Maximum number of persistent connections", :@max_persistent_conns, 512],
128
+ ['' , '--ssl', "Enables SSL", :@ssl, nil],
129
+ ['' , '--ssl-key-file PATH', "Path to private key", :@ssl_key_file, nil],
130
+ ['' , '--ssl-cert-file PATH', "Path to certificate", :@ssl_cert_file, nil],
131
+ ['' , '--ssl-verify', "Enables SSL certificate verification", :@ssl_verify, nil],
132
+ ['' , '--prefix PATH', "URL prefix for Rails app", :@prefix, nil],
133
+ ]
134
+ end
135
+
136
+ # When we validate the options, we need to make sure the --root is actually RAILS_ROOT
137
+ # of the rails application we wanted to serve, because later "as service" no error
138
+ # show to trace this.
139
+ def validate
140
+ @cwd = File.expand_path(@cwd)
141
+ valid_dir? @cwd, "Invalid path to change to: #@cwd"
142
+
143
+ # change there to start, then we'll have to come back after daemonize
144
+ Dir.chdir(@cwd)
145
+
146
+ valid? @svc_name != nil, "A service name is mandatory."
147
+ valid? !ServiceManager.exist?(@svc_name), "The service already exist, please remove it first."
148
+
149
+ # default service display to service name
150
+ @svc_display = @svc_name if !@svc_display
151
+
152
+ # start with the premise of app really exist.
153
+ app_exist = true
154
+ %w{app config log}.each do |path|
155
+ if !File.directory?(File.join(@cwd, path))
156
+ app_exist = false
157
+ break
158
+ end
159
+ end
160
+
161
+ valid?(@prefix[0].chr == "/" && @prefix[-1].chr != "/", "Prefix must begin with / and not end in /") if @prefix
162
+
163
+ valid? app_exist == true, "The path you specified isn't a valid Rails application."
164
+
165
+ return @valid
166
+ end
167
+
168
+ def run
169
+ # check if thin_service.exe is in ruby bindir.
170
+ gem_root = File.join(File.dirname(__FILE__), "..", "..")
171
+ gem_executable = File.join(gem_root, "resource/thin_service_wrapper.exe")
172
+ bindir_executable = File.join(RbConfig::CONFIG['bindir'], '/thin_service_wrapper.exe')
173
+
174
+ unless File.exist?(bindir_executable)
175
+ STDERR.puts "** Copying native thin_service executable..."
176
+ FileUtils.cp gem_executable, bindir_executable rescue nil
177
+ end
178
+
179
+ unless FileUtils.compare_file(bindir_executable, gem_executable)
180
+ STDERR.puts "** Updating native thin_service executable..."
181
+ FileUtils.rm_f bindir_executable rescue nil
182
+ FileUtils.cp gem_executable, bindir_executable rescue nil
183
+ end
184
+
185
+ # build the command line
186
+ argv = []
187
+
188
+ # start using the native executable
189
+ argv << '"' + bindir_executable + '"'
190
+
191
+ # force indication of service mode
192
+ argv << "start"
193
+
194
+ # now the options
195
+ argv << "-e #{@environment}" if @environment
196
+ argv << "-p #{@port}"
197
+ argv << "-a #{@host}" if @host
198
+ argv << "-c \"#{@cwd}\"" if @cwd
199
+ argv << "-t #{@timeout}" if @timeout
200
+ argv << "-D" if @debug
201
+ argv << "--max-persistent-conns #{@max_persistent_conns}" if @max_persistent_conns
202
+ argv << "--ssl" if @ssl
203
+ argv << "--ssl-key-file \"#{@ssl_key_file}\"" if @ssl_key_file
204
+ argv << "--ssl-cert-file \"#{@ssl_cert_file}\"" if @ssl_cert_file
205
+ argv << "--ssl-verify" if @ssl_verify
206
+ argv << "--prefix \"#{@prefix}\"" if @prefix
207
+
208
+ # concat remaining non-parsed ARGV
209
+ argv.concat(ARGV)
210
+
211
+ begin
212
+ ServiceManager.create(
213
+ @svc_name,
214
+ @svc_display,
215
+ argv.join(' ')
216
+ )
217
+ puts "#{@svc_display} service created."
218
+ rescue ServiceManager::CreateError => e
219
+ puts "There was a problem installing the service:"
220
+ puts e
221
+ end
222
+ end
223
+ end
224
+
225
+ module ServiceValidation
226
+ def configure
227
+ options [
228
+ ['-N', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
229
+ ]
230
+ end
231
+
232
+ def validate
233
+ valid? @svc_name != nil, "A service name is mandatory."
234
+
235
+ # Validate that the service exists
236
+ valid? ServiceManager.exist?(@svc_name), "There is no service with that name, cannot proceed."
237
+ if @valid then
238
+ ServiceManager.open(@svc_name) do |svc|
239
+ valid? svc.binary_path_name.include?("thin_service"), "The service specified isn't a Thin service."
240
+ end
241
+ end
242
+
243
+ return @valid
244
+ end
245
+ end
246
+
247
+ class Remove < ThinService::Command::Base
248
+ include ServiceValidation
249
+
250
+ def run
251
+ display_name = ServiceManager.getdisplayname(@svc_name)
252
+
253
+ begin
254
+ puts "Stopping #{display_name} if running..."
255
+ ServiceManager.stop(@svc_name)
256
+ rescue ServiceManager::ServiceError => e
257
+ end
258
+
259
+ begin
260
+ ServiceManager.delete(@svc_name)
261
+ rescue ServiceManager::ServiceError => e
262
+ puts e
263
+ end
264
+
265
+ unless ServiceManager.exist?(@svc_name) then
266
+ puts "#{display_name} service removed."
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ # Manages all of the available commands
273
+ # and handles running them.
274
+ class Registry
275
+
276
+ # Builds a list of possible commands from the Command derivates list
277
+ def commands
278
+ ThinService::Command::COMMANDS
279
+ end
280
+
281
+ # Prints a list of available commands.
282
+ def print_command_list
283
+ puts("#{ThinService::Command::BANNER}\nAvailable commands are:\n\n")
284
+
285
+ self.commands.each do |name|
286
+ puts(" - #{name}\n")
287
+ end
288
+
289
+ puts("\nEach command takes -h as an option to get help.")
290
+
291
+ end
292
+
293
+ def constantize(class_name)
294
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ class_name
295
+ raise NameError, "#{class_name.inspect} is not a valid constant name!"
296
+ end
297
+
298
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
299
+ end
300
+
301
+
302
+ # Runs the args against the first argument as the command name.
303
+ # If it has any errors it returns a false, otherwise it return true.
304
+ def run(args)
305
+ # find the command
306
+ cmd_name = args.shift
307
+
308
+ if !cmd_name || cmd_name == "-?" || cmd_name == "--help"
309
+ print_command_list
310
+ return true
311
+ elsif cmd_name == "--version"
312
+ puts("ThinService #{ThinService::VERSION}")
313
+ return true
314
+ end
315
+
316
+ begin
317
+ cmd_class_name = "ThinService::Command::Commands::" + cmd_name.capitalize
318
+ command = constantize(cmd_class_name).new( :argv => args )
319
+ rescue OptionParser::InvalidOption
320
+ STDERR.puts "#$! for command '#{cmd_name}'"
321
+ STDERR.puts "Try #{cmd_name} -h to get help."
322
+ return false
323
+ rescue
324
+ STDERR.puts "ERROR RUNNING '#{cmd_name}': #$!"
325
+ STDERR.puts "Use help command to get help"
326
+ return false
327
+ end
328
+
329
+ if !command.done_validating
330
+ if !command.validate
331
+ STDERR.puts "#{cmd_name} reported an error. Use thin_service #{cmd_name} -h to get help."
332
+ return false
333
+ else
334
+ command.run
335
+ end
336
+ end
337
+
338
+ return true
339
+ end
340
+
341
+ end
342
+ end
343
+ end