Skip to content

Commit

Permalink
extensive refactoring around detecting changed local caches; reduces …
Browse files Browse the repository at this point in the history
…cyclomatic complexity and eliminates unnecessary pipefitting
  • Loading branch information
Mark Cornick committed Aug 7, 2009
1 parent 040cdb1 commit c9d956b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 70 deletions.
3 changes: 2 additions & 1 deletion lib/capistrano/recipes/deploy/strategy/exceptions.reek
Expand Up @@ -5,10 +5,11 @@ Duplication:
- command
- deploy!
- rsync_host
- remove_cache_if_repo_changed

FeatureEnvy:
exclude:
- check!

LongMethod:
max_statements: 15
max_statements: 10
54 changes: 25 additions & 29 deletions lib/capistrano/recipes/deploy/strategy/rsync_with_remote_cache.rb
Expand Up @@ -6,6 +6,13 @@ module Deploy
module Strategy
class RsyncWithRemoteCache < Remote

INFO_COMMANDS = {
:subversion => "svn info . | sed -n \'s/URL: //p\'",
:git => "git config remote.origin.url",
:mercurial => "hg showconfig paths.default",
:bzr => "bzr info | grep parent | sed \'s/^.*parent branch: //\'"
}

# The deployment method itself, in three major steps: update the local cache, update the remote
# cache, and copy the remote cache into place.
def deploy!
Expand Down Expand Up @@ -63,45 +70,34 @@ def rsync_host(server)
end
end

# Command to get source from SCM on the local side. If the local_cache directory exists,
# we check to see if it's an SCM checkout that matches the currently configured repository.
# If it matches, we update it. If it doesn't match (either it's for another repository or
# not a checkout at all), we remove the directory and recreate it with a fresh SCM checkout.
# If the directory doesn't exist, we create it with a fresh SCM checkout.
# Remove the local cache (so it can be recreated) if the repository URL has changed
# since the last deployment.
# TODO: punt in some sensible way if local_cache exists but is a regular file.
def command
case configuration[:scm]
when :subversion
info_command = "svn info #{local_cache} | sed -n 's/URL: //p'"
when :git
info_command = "cd #{local_cache} && git config remote.origin.url"
when :mercurial
info_command = "cd #{local_cache} && hg showconfig paths.default"
when :bzr
info_command = "cd #{local_cache} && bzr info | grep parent | sed 's/^.*parent branch: //'"
else
# an effective no-op
info_command = "echo #{configuration[:repository]}"
end
cache_info = IO.popen(info_command)

cached_repository = cache_info.gets
cache_info.close
if cached_repository && cached_repository.chomp != configuration[:repository]
logger.trace "repository has changed; removing old local cache"
FileUtils.rm_rf local_cache
def remove_cache_if_repo_changed
if INFO_COMMANDS[configuration[:scm]] && File.directory?(local_cache)
info_command = "cd #{local_cache} && #{INFO_COMMANDS[configuration[:scm]]}"
cached_repo_url = IO.popen(info_command){|pipe| pipe.readline}.chomp
if cached_repo_url != configuration[:repository]
logger.trace "repository has changed; removing old local cache"
FileUtils.rm_rf(local_cache)
end
end
end

# Command to get source from SCM on the local side. The local cache is either created,
# updated, or destroyed and recreated depending on whether it exists and is a cache of
# the right repository.
def command
remove_cache_if_repo_changed
if File.exists?(local_cache) && File.directory?(local_cache)
logger.trace "updating local cache to revision #{revision}"
cmd = source.sync(revision, local_cache)
return source.sync(revision, local_cache)
else
logger.trace "creating local cache with revision #{revision}"
File.delete(local_cache) if File.exists?(local_cache)
Dir.mkdir(File.dirname(local_cache)) unless File.directory?(File.dirname(local_cache))
cmd = source.checkout(revision, local_cache)
return source.checkout(revision, local_cache)
end
cmd
end
end
end
Expand Down
64 changes: 24 additions & 40 deletions test/capistrano_rsync_with_remote_cache_test.rb
Expand Up @@ -9,25 +9,9 @@ def stub_configuration(hash)
@rwrc.expects(:configuration).at_least_once.returns(hash)
end

def stub_creation_of_new_local_cache
File.expects(:exists?).with('.rsync_cache').times(2).returns(false)
File.expects(:directory?).with(File.dirname('.rsync_cache')).returns(false)
Dir.expects(:mkdir).with(File.dirname('.rsync_cache'))
source_stub = stub()
source_stub.expects(:checkout)
@rwrc.expects(:source).returns(source_stub)
end

def stub_detection_of_changed_local_cache(command, returns)
cache_info_stub = stub()
cache_info_stub.expects(:gets).returns(returns)
cache_info_stub.expects(:close)
IO.expects(:popen).with(command).returns(cache_info_stub)
end

def stub_recreation_of_local_cache
FileUtils.expects(:rm_rf).with('.rsync_cache')
stub_creation_of_new_local_cache
def stub_detection_of_changed_local_cache(command, returned)
File.expects(:directory?).with('.rsync_cache').returns(true)
IO.expects(:popen).with(command).returns(returned)
end

context 'RsyncWithRemoteCache' do
Expand Down Expand Up @@ -128,66 +112,66 @@ def stub_recreation_of_local_cache
end
end

context 'command' do
context 'remove_cache_if_repo_changed' do
should 'purge local cache if it detects subversion info has changed' do
stub_configuration(:scm => :subversion, :repository => 'repository')
stub_detection_of_changed_local_cache("svn info .rsync_cache | sed -n 's/URL: //p'", "URL: url\n")
stub_recreation_of_local_cache
@rwrc.send(:command)
stub_detection_of_changed_local_cache("cd .rsync_cache && svn info . | sed -n 's/URL: //p'", "URL: url\n")
FileUtils.expects(:rm_rf).with('.rsync_cache')
@rwrc.send(:remove_cache_if_repo_changed)
end

should 'purge local cache if it detects git info has changed' do
stub_configuration(:scm => :git, :repository => 'repository')
stub_detection_of_changed_local_cache("cd .rsync_cache && git config remote.origin.url", "beep\n")
stub_recreation_of_local_cache
@rwrc.send(:command)
FileUtils.expects(:rm_rf).with('.rsync_cache')
@rwrc.send(:remove_cache_if_repo_changed)
end

should 'purge local cache if it detects hg info has changed' do
stub_configuration(:scm => :mercurial, :repository => 'repository')
stub_detection_of_changed_local_cache("cd .rsync_cache && hg showconfig paths.default", "beep\n")
stub_recreation_of_local_cache
@rwrc.send(:command)
FileUtils.expects(:rm_rf).with('.rsync_cache')
@rwrc.send(:remove_cache_if_repo_changed)
end

should 'purge local cache if it detects bzr info has changed' do
stub_configuration(:scm => :bzr, :repository => 'repository')
stub_detection_of_changed_local_cache("cd .rsync_cache && bzr info | grep parent | sed 's/^.*parent branch: //'", "beep\n")
stub_recreation_of_local_cache
@rwrc.send(:command)
FileUtils.expects(:rm_rf).with('.rsync_cache')
@rwrc.send(:remove_cache_if_repo_changed)
end

should 'not attempt to purge local cache that does not exist' do
stub_configuration(:scm => :subversion, :repository => 'repository')
stub_detection_of_changed_local_cache("svn info .rsync_cache | sed -n 's/URL: //p'", nil)
File.expects(:directory?).with('.rsync_cache').returns(false)
FileUtils.expects(:rm_rf).with('.rsync_cache').never
stub_creation_of_new_local_cache

@rwrc.send(:command)
@rwrc.send(:remove_cache_if_repo_changed)
end

should 'not attempt to purge local cache if the scm is not supported by this gem' do
stub_configuration(:scm => :cvs, :repository => 'repository')
stub_detection_of_changed_local_cache("echo repository", "repository\n")
FileUtils.expects(:rm_rf).with('.rsync_cache').never
stub_creation_of_new_local_cache

@rwrc.send(:command)
@rwrc.send(:remove_cache_if_repo_changed)
end
end

context 'command' do
should 'update local cache if it exists' do
File.expects(:exists?).with('.rsync_cache').returns(true)
File.expects(:directory?).with('.rsync_cache').returns(true)
source_stub = stub()
source_stub.expects(:sync)
@rwrc.expects(:source).returns(source_stub)

@rwrc.send(:command)
end

should 'create local cache if it does not exist' do
stub_creation_of_new_local_cache

File.expects(:exists?).with('.rsync_cache').times(2).returns(false)
File.expects(:directory?).with(File.dirname('.rsync_cache')).returns(false)
Dir.expects(:mkdir).with(File.dirname('.rsync_cache'))
source_stub = stub()
source_stub.expects(:checkout)
@rwrc.expects(:source).returns(source_stub)
@rwrc.send(:command)
end
end
Expand Down

0 comments on commit c9d956b

Please sign in to comment.