stickler 2.0.0a → 2.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 (64) hide show
  1. data/.bnsignore +14 -0
  2. data/.gitignore +17 -0
  3. data/HISTORY.asciidoc +20 -0
  4. data/README.asciidoc +126 -0
  5. data/Rakefile +22 -3
  6. data/bin/stickler +50 -0
  7. data/bin/stickler-passenger-config +112 -0
  8. data/bin/stickler-server +109 -0
  9. data/examples/config.ru +6 -3
  10. data/examples/gemcutter_repo.ru +2 -0
  11. data/examples/index_repo.ru +2 -0
  12. data/examples/local_repo.ru +6 -3
  13. data/examples/mirror_repo.ru +2 -0
  14. data/examples/not_found.ru +2 -0
  15. data/lib/stickler.rb +12 -0
  16. data/lib/stickler/client.rb +47 -0
  17. data/lib/stickler/client/config.rb +35 -0
  18. data/lib/stickler/client/config_file.rb +58 -0
  19. data/lib/stickler/client/mirror.rb +61 -0
  20. data/lib/stickler/client/push.rb +50 -0
  21. data/lib/stickler/client/yank.rb +51 -0
  22. data/lib/stickler/logable.rb +35 -0
  23. data/lib/stickler/middleware/gemcutter.rb +5 -0
  24. data/lib/stickler/middleware/helpers.rb +32 -0
  25. data/lib/stickler/middleware/index.rb +30 -4
  26. data/lib/stickler/middleware/mirror.rb +8 -3
  27. data/lib/stickler/middleware/not_found.rb +4 -2
  28. data/lib/stickler/paths.rb +53 -0
  29. data/lib/stickler/repository/local.rb +12 -12
  30. data/lib/stickler/repository/mirror.rb +13 -6
  31. data/lib/stickler/repository/null.rb +1 -0
  32. data/lib/stickler/repository/remote.rb +10 -4
  33. data/lib/stickler/repository/rubygems_authenticator.rb +32 -0
  34. data/lib/stickler/server.rb +34 -0
  35. data/lib/stickler/server/public/css/blueprint/LICENSE +22 -0
  36. data/lib/stickler/server/public/css/blueprint/ie.css +35 -0
  37. data/lib/stickler/server/public/css/blueprint/screen.css +266 -0
  38. data/lib/stickler/server/public/css/style.css +19 -0
  39. data/lib/stickler/server/public/images/apple-touch-icon.png +0 -0
  40. data/lib/stickler/server/public/images/favicon.ico +0 -0
  41. data/lib/stickler/server/public/js/modernizr-1.5.min.js +28 -0
  42. data/lib/stickler/server/views/index.erb +35 -0
  43. data/lib/stickler/server/views/layout.erb +42 -0
  44. data/lib/stickler/spec_lite.rb +16 -6
  45. data/lib/stickler/version.rb +1 -1
  46. data/man/asciidoc.conf +25 -0
  47. data/man/stickler-passenger-config.asciidoc +74 -0
  48. data/man/stickler-server.asciidoc +87 -0
  49. data/man/stickler.asciidoc +148 -0
  50. data/spec/middleware/common_gem_server_helpers.rb +4 -2
  51. data/spec/middleware/index_spec.rb +3 -3
  52. data/spec/middleware/legacy_gem_server_behavior.rb +0 -2
  53. data/spec/middleware/local_spec.rb +3 -3
  54. data/spec/middleware/modern_gem_server_behavior.rb +2 -0
  55. data/spec/paths_spec.rb +13 -0
  56. data/spec/spec_lite_spec.rb +14 -0
  57. data/tasks/man.rake +19 -0
  58. metadata +183 -56
  59. data/HISTORY.rdoc +0 -12
  60. data/README.rdoc +0 -88
  61. data/lib/stickler/web.rb +0 -19
  62. data/stickler.gemspec +0 -60
  63. data/views/index.erb +0 -19
  64. data/views/layout.erb +0 -39
@@ -1,9 +1,12 @@
1
1
  #-----------------------------------------------------------------------
2
2
  # Example rackup file for an entire stickler stack
3
+ #
4
+ # -*- vim: set ft=ruby: -*-
3
5
  #-----------------------------------------------------------------------
4
6
  $:.unshift File.expand_path( File.join( File.dirname(__FILE__), "..", "lib" ) )
5
7
 
6
- require 'stickler/web'
8
+ require 'stickler'
7
9
 
8
- use Stickler::Web
9
- run Sinatra::Base
10
+ tmp = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "tmp" ) )
11
+
12
+ run Stickler::Server.new( tmp ).app
@@ -1,4 +1,6 @@
1
1
  #-----------------------------------------------------------------------
2
+ # -*- vim: set ft=ruby: -*-
3
+ #
2
4
  # An Example remote repository that implements all the methods that are
3
5
  # required to satisfy being talked to by a Respository::Remote client.
4
6
  # This means it needs to speak:
@@ -1,4 +1,6 @@
1
1
  #-----------------------------------------------------------------------
2
+ #-*- vim: set ft=ruby: -*-
3
+ #
2
4
  # Example rackup file for serving up a null repository. This really
3
5
  # would never be used in the wild, but it shows the basics of what
4
6
  # is required to setup a stickler webstack
@@ -1,14 +1,17 @@
1
1
  #-----------------------------------------------------------------------
2
+ #-*- vim: set ft=ruby: -*-
3
+ #
2
4
  # Example rackup file for serving up a single repository. This repository
3
5
  # will respond to index and gem requests.
4
6
  #-----------------------------------------------------------------------
5
7
  $:.unshift File.expand_path( File.join( File.dirname(__FILE__), "..", "lib" ) )
6
8
 
7
9
  require 'stickler/middleware/compression'
8
- require 'stickler/middleware/repo_local'
10
+ require 'stickler/middleware/local'
9
11
 
10
- gem_dir = File.join( File.expand_path( File.dirname( __FILE__ ) ), "data" )
12
+ gem_dir = File.expand_path( File.join( File.dirname( __FILE__ ), *%w[ .. spec data ]))
11
13
 
14
+ puts gem_dir
12
15
  use ::Stickler::Middleware::Compression
13
- use ::Stickler::Middleware::RepoLocal, :repo_root => gem_dir
16
+ use ::Stickler::Middleware::Local, :repo_root => gem_dir
14
17
  run ::Sinatra::Base
@@ -1,4 +1,6 @@
1
1
  #-----------------------------------------------------------------------
2
+ #-*- vim: set ft=ruby: -*-
3
+ #
2
4
  # Example repository for serving up a Mirror repository. This repo
3
5
  # will respond to mirroring requests and mirror gems from a remote
4
6
  # repository locally.
@@ -1,4 +1,6 @@
1
1
  #-----------------------------------------------------------------------
2
+ #-*- vim: set ft=ruby: -*-
3
+ #
2
4
  # Serve up the not found page for everything
3
5
  #-----------------------------------------------------------------------
4
6
  $:.unshift File.expand_path( File.join( File.dirname(__FILE__), "..", "lib" ) )
@@ -0,0 +1,12 @@
1
+ module Stickler
2
+ end
3
+
4
+ require 'stickler/error'
5
+ require 'stickler/paths'
6
+ require 'stickler/middleware'
7
+ require 'stickler/repository'
8
+ require 'stickler/spec_lite'
9
+ require 'stickler/version'
10
+ require 'stickler/server'
11
+
12
+
@@ -0,0 +1,47 @@
1
+ require 'trollop'
2
+ require 'rubygems'
3
+ require 'stickler/client/config_file'
4
+
5
+ module Stickler
6
+ class Client
7
+
8
+ attr_reader :argv
9
+ attr_reader :sources
10
+
11
+ def self.config
12
+ ::Stickler::Client::ConfigFile.new
13
+ end
14
+
15
+ def initialize( argv = ARGV )
16
+ @argv = argv
17
+ end
18
+
19
+ def parser
20
+ me = self # scoping forces this
21
+ @parser ||= Trollop::Parser.new do
22
+ banner me.class.banner
23
+ opt :server, "The gem or stickler server URL", :type => :string, :default => Client.config.server
24
+ opt :debug, "Output debug information for the server interaction", :default => false
25
+ end
26
+ end
27
+
28
+ def parse( argv )
29
+ opts = Trollop::with_standard_exception_handling( parser ) do
30
+ raise Trollop::HelpNeeded if argv.empty? # show help screen
31
+ o = parser.parse( argv )
32
+ yield parser if block_given?
33
+ return o
34
+ end
35
+ return opts
36
+ end
37
+
38
+ def remote_repo_for( opts )
39
+ Stickler::Repository::Remote.new( opts[:server], :debug => opts[:debug] )
40
+ end
41
+ end
42
+ end
43
+
44
+ require 'stickler/client/push'
45
+ require 'stickler/client/yank'
46
+ require 'stickler/client/mirror'
47
+ require 'stickler/client/config'
@@ -0,0 +1,35 @@
1
+ module Stickler
2
+ class Client
3
+ class Config < Stickler::Client
4
+ def self.banner
5
+ <<-_
6
+ Access or update the Stickler client configuration.
7
+
8
+ Usage: stickler config [options]
9
+
10
+ Options:
11
+ _
12
+ end
13
+
14
+ def parser
15
+ unless @parser then
16
+ @parser = super
17
+ @parser.opt( :upstream, "The upstream gem server from which to pull", :type => :string, :default => Client.config.upstream )
18
+ @parser.opt( :add, "Add upstream and/or server to the configuration", :type => :boolean )
19
+ @parser.opt( :list, "display the current configuration", :type => :boolean )
20
+ end
21
+ return @parser
22
+ end
23
+
24
+ def dump_config( opts )
25
+ puts " server : #{Client.config.server}"
26
+ puts "upstream : #{Client.config.upstream}"
27
+ end
28
+
29
+ def run
30
+ opts = parse( self.argv )
31
+ dump_config( opts ) if Client.config.update( opts ) || opts[:list]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'stickler/repository/rubygems_authenticator'
3
+
4
+ module Stickler
5
+ class Client
6
+ class ConfigFile
7
+ def initalize
8
+ @updated = false
9
+ end
10
+
11
+ def config_path
12
+ File.join(Gem.user_home, '.gem', 'stickler')
13
+ end
14
+
15
+ def configuration
16
+ Gem.configuration.load_file(config_path)
17
+ end
18
+
19
+ def update( opts )
20
+ self.server = opts[:server] if opts[:server]
21
+ self.upstream = opts[:upstream] if opts[:upstream]
22
+ return updated?
23
+ end
24
+
25
+ def updated?
26
+ return @updated
27
+ end
28
+
29
+ def server
30
+ configuration[:server]
31
+ end
32
+
33
+ def server=( server )
34
+ config = configuration.merge( :server => server )
35
+ save_config( config )
36
+ end
37
+
38
+ def upstream
39
+ configuration[:upstream] || ::Stickler::Repository::RubygemsAuthenticator.rubygems_uri.to_s
40
+ end
41
+
42
+ def upstream=( upstream )
43
+ config = configuration.merge( :upstream => upstream )
44
+ save_config( config )
45
+ end
46
+
47
+ def save_config( config )
48
+ dirname = File.dirname(config_path)
49
+ Dir.mkdir(dirname) unless File.exists?(dirname)
50
+
51
+ File.open(config_path, "w") do |f|
52
+ f.write config.to_yaml
53
+ end
54
+ @updated = true
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ module Stickler
2
+ class Client
3
+ class Mirror < Stickler::Client
4
+ def self.banner
5
+ <<-_
6
+ Pull a specific version of a gem from an upstream gem server
7
+ and store it in a stickler server.
8
+
9
+ Usage: stickler mirror [options] --gem-version x.y.z gem
10
+
11
+ Options:
12
+ _
13
+ end
14
+
15
+ def parser
16
+ unless @parser then
17
+ @parser = super
18
+ @parser.opt( :upstream, "The upstream gem server from which to pull", :type => :string, :default => Client.config.upstream )
19
+ @parser.opt( :gem_version, "The version of the gem to yank (required)", :type => :string, :required => true )
20
+ @parser.opt( :platform, "The platform of the gem to yank", :type => :string, :default => ::Gem::Platform::RUBY )
21
+ end
22
+ return @parser
23
+ end
24
+
25
+ def parse( argv )
26
+ gem_name = nil
27
+ opts = super( argv ) do |p|
28
+ raise Trollop::CommandlineError, "At least one gem is required to mirror" if p.leftovers.empty?
29
+ gem_name = p.leftovers.shift
30
+ end
31
+ opts[:gem_name] = gem_name
32
+ return opts
33
+ end
34
+
35
+ def resource_uri( opts )
36
+ opts[:server] || Client.config.server
37
+ end
38
+
39
+ def run
40
+ opts = parse( self.argv )
41
+ repo = remote_repo_for( opts )
42
+ spec = Stickler::SpecLite.new( opts[:gem_name], opts[:gem_version], opts[:platform] )
43
+ upstream_host = Addressable::URI.parse( opts[:upstream] ).host
44
+
45
+ $stdout.write "Asking #{repo.uri} to mirror #{spec.full_name} from #{upstream_host} : "
46
+ $stdout.flush
47
+
48
+ uri = [ repo.uri.join( upstream_host ), opts[:gem_name], opts[:gem_version], opts[:platform] ].join("/")
49
+ resource = repo.http.resource( uri )
50
+
51
+ resp = resource.post
52
+ $stdout.puts "OK -> #{repo.uri.join(resp.headers['Location'])}"
53
+ rescue Resourceful::UnsuccessfulHttpRequestError => he
54
+ resp = he.http_response
55
+ $stdout.puts "ERROR -> #{resp.body}"
56
+ rescue StandardError => e
57
+ $stdout.puts "ERROR -> #{e.message}"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,50 @@
1
+ require 'trollop'
2
+ module Stickler
3
+ class Client
4
+ class Push < Stickler::Client
5
+ def self.banner
6
+ <<-_
7
+ Push one or more gems to a gemserver.
8
+
9
+ Usage: stickler push [options] gemfile(s)
10
+
11
+ Options:
12
+ _
13
+ end
14
+
15
+ def parse( argv )
16
+ gemfiles = []
17
+ opts = super do |p|
18
+ raise Trollop::CommandlineError, "At least one file is required to push" if p.leftovers.empty?
19
+ p.leftovers.each do |gemfile|
20
+ raise Trollop::CommandlineError, "#{gemfile} must be readable" unless File.readable?( gemfile )
21
+ gemfiles << File.expand_path( gemfile )
22
+ end
23
+ end
24
+ opts[:gemfiles] = gemfiles
25
+ return opts
26
+ end
27
+
28
+ def run
29
+ opts = parse( self.argv )
30
+ repo = remote_repo_for( opts )
31
+
32
+ width = opts[:gemfiles].collect { |g| g.length }.sort.last
33
+
34
+ puts "Pushing gem(s) to #{repo.uri} ..."
35
+ opts[:gemfiles].each do |gemfile|
36
+ begin
37
+ $stdout.write " #{gemfile.ljust( width )} -> "
38
+ $stdout.flush
39
+ spec = repo.push( gemfile )
40
+ ok_msg = "OK"
41
+ ok_msg += " #{repo.uri_for_gem( spec )}"
42
+ $stdout.puts ok_msg
43
+ rescue Stickler::Repository::Error => e
44
+ $stdout.puts "ERROR: #{e.message}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ module Stickler
2
+ class Client
3
+ class Yank < Stickler::Client
4
+ def self.banner
5
+ <<-_
6
+ Remove a gem from the gemserver's index.
7
+ It will still be available for direct download.
8
+
9
+ Usage: stickler yank [options] --gem-version x.y.z gem
10
+
11
+ Options:
12
+ _
13
+ end
14
+
15
+ def parser
16
+ unless @parser then
17
+ @parser = super
18
+ @parser.opt( :gem_version, "The version of the gem to yank (required)", :type => :string, :required => true )
19
+ @parser.opt( :platform, "The platform of the gem to yank", :type => :string, :default => ::Gem::Platform::RUBY )
20
+ end
21
+ return @parser
22
+ end
23
+
24
+ def parse( argv )
25
+ gem_name = nil
26
+ opts = super( argv ) do |p|
27
+ raise Trollop::CommandlineError, "At least one gem is required to yank" if p.leftovers.empty?
28
+ gem_name = p.leftovers.shift
29
+ end
30
+ opts[:gem_name] = gem_name
31
+ return opts
32
+ end
33
+
34
+ def run
35
+ opts = parse( self.argv )
36
+ repo = remote_repo_for( opts )
37
+ spec = Stickler::SpecLite.new( opts[:gem_name], opts[:gem_version], opts[:platform] )
38
+
39
+ $stdout.write "Yanking gem #{spec.full_name} from #{repo.uri} : "
40
+ $stdout.flush
41
+ if spec = repo.yank( spec ) then
42
+ $stdout.puts "OK"
43
+ else
44
+ $stdout.puts "FAILURE"
45
+ end
46
+ rescue Stickler::Repository::Error => e
47
+ $stdout.puts "ERROR: #{e.message}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,35 @@
1
+ require 'logging'
2
+ module Stickler
3
+
4
+ def self.app_name
5
+ @app_name || "stickler"
6
+ end
7
+
8
+ def self.app_name=( name )
9
+ @app_name = name
10
+ end
11
+
12
+ class Logging
13
+ def self.init
14
+ unless @initialized then
15
+ layout = ::Logging::Layouts::Pattern.new( :pattern => "%5l %c : %m" )
16
+ appender = ::Logging::Appenders::Syslog.new( Stickler.app_name,
17
+ :logopt => ::Syslog::Constants::LOG_CONS | ::Syslog::Constants::LOG_PID,
18
+ :facility => ::Syslog::Constants::LOG_LOCAL0,
19
+ :layout => layout)
20
+ ::Logging::Appenders['syslog'] = appender
21
+ logger = ::Logging::Logger[Stickler]
22
+ logger.add_appenders( appender )
23
+ @initialized = true
24
+ end
25
+ return @initialized
26
+ end
27
+ end
28
+
29
+ module Logable
30
+ def logger
31
+ Stickler::Logging.init
32
+ ::Logging::Logger[self]
33
+ end
34
+ end
35
+ end
@@ -33,8 +33,10 @@ module Stickler::Middleware
33
33
  post '/api/v1/gems' do
34
34
  begin
35
35
  spec = @repo.add( request.body )
36
+ logger.info( "Pushed #{spec.full_name}" )
36
37
  return spec.to_s
37
38
  rescue Stickler::Repository::Error => e
39
+ logger.error( "Error adding #{spec.full_name} to repo : #{e}" )
38
40
  error( 500, "Error adding gem to repo: #{e}" )
39
41
  end
40
42
  end
@@ -43,8 +45,10 @@ module Stickler::Middleware
43
45
  delete '/api/v1/gems/yank' do
44
46
  spec = Stickler::SpecLite.new( params[:gem_name], params[:version] )
45
47
  if s = @repo.yank( spec ) then
48
+ logger.info( "Yanked #{spec.full_name}" )
46
49
  return "Yanked #{s.to_s}"
47
50
  else
51
+ logger.warn( "Did not Yank #{spec.full_name}" )
48
52
  error( 503, "Did not Yank #{spec.to_s}" )
49
53
  end
50
54
  end
@@ -54,6 +58,7 @@ module Stickler::Middleware
54
58
  full_name, name, version, platform = *params[:captures]
55
59
  spec = Stickler::SpecLite.new( name, version, platform )
56
60
  @repo.delete( spec )
61
+ logger.info( "Deleted #{spec.full_name}" )
57
62
  return "deleted gem #{spec.full_name}"
58
63
  end
59
64
  end