В итоге я использовал следующий рецепт, который в основном является копией рецепта очистки в источнике Capistrano , за исключением некоторой дополнительной логики для определения и пропуска каталогов с символическими ссылками:
desc "Clean up old releases"
task :cleanup do
on release_roles :all do |host|
releases = capture(:ls, "-x", releases_path).split
kept_paths = []
within release_path.parent.parent do
root_path = release_path.parent.parent
links = capture(:ls, "-l", "|", "grep", "^l").split("\n")
links.each { |x|
next_link_target = x.split("->")[1]
next_link_target = next_link_target.gsub("/build", "")
target_components = next_link_target.split("/")
next_link_target = target_components[target_components.size - 1]
kept_paths.push(next_link_target)
}
end
valid, invalid = releases.partition { |e| /^\d{14}$/ =~ e }
warn t(:skip_cleanup, host: host.to_s) if invalid.any?
valid, invalid = valid.partition { |v|
split_path = v.split("/")
!kept_paths.include? split_path[split_path.size - 1]
}
if invalid.any?
info "Skipping cleanup of releases: #{invalid} because they are symlinked in the root directory"
end
if valid.count >= fetch(:keep_releases)
info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: valid.count)
directories = (valid - valid.last(fetch(:keep_releases))).map do |release|
releases_path.join(release).to_s
end
if test("[ -d #{current_path} ]")
current_release = capture(:readlink, current_path).to_s
if directories.include?(current_release)
warn t(:wont_delete_current_release, host: host.to_s)
directories.delete(current_release)
end
else
debug t(:no_current_release, host: host.to_s)
end
if directories.any?
execute :rm, "-rf", *directories
else
info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases))
end
end
end
end