Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement unyank for local and remote repositories. #26

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions lib/stickler/client/unyank.rb
@@ -0,0 +1,50 @@
module Stickler
class Client
class Unyank < Stickler::Client
def self.banner
<<-_
Restore a yanked gem to the gemserver's index.

Usage: stickler unyank [options] --gem-version x.y.z gem

Options:
_
end

def parser
unless @parser then
@parser = super
@parser.opt( :gem_version, "The version of the gem to unyank (required)", :type => :string, :required => true )
@parser.opt( :platform, "The platform of the gem to unyank", :type => :string, :default => ::Gem::Platform::RUBY )
end
return @parser
end

def parse( argv )
gem_name = nil
opts = super( argv ) do |p|
raise Trollop::CommandlineError, "At least one gem is required to unyank" if p.leftovers.empty?
gem_name = p.leftovers.shift
end
opts[:gem_name] = gem_name
return opts
end

def run
opts = parse( self.argv )
repo = remote_repo_for( opts )
spec = Stickler::SpecLite.new( opts[:gem_name], opts[:gem_version], opts[:platform] )

$stdout.write "Unyanking gem #{spec.full_name} from #{repo.uri} : "
$stdout.flush
if spec = repo.unyank( spec ) then
$stdout.puts "OK"
else
$stdout.puts "FAILURE"
end
rescue Stickler::Repository::Error => e
$stdout.puts "ERROR: #{e.message}"
end
end
end
end
13 changes: 13 additions & 0 deletions lib/stickler/middleware/gemcutter.rb
Expand Up @@ -41,6 +41,19 @@ def initialize( app = nil, options = {} )
end
end

# gemcutter unyank
post '/api/v1/gems/unyank' do
begin
spec = Stickler::SpecLite.new( params[:spec_name], params[:version] )
@repo.unyank( spec )
logger.info( "Unyanked #{spec.full_name}" )
return spec.to_s
rescue Stickler::Repository::Error => e
logger.error( "Error unyanking #{spec.full_name} to repo : #{e}" )
error( 500, "Error unyanking gem to repo: #{e}" )
end
end

# gemcutter yank
delete '/api/v1/gems/yank' do
spec = Stickler::SpecLite.new( params[:gem_name], params[:version] )
Expand Down
12 changes: 11 additions & 1 deletion lib/stickler/repository/local.rb
Expand Up @@ -162,6 +162,15 @@ def yank( spec )
return uri_for_gem( spec )
end

#
# See Api#unyank
#
def unyank( spec )
return nil if specification_file_exist?( spec )
return nil unless gem_file_exist?( spec )
install_specification( spec )
end


#
# :call-seq:
Expand Down Expand Up @@ -194,7 +203,8 @@ def add( io )
# See Api#push
#
def push( path )
spec = specification_from_gem_file( path )
# is this line needed? Never used.
# spec = specification_from_gem_file( path )
result = nil
File.open( path ) do |io|
result = add( io )
Expand Down
27 changes: 27 additions & 0 deletions lib/stickler/repository/remote.rb
Expand Up @@ -95,6 +95,19 @@ def yank( spec )
raise Stickler::Repository::Error, "Failure yanking: #{e.inspect}"
end

#
# See Api#unyank
#
def unyank( spec )
return nil unless remote_gem_file_exist?( spec )
query = { :spec_name => spec.name, :version => spec.version.to_s }
resp = resource_request( unyank_resource, :query => query )
true
rescue Excon::Errors::Error => e
# raise Stickler::Repository::Error, "Failure unyanking: #{e.inspect}"
[]
end

#
# See Api#delete
#
Expand Down Expand Up @@ -179,6 +192,10 @@ def yank_uri
Addressable::URI.join( uri, "api/v1/gems/yank" )
end

def unyank_uri
Addressable::URI.join( uri, "api/v1/gems/unyank" )
end

def yank_resource
unless @yank_resource then
params = { :method => :delete,
Expand All @@ -188,6 +205,16 @@ def yank_resource
end
return @yank_resource
end

def unyank_resource
unless @unyank_resource then
params = { :method => :post,
:headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
:expects => [200] }
@unyank_resource = Excon.new( unyank_uri.to_s, params )
end
return @unyank_resource
end

def gem_resource( spec )
Excon.new( full_uri_to_gem( spec ), :method => :get, :expects => [200] )
Expand Down
32 changes: 32 additions & 0 deletions spec/repository/api_behavior.rb
Expand Up @@ -104,6 +104,38 @@

end

describe "#unyank" do
before( :each ) do
@repo.search_for( @foo_spec ).should be_empty
@repo.push( @foo_gem_local_path )
end

it "returns nil if the gem to unyank does not exist" do
non_existing_gem = @missing_spec
@repo.unyank( non_existing_gem ).should be_nil
end

#Do we even care about this?
xit "returns nil if the gem to unyank has not been yanked" do
@repo.unyank( @foo_spec ).should be_nil
end

context " when file has been yanked" do
before :each do
@repo.yank( @foo_spec )
end

it "return true if the gem is successfully unyanked" do
@repo.unyank( @foo_spec ).should be_true
end

it "finds the gem in a search" do
@repo.unyank( @foo_spec )
@repo.search_for( @foo_spec ).should_not be_empty
end
end
end

describe "#search_for" do
it "returns specs for items that are found" do
@repo.push( @foo_gem_local_path )
Expand Down