stickler 2.0.0a → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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