alloy-microgem 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.rdoc +55 -0
- data/Rakefile +24 -0
- data/TODO +13 -0
- data/bin/zinflate +17 -0
- data/bin//302/265gem +14 -0
- data/lib/microgem.rb +56 -0
- data/lib/microgem/bare_specification.rb +40 -0
- data/lib/microgem/bin_wrapper_emitter.rb +58 -0
- data/lib/microgem/config.rb +96 -0
- data/lib/microgem/dependency.rb +37 -0
- data/lib/microgem/downloader.rb +48 -0
- data/lib/microgem/installer.rb +147 -0
- data/lib/microgem/options_parser.rb +67 -0
- data/lib/microgem/requirement.rb +36 -0
- data/lib/microgem/source.rb +108 -0
- data/lib/microgem/specification.rb +65 -0
- data/lib/microgem/specification_emitter.rb +75 -0
- data/lib/microgem/unpacker.rb +55 -0
- data/lib/microgem/utils.rb +51 -0
- data/lib/microgem/version.rb +35 -0
- data/lib/microgem/yamlable.rb +32 -0
- data/test/bare_specification_test.rb +43 -0
- data/test/bin_wrapper_emitter_test.rb +57 -0
- data/test/config_test.rb +131 -0
- data/test/dependency_test.rb +41 -0
- data/test/downloader_test.rb +100 -0
- data/test/fixtures/gems.github.com +0 -0
- data/test/fixtures/gems.rubyforge.org +0 -0
- data/test/fixtures/gems/rake-0.8.0/rake.rb +1 -0
- data/test/fixtures/gems/rake-0.8.1/rake.rb +1 -0
- data/test/fixtures/gems/test-spec-0.3.0/test-spec.rb +1 -0
- data/test/fixtures/gems/test-spec-mock-0.3.0/test-spec-mock.rb +1 -0
- data/test/fixtures/rails-2.1.1.gemspec +26 -0
- data/test/fixtures/rails-2.1.1.gemspec.marshal +0 -0
- data/test/fixtures/rake-0.8.1.gem +0 -0
- data/test/fixtures/rake-0.8.1.gemspec +20 -0
- data/test/fixtures/rake-0.8.1.gemspec.marshal +0 -0
- data/test/fixtures/rake-0.8.1.gemspec.rz +2 -0
- data/test/fixtures/specs.4.8.gz +0 -0
- data/test/installer_test.rb +198 -0
- data/test/microgem_test.rb +34 -0
- data/test/options_parser_test.rb +36 -0
- data/test/requirement_test.rb +40 -0
- data/test/source_test.rb +153 -0
- data/test/specification_emitter_test.rb +139 -0
- data/test/specification_test.rb +45 -0
- data/test/test_helper.rb +71 -0
- data/test/unpacker_test.rb +91 -0
- data/test/utils_test.rb +42 -0
- data/test/version_test.rb +27 -0
- data/test/yamlable_test.rb +15 -0
- 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
|