├── work ├── deprecated │ ├── meta │ │ ├── version │ │ ├── name │ │ ├── authors │ │ ├── summary │ │ └── description │ ├── scripts │ │ ├── txt2html │ │ ├── makemanifest.rb │ │ └── lib-txt2html.rb │ ├── Changes.txt │ ├── Rakefile │ ├── default_task.rb │ ├── lookup.rb │ └── setup.rb ├── autoreload.rb └── consider │ └── autoreload.rb ├── .gitignore ├── lib ├── autoreload │ ├── version.rb │ └── reloader.rb └── autoreload.rb ├── try ├── changeme.rb └── tryme.rb ├── .yardopts ├── .travis.yml ├── Gemfile ├── Rakefile ├── Manifest.txt ├── spec ├── helper.rb ├── autoreload_spec.rb └── require_spec.rb ├── Assembly ├── Index.rb ├── .index ├── LICENSE.md ├── README.md ├── HISTORY.md └── autoreload.gemspec /work/deprecated/meta/version: -------------------------------------------------------------------------------- 1 | 0.2.0 2 | -------------------------------------------------------------------------------- /work/deprecated/meta/name: -------------------------------------------------------------------------------- 1 | autoreload 2 | -------------------------------------------------------------------------------- /work/deprecated/meta/authors: -------------------------------------------------------------------------------- 1 | Kouichirou Eto 2 | Thomas Sawyer 3 | -------------------------------------------------------------------------------- /work/deprecated/meta/summary: -------------------------------------------------------------------------------- 1 | Automatically reload library files. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .reap/digest 2 | .rdoc 3 | .yardoc 4 | log 5 | pkg 6 | tmp 7 | doc 8 | web 9 | *.gem 10 | -------------------------------------------------------------------------------- /lib/autoreload/version.rb: -------------------------------------------------------------------------------- 1 | module AutoReload 2 | # Public: Current release version. 3 | VERSION = '1.2.0' 4 | end 5 | -------------------------------------------------------------------------------- /try/changeme.rb: -------------------------------------------------------------------------------- 1 | # Change this file while `tryme.rb' is running. 2 | 3 | def message 4 | "Change Me!" 5 | end 6 | 7 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title AutoReload 2 | --readme README.rdoc 3 | --plugin tomdoc 4 | --private 5 | --protected 6 | lib/ 7 | - 8 | [A-Z]*.* 9 | 10 | -------------------------------------------------------------------------------- /work/deprecated/meta/description: -------------------------------------------------------------------------------- 1 | Autoreload automatically reloads library files when they have been 2 | updated. It is especailly useful when testing stateless services 3 | such as web applications. 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | script: "bundle exec rake test" 4 | rvm: 5 | - 1.9.3 6 | - 2.0.0 7 | - 2.1.1 8 | - rbx 9 | - jruby 10 | matrix: 11 | allow_failures: 12 | - rvm: rbx 13 | cache: bundler 14 | 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | group :development do 4 | #gem 'detroit' 5 | gem 'rake' 6 | end 7 | 8 | group :test do 9 | gem 'minitest' 10 | end 11 | 12 | platforms :rbx do 13 | gem 'psych' # yaml 14 | gem 'rubysl', '~> 2.0' 15 | gem 'minitest' 16 | end 17 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | 3 | task :default => [:test] 4 | 5 | Rake::TestTask.new do |t| 6 | t.libs << "lib" 7 | t.libs << "tmp" 8 | t.test_files = FileList['spec/*_spec.rb'] 9 | t.verbose = false 10 | end 11 | 12 | desc "git pull origin master" 13 | task :pull do 14 | sh "git pull origin master" 15 | end 16 | 17 | -------------------------------------------------------------------------------- /Manifest.txt: -------------------------------------------------------------------------------- 1 | #!mast .index .yardopts bin data demo lib man spec test try [A-Z]*.* 2 | .index 3 | .yardopts 4 | lib/autoreload/reloader.rb 5 | lib/autoreload/version.rb 6 | lib/autoreload.rb 7 | spec/autoreload_spec.rb 8 | spec/helper.rb 9 | spec/require_spec.rb 10 | try/changeme.rb 11 | try/tryme.rb 12 | LICENSE.md 13 | HISTORY.md 14 | README.md 15 | -------------------------------------------------------------------------------- /work/deprecated/scripts/txt2html: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.dirname(__FILE__) + '/../lib/sgl/version.rb' 4 | require 'scripts/lib-txt2html' 5 | 6 | VERS = AutoReload::VERSION::STRING 7 | RUBYFORGE_PROJECT = 'autoreload' # The unix name for your project 8 | DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" 9 | 10 | Txt2Html.main(ARGV) 11 | -------------------------------------------------------------------------------- /try/tryme.rb: -------------------------------------------------------------------------------- 1 | puts "Edit 'changme.rb' while this script is still running." 2 | 3 | __dir__ = File.dirname(__FILE__) 4 | 5 | $LOAD_PATH.unshift(File.join(__dir__, '../lib')) 6 | 7 | library = './' + __dir__ + '/changeme.rb' 8 | 9 | require 'autoreload' 10 | 11 | autoreload(:interval=>1, :verbose=>true) do 12 | require library 13 | end 14 | 15 | loop { 16 | puts message 17 | sleep 1 18 | } 19 | -------------------------------------------------------------------------------- /work/deprecated/scripts/makemanifest.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | base_dir = File.join(File.dirname(__FILE__), "..") 4 | glob_pattern = File.join("**", "*") 5 | exclude_patterns = [ 6 | /^pkg/,/^doc/, 7 | ] 8 | 9 | Dir.chdir(base_dir) 10 | files = Dir.glob(glob_pattern).delete_if do |fname| 11 | File.directory?(fname) or 12 | exclude_patterns.find do |pattern| 13 | pattern =~ fname 14 | end 15 | end 16 | manifest = File.new("Manifest.txt", "w") 17 | manifest.puts files.sort.join("\n") 18 | manifest.close 19 | 20 | puts "Manifest.txt updated" 21 | -------------------------------------------------------------------------------- /spec/helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/spec' 2 | require 'minitest/autorun' 3 | 4 | require 'fileutils' 5 | require 'pathname' 6 | require 'autoreload' 7 | 8 | # Some helper stuff.... 9 | 10 | # create a tmp directory 11 | FileUtils.mkdir('tmp') unless File.exist?('tmp') 12 | 13 | $LOAD_PATH.unshift 'lib' 14 | $LOAD_PATH.unshift 'tmp' 15 | 16 | class Pathname 17 | def write(str) 18 | self.open('w') {|out| 19 | out.puts str 20 | } 21 | end 22 | end 23 | 24 | module AutoReload 25 | class Reloader 26 | public :warn 27 | end 28 | end 29 | 30 | -------------------------------------------------------------------------------- /lib/autoreload.rb: -------------------------------------------------------------------------------- 1 | require 'autoreload/version' 2 | require 'autoreload/reloader' 3 | 4 | # Reload features automatically at given intervals. 5 | # 6 | # options - The Hash options used to refine the reloader (default: {}): 7 | # :interval - Seconds between updates. 8 | # :verbose - True provides reload warning. 9 | # :reprime - Include $0 in reload list. 10 | # 11 | # Returns Thread that's taking care of reload loop. 12 | def autoreload(options={}, &block) 13 | AutoReload::Reloader.start(options, &block) 14 | end 15 | 16 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | email: 3 | mailto : 4 | - ruby-talk@ruby-lang.org 5 | - rubyworks-mailinglist@googlegroups.com 6 | 7 | gem: 8 | active: true 9 | 10 | github: 11 | gh_pages: web 12 | 13 | yard: 14 | yardopts: true 15 | priority: 2 16 | 17 | minitest: 18 | tests : spec/*_spec.rb 19 | loadpath : lib 20 | requires : ~ 21 | active : true 22 | 23 | dnote: 24 | labels: ~ 25 | output: log/DNOTE.rdoc 26 | 27 | vclog: 28 | output: 29 | - log/Changes.rdoc 30 | - log/History.rdoc 31 | 32 | #locat: 33 | # path: lib,test 34 | # output: log/LOCat.html 35 | 36 | -------------------------------------------------------------------------------- /spec/autoreload_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/helper') 2 | 3 | describe "AutoReload" do 4 | 5 | it "should autoreload" do 6 | # create a library 7 | library = Pathname.new('tmp/library.rb') 8 | library.write 'def foo; 1; end' 9 | 10 | # setup the autoreload 11 | autoreload(:interval => 1) do #, :verbose=>true) 12 | require "library" 13 | end 14 | 15 | # check the number 16 | foo.must_equal 1 17 | 18 | # wait is needed for time stamp to not be same with the next file. 19 | sleep 2 20 | 21 | # recreate the file 22 | library.write 'def foo; 2; end' 23 | 24 | # wait again for the autoreload loop to repeat. 25 | sleep 2 26 | 27 | # check the number again 28 | foo.must_equal 2 29 | 30 | # clean up 31 | library.delete 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /spec/require_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/helper') 2 | 3 | describe "AutoReload" do 4 | 5 | it "should autoreload a require of a require" do 6 | library1 = Pathname.new('tmp/library1.rb') 7 | library2 = Pathname.new('tmp/library2.rb') 8 | 9 | library1.write "require 'library2'" 10 | library2.write "def foo; 1; end" 11 | 12 | # setup the autoreload 13 | autoreload(:interval => 1) do #, :verbose=>true) 14 | require "library1" 15 | end 16 | 17 | # check the number 18 | foo.must_equal 1 19 | 20 | # wait is needed for time stamp to not be same with the next file. 21 | sleep 2 22 | 23 | # recreate the file 24 | library2.write "def foo; 2; end" 25 | 26 | # wait again for the autoreload loop to repeat. 27 | sleep 2 28 | 29 | # check the number again 30 | foo.must_equal 2 31 | 32 | # clean up 33 | library2.delete 34 | library1.delete 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /Index.rb: -------------------------------------------------------------------------------- 1 | #!usr/bin/env ruby 2 | 3 | require File.dirname(__FILE__) + '/lib/autoreload/version' 4 | 5 | version AutoReload::VERSION 6 | 7 | name 'autoreload' 8 | title 'AutoReload' 9 | summary 'Automatically reload library files' 10 | 11 | description 'Autoreload automatically reloads library files when they have been ' + 12 | 'updated. It is especially useful when testing stateless services ' + 13 | 'such as web applications.' 14 | 15 | authors 'Thomas Sawyer ', 16 | 'Kouichirou Eto' 17 | 18 | resources 'home' => 'http://rubyworks.github.com/autoreload', 19 | 'code' => 'http://github.com/rubyworks/autoreload', 20 | 'gems' => 'http://rubygems.org/gems/autoreload' 21 | 22 | created '2007-07-01' 23 | 24 | copyrights '2010 Thomas Sawyer (BSD-2-Clause)', 25 | '2003 Kouichiro Eto (RUBY)' 26 | 27 | webcvs 'https://github.com/rubyworks/autoreload/tree/master' 28 | -------------------------------------------------------------------------------- /work/deprecated/Changes.txt: -------------------------------------------------------------------------------- 1 | == 2007-07-07 2 | 3 | * lib/autoreload.rb: Do not use @thread. 4 | 5 | == 2007-07-06 6 | 7 | * Rakefile: To use Chages.txt 8 | 9 | == 2007-07-05 10 | 11 | * Changes.txt: New file. Moved from ChangeLog. 12 | * ChangeLog: Deleted. 13 | 14 | * bin: Deleted. 15 | 16 | * lib/autoreload.rb: Make it start from class method. 17 | 18 | * lib/autoreload/version.rb: Removed. 19 | 20 | * lib/autoreload.rb: Reformat. 21 | 22 | * examples/sample1.rb: New file. 23 | * examples/foo.rb: New file. 24 | 25 | * default_task.rb: New file. Splited from Rakefile. 26 | * Rakefile: Follow. 27 | * script/lib-txt2html.rb: New file. 28 | * script/makemanifest.rb: New file. 29 | 30 | * License.txt: Update license to Ruby license. 31 | 32 | * test/test_autoreload.rb: Sometimes test is failed. 33 | 34 | * default_task.rb: Check file exist in chmod task. 35 | 36 | * default_task.rb: Specify version and download. 37 | * scripts/lib-txt2html.rb: Remove dependency. 38 | * scripts/txt2html: Follow. 39 | 40 | == 2007-07-04 41 | 42 | * License.txt: created. 43 | * README.txt: created. 44 | 45 | * lib/autoreload/version.rb: Truncated. 46 | * Rakefile: Ditto. 47 | 48 | * lib/autoreload.rb: Created. 49 | * test/test_autoreload.rb: Ditto. 50 | 51 | * lib/autoreload.rb: Refactoring. 52 | 53 | == 2007-07-04 54 | 55 | * Init. 56 | 57 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | revision: 2013 3 | type: ruby 4 | sources: 5 | - Index.rb 6 | - Gemfile 7 | authors: 8 | - name: Thomas Sawyer 9 | email: transfire@gmail.com 10 | - name: Kouichirou Eto 11 | organizations: [] 12 | requirements: 13 | - groups: 14 | - development 15 | version: '>= 0' 16 | name: rake 17 | - groups: 18 | - test 19 | version: '>= 0' 20 | name: minitest 21 | - engines: 22 | - name: rbx 23 | version: 0+ 24 | version: '>= 0' 25 | name: psych 26 | - engines: 27 | - name: rbx 28 | version: 0+ 29 | version: ~> 2.0 30 | name: rubysl 31 | - engines: 32 | - name: rbx 33 | version: 0+ 34 | version: '>= 0' 35 | name: minitest 36 | conflicts: [] 37 | alternatives: [] 38 | resources: 39 | - type: home 40 | uri: http://rubyworks.github.com/autoreload 41 | label: Homepage 42 | - type: code 43 | uri: http://github.com/rubyworks/autoreload 44 | label: Source Code 45 | - type: gems 46 | uri: http://rubygems.org/gems/autoreload 47 | repositories: [] 48 | categories: [] 49 | copyrights: 50 | - holder: Thomas Sawyer 51 | year: '2010' 52 | license: BSD-2-Clause 53 | - holder: Kouichiro Eto 54 | year: '2003' 55 | license: RUBY 56 | customs: [] 57 | paths: 58 | lib: 59 | - lib 60 | version: 1.2.0 61 | name: autoreload 62 | title: AutoReload 63 | summary: Automatically reload library files 64 | description: Autoreload automatically reloads library files when they have been updated. 65 | It is especially useful when testing stateless services such as web applications. 66 | created: '2007-07-01' 67 | webcvs: https://github.com/rubyworks/autoreload/tree/master 68 | date: '2015-05-07' 69 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Autoreload 2 | 3 | Copyright (c) 2010 Rubyworks. 4 | Copyright (c) 2003 Kouichirou Eto. 5 | 6 | All rights reserved. 7 | 8 | License (spdx) [BSD-2-Clause](http://spdx.org/licenses/bsd-2-clause) 9 | 10 | Redistribution and use in source and binary forms, with or without modification, are 11 | permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions of source code must retain the above copyright notice, this list of 14 | conditions and the following disclaimer. 15 | 16 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 17 | of conditions and the following disclaimer in the documentation and/or other materials 18 | provided with the distribution. 19 | 20 | THIS SOFTWARE IS PROVIDED BY Thomas Sawyer ``AS IS'' AND ANY EXPRESS OR IMPLIED 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Thomas Sawyer OR 23 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | The views and conclusions contained in the software and documentation are those of the 31 | authors and should not be interpreted as representing official policies, either expressed 32 | or implied, of Thomas Sawyer. 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoReload 2 | 3 | [Homepage](http://rubyworks.github.com/autoreload) | 4 | [Development](http://github.com/rubyworks/autoreload) | 5 | [Mailing List](http://groups.google.com/group/rubyworks-mailinglist) 6 | 7 | [![Build Status](https://secure.travis-ci.org/rubyworks/autoreload.png)](http://travis-ci.org/rubyworks/autoreload) 8 | 9 | 10 | ## Description 11 | 12 | Autoreload automatically reloads library files after they 13 | have been updated. It is especially useful when testing 14 | stateless services such as web applications. 15 | 16 | IMPORTANT! Version 1.0+ has a new API. It also works best 17 | under Ruby 1.9 or above. Under Ruby 1.8 or older files are 18 | reloaded regardless of whether they actually have changed 19 | since the last load. Whereas in Ruby 1.9+, they only reload 20 | if the mtime on the file is newer than the previous time. 21 | 22 | 23 | ## Synopsis 24 | 25 | Say we have a library foo.rb in our load path: 26 | 27 | def foo 28 | 1 29 | end 30 | 31 | 32 | We can then run the following script, example.rb: 33 | 34 | require 'autoreload' 35 | 36 | autoreload(:interval=>2, :verbose=>true) do 37 | require 'foo.rb' 38 | end 39 | 40 | loop { 41 | puts foo 42 | sleep 2 43 | } 44 | 45 | While that's running we can change `foo.rb` and the change will 46 | take effect in `example.rb` within two seconds of being made. 47 | 48 | Note that autoreload only works with _required_ files. It cannot 49 | monitor files that are brought in with `#load`. This is because 50 | `$LOADED_FEATURES` is used to track which files are monitored. 51 | 52 | 53 | ## Acknowledgements 54 | 55 | The current version of Autoreload is a derviative of Kouichirou Eto's original 56 | work which can still be found at http://autoreload.rubyforge.org. 57 | 58 | 59 | ## License & Copyrights 60 | 61 | Autoreload is released as free software under the BSD-2-Clause license. 62 | 63 | * Copyright 2010 Rubyworks 64 | * Copyright 2003 Kouichirou Eto 65 | 66 | See LICENSE.md for details. 67 | 68 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 1.2.0 4 | 5 | Add `watch_gems` option to watch all required gems. The default 6 | is now to only watch `.rb` files in the current working directory. 7 | 8 | Changes: 9 | 10 | * Add `:watch_gems` option. 11 | * Watch current working directory only, as default. 12 | 13 | 14 | ## 1.1.0 15 | 16 | This release is simply a maintenance release to bring the build 17 | configuration up to date. 18 | 19 | Changes: 20 | 21 | * Modernize build configuration. 22 | * Use interpolation on error message. 23 | 24 | 25 | ## 1.0.0 (2011-07-16) 26 | 27 | This release overhauls the API. The #autoreload method now 28 | takes a block. All libraries required within this block 29 | will be autoreloaded. The old API will raise an error!!! 30 | This was done to simplify the overaul design of the library 31 | and consequently make it much more efficient, but also to 32 | fix a rather nasty bug that prevented scripts required by 33 | other scripts that were to be autoreloaded from autoreloading 34 | as well. 35 | 36 | The new design rely's solely on $LOADED_FEATURES, rather than 37 | looking up files on the $LOAD_PATH itself. This has an important 38 | consequence for Ruby 1.8 or older. Becuase older version of Ruby 39 | do not put the expanded path in $LOADED_FEATURES, autoreloading 40 | occurs regardless of whether the file has changed or not. On 41 | Ruby 1.9+ however, where the full path is available, the file will 42 | only be reloaded if it has changed, it does this by checking the 43 | mtime of the file. 44 | 45 | Changes: 46 | 47 | * Overhaul API to use block form. 48 | * Remove Lookup module (no longer needed). 49 | * Fix require of require issue. 50 | 51 | 52 | ## 0.3.1 (2011-05-15) 53 | 54 | This release simply fixes licensing issues. Autoreload is licensed 55 | under the GPL v3. 56 | 57 | 58 | ## 0.3.0 (2010-10-14) 59 | 60 | Changes: 61 | 62 | * Fix issue with looking up Roller libraries. 63 | * Switch testing framework to RSpec2. 64 | 65 | 66 | ## 0.2.0 (2010-05-10) 67 | 68 | Changes: 69 | 70 | * Completely reworked API. 71 | 72 | 73 | ## 0.1.0 (2010-05-01) 74 | 75 | Changes: 76 | 77 | * Same as original, but now a RubyWorks project. 78 | 79 | 80 | ## 0.0.1 (2007-07-01) 81 | 82 | Changes: 83 | 84 | * Initial release 85 | 86 | -------------------------------------------------------------------------------- /work/deprecated/Rakefile: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | include FileUtils 3 | require File.join(File.dirname(__FILE__), 'default_task') 4 | require File.join(File.dirname(__FILE__), 'lib', 'autoreload') 5 | 6 | AUTHOR = 'FIXME full name' # can also be an array of Authors 7 | EMAIL = "FIXME email" 8 | DESCRIPTION = "description of gem" 9 | GEM_NAME = 'autoreload' # what ppl will type to install your gem 10 | 11 | @config_file = "~/.rubyforge/user-config.yml" 12 | @config = nil 13 | def rubyforge_username 14 | unless @config 15 | begin 16 | @config = YAML.load(File.read(File.expand_path(@config_file))) 17 | rescue 18 | puts <<-EOS 19 | ERROR: No rubyforge config file found: #{@config_file}" 20 | Run 'rubyforge setup' to prepare your env for access to Rubyforge 21 | - See http://newgem.rubyforge.org/rubyforge.html for more details 22 | EOS 23 | # " 24 | exit 25 | end 26 | end 27 | @rubyforge_username ||= @config["username"] 28 | end 29 | 30 | RUBYFORGE_PROJECT = 'autoreload' # The unix name for your project 31 | HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" 32 | DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" 33 | 34 | NAME = "autoreload" 35 | REV = nil 36 | # UNCOMMENT IF REQUIRED: 37 | # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil 38 | VERS = AutoReload::VERSION::STRING + (REV ? ".#{REV}" : "") 39 | CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] 40 | RDOC_OPTS = ['--quiet', '--title', 'autoreload documentation', 41 | "--opname", "index.html", 42 | "--line-numbers", 43 | "--main", "README", 44 | "--inline-source"] 45 | 46 | # Generate all the Rake tasks 47 | # Run 'rake -T' to see list of generated tasks (from gem root directory) 48 | hoe = Hoe.new(GEM_NAME, VERS) do |p| 49 | p.author = AUTHOR 50 | p.description = DESCRIPTION 51 | p.email = EMAIL 52 | p.summary = DESCRIPTION 53 | p.url = HOMEPATH 54 | p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT 55 | p.test_globs = ["test/**/test_*.rb"] 56 | p.clean_globs |= CLEAN #An array of file patterns to delete on clean. 57 | 58 | # == Optional 59 | p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n") 60 | #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ] 61 | #p.spec_extras = {} # A hash of extra values to set in the gemspec. 62 | end 63 | 64 | CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n") 65 | PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" 66 | hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc') 67 | 68 | # clear current task 69 | t = Rake.application.lookup(:install_gem) 70 | t.clear_actions if t 71 | 72 | # redefine task 73 | task :install_gem => [:clean, :package] do 74 | if /mswin32/ =~ RUBY_PLATFORM || /cygwin/ =~ RUBY_PLATFORM 75 | sh "gem.cmd install pkg/*.gem" # for Cygwin 76 | else 77 | sh "sudo gem install pkg/*.gem" 78 | end 79 | end 80 | 81 | -------------------------------------------------------------------------------- /work/deprecated/default_task.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | require 'rake/clean' 4 | require 'rake/testtask' 5 | require 'rake/packagetask' 6 | require 'rake/gempackagetask' 7 | require 'rake/rdoctask' 8 | require 'rake/contrib/rubyforgepublisher' 9 | require 'hoe' 10 | begin 11 | require 'spec/rake/spectask' 12 | rescue LoadError 13 | puts 'To use rspec for testing you must install rspec gem:' 14 | puts '$ sudo gem install rspec' 15 | exit 16 | end 17 | 18 | class Hoe 19 | def extra_deps 20 | @extra_deps.reject { |x| Array(x).first == 'hoe' } 21 | end 22 | end 23 | 24 | desc 'Generate website files' 25 | task :website_generate do 26 | require 'scripts/lib-txt2html' 27 | t2h = Txt2Html.new 28 | Dir['website/**/*.txt'].each do |txt| 29 | puts txt 30 | version = VERS 31 | download = DOWNLOAD_PATH 32 | t2h.translate(txt, txt.gsub(/txt$/, 'html'), version, download) 33 | end 34 | end 35 | 36 | # add chmod. 37 | task :website_generate do 38 | sh %{ chmod -R go+rx website } 39 | end 40 | 41 | desc 'Upload website files to rubyforge' 42 | task :website_upload do 43 | host = "#{rubyforge_username}@rubyforge.org" 44 | remote_dir = "/var/www/gforge-projects/#{PATH}/" 45 | local_dir = 'website' 46 | sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}} 47 | end 48 | 49 | desc 'Generate and upload website files' 50 | task :website => [:website_generate, :website_upload, :publish_docs] 51 | 52 | desc 'Release the website and new gem version' 53 | task :deploy => [:check_version, :website, :release] do 54 | puts "Remember to create SVN tag:" 55 | puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " + 56 | "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} " 57 | puts "Suggested comment:" 58 | puts "Tagging release #{CHANGES}" 59 | end 60 | 61 | desc 'Runs tasks website_generate and install_gem as a local deployment of the gem' 62 | task :local_deploy => [:website_generate, :install_gem] 63 | 64 | task :check_version do 65 | unless ENV['VERSION'] 66 | puts 'Must pass a VERSION=x.y.z release version' 67 | exit 68 | end 69 | unless ENV['VERSION'] == VERS 70 | puts "Please update your version.rb to match the release version, currently #{VERS}" 71 | exit 72 | end 73 | end 74 | 75 | desc "Run the specs under spec/models" 76 | Spec::Rake::SpecTask.new do |t| 77 | t.spec_opts = ['--options', "spec/spec.opts"] 78 | t.spec_files = FileList['spec/*_spec.rb'] 79 | t.libs << "lib" 80 | end 81 | 82 | # add chmod. 83 | task :docs do 84 | sh %{ chmod -R go+rx doc } 85 | end 86 | 87 | # clear current task 88 | module Rake 89 | class Task 90 | def clear_actions 91 | @actions.clear 92 | end 93 | end 94 | end 95 | 96 | task :clean => [:chmod] 97 | 98 | CHMOD644 = FileList[%w( 99 | Rakefile Change* 100 | **/*.txt 101 | **/*.html 102 | **/*.rhtml 103 | **/*.js 104 | **/*.css 105 | **/*.rb 106 | **/*.opts 107 | )] 108 | CHMOD755 = FileList[%w(scripts/*)] 109 | 110 | desc 'Chmod all files.' 111 | task :chmod do 112 | CHMOD644.each {|f| 113 | File.chmod 0644, f if File.exist? f 114 | } 115 | CHMOD755.each {|f| 116 | File.chmod 0755, f if File.exist? f 117 | } 118 | end 119 | 120 | desc 'Create Manifest.txt file.' 121 | task :manifest => [:chmod, :clean] do 122 | ruby "scripts/makemanifest.rb" 123 | end 124 | 125 | # Add tasks to gem 126 | task :gem => [:manifest] 127 | 128 | desc "Default task is to run specs" 129 | task :default => [:spec] 130 | -------------------------------------------------------------------------------- /work/autoreload.rb: -------------------------------------------------------------------------------- 1 | module Kernel 2 | 3 | # Autoreload feature files. 4 | # 5 | # Automatically reload, at regular intervals, any previously loaded features, 6 | # and/or other files not already loaded, if they have been modified since the last 7 | # interval check. A numeric parameter sets the reload interval in seconds 8 | # and the file parameter can either be a glob string or an array 9 | # of file paths. If a glob string, it is expanded only once on the initial 10 | # method call. Supplying a boolean parameter of 'false' will force autreload to 11 | # skip previously loaded features and only reload the specified files. 12 | # Also keeps a "dirty" flag. 13 | # 14 | # Copyright (c) 2003 Michael Neumann 15 | 16 | def autoreload( *args ) 17 | 18 | check_interval=10 19 | include_features = true 20 | files = nil 21 | 22 | args.each do |arg| 23 | case arg 24 | when Numeric 25 | check_interval = arg 26 | when String 27 | files = Dir.glob( arg ) 28 | when Array 29 | files = arg 30 | when TrueClass, FalseClass 31 | include_features = arg 32 | end 33 | end 34 | 35 | file_mtime = {} 36 | 37 | Thread.new(Time.now) do |start_time| 38 | loop do 39 | sleep check_interval 40 | 41 | if include_features 42 | feature_files = $LOADED_FEATURES.collect { |feature| 43 | $LOAD_PATH.each { |lp| file = File.join(lp, feature) } 44 | }.flatten 45 | 46 | feature_files.each { |file| 47 | if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) 48 | $autoreload_dirty = true 49 | file_mtime[file] = mtime 50 | STDERR.puts "File '#{ file }' reloaded" 51 | begin 52 | load(file) 53 | rescue Exception => e 54 | STDERR.puts e.inspect 55 | end 56 | end 57 | } 58 | end 59 | 60 | if files 61 | files.each do |file| 62 | if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) 63 | $autoreload_dirty = true 64 | file_mtime[file] = mtime 65 | STDERR.puts "File '#{ file }' changed" 66 | end 67 | end 68 | end 69 | 70 | end 71 | end 72 | 73 | end 74 | 75 | # Same as #autoreload, but does not include previously loaded features. 76 | # This is equivalent to as adding a 'false' parameter to #autoreload. 77 | # 78 | def autoreload_files(*args) 79 | autoreload(false, *args) 80 | end 81 | 82 | # deprecated 83 | #def autoreload_glob(*args) 84 | # warn "autoreload_glob will be deprecated. Use autoreload_files instead." 85 | # autoreload_files(*args) 86 | #end 87 | end 88 | 89 | #-- 90 | # # OLD VERSION 91 | # def autoreload(check_interval=10) 92 | # Thread.new(Time.now) { |start_time| 93 | # file_mtime = {} 94 | # loop { 95 | # sleep check_interval 96 | # $LOADED_FEATURES.each { |feature| 97 | # $LOAD_PATH.each { |lp| 98 | # file = File.join(lp, feature) 99 | # if (File.exists?(file) and 100 | # File.stat(file).mtime > (file_mtime[file] || start_time)) 101 | # file_mtime[file] = File.stat(file).mtime 102 | # STDERR.puts "reload #{ file }" 103 | # begin 104 | # load(file) 105 | # rescue Exception => e 106 | # STDERR.puts e.inspect 107 | # end 108 | # end 109 | # } 110 | # } 111 | # } 112 | # } 113 | # end 114 | #++ 115 | 116 | -------------------------------------------------------------------------------- /work/consider/autoreload.rb: -------------------------------------------------------------------------------- 1 | module Kernel 2 | 3 | # Autoreload feature files. 4 | # 5 | # Automatically reload, at regular intervals, any previously loaded features, 6 | # and/or other files not already loaded, if they have been modified since the last 7 | # interval check. A numeric parameter sets the reload interval in seconds 8 | # and the file parameter can either be a glob string or an array 9 | # of file paths. If a glob string, it is expanded only once on the initial 10 | # method call. Supplying a boolean parameter of 'false' will force autreload to 11 | # skip previously loaded features and only reload the specified files. 12 | # Also keeps a "dirty" flag. 13 | # 14 | # Copyright (c) 2003 Michael Neumann 15 | 16 | def autoreload( *args ) 17 | 18 | check_interval=10 19 | include_features = true 20 | files = nil 21 | 22 | args.each do |arg| 23 | case arg 24 | when Numeric 25 | check_interval = arg 26 | when String 27 | files = Dir.glob( arg ) 28 | when Array 29 | files = arg 30 | when TrueClass, FalseClass 31 | include_features = arg 32 | end 33 | end 34 | 35 | file_mtime = {} 36 | 37 | Thread.new(Time.now) do |start_time| 38 | loop do 39 | sleep check_interval 40 | 41 | if include_features 42 | feature_files = $LOADED_FEATURES.collect { |feature| 43 | $LOAD_PATH.each { |lp| file = File.join(lp, feature) } 44 | }.flatten 45 | 46 | feature_files.each { |file| 47 | if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) 48 | $autoreload_dirty = true 49 | file_mtime[file] = mtime 50 | STDERR.puts "File '#{ file }' reloaded" 51 | begin 52 | load(file) 53 | rescue Exception => e 54 | STDERR.puts e.inspect 55 | end 56 | end 57 | } 58 | end 59 | 60 | if files 61 | files.each do |file| 62 | if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time) 63 | $autoreload_dirty = true 64 | file_mtime[file] = mtime 65 | STDERR.puts "File '#{ file }' changed" 66 | end 67 | end 68 | end 69 | 70 | end 71 | end 72 | 73 | end 74 | 75 | # Same as #autoreload, but does not include previously loaded features. 76 | # This is equivalent to as adding a 'false' parameter to #autoreload. 77 | # 78 | def autoreload_files(*args) 79 | autoreload(false, *args) 80 | end 81 | 82 | # deprecated 83 | #def autoreload_glob(*args) 84 | # warn "autoreload_glob will be deprecated. Use autoreload_files instead." 85 | # autoreload_files(*args) 86 | #end 87 | end 88 | 89 | #-- 90 | # # OLD VERSION 91 | # def autoreload(check_interval=10) 92 | # Thread.new(Time.now) { |start_time| 93 | # file_mtime = {} 94 | # loop { 95 | # sleep check_interval 96 | # $LOADED_FEATURES.each { |feature| 97 | # $LOAD_PATH.each { |lp| 98 | # file = File.join(lp, feature) 99 | # if (File.exists?(file) and 100 | # File.stat(file).mtime > (file_mtime[file] || start_time)) 101 | # file_mtime[file] = File.stat(file).mtime 102 | # STDERR.puts "reload #{ file }" 103 | # begin 104 | # load(file) 105 | # rescue Exception => e 106 | # STDERR.puts e.inspect 107 | # end 108 | # end 109 | # } 110 | # } 111 | # } 112 | # } 113 | # end 114 | #++ 115 | 116 | -------------------------------------------------------------------------------- /work/deprecated/scripts/lib-txt2html.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'rubygems' 4 | require 'redcloth' 5 | require 'syntax/convertors/html' 6 | require 'erb' 7 | 8 | class Fixnum 9 | def ordinal 10 | # teens 11 | return 'th' if (10..19).include?(self % 100) 12 | # others 13 | case self % 10 14 | when 1: return 'st' 15 | when 2: return 'nd' 16 | when 3: return 'rd' 17 | else return 'th' 18 | end 19 | end 20 | end 21 | 22 | class Time 23 | def pretty 24 | return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}" 25 | end 26 | end 27 | 28 | class Txt2Html 29 | def self.main(argv) 30 | self.new.main(argv) 31 | end 32 | 33 | DEFAULT_TEMPLATE = File.dirname(__FILE__) + '/../website/template.rhtml' 34 | 35 | def main(argv) 36 | if argv.length >= 1 37 | src, template = argv 38 | template ||= DEFAULT_TEMPLATE 39 | else 40 | puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html") 41 | exit! 42 | end 43 | 44 | version = VERS 45 | download = DOWNLOAD_PATH 46 | result = generate2(template, src, version, download) 47 | $stdout << result 48 | end 49 | 50 | def translate(src, dest, version, download) 51 | template = DEFAULT_TEMPLATE 52 | result = generate2(template, src, version, download) 53 | File.open(dest, 'wb') {|f| f.print result } 54 | end 55 | 56 | def generate2(template, src, version, download) 57 | template_text = File.open(template).read 58 | src_text = File.open(src) {|fsrc| fsrc.read } 59 | modified = File.stat(src).mtime 60 | result = generate(template_text, src_text, modified, version, download) 61 | end 62 | 63 | def generate(template_text, src_text, modified, version, download) 64 | title_text, body_text = parse_title_body(src_text) 65 | title = create_title(title_text) 66 | body = create_body(body_text) 67 | template = ERB.new(template_text) 68 | result = template.result(binding) 69 | return result 70 | end 71 | 72 | def parse_title_body(str) 73 | /\A(.*?)\n(.*)/m =~ str 74 | return $1, $2 75 | end 76 | 77 | def create_title(title_text) 78 | return RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip 79 | end 80 | 81 | def create_body(body_text) 82 | syntax_items = [] 83 | body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)!m) { 84 | ident = syntax_items.length 85 | element, syntax, source = $1, $2, $3 86 | syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}" 87 | "syntax-temp-#{ident}" 88 | } 89 | body = RedCloth.new(body_text).to_html 90 | body.gsub!(%r!(?:
)?syntax-temp-(d+)(?:
)?!){ syntax_items[$1.to_i] } 91 | return body 92 | end 93 | 94 | def convert_syntax(syntax, source) 95 | return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^
|
$!, '') 96 | end 97 | end 98 | 99 | if $0 == __FILE__ 100 | require "test/unit" 101 | $__test_txt2html__ = true 102 | end 103 | 104 | if defined?($__test_txt2html__) && $__test_txt2html__ 105 | class TestTxt2Html < Test::Unit::TestCase #:nodoc: 106 | def test_fixnum_ordinal 107 | assert_equal 'st', 1.ordinal 108 | end 109 | 110 | def test_time_pretty 111 | assert_equal '1st January 1970', Time.at(0).pretty 112 | end 113 | 114 | def test_all 115 | # test_txt2html 116 | t2h = Txt2Html.new 117 | 118 | # test_parse_title_body 119 | assert_equal ["title", "body\n"], t2h.parse_title_body("title\nbody\n") 120 | assert_equal ["title", "b\nb\n"], t2h.parse_title_body("title\nb\nb\n") 121 | 122 | # test_create_title 123 | assert_equal 'title', t2h.create_title('h1. title') 124 | 125 | # test_create_body 126 | assert_equal '

body

', t2h.create_body('h2. body') 127 | 128 | # test_convert_syntax 129 | assert_equal '0', 130 | t2h.convert_syntax('ruby', '0') 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /lib/autoreload/reloader.rb: -------------------------------------------------------------------------------- 1 | require 'thread' 2 | 3 | module AutoReload 4 | 5 | # Reload class does all the heavy lifting 6 | # for AutoReload library. 7 | # 8 | class Reloader 9 | 10 | # Public: Shortcut for Reloader.new(*args).start. 11 | def self.start(*args, &block) 12 | self.new(*args, &block).start 13 | end 14 | 15 | # Public: Default interval is one second. 16 | DEFAULT_INTERVAL = 1 17 | 18 | # New Reloader. 19 | # 20 | # options - The Hash options used to refine the reloader (default: {}): 21 | # :interval - Seconds between updates. 22 | # :verbose - True provides reload warning. 23 | # :reprime - Include $0 in reload list. 24 | # 25 | def initialize(options={}, &block) 26 | @interval = (options[:interval] || DEFAULT_INTERVAL).to_i 27 | @verbose = (options[:verbose]) 28 | @reprime = (options[:reprime]) 29 | @watch_gems = (options[:watch_gems]) 30 | 31 | @status = {} 32 | 33 | features = $".dup 34 | if block 35 | block.call 36 | @files = ($" - features).select do |f| 37 | (@watch_gems ? true : f.start_with?(Dir.pwd)) && f.end_with?(".rb") 38 | end.reverse 39 | 40 | if @verbose 41 | puts "watching files:" 42 | puts "---------------" 43 | puts @files 44 | puts "---------------" 45 | end 46 | else 47 | @files = [] 48 | end 49 | end 50 | 51 | # Public: Start the reload thread. 52 | def start 53 | update # prime the path loads 54 | @thread = Thread.new do 55 | loop do 56 | begin 57 | update 58 | rescue Exception 59 | warn "autoreload failed unexpectedly: #{$!}" 60 | end 61 | sleep @interval 62 | end 63 | end 64 | @thread.abort_on_exception = true 65 | @thread 66 | end 67 | 68 | # Public: Kills the autoreload thread. 69 | def stop 70 | @thread.kill if @thread 71 | end 72 | 73 | # Public: References the reload thread. 74 | attr :thread 75 | 76 | # Public: List of files provided to autoreload. 77 | attr :files 78 | 79 | # Public: Status hash, used to track reloads. 80 | attr :status 81 | 82 | # Public: The periodic interval of reload in seconds. 83 | attr :interval 84 | 85 | # Public: Provide warning on reload. 86 | # 87 | # Returns true/false if versboe mode. 88 | def verbose? 89 | @verbose || $VERBOSE 90 | end 91 | 92 | # Public: Put $0 in the reload list? 93 | # 94 | # Returns true/false whether to include $0. 95 | def reprime? 96 | @reprime 97 | end 98 | 99 | private 100 | 101 | # TODO: Why include $0 in #libraries ? 102 | 103 | # The library files to autoreload. 104 | def libraries 105 | if @files.empty? 106 | @reprime ? [$0] + $" : $" 107 | else 108 | @files 109 | end 110 | end 111 | 112 | # Iterate through all selection library files and reload if needed. 113 | def update 114 | libraries.each{ |lib| check(lib) } 115 | end 116 | 117 | # Check status and reload if out-of-date. 118 | # 119 | # We can't check mtime under 1.8 b/c $LOADED_FEATURES does not 120 | # store the full path. 121 | # 122 | # lib - A library file. 123 | # 124 | # Returns Array of [file, mtime]. 125 | def check(lib) 126 | if RUBY_VERSION < '1.9' 127 | warn "reload: '#{lib}'" if verbose? 128 | begin 129 | load lib 130 | rescue LoadError 131 | # file has been removed 132 | end 133 | else 134 | file, mtime = @status[lib] 135 | if file 136 | if FileTest.exist?(file) 137 | curtime = File.mtime(file).to_i 138 | if mtime < curtime 139 | warn "reload: '#{file}'" if verbose? 140 | load file 141 | @status[lib] = [file, curtime] 142 | end 143 | else 144 | # file has been removed 145 | end 146 | else 147 | @status[lib] = get_status(lib) 148 | end 149 | end 150 | end 151 | 152 | # Get library file status. 153 | # 154 | # file - The file path from which to get status. 155 | # 156 | # Returns Array of [file, mtime] or [nil, nil] if file not found. 157 | def get_status(file) 158 | if FileTest.exist?(file) 159 | [file, File.mtime(file).to_i] 160 | else 161 | warn "reload fail: library '#{file}' not found" if verbose? 162 | #raise "The library '#{file}' is not found." 163 | #$stdout.puts(message("The library '#{file}' is not found.")) if @verbose 164 | [nil, nil] 165 | end 166 | end 167 | 168 | end 169 | 170 | end 171 | 172 | # Copyright (C) 2010 Rubyworks (BSD-2-Clause) 173 | -------------------------------------------------------------------------------- /work/deprecated/lookup.rb: -------------------------------------------------------------------------------- 1 | module AutoReload 2 | 3 | # = Library Lookup 4 | # 5 | # This library is a slightly modified copy of the +plugin+ library. 6 | # 7 | module Lookup 8 | 9 | extend self 10 | 11 | # Find plugins, searching through standard $LOAD_PATH, 12 | # Roll Libraries and RubyGems. 13 | # 14 | # Provide a +match+ file glob to find plugins. 15 | # 16 | # Lookup.find('syckle/*') 17 | # 18 | def find(match, options={}) 19 | plugins = [] 20 | plugins.concat find_roll(match, options) 21 | plugins.concat find_loadpath(match, options) 22 | plugins.concat find_gems(match, options) 23 | plugins.uniq 24 | end 25 | 26 | # Shortcut for #find. 27 | # 28 | # Lookup['syckle/*'] 29 | # 30 | alias_method :[], :find 31 | 32 | # Search roll for current or latest libraries. 33 | def find_roll(match, options={}) 34 | plugins = [] 35 | #directory = options[:directory] || DIRECTORY 36 | if defined?(::Roll) 37 | # Not ::Roll::Library ? 38 | ::Library.ledger.each do |name, lib| 39 | lib = lib.sort.first if Array===lib 40 | lib.loadpath.each do |path| 41 | #find = File.join(lib.location, path, directory, match) 42 | find = File.join(lib.location, path, match) 43 | list = Dir.glob(find) 44 | list = list.map{ |d| d.chomp('/') } 45 | plugins.concat(list) 46 | end 47 | end 48 | end 49 | plugins 50 | end 51 | 52 | # Search standard $LOAD_PATH. 53 | # 54 | # Activated gem versions are in here too. 55 | 56 | def find_loadpath(match, options={}) 57 | plugins = [] 58 | #directory = options[:directory] || DIRECTORY 59 | $LOAD_PATH.uniq.each do |path| 60 | path = File.expand_path(path) 61 | #list = Dir.glob(File.join(path, directory, match)) 62 | list = Dir.glob(File.join(path, match)) 63 | list = list.map{ |d| d.chomp('/') } 64 | plugins.concat(list) 65 | end 66 | plugins 67 | end 68 | 69 | # # Search latest gem versions. 70 | # # 71 | # # TODO: Is there anyway to skip active gems? 72 | # 73 | # def find_gems(match, options={}) 74 | # plugins = [] 75 | # #directory = options[:directory] || DIRECTORY 76 | # if defined?(::Gem) 77 | # ::Gem.latest_load_paths do |path| 78 | # #list = Dir.glob(File.join(path, directory, match)) 79 | # list = Dir.glob(File.join(path, match)) 80 | # list = list.map{ |d| d.chomp('/') } 81 | # plugins.concat(list) 82 | # end 83 | # end 84 | # plugins 85 | # end 86 | 87 | # Find the highest versions of unactived gems. 88 | # 89 | # TODO: Skip active gems. 90 | # 91 | # @returns Array 92 | def find_gems(match, options={}) 93 | #directory = options[:directory] || DIRECTORY 94 | plugins = [] 95 | if defined?(::Gem) 96 | latest_load_paths = [] 97 | Gem.path.each do |path| 98 | libs = Dir[File.join(path, 'gems', '*', 'lib')] 99 | latest_load_paths.concat(libs) 100 | end 101 | latest_load_paths.sort!{ |a,b| natcmp(a,b) } 102 | # TODO: reduce latest_load_paths to highest versions 103 | latest_load_paths.each do |path| #::Gem.latest_load_paths do |path| 104 | #list = Dir.glob(File.join(path, directory, match)) 105 | list = Dir.glob(File.join(path, match)) 106 | list = list.map{ |d| d.chomp('/') } 107 | plugins.concat(list) 108 | end 109 | end 110 | plugins 111 | end 112 | 113 | private 114 | 115 | # 'Natural order' comparison of strings, e.g. ... 116 | # 117 | # "my_prog_v1.1.0" < "my_prog_v1.2.0" < "my_prog_v1.10.0" 118 | # 119 | # which does not follow alphabetically. A secondary 120 | # parameter, if set to _true_, makes the comparison 121 | # case insensitive. 122 | # 123 | # "Hello.1".natcmp("Hello.10") #=> -1 124 | # 125 | # TODO: Invert case flag? 126 | # 127 | # CREDIT: Alan Davies, Martin Pool 128 | 129 | def natcmp(str1, str2, caseInsensitive=false) 130 | str1 = str1.dup 131 | str2 = str2.dup 132 | compareExpression = /^(\D*)(\d*)(.*)$/ 133 | 134 | if caseInsensitive 135 | str1.downcase! 136 | str2.downcase! 137 | end 138 | 139 | # -- remove all whitespace 140 | str1.gsub!(/\s*/, '') 141 | str2.gsub!(/\s*/, '') 142 | 143 | while (str1.length > 0) or (str2.length > 0) do 144 | # -- extract non-digits, digits and rest of string 145 | str1 =~ compareExpression 146 | chars1, num1, str1 = $1.dup, $2.dup, $3.dup 147 | str2 =~ compareExpression 148 | chars2, num2, str2 = $1.dup, $2.dup, $3.dup 149 | # -- compare the non-digits 150 | case (chars1 <=> chars2) 151 | when 0 # Non-digits are the same, compare the digits... 152 | # If either number begins with a zero, then compare alphabetically, 153 | # otherwise compare numerically 154 | if (num1[0] != 48) and (num2[0] != 48) 155 | num1, num2 = num1.to_i, num2.to_i 156 | end 157 | case (num1 <=> num2) 158 | when -1 then return -1 159 | when 1 then return 1 160 | end 161 | when -1 then return -1 162 | when 1 then return 1 163 | end # case 164 | end # while 165 | 166 | # -- strings are naturally equal 167 | return 0 168 | end 169 | 170 | end 171 | 172 | end 173 | 174 | # Copyright (C) 2010 Thomas Sawyer 175 | -------------------------------------------------------------------------------- /autoreload.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | paths = metadata['paths'] || {} 159 | paths['load'] || ['lib'] 160 | end 161 | 162 | # 163 | # Convert to gemnspec. 164 | # 165 | def to_gemspec 166 | if has_root? 167 | Gem::Specification.new do |gemspec| 168 | to_gemspec_data(gemspec) 169 | to_gemspec_paths(gemspec) 170 | end 171 | else 172 | Gem::Specification.new do |gemspec| 173 | to_gemspec_data(gemspec) 174 | to_gemspec_paths(gemspec) 175 | end 176 | end 177 | end 178 | 179 | # 180 | # Convert pure data settings. 181 | # 182 | def to_gemspec_data(gemspec) 183 | gemspec.name = name 184 | gemspec.version = metadata['version'] 185 | gemspec.summary = metadata['summary'] 186 | gemspec.description = metadata['description'] 187 | 188 | metadata['authors'].each do |author| 189 | gemspec.authors << author['name'] 190 | 191 | if author.has_key?('email') 192 | if gemspec.email 193 | gemspec.email << author['email'] 194 | else 195 | gemspec.email = [author['email']] 196 | end 197 | end 198 | end 199 | 200 | gemspec.licenses = licenses 201 | 202 | requirements = metadata['requirements'] || [] 203 | requirements.each do |req| 204 | next if req['optional'] 205 | next if req['external'] 206 | 207 | name = req['name'] 208 | groups = req['groups'] || [] 209 | 210 | version = gemify_version(req['version']) 211 | 212 | if groups.empty? or groups.include?('runtime') 213 | # populate runtime dependencies 214 | if gemspec.respond_to?(:add_runtime_dependency) 215 | gemspec.add_runtime_dependency(name,*version) 216 | else 217 | gemspec.add_dependency(name,*version) 218 | end 219 | else 220 | # populate development dependencies 221 | if gemspec.respond_to?(:add_development_dependency) 222 | gemspec.add_development_dependency(name,*version) 223 | else 224 | gemspec.add_dependency(name,*version) 225 | end 226 | end 227 | end 228 | 229 | # convert external dependencies into gemspec requirements 230 | requirements.each do |req| 231 | next unless req['external'] 232 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 233 | end 234 | 235 | gemspec.homepage = homepage 236 | gemspec.require_paths = require_paths 237 | gemspec.post_install_message = metadata['install_message'] 238 | end 239 | 240 | # 241 | # Set gemspec settings that require a root directory path. 242 | # 243 | def to_gemspec_paths(gemspec) 244 | gemspec.files = files 245 | gemspec.extensions = extensions 246 | gemspec.executables = executables 247 | 248 | if Gem::VERSION < '1.7.' 249 | gemspec.default_executable = gemspec.executables.first 250 | end 251 | 252 | gemspec.test_files = glob_files(patterns[:test]) 253 | 254 | unless gemspec.files.include?('.document') 255 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 256 | end 257 | end 258 | 259 | # 260 | # Return a copy of this file. This is used to generate a local 261 | # .gemspec file that can automatically read the index file. 262 | # 263 | def self.source_code 264 | File.read(__FILE__) 265 | end 266 | 267 | private 268 | 269 | def find_root 270 | root_files = patterns[:root] 271 | if Dir.glob(root_files).first 272 | Pathname.new(Dir.pwd) 273 | elsif Dir.glob("../#{root_files}").first 274 | Pathname.new(Dir.pwd).parent 275 | else 276 | #raise "Can't find root of project containing `#{root_files}'." 277 | warn "Can't find root of project containing `#{root_files}'." 278 | nil 279 | end 280 | end 281 | 282 | def glob(pattern) 283 | if File.directory?(pattern) 284 | Dir.glob(File.join(pattern, '**', '*')) 285 | else 286 | Dir.glob(pattern) 287 | end 288 | end 289 | 290 | def gemify_version(version) 291 | case version 292 | when /^(.*?)\+$/ 293 | ">= #{$1}" 294 | when /^(.*?)\-$/ 295 | "< #{$1}" 296 | when /^(.*?)\~$/ 297 | "~> #{$1}" 298 | else 299 | version 300 | end 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | Indexer::GemspecExporter.gemspec -------------------------------------------------------------------------------- /work/deprecated/setup.rb: -------------------------------------------------------------------------------- 1 | # 2 | # setup.rb 3 | # 4 | # Copyright (c) 2000-2005 Minero Aoki 5 | # 6 | # This program is free software. 7 | # You can distribute/modify this program under the terms of 8 | # the GNU LGPL, Lesser General Public License version 2.1. 9 | # 10 | 11 | unless Enumerable.method_defined?(:map) # Ruby 1.4.6 12 | module Enumerable 13 | alias map collect 14 | end 15 | end 16 | 17 | unless File.respond_to?(:read) # Ruby 1.6 18 | def File.read(fname) 19 | open(fname) {|f| 20 | return f.read 21 | } 22 | end 23 | end 24 | 25 | unless Errno.const_defined?(:ENOTEMPTY) # Windows? 26 | module Errno 27 | class ENOTEMPTY 28 | # We do not raise this exception, implementation is not needed. 29 | end 30 | end 31 | end 32 | 33 | def File.binread(fname) 34 | open(fname, 'rb') {|f| 35 | return f.read 36 | } 37 | end 38 | 39 | # for corrupted Windows' stat(2) 40 | def File.dir?(path) 41 | File.directory?((path[-1,1] == '/') ? path : path + '/') 42 | end 43 | 44 | 45 | class ConfigTable 46 | 47 | include Enumerable 48 | 49 | def initialize(rbconfig) 50 | @rbconfig = rbconfig 51 | @items = [] 52 | @table = {} 53 | # options 54 | @install_prefix = nil 55 | @config_opt = nil 56 | @verbose = true 57 | @no_harm = false 58 | end 59 | 60 | attr_accessor :install_prefix 61 | attr_accessor :config_opt 62 | 63 | attr_writer :verbose 64 | 65 | def verbose? 66 | @verbose 67 | end 68 | 69 | attr_writer :no_harm 70 | 71 | def no_harm? 72 | @no_harm 73 | end 74 | 75 | def [](key) 76 | lookup(key).resolve(self) 77 | end 78 | 79 | def []=(key, val) 80 | lookup(key).set val 81 | end 82 | 83 | def names 84 | @items.map {|i| i.name } 85 | end 86 | 87 | def each(&block) 88 | @items.each(&block) 89 | end 90 | 91 | def key?(name) 92 | @table.key?(name) 93 | end 94 | 95 | def lookup(name) 96 | @table[name] or setup_rb_error "no such config item: #{name}" 97 | end 98 | 99 | def add(item) 100 | @items.push item 101 | @table[item.name] = item 102 | end 103 | 104 | def remove(name) 105 | item = lookup(name) 106 | @items.delete_if {|i| i.name == name } 107 | @table.delete_if {|name, i| i.name == name } 108 | item 109 | end 110 | 111 | def load_script(path, inst = nil) 112 | if File.file?(path) 113 | MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path 114 | end 115 | end 116 | 117 | def savefile 118 | '.config' 119 | end 120 | 121 | def load_savefile 122 | begin 123 | File.foreach(savefile()) do |line| 124 | k, v = *line.split(/=/, 2) 125 | self[k] = v.strip 126 | end 127 | rescue Errno::ENOENT 128 | setup_rb_error $!.message + "\n#{File.basename($0)} config first" 129 | end 130 | end 131 | 132 | def save 133 | @items.each {|i| i.value } 134 | File.open(savefile(), 'w') {|f| 135 | @items.each do |i| 136 | f.printf "%s=%s\n", i.name, i.value if i.value? and i.value 137 | end 138 | } 139 | end 140 | 141 | def load_standard_entries 142 | standard_entries(@rbconfig).each do |ent| 143 | add ent 144 | end 145 | end 146 | 147 | def standard_entries(rbconfig) 148 | c = rbconfig 149 | 150 | rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) 151 | 152 | major = c['MAJOR'].to_i 153 | minor = c['MINOR'].to_i 154 | teeny = c['TEENY'].to_i 155 | version = "#{major}.#{minor}" 156 | 157 | # ruby ver. >= 1.4.4? 158 | newpath_p = ((major >= 2) or 159 | ((major == 1) and 160 | ((minor >= 5) or 161 | ((minor == 4) and (teeny >= 4))))) 162 | 163 | if c['rubylibdir'] 164 | # V > 1.6.3 165 | libruby = "#{c['prefix']}/lib/ruby" 166 | librubyver = c['rubylibdir'] 167 | librubyverarch = c['archdir'] 168 | siteruby = c['sitedir'] 169 | siterubyver = c['sitelibdir'] 170 | siterubyverarch = c['sitearchdir'] 171 | elsif newpath_p 172 | # 1.4.4 <= V <= 1.6.3 173 | libruby = "#{c['prefix']}/lib/ruby" 174 | librubyver = "#{c['prefix']}/lib/ruby/#{version}" 175 | librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" 176 | siteruby = c['sitedir'] 177 | siterubyver = "$siteruby/#{version}" 178 | siterubyverarch = "$siterubyver/#{c['arch']}" 179 | else 180 | # V < 1.4.4 181 | libruby = "#{c['prefix']}/lib/ruby" 182 | librubyver = "#{c['prefix']}/lib/ruby/#{version}" 183 | librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" 184 | siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" 185 | siterubyver = siteruby 186 | siterubyverarch = "$siterubyver/#{c['arch']}" 187 | end 188 | parameterize = lambda {|path| 189 | path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') 190 | } 191 | 192 | if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } 193 | makeprog = arg.sub(/'/, '').split(/=/, 2)[1] 194 | else 195 | makeprog = 'make' 196 | end 197 | 198 | [ 199 | ExecItem.new('installdirs', 'std/site/home', 200 | 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ 201 | {|val, table| 202 | case val 203 | when 'std' 204 | table['rbdir'] = '$librubyver' 205 | table['sodir'] = '$librubyverarch' 206 | when 'site' 207 | table['rbdir'] = '$siterubyver' 208 | table['sodir'] = '$siterubyverarch' 209 | when 'home' 210 | setup_rb_error '$HOME was not set' unless ENV['HOME'] 211 | table['prefix'] = ENV['HOME'] 212 | table['rbdir'] = '$libdir/ruby' 213 | table['sodir'] = '$libdir/ruby' 214 | end 215 | }, 216 | PathItem.new('prefix', 'path', c['prefix'], 217 | 'path prefix of target environment'), 218 | PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 219 | 'the directory for commands'), 220 | PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 221 | 'the directory for libraries'), 222 | PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 223 | 'the directory for shared data'), 224 | PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 225 | 'the directory for man pages'), 226 | PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 227 | 'the directory for system configuration files'), 228 | PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 229 | 'the directory for local state data'), 230 | PathItem.new('libruby', 'path', libruby, 231 | 'the directory for ruby libraries'), 232 | PathItem.new('librubyver', 'path', librubyver, 233 | 'the directory for standard ruby libraries'), 234 | PathItem.new('librubyverarch', 'path', librubyverarch, 235 | 'the directory for standard ruby extensions'), 236 | PathItem.new('siteruby', 'path', siteruby, 237 | 'the directory for version-independent aux ruby libraries'), 238 | PathItem.new('siterubyver', 'path', siterubyver, 239 | 'the directory for aux ruby libraries'), 240 | PathItem.new('siterubyverarch', 'path', siterubyverarch, 241 | 'the directory for aux ruby binaries'), 242 | PathItem.new('rbdir', 'path', '$siterubyver', 243 | 'the directory for ruby scripts'), 244 | PathItem.new('sodir', 'path', '$siterubyverarch', 245 | 'the directory for ruby extentions'), 246 | PathItem.new('rubypath', 'path', rubypath, 247 | 'the path to set to #! line'), 248 | ProgramItem.new('rubyprog', 'name', rubypath, 249 | 'the ruby program using for installation'), 250 | ProgramItem.new('makeprog', 'name', makeprog, 251 | 'the make program to compile ruby extentions'), 252 | SelectItem.new('shebang', 'all/ruby/never', 'ruby', 253 | 'shebang line (#!) editing mode'), 254 | BoolItem.new('without-ext', 'yes/no', 'no', 255 | 'does not compile/install ruby extentions') 256 | ] 257 | end 258 | private :standard_entries 259 | 260 | def load_multipackage_entries 261 | multipackage_entries().each do |ent| 262 | add ent 263 | end 264 | end 265 | 266 | def multipackage_entries 267 | [ 268 | PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 269 | 'package names that you want to install'), 270 | PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 271 | 'package names that you do not want to install') 272 | ] 273 | end 274 | private :multipackage_entries 275 | 276 | ALIASES = { 277 | 'std-ruby' => 'librubyver', 278 | 'stdruby' => 'librubyver', 279 | 'rubylibdir' => 'librubyver', 280 | 'archdir' => 'librubyverarch', 281 | 'site-ruby-common' => 'siteruby', # For backward compatibility 282 | 'site-ruby' => 'siterubyver', # For backward compatibility 283 | 'bin-dir' => 'bindir', 284 | 'bin-dir' => 'bindir', 285 | 'rb-dir' => 'rbdir', 286 | 'so-dir' => 'sodir', 287 | 'data-dir' => 'datadir', 288 | 'ruby-path' => 'rubypath', 289 | 'ruby-prog' => 'rubyprog', 290 | 'ruby' => 'rubyprog', 291 | 'make-prog' => 'makeprog', 292 | 'make' => 'makeprog' 293 | } 294 | 295 | def fixup 296 | ALIASES.each do |ali, name| 297 | @table[ali] = @table[name] 298 | end 299 | @items.freeze 300 | @table.freeze 301 | @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ 302 | end 303 | 304 | def parse_opt(opt) 305 | m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" 306 | m.to_a[1,2] 307 | end 308 | 309 | def dllext 310 | @rbconfig['DLEXT'] 311 | end 312 | 313 | def value_config?(name) 314 | lookup(name).value? 315 | end 316 | 317 | class Item 318 | def initialize(name, template, default, desc) 319 | @name = name.freeze 320 | @template = template 321 | @value = default 322 | @default = default 323 | @description = desc 324 | end 325 | 326 | attr_reader :name 327 | attr_reader :description 328 | 329 | attr_accessor :default 330 | alias help_default default 331 | 332 | def help_opt 333 | "--#{@name}=#{@template}" 334 | end 335 | 336 | def value? 337 | true 338 | end 339 | 340 | def value 341 | @value 342 | end 343 | 344 | def resolve(table) 345 | @value.gsub(%r<\$([^/]+)>) { table[$1] } 346 | end 347 | 348 | def set(val) 349 | @value = check(val) 350 | end 351 | 352 | private 353 | 354 | def check(val) 355 | setup_rb_error "config: --#{name} requires argument" unless val 356 | val 357 | end 358 | end 359 | 360 | class BoolItem < Item 361 | def config_type 362 | 'bool' 363 | end 364 | 365 | def help_opt 366 | "--#{@name}" 367 | end 368 | 369 | private 370 | 371 | def check(val) 372 | return 'yes' unless val 373 | case val 374 | when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' 375 | when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' 376 | else 377 | setup_rb_error "config: --#{@name} accepts only yes/no for argument" 378 | end 379 | end 380 | end 381 | 382 | class PathItem < Item 383 | def config_type 384 | 'path' 385 | end 386 | 387 | private 388 | 389 | def check(path) 390 | setup_rb_error "config: --#{@name} requires argument" unless path 391 | path[0,1] == '$' ? path : File.expand_path(path) 392 | end 393 | end 394 | 395 | class ProgramItem < Item 396 | def config_type 397 | 'program' 398 | end 399 | end 400 | 401 | class SelectItem < Item 402 | def initialize(name, selection, default, desc) 403 | super 404 | @ok = selection.split('/') 405 | end 406 | 407 | def config_type 408 | 'select' 409 | end 410 | 411 | private 412 | 413 | def check(val) 414 | unless @ok.include?(val.strip) 415 | setup_rb_error "config: use --#{@name}=#{@template} (#{val})" 416 | end 417 | val.strip 418 | end 419 | end 420 | 421 | class ExecItem < Item 422 | def initialize(name, selection, desc, &block) 423 | super name, selection, nil, desc 424 | @ok = selection.split('/') 425 | @action = block 426 | end 427 | 428 | def config_type 429 | 'exec' 430 | end 431 | 432 | def value? 433 | false 434 | end 435 | 436 | def resolve(table) 437 | setup_rb_error "$#{name()} wrongly used as option value" 438 | end 439 | 440 | undef set 441 | 442 | def evaluate(val, table) 443 | v = val.strip.downcase 444 | unless @ok.include?(v) 445 | setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" 446 | end 447 | @action.call v, table 448 | end 449 | end 450 | 451 | class PackageSelectionItem < Item 452 | def initialize(name, template, default, help_default, desc) 453 | super name, template, default, desc 454 | @help_default = help_default 455 | end 456 | 457 | attr_reader :help_default 458 | 459 | def config_type 460 | 'package' 461 | end 462 | 463 | private 464 | 465 | def check(val) 466 | unless File.dir?("packages/#{val}") 467 | setup_rb_error "config: no such package: #{val}" 468 | end 469 | val 470 | end 471 | end 472 | 473 | class MetaConfigEnvironment 474 | def initialize(config, installer) 475 | @config = config 476 | @installer = installer 477 | end 478 | 479 | def config_names 480 | @config.names 481 | end 482 | 483 | def config?(name) 484 | @config.key?(name) 485 | end 486 | 487 | def bool_config?(name) 488 | @config.lookup(name).config_type == 'bool' 489 | end 490 | 491 | def path_config?(name) 492 | @config.lookup(name).config_type == 'path' 493 | end 494 | 495 | def value_config?(name) 496 | @config.lookup(name).config_type != 'exec' 497 | end 498 | 499 | def add_config(item) 500 | @config.add item 501 | end 502 | 503 | def add_bool_config(name, default, desc) 504 | @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) 505 | end 506 | 507 | def add_path_config(name, default, desc) 508 | @config.add PathItem.new(name, 'path', default, desc) 509 | end 510 | 511 | def set_config_default(name, default) 512 | @config.lookup(name).default = default 513 | end 514 | 515 | def remove_config(name) 516 | @config.remove(name) 517 | end 518 | 519 | # For only multipackage 520 | def packages 521 | raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer 522 | @installer.packages 523 | end 524 | 525 | # For only multipackage 526 | def declare_packages(list) 527 | raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer 528 | @installer.packages = list 529 | end 530 | end 531 | 532 | end # class ConfigTable 533 | 534 | 535 | # This module requires: #verbose?, #no_harm? 536 | module FileOperations 537 | 538 | def mkdir_p(dirname, prefix = nil) 539 | dirname = prefix + File.expand_path(dirname) if prefix 540 | $stderr.puts "mkdir -p #{dirname}" if verbose? 541 | return if no_harm? 542 | 543 | # Does not check '/', it's too abnormal. 544 | dirs = File.expand_path(dirname).split(%r<(?=/)>) 545 | if /\A[a-z]:\z/i =~ dirs[0] 546 | disk = dirs.shift 547 | dirs[0] = disk + dirs[0] 548 | end 549 | dirs.each_index do |idx| 550 | path = dirs[0..idx].join('') 551 | Dir.mkdir path unless File.dir?(path) 552 | end 553 | end 554 | 555 | def rm_f(path) 556 | $stderr.puts "rm -f #{path}" if verbose? 557 | return if no_harm? 558 | force_remove_file path 559 | end 560 | 561 | def rm_rf(path) 562 | $stderr.puts "rm -rf #{path}" if verbose? 563 | return if no_harm? 564 | remove_tree path 565 | end 566 | 567 | def remove_tree(path) 568 | if File.symlink?(path) 569 | remove_file path 570 | elsif File.dir?(path) 571 | remove_tree0 path 572 | else 573 | force_remove_file path 574 | end 575 | end 576 | 577 | def remove_tree0(path) 578 | Dir.foreach(path) do |ent| 579 | next if ent == '.' 580 | next if ent == '..' 581 | entpath = "#{path}/#{ent}" 582 | if File.symlink?(entpath) 583 | remove_file entpath 584 | elsif File.dir?(entpath) 585 | remove_tree0 entpath 586 | else 587 | force_remove_file entpath 588 | end 589 | end 590 | begin 591 | Dir.rmdir path 592 | rescue Errno::ENOTEMPTY 593 | # directory may not be empty 594 | end 595 | end 596 | 597 | def move_file(src, dest) 598 | force_remove_file dest 599 | begin 600 | File.rename src, dest 601 | rescue 602 | File.open(dest, 'wb') {|f| 603 | f.write File.binread(src) 604 | } 605 | File.chmod File.stat(src).mode, dest 606 | File.unlink src 607 | end 608 | end 609 | 610 | def force_remove_file(path) 611 | begin 612 | remove_file path 613 | rescue 614 | end 615 | end 616 | 617 | def remove_file(path) 618 | File.chmod 0777, path 619 | File.unlink path 620 | end 621 | 622 | def install(from, dest, mode, prefix = nil) 623 | $stderr.puts "install #{from} #{dest}" if verbose? 624 | return if no_harm? 625 | 626 | realdest = prefix ? prefix + File.expand_path(dest) : dest 627 | realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) 628 | str = File.binread(from) 629 | if diff?(str, realdest) 630 | verbose_off { 631 | rm_f realdest if File.exist?(realdest) 632 | } 633 | File.open(realdest, 'wb') {|f| 634 | f.write str 635 | } 636 | File.chmod mode, realdest 637 | 638 | File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| 639 | if prefix 640 | f.puts realdest.sub(prefix, '') 641 | else 642 | f.puts realdest 643 | end 644 | } 645 | end 646 | end 647 | 648 | def diff?(new_content, path) 649 | return true unless File.exist?(path) 650 | new_content != File.binread(path) 651 | end 652 | 653 | def command(*args) 654 | $stderr.puts args.join(' ') if verbose? 655 | system(*args) or raise RuntimeError, 656 | "system(#{args.map{|a| a.inspect }.join(' ')}) failed" 657 | end 658 | 659 | def ruby(*args) 660 | command config('rubyprog'), *args 661 | end 662 | 663 | def make(task = nil) 664 | command(*[config('makeprog'), task].compact) 665 | end 666 | 667 | def extdir?(dir) 668 | File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") 669 | end 670 | 671 | def files_of(dir) 672 | Dir.open(dir) {|d| 673 | return d.select {|ent| File.file?("#{dir}/#{ent}") } 674 | } 675 | end 676 | 677 | DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) 678 | 679 | def directories_of(dir) 680 | Dir.open(dir) {|d| 681 | return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT 682 | } 683 | end 684 | 685 | end 686 | 687 | 688 | # This module requires: #srcdir_root, #objdir_root, #relpath 689 | module HookScriptAPI 690 | 691 | def get_config(key) 692 | @config[key] 693 | end 694 | 695 | alias config get_config 696 | 697 | # obsolete: use metaconfig to change configuration 698 | def set_config(key, val) 699 | @config[key] = val 700 | end 701 | 702 | # 703 | # srcdir/objdir (works only in the package directory) 704 | # 705 | 706 | def curr_srcdir 707 | "#{srcdir_root()}/#{relpath()}" 708 | end 709 | 710 | def curr_objdir 711 | "#{objdir_root()}/#{relpath()}" 712 | end 713 | 714 | def srcfile(path) 715 | "#{curr_srcdir()}/#{path}" 716 | end 717 | 718 | def srcexist?(path) 719 | File.exist?(srcfile(path)) 720 | end 721 | 722 | def srcdirectory?(path) 723 | File.dir?(srcfile(path)) 724 | end 725 | 726 | def srcfile?(path) 727 | File.file?(srcfile(path)) 728 | end 729 | 730 | def srcentries(path = '.') 731 | Dir.open("#{curr_srcdir()}/#{path}") {|d| 732 | return d.to_a - %w(. ..) 733 | } 734 | end 735 | 736 | def srcfiles(path = '.') 737 | srcentries(path).select {|fname| 738 | File.file?(File.join(curr_srcdir(), path, fname)) 739 | } 740 | end 741 | 742 | def srcdirectories(path = '.') 743 | srcentries(path).select {|fname| 744 | File.dir?(File.join(curr_srcdir(), path, fname)) 745 | } 746 | end 747 | 748 | end 749 | 750 | 751 | class ToplevelInstaller 752 | 753 | Version = '3.4.1' 754 | Copyright = 'Copyright (c) 2000-2005 Minero Aoki' 755 | 756 | TASKS = [ 757 | [ 'all', 'do config, setup, then install' ], 758 | [ 'config', 'saves your configurations' ], 759 | [ 'show', 'shows current configuration' ], 760 | [ 'setup', 'compiles ruby extentions and others' ], 761 | [ 'install', 'installs files' ], 762 | [ 'test', 'run all tests in test/' ], 763 | [ 'clean', "does `make clean' for each extention" ], 764 | [ 'distclean',"does `make distclean' for each extention" ] 765 | ] 766 | 767 | def ToplevelInstaller.invoke 768 | config = ConfigTable.new(load_rbconfig()) 769 | config.load_standard_entries 770 | config.load_multipackage_entries if multipackage? 771 | config.fixup 772 | klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) 773 | klass.new(File.dirname($0), config).invoke 774 | end 775 | 776 | def ToplevelInstaller.multipackage? 777 | File.dir?(File.dirname($0) + '/packages') 778 | end 779 | 780 | def ToplevelInstaller.load_rbconfig 781 | if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } 782 | ARGV.delete(arg) 783 | load File.expand_path(arg.split(/=/, 2)[1]) 784 | $".push 'rbconfig.rb' 785 | else 786 | require 'rbconfig' 787 | end 788 | ::Config::CONFIG 789 | end 790 | 791 | def initialize(ardir_root, config) 792 | @ardir = File.expand_path(ardir_root) 793 | @config = config 794 | # cache 795 | @valid_task_re = nil 796 | end 797 | 798 | def config(key) 799 | @config[key] 800 | end 801 | 802 | def inspect 803 | "#<#{self.class} #{__id__()}>" 804 | end 805 | 806 | def invoke 807 | run_metaconfigs 808 | case task = parsearg_global() 809 | when nil, 'all' 810 | parsearg_config 811 | init_installers 812 | exec_config 813 | exec_setup 814 | exec_install 815 | else 816 | case task 817 | when 'config', 'test' 818 | ; 819 | when 'clean', 'distclean' 820 | @config.load_savefile if File.exist?(@config.savefile) 821 | else 822 | @config.load_savefile 823 | end 824 | __send__ "parsearg_#{task}" 825 | init_installers 826 | __send__ "exec_#{task}" 827 | end 828 | end 829 | 830 | def run_metaconfigs 831 | @config.load_script "#{@ardir}/metaconfig" 832 | end 833 | 834 | def init_installers 835 | @installer = Installer.new(@config, @ardir, File.expand_path('.')) 836 | end 837 | 838 | # 839 | # Hook Script API bases 840 | # 841 | 842 | def srcdir_root 843 | @ardir 844 | end 845 | 846 | def objdir_root 847 | '.' 848 | end 849 | 850 | def relpath 851 | '.' 852 | end 853 | 854 | # 855 | # Option Parsing 856 | # 857 | 858 | def parsearg_global 859 | while arg = ARGV.shift 860 | case arg 861 | when /\A\w+\z/ 862 | setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) 863 | return arg 864 | when '-q', '--quiet' 865 | @config.verbose = false 866 | when '--verbose' 867 | @config.verbose = true 868 | when '--help' 869 | print_usage $stdout 870 | exit 0 871 | when '--version' 872 | puts "#{File.basename($0)} version #{Version}" 873 | exit 0 874 | when '--copyright' 875 | puts Copyright 876 | exit 0 877 | else 878 | setup_rb_error "unknown global option '#{arg}'" 879 | end 880 | end 881 | nil 882 | end 883 | 884 | def valid_task?(t) 885 | valid_task_re() =~ t 886 | end 887 | 888 | def valid_task_re 889 | @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ 890 | end 891 | 892 | def parsearg_no_options 893 | unless ARGV.empty? 894 | task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) 895 | setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" 896 | end 897 | end 898 | 899 | alias parsearg_show parsearg_no_options 900 | alias parsearg_setup parsearg_no_options 901 | alias parsearg_test parsearg_no_options 902 | alias parsearg_clean parsearg_no_options 903 | alias parsearg_distclean parsearg_no_options 904 | 905 | def parsearg_config 906 | evalopt = [] 907 | set = [] 908 | @config.config_opt = [] 909 | while i = ARGV.shift 910 | if /\A--?\z/ =~ i 911 | @config.config_opt = ARGV.dup 912 | break 913 | end 914 | name, value = *@config.parse_opt(i) 915 | if @config.value_config?(name) 916 | @config[name] = value 917 | else 918 | evalopt.push [name, value] 919 | end 920 | set.push name 921 | end 922 | evalopt.each do |name, value| 923 | @config.lookup(name).evaluate value, @config 924 | end 925 | # Check if configuration is valid 926 | set.each do |n| 927 | @config[n] if @config.value_config?(n) 928 | end 929 | end 930 | 931 | def parsearg_install 932 | @config.no_harm = false 933 | @config.install_prefix = '' 934 | while a = ARGV.shift 935 | case a 936 | when '--no-harm' 937 | @config.no_harm = true 938 | when /\A--prefix=/ 939 | path = a.split(/=/, 2)[1] 940 | path = File.expand_path(path) unless path[0,1] == '/' 941 | @config.install_prefix = path 942 | else 943 | setup_rb_error "install: unknown option #{a}" 944 | end 945 | end 946 | end 947 | 948 | def print_usage(out) 949 | out.puts 'Typical Installation Procedure:' 950 | out.puts " $ ruby #{File.basename $0} config" 951 | out.puts " $ ruby #{File.basename $0} setup" 952 | out.puts " # ruby #{File.basename $0} install (may require root privilege)" 953 | out.puts 954 | out.puts 'Detailed Usage:' 955 | out.puts " ruby #{File.basename $0} " 956 | out.puts " ruby #{File.basename $0} [] []" 957 | 958 | fmt = " %-24s %s\n" 959 | out.puts 960 | out.puts 'Global options:' 961 | out.printf fmt, '-q,--quiet', 'suppress message outputs' 962 | out.printf fmt, ' --verbose', 'output messages verbosely' 963 | out.printf fmt, ' --help', 'print this message' 964 | out.printf fmt, ' --version', 'print version and quit' 965 | out.printf fmt, ' --copyright', 'print copyright and quit' 966 | out.puts 967 | out.puts 'Tasks:' 968 | TASKS.each do |name, desc| 969 | out.printf fmt, name, desc 970 | end 971 | 972 | fmt = " %-24s %s [%s]\n" 973 | out.puts 974 | out.puts 'Options for CONFIG or ALL:' 975 | @config.each do |item| 976 | out.printf fmt, item.help_opt, item.description, item.help_default 977 | end 978 | out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" 979 | out.puts 980 | out.puts 'Options for INSTALL:' 981 | out.printf fmt, '--no-harm', 'only display what to do if given', 'off' 982 | out.printf fmt, '--prefix=path', 'install path prefix', '' 983 | out.puts 984 | end 985 | 986 | # 987 | # Task Handlers 988 | # 989 | 990 | def exec_config 991 | @installer.exec_config 992 | @config.save # must be final 993 | end 994 | 995 | def exec_setup 996 | @installer.exec_setup 997 | end 998 | 999 | def exec_install 1000 | @installer.exec_install 1001 | end 1002 | 1003 | def exec_test 1004 | @installer.exec_test 1005 | end 1006 | 1007 | def exec_show 1008 | @config.each do |i| 1009 | printf "%-20s %s\n", i.name, i.value if i.value? 1010 | end 1011 | end 1012 | 1013 | def exec_clean 1014 | @installer.exec_clean 1015 | end 1016 | 1017 | def exec_distclean 1018 | @installer.exec_distclean 1019 | end 1020 | 1021 | end # class ToplevelInstaller 1022 | 1023 | 1024 | class ToplevelInstallerMulti < ToplevelInstaller 1025 | 1026 | include FileOperations 1027 | 1028 | def initialize(ardir_root, config) 1029 | super 1030 | @packages = directories_of("#{@ardir}/packages") 1031 | raise 'no package exists' if @packages.empty? 1032 | @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) 1033 | end 1034 | 1035 | def run_metaconfigs 1036 | @config.load_script "#{@ardir}/metaconfig", self 1037 | @packages.each do |name| 1038 | @config.load_script "#{@ardir}/packages/#{name}/metaconfig" 1039 | end 1040 | end 1041 | 1042 | attr_reader :packages 1043 | 1044 | def packages=(list) 1045 | raise 'package list is empty' if list.empty? 1046 | list.each do |name| 1047 | raise "directory packages/#{name} does not exist"\ 1048 | unless File.dir?("#{@ardir}/packages/#{name}") 1049 | end 1050 | @packages = list 1051 | end 1052 | 1053 | def init_installers 1054 | @installers = {} 1055 | @packages.each do |pack| 1056 | @installers[pack] = Installer.new(@config, 1057 | "#{@ardir}/packages/#{pack}", 1058 | "packages/#{pack}") 1059 | end 1060 | with = extract_selection(config('with')) 1061 | without = extract_selection(config('without')) 1062 | @selected = @installers.keys.select {|name| 1063 | (with.empty? or with.include?(name)) \ 1064 | and not without.include?(name) 1065 | } 1066 | end 1067 | 1068 | def extract_selection(list) 1069 | a = list.split(/,/) 1070 | a.each do |name| 1071 | setup_rb_error "no such package: #{name}" unless @installers.key?(name) 1072 | end 1073 | a 1074 | end 1075 | 1076 | def print_usage(f) 1077 | super 1078 | f.puts 'Inluded packages:' 1079 | f.puts ' ' + @packages.sort.join(' ') 1080 | f.puts 1081 | end 1082 | 1083 | # 1084 | # Task Handlers 1085 | # 1086 | 1087 | def exec_config 1088 | run_hook 'pre-config' 1089 | each_selected_installers {|inst| inst.exec_config } 1090 | run_hook 'post-config' 1091 | @config.save # must be final 1092 | end 1093 | 1094 | def exec_setup 1095 | run_hook 'pre-setup' 1096 | each_selected_installers {|inst| inst.exec_setup } 1097 | run_hook 'post-setup' 1098 | end 1099 | 1100 | def exec_install 1101 | run_hook 'pre-install' 1102 | each_selected_installers {|inst| inst.exec_install } 1103 | run_hook 'post-install' 1104 | end 1105 | 1106 | def exec_test 1107 | run_hook 'pre-test' 1108 | each_selected_installers {|inst| inst.exec_test } 1109 | run_hook 'post-test' 1110 | end 1111 | 1112 | def exec_clean 1113 | rm_f @config.savefile 1114 | run_hook 'pre-clean' 1115 | each_selected_installers {|inst| inst.exec_clean } 1116 | run_hook 'post-clean' 1117 | end 1118 | 1119 | def exec_distclean 1120 | rm_f @config.savefile 1121 | run_hook 'pre-distclean' 1122 | each_selected_installers {|inst| inst.exec_distclean } 1123 | run_hook 'post-distclean' 1124 | end 1125 | 1126 | # 1127 | # lib 1128 | # 1129 | 1130 | def each_selected_installers 1131 | Dir.mkdir 'packages' unless File.dir?('packages') 1132 | @selected.each do |pack| 1133 | $stderr.puts "Processing the package `#{pack}' ..." if verbose? 1134 | Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") 1135 | Dir.chdir "packages/#{pack}" 1136 | yield @installers[pack] 1137 | Dir.chdir '../..' 1138 | end 1139 | end 1140 | 1141 | def run_hook(id) 1142 | @root_installer.run_hook id 1143 | end 1144 | 1145 | # module FileOperations requires this 1146 | def verbose? 1147 | @config.verbose? 1148 | end 1149 | 1150 | # module FileOperations requires this 1151 | def no_harm? 1152 | @config.no_harm? 1153 | end 1154 | 1155 | end # class ToplevelInstallerMulti 1156 | 1157 | 1158 | class Installer 1159 | 1160 | FILETYPES = %w( bin lib ext data conf man ) 1161 | 1162 | include FileOperations 1163 | include HookScriptAPI 1164 | 1165 | def initialize(config, srcroot, objroot) 1166 | @config = config 1167 | @srcdir = File.expand_path(srcroot) 1168 | @objdir = File.expand_path(objroot) 1169 | @currdir = '.' 1170 | end 1171 | 1172 | def inspect 1173 | "#<#{self.class} #{File.basename(@srcdir)}>" 1174 | end 1175 | 1176 | def noop(rel) 1177 | end 1178 | 1179 | # 1180 | # Hook Script API base methods 1181 | # 1182 | 1183 | def srcdir_root 1184 | @srcdir 1185 | end 1186 | 1187 | def objdir_root 1188 | @objdir 1189 | end 1190 | 1191 | def relpath 1192 | @currdir 1193 | end 1194 | 1195 | # 1196 | # Config Access 1197 | # 1198 | 1199 | # module FileOperations requires this 1200 | def verbose? 1201 | @config.verbose? 1202 | end 1203 | 1204 | # module FileOperations requires this 1205 | def no_harm? 1206 | @config.no_harm? 1207 | end 1208 | 1209 | def verbose_off 1210 | begin 1211 | save, @config.verbose = @config.verbose?, false 1212 | yield 1213 | ensure 1214 | @config.verbose = save 1215 | end 1216 | end 1217 | 1218 | # 1219 | # TASK config 1220 | # 1221 | 1222 | def exec_config 1223 | exec_task_traverse 'config' 1224 | end 1225 | 1226 | alias config_dir_bin noop 1227 | alias config_dir_lib noop 1228 | 1229 | def config_dir_ext(rel) 1230 | extconf if extdir?(curr_srcdir()) 1231 | end 1232 | 1233 | alias config_dir_data noop 1234 | alias config_dir_conf noop 1235 | alias config_dir_man noop 1236 | 1237 | def extconf 1238 | ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt 1239 | end 1240 | 1241 | # 1242 | # TASK setup 1243 | # 1244 | 1245 | def exec_setup 1246 | exec_task_traverse 'setup' 1247 | end 1248 | 1249 | def setup_dir_bin(rel) 1250 | files_of(curr_srcdir()).each do |fname| 1251 | update_shebang_line "#{curr_srcdir()}/#{fname}" 1252 | end 1253 | end 1254 | 1255 | alias setup_dir_lib noop 1256 | 1257 | def setup_dir_ext(rel) 1258 | make if extdir?(curr_srcdir()) 1259 | end 1260 | 1261 | alias setup_dir_data noop 1262 | alias setup_dir_conf noop 1263 | alias setup_dir_man noop 1264 | 1265 | def update_shebang_line(path) 1266 | return if no_harm? 1267 | return if config('shebang') == 'never' 1268 | old = Shebang.load(path) 1269 | if old 1270 | $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 1271 | new = new_shebang(old) 1272 | return if new.to_s == old.to_s 1273 | else 1274 | return unless config('shebang') == 'all' 1275 | new = Shebang.new(config('rubypath')) 1276 | end 1277 | $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? 1278 | open_atomic_writer(path) {|output| 1279 | File.open(path, 'rb') {|f| 1280 | f.gets if old # discard 1281 | output.puts new.to_s 1282 | output.print f.read 1283 | } 1284 | } 1285 | end 1286 | 1287 | def new_shebang(old) 1288 | if /\Aruby/ =~ File.basename(old.cmd) 1289 | Shebang.new(config('rubypath'), old.args) 1290 | elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' 1291 | Shebang.new(config('rubypath'), old.args[1..-1]) 1292 | else 1293 | return old unless config('shebang') == 'all' 1294 | Shebang.new(config('rubypath')) 1295 | end 1296 | end 1297 | 1298 | def open_atomic_writer(path, &block) 1299 | tmpfile = File.basename(path) + '.tmp' 1300 | begin 1301 | File.open(tmpfile, 'wb', &block) 1302 | File.rename tmpfile, File.basename(path) 1303 | ensure 1304 | File.unlink tmpfile if File.exist?(tmpfile) 1305 | end 1306 | end 1307 | 1308 | class Shebang 1309 | def Shebang.load(path) 1310 | line = nil 1311 | File.open(path) {|f| 1312 | line = f.gets 1313 | } 1314 | return nil unless /\A#!/ =~ line 1315 | parse(line) 1316 | end 1317 | 1318 | def Shebang.parse(line) 1319 | cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') 1320 | new(cmd, args) 1321 | end 1322 | 1323 | def initialize(cmd, args = []) 1324 | @cmd = cmd 1325 | @args = args 1326 | end 1327 | 1328 | attr_reader :cmd 1329 | attr_reader :args 1330 | 1331 | def to_s 1332 | "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") 1333 | end 1334 | end 1335 | 1336 | # 1337 | # TASK install 1338 | # 1339 | 1340 | def exec_install 1341 | rm_f 'InstalledFiles' 1342 | exec_task_traverse 'install' 1343 | end 1344 | 1345 | def install_dir_bin(rel) 1346 | install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 1347 | end 1348 | 1349 | def install_dir_lib(rel) 1350 | install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 1351 | end 1352 | 1353 | def install_dir_ext(rel) 1354 | return unless extdir?(curr_srcdir()) 1355 | install_files rubyextentions('.'), 1356 | "#{config('sodir')}/#{File.dirname(rel)}", 1357 | 0555 1358 | end 1359 | 1360 | def install_dir_data(rel) 1361 | install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 1362 | end 1363 | 1364 | def install_dir_conf(rel) 1365 | # FIXME: should not remove current config files 1366 | # (rename previous file to .old/.org) 1367 | install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 1368 | end 1369 | 1370 | def install_dir_man(rel) 1371 | install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 1372 | end 1373 | 1374 | def install_files(list, dest, mode) 1375 | mkdir_p dest, @config.install_prefix 1376 | list.each do |fname| 1377 | install fname, dest, mode, @config.install_prefix 1378 | end 1379 | end 1380 | 1381 | def libfiles 1382 | glob_reject(%w(*.y *.output), targetfiles()) 1383 | end 1384 | 1385 | def rubyextentions(dir) 1386 | ents = glob_select("*.#{@config.dllext}", targetfiles()) 1387 | if ents.empty? 1388 | setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" 1389 | end 1390 | ents 1391 | end 1392 | 1393 | def targetfiles 1394 | mapdir(existfiles() - hookfiles()) 1395 | end 1396 | 1397 | def mapdir(ents) 1398 | ents.map {|ent| 1399 | if File.exist?(ent) 1400 | then ent # objdir 1401 | else "#{curr_srcdir()}/#{ent}" # srcdir 1402 | end 1403 | } 1404 | end 1405 | 1406 | # picked up many entries from cvs-1.11.1/src/ignore.c 1407 | JUNK_FILES = %w( 1408 | core RCSLOG tags TAGS .make.state 1409 | .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb 1410 | *~ *.old *.bak *.BAK *.orig *.rej _$* *$ 1411 | 1412 | *.org *.in .* 1413 | ) 1414 | 1415 | def existfiles 1416 | glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) 1417 | end 1418 | 1419 | def hookfiles 1420 | %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| 1421 | %w( config setup install clean ).map {|t| sprintf(fmt, t) } 1422 | }.flatten 1423 | end 1424 | 1425 | def glob_select(pat, ents) 1426 | re = globs2re([pat]) 1427 | ents.select {|ent| re =~ ent } 1428 | end 1429 | 1430 | def glob_reject(pats, ents) 1431 | re = globs2re(pats) 1432 | ents.reject {|ent| re =~ ent } 1433 | end 1434 | 1435 | GLOB2REGEX = { 1436 | '.' => '\.', 1437 | '$' => '\$', 1438 | '#' => '\#', 1439 | '*' => '.*' 1440 | } 1441 | 1442 | def globs2re(pats) 1443 | /\A(?:#{ 1444 | pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') 1445 | })\z/ 1446 | end 1447 | 1448 | # 1449 | # TASK test 1450 | # 1451 | 1452 | TESTDIR = 'test' 1453 | 1454 | def exec_test 1455 | unless File.directory?('test') 1456 | $stderr.puts 'no test in this package' if verbose? 1457 | return 1458 | end 1459 | $stderr.puts 'Running tests...' if verbose? 1460 | begin 1461 | require 'test/unit' 1462 | rescue LoadError 1463 | setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' 1464 | end 1465 | runner = Test::Unit::AutoRunner.new(true) 1466 | runner.to_run << TESTDIR 1467 | runner.run 1468 | end 1469 | 1470 | # 1471 | # TASK clean 1472 | # 1473 | 1474 | def exec_clean 1475 | exec_task_traverse 'clean' 1476 | rm_f @config.savefile 1477 | rm_f 'InstalledFiles' 1478 | end 1479 | 1480 | alias clean_dir_bin noop 1481 | alias clean_dir_lib noop 1482 | alias clean_dir_data noop 1483 | alias clean_dir_conf noop 1484 | alias clean_dir_man noop 1485 | 1486 | def clean_dir_ext(rel) 1487 | return unless extdir?(curr_srcdir()) 1488 | make 'clean' if File.file?('Makefile') 1489 | end 1490 | 1491 | # 1492 | # TASK distclean 1493 | # 1494 | 1495 | def exec_distclean 1496 | exec_task_traverse 'distclean' 1497 | rm_f @config.savefile 1498 | rm_f 'InstalledFiles' 1499 | end 1500 | 1501 | alias distclean_dir_bin noop 1502 | alias distclean_dir_lib noop 1503 | 1504 | def distclean_dir_ext(rel) 1505 | return unless extdir?(curr_srcdir()) 1506 | make 'distclean' if File.file?('Makefile') 1507 | end 1508 | 1509 | alias distclean_dir_data noop 1510 | alias distclean_dir_conf noop 1511 | alias distclean_dir_man noop 1512 | 1513 | # 1514 | # Traversing 1515 | # 1516 | 1517 | def exec_task_traverse(task) 1518 | run_hook "pre-#{task}" 1519 | FILETYPES.each do |type| 1520 | if type == 'ext' and config('without-ext') == 'yes' 1521 | $stderr.puts 'skipping ext/* by user option' if verbose? 1522 | next 1523 | end 1524 | traverse task, type, "#{task}_dir_#{type}" 1525 | end 1526 | run_hook "post-#{task}" 1527 | end 1528 | 1529 | def traverse(task, rel, mid) 1530 | dive_into(rel) { 1531 | run_hook "pre-#{task}" 1532 | __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') 1533 | directories_of(curr_srcdir()).each do |d| 1534 | traverse task, "#{rel}/#{d}", mid 1535 | end 1536 | run_hook "post-#{task}" 1537 | } 1538 | end 1539 | 1540 | def dive_into(rel) 1541 | return unless File.dir?("#{@srcdir}/#{rel}") 1542 | 1543 | dir = File.basename(rel) 1544 | Dir.mkdir dir unless File.dir?(dir) 1545 | prevdir = Dir.pwd 1546 | Dir.chdir dir 1547 | $stderr.puts '---> ' + rel if verbose? 1548 | @currdir = rel 1549 | yield 1550 | Dir.chdir prevdir 1551 | $stderr.puts '<--- ' + rel if verbose? 1552 | @currdir = File.dirname(rel) 1553 | end 1554 | 1555 | def run_hook(id) 1556 | path = [ "#{curr_srcdir()}/#{id}", 1557 | "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } 1558 | return unless path 1559 | begin 1560 | instance_eval File.read(path), path, 1 1561 | rescue 1562 | raise if $DEBUG 1563 | setup_rb_error "hook #{path} failed:\n" + $!.message 1564 | end 1565 | end 1566 | 1567 | end # class Installer 1568 | 1569 | 1570 | class SetupError < StandardError; end 1571 | 1572 | def setup_rb_error(msg) 1573 | raise SetupError, msg 1574 | end 1575 | 1576 | if $0 == __FILE__ 1577 | begin 1578 | ToplevelInstaller.invoke 1579 | rescue SetupError 1580 | raise if $DEBUG 1581 | $stderr.puts $!.message 1582 | $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." 1583 | exit 1 1584 | end 1585 | end 1586 | --------------------------------------------------------------------------------