thin_service 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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