stickler 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +1 -0
  2. data/HISTORY.asciidoc +17 -8
  3. data/LICENSE +13 -54
  4. data/README.asciidoc +29 -5
  5. data/Rakefile +11 -10
  6. data/TODO.asciidoc +6 -0
  7. data/bin/stickler +5 -2
  8. data/examples/fetch-a-gem +6 -0
  9. data/examples/gemcutter_repo.ru +1 -1
  10. data/lib/stickler.rb +1 -1
  11. data/lib/stickler/client.rb +1 -0
  12. data/lib/stickler/client/list.rb +30 -0
  13. data/lib/stickler/client/mirror.rb +5 -5
  14. data/lib/stickler/client/push.rb +1 -1
  15. data/lib/stickler/middleware/gemcutter.rb +2 -2
  16. data/lib/stickler/middleware/helpers.rb +37 -42
  17. data/lib/stickler/middleware/index.rb +51 -19
  18. data/lib/stickler/repository/index.rb +46 -9
  19. data/lib/stickler/repository/local.rb +75 -20
  20. data/lib/stickler/repository/null.rb +0 -2
  21. data/lib/stickler/repository/remote.rb +81 -64
  22. data/lib/stickler/repository/rubygems_authenticator.rb +3 -8
  23. data/lib/stickler/server.rb +1 -1
  24. data/lib/stickler/spec_lite.rb +13 -10
  25. data/lib/stickler/version.rb +2 -2
  26. data/man/stickler.asciidoc +3 -1
  27. data/spec/data/gems/foo-2.0.0a.gem +0 -0
  28. data/spec/index_spec_helpers.rb +71 -0
  29. data/spec/middleware/local_spec.rb +58 -10
  30. data/spec/middleware/not_found_spec.rb +1 -0
  31. data/spec/repository/index_spec.rb +15 -0
  32. data/spec/repository/local_spec.rb +20 -5
  33. data/spec/repository/remote_spec.rb +2 -3
  34. data/spec/spec.opts +1 -1
  35. data/spec/spec_helper.rb +8 -6
  36. data/spec/spec_lite_spec.rb +19 -6
  37. data/tasks/man.rake +1 -1
  38. metadata +74 -40
  39. data/spec/middleware/common_gem_server_helpers.rb +0 -69
  40. data/spec/middleware/index_spec.rb +0 -26
  41. data/spec/middleware/legacy_gem_server_behavior.rb +0 -31
  42. data/spec/middleware/modern_gem_server_behavior.rb +0 -22
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ tmp
15
15
  man/*.xml
16
16
  man/*.1
17
17
  *.gemspec
18
+ work/
@@ -2,19 +2,28 @@ Stickler Changelog
2
2
  ==================
3
3
  Jeremy Hinegardner <jeremy@hinegardner.org>
4
4
 
5
- Version 2.0.1
6
- -------------
5
+ Version 2.1.0 - 2011-03-25
6
+ --------------------------
7
+ * Added 'list' client command
8
+ * Added support for prerelease gems
9
+ * Internal refactoring of how internal repositories are managed
10
+ * Refactored testing and updated to rspec2
11
+ * Switched underlying HTTP client to Excon
12
+ * Change to ISC License
13
+
14
+ Version 2.0.1 - 2010-09-19
15
+ --------------------------
7
16
  * Complete rewrite using Rack and Sinatra
8
17
 
9
- Version 0.1.2
10
- -------------
18
+ Version 0.1.2 - 2009-02-19
19
+ --------------------------
11
20
  * fix compatibility with gems 1.3.1
12
21
 
13
- Version 0.1.1
14
- -------------
22
+ Version 0.1.1 - 2008-10-12
23
+ --------------------------
15
24
  * remove unnecessary require 'progressbar'
16
25
 
17
- Version 0.1.0
18
- -------------
26
+ Version 0.1.0 - 2008-10-10
27
+ --------------------------
19
28
  * http://copiousfreetime.org/articles/2008/10/09/managing-a-gem-repository-with-stickler.html[Managing a Gem Repository with Stickler]
20
29
  * Initial public release
data/LICENSE CHANGED
@@ -1,54 +1,13 @@
1
- Stickler is copyrighted free software by Jeremy Hinegardner
2
- <jeremy at hinegardner dot org>. You can redistribute it and/or modify it under
3
- either the terms of the GPL (see COPYING file), or the conditions below:
4
-
5
- 1. You may make and give away verbatim copies of the source form of the
6
- software without restriction, provided that you duplicate all of the
7
- original copyright notices and associated disclaimers.
8
-
9
- 2. You may modify your copy of the software in any way, provided that
10
- you do at least ONE of the following:
11
-
12
- a) place your modifications in the Public Domain or otherwise
13
- make them Freely Available, such as by posting said
14
- modifications to Usenet or an equivalent medium, or by allowing
15
- the author to include your modifications in the software.
16
-
17
- b) use the modified software only within your corporation or
18
- organization.
19
-
20
- c) rename any non-standard executables so the names do not conflict
21
- with standard executables, which must also be provided.
22
-
23
- d) make other distribution arrangements with the author.
24
-
25
- 3. You may distribute the software in object code or executable
26
- form, provided that you do at least ONE of the following:
27
-
28
- a) distribute the executables and library files of the software,
29
- together with instructions (in the manual page or equivalent)
30
- on where to get the original distribution.
31
-
32
- b) accompany the distribution with the machine-readable source of
33
- the software.
34
-
35
- c) give non-standard executables non-standard names, with
36
- instructions on where to get the original software distribution.
37
-
38
- d) make other distribution arrangements with the author.
39
-
40
- 4. You may modify and include the part of the software into any other
41
- software (possibly commercial). But some files in the distribution
42
- are not written by the author, so that they are not under this terms.
43
-
44
- 5. The scripts and library files supplied as input to or produced as
45
- output from the software do not automatically fall under the
46
- copyright of the software, but belong to whomever generated them,
47
- and may be sold commercially, and may be aggregated with this
48
- software.
49
-
50
- 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
51
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
52
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
- PURPOSE.
54
-
1
+ Copyright (c) 2008-2010, Jeremy Hinegadner
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
@@ -83,12 +83,39 @@ Pushing gem(s) to http://localhost:6789/ ...
83
83
  /Users/jeremy/tmp/gems/stickler-2.0.0.gem -> OK http://localhost:6789/gems/stickler-2.0.0.gem
84
84
  ------------------------------------------------------------------
85
85
 
86
- .Mirror a gem
86
+ .Mirror a gem from upstream
87
87
  ------------------------------------------------------------------
88
88
  % stickler mirror --gem-version 1.4.3 logging
89
89
  Asking http://localhost:6789/ to mirror logging-1.4.3 from rubygems.org : OK -> http://localhost:6789/gems/logging-1.4.3.gem
90
+ % stickler mirror --gem-version 1.16.2 trollop
91
+ Asking http://localhost:6789/ to mirror trollop-1.16.2 from rubygems.org : OK -> http://localhost:6789/gems/trollop-1.16.2.gem
90
92
  ------------------------------------------------------------------
91
93
 
94
+ .Look at all the gems installed in your stickler server
95
+ Open your browser to http://localhost:6789
96
+ -------------------------------
97
+ % launchy http://localhost:6789
98
+ -------------------------------
99
+
100
+ .Install a gem from your new stickler gem server
101
+ ------------------------------------------------------
102
+ % gem install hitimes --source http://localhost:6789/
103
+ ------------------------------------------------------
104
+
105
+ .Configure your servers to globally use your internal stickler gem server
106
+ -----------------------------
107
+ % cat /etc/gemrc
108
+ ---
109
+ :benchmark: false
110
+ :verbose: false
111
+ :update_sources: true
112
+ :bulk_threshold: 1000
113
+ :backtrace: false
114
+ :sources:
115
+ - http://stickler.example.com
116
+ gem: --no-rdoc --no-ri
117
+ -----------------------------
118
+
92
119
 
93
120
  See Also
94
121
  --------
@@ -114,10 +141,7 @@ Credits
114
141
  License
115
142
  -------
116
143
  Copyright (C) 2008-2010 Jeremy Hinegardner
117
-
118
- All rights reserved. Licensed under the same terms as Ruby. No warranty is
119
- provided. See LICENSE and COPYING for details.
120
-
144
+ ISC License, See LICENSE for details
121
145
 
122
146
  Appendix
123
147
  --------
data/Rakefile CHANGED
@@ -21,9 +21,8 @@ Bones {
21
21
  readme_file 'README.asciidoc'
22
22
  ignore_file '.bnsignore'
23
23
  history_file 'HISTORY.asciidoc'
24
- rubyforge.name 'copiousfreetime'
25
24
 
26
- spec.opts << "--color" << "--format specdoc"
25
+ spec.opts << "--color" << "--format documentation"
27
26
 
28
27
  summary 'Stickler is a tool to organize and maintain an internal gem repository.'
29
28
  description <<_
@@ -38,13 +37,15 @@ Primarily, you would want to use Stickler if:
38
37
  _
39
38
 
40
39
 
41
- depend_on 'sinatra', '~> 1.0.0'
42
- depend_on 'addressable', '~> 2.1.2'
43
- depend_on 'resourceful', '~> 1.0.1'
44
- depend_on 'trollop', '~> 1.16.2'
45
- depend_on 'logging', '~> 1.4.3'
40
+ depend_on 'sinatra' , '~> 1.2.1'
41
+ depend_on 'addressable', '~> 2.2.4'
42
+ depend_on 'excon' , '~> 0.5.8'
43
+ depend_on 'trollop' , '~> 1.16.2'
44
+ depend_on 'logging' , '~> 1.5.0'
46
45
 
47
- depend_on 'bones' , '~> 3.4.6', :development => true
48
- depend_on 'rack-test' , '~> 0.5.4', :development => true
49
- depend_on 'bones-extras', '~> 1.2.4', :development => true
46
+ depend_on 'bones' , '~> 3.6.5', :development => true
47
+ depend_on 'rack-test' , '~> 0.5.7', :development => true
48
+ depend_on 'bones-extras', '~> 1.3.0', :development => true
49
+ depend_on 'builder' , '~> 3.0.0', :development => true
50
+ depend_on 'rspec' , '~> 2.5.0', :development => true
50
51
  }
@@ -0,0 +1,6 @@
1
+ * Add in a full transparent proxy for automatically pullilng gems from an
2
+ upstream gem server if the local gem server does not have the gem in question
3
+ * There appears to be something different about evaling the specification off
4
+ disk, and the loading the specification from the yaml in the .gem file. They
5
+ are different. It appears that @original_platform is not set when the Ruby
6
+ specification is eval'd but it is when the yaml is loaded.
@@ -3,7 +3,7 @@
3
3
  require 'stickler'
4
4
  require 'stickler/client'
5
5
 
6
- SUB_COMMANDS = %w[ push yank mirror config ]
6
+ SUB_COMMANDS = %w[ push yank mirror config list ].sort
7
7
  exec_name = File.basename( $0 )
8
8
 
9
9
  #----------------------------------------------------------------------
@@ -20,9 +20,10 @@ Stickler server interaction
20
20
  Examples:
21
21
  #{exec_name} push ./my_gem-1.0.0.gem --server http://stickler.example.com/
22
22
  #{exec_name} yank my_gem --version 1.0.0 --server http://stickler.example.com/
23
- #{exec_name} mirror third_party --version 0.4.2 --upstream http://rubygems.org/ --server http://stickler.example.com/
23
+ #{exec_name} mirror third_party_gem --gem-version 0.4.2 --upstream http://rubygems.org/ --server http://stickler.example.com/
24
24
  #{exec_name} mirror --help
25
25
  #{exec_name} config --server http://stickler.example.com --upstream http://rubygems.org/
26
+ #{exec_name} list --server http://stickler.example.com
26
27
 
27
28
  Options:
28
29
  _
@@ -46,5 +47,7 @@ when "mirror"
46
47
  ::Stickler::Client::Mirror.new( ARGV ).run
47
48
  when "config"
48
49
  ::Stickler::Client::Config.new( ARGV ).run
50
+ when "list"
51
+ ::Stickler::Client::List.new( ARGV ).run
49
52
  end
50
53
 
@@ -0,0 +1,6 @@
1
+ require 'stickler'
2
+
3
+ repo = Stickler::Repository::Remote.new( "https://rubygems.org" )
4
+ spec = Stickler::SpecLite.new( "hitimes", "1.1.1" )
5
+ g = repo.get( spec )
6
+ puts "Retrieved #{g.size} bytes"
@@ -13,7 +13,7 @@ $:.unshift File.expand_path( File.join( File.dirname(__FILE__), "..", "lib" ) )
13
13
  require 'stickler/middleware/gemcutter'
14
14
  require 'stickler/middleware/compression'
15
15
 
16
- gem_dir = File.join( File.expand_path( File.dirname( __FILE__ ) ), "..", "spec", "tmp" )
16
+ gem_dir = File.expand_path( "../spec/tmp", File.dirname( __FILE__ ) )
17
17
 
18
18
  use ::Stickler::Middleware::Compression
19
19
  use ::Stickler::Middleware::Gemcutter, :repo_root => gem_dir
@@ -3,8 +3,8 @@ end
3
3
 
4
4
  require 'stickler/error'
5
5
  require 'stickler/paths'
6
- require 'stickler/middleware'
7
6
  require 'stickler/repository'
7
+ require 'stickler/middleware'
8
8
  require 'stickler/spec_lite'
9
9
  require 'stickler/version'
10
10
  require 'stickler/server'
@@ -45,3 +45,4 @@ require 'stickler/client/push'
45
45
  require 'stickler/client/yank'
46
46
  require 'stickler/client/mirror'
47
47
  require 'stickler/client/config'
48
+ require 'stickler/client/list'
@@ -0,0 +1,30 @@
1
+ module Stickler
2
+ class Client
3
+ class List < Stickler::Client
4
+ def self.banner
5
+ <<-_
6
+ List the gems in the stickler server with repository information.
7
+
8
+ Usage: stickler list
9
+
10
+ Options:
11
+ _
12
+ end
13
+
14
+ def run
15
+ opts = parse( self.argv )
16
+ repo = remote_repo_for( opts )
17
+ gems = Hash.new { |h,k| h[k] = Array.new }
18
+
19
+ repo.specs_list.each do |name, version, platform|
20
+ spec = Stickler::SpecLite.new( name, version, platform )
21
+ gems[name] << spec
22
+ end
23
+
24
+ gems.keys.sort.each do |name|
25
+ puts "#{name} (#{gems[name].collect { |s| s.version_platform }.join( ", " )})"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -45,15 +45,15 @@ _
45
45
  $stdout.write "Asking #{repo.uri} to mirror #{spec.full_name} from #{upstream_host} : "
46
46
  $stdout.flush
47
47
 
48
- uri = [ repo.uri.join( upstream_host ), opts[:gem_name], opts[:gem_version], opts[:platform] ].join("/")
49
- resource = repo.http.resource( uri )
48
+ uri = [ repo.uri.join( upstream_host ), opts[:gem_name], opts[:gem_version], opts[:platform] ].join("/")
49
+ resp = Excon.post( uri, :expects => [200] )
50
50
 
51
- resp = resource.post
52
51
  $stdout.puts "OK -> #{repo.uri.join(resp.headers['Location'])}"
53
- rescue Resourceful::UnsuccessfulHttpRequestError => he
54
- resp = he.http_response
52
+ rescue Excon::Errors::Error => he
53
+ resp = he.response
55
54
  $stdout.puts "ERROR -> #{resp.body}"
56
55
  rescue StandardError => e
56
+ puts e.backtrace.join("\n")
57
57
  $stdout.puts "ERROR -> #{e.message}"
58
58
  end
59
59
  end
@@ -31,7 +31,7 @@ _
31
31
 
32
32
  width = opts[:gemfiles].collect { |g| g.length }.sort.last
33
33
 
34
- puts "Pushing gem(s) to #{repo.uri} ..."
34
+ $stdout.puts "Pushing gem(s) to #{repo.uri} ..."
35
35
  opts[:gemfiles].each do |gemfile|
36
36
  begin
37
37
  $stdout.write " #{gemfile.ljust( width )} -> "
@@ -4,7 +4,7 @@ require 'stickler/middleware/local'
4
4
  require 'stickler/repository/local'
5
5
 
6
6
  module Stickler::Middleware
7
- #
7
+ #
8
8
  # A rack middleware for implementing the gemcutter api
9
9
  #
10
10
  # == Options
@@ -46,7 +46,7 @@ module Stickler::Middleware
46
46
  spec = Stickler::SpecLite.new( params[:gem_name], params[:version] )
47
47
  if s = @repo.yank( spec ) then
48
48
  logger.info( "Yanked #{spec.full_name}" )
49
- return "Yanked #{s.to_s}"
49
+ return "Yanked #{spec.full_name}"
50
50
  else
51
51
  logger.warn( "Did not Yank #{spec.full_name}" )
52
52
  error( 503, "Did not Yank #{spec.to_s}" )
@@ -1,4 +1,5 @@
1
1
  require 'stickler/middleware'
2
+ require 'stickler/repository/local'
2
3
  module Stickler::Middleware
3
4
  module Helpers
4
5
  #
@@ -34,15 +35,44 @@ module Stickler::Middleware
34
35
  # The specs by repository
35
36
  #
36
37
  def specs_by_repo
37
- env['stickler.specs'] ||= Hash.new{ |h,k| h[k] = Array.new }
38
+ Stickler::Repository::Local.repos
38
39
  end
39
40
 
40
41
  #
41
- # return the flattened array of all the values in
42
- # <tt>#specs_by_repo</tt>
42
+ # return the list of all the specs in all the repos
43
43
  #
44
44
  def specs
45
- [ specs_by_repo.values ].flatten.sort
45
+ collect_specs_via( :specs )
46
+ end
47
+
48
+ #
49
+ # return the list of all the latest_specs in all the repos
50
+ #
51
+ def latest_specs
52
+ collect_specs_via( :latest_specs )
53
+ end
54
+
55
+ #
56
+ # return the list of all the pre-release specs
57
+ #
58
+ def prerelease_specs
59
+ collect_specs_via( :prerelease_specs )
60
+ end
61
+
62
+ #
63
+ # return just the list of the releeased specs in all the repos
64
+ #
65
+ def released_specs
66
+ collect_specs_via( :released_specs )
67
+ end
68
+
69
+ #
70
+ # Collect all the specs via a call on each Repository
71
+ #
72
+ def collect_specs_via( method )
73
+ specs_by_repo.values.collect do |idx|
74
+ idx.send( method )
75
+ end.flatten.sort
46
76
  end
47
77
 
48
78
  #
@@ -69,48 +99,13 @@ module Stickler::Middleware
69
99
  #
70
100
  # Given a list of specs, this will group them by name
71
101
  #
72
- def specs_grouped_by_name( list )
102
+ def specs_grouped_by_name( spec_list )
73
103
  by_name = Hash.new{ |h,k| h[k] = Array.new }
74
- list.each do |spec|
104
+ spec_list.each do |spec|
75
105
  by_name[spec.name.downcase] << spec
76
106
  end
77
107
  return by_name
78
108
  end
79
-
80
- #
81
- # Append spec or array of specs to the current list of specs for this key.
82
- #
83
- def append_spec( key, spec_or_array_of_specs )
84
- if Array === spec_or_array_of_specs then
85
- specs_by_repo[key].concat( spec_or_array_of_specs )
86
- else
87
- specs_by_repo[key] << spec_or_array_of_specs
88
- end
89
- end
90
-
91
- #
92
- # Automatically append the specs from the included class into the specs
93
- # environment variable.
94
- #
95
- # The Class that includes this module and wants to use +append_specs+
96
- # MUST have a +repo+ method. The +repo+ method must +respond_to+ both
97
- # +root_dir+ and +specs+.
98
- #
99
- def append_specs
100
- append_spec( self.repo.root_dir, self.repo.specs )
101
- end
102
-
103
- #
104
- # Automatically append the latest_specs from the included class into the
105
- # specs environment variable.
106
- #
107
- # The Class that includes this module and wants to use +append_specs+ MUST
108
- # have a +repo+ method. The +repo+ method must +respond_to+ both
109
- # +root_dir+ and +specs+.
110
- #
111
- def append_latest_specs
112
- append_spec( self.repo.root_dir, self.repo.latest_specs )
113
- end
114
- end
109
+ end
115
110
  end
116
111
  end