Permalink
Browse files

Replace win32-service dependency

GCC builds of Ruby are not compatible with win32-service due
the usage of SEH inside deamons.

To workaround that, instead of using win32-service gems, I've
replaced the code with a custom module that mimics the functionality
and stays pure-ruby. It shells out to 'sc' utility, which is part
of every Windows installation.
  • Loading branch information...
1 parent d5f50f6 commit fa361ece17a5eb1c665bf4523183a5aca4f51757 @luislavena committed Jan 1, 2010
Showing with 94 additions and 36 deletions.
  1. +1 −0 Manifest.txt
  2. +24 −35 lib/mongrel_service/init.rb
  3. +69 −0 lib/mongrel_service/service_manager.rb
  4. +0 −1 tasks/gem.rake
View
@@ -1,5 +1,6 @@
History.txt
lib/mongrel_service/init.rb
+lib/mongrel_service/service_manager.rb
LICENSE.txt
Manifest.txt
Rakefile
@@ -3,6 +3,7 @@
require 'mongrel/rails'
require 'rbconfig'
require 'fileutils'
+require 'mongrel_service/service_manager'
module Service
class Install < GemPlugin::Plugin "/commands"
@@ -33,10 +34,6 @@ def configure
# of the rails application we wanted to serve, because later "as service" no error
# show to trace this.
def validate
- # TODO: investigate why Win32::Service interfere with gem_plugin
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
@cwd = File.expand_path(@cwd)
valid_dir? @cwd, "Invalid path to change to: #@cwd"
@@ -77,12 +74,9 @@ def validate
end
def run
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
# check if mongrel_service.exe is in ruby bindir.
gem_root = File.join(File.dirname(__FILE__), "..", "..")
- gem_executable = File.join(gem_root, "bin/mongrel_service.exe")
+ gem_executable = File.join(gem_root, "resources/mongrel_service.exe")
bindir_executable = File.join(Config::CONFIG['bindir'], '/mongrel_service.exe')
unless File.exist?(bindir_executable)
@@ -143,21 +137,16 @@ def run
argv << "--prefix \"#{@options[:prefix]}\"" if @options[:prefix]
end
- svc = Win32::Service.new
begin
- svc.create_service{ |s|
- s.service_name = @svc_name
- s.display_name = @svc_display
- s.binary_path_name = argv.join ' '
- s.dependencies = []
- s.service_type = Win32::Service::WIN32_OWN_PROCESS
- }
- puts "Mongrel service '#{@svc_display}' installed as '#{@svc_name}'."
- rescue Win32::ServiceError => err
+ ServiceManager.create(
+ @svc_name,
+ @svc_display,
+ argv.join(' ')
+ )
+ rescue ServiceManager::CreateError => e
puts "There was a problem installing the service:"
- puts err
+ puts e
end
- svc.close
end
end
@@ -171,13 +160,10 @@ def configure
def validate
valid? @svc_name != nil, "A service name is mandatory."
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
-
# Validate that the service exists
begin
- valid? Win32::Service.exists?(@svc_name), "There is no service with that name, cannot proceed."
- Win32::Service.open(@svc_name) do |svc|
+ valid? ServiceManager.exists?(@svc_name), "There is no service with that name, cannot proceed."
+ ServiceManager.open(@svc_name) do |svc|
valid? svc.binary_path_name.include?("mongrel_service"), "The service specified isn't a Mongrel service."
end
rescue
@@ -190,22 +176,25 @@ def validate
class Remove < GemPlugin::Plugin "/commands"
include Mongrel::Command::Base
include ServiceValidation
-
+
def run
- gem 'win32-service', '>= 0.5.2', '< 0.6.0'
- require 'win32/service'
+ display_name = ServiceManager.getdisplayname(@svc_name)
- display_name = Win32::Service.getdisplayname(@svc_name)
-
begin
- Win32::Service.stop(@svc_name)
- rescue
+ ServiceManager.stop(@svc_name)
+ rescue ServiceManager::ServiceError => e
+ puts e
end
+
begin
- Win32::Service.delete(@svc_name)
- rescue
+ ServiceManager.delete(@svc_name)
+ rescue ServiceManager::ServiceError => e
+ puts e
+ end
+
+ unless ServiceManager.exist?(@svc_name) then
+ puts "#{display_name} service removed."
end
- puts "#{display_name} service removed."
end
end
end
@@ -0,0 +1,69 @@
+module ServiceManager
+ class CreateError < StandardError; end
+ class ServiceNotFound < StandardError; end
+ class ServiceError < StandardError; end
+
+ class ServiceStruct < Struct.new(:service_name, :display_name, :binary_path_name)
+ end
+
+ def self.create(service_name, display_name, binary_path_name)
+ cmd = ['create']
+ cmd << service_name
+ cmd << "binPath=" << binary_path_name
+ cmd << "DisplayName=" << display_name
+ status, out = sc(*cmd)
+ raise CreateError.new(out) unless status == 0
+
+ return true
+ end
+
+ def self.exist?(service_name)
+ status, out = sc('query', service_name)
+ status == 0
+ end
+
+ def self.open(service_name)
+ status, out = sc('qc', service_name)
+ raise ServiceNotFound.new(out) unless status == 0
+
+ out =~ /BINARY\_PATH\_NAME.*\: (.*)$/
+ binary_path_name = $1.strip
+
+ out =~ /DISPLAY\_NAME.*\: (.*)$/
+ display_name = $1.strip
+
+ svc = ServiceStruct.new(service_name, display_name, binary_path_name)
+
+ yield svc if block_given?
+ svc
+ end
+
+ def self.getdisplayname(service_name)
+ status, out = sc('GetDisplayName', service_name)
+ raise ServiceNotFound.new(out) unless status == 0
+
+ out =~ /\=(.*)$/
+ $1.strip
+ end
+
+ def self.stop(service_name)
+ status, out = sc('stop', service_name)
+ raise ServiceError.new(out) unless status == 0
+
+ return true
+ end
+
+ def self.delete(service_name)
+ status, out = sc('delete', service_name)
+ raise ServiceError.new(out) unless status == 0
+
+ return true
+ end
+
+ private
+
+ def self.sc(*args)
+ output = `sc #{args.join(' ')} 2>&1`
+ return [$?.exitstatus, output]
+ end
+end
View
@@ -11,7 +11,6 @@ HOE = Hoe.spec 'mongrel_service' do
extra_deps << ['gem_plugin', '~> 0.2.3']
extra_deps << ['mongrel', '~> 1.1.5']
- extra_deps << ['win32-service', '~> 0.5.2']
self.need_tar = false
end

0 comments on commit fa361ec

Please sign in to comment.