Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 9322fdfba67f8e601fc0d2f103b68b412b03544a @raggi committed Jan 16, 2009
Showing with 1,133 additions and 0 deletions.
  1. +4 −0 History.txt
  2. +21 −0 Manifest.txt
  3. +88 −0 README.txt
  4. +16 −0 Rakefile
  5. +106 −0 lib/rubyw_helper.rb
  6. 0 spec/.bacon
  7. +16 −0 spec/helper.rb
  8. +9 −0 spec/runner
  9. +70 −0 spec/spec_rubyw_helper.rb
  10. +81 −0 tasks/ann.rake
  11. +33 −0 tasks/autospec.rake
  12. +5 −0 tasks/bacon.rake
  13. +21 −0 tasks/bones.rake
  14. +126 −0 tasks/gem.rake
  15. +41 −0 tasks/git.rake
  16. +49 −0 tasks/manifest.rake
  17. +28 −0 tasks/notes.rake
  18. +39 −0 tasks/post_load.rake
  19. +55 −0 tasks/rdoc.rake
  20. +57 −0 tasks/rubyforge.rake
  21. +268 −0 tasks/setup.rb
@@ -0,0 +1,4 @@
+== 0.1.0 / 2008-12-24
+
+* 1 major enhancement
+ * Birthday!
@@ -0,0 +1,21 @@
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+lib/rubyw_helper.rb
+spec/.bacon
+spec/helper.rb
+spec/runner
+spec/spec_rubyw_helper.rb
+tasks/ann.rake
+tasks/autospec.rake
+tasks/bacon.rake
+tasks/bones.rake
+tasks/gem.rake
+tasks/git.rake
+tasks/manifest.rake
+tasks/notes.rake
+tasks/post_load.rake
+tasks/rdoc.rake
+tasks/rubyforge.rake
+tasks/setup.rb
@@ -0,0 +1,88 @@
+rubyw_helper
+ by James Tucker
+ http://ra66i.org
+ http://github.com/raggi/rubyw_helper
+
+== DESCRIPTION:
+
+A simple redirector for use when you just want to safely redirect stdio.
+Simply encapsulates a few different safety mechanisms when redirecting stdio,
+with the primary goal of making it easier to write apps that run under
+rubyw.exe, where ruby loads with stdio closed.
+
+Whilst the primary intention for use is under win32, and was actually
+developed as an external helper for specifically win32-service usage, this gem
+may be useful to some other folks on other platforms. It is not win32
+specific.
+
+== FEATURES/PROBLEMS:
+
+* Lacking any tertiary logging infrastructure specific to any platform.
+
+== SYNOPSIS:
+
+The following parameters are also the defaults:
+
+ stdout = File.join(Dir.pwd, 'logs', "#{app_name}.stdout.log"),
+ stderr = File.join(Dir.pwd, 'logs', "#{app_name}.stderr.log")
+ stdin = case RUBY_PLATFORM
+ when /mingw|mswin/
+ 'NUL:'
+ else
+ '/dev/null'
+ end
+
+ helper = RubywHelper.new(stdout, stderr, stdin)
+
+You achieve basic redirection if you wrap your runner for your program in the
+with_redirection block:
+
+ helper.with_redirection do
+ puts "hello logfile!"
+ end
+
+Or you can simply just redirect them:
+
+ helper.redirect_stdio!
+
+For your convenience, there is also a method which attempts to see if it may
+be a good idea to redirect stdio, in other words, it returns true if all of
+stdio is closed:
+
+ helper.stdio_danger?
+
+This typically returns true under rubyw.exe and any equivalents.
+
+== REQUIREMENTS:
+
+* Ruby
+* gem inst exception_string
+
+== INSTALL:
+
+* gem inst rubyw_helper
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2008 James Tucker
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,16 @@
+load 'tasks/setup.rb'
+
+ensure_in_path 'lib'
+require 'rubyw_helper'
+
+task :default => 'spec:run'
+
+PROJ.name = 'rubyw_helper'
+PROJ.authors = 'James Tucker'
+PROJ.email = 'raggi@rubyforge.org'
+PROJ.url = 'http://github.com/raggi/rubyw_helper'
+PROJ.rubyforge.name = 'raggi'
+PROJ.version = RubywHelper.version
+
+PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.git \.hg \.svn ^pkg ^doc \.DS_Store \.cvs
+ \.svn \.hgignore \.gitignore \.dotest \.swp$ ~$ \.bin$ \.h$ \.rc$ \.res$)
@@ -0,0 +1,106 @@
+require 'fileutils'
+require 'exception_string'
+
+class RubywHelper
+
+ Version = VERSION = '0.1.0'
+ def self.version; Version; end
+
+ app_name = File.basename($0)
+ Defaults = {
+ :out => File.join(Dir.pwd, 'logs', "#{app_name}.stdout.log"),
+ :err => File.join(Dir.pwd, 'logs', "#{app_name}.stderr.log"),
+ :in => case RUBY_PLATFORM
+ when /mingw|mswin/
+ 'NUL:'
+ else
+ '/dev/null'
+ end
+ }
+
+ attr_reader :old_out, :old_err, :old_in
+
+ # out replaces $stdout, err replaces $stderr, inn replaces $stdin, simple.
+ # provide nils / false to use the Defaults
+ def initialize(out = nil, err = nil, inn = nil)
+ @stdout, @stderr = out || Defaults[:out], err || Defaults[:err]
+ @stdin = inn || Defaults[:in]
+ @old_out, @old_err, @old_in = $stdout, $stderr, $stdin
+ end
+
+ def stdio_danger?
+ $stdout.closed? && $stderr.closed? && $stdin.closed?
+ end
+
+ # Takes a block, because under these conditions, it really helps developers
+ # if best effort is made to try and log error conditions to the files before
+ # leaving the process.
+ def with_redirection
+ ensure_files!
+ redirect_stdio!
+ yield
+ restore_stdio!
+ rescue Exception => exception
+ fatal! exception.to_s_mri
+ end
+
+ # Sets up the global IO objects to point to where we want.
+ def redirect_stdio!
+ inn, out, err = open(@stdin), open(@stdout, 'a+'), open(@stderr, 'a+')
+ no_warn do
+ $stdin = Object.const_set(:STDIN, inn)
+ $stdout = Object.const_set(:STDOUT, out)
+ $stderr = Object.const_set(:STDERR, err)
+ end
+ end
+
+ def restore_stdio!
+ no_warn do
+ $stdin = Object.const_set(:STDIN, @old_in)
+ $stdout = Object.const_set(:STDOUT, @old_out)
+ $stderr = Object.const_set(:STDERR, @old_err)
+ end
+ end
+
+ private
+ # Tries to create any containing directories, and errors out if we can't
+ # write to the outputs or read from the input.
+ def ensure_files!
+ fatal! "Cannot read from #{@stdin}" unless File.readable? @stdin
+ [@stdout, @stderr].each do |f|
+ dir = File.dirname(f)
+ safely { FileUtils.mkdir_p(dir) unless File.directory?(dir) }
+ next if File.writable? f
+ fatal! "Cannot write to #{f}"
+ end
+ end
+
+ # For each output io, safely wrap the given block, and yield the io.
+ def safe_each
+ [$stderr, $stdout].each { |io| safely { yield io } }
+ end
+
+ # Tries real hard to log the message, then exits with failure status.
+ def fatal!(message)
+ # Not using safe_each in case that caused an error.
+ safely { $stdout.reopen(@stdout, 'a+'); $stdout.puts message }
+ safely { $stderr.reopen(@stderr, 'a+'); $stderr.puts message }
+ exit 1
+ end
+
+ # Ignores errors, which we might not be able to avoid.
+ def safely
+ yield
+ rescue Exception
+ nil
+ end
+
+ # Suppress warnings, most useful for constant redefinition.
+ def no_warn
+ verbose = $VERBOSE
+ $VERBOSE = nil
+ yield
+ ensure
+ $VERBOSE = verbose
+ end
+end
No changes.
@@ -0,0 +1,16 @@
+# Disable test/unit and rspec from running, in case loaded by broken tools.
+Test::Unit.run = false if defined?(Test) && defined?(Test::Unit)
+Spec::run = false if defined?(Spec) && Spec::respond_to?(:run=)
+
+# Setup a nice testing environment
+$DEBUG, $TESTING = true, true
+$:.push File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
+$:.uniq!
+
+%w[rubygems bacon].each { |r| require r }
+
+# Bacon doesn't do any automagic, so lets tell it to!
+Bacon.summary_on_exit
+
+require File.expand_path(
+ File.join(File.dirname(__FILE__), %w[.. lib rubyw_helper]))
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+__DIR__ = File.dirname(__FILE__)
+__APP__ = File.expand_path(__DIR__ + '/../')
+
+puts
+Dir.chdir(__APP__) do
+ files = ARGV.empty? ? Dir.glob('{test,spec}/**/{test,spec}_*.rb') : ARGV
+ files.each { |f| require f }
+end
@@ -0,0 +1,70 @@
+require File.dirname(__FILE__) + '/helper'
+require 'stringio'
+require 'tempfile'
+
+describe "RubywHelper" do
+
+ def temp_io
+ stdin = case RUBY_PLATFORM
+ when /mingw|mswin/
+ 'NUL:'
+ else
+ '/dev/null'
+ end
+ tmp_io = %W(
+ /tmp/rubyw_helper_test_stdout.log
+ /tmp/rubyw_helper_test_stderr.log
+ )
+ tmp_io.each { |f| open(f, 'w') {} }
+ yield tmp_io + [stdin]
+ ensure
+ tmp_io.each { |f| File.delete(f) }
+ end
+
+ should "have stdio_danger? when stdout, stderr, and stdin are closed" do
+ $stdout, $stderr, $stdin = Array.new(3) { s = StringIO.new(''); s.close; s }
+ RubywHelper.new.stdio_danger?.should.eql true
+ $stdout, $stderr, $stdin = STDOUT, STDERR, STDIN
+ end
+
+ should "restore the old stdios" do
+ oout, oerr, oin = $stdout, $stderr, $stdin
+ h = RubywHelper.new
+ $stdout, $stderr, $stdin = Array.new(3) do
+ s = StringIO.new('')
+ s.close
+ s
+ end
+ h.restore_stdio!
+ $stdout.should.eql oout
+ $stderr.should.eql oerr
+ $stdin.should.eql oin
+ end
+
+ should "redirect to the appropriate files and restore stdio afterward" do
+ oout, oerr, oin = $stdout, $stderr, $stdin
+ temp_io do |out, err, inn|
+ h = RubywHelper.new(out, err, inn)
+ h.with_redirection do
+ $stdout.path.should.eql out
+ $stderr.path.should.eql err
+ $stdin.path.should.eql inn
+ STDOUT.path.should.eql out
+ STDERR.path.should.eql err
+ STDIN.path.should.eql inn
+ $stdout.puts "1234567890"
+ $stderr.puts "1234567890"
+ [$stdin, $stderr, $stdout].each { |io| io.close unless io.closed? }
+ end
+ $stdout.should.eql oout
+ $stderr.should.eql oerr
+ $stdin.should.eql oin
+ STDOUT.should.eql oout
+ STDERR.should.eql oerr
+ STDIN.should.eql oin
+ File.read(out).should.eql("1234567890\n")
+ File.read(err).should.eql("1234567890\n")
+ end
+ end
+
+end
Oops, something went wrong.

0 comments on commit 9322fdf

Please sign in to comment.