class Berkshelf::Uploader

def filtered_cookbooks

Returns:
  • (Array) -
def filtered_cookbooks
  # Create a copy of the dependencies. We need to make a copy, or else
  # we would be adding dependencies directly to the Berksfile object, and
  # that would be a bad idea...
  dependencies = berksfile.dependencies.map(&:name)
  checked = {}
  cookbook_order = dependencies.map do |dependency|
    # for each dep add all its deps first, then the dep itself
    lookup_dependencies(dependency, checked) + [ dependency ]
  end.flatten
  cookbook_order.uniq.map { |dependency| lockfile.retrieve(dependency) }
end

def initialize(berksfile, *args)

def initialize(berksfile, *args)
  @berksfile = berksfile
  @lockfile  = berksfile.lockfile
  opts       = args.last.respond_to?(:to_hash) ? args.pop.to_hash.each_with_object({}) { |(k, v), m| m[k.to_sym] = v } : {}
  @options = {
    force: false,
    freeze: true,
    halt_on_frozen: false,
    validate: true,
  }.merge(opts)
  @names = Array(args).flatten
end

def lookup_dependencies(cookbook, checked = {})

Returns:
  • (Array) -
def lookup_dependencies(cookbook, checked = {})
  Berkshelf.log.debug "  Looking up dependencies for #{cookbook}"
  dependencies = []
  lockfile.graph.find(cookbook).dependencies.each do |name, _|
    next if checked[name]
    # break cyclic graphs
    checked[name] = true
    # this is your standard depth-first tree traversal with the deps first...
    dependencies += lookup_dependencies(name, checked)
    # ..then the node itself
    dependencies << name
  end
  dependencies
end

def run

def run
  Berkshelf.log.info "Uploading cookbooks"
  cookbooks = if names.empty?
                Berkshelf.log.debug "  No names given, using all cookbooks"
                filtered_cookbooks
              else
                Berkshelf.log.debug "  Names given (#{names.join(", ")})"
                names.map { |name| lockfile.retrieve(name) }
              end
  # Perform all validations first to prevent partially uploaded cookbooks
  Validator.validate_files(cookbooks)
  upload(cookbooks)
  cookbooks
end

def upload(cookbooks)

Parameters:
  • cookbooks (Array) --
def upload(cookbooks)
  Berkshelf.log.info "Starting upload"
  Berkshelf.ridley_connection(options) do |connection|
    # this is a hack to work around a bug in chef 13.0-13.2 protocol negotiation on POST requests, its only
    # use is to force protocol negotiation via a GET request -- it doesn't matter if it 404s.  once we do not
    # support those early 13.x versions this line can be safely deleted.
    connection.get("users/#{Berkshelf.config.chef.node_name}") rescue nil
    cookbooks.map do |cookbook|
      compiled_metadata = cookbook.compile_metadata
      cookbook.reload if compiled_metadata
      cookbook_version = cookbook.cookbook_version
      Berkshelf.log.debug "  Uploading #{cookbook.cookbook_name}"
      cookbook_version.freeze_version if options[:freeze]
      # another two lines that are necessary for chef < 13.2 support (affects 11.x/12.x as well)
      cookbook_version.metadata.maintainer "" if cookbook_version.metadata.maintainer.nil?
      cookbook_version.metadata.maintainer_email "" if cookbook_version.metadata.maintainer_email.nil?
      begin
        Chef::CookbookUploader.new(
          [ cookbook_version ],
          force: options[:force],
          concurrency: 1, # sadly
          rest: connection,
          skip_syntax_check: options[:skip_syntax_check]
        ).upload_cookbooks
        Berkshelf.formatter.uploaded(cookbook, connection)
      rescue Chef::Exceptions::CookbookFrozen
        if options[:halt_on_frozen]
          raise FrozenCookbook.new(cookbook)
        end
        Berkshelf.formatter.skipping(cookbook, connection)
      end
    ensure
      if compiled_metadata
        # this is necessary on windows to clean up the ruby object that was pointing at the file
        # so that we can reliably delete it.  windows is terrible.
        GC.start
        File.unlink(compiled_metadata)
      end
    end
  end
end