@@ -562,6 +562,149 @@ def delete(package)
562562 end
563563
564564
565+ desc "delete-batch PACKAGES..." ,
566+ "Batch delete many packages at once. Supply each as name or name=version."
567+
568+ option :arch ,
569+ :type => :string ,
570+ :aliases => "-a" ,
571+ :desc => "The architecture of the packages to remove."
572+
573+ option :lock ,
574+ :default => false ,
575+ :type => :boolean ,
576+ :aliases => "-l" ,
577+ :desc => "Whether to lock the repository during updates."
578+
579+ option :do_package_remove ,
580+ :default => false ,
581+ :type => :boolean ,
582+ :desc => "Whether to delete the underlying .deb files from S3."
583+
584+ def delete_batch ( *pkg_args )
585+ if pkg_args . nil? || pkg_args . empty?
586+ error ( "You must specify at least one package, like: pkgA=1.2.3 pkgB pkgC=5.0.0" )
587+ end
588+
589+ arch = options [ :arch ]
590+ if arch . nil?
591+ error ( "You must specify --arch for batch deletion." )
592+ end
593+
594+ configure_s3_client
595+
596+ # Parse package specifications
597+ # { "pkgA" => ["1.2.3"], "pkgB" => nil (delete all versions), ... }
598+ package_map = { }
599+ pkg_args . each do |arg |
600+ if arg . include? ( "=" )
601+ name , version = arg . split ( "=" , 2 )
602+ package_map [ name ] ||= [ ]
603+ package_map [ name ] << version
604+ else
605+ package_map [ arg ] = nil
606+ end
607+ end
608+
609+ begin
610+ if options [ :lock ]
611+ log ( "Checking for existing lock file" )
612+ log ( "Locking repository for updates" )
613+ Deb ::S3 ::Lock . lock ( options [ :codename ] , component , arch , options [ :cache_control ] )
614+ @lock_acquired = true
615+ end
616+
617+ log ( "Retrieving existing manifests" )
618+ release = Deb ::S3 ::Release . retrieve ( options [ :codename ] , options [ :origin ] , options [ :suite ] )
619+
620+ # Handle arch == all
621+ target_arches =
622+ if arch == "all"
623+ release . architectures
624+ else
625+ [ arch ]
626+ end
627+
628+ total_deleted = 0
629+
630+ target_arches . each do |ar |
631+ manifest = Deb ::S3 ::Manifest . retrieve (
632+ options [ :codename ] ,
633+ component ,
634+ ar ,
635+ options [ :cache_control ] ,
636+ false ,
637+ options [ :skip_package_upload ] ,
638+ options [ :do_package_remove ]
639+ )
640+
641+ log ( "Processing batch deletion for arch #{ ar } " )
642+
643+ s3_objects_to_delete = [ ]
644+
645+ package_map . each do |name , versions |
646+ deleted = manifest . delete_package ( name , versions )
647+ if deleted . empty?
648+ if versions . nil?
649+ sublog ( "No entries found for #{ name } in arch #{ ar } ." )
650+ else
651+ sublog ( "No entries of #{ name } versions #{ versions . join ( ', ' ) } found in arch #{ ar } ." )
652+ end
653+ next
654+ end
655+
656+ deleted . each do |p |
657+ total_deleted += 1
658+ sublog ( "Deleting #{ p . name } version #{ p . full_version } from arch #{ ar } " )
659+
660+ if options [ :do_package_remove ]
661+ s3_objects_to_delete << p . url_filename ( options [ :codename ] )
662+ end
663+ end
664+ end
665+
666+ # Update manifests if necessary
667+ if total_deleted > 0
668+ log ( "Uploading updated manifests to S3 (arch #{ ar } )" )
669+ manifest . write_to_s3 { |f | sublog ( "Transferring #{ f } " ) }
670+ release . update_manifest ( manifest )
671+ release . write_to_s3 { |f | sublog ( "Transferring #{ f } " ) }
672+ end
673+
674+ # Delete .deb files from S3
675+ if options [ :do_package_remove ] && !s3_objects_to_delete . empty?
676+ log ( "Batch removing #{ s3_objects_to_delete . length } S3 objects for arch #{ ar } " )
677+ batch_delete_s3_objects ( s3_objects_to_delete )
678+ end
679+ end
680+
681+ if total_deleted == 0
682+ error ( "No packages were deleted. Nothing matched the provided arguments." )
683+ else
684+ log ( "Batch delete complete. #{ total_deleted } package entries removed." )
685+ end
686+
687+ ensure
688+ if options [ :lock ] && @lock_acquired
689+ Deb ::S3 ::Lock . unlock ( options [ :codename ] , component , arch , options [ :cache_control ] )
690+ log ( "Lock released." )
691+ end
692+ end
693+ end
694+
695+ no_commands do
696+ def batch_delete_s3_objects ( keys )
697+ keys . each_slice ( 1000 ) do |chunk |
698+ sublog ( "Deleting #{ chunk . length } objects..." )
699+ chunk . each do |key |
700+ Deb ::S3 ::Utils . s3_remove ( key )
701+ end
702+ end
703+ end
704+ end
705+
706+
707+
565708 desc "verify" , "Verifies that the files in the package manifests exist"
566709
567710 option :fix_manifests ,
0 commit comments