alloy-microgem 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/LICENSE +21 -0
  2. data/README.rdoc +55 -0
  3. data/Rakefile +24 -0
  4. data/TODO +13 -0
  5. data/bin/zinflate +17 -0
  6. data/bin//302/265gem +14 -0
  7. data/lib/microgem.rb +56 -0
  8. data/lib/microgem/bare_specification.rb +40 -0
  9. data/lib/microgem/bin_wrapper_emitter.rb +58 -0
  10. data/lib/microgem/config.rb +96 -0
  11. data/lib/microgem/dependency.rb +37 -0
  12. data/lib/microgem/downloader.rb +48 -0
  13. data/lib/microgem/installer.rb +147 -0
  14. data/lib/microgem/options_parser.rb +67 -0
  15. data/lib/microgem/requirement.rb +36 -0
  16. data/lib/microgem/source.rb +108 -0
  17. data/lib/microgem/specification.rb +65 -0
  18. data/lib/microgem/specification_emitter.rb +75 -0
  19. data/lib/microgem/unpacker.rb +55 -0
  20. data/lib/microgem/utils.rb +51 -0
  21. data/lib/microgem/version.rb +35 -0
  22. data/lib/microgem/yamlable.rb +32 -0
  23. data/test/bare_specification_test.rb +43 -0
  24. data/test/bin_wrapper_emitter_test.rb +57 -0
  25. data/test/config_test.rb +131 -0
  26. data/test/dependency_test.rb +41 -0
  27. data/test/downloader_test.rb +100 -0
  28. data/test/fixtures/gems.github.com +0 -0
  29. data/test/fixtures/gems.rubyforge.org +0 -0
  30. data/test/fixtures/gems/rake-0.8.0/rake.rb +1 -0
  31. data/test/fixtures/gems/rake-0.8.1/rake.rb +1 -0
  32. data/test/fixtures/gems/test-spec-0.3.0/test-spec.rb +1 -0
  33. data/test/fixtures/gems/test-spec-mock-0.3.0/test-spec-mock.rb +1 -0
  34. data/test/fixtures/rails-2.1.1.gemspec +26 -0
  35. data/test/fixtures/rails-2.1.1.gemspec.marshal +0 -0
  36. data/test/fixtures/rake-0.8.1.gem +0 -0
  37. data/test/fixtures/rake-0.8.1.gemspec +20 -0
  38. data/test/fixtures/rake-0.8.1.gemspec.marshal +0 -0
  39. data/test/fixtures/rake-0.8.1.gemspec.rz +2 -0
  40. data/test/fixtures/specs.4.8.gz +0 -0
  41. data/test/installer_test.rb +198 -0
  42. data/test/microgem_test.rb +34 -0
  43. data/test/options_parser_test.rb +36 -0
  44. data/test/requirement_test.rb +40 -0
  45. data/test/source_test.rb +153 -0
  46. data/test/specification_emitter_test.rb +139 -0
  47. data/test/specification_test.rb +45 -0
  48. data/test/test_helper.rb +71 -0
  49. data/test/unpacker_test.rb +91 -0
  50. data/test/utils_test.rb +42 -0
  51. data/test/version_test.rb +27 -0
  52. data/test/yamlable_test.rb +15 -0
  53. metadata +114 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) <2009> Eloy Duran <eloy.de.enige@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ == MicroGem
2
+ The aim of this project is, at first, to create a re-implementation of the
3
+ RubyGems +install+ command, which should be easier to get up and running on
4
+ Ruby implementations such as MacRuby.
5
+
6
+ See the TODO file for a list of todo's.
7
+
8
+ === Installation
9
+
10
+ $ sudo gem install alloy-microgem -s http://gems.github.com
11
+
12
+ === µgem banner
13
+ Microgem is an unsophisticated package manager for Ruby.
14
+ And the first commandline utility to start with a multibyte character; µ
15
+
16
+ Usage:
17
+ µgem [command] [arguments…] [options…]
18
+
19
+ Example:
20
+ µgem install rake
21
+ µgem install rails --force
22
+ µgem cache update --debug
23
+
24
+ Options:
25
+ --debug Raises the log level to `debug'
26
+ --force Forces a command
27
+ --simple-downloader Use curl to download files instead of Net::HTTP
28
+ --simple-unpacker Use external tools to unpack archives instead of Zlib
29
+ --simple Enables --simple-downloader and --simple-unpacker
30
+ --help Show help information
31
+
32
+ === Development
33
+ The way it's being developed is in a test and RubyGems data driven manner.
34
+ We are using the `quick' marshalled specs, so we use those fixtures to run the tests.
35
+
36
+ ==== Getting started
37
+
38
+ Get the source:
39
+
40
+ $ git clone git://github.com/alloy/microgem.git
41
+
42
+ Install a gem:
43
+
44
+ $ ./bin/µgem install rake
45
+
46
+ Note that unless you set the PRODUCTION environment variable everything is installed in ./tmp.
47
+
48
+ The current default sources are rubyforge and github.
49
+
50
+ === Goals
51
+ * Install gems.
52
+ * Small.
53
+ * Test driven.
54
+ * Clean room design.
55
+ * Naive, no more code than necessary should be written. (YAGNI)
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rake/testtask'
2
+
3
+ HOME = File.expand_path('../tmp/gem_home', __FILE__)
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/*_test.rb']
7
+ end
8
+
9
+ task :default => :test
10
+
11
+ desc "Cleans the temporary development directory"
12
+ task :clean do
13
+ rm_rf 'tmp'
14
+ rm_rf 'pkg'
15
+ end
16
+
17
+ directory 'pkg'
18
+
19
+ desc "Builds and installs the gem"
20
+ task :install => :pkg do
21
+ # TODO: install gem with µgem, this is why we don't use the rake gem tasks.
22
+ sh 'gem build microgem.gemspec && mv microgem-*.gem pkg/'
23
+ sh 'cd pkg && sudo gem install microgem-*.gem'
24
+ end
data/TODO ADDED
@@ -0,0 +1,13 @@
1
+ === TODO (in order of priority)
2
+ * Add support for <tt>~/.gemrc</tt>
3
+ * Add support for configuring multiple gem servers.
4
+ * Remove any unnecessary “complex” code.
5
+ * Bring back to _one_ file, or at least less files if it doesn't harm
6
+ readability.
7
+
8
+ ==== Laurents wish list
9
+ * More commands:
10
+ * +uninstall+
11
+ * +search+
12
+ * +update+
13
+ * +list+
data/bin/zinflate ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # TODO: We should probably write a C version of this.
4
+
5
+ require File.expand_path('../../lib/microgem/utils', __FILE__)
6
+ require File.expand_path('../../lib/microgem/unpacker', __FILE__)
7
+
8
+ archive, out_file = ARGV[0], ARGV[1]
9
+
10
+ if archive && out_file
11
+ Gem::Micro::Unpacker.inflate_with_zlib(archive, out_file)
12
+ else
13
+ puts "This is a simple bin file which is able to inflate the .Z/.rz files returned from a gem server."
14
+ puts "This bin can be invoked from microgem with a Ruby which does support zlib."
15
+ puts ''
16
+ puts "Usage: zinflate /path/to/archive.Z /path/to/uncompressed_file"
17
+ end
data/bin//302/265gem ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if defined?(Gem)
4
+ # Hack to make sure we don't run with RubyGems loaded.
5
+ ENV['PRODUCTION'] = 'true'
6
+ exec "#{File.expand_path(__FILE__)} #{ARGV.join(' ')}"
7
+
8
+ else
9
+ # Run the normal operations.
10
+ $:.unshift File.expand_path('../../lib', __FILE__)
11
+ require 'microgem'
12
+
13
+ Gem::Micro.run(ARGV)
14
+ end
data/lib/microgem.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'microgem/yamlable'
2
+ require 'microgem/utils'
3
+
4
+ require 'microgem/bare_specification'
5
+ require 'microgem/bin_wrapper_emitter'
6
+ require 'microgem/config'
7
+ require 'microgem/dependency'
8
+ require 'microgem/downloader'
9
+ require 'microgem/installer'
10
+ require 'microgem/options_parser'
11
+ require 'microgem/requirement'
12
+ require 'microgem/source'
13
+ require 'microgem/specification'
14
+ require 'microgem/specification_emitter'
15
+ require 'microgem/unpacker'
16
+ require 'microgem/version'
17
+
18
+ module Gem
19
+ module Micro
20
+ class << self
21
+ include Utils
22
+
23
+ # The main +run+ method which is used by the µgem script to perform the
24
+ # actions specified by the user.
25
+ def run(arguments)
26
+ parser = OptionsParser.new
27
+ parser.parse(arguments)
28
+ Config.merge!(parser.options)
29
+
30
+ case parser.command
31
+ when 'install'
32
+ gem_spec = Source.gem_spec(parser.arguments.first, Gem::Version[:version => '0'])
33
+ gem_spec.install!
34
+
35
+ when 'sources'
36
+ case parser.arguments.first
37
+ when 'update'
38
+ Source.update!
39
+
40
+ end
41
+ else
42
+ puts parser.banner
43
+ end
44
+ end
45
+
46
+ # Returns an array of all installed gems their directory names,
47
+ # optionally limited to gems matching the given +name+.
48
+ def installed_gem_dirnames(name = nil)
49
+ directories = Dir.glob(File.join(Config.gems_path, '*')).sort
50
+ directories = directories.map { |dir| File.basename(dir) }
51
+
52
+ name.nil? ? directories : directories.select { |dirname| dirname =~ /^#{name}-[\d\.]+/ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,40 @@
1
+ module Gem
2
+ module Micro
3
+ class BareSpecification
4
+ include Utils
5
+
6
+ def initialize(source, name, version)
7
+ @source, @name, @version = source, name, version
8
+ end
9
+
10
+ # Returns the url from where the gemspec should be downloaded.
11
+ def gem_spec_url
12
+ "http://#{@source.host}/quick/Marshal.4.8/#{@name}-#{@version}.gemspec.rz"
13
+ end
14
+
15
+ # Returns the full path to the gemspec file in the temporary work
16
+ # directory.
17
+ def gem_spec_work_file
18
+ File.join(tmpdir, "#{@name}-#{@version}.gemspec")
19
+ end
20
+
21
+ # Returns the full path to the archive containing the gemspec file in the
22
+ # temporary work directory.
23
+ def gem_spec_work_archive_file
24
+ "#{gem_spec_work_file}.rz"
25
+ end
26
+
27
+ # Retrieves the gem spec from gem_spec_url and loads the marshalled data.
28
+ #
29
+ # The returned Gem::Specification instance knows to which
30
+ # Gem::Micro::Source it belongs.
31
+ def gem_spec
32
+ Downloader.get(gem_spec_url, gem_spec_work_archive_file)
33
+ Unpacker.inflate(gem_spec_work_archive_file, gem_spec_work_file)
34
+ gem_spec = Marshal.load(File.read(gem_spec_work_file))
35
+ gem_spec.source = @source
36
+ gem_spec
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ require 'rbconfig'
2
+
3
+ module Gem
4
+ module Micro
5
+ class BinWrapperEmitter
6
+ # Initializes a new BinWrapperEmitter with a +gem_name+ and a +bin_name+.
7
+ def initialize(gem_name, bin_name)
8
+ @gem_name, @bin_name = gem_name, bin_name
9
+ end
10
+
11
+ # Returns the full path to where the bin wrapper script should be
12
+ # created. If Ruby was installed with a prefix or suffix it will be
13
+ # inflected and added to the name of the executable.
14
+ #
15
+ # If the prefix is, for instance, `mac' an executable like +macrake+ will
16
+ # be installed. With a suffix like `19' the name will be +rake19+.
17
+ def bin_wrapper_file
18
+ rbconfig('ruby_install_name').match /^(.*)ruby(.*)$/
19
+ File.join(Config.bin_dir, "#{$1}#{@bin_name}#{$2}")
20
+ end
21
+
22
+ # Creates the bin wrapper script in bin_wrapper_file.
23
+ def create_bin_wrapper!
24
+ Utils.log(:debug, "Creating bin wrapper `#{bin_wrapper_file}'")
25
+ File.open(bin_wrapper_file, 'w') { |f| f << to_ruby }
26
+ File.chmod(0755, bin_wrapper_file)
27
+ end
28
+
29
+ # Returns a string representation of the bin wrapper file.
30
+ def to_ruby
31
+ %{#!#{ File.join(rbconfig('bindir'), rbconfig('ruby_install_name')) }
32
+ #
33
+ # This file was generated by MicroGem (µgem).
34
+ #
35
+ # The application '#{@bin_name}' is installed as part of a gem, and
36
+ # this file is here to facilitate running it.
37
+
38
+ require 'rubygems'
39
+
40
+ version = "> 0"
41
+ if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
42
+ version = $1
43
+ ARGV.shift
44
+ end
45
+
46
+ gem '#{@gem_name}', version
47
+ load '#{@bin_name}'
48
+ }
49
+ end
50
+
51
+ private
52
+
53
+ def rbconfig(key)
54
+ ::Config::CONFIG[key]
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,96 @@
1
+ require 'rbconfig'
2
+
3
+ module Gem
4
+ module Micro
5
+ class Config
6
+ class << self
7
+ include Utils
8
+
9
+ # Returns the full path to the Gem home directory.
10
+ def gem_home
11
+ @gem_home ||= ensure_dir(if ENV['PRODUCTION']
12
+ sitelibdir = ::Config::CONFIG['sitelibdir']
13
+ version = ::Config::CONFIG['ruby_version']
14
+ File.expand_path("../../Gems/#{version}", sitelibdir)
15
+ else
16
+ File.expand_path("../../../tmp/gem_home", __FILE__)
17
+ end)
18
+ end
19
+
20
+ # Returns the full path to the bin directory.
21
+ def bin_dir
22
+ @bin_dir ||= if ENV['PRODUCTION']
23
+ if macruby?
24
+ '/usr/local/bin'
25
+ elsif osx_default_ruby?
26
+ '/usr/bin'
27
+ else
28
+ ::Config::CONFIG['bindir']
29
+ end
30
+ else
31
+ ensure_dir(File.expand_path("../../../tmp/bin", __FILE__))
32
+ end
33
+ end
34
+
35
+ # Returns the full path to the directory where the installed gems are.
36
+ def gems_path
37
+ @gems_path ||= ensure_dir(File.join(gem_home, 'gems'))
38
+ end
39
+
40
+ # Returns the full path to the directory where the installed gem specs
41
+ # are.
42
+ def specifications_path
43
+ @specifications_path ||= ensure_dir(File.join(gem_home, 'specifications'))
44
+ end
45
+
46
+ # Returns the full path to the directory where the gems are cached.
47
+ def cache_path
48
+ @cache_path ||= ensure_dir(File.join(gem_home, 'cache'))
49
+ end
50
+
51
+ # Returns an array of source hosts from which to fetch gems.
52
+ def sources
53
+ %w{ gems.rubyforge.org gems.github.com }
54
+ end
55
+
56
+ attr_writer :log_level, :force, :simple_downloader, :simple_unpacker
57
+
58
+ # Returns the current log level, which is +:info+ or +:debug+.
59
+ def log_level
60
+ @log_level ||= :info
61
+ end
62
+
63
+ # Returns whether or not actions should be forced.
64
+ def force?
65
+ @force ||= false
66
+ end
67
+
68
+ # Returns whether or not to use +curl+ instead of Net::HTTP.
69
+ def simple_downloader?
70
+ @simple_downloader ||= false
71
+ end
72
+
73
+ # Returns whether or not to use the external +xinflate+ instead of
74
+ # Zlib::Inflate.inflate.
75
+ def simple_unpacker?
76
+ @simple_unpacker ||= false
77
+ end
78
+
79
+ # Merges the values from the +options+ hash.
80
+ def merge!(options)
81
+ options.each { |k,v| send("#{k}=", v) }
82
+ end
83
+
84
+ private
85
+
86
+ def osx_default_ruby?
87
+ defined? RUBY_FRAMEWORK_VERSION
88
+ end
89
+
90
+ def macruby?
91
+ defined? MACRUBY_VERSION
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,37 @@
1
+ module Gem
2
+ module Micro
3
+ class GemSpecMissingError < StandardError; end
4
+ end
5
+
6
+ class Dependency < Micro::YAMLable
7
+ attr_reader :name, :version, :version_requirements
8
+
9
+ # Returns whether or not any of the installed gems matches the requirements.
10
+ #
11
+ # For now we just compare against the last one which should be the highest.
12
+ def meets_requirements?
13
+ if dirname = Micro.installed_gem_dirnames(name).last
14
+ Gem::Version.from_gem_dirname(dirname) >= @version_requirements.version
15
+ end
16
+ end
17
+
18
+ # Returns the Gem::Specification instance for this dependency. If the
19
+ # required version is `0' then the latest version is used.
20
+ def gem_spec
21
+ if @gem_spec.nil?
22
+ unless @gem_spec = Micro::Source.gem_spec(@name, @version_requirements.version)
23
+ raise Micro::GemSpecMissingError, "Unable to locate Gem::Specification for Gem::Dependency `#{self}'"
24
+ end
25
+ end
26
+
27
+ @gem_spec
28
+ end
29
+
30
+ # Returns a ‘pretty’ string representation of the Dependency instance:
31
+ #
32
+ # dependency.to_s # => "rake >= 0.8.1"
33
+ def to_s
34
+ "#{name} #{@version_requirements}"
35
+ end
36
+ end
37
+ end