stickler 2.0.2 → 2.1.0

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 (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