module Berkshelf # @author Jamie Winsor class Berksfile include DSL class << self def from_file(file) content = File.read(file) read(content) rescue Errno::ENOENT => e raise BerksfileNotFound, "No Berksfile or Berksfile.lock found at: #{file}" end def read(content) object = new object.instance_eval(content) object end # @param [Array] sources # an array of sources to filter # @param [Array, Symbol] excluded # an array of symbols or a symbol representing the group or group(s) # to exclude # # @return [Array] # an array of sources that are not members of the excluded group(s) def filter_sources(sources, excluded) excluded = Array(excluded) excluded.collect!(&:to_sym) sources.select { |source| (excluded & source.groups).empty? } end end def initialize @sources = Hash.new end # Add the given source to the sources array. A DuplicateSourceDefined # exception will be raised if a source is added whose name conflicts # with a source who has already been added. # # @param [Berkshelf::CookbookSource] source # the source to add # # @return [Array] def sources(options = {}) l_sources = @sources.collect { |name, source| source }.flatten if options[:exclude] self.class.filter_sources(l_sources, options[:exclude]) else l_sources end end # @return [Hash] # a hash containing group names as keys and an array of CookbookSources # that are a member of that group as values # # Example: # { # nautilus: [ # #, # #, # ], # skarner: [ # # # ] # } def groups {}.tap do |groups| @sources.each_pair do |name, source| source.groups.each do |group| groups[group] ||= [] groups[group] << source end end end end # @param [String] name # name of the source to return # # @return [Berkshelf::CookbookSource] def [](name) @sources[name] end alias_method :get_source, :[] # @option options [Symbol, Array] :without # Group(s) to exclude which will cause any sources marked as a member of the # group to not be installed def install(options = {}) resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without])) resolver.resolve write_lockfile(resolver.sources) unless lockfile_present? end # @param [String] chef_server_url # the full URL to the Chef Server to upload to # # "https://api.opscode.com/organizations/vialstudios" # # @option options [Symbol, Array] :without # Group(s) to exclude which will cause any sources marked as a member of the # group to not be installed # @option options [String] :node_name # the name of the client used to sign REST requests to the Chef Server # @option options [String] :client_key # the filepath location for the client's key used to sign REST requests # to the Chef Server # @option options [Boolean] :force Upload the Cookbook even if the version # already exists and is frozen on the target Chef Server # @option options [Boolean] :freeze Freeze the uploaded Cookbook on the Chef # Server so that it cannot be overwritten def upload(chef_server_url, options = {}) uploader = Uploader.new(chef_server_url, options) resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without])) resolver.resolve.each do |cb| Berkshelf.ui.info "Uploading #{cb.cookbook_name} (#{cb.version}) to: '#{chef_server_url}'" uploader.upload!(cb, options) end end private def lockfile_present? File.exist?(Berkshelf::Lockfile::DEFAULT_FILENAME) end def write_lockfile(sources) Berkshelf::Lockfile.new(sources).write end end end