Basic CVS support
This commit is contained in:
42
README.CVS.markdown
Normal file
42
README.CVS.markdown
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
Using vcsrepo with CVS
|
||||||
|
======================
|
||||||
|
|
||||||
|
To create a blank repository
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Define a `vcsrepo` without a `source` or `revision`:
|
||||||
|
|
||||||
|
vcsrepo { "/path/to/repo":
|
||||||
|
ensure => present,
|
||||||
|
provider => cvs
|
||||||
|
}
|
||||||
|
|
||||||
|
To checkout/update from a repository
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
To get the current mainline:
|
||||||
|
|
||||||
|
vcsrepo { "/path/to/workspace":
|
||||||
|
ensure => present,
|
||||||
|
provider => cvs,
|
||||||
|
source => ":pserver:anonymous@example.com:/sources/myproj"
|
||||||
|
}
|
||||||
|
|
||||||
|
You can use the `compression` parameter (it works like CVS `-z`):
|
||||||
|
|
||||||
|
vcsrepo { "/path/to/workspace":
|
||||||
|
ensure => present,
|
||||||
|
provider => cvs,
|
||||||
|
compression => 3,
|
||||||
|
source => ":pserver:anonymous@example.com:/sources/myproj"
|
||||||
|
}
|
||||||
|
|
||||||
|
For a specific tag, use `revision`:
|
||||||
|
|
||||||
|
vcsrepo { "/path/to/workspace":
|
||||||
|
ensure => present,
|
||||||
|
provider => cvs,
|
||||||
|
compression => 3,
|
||||||
|
source => ":pserver:anonymous@example.com:/sources/myproj",
|
||||||
|
revision => "SOMETAG"
|
||||||
|
}
|
||||||
87
lib/puppet/provider/vcsrepo/cvs.rb
Normal file
87
lib/puppet/provider/vcsrepo/cvs.rb
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
Puppet::Type.type(:vcsrepo).provide(:cvs) do
|
||||||
|
desc "Supports CVS repositories/workspaces"
|
||||||
|
|
||||||
|
commands :cvs => 'cvs'
|
||||||
|
defaultfor :cvs => :exists
|
||||||
|
|
||||||
|
def create
|
||||||
|
if !@resource.value(:source)
|
||||||
|
create_repository(@resource.value(:path))
|
||||||
|
else
|
||||||
|
checkout_repository
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exists?
|
||||||
|
if @resource.value(:source)
|
||||||
|
directory = File.join(@resource.value(:path), 'CVS')
|
||||||
|
else
|
||||||
|
directory = File.join(@resource.value(:path), 'CVSROOT')
|
||||||
|
end
|
||||||
|
File.directory?(directory)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
FileUtils.rm_rf(@resource.value(:path))
|
||||||
|
end
|
||||||
|
|
||||||
|
def revision
|
||||||
|
if File.exist?(tag_file)
|
||||||
|
contents = File.read(tag_file)
|
||||||
|
# Note: Doesn't differentiate between N and T entries
|
||||||
|
contents[1..-1]
|
||||||
|
else
|
||||||
|
'MAIN'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def revision=(desired)
|
||||||
|
at_path do
|
||||||
|
cvs('update', '-r', desired, '.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def tag_file
|
||||||
|
File.join(@resource.value(:path), 'CVS', 'Tag')
|
||||||
|
end
|
||||||
|
|
||||||
|
def checkout_repository
|
||||||
|
dirname, basename = File.split(@resource.value(:path))
|
||||||
|
Dir.chdir(dirname) do
|
||||||
|
args = ['-d', @resource.value(:source)]
|
||||||
|
if @resource.value(:compression)
|
||||||
|
args.push('-z', @resource.value(:compression))
|
||||||
|
end
|
||||||
|
args.push('checkout', '-d', basename, module_name)
|
||||||
|
cvs(*args)
|
||||||
|
end
|
||||||
|
if @resource.value(:revision)
|
||||||
|
self.revision = @resource.value(:revision)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# When the source:
|
||||||
|
# * Starts with ':' (eg, :pserver:...)
|
||||||
|
def module_name
|
||||||
|
if (source = @resource.value(:source))
|
||||||
|
source[0, 1] == ':' ? File.basename(source) : '.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_repository(path)
|
||||||
|
cvs('-d', path, 'init')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Note: We don't rely on Dir.chdir's behavior of automatically returning the
|
||||||
|
# value of the last statement -- for easier stubbing.
|
||||||
|
def at_path(&block) #:nodoc:
|
||||||
|
value = nil
|
||||||
|
Dir.chdir(@resource.value(:path)) do
|
||||||
|
value = yield
|
||||||
|
end
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -56,12 +56,6 @@ Puppet::Type.type(:vcsrepo).provide(:svn) do
|
|||||||
svnadmin(*args)
|
svnadmin(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset(desired)
|
|
||||||
at_path do
|
|
||||||
git('reset', '--hard', desired)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Note: We don't rely on Dir.chdir's behavior of automatically returning the
|
# Note: We don't rely on Dir.chdir's behavior of automatically returning the
|
||||||
# value of the last statement -- for easier stubbing.
|
# value of the last statement -- for easier stubbing.
|
||||||
def at_path(&block) #:nodoc:
|
def at_path(&block) #:nodoc:
|
||||||
|
|||||||
@@ -13,12 +13,20 @@ Puppet::Type.newtype(:vcsrepo) do
|
|||||||
def retrieve
|
def retrieve
|
||||||
prov = @resource.provider
|
prov = @resource.provider
|
||||||
if prov
|
if prov
|
||||||
if prov.respond_to?(:working_copy_exists?) && prov.working_copy_exists?
|
if prov.respond_to?(:bare_exists?)
|
||||||
:present
|
if prov.respond_to?(:working_copy_exists?) && prov.working_copy_exists?
|
||||||
elsif prov.respond_to?(:bare_exists?) && prov.bare_exists?
|
:present
|
||||||
:bare
|
elsif prov.respond_to?(:bare_exists?) && prov.bare_exists?
|
||||||
|
:bare
|
||||||
|
else
|
||||||
|
:absent
|
||||||
|
end
|
||||||
else
|
else
|
||||||
:absent
|
if prov.exists?
|
||||||
|
:present
|
||||||
|
else
|
||||||
|
:absent
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
:absent
|
:absent
|
||||||
@@ -39,10 +47,7 @@ Puppet::Type.newtype(:vcsrepo) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
newparam(:source) do
|
newparam(:source) do
|
||||||
desc "The source URL for the repository"
|
desc "The source URI for the repository"
|
||||||
validate do |value|
|
|
||||||
URI.parse(value)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
newparam(:fstype) do
|
newparam(:fstype) do
|
||||||
@@ -54,4 +59,13 @@ Puppet::Type.newtype(:vcsrepo) do
|
|||||||
newvalue(/^\S+$/)
|
newvalue(/^\S+$/)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
newparam :compression do
|
||||||
|
desc "Compression level (used by CVS)"
|
||||||
|
validate do |amount|
|
||||||
|
unless Integer(amount).between?(0, 6)
|
||||||
|
raise ArgumentError, "Unsupported compression level: #{amount} (expected 0-6)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
137
spec/unit/puppet/provider/vcsrepo/cvs_spec.rb
Normal file
137
spec/unit/puppet/provider/vcsrepo/cvs_spec.rb
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
require 'pathname'; Pathname.new(__FILE__).realpath.ascend { |x| begin; require (x + 'spec_helper.rb'); break; rescue LoadError; end }
|
||||||
|
|
||||||
|
provider_class = Puppet::Type.type(:vcsrepo).provider(:cvs)
|
||||||
|
|
||||||
|
describe provider_class do
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
@resource = stub("resource")
|
||||||
|
@provider = provider_class.new(@resource)
|
||||||
|
@path = '/tmp/vcsrepo'
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when creating' do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:path).returns(@path).at_least_once
|
||||||
|
end
|
||||||
|
context "when a source is given" do
|
||||||
|
before do
|
||||||
|
@source = ":pserver:anonymous@example.com:/sources/myproj"
|
||||||
|
@resource.expects(:value).with(:source).returns(@source).at_least_once
|
||||||
|
Dir.expects(:chdir).with(File.dirname(@path)).yields
|
||||||
|
end
|
||||||
|
context "and when a revision is given" do
|
||||||
|
before do
|
||||||
|
@tag = 'SOMETAG'
|
||||||
|
@resource.expects(:value).with(:revision).returns(@tag).at_least_once
|
||||||
|
@resource.expects(:value).with(:compression).returns(nil).at_least_once
|
||||||
|
end
|
||||||
|
it "should execute 'cvs checkout' and 'cvs update -r'" do
|
||||||
|
@provider.expects(:cvs).with('-d', @source, 'checkout', '-d', File.basename(@path), File.basename(@source))
|
||||||
|
Dir.expects(:chdir).with(@path).yields
|
||||||
|
@provider.expects(:cvs).with('update', '-r', @tag, '.')
|
||||||
|
@provider.create
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "and when a revision is not given" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:revision).returns(nil).at_least_once
|
||||||
|
@resource.expects(:value).with(:compression).returns(nil).at_least_once
|
||||||
|
end
|
||||||
|
it "should just execute 'cvs checkout' without a revision" do
|
||||||
|
@provider.expects(:cvs).with('-d', @source, 'checkout', '-d', File.basename(@path), File.basename(@source))
|
||||||
|
@provider.create
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "when a compression level is given" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:revision).returns(nil).at_least_once
|
||||||
|
@resource.expects(:value).with(:compression).returns('3').at_least_once
|
||||||
|
end
|
||||||
|
it "should just execute 'cvs checkout' without a revision" do
|
||||||
|
@provider.expects(:cvs).with('-d', @source, '-z', '3', 'checkout', '-d', File.basename(@path), File.basename(@source))
|
||||||
|
@provider.create
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "when a source is not given" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:source).returns(nil)
|
||||||
|
end
|
||||||
|
it "should execute 'cvs init'" do
|
||||||
|
@provider.expects(:cvs).with('-d', @path, 'init')
|
||||||
|
@provider.create
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when destroying' do
|
||||||
|
it "it should remove the directory" do
|
||||||
|
@resource.expects(:value).with(:path).returns(@path).at_least_once
|
||||||
|
FileUtils.expects(:rm_rf).with(@path)
|
||||||
|
@provider.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when checking existence" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:path).returns(@path)
|
||||||
|
end
|
||||||
|
context "when a source is provided" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:source).returns(":pserver:anonymous@example.com:/sources/myproj")
|
||||||
|
end
|
||||||
|
it "should check for the CVS directory" do
|
||||||
|
File.expects(:directory?).with(File.join(@path, 'CVS'))
|
||||||
|
@provider.exists?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "when a source is not provided" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:source).returns(nil)
|
||||||
|
end
|
||||||
|
it "should check for the CVSROOT directory" do
|
||||||
|
File.expects(:directory?).with(File.join(@path, 'CVSROOT'))
|
||||||
|
@provider.exists?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when checking the revision property" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:path).returns(@path).at_least_once
|
||||||
|
@tag_file = File.join(@path, 'CVS', 'Tag')
|
||||||
|
end
|
||||||
|
context "when CVS/Tag exists" do
|
||||||
|
before do
|
||||||
|
@tag = 'HEAD'
|
||||||
|
File.expects(:exist?).with(@tag_file).returns(true)
|
||||||
|
end
|
||||||
|
it "should read CVS/Tag" do
|
||||||
|
File.expects(:read).with(@tag_file).returns("T#{@tag}")
|
||||||
|
@provider.revision.should == @tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "when CVS/Tag does not exist" do
|
||||||
|
before do
|
||||||
|
File.expects(:exist?).with(@tag_file).returns(false)
|
||||||
|
end
|
||||||
|
it "assumes MAIN" do
|
||||||
|
@provider.revision.should == 'MAIN'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when setting the revision property" do
|
||||||
|
before do
|
||||||
|
@resource.expects(:value).with(:path).returns(@path).at_least_once
|
||||||
|
@tag = 'SOMETAG'
|
||||||
|
end
|
||||||
|
it "should use 'cvs update -r'" do
|
||||||
|
Dir.expects(:chdir).with(@path).yields
|
||||||
|
@provider.expects('cvs').with('update', '-r', @tag, '.')
|
||||||
|
@provider.revision = @tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user