# File lib/chef/cookbook_uploader.rb, line 56
    def upload_cookbook
      Thread.abort_on_exception = true
      Chef::Log.info("Saving #{cookbook.name}")

      # Syntax Check
      validate_cookbook
      # generate checksums of cookbook files and create a sandbox
      checksum_files = cookbook.checksums
      checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
      new_sandbox = rest.post_rest("sandboxes", { :checksums => checksums })

      Chef::Log.info("Uploading files")

      self.class.setup_worker_threads

      checksums_to_upload = Set.new

      # upload the new checksums and commit the sandbox
      new_sandbox['checksums'].each do |checksum, info|
        if info['needs_upload'] == true
          checksums_to_upload << checksum
          Chef::Log.info("Uploading #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}")
          self.class.work_queue << uploader_function_for(checksum_files[checksum], checksum, info['url'], checksums_to_upload)
        else
          Chef::Log.debug("#{checksum_files[checksum]} has not changed")
        end
      end

      until checksums_to_upload.empty?
        sleep 0.1
      end

      sandbox_url = new_sandbox['uri']
      Chef::Log.debug("Committing sandbox")
      # Retry if S3 is claims a checksum doesn't exist (the eventual
      # in eventual consistency)
      retries = 0
      begin
        rest.put_rest(sandbox_url, {:is_completed => true})
      rescue Net::HTTPServerException => e
        if e.message =~ /^400/ && (retries += 1) <= 5
          sleep 2
          retry
        else
          raise
        end
      end

      # files are uploaded, so save the manifest
      save_url = opts[:force] ? cookbook.force_save_url : cookbook.save_url
      rest.put_rest(save_url, cookbook)

      Chef::Log.info("Upload complete!")
    end