botanicus-gemcutter 0.2.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.
@@ -0,0 +1,115 @@
1
+ require 'rubygems/local_remote_options'
2
+
3
+ class Gem::AbstractCommand < Gem::Command
4
+ include Gem::LocalRemoteOptions
5
+
6
+ URL = "http://gemcutter.org"
7
+
8
+ def gemcutter_url
9
+ ENV['GEMCUTTER_URL'] || 'https://gemcutter.org'
10
+ end
11
+
12
+ def setup
13
+ use_proxy! if http_proxy
14
+ sign_in unless api_key
15
+ end
16
+
17
+ def sign_in
18
+ say "Enter your Gemcutter credentials. Don't have an account yet? Create one at #{URL}/sign_up"
19
+
20
+ email = ask("Email: ")
21
+ password = ask_for_password("Password: ")
22
+
23
+ response = make_request(:get, "api_key") do |request|
24
+ request.basic_auth email, password
25
+ end
26
+
27
+ case response
28
+ when Net::HTTPSuccess
29
+ self.api_key = response.body
30
+ say "Signed in. Your api key has been stored in ~/.gem/credentials"
31
+ else
32
+ say response.body
33
+ terminate_interaction
34
+ end
35
+ end
36
+
37
+ def credentials_path
38
+ File.join(Gem.user_home, '.gem', 'credentials')
39
+ end
40
+
41
+ def api_key
42
+ Gem.configuration.load_file(credentials_path)[:rubygems_api_key]
43
+ end
44
+
45
+ def api_key=(api_key)
46
+ config = Gem.configuration.load_file(credentials_path).merge(:rubygems_api_key => api_key)
47
+
48
+ dirname = File.dirname(credentials_path)
49
+ Dir.mkdir(dirname) unless File.exists?(dirname)
50
+
51
+ File.open(credentials_path, 'w') do |f|
52
+ f.write config.to_yaml
53
+ end
54
+
55
+ @rubygems_api_key = api_key
56
+ end
57
+
58
+ def make_request(method, path)
59
+ require 'net/http'
60
+
61
+ url = URI.parse("#{gemcutter_url}/api/v1/#{path}")
62
+
63
+ http = proxy_class.new(url.host, url.port)
64
+
65
+ if url.scheme == 'https'
66
+ require 'net/https'
67
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
68
+ http.use_ssl = true
69
+ end
70
+
71
+ request_method =
72
+ case method
73
+ when :get
74
+ proxy_class::Get
75
+ when :post
76
+ proxy_class::Post
77
+ when :put
78
+ proxy_class::Put
79
+ when :delete
80
+ proxy_class::Delete
81
+ else
82
+ raise ArgumentError
83
+ end
84
+
85
+ request = request_method.new(url.path)
86
+ request.add_field "User-Agent", "Gemcutter/0.2.0"
87
+
88
+ yield request if block_given?
89
+ http.request(request)
90
+ end
91
+
92
+ def use_proxy!
93
+ proxy_uri = http_proxy
94
+ @proxy_class = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
95
+ end
96
+
97
+ def proxy_class
98
+ @proxy_class || Net::HTTP
99
+ end
100
+
101
+ # @return [URI, nil] the HTTP-proxy as a URI if set; +nil+ otherwise
102
+ def http_proxy
103
+ proxy = Gem.configuration[:http_proxy] || ENV['http_proxy'] || ENV['HTTP_PROXY']
104
+ return nil if proxy.nil? || proxy == :no_proxy
105
+ URI.parse(proxy)
106
+ end
107
+
108
+ def ask_for_password(message)
109
+ system "stty -echo"
110
+ password = ask(message)
111
+ system "stty echo"
112
+ ui.say("\n")
113
+ password
114
+ end
115
+ end
@@ -0,0 +1,14 @@
1
+ class Gem::Commands::MigrateCommand < Gem::AbstractCommand
2
+ def description
3
+ 'Deprecate method for migrating a gem you own from Rubyforge to Gemcutter.'
4
+ end
5
+
6
+ def initialize
7
+ super 'migrate', description
8
+ end
9
+
10
+ def execute
11
+ say "This command is deprecated, RubyForge accounts/ownerships have been transferred to Gemcutter."
12
+ say "Please see http://gemcutter.org/pages/migrate for more information"
13
+ end
14
+ end
@@ -0,0 +1,89 @@
1
+ class Gem::Commands::OwnerCommand < Gem::AbstractCommand
2
+ def description
3
+ 'Manage gem owners on Gemcutter.'
4
+ end
5
+
6
+ def initialize
7
+ super 'owner', description
8
+ defaults.merge!(:add => [], :remove => [])
9
+
10
+ add_option('-a', '--add EMAIL', 'Add an owner') do |value, options|
11
+ options[:add] << value
12
+ end
13
+
14
+ add_option('-r', '--remove EMAIL', 'Remove an owner') do |value, options|
15
+ options[:remove] << value
16
+ end
17
+ end
18
+
19
+ def execute
20
+ setup
21
+ name = get_one_gem_name
22
+
23
+ add_owners name, options[:add]
24
+ remove_owners name, options[:remove]
25
+ show_owners name
26
+ end
27
+
28
+ def add_owners(name, owners)
29
+ owners.each do |owner|
30
+ response = make_request(:post, "gems/#{name}/owners.json") do |request|
31
+ request.set_form_data("email" => owner)
32
+ request.add_field("Authorization", api_key)
33
+ end
34
+
35
+ case response
36
+ when Net::HTTPSuccess
37
+ say "Added owner: #{owner}"
38
+ else
39
+ say "Error adding owner: #{owner}"
40
+ end
41
+ end
42
+ end
43
+
44
+ def remove_owners(name, owners)
45
+ owners.each do |owner|
46
+ response = make_request(:delete, "gems/#{name}/owners.json") do |request|
47
+ request.set_form_data(:email => owner)
48
+ request.add_field("Authorization", api_key)
49
+ end
50
+
51
+ case response
52
+ when Net::HTTPSuccess
53
+ say "Removed owner: #{owner}"
54
+ else
55
+ say "Error removing owner: #{owner}"
56
+ end
57
+ end end
58
+
59
+ def show_owners(name)
60
+ require 'json/pure'
61
+ response = make_request(:get, "gems/#{name}/owners.json") do |request|
62
+ request.add_field("Authorization", api_key)
63
+ end
64
+
65
+ case response
66
+ when Net::HTTPSuccess
67
+ begin
68
+ owners = JSON.parse(response.body)
69
+
70
+ say "Owners for gem: #{name}"
71
+ owners.each do |owner|
72
+ say "- #{owner['email']}"
73
+ end
74
+ rescue JSON::ParserError => json_error
75
+ say "There was a problem parsing the data: #{json_error}"
76
+ terminate_interaction
77
+ end
78
+ when Net::HTTPNotFound
79
+ say "This gem is currently not hosted on Gemcutter."
80
+ terminate_interaction
81
+ when Net::HTTPUnauthorized
82
+ say "You do not have permission to manage this gem."
83
+ terminate_interaction
84
+ else
85
+ say "There was a problem processing your request."
86
+ terminate_interaction
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,39 @@
1
+ class Gem::Commands::PushCommand < Gem::AbstractCommand
2
+
3
+ def description
4
+ 'Push a gem up to Gemcutter'
5
+ end
6
+
7
+ def arguments
8
+ "GEM built gem to push up"
9
+ end
10
+
11
+ def usage
12
+ "#{program_name} GEM"
13
+ end
14
+
15
+ def initialize
16
+ super 'push', description
17
+ add_proxy_option
18
+ end
19
+
20
+ def execute
21
+ setup
22
+ send_gem
23
+ end
24
+
25
+ def send_gem
26
+ say "Pushing gem to Gemcutter..."
27
+
28
+ name = get_one_gem_name
29
+ response = make_request(:post, "gems") do |request|
30
+ request.body = File.open(name, 'rb'){|io| io.read }
31
+ request.add_field("Content-Length", request.body.size)
32
+ request.add_field("Content-Type", "application/octet-stream")
33
+ request.add_field("Authorization", api_key)
34
+ end
35
+
36
+ say response.body
37
+ end
38
+
39
+ end
@@ -0,0 +1,13 @@
1
+ class Gem::Commands::TumbleCommand < Gem::AbstractCommand
2
+ def description
3
+ "Deprecated method of upgrading to Gemcutter.org for gem downloads"
4
+ end
5
+
6
+ def initialize
7
+ super 'tumble', description
8
+ end
9
+
10
+ def execute
11
+ say "This command is deprecated, Gemcutter.org is the primary source for gems."
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
+
3
+ require 'rubygems/command_manager'
4
+ require 'commands/abstract_command'
5
+
6
+ %w[migrate owner push tumble].each do |command|
7
+ require "commands/#{command}"
8
+ Gem::CommandManager.instance.register_command command.to_sym
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require "#{File.dirname(__FILE__)}/../../vendor/bundler_gems/environment"
5
+
6
+ require 'shoulda'
7
+ begin
8
+ require 'redgreen'
9
+ rescue LoadError
10
+ end
11
+ require 'active_support'
12
+ require 'active_support/test_case'
13
+ require 'fakeweb'
14
+ require 'rr'
15
+
16
+ FakeWeb.allow_net_connect = false
17
+
18
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), ".."))
19
+
20
+ require "rubygems_plugin"
21
+
22
+ class CommandTest < ActiveSupport::TestCase
23
+ include RR::Adapters::TestUnit unless include?(RR::Adapters::TestUnit)
24
+ end
25
+
26
+ def stub_config(config)
27
+ file = Gem::ConfigFile.new({})
28
+ config.each { |key, value| file[key] = value }
29
+ stub(Gem).configuration { file }
30
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: botanicus-gemcutter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Nick Quaranto
8
+ - Jakub Stastny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-12-10 00:00:00 +00:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: json_pure
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ description: Adds several commands for using gemcutter.org, such as pushing new gems, migrating gems from RubyForge, and more.
27
+ email: nick@quaran.to
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - lib/commands/abstract_command.rb
36
+ - lib/commands/migrate.rb
37
+ - lib/commands/owner.rb
38
+ - lib/commands/push.rb
39
+ - lib/commands/tumble.rb
40
+ - lib/rubygems_plugin.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/qrush/gemcutter
43
+ licenses: []
44
+
45
+ post_install_message: |+
46
+
47
+ ========================================================================
48
+
49
+ Thanks for installing Gemcutter! You can now run:
50
+
51
+ gem push publish your gems for the world to use and enjoy
52
+ gem owner allow/disallow others to push to your gems
53
+
54
+ ========================================================================
55
+
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 1.3.5
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project: gemcutter
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Commands to interact with gemcutter.org
79
+ test_files:
80
+ - test/command_helper.rb