diff --git a/lib/puppet/face/module_tool/search.rb b/lib/puppet/face/module_tool/search.rb index e36af3d03..94dd5554a 100644 --- a/lib/puppet/face/module_tool/search.rb +++ b/lib/puppet/face/module_tool/search.rb @@ -1,64 +1,66 @@ Puppet::Face.define(:module_tool, '1.0.0') do action(:search) do summary "Search a repository for a module." description <<-EOT Search a repository for modules whose names match a specific substring. EOT returns "Array of module metadata hashes" examples <<-EOT Search the default repository for a module: $ puppet module_tool search puppetlabs notice: Searching http://forge.puppetlabs.com notice: 24 found. puppetlabs/apache (0.0.3) puppetlabs/collectd (0.0.1) puppetlabs/ruby (0.0.1) puppetlabs/vcsrepo (0.0.4) puppetlabs/gcc (0.0.3) puppetlabs/passenger (0.0.2) puppetlabs/DeveloperBootstrap (0.0.5) jeffmccune/tomcat (1.0.1) puppetlabs/motd (1.0.0) puppetlabs/lvm (0.1.0) puppetlabs/rabbitmq (1.0.4) puppetlabs/prosvc_repo (1.0.1) puppetlabs/stdlib (2.2.0) puppetlabs/java (0.1.5) puppetlabs/activemq (0.1.6) puppetlabs/mcollective (0.1.8) puppetlabs/git (0.0.2) puppetlabs/ntp (0.0.4) puppetlabs/nginx (0.0.1) puppetlabs/cloud_provisioner (0.6.0rc1) puppetlabs/mrepo (0.1.1) puppetlabs/f5 (0.1.0) puppetlabs/firewall (0.0.3) puppetlabs/bprobe (0.0.3) EOT arguments "" option "--module-repository=", "-r=" do default_to { Puppet.settings[:module_repository] } summary "Module repository to use." description <<-EOT Module repository to use. EOT end when_invoked do |term, options| Puppet.notice "Searching #{options[:module_repository]}" Puppet::Module::Tool::Applications::Searcher.run(term, options) end when_rendering :console do |return_value| Puppet.notice "#{return_value.size} found." return_value.map do |match| + # We reference the full_name here when referring to the full_module_name, + # because full_name is what is returned from the forge API call. "#{match['full_name']} (#{match['version']})" end.join("\n") end end end diff --git a/lib/puppet/module_tool.rb b/lib/puppet/module_tool.rb index 3607d6daf..c11fd58b1 100644 --- a/lib/puppet/module_tool.rb +++ b/lib/puppet/module_tool.rb @@ -1,97 +1,97 @@ # Load standard libraries require 'pathname' require 'fileutils' require 'puppet/module_tool/utils' # Define tool module Puppet class Module module Tool # Directory names that should not be checksummed. ARTIFACTS = ['pkg', /^\./, /^~/, /^#/, 'coverage'] - FULL_NAME_PATTERN = /\A([^-\/|.]+)[-|\/](.+)\z/ + FULL_MODULE_NAME_PATTERN = /\A([^-\/|.]+)[-|\/](.+)\z/ REPOSITORY_URL = Puppet.settings[:module_repository] # Is this a directory that shouldn't be checksummed? # # TODO: Should this be part of Checksums? # TODO: Rename this method to reflect it's purpose? # TODO: Shouldn't this be used when building packages too? def self.artifact?(path) case File.basename(path) when *ARTIFACTS true else false end end - # Return the +username+ and +modname+ for a given +full_name+, or raise an + # Return the +username+ and +modname+ for a given +full_module_name+, or raise an # ArgumentError if the argument isn't parseable. - def self.username_and_modname_from(full_name) - if matcher = full_name.match(FULL_NAME_PATTERN) + def self.username_and_modname_from(full_module_name) + if matcher = full_module_name.match(FULL_MODULE_NAME_PATTERN) return matcher.captures else - raise ArgumentError, "Not a valid full name: #{full_name}" + raise ArgumentError, "Not a valid full name: #{full_module_name}" end end # Read HTTP proxy configurationm from Puppet's config file, or the # http_proxy environment variable. def self.http_proxy_env proxy_env = ENV["http_proxy"] || ENV["HTTP_PROXY"] || nil begin return URI.parse(proxy_env) if proxy_env rescue URI::InvalidURIError return nil end return nil end def self.http_proxy_host env = http_proxy_env if env and env.host then return env.host end if Puppet.settings[:http_proxy_host] == 'none' return nil end return Puppet.settings[:http_proxy_host] end def self.http_proxy_port env = http_proxy_env if env and env.port then return env.port end return Puppet.settings[:http_proxy_port] end def self.find_module_root(path) for dir in [path, Dir.pwd].compact if File.exist?(File.join(dir, 'Modulefile')) return dir end end raise ArgumentError, "Could not find a valid module at #{path ? path.inspect : 'current directory'}" end end end end # Load remaining libraries require 'puppet/module_tool/applications' require 'puppet/module_tool/cache' require 'puppet/module_tool/checksums' require 'puppet/module_tool/contents_description' require 'puppet/module_tool/dependency' require 'puppet/module_tool/metadata' require 'puppet/module_tool/modulefile' require 'puppet/module_tool/repository' require 'puppet/module_tool/skeleton' diff --git a/lib/puppet/module_tool/applications/application.rb b/lib/puppet/module_tool/applications/application.rb index 0f0edb92b..fac0d1961 100644 --- a/lib/puppet/module_tool/applications/application.rb +++ b/lib/puppet/module_tool/applications/application.rb @@ -1,82 +1,82 @@ require 'net/http' module Puppet::Module::Tool module Applications class Application include Utils::Interrogation def self.run(*args) new(*args).run end attr_accessor :options def initialize(options = {}) @options = options end def repository @repository ||= Repository.new(@options[:module_repository]) end def run raise NotImplementedError, "Should be implemented in child classes." end def discuss(response, success, failure) case response when Net::HTTPOK, Net::HTTPCreated Puppet.notice success else errors = PSON.parse(response.body)['error'] rescue "HTTP #{response.code}, #{response.body}" Puppet.warning "#{failure} (#{errors})" end end def metadata(require_modulefile = false) unless @metadata unless @path raise SystemExit, "Could not determine module path" end @metadata = Puppet::Module::Tool::Metadata.new contents = ContentsDescription.new(@path) contents.annotate(@metadata) checksums = Checksums.new(@path) checksums.annotate(@metadata) modulefile_path = File.join(@path, 'Modulefile') if File.file?(modulefile_path) Modulefile.evaluate(@metadata, modulefile_path) elsif require_modulefile raise SystemExit, "No Modulefile found." end end @metadata end def load_modulefile! @metadata = nil metadata(true) end # Use to extract and validate a module name and version from a # filename # Note: Must have @filename set to use this def parse_filename! @release_name = File.basename(@filename,'.tar.gz') match = /^(.*?)-(.*?)-(\d+\.\d+\.\d+.*?)$/.match(@release_name) if match then @username, @module_name, @version = match.captures else raise SystemExit, "Could not parse filename to obtain the username, module name and version. (#{@release_name})" end - @full_name = [@username, @module_name].join('-') + @full_module_name = [@username, @module_name].join('-') unless @username && @module_name raise SystemExit, "Username and Module name not provided" end if @version !~ /^(\d+)\.(\d+)\.(\d+)([a-zA-Z][a-zA-Z0-9-]*){0,1}$/ then raise SystemExit, "Invalid version format: #{@version} (Semantic Versions are acceptable: http://semver.org)" end end end end end diff --git a/lib/puppet/module_tool/applications/generator.rb b/lib/puppet/module_tool/applications/generator.rb index 8af5c8484..9dbe09611 100644 --- a/lib/puppet/module_tool/applications/generator.rb +++ b/lib/puppet/module_tool/applications/generator.rb @@ -1,141 +1,141 @@ require 'pathname' require 'fileutils' require 'erb' module Puppet::Module::Tool module Applications class Generator < Application - def initialize(full_name, options = {}) + def initialize(full_module_name, options = {}) begin - @metadata = Metadata.new(:full_name => full_name) + @metadata = Metadata.new(:full_module_name => full_module_name) rescue ArgumentError - raise SystemExit, "Could not generate directory #{full_name.inspect}, you must specify a dash-separated username and module name." + raise SystemExit, "Could not generate directory #{full_module_name.inspect}, you must specify a dash-separated username and module name." end super(options) end def skeleton @skeleton ||= Skeleton.new end def get_binding binding end def run if destination.directory? raise SystemExit, "#{destination} already exists." end Puppet.notice "Generating module at #{Dir.pwd}/#{@metadata.dashed_name}" files_created = [] skeleton.path.find do |path| if path == skeleton destination.mkpath else node = Node.on(path, self) if node node.install! files_created << node.target else Puppet.notice "Could not generate from #{path}" end end end # Return an array of Pathname objects representing file paths of files # and directories just generated. This return value is used by the # module_tool face generate action, and displayed on the console. # # Example return value: # # [ # #, # #, # #, # #, # #, # #, # #, # #, # #, # #, # # "nginx", # "project_url" => "http://github.com/puppetlabs/puppetlabs-nginx", # "version" => "0.0.1", - # "full_name" => "puppetlabs/nginx" - # } + # "full_name" => "puppetlabs/nginx" # full_name comes back from + # } # API all to the forge. # ] # matches end end end end diff --git a/lib/puppet/module_tool/dependency.rb b/lib/puppet/module_tool/dependency.rb index 9472be37f..bb55f5945 100644 --- a/lib/puppet/module_tool/dependency.rb +++ b/lib/puppet/module_tool/dependency.rb @@ -1,24 +1,24 @@ module Puppet::Module::Tool class Dependency - # Instantiates a new module dependency with a +full_name+ (e.g. + # Instantiates a new module dependency with a +full_module_name+ (e.g. # "myuser-mymodule"), and optional +version_requirement+ (e.g. "0.0.1") and # optional repository (a URL string). - def initialize(full_name, version_requirement = nil, repository = nil) - @full_name = full_name - # TODO: add error checking, the next line raises ArgumentError when +full_name+ is invalid - @username, @name = Puppet::Module::Tool.username_and_modname_from(full_name) + def initialize(full_module_name, version_requirement = nil, repository = nil) + @full_module_name = full_module_name + # TODO: add error checking, the next line raises ArgumentError when +full_module_name+ is invalid + @username, @name = Puppet::Module::Tool.username_and_modname_from(full_module_name) @version_requirement = version_requirement @repository = repository ? Repository.new(repository) : nil end # Return PSON representation of this data. def to_pson(*args) - result = { :name => @full_name } + result = { :name => @full_module_name } result[:version_requirement] = @version_requirement if @version_requirement && ! @version_requirement.nil? result[:repository] = @repository.to_s if @repository && ! @repository.nil? result.to_pson(*args) end end end diff --git a/lib/puppet/module_tool/metadata.rb b/lib/puppet/module_tool/metadata.rb index b01ff0c10..f24910aba 100644 --- a/lib/puppet/module_tool/metadata.rb +++ b/lib/puppet/module_tool/metadata.rb @@ -1,132 +1,132 @@ module Puppet::Module::Tool # = Metadata # # This class provides a data structure representing a module's metadata. # It provides some basic parsing, but other data is injected into it using # +annotate+ methods in other classes. class Metadata # The full name of the module, which is a dash-separated combination of the # +username+ and module +name+. - attr_reader :full_name + attr_reader :full_module_name # The name of the user that owns this module. attr_reader :username - # The name of this module. See also +full_name+. + # The name of this module. See also +full_module_name+. attr_reader :name # The version of this module, a string like '0.1.0'. attr_accessor :version # Instantiate from a hash, whose keys are setters in this class. def initialize(settings={}) settings.each do |key, value| send("#{key}=", value) end end # Set the full name of this module, and from it, the +username+ and # module +name+. - def full_name=(full_name) - @full_name = full_name - @username, @name = Puppet::Module::Tool::username_and_modname_from(full_name) + def full_module_name=(full_module_name) + @full_module_name = full_module_name + @username, @name = Puppet::Module::Tool::username_and_modname_from(full_module_name) end # Return an array of the module's Dependency objects. def dependencies return @dependencies ||= [] end def author @author || @username end def author=(author) @author = author end def source @source || 'UNKNOWN' end def source=(source) @source = source end def license @license || 'UNKNOWN' end def license=(license) @license = license end def summary @summary || 'UNKNOWN' end def summary=(summary) @summary = summary end def description @description || 'UNKNOWN' end def description=(description) @description = description end def project_page @project_page || 'UNKNOWN' end def project_page=(project_page) @project_page = project_page end # Return an array of the module's Puppet types, each one is a hash # containing :name and :doc. # TODO Shouldn't this be it's own class? def types return @types ||= [] end # Return module's file checksums. def checksums return @checksums ||= {} end # Return the dashed name of the module, which may either be the # dash-separated combination of the +username+ and module +name+, or just # the module +name+. def dashed_name return [@username, @name].compact.join('-') end # Return the release name, which is the combination of the +dashed_name+ # of the module and its +version+ number. def release_name return [dashed_name, @version].join('-') end # Return the PSON record representing this instance. def to_pson(*args) return { - :name => @full_name, + :name => @full_module_name, :version => @version, :source => source, :author => author, :license => license, :summary => summary, :description => description, :project_page => project_page, :dependencies => dependencies, :types => types, :checksums => checksums }.to_pson(*args) end end end diff --git a/lib/puppet/module_tool/modulefile.rb b/lib/puppet/module_tool/modulefile.rb index 352a5cccf..f09074cfe 100644 --- a/lib/puppet/module_tool/modulefile.rb +++ b/lib/puppet/module_tool/modulefile.rb @@ -1,75 +1,75 @@ module Puppet::Module::Tool # = Modulefile # # This class provides the DSL used for evaluating the module's 'Modulefile'. # These methods are used to concisely define this module's attributes, which # are later rendered as PSON into a 'metadata.json' file. class Modulefile # Read the +filename+ and eval its Ruby code to set values in the Metadata # +metadata+ instance. def self.evaluate(metadata, filename) returning(new(metadata)) do |builder| if File.file?(filename) builder.instance_eval(File.read(filename.to_s), filename.to_s, 1) else Puppet.warning "No Modulefile: #{filename}" end end end # Instantiate with the Metadata +metadata+ instance. def initialize(metadata) @metadata = metadata end - # Set the +full_name+ (e.g. "myuser-mymodule"), which will also set the + # Set the +full_module_name+ (e.g. "myuser-mymodule"), which will also set the # +username+ and module +name+. Required. def name(name) - @metadata.full_name = name + @metadata.full_module_name = name end # Set the module +version+ (e.g., "0.0.1"). Required. def version(version) @metadata.version = version end - # Add a dependency with the full_name +name+ (e.g. "myuser-mymodule"), an + # Add a dependency with the full_module_name +name+ (e.g. "myuser-mymodule"), an # optional +version_requirement+ (e.g. "0.0.1") and +repository+ (a URL # string). Optional. Can be called multiple times to add many dependencies. def dependency(name, version_requirement = nil, repository = nil) @metadata.dependencies << Dependency.new(name, version_requirement, repository) end # Set the source def source(source) @metadata.source = source end # Set the author or default to +username+ def author(author) @metadata.author = author end # Set the license def license(license) @metadata.license = license end # Set the summary def summary(summary) @metadata.summary = summary end # Set the description def description(description) @metadata.description = description end # Set the project page def project_page(project_page) @metadata.project_page = project_page end end end diff --git a/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb b/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb index 178881338..845102d6e 100644 --- a/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb +++ b/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb @@ -1,11 +1,11 @@ -name '<%= metadata.full_name %>' +name '<%= metadata.full_module_name %>' version '0.0.1' source '<%= metadata.source %>' author '<%= metadata.author %>' license '<%= metadata.license %>' summary '<%= metadata.summary %>' description '<%= metadata.description %>' project_page '<%= metadata.project_page %>' ## Add dependencies, if any: # dependency 'username/name', '>= 1.2.0' diff --git a/spec/integration/module_tool_spec.rb b/spec/integration/module_tool_spec.rb index a26f06c9e..6fcf75afd 100644 --- a/spec/integration/module_tool_spec.rb +++ b/spec/integration/module_tool_spec.rb @@ -1,477 +1,477 @@ require 'spec_helper' require 'tmpdir' require 'fileutils' # FIXME This are helper methods that could be used by other tests in the # future, should we move these to a more central location def stub_repository_read(code, body) kind = Net::HTTPResponse.send(:response_class, code.to_s) response = kind.new('1.0', code.to_s, 'HTTP MESSAGE') response.stubs(:read_body).returns(body) Puppet::Module::Tool::Repository.any_instance.stubs(:read_response).returns(response) end def stub_installer_read(body) Puppet::Module::Tool::Applications::Installer.any_instance.stubs(:read_match).returns(body) end def stub_cache_read(body) Puppet::Module::Tool::Cache.any_instance.stubs(:read_retrieve).returns(body) end # Return path to temparory directory for testing. def testdir return @testdir ||= tmpdir("module_tool_testdir") end # Create a temporary testing directory, change into it, and execute the # +block+. When the block exists, remove the test directory and change back # to the previous directory. def mktestdircd(&block) previousdir = Dir.pwd rmtestdir FileUtils.mkdir_p(testdir) Dir.chdir(testdir) block.call ensure rmtestdir Dir.chdir previousdir end # Remove the temporary test directory. def rmtestdir FileUtils.rm_rf(testdir) if File.directory?(testdir) end # END helper methods # Directory that contains sample releases. RELEASE_FIXTURES_DIR = File.join(PuppetSpec::FIXTURE_DIR, "releases") # Return the pathname string to the directory containing the release fixture called +name+. def release_fixture(name) return File.join(RELEASE_FIXTURES_DIR, name) end # Copy the release fixture called +name+ into the current working directory. def install_release_fixture(name) release_fixture(name) FileUtils.cp_r(release_fixture(name), name) end describe "module_tool" do include PuppetSpec::Files before do @tmp_confdir = Puppet[:confdir] = tmpdir("module_tool_test_confdir") @tmp_vardir = Puppet[:vardir] = tmpdir("module_tool_test_vardir") Puppet[:module_repository] = "http://forge.puppetlabs.com" @mytmpdir = Pathname.new(tmpdir("module_tool_test")) @options = {} @options[:install_dir] = @mytmpdir @options[:module_repository] = "http://forge.puppetlabs.com" end def build_and_install_module - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - FileUtils.mv("#{@full_name}/pkg/#{@release_name}.tar.gz", "#{@release_name}.tar.gz") - FileUtils.rm_rf(@full_name) + FileUtils.mv("#{@full_module_name}/pkg/#{@release_name}.tar.gz", "#{@release_name}.tar.gz") + FileUtils.rm_rf(@full_module_name) Puppet::Module::Tool::Applications::Installer.run("#{@release_name}.tar.gz", @options) end # Return STDOUT and STDERR output generated from +block+ as it's run within a temporary test directory. def run(&block) mktestdircd do block.call end end before :all do @username = "myuser" @module_name = "mymodule" - @full_name = "#{@username}-#{@module_name}" + @full_module_name = "#{@username}-#{@module_name}" @version = "0.0.1" - @release_name = "#{@full_name}-#{@version}" + @release_name = "#{@full_module_name}-#{@version}" end before :each do Puppet.settings.stubs(:parse) Puppet::Module::Tool::Cache.clean end after :each do Puppet::Module::Tool::Cache.clean end describe "generate" do it "should generate a module if given a dashed name" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) - File.directory?(@full_name).should == true - modulefile = File.join(@full_name, "Modulefile") + File.directory?(@full_module_name).should == true + modulefile = File.join(@full_module_name, "Modulefile") File.file?(modulefile).should == true metadata = Puppet::Module::Tool::Metadata.new Puppet::Module::Tool::Modulefile.evaluate(metadata, modulefile) - metadata.full_name.should == @full_name + metadata.full_module_name.should == @full_module_name metadata.username.should == @username metadata.name.should == @module_name end end it "should fail if given an undashed name" do run do lambda { Puppet::Module::Tool::Applications::Generator.run("invalid") }.should raise_error(SystemExit) end end it "should fail if directory already exists" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - lambda { Puppet::Module::Tool::Applications::Generator.run(@full_name) }.should raise_error(SystemExit) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + lambda { Puppet::Module::Tool::Applications::Generator.run(@full_module_name) }.should raise_error(SystemExit) end end it "should return an array of Pathname objects representing paths of generated files" do run do - return_value = Puppet::Module::Tool::Applications::Generator.run(@full_name) + return_value = Puppet::Module::Tool::Applications::Generator.run(@full_module_name) return_value.each do |generated_file| generated_file.should be_kind_of(Pathname) end return_value.should be_kind_of(Array) end end end describe "build" do it "should build a module in a directory" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - File.directory?(File.join(@full_name, "pkg", @release_name)).should == true - File.file?(File.join(@full_name, "pkg", @release_name + ".tar.gz")).should == true - metadata_file = File.join(@full_name, "pkg", @release_name, "metadata.json") + File.directory?(File.join(@full_module_name, "pkg", @release_name)).should == true + File.file?(File.join(@full_module_name, "pkg", @release_name + ".tar.gz")).should == true + metadata_file = File.join(@full_module_name, "pkg", @release_name, "metadata.json") File.file?(metadata_file).should == true metadata = PSON.parse(File.read(metadata_file)) - metadata["name"].should == @full_name + metadata["name"].should == @full_module_name metadata["version"].should == @version metadata["checksums"].should be_a_kind_of(Hash) metadata["dependencies"].should == [] metadata["types"].should == [] end end it "should build a module's checksums" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - metadata_file = File.join(@full_name, "pkg", @release_name, "metadata.json") + metadata_file = File.join(@full_module_name, "pkg", @release_name, "metadata.json") metadata = PSON.parse(File.read(metadata_file)) metadata["checksums"].should be_a_kind_of(Hash) - modulefile_path = Pathname.new(File.join(@full_name, "Modulefile")) + modulefile_path = Pathname.new(File.join(@full_module_name, "Modulefile")) metadata["checksums"]["Modulefile"].should == Digest::MD5.hexdigest(modulefile_path.read) end end it "should build a module's types and providers" do run do name = "jamtur01-apache" install_release_fixture name Puppet::Module::Tool::Applications::Builder.run(name) metadata_file = File.join(name, "pkg", "#{name}-0.0.1", "metadata.json") metadata = PSON.parse(File.read(metadata_file)) metadata["types"].size.should == 1 type = metadata["types"].first type["name"].should == "a2mod" type["doc"].should == "Manage Apache 2 modules" type["parameters"].size.should == 1 type["parameters"].first.tap do |o| o["name"].should == "name" o["doc"].should == "The name of the module to be managed" end type["properties"].size.should == 1 type["properties"].first.tap do |o| o["name"].should == "ensure" o["doc"].should =~ /present.+absent/ end type["providers"].size.should == 1 type["providers"].first.tap do |o| o["name"].should == "debian" o["doc"].should =~ /Manage Apache 2 modules on Debian-like OSes/ end end end it "should build a module's dependencies" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - modulefile = File.join(@full_name, "Modulefile") + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + modulefile = File.join(@full_module_name, "Modulefile") dependency1_name = "anotheruser-anothermodule" dependency1_requirement = ">= 1.2.3" dependency2_name = "someuser-somemodule" dependency2_requirement = "4.2" dependency2_repository = "http://some.repo" File.open(modulefile, "a") do |handle| handle.puts "dependency '#{dependency1_name}', '#{dependency1_requirement}'" handle.puts "dependency '#{dependency2_name}', '#{dependency2_requirement}', '#{dependency2_repository}'" end - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - metadata_file = File.join(@full_name, "pkg", "#{@full_name}-#{@version}", "metadata.json") + metadata_file = File.join(@full_module_name, "pkg", "#{@full_module_name}-#{@version}", "metadata.json") metadata = PSON.parse(File.read(metadata_file)) metadata['dependencies'].size.should == 2 metadata['dependencies'].sort_by{|t| t['name']}.tap do |dependencies| dependencies[0].tap do |dependency1| dependency1['name'].should == dependency1_name dependency1['version_requirement'].should == dependency1_requirement dependency1['repository'].should be_nil end dependencies[1].tap do |dependency2| dependency2['name'].should == dependency2_name dependency2['version_requirement'].should == dependency2_requirement dependency2['repository'].should == dependency2_repository end end end end it "should rebuild a module in a directory" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) end end it "should build a module in the current directory" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Dir.chdir(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Dir.chdir(@full_module_name) Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(nil)) File.file?(File.join("pkg", @release_name + ".tar.gz")).should == true end end it "should fail to build a module without a Modulefile" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - FileUtils.rm(File.join(@full_name, "Modulefile")) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + FileUtils.rm(File.join(@full_module_name, "Modulefile")) - lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_name)) }.should raise_error(ArgumentError) + lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_module_name)) }.should raise_error(ArgumentError) end end it "should fail to build a module directory that doesn't exist" do run do - lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_name)) }.should raise_error(ArgumentError) + lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_module_name)) }.should raise_error(ArgumentError) end end it "should fail to build a module in the current directory that's not a module" do run do lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(nil)) }.should raise_error(ArgumentError) end end it "should return a Pathname object representing the path to the release archive." do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name).should be_kind_of(Pathname) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name).should be_kind_of(Pathname) end end end describe "search" do it "should display matching modules" do run do stub_repository_read 200, <<-HERE [ - {"full_name": "cli", "version": "1.0"}, - {"full_name": "web", "version": "2.0"} + {"full_module_name": "cli", "version": "1.0"}, + {"full_module_name": "web", "version": "2.0"} ] HERE Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options).size.should == 2 end end it "should display no matches" do run do stub_repository_read 200, "[]" Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options).should == [] end end it "should fail if can't get a connection" do run do stub_repository_read 500, "OH NOES!!1!" lambda { Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options) }.should raise_error(SystemExit) end end it "should return an array of module metadata hashes" do run do results = <<-HERE [ - {"full_name": "cli", "version": "1.0"}, - {"full_name": "web", "version": "2.0"} + {"full_module_name": "cli", "version": "1.0"}, + {"full_module_name": "web", "version": "2.0"} ] HERE expected = [ - {"version"=>"1.0", "full_name"=>"cli"}, - {"version"=>"2.0", "full_name"=>"web"} + {"version"=>"1.0", "full_module_name"=>"cli"}, + {"version"=>"2.0", "full_module_name"=>"web"} ] stub_repository_read 200, results return_value = Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options) return_value.should == expected return_value.should be_kind_of(Array) end end end describe "install" do it "should install a module to the puppet modulepath by default" do myothertmpdir = Pathname.new(tmpdir("module_tool_test_myothertmpdir")) run do @options[:install_dir] = myothertmpdir Puppet::Module::Tool.unstub(:install_dir) build_and_install_module File.directory?(myothertmpdir + @module_name).should == true File.file?(myothertmpdir + @module_name + 'metadata.json').should == true end end it "should install a module from a filesystem path" do run do build_and_install_module File.directory?(@mytmpdir + @module_name).should == true File.file?(@mytmpdir + @module_name + 'metadata.json').should == true end end it "should install a module from a webserver URL" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - stub_cache_read File.read("#{@full_name}/pkg/#{@release_name}.tar.gz") - FileUtils.rm_rf(@full_name) + stub_cache_read File.read("#{@full_module_name}/pkg/#{@release_name}.tar.gz") + FileUtils.rm_rf(@full_module_name) stub_installer_read <<-HERE {"file": "/foo/bar/#{@release_name}.tar.gz", "version": "#{@version}"} HERE - Puppet::Module::Tool::Applications::Installer.run(@full_name, @options) + Puppet::Module::Tool::Applications::Installer.run(@full_module_name, @options) File.directory?(@mytmpdir + @module_name).should == true File.file?(@mytmpdir + @module_name + 'metadata.json').should == true end end it "should install a module from a webserver URL using a version requirement" # TODO it "should fail if module isn't a slashed name" do run do lambda { Puppet::Module::Tool::Applications::Installer.run("invalid") }.should raise_error(SystemExit) end end it "should fail if module doesn't exist on webserver" do run do stub_installer_read "{}" lambda { Puppet::Module::Tool::Applications::Installer.run("not-found", @options) }.should raise_error(SystemExit) end end it "should fail gracefully when receiving invalid PSON" do pending "Implement PSON error wrapper" # TODO run do stub_installer_read "1/0" lambda { Puppet::Module::Tool::Applications::Installer.run("not-found") }.should raise_error(SystemExit) end end it "should fail if installing a module that's already installed" do run do name = "myuser-mymodule" Dir.mkdir name lambda { Puppet::Module::Tool::Applications::Installer.run(name) }.should raise_error(SystemExit) end end it "should return a Pathname object representing the path to the installed module" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) - stub_cache_read File.read("#{@full_name}/pkg/#{@release_name}.tar.gz") - FileUtils.rm_rf(@full_name) + stub_cache_read File.read("#{@full_module_name}/pkg/#{@release_name}.tar.gz") + FileUtils.rm_rf(@full_module_name) stub_installer_read <<-HERE {"file": "/foo/bar/#{@release_name}.tar.gz", "version": "#{@version}"} HERE - Puppet::Module::Tool::Applications::Installer.run(@full_name, @options).should be_kind_of(Pathname) + Puppet::Module::Tool::Applications::Installer.run(@full_module_name, @options).should be_kind_of(Pathname) end end end describe "clean" do require 'puppet/module_tool' it "should clean cache" do run do build_and_install_module Puppet::Module::Tool::Cache.base_path.directory?.should == true Puppet::Module::Tool::Applications::Cleaner.run Puppet::Module::Tool::Cache.base_path.directory?.should == false end end it "should return a status Hash" do run do build_and_install_module return_value = Puppet::Module::Tool::Applications::Cleaner.run return_value.should include(:msg) return_value.should include(:status) return_value.should be_kind_of(Hash) end end end describe "changes" do it "should return an array of modified files" do run do - Puppet::Module::Tool::Applications::Generator.run(@full_name) - Puppet::Module::Tool::Applications::Builder.run(@full_name) - Dir.chdir("#{@full_name}/pkg/#{@release_name}") + Puppet::Module::Tool::Applications::Generator.run(@full_module_name) + Puppet::Module::Tool::Applications::Builder.run(@full_module_name) + Dir.chdir("#{@full_module_name}/pkg/#{@release_name}") File.open("Modulefile", "a") do |handle| handle.puts handle.puts "# Added" end return_value = Puppet::Module::Tool::Applications::Checksummer.run(".") return_value.should include("Modulefile") return_value.should be_kind_of(Array) end end end end