win32_service_manager 0.1.0

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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.0 / 2009-02-05
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/Manifest.txt ADDED
@@ -0,0 +1,20 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ bin/win32_service_manager
6
+ lib/win32_service_manager.rb
7
+ spec/helper.rb
8
+ spec/runner
9
+ spec/spec_win32_service_manager.rb
10
+ tasks/autospec.rake
11
+ tasks/bacon.rake
12
+ tasks/bones.rake
13
+ tasks/gem.rake
14
+ tasks/git.rake
15
+ tasks/manifest.rake
16
+ tasks/notes.rake
17
+ tasks/post_load.rake
18
+ tasks/rdoc.rake
19
+ tasks/rubyforge.rake
20
+ tasks/setup.rb
data/README.rdoc ADDED
@@ -0,0 +1,59 @@
1
+ = win32_service_manager
2
+ by James Tucker
3
+ http://ra66i.org
4
+ http://github.com/raggi/win32_service_manager
5
+ http://libraggi.rubyforge.org/win32_service_manager
6
+
7
+ == DESCRIPTION:
8
+
9
+ A simple wrapper around Win32::Service to present a more 'God'
10
+ (http://god.rubyforge.org) like interface. Also presents all service
11
+ information as hashes rather than structs to save on wire transport and
12
+ multi-platform complexity.
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ * Really heavily mocked out for testing, might need more integration tests.
17
+
18
+ == SYNOPSIS:
19
+
20
+ sm = Win32ServiceManager.new('')
21
+ sm.status
22
+ sm.status('Abiosdsk')
23
+
24
+ == REQUIREMENTS:
25
+
26
+ At the time of writing, some of the dependencies are only available as gems to
27
+ the 'x86-mswin32-60' platform. If you are installing on mingw, you can get
28
+ away with installing them using a specific --platform argument to rubygems.
29
+
30
+ * win32-service
31
+
32
+ == INSTALL:
33
+
34
+ * gem inst win32_service_manager
35
+
36
+ == LICENSE:
37
+
38
+ (The MIT License)
39
+
40
+ Copyright (c) 2009 James Tucker
41
+
42
+ Permission is hereby granted, free of charge, to any person obtaining
43
+ a copy of this software and associated documentation files (the
44
+ 'Software'), to deal in the Software without restriction, including
45
+ without limitation the rights to use, copy, modify, merge, publish,
46
+ distribute, sublicense, and/or sell copies of the Software, and to
47
+ permit persons to whom the Software is furnished to do so, subject to
48
+ the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be
51
+ included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
54
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ load 'tasks/setup.rb'
2
+
3
+ ensure_in_path 'lib'
4
+ require 'win32_service_manager'
5
+
6
+ task :default => :test
7
+
8
+ PROJ.name = 'win32_service_manager'
9
+ PROJ.authors = 'James Tucker'
10
+ PROJ.email = 'raggi@rubyforge.org'
11
+ PROJ.url = 'http://github.com/raggi/win32_service_manager'
12
+ PROJ.rubyforge.name = 'libraggi'
13
+ PROJ.version = Win32ServiceManager.version
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), '..', 'lib', 'win32_service_manager'))
5
+
6
+ # Put your code here
@@ -0,0 +1,70 @@
1
+ require 'win32_service_manager/core_ext/struct_to_hash'
2
+
3
+ class Win32ServiceManager
4
+
5
+ VERSION = '0.1.0'
6
+ def self.version; VERSION; end
7
+ def self.load_dependencies; require 'win32/service'; end
8
+
9
+ # Construct a new service manager, just sets up a name_key, which is used
10
+ # as a leading string to the name of all services managed by the instance.
11
+ # srv_any_path must be a full path to srvany.exe.
12
+ def initialize(name_key = '')
13
+ self.class.load_dependencies
14
+ @name_key = name_key
15
+ end
16
+
17
+ # Create a new service. The service name will be appended to the name_key
18
+ # and inserted into the registry using Win32::Service. The arguments are
19
+ # then adjusted with win32-registry.
20
+ # One recommended pattern is to store persisence details about the service
21
+ # as yaml in the optional description field.
22
+ def create(name, command, args = '', description = nil, options = {})
23
+ defaults = {
24
+ :service_type => Win32::Service::WIN32_OWN_PROCESS,
25
+ :start_type => Win32::Service::AUTO_START,
26
+ :error_control => Win32::Service::ERROR_NORMAL
27
+ }
28
+ defaults.merge!(options)
29
+ name = n(name)
30
+ options = defaults.merge(
31
+ :display_name => name,
32
+ :description => description || name,
33
+ :binary_path_name => command
34
+ )
35
+ Win32::Service.create(name, nil, options)
36
+ end
37
+
38
+ # Mark a service for deletion (note, does not terminate the service)
39
+ def delete(name)
40
+ Win32::Service.delete(n(name))
41
+ end
42
+
43
+ def start(name)
44
+ Win32::Service.start(n(name))
45
+ end
46
+
47
+ def stop(name)
48
+ Win32::Service.stop(n(name))
49
+ end
50
+
51
+ # Returns an array of tuples of name and description
52
+ def status(name = nil)
53
+ list = name ? services.select { |s| s.display_name == name } : services
54
+ list.map { |svc_info| svc_info.to_hash }
55
+ end
56
+ alias_method :list, :status
57
+
58
+ def services
59
+ Win32::Service.services.select do |svc|
60
+ # TODO in future, 1.8.7, can use start_with?
61
+ svc.display_name[0,@name_key.size] == @name_key
62
+ end
63
+ end
64
+
65
+ private
66
+ def n(name)
67
+ @name_key + name.to_s
68
+ end
69
+
70
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Disable test/unit and rspec from running, in case loaded by broken tools.
2
+ Test::Unit.run = false if defined?(Test) && defined?(Test::Unit)
3
+ Spec::run = false if defined?(Spec) && Spec::respond_to?(:run=)
4
+
5
+ # Setup a nice testing environment
6
+ $DEBUG, $TESTING = true, true
7
+ $:.push File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $:.uniq!
9
+
10
+ %w[rubygems bacon].each { |r| require r }
11
+
12
+ # Bacon doesn't do any automagic, so lets tell it to!
13
+ Bacon.summary_on_exit
14
+
15
+ require File.expand_path(
16
+ File.join(File.dirname(__FILE__), %w[.. lib win32_service_manager]))
17
+
18
+ def Win32ServiceManager.load_dependencies; end
data/spec/runner ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ __DIR__ = File.dirname(__FILE__)
3
+ __APP__ = File.expand_path(__DIR__ + '/../')
4
+
5
+ puts
6
+ Dir.chdir(__APP__) do
7
+ files = ARGV.empty? ? Dir.glob('{test,spec}/**/{test,spec}_*.rb') : ARGV
8
+ files.each { |f| require f }
9
+ end
@@ -0,0 +1,110 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ # Because sometimes, I just wanna spec on another platform...
4
+ module Win32
5
+ module Registry
6
+ HKEY_LOCAL_MACHINE = self
7
+ KEY_WRITE = self
8
+ KEY_READ = self
9
+ def self.method_missing(name, *args)
10
+ self
11
+ end
12
+ end
13
+
14
+ module Service
15
+ WIN32_OWN_PROCESS, DEMAND_START, ERROR_NORMAL, AUTO_START = nil
16
+ class <<self
17
+ attr_accessor :services, :started, :stopped
18
+ end
19
+
20
+ SvcInfo = Struct.new(:name, :host, :options)
21
+ class SvcInfo
22
+ def display_name
23
+ options[:display_name]
24
+ end
25
+ end
26
+
27
+ def self.create(name, host, options)
28
+ @services << SvcInfo.new(name, host, options)
29
+ end
30
+
31
+ def self.delete(name)
32
+ @services.delete_if { |svc| svc.name == name }
33
+ end
34
+
35
+ def self.start(name)
36
+ @started << name
37
+ end
38
+
39
+ def self.stop(name)
40
+ @stopped << name
41
+ end
42
+
43
+ def self.services
44
+ @services
45
+ end
46
+
47
+ def self.list
48
+ @services
49
+ end
50
+
51
+ def self.clear!
52
+ @services, @started, @stopped = [], [], []
53
+ end
54
+ end
55
+ end
56
+
57
+
58
+ describe 'Win32ServiceManager' do
59
+ before do
60
+ @prefix = 'SM_TEST_'
61
+ @sm = Win32ServiceManager.new(@prefix)
62
+ # N.B. this is a mock, setup in helper
63
+ Win32::Service.clear!
64
+ end
65
+
66
+ should 'create services with name prefixes' do
67
+ @sm.create('bar', 'false.exe')
68
+ service_names = Win32::Service.list.select { |obj| obj.display_name }
69
+ service_names.find { |s| s.name == @prefix + 'bar'}
70
+ service_names.size.should.eql(1)
71
+ end
72
+
73
+ should 'delete services' do
74
+ @sm.create('bar', 'false.exe')
75
+ service_names = Win32::Service.list.select { |obj| obj.display_name }
76
+ service_names.find{ |s| s.display_name == @prefix + 'bar' }.should.not.be.nil
77
+ service_names.size.should.eql(1)
78
+ @sm.delete('bar')
79
+ service_names = Win32::Service.list.select { |obj| obj.display_name }
80
+ service_names.should.not.include?(@prefix + 'bar')
81
+ service_names.size.should.eql(0)
82
+ end
83
+
84
+ should 'list services' do
85
+ @sm.create('bar', 'false.exe', 'args', 'descrip')
86
+ @sm.list.find { |s| s[:name] == 'SM_TEST_bar' }.should.not.be.nil
87
+ @sm.list.size.should.eql(Win32::Service.list.size)
88
+ end
89
+ end
90
+
91
+ describe 'ServiceManager service control' do
92
+ before do
93
+ @prefix = 'SM_TEST_'
94
+ @sm = Win32ServiceManager.new(@prefix)
95
+ Win32::Service.clear!
96
+ @name = 'test_service'
97
+ @command = 'foo.exe'
98
+ @sm.create(@name, @command)
99
+ end
100
+
101
+ should 'stop services' do
102
+ @sm.stop(@name)
103
+ Win32::Service.stopped.should.include?(@prefix + @name)
104
+ end
105
+
106
+ should 'start services' do
107
+ @sm.start(@name)
108
+ Win32::Service.started.should.include?(@prefix + @name)
109
+ end
110
+ end
@@ -0,0 +1,33 @@
1
+ # Poor mans autotest, for when you absolutely positively, just need an autotest.
2
+ # N.B. Uses a runner under test/ or spec/, so you can customize the runtime.
3
+ # Thanks to manveru for this!
4
+ desc "Run specs every time a file changes in lib or spec"
5
+ task :autospec do
6
+ rb = Gem.ruby rescue nil
7
+ rb ||= (require 'rbconfig'; File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']))
8
+ command = 'spec/runner' if test ?e, 'spec/runner'
9
+ command ||= 'test/runner' if test ?e, 'test/runner'
10
+ files = Dir.glob('{lib,spec,test}/**/*.rb')
11
+ mtimes = {}
12
+ sigtrap = proc { puts "\rDo that again, I dare you!"; trap(:INT){ exit 0 }; sleep 0.8; trap(:INT, &sigtrap) }
13
+ trap(:INT, &sigtrap)
14
+ system "#{rb} -I#{GSpec.require_path} #{command}"
15
+ while file = files.shift
16
+ begin
17
+ mtime = File.mtime(file)
18
+ mtimes[file] ||= mtime
19
+ if mtime > mtimes[file]
20
+ files = Dir.glob('{lib,spec,test}/**/*.rb') - [file] # refresh the file list.
21
+ puts
22
+ system "#{rb} -I#{GSpec.require_path} #{command} #{file}"
23
+ puts
24
+ end
25
+ mtimes[file] = mtime
26
+ files << file
27
+ rescue Exception
28
+ retry
29
+ end
30
+ # print "\rChecking: #{file.ljust((ENV['COLUMNS']||80)-11)}";$stdout.flush
31
+ sleep 0.2
32
+ end
33
+ end
data/tasks/bacon.rake ADDED
@@ -0,0 +1,7 @@
1
+ desc "Run the executable test specifications"
2
+ task :spec do
3
+ ruby 'spec/runner'
4
+ end
5
+
6
+ desc "Run the executable test specifications"
7
+ task :test => :spec
data/tasks/bones.rake ADDED
@@ -0,0 +1,21 @@
1
+ # $Id$
2
+
3
+ if HAVE_BONES
4
+
5
+ namespace :bones do
6
+
7
+ desc 'Show the PROJ open struct'
8
+ task :debug do |t|
9
+ atr = if t.application.top_level_tasks.length == 2
10
+ t.application.top_level_tasks.pop
11
+ end
12
+
13
+ if atr then Bones::Debug.show_attr(PROJ, atr)
14
+ else Bones::Debug.show PROJ end
15
+ end
16
+
17
+ end # namespace :bones
18
+
19
+ end # HAVE_BONES
20
+
21
+ # EOF
data/tasks/gem.rake ADDED
@@ -0,0 +1,138 @@
1
+ # $Id$
2
+
3
+ require 'rake/gempackagetask'
4
+
5
+ namespace :gem do
6
+
7
+ PROJ.gem._spec = Gem::Specification.new do |s|
8
+ s.name = PROJ.name
9
+ s.version = PROJ.version
10
+ s.summary = PROJ.summary
11
+ s.authors = Array(PROJ.authors)
12
+ s.email = PROJ.email
13
+ s.homepage = Array(PROJ.url).first
14
+ s.rubyforge_project = PROJ.rubyforge.name
15
+
16
+ s.description = PROJ.description
17
+
18
+ PROJ.gem.dependencies.each do |dep|
19
+ s.add_dependency(*dep)
20
+ end
21
+ PROJ.gem.development_dependencies.each do |dep|
22
+ s.add_development_dependency(*dep)
23
+ end
24
+
25
+ s.files = PROJ.gem.files
26
+ s.executables = PROJ.gem.executables.map {|fn| File.basename(fn)}
27
+ s.extensions = PROJ.gem.files.grep %r/extconf\.rb$/
28
+
29
+ s.bindir = 'bin'
30
+ dirs = Dir["{#{PROJ.libs.join(',')}}"]
31
+ s.require_paths = dirs unless dirs.empty?
32
+
33
+ incl = Regexp.new(PROJ.rdoc.include.join('|'))
34
+ excl = PROJ.rdoc.exclude.dup.concat %w[\.rb$ ^(\.\/|\/)?ext]
35
+ excl = Regexp.new(excl.join('|'))
36
+ rdoc_files = PROJ.gem.files.find_all do |fn|
37
+ case fn
38
+ when excl; false
39
+ when incl; true
40
+ else false end
41
+ end
42
+ s.rdoc_options = PROJ.rdoc.opts + ['--main', PROJ.rdoc.main]
43
+ s.extra_rdoc_files = rdoc_files
44
+ s.has_rdoc = true
45
+
46
+ if test ?f, PROJ.test.file
47
+ s.test_file = PROJ.test.file
48
+ else
49
+ s.test_files = PROJ.test.files.to_a
50
+ end
51
+
52
+ # Do any extra stuff the user wants
53
+ PROJ.gem.extras.each do |msg, val|
54
+ case val
55
+ when Proc
56
+ val.call(s.send(msg))
57
+ else
58
+ s.send "#{msg}=", val
59
+ end
60
+ end
61
+ end # Gem::Specification.new
62
+
63
+ # A prerequisites task that all other tasks depend upon
64
+ task :prereqs
65
+
66
+ desc 'Show information about the gem'
67
+ task :debug => 'gem:prereqs' do
68
+ puts PROJ.gem._spec.to_ruby
69
+ end
70
+
71
+ pkg = Rake::PackageTask.new(PROJ.name, PROJ.version) do |pkg|
72
+ pkg.need_tar = PROJ.gem.need_tar
73
+ pkg.need_zip = PROJ.gem.need_zip
74
+ pkg.package_files += PROJ.gem._spec.files
75
+ end
76
+ Rake::Task['gem:package'].instance_variable_set(:@full_comment, nil)
77
+
78
+ gem_file = if PROJ.gem._spec.platform == Gem::Platform::RUBY
79
+ "#{pkg.package_name}.gem"
80
+ else
81
+ "#{pkg.package_name}-#{PROJ.gem._spec.platform}.gem"
82
+ end
83
+
84
+ desc "Build the gem file #{gem_file}"
85
+ task :package => ['gem:prereqs', "#{pkg.package_dir}/#{gem_file}"]
86
+
87
+ file "#{pkg.package_dir}/#{gem_file}" => [pkg.package_dir] + PROJ.gem._spec.files do
88
+ when_writing("Creating GEM") {
89
+ Gem::Builder.new(PROJ.gem._spec).build
90
+ verbose(true) {
91
+ mv gem_file, "#{pkg.package_dir}/#{gem_file}"
92
+ }
93
+ }
94
+ end
95
+
96
+ desc 'Install the gem'
97
+ task :install => [:clobber, 'gem:package'] do
98
+ sh "#{SUDO} #{GEM} install --local pkg/#{PROJ.gem._spec.full_name}"
99
+
100
+ # use this version of the command for rubygems > 1.0.0
101
+ #sh "#{SUDO} #{GEM} install --no-update-sources pkg/#{PROJ.gem._spec.full_name}"
102
+ end
103
+
104
+ desc 'Uninstall the gem'
105
+ task :uninstall do
106
+ installed_list = Gem.source_index.find_name(PROJ.name)
107
+ if installed_list and installed_list.collect { |s| s.version.to_s}.include?(PROJ.version) then
108
+ sh "#{SUDO} #{GEM} uninstall --version '#{PROJ.version}' --ignore-dependencies --executables #{PROJ.name}"
109
+ end
110
+ end
111
+
112
+ desc 'Reinstall the gem'
113
+ task :reinstall => [:uninstall, :install]
114
+
115
+ desc 'Cleanup the gem'
116
+ task :cleanup do
117
+ sh "#{SUDO} #{GEM} cleanup #{PROJ.gem._spec.name}"
118
+ end
119
+
120
+ file "#{PROJ.name}.gemspec" => PROJ.gem._spec.files do |t|
121
+ open(t.name, 'w') { |f| f.write PROJ.gem._spec.to_ruby }
122
+ end
123
+ CLOBBER.include("#{PROJ.name}.gemspec")
124
+
125
+ desc 'Generate gemspec'
126
+ task :spec => "#{PROJ.name}.gemspec"
127
+ task :release => :spec
128
+
129
+ end # namespace :gem
130
+
131
+ desc 'Alias to gem:package'
132
+ task :gem => 'gem:package'
133
+
134
+ task :clobber => 'gem:clobber_package'
135
+
136
+ remove_desc_for_task %w(gem:clobber_package)
137
+
138
+ # EOF
data/tasks/git.rake ADDED
@@ -0,0 +1,41 @@
1
+ # $Id$
2
+
3
+ if HAVE_GIT
4
+
5
+ namespace :git do
6
+
7
+ # A prerequisites task that all other tasks depend upon
8
+ task :prereqs
9
+
10
+ desc 'Show tags from the Git repository'
11
+ task :show_tags => 'git:prereqs' do |t|
12
+ puts %x/git tag/
13
+ end
14
+
15
+ desc 'Create a new tag in the Git repository'
16
+ task :create_tag => 'git:prereqs' do |t|
17
+ v = ENV['VERSION'] or abort 'Must supply VERSION=x.y.z'
18
+ abort "Versions don't match #{v} vs #{PROJ.version}" if v != PROJ.version
19
+
20
+ tag = "%s-%s" % [PROJ.name, PROJ.version]
21
+ msg = "Creating tag for #{PROJ.name} version #{PROJ.version}"
22
+
23
+ puts "Creating Git tag '#{tag}'"
24
+ unless system "git tag -a -m '#{msg}' #{tag}"
25
+ # abort "Tag creation failed"
26
+ end
27
+
28
+ if %x/git remote/ =~ %r/^origin\s*$/
29
+ unless system "git push origin #{tag}"
30
+ abort "Could not push tag to remote Git repository"
31
+ end
32
+ end
33
+ end
34
+
35
+ end # namespace :git
36
+
37
+ task 'gem:release' => 'git:create_tag'
38
+
39
+ end # if HAVE_GIT
40
+
41
+ # EOF
@@ -0,0 +1,49 @@
1
+ # $Id$
2
+
3
+ require 'find'
4
+
5
+ namespace :manifest do
6
+
7
+ desc 'Verify the manifest'
8
+ task :check do
9
+ fn = PROJ.manifest_file + '.tmp'
10
+ files = manifest_files
11
+
12
+ File.open(fn, 'w') {|fp| fp.puts files}
13
+ lines = %x(#{DIFF} -du #{PROJ.manifest_file} #{fn}).split("\n")
14
+ if HAVE_FACETS_ANSICODE and ENV.has_key?('TERM')
15
+ lines.map! do |line|
16
+ case line
17
+ when %r/^(-{3}|\+{3})/; nil
18
+ when %r/^@/; Console::ANSICode.blue line
19
+ when %r/^\+/; Console::ANSICode.green line
20
+ when %r/^\-/; Console::ANSICode.red line
21
+ else line end
22
+ end
23
+ end
24
+ puts lines.compact
25
+ rm fn rescue nil
26
+ end
27
+
28
+ desc 'Create a new manifest'
29
+ task :create do
30
+ files = manifest_files
31
+ unless test(?f, PROJ.manifest_file)
32
+ files << PROJ.manifest_file
33
+ files.sort!
34
+ end
35
+ File.open(PROJ.manifest_file, 'w') {|fp| fp.puts files}
36
+ end
37
+
38
+ task :assert do
39
+ files = manifest_files
40
+ manifest = File.read(PROJ.manifest_file).split($/)
41
+ raise "ERROR: #{PROJ.manifest_file} is out of date" unless files == manifest
42
+ end
43
+
44
+ end # namespace :manifest
45
+
46
+ desc 'Alias to manifest:check'
47
+ task :manifest => 'manifest:check'
48
+
49
+ # EOF
data/tasks/notes.rake ADDED
@@ -0,0 +1,28 @@
1
+ # $Id$
2
+
3
+ if HAVE_BONES
4
+
5
+ desc "Enumerate all annotations"
6
+ task :notes do |t|
7
+ id = if t.application.top_level_tasks.length > 1
8
+ t.application.top_level_tasks.slice!(1..-1).join(' ')
9
+ end
10
+ Bones::AnnotationExtractor.enumerate(
11
+ PROJ, PROJ.notes.tags.join('|'), id, :tag => true)
12
+ end
13
+
14
+ namespace :notes do
15
+ PROJ.notes.tags.each do |tag|
16
+ desc "Enumerate all #{tag} annotations"
17
+ task tag.downcase.to_sym do |t|
18
+ id = if t.application.top_level_tasks.length > 1
19
+ t.application.top_level_tasks.slice!(1..-1).join(' ')
20
+ end
21
+ Bones::AnnotationExtractor.enumerate(PROJ, tag, id)
22
+ end
23
+ end
24
+ end
25
+
26
+ end # if HAVE_BONES
27
+
28
+ # EOF
@@ -0,0 +1,39 @@
1
+ # $Id$
2
+
3
+ # This file does not define any rake tasks. It is used to load some project
4
+ # settings if they are not defined by the user.
5
+
6
+ PROJ.rdoc.main ||= PROJ.readme_file
7
+ PROJ.rdoc.dir ||= File.join('doc', PROJ.name)
8
+
9
+ PROJ.rdoc.exclude << "^#{Regexp.escape(PROJ.manifest_file)}$"
10
+ PROJ.exclude << ["^#{Regexp.escape(PROJ.rdoc.dir)}/",
11
+ "^#{Regexp.escape(PROJ.rcov.dir)}/"]
12
+
13
+ flatten_arrays = lambda do |this,os|
14
+ os.instance_variable_get(:@table).each do |key,val|
15
+ next if key == :dependencies
16
+ case val
17
+ when Array; val.flatten!
18
+ when OpenStruct; this.call(this,val)
19
+ end
20
+ end
21
+ end
22
+ flatten_arrays.call(flatten_arrays,PROJ)
23
+
24
+ PROJ.changes ||= paragraphs_of(PROJ.history_file, 0..1).join("\n\n")
25
+
26
+ PROJ.description ||= paragraphs_of(PROJ.readme_file, 'description').join("\n\n")
27
+
28
+ PROJ.summary ||= PROJ.description.split('.').first
29
+
30
+ PROJ.gem.files ||=
31
+ if test(?f, PROJ.manifest_file)
32
+ files = File.readlines(PROJ.manifest_file).map {|fn| fn.chomp.strip}
33
+ files.delete ''
34
+ files
35
+ else [] end
36
+
37
+ PROJ.gem.executables ||= PROJ.gem.files.find_all {|fn| fn =~ %r/^bin/}
38
+
39
+ # EOF
data/tasks/rdoc.rake ADDED
@@ -0,0 +1,55 @@
1
+ # $Id$
2
+
3
+ begin
4
+ require 'hanna/rdoctask'
5
+ rescue LoadError
6
+ require 'rake/rdoctask'
7
+ end
8
+
9
+ namespace :doc do
10
+
11
+ desc 'Generate RDoc documentation'
12
+ Rake::RDocTask.new do |rd|
13
+ rdoc = PROJ.rdoc
14
+ rd.main = rdoc.main
15
+ rd.rdoc_dir = rdoc.dir
16
+
17
+ incl = Regexp.new(rdoc.include.join('|'))
18
+ excl = Regexp.new(rdoc.exclude.join('|'))
19
+ files = PROJ.gem.files.find_all do |fn|
20
+ case fn
21
+ when excl; false
22
+ when incl; true
23
+ else false end
24
+ end
25
+ rd.rdoc_files.push(*files)
26
+
27
+ title = "#{PROJ.name}-#{PROJ.version} Documentation"
28
+
29
+ rf_name = PROJ.rubyforge.name
30
+ title = "#{rf_name}'s " + title if rf_name.valid? and rf_name != title
31
+
32
+ rd.options << "-t #{title}"
33
+ rd.options.concat(rdoc.opts)
34
+ end
35
+
36
+ desc 'Generate ri locally for testing'
37
+ task :ri => :clobber_ri do
38
+ sh "#{RDOC} --ri -o ri ."
39
+ end
40
+
41
+ task :clobber_ri do
42
+ rm_r 'ri' rescue nil
43
+ end
44
+
45
+ end # namespace :doc
46
+
47
+ desc 'Alias to doc:rdoc'
48
+ task :doc => 'doc:rdoc'
49
+
50
+ desc 'Remove all build products'
51
+ task :clobber => %w(doc:clobber_rdoc doc:clobber_ri)
52
+
53
+ remove_desc_for_task %w(doc:clobber_rdoc)
54
+
55
+ # EOF
@@ -0,0 +1,57 @@
1
+
2
+ if PROJ.rubyforge.name.valid? && HAVE_RUBYFORGE
3
+
4
+ require 'rubyforge'
5
+ require 'rake/contrib/sshpublisher'
6
+
7
+ namespace :gem do
8
+ desc 'Package and upload to RubyForge'
9
+ task :release => [:clobber, 'gem:package'] do |t|
10
+ v = ENV['VERSION'] or abort 'Must supply VERSION=x.y.z'
11
+ abort "Versions don't match #{v} vs #{PROJ.version}" if v != PROJ.version
12
+ pkg = "pkg/#{PROJ.gem._spec.full_name}"
13
+
14
+ if $DEBUG then
15
+ puts "release_id = rf.add_release #{PROJ.rubyforge.name.inspect}, #{PROJ.name.inspect}, #{PROJ.version.inspect}, \"#{pkg}.tgz\""
16
+ puts "rf.add_file #{PROJ.rubyforge.name.inspect}, #{PROJ.name.inspect}, release_id, \"#{pkg}.gem\""
17
+ end
18
+
19
+ rf = RubyForge.new
20
+ rf.configure rescue nil
21
+ puts 'Logging in'
22
+ rf.login
23
+
24
+ c = rf.userconfig
25
+ c['release_notes'] = PROJ.description if PROJ.description
26
+ c['release_changes'] = PROJ.changes if PROJ.changes
27
+ c['preformatted'] = true
28
+
29
+ files = [(PROJ.gem.need_tar ? "#{pkg}.tgz" : nil),
30
+ (PROJ.gem.need_zip ? "#{pkg}.zip" : nil),
31
+ "#{pkg}.gem"].compact
32
+
33
+ puts "Releasing #{PROJ.name} v. #{PROJ.version}"
34
+ rf.add_release PROJ.rubyforge.name, PROJ.name, PROJ.version, *files
35
+ end
36
+ end # namespace :gem
37
+
38
+
39
+ namespace :doc do
40
+ desc "Publish RDoc to RubyForge"
41
+ task :release => %w(doc:clobber_rdoc doc:rdoc) do
42
+ config = YAML.load(
43
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
44
+ )
45
+
46
+ host = "#{config['username']}@rubyforge.org"
47
+ remote_dir = "/var/www/gforge-projects/#{PROJ.rubyforge.name}/"
48
+ remote_dir << PROJ.rdoc.remote_dir if PROJ.rdoc.remote_dir
49
+ local_dir = File.dirname(PROJ.rdoc.dir)
50
+
51
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
52
+ end
53
+ end # namespace :doc
54
+
55
+ end # if HAVE_RUBYFORGE
56
+
57
+ # EOF
data/tasks/setup.rb ADDED
@@ -0,0 +1,238 @@
1
+ # $Id$
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/clean'
6
+ require 'fileutils'
7
+ require 'ostruct'
8
+
9
+ class OpenStruct; undef :gem; end
10
+
11
+ PROJ = OpenStruct.new(
12
+ # Project Defaults
13
+ :name => nil,
14
+ :summary => nil,
15
+ :description => nil,
16
+ :changes => nil,
17
+ :authors => nil,
18
+ :email => nil,
19
+ :url => "\000",
20
+ :version => ENV['VERSION'] || '0.0.0',
21
+ :exclude => %w(tmp$ bak$ ~$ CVS \.git/ \.hg/ \.svn/ ^pkg/ ^doc/ \.DS_Store
22
+ \.hgignore \.gitignore \.dotest \.swp$ .*\.gemspec$),
23
+ :release_name => ENV['RELEASE'],
24
+
25
+ # System Defaults
26
+ :ruby_opts => %w(-w),
27
+ :libs => [],
28
+ :history_file => 'History.txt',
29
+ :manifest_file => 'Manifest.txt',
30
+ :readme_file => 'README.rdoc',
31
+
32
+ # Gem Packaging
33
+ :gem => OpenStruct.new(
34
+ :dependencies => [],
35
+ :development_dependencies => ['rake', 'bones', 'bacon'],
36
+ :executables => nil,
37
+ :extensions => FileList['ext/**/extconf.rb'],
38
+ :files => nil,
39
+ :need_tar => true,
40
+ :need_zip => false,
41
+ :extras => {}
42
+ ),
43
+
44
+ # File Annotations
45
+ :notes => OpenStruct.new(
46
+ :exclude => %w(^tasks/setup\.rb$),
47
+ :extensions => %w(.txt .rb .erb .rdoc) << '',
48
+ :tags => %w(FIXME OPTIMIZE TODO)
49
+ ),
50
+
51
+ # Rcov
52
+ :rcov => OpenStruct.new(
53
+ :dir => 'coverage',
54
+ :opts => %w[--sort coverage -T],
55
+ :threshold => 90.0,
56
+ :threshold_exact => false
57
+ ),
58
+
59
+ # Rdoc
60
+ :rdoc => OpenStruct.new(
61
+ :opts => [],
62
+ :include => %w(^lib/ ^bin/ ^ext/ \.txt$ \.rdoc$),
63
+ :exclude => %w(extconf\.rb$),
64
+ :main => nil,
65
+ :dir => nil,
66
+ :remote_dir => nil
67
+ ),
68
+
69
+ # Rubyforge
70
+ :rubyforge => OpenStruct.new(
71
+ :name => "\000"
72
+ ),
73
+
74
+ # Tests
75
+ :test => OpenStruct.new(
76
+ :files => FileList['{test,spec}/{{test,spec}_*.rb,*_spec.rb}'],
77
+ :file => '',
78
+ :opts => []
79
+ )
80
+ )
81
+
82
+ # Load the other rake files in the tasks folder
83
+ rakefiles = Dir.glob('tasks/*.rake').sort
84
+ rakefiles.unshift(rakefiles.delete('tasks/post_load.rake')).compact!
85
+ import(*rakefiles)
86
+
87
+ # Setup the project libraries
88
+ %w(lib ext).each {|dir| PROJ.libs << dir if test ?d, dir}
89
+
90
+ # Setup some constants
91
+ WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WIN32
92
+
93
+ DEV_NULL = WIN32 ? 'NUL:' : '/dev/null'
94
+
95
+ def quiet( &block )
96
+ io = [STDOUT.dup, STDERR.dup]
97
+ STDOUT.reopen DEV_NULL
98
+ STDERR.reopen DEV_NULL
99
+ block.call
100
+ ensure
101
+ STDOUT.reopen io.first
102
+ STDERR.reopen io.last
103
+ $stdout, $stderr = STDOUT, STDERR
104
+ end
105
+
106
+ DIFF = if WIN32 then 'diff.exe'
107
+ else
108
+ if quiet {system "gdiff", __FILE__, __FILE__} then 'gdiff'
109
+ else 'diff' end
110
+ end unless defined? DIFF
111
+
112
+ SUDO = if WIN32 then ''
113
+ else
114
+ if quiet {system 'which sudo'} then 'sudo'
115
+ else '' end
116
+ end
117
+
118
+ RCOV = WIN32 ? 'rcov.bat' : 'rcov'
119
+ RDOC = WIN32 ? 'rdoc.bat' : 'rdoc'
120
+ GEM = WIN32 ? 'gem.bat' : 'gem'
121
+
122
+ %w(rcov spec/rake/spectask rubyforge bones facets/ansicode).each do |lib|
123
+ begin
124
+ require lib
125
+ Object.instance_eval {const_set "HAVE_#{lib.tr('/','_').upcase}", true}
126
+ rescue LoadError
127
+ Object.instance_eval {const_set "HAVE_#{lib.tr('/','_').upcase}", false}
128
+ end
129
+ end
130
+ HAVE_SVN = (Dir.entries(Dir.pwd).include?('.svn') and
131
+ system("svn --version 2>&1 > #{DEV_NULL}"))
132
+ HAVE_GIT = (Dir.entries(Dir.pwd).include?('.git') and
133
+ system("git --version 2>&1 > #{DEV_NULL}"))
134
+
135
+ # Reads a file at +path+ and spits out an array of the +paragraphs+
136
+ # specified.
137
+ #
138
+ # changes = paragraphs_of('History.txt', 0..1).join("\n\n")
139
+ # summary, *description = paragraphs_of('README.rdoc', 3, 3..8)
140
+ #
141
+ def paragraphs_of( path, *paragraphs )
142
+ title = String === paragraphs.first ? paragraphs.shift : nil
143
+ ary = File.read(path).delete("\r").split(/\n\n+/)
144
+
145
+ result = if title
146
+ tmp, matching = [], false
147
+ rgxp = %r/^=+\s*#{Regexp.escape(title)}/i
148
+ paragraphs << (0..-1) if paragraphs.empty?
149
+
150
+ ary.each do |val|
151
+ if val =~ rgxp
152
+ break if matching
153
+ matching = true
154
+ rgxp = %r/^=+/i
155
+ elsif matching
156
+ tmp << val
157
+ end
158
+ end
159
+ tmp
160
+ else ary end
161
+
162
+ result.values_at(*paragraphs)
163
+ end
164
+
165
+ # Adds the given gem _name_ to the current project's dependency list. An
166
+ # optional gem _version_ can be given. If omitted, the newest gem version
167
+ # will be used.
168
+ #
169
+ def depend_on( name, version = nil )
170
+ spec = Gem.source_index.find_name(name).last
171
+ version = spec.version.to_s if version.nil? and !spec.nil?
172
+
173
+ PROJ.gem.dependencies << case version
174
+ when nil; [name]
175
+ when %r/^\d/; [name, ">= #{version}"]
176
+ else [name, version] end
177
+ end
178
+
179
+ # Adds the given arguments to the include path if they are not already there
180
+ #
181
+ def ensure_in_path( *args )
182
+ args.each do |path|
183
+ path = File.expand_path(path)
184
+ $:.unshift(path) if test(?d, path) and not $:.include?(path)
185
+ end
186
+ end
187
+
188
+ # Find a rake task using the task name and remove any description text. This
189
+ # will prevent the task from being displayed in the list of available tasks.
190
+ #
191
+ def remove_desc_for_task( names )
192
+ Array(names).each do |task_name|
193
+ task = Rake.application.tasks.find {|t| t.name == task_name}
194
+ next if task.nil?
195
+ task.instance_variable_set :@comment, nil
196
+ end
197
+ end
198
+
199
+ # Change working directories to _dir_, call the _block_ of code, and then
200
+ # change back to the original working directory (the current directory when
201
+ # this method was called).
202
+ #
203
+ def in_directory( dir, &block )
204
+ curdir = pwd
205
+ begin
206
+ cd dir
207
+ return block.call
208
+ ensure
209
+ cd curdir
210
+ end
211
+ end
212
+
213
+ # Scans the current working directory and creates a list of files that are
214
+ # candidates to be in the manifest.
215
+ #
216
+ def manifest_files
217
+ files = []
218
+ exclude = Regexp.new(PROJ.exclude.join('|'))
219
+ Find.find '.' do |path|
220
+ path.sub! %r/^(\.\/|\/)/o, ''
221
+ next unless test ?f, path
222
+ next if path =~ exclude
223
+ files << path
224
+ end
225
+ files.sort!
226
+ end
227
+
228
+ # We need a "valid" method thtat determines if a string is suitable for use
229
+ # in the gem specification.
230
+ #
231
+ class Object
232
+ def valid?
233
+ return !(self.empty? or self == "\000") if self.respond_to?(:to_str)
234
+ return false
235
+ end
236
+ end
237
+
238
+ # EOF
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: win32_service_manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - James Tucker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-09 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: bones
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: bacon
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: A simple wrapper around Win32::Service to present a more 'God' (http://god.rubyforge.org) like interface. Also presents all service information as hashes rather than structs to save on wire transport and multi-platform complexity.
46
+ email: raggi@rubyforge.org
47
+ executables:
48
+ - win32_service_manager
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - History.txt
53
+ - README.rdoc
54
+ - bin/win32_service_manager
55
+ files:
56
+ - History.txt
57
+ - Manifest.txt
58
+ - README.rdoc
59
+ - Rakefile
60
+ - bin/win32_service_manager
61
+ - lib/win32_service_manager.rb
62
+ - spec/helper.rb
63
+ - spec/runner
64
+ - spec/spec_win32_service_manager.rb
65
+ - tasks/autospec.rake
66
+ - tasks/bacon.rake
67
+ - tasks/bones.rake
68
+ - tasks/gem.rake
69
+ - tasks/git.rake
70
+ - tasks/manifest.rake
71
+ - tasks/notes.rake
72
+ - tasks/post_load.rake
73
+ - tasks/rdoc.rake
74
+ - tasks/rubyforge.rake
75
+ - tasks/setup.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/raggi/win32_service_manager
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --main
81
+ - README.rdoc
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project: libraggi
99
+ rubygems_version: 1.3.1
100
+ signing_key:
101
+ specification_version: 2
102
+ summary: A simple wrapper around Win32::Service to present a more 'God' (http://god
103
+ test_files:
104
+ - spec/spec_win32_service_manager.rb