diff --git a/lib/puppet/provider/repository/git.rb b/lib/puppet/provider/repository/git.rb new file mode 100644 index 0000000..9bf335a --- /dev/null +++ b/lib/puppet/provider/repository/git.rb @@ -0,0 +1,60 @@ +require 'fileutils' + +Puppet::Type.type(:repository).provide(:git) do + desc "Git repository clones" + + # FIX: needs to infer path + CRED_HELPER_PATH = "#{Facter[:boxen_home].value}/bin/boxen-git-credential" + CRED_HELPER = "-c credential.helper=#{CRED_HELPER_PATH}" + GIT_BIN = "#{Facter[:boxen_home].value}/homebrew/bin/git" + commands :git => GIT_BIN + + def self.default_protocol + 'https' + end + + def exists? + File.directory?(@resource[:path]) && + File.directory?("#{@resource[:path]}/.git") + end + + def create + source = expand_source(@resource[:source]) + path = @resource[:path] + + if File.exist? CRED_HELPER_PATH + args = [ + GIT_BIN, + "clone", + CRED_HELPER, + @resource[:extra].to_a.flatten.join(' ').strip, + source, + path + ] + else + args = [ + GIT_BIN, + "clone", + @resource[:extra].to_a.flatten.join(' ').strip, + source, + path + ] + end + + execute args.flatten.join(' '), :uid => Facter[:luser].value + end + + def destroy + path = @resource[:path] + + FileUtils.rm_rf path + end + + def expand_source(source) + if source =~ /\A\S+\/\S+\z/ + "#{@resource[:protocol]}://github.com/#{source}" + else + source + end + end +end diff --git a/lib/puppet/type/repository.rb b/lib/puppet/type/repository.rb new file mode 100644 index 0000000..4eac678 --- /dev/null +++ b/lib/puppet/type/repository.rb @@ -0,0 +1,54 @@ +require 'pathname' + +Puppet.newtype(:repository) do + @doc = "Clones or checks out a repository on a system" + + ensurable do + newvalue(:present) do + provider.create + end + + newvalue(:absent) do + provider.destroy + end + + defaultto :present + end + + newparam(:path, :namevar => true) do + desc "The path of the repository." + + validate do |value| + unless Pathname.new(value).absolute? + raise ArgumentError, "Path is not an absolute path: #{value}" + end + end + end + + newparam(:source) do + desc "The remote source for the repository." + end + + newparam(:protocol) do + desc "The protocol used to fetch the repository." + + defaultto do + if provider.class.respond_to?(:default_protocol) + provider.class.default_protocol + end + end + end + + newparam(:extra, :array_matching => :all) do + desc "Extra actions or information for a provider" + end + + validate do + if self[:source].nil? + # ensure => absent does not need a source + unless self[:ensure] == :absent || self[:ensure] == 'absent' + self.fail "Repository[#{self[:name]}]: You must specify a source" + end + end + end +end diff --git a/spec/unit/puppet/type/repository_spec.rb b/spec/unit/puppet/type/repository_spec.rb new file mode 100644 index 0000000..e1c0085 --- /dev/null +++ b/spec/unit/puppet/type/repository_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +# Stub out some boxen specific Facter facts +Facter.add('boxen_home') { setcode { '/opt/boxen' } } +Facter.add('luser') { setcode { 'skalnik' } } + +require 'puppet/type/repository' + +describe Puppet::Type.type(:repository) do + let(:resource) { + described_class.new(:source => 'boxen/boxen', :path => '/tmp/boxen') + } + + it "should accept an ensure property" do + resource[:ensure] = :present + resource[:ensure].should == :present + end + + it "should accept an absolute path" do + expect { resource[:path] = '/tmp/foo' }.to_not raise_error + end + + it "should not accept a relative path" do + expect { + resource[:path] = 'foo' + }.to raise_error(Puppet::Error, /Path is not an absolute path: foo/) + end + + it "should accept a source parameter" do + resource[:source] = 'boxen/test' + resource[:source].should == 'boxen/test' + end + + it "should accept a protocol parameter" do + resource[:protocol] = 'git' + resource[:protocol].should == 'git' + end + + it "should accept an array of extra options" do + resource[:extra] = ['foo', 'bar'] + resource[:extra].should == ['foo', 'bar'] + end + + it "should fail when not provided with a source" do + expect { + described_class.new(:path => '/tmp/foo') + }.to raise_error(Puppet::Error, /You must specify a source/) + end + + it "should fail when not provided with a path" do + expect { + described_class.new(:source => 'boxen/boxen') + }.to raise_error(Puppet::Error, /Title or name must be provided/) + end +end