Commit ebfd838b authored by Kyle Fuller's avatar Kyle Fuller

[Repo Command] Refactor into multiple files #1986

parent 7f38d3f7
require 'fileutils'
require 'cocoapods/command/repo/add'
require 'cocoapods/command/repo/lint'
require 'cocoapods/command/repo/list'
require 'cocoapods/command/repo/push'
require 'cocoapods/command/repo/remove'
require 'cocoapods/command/repo/update'
module Pod
class Command
......@@ -11,273 +16,6 @@ module Pod
self.summary = 'Manage spec-repositories'
self.default_subcommand = 'list'
class Add < Repo
self.summary = 'Add a spec repo.'
self.description = <<-DESC
Clones `URL` in the local spec-repos directory at `~/.cocoapods/repos/`. The
remote can later be referred to by `NAME`.
DESC
self.arguments = [
CLAide::Argument.new('NAME', true),
CLAide::Argument.new('URL', true),
CLAide::Argument.new('BRANCH', false),
]
def self.options
[
['--shallow', 'Create a shallow clone (fast clone, but no push capabilities)'],
].concat(super)
end
def initialize(argv)
@shallow = argv.flag?('shallow', false)
@name, @url, @branch = argv.shift_argument, argv.shift_argument, argv.shift_argument
super
end
def validate!
super
unless @name && @url
help! 'Adding a repo needs a `NAME` and a `URL`.'
end
end
def run
prefix = @shallow ? 'Creating shallow clone of' : 'Cloning'
UI.section("#{prefix} spec repo `#{@name}` from `#{@url}`#{" (branch `#{@branch}`)" if @branch}") do
config.repos_dir.mkpath
Dir.chdir(config.repos_dir) do
command = "clone '#{@url}' #{@name}"
command << ' --depth=1' if @shallow
git!(command)
end
Dir.chdir(dir) { git!("checkout #{@branch}") } if @branch
SourcesManager.check_version_information(dir)
end
end
end
#-----------------------------------------------------------------------#
class Update < Repo
self.summary = 'Update a spec repo.'
self.description = <<-DESC
Updates the local clone of the spec-repo `NAME`. If `NAME` is omitted
this will update all spec-repos in `~/.cocoapods/repos`.
DESC
self.arguments = [
CLAide::Argument.new('NAME', false),
]
def initialize(argv)
@name = argv.shift_argument
super
end
def run
SourcesManager.update(@name, true)
end
end
#-----------------------------------------------------------------------#
class Lint < Repo
self.summary = 'Validates all specs in a repo.'
self.description = <<-DESC
Lints the spec-repo `NAME`. If a directory is provided it is assumed
to be the root of a repo. Finally, if `NAME` is not provided this
will lint all the spec-repos known to CocoaPods.
DESC
self.arguments = [
CLAide::Argument.new(%w(NAME DIRECTORY), false),
]
def self.options
[['--only-errors', 'Lint presents only the errors']].concat(super)
end
def initialize(argv)
@name = argv.shift_argument
@only_errors = argv.flag?('only-errors')
super
end
# @todo Part of this logic needs to be ported to cocoapods-core so web
# services can validate the repo.
#
# @todo add UI.print and enable print statements again.
#
def run
if @name
dirs = File.exist?(@name) ? [Pathname.new(@name)] : [dir]
else
dirs = config.repos_dir.children.select(&:directory?)
end
dirs.each do |dir|
SourcesManager.check_version_information(dir)
UI.puts "\nLinting spec repo `#{dir.realpath.basename}`\n".yellow
validator = Source::HealthReporter.new(dir)
validator.pre_check do |_name, _version|
UI.print '.'
end
report = validator.analyze
UI.puts
UI.puts
report.pods_by_warning.each do |message, versions_by_name|
UI.puts "-> #{message}".yellow
versions_by_name.each { |name, versions| UI.puts " - #{name} (#{versions * ', '})" }
UI.puts
end
report.pods_by_error.each do |message, versions_by_name|
UI.puts "-> #{message}".red
versions_by_name.each { |name, versions| UI.puts " - #{name} (#{versions * ', '})" }
UI.puts
end
UI.puts "Analyzed #{report.analyzed_paths.count} podspecs files.\n\n"
if report.pods_by_error.count.zero?
UI.puts 'All the specs passed validation.'.green << "\n\n"
else
raise Informative, "#{report.pods_by_error.count} podspecs failed validation."
end
end
end
end
#-----------------------------------------------------------------------#
class Remove < Repo
self.summary = 'Remove a spec repo'
self.description = <<-DESC
Deletes the remote named `NAME` from the local spec-repos directory at `~/.cocoapods/repos/.`
DESC
self.arguments = [
CLAide::Argument.new('NAME', true),
]
def initialize(argv)
@name = argv.shift_argument
super
end
def validate!
super
help! 'Deleting a repo needs a `NAME`.' unless @name
help! "repo #{@name} does not exist" unless File.directory?(dir)
help! "You do not have permission to delete the #{@name} repository." \
'Perhaps try prefixing this command with sudo.' unless File.writable?(dir)
end
def run
UI.section("Removing spec repo `#{@name}`") do
FileUtils.rm_rf(dir)
end
end
end
#-----------------------------------------------------------------------#
class List < Repo
self.summary = 'List repos'
self.description = <<-DESC
List the repos from the local spec-repos directory at `~/.cocoapods/repos/.`
DESC
def self.options
[["--count-only", "Show the total number of repos"]].concat(super)
end
def initialize(argv)
@count_only = argv.flag?('count-only')
super
end
# @output Examples:
#
# master
# - type: git (origin)
# - URL: https://github.com/CocoaPods/Specs.git
# - path: /Users/lascorbe/.cocoapods/repos/master
#
# test
# - type: local copy
# - path: /Users/lascorbe/.cocoapods/repos/test
#
def run
sources = SourcesManager.all
print_sources(sources) unless @count_only
print_count_of_sources(sources)
end
private
# Pretty-prints the source at the given path.
#
# @param [String,Pathname] path
# The path of the source to be printed.
#
# @return [void]
#
def print_source_at_path(path)
Dir.chdir(path) do
if SourcesManager.git_repo?(path)
remote_name = branch_remote_name(branch_name)
if remote_name
UI.puts "- Type: git (#{remote_name})"
url = url_of_git_repo(remote_name)
UI.puts "- URL: #{url}"
else
UI.puts "- Type: git (no remote information available)"
end
else
UI.puts "- Type: local copy"
end
UI.puts "- Path: #{path}"
end
end
# Pretty-prints the given sources.
#
# @param [Array<Source>] sources
# The sources that should be printed.
#
# @return [void]
#
def print_sources(sources)
sources.each do |source|
UI.title source.name do
print_source_at_path source.repo
end
end
UI.puts "\n"
end
# Pretty-prints the number of sources.
#
# @param [Array<Source>] sources
# The sources whose count should be printed.
#
# @return [void]
#
def print_count_of_sources(sources)
number_of_repos = sources.length
repo_string = number_of_repos != 1 ? 'repos' : 'repo'
UI.puts "#{number_of_repos} #{repo_string}".green
end
end
#-----------------------------------------------------------------------#
extend Executable
......
module Pod
class Command
class Repo < Command
class Add < Repo
self.summary = 'Add a spec repo.'
self.description = <<-DESC
Clones `URL` in the local spec-repos directory at `~/.cocoapods/repos/`. The
remote can later be referred to by `NAME`.
DESC
self.arguments = [
CLAide::Argument.new('NAME', true),
CLAide::Argument.new('URL', true),
CLAide::Argument.new('BRANCH', false),
]
def self.options
[
['--shallow', 'Create a shallow clone (fast clone, but no push capabilities)'],
].concat(super)
end
def initialize(argv)
@shallow = argv.flag?('shallow', false)
@name, @url, @branch = argv.shift_argument, argv.shift_argument, argv.shift_argument
super
end
def validate!
super
unless @name && @url
help! 'Adding a repo needs a `NAME` and a `URL`.'
end
end
def run
prefix = @shallow ? 'Creating shallow clone of' : 'Cloning'
UI.section("#{prefix} spec repo `#{@name}` from `#{@url}`#{" (branch `#{@branch}`)" if @branch}") do
config.repos_dir.mkpath
Dir.chdir(config.repos_dir) do
command = "clone '#{@url}' #{@name}"
command << ' --depth=1' if @shallow
git!(command)
end
Dir.chdir(dir) { git!("checkout #{@branch}") } if @branch
SourcesManager.check_version_information(dir)
end
end
end
end
end
end
module Pod
class Command
class Repo < Command
class Lint < Repo
self.summary = 'Validates all specs in a repo.'
self.description = <<-DESC
Lints the spec-repo `NAME`. If a directory is provided it is assumed
to be the root of a repo. Finally, if `NAME` is not provided this
will lint all the spec-repos known to CocoaPods.
DESC
self.arguments = [
CLAide::Argument.new(%w(NAME DIRECTORY), false),
]
def self.options
[['--only-errors', 'Lint presents only the errors']].concat(super)
end
def initialize(argv)
@name = argv.shift_argument
@only_errors = argv.flag?('only-errors')
super
end
# @todo Part of this logic needs to be ported to cocoapods-core so web
# services can validate the repo.
#
# @todo add UI.print and enable print statements again.
#
def run
if @name
dirs = File.exist?(@name) ? [Pathname.new(@name)] : [dir]
else
dirs = config.repos_dir.children.select(&:directory?)
end
dirs.each do |dir|
SourcesManager.check_version_information(dir)
UI.puts "\nLinting spec repo `#{dir.realpath.basename}`\n".yellow
validator = Source::HealthReporter.new(dir)
validator.pre_check do |_name, _version|
UI.print '.'
end
report = validator.analyze
UI.puts
UI.puts
report.pods_by_warning.each do |message, versions_by_name|
UI.puts "-> #{message}".yellow
versions_by_name.each { |name, versions| UI.puts " - #{name} (#{versions * ', '})" }
UI.puts
end
report.pods_by_error.each do |message, versions_by_name|
UI.puts "-> #{message}".red
versions_by_name.each { |name, versions| UI.puts " - #{name} (#{versions * ', '})" }
UI.puts
end
UI.puts "Analyzed #{report.analyzed_paths.count} podspecs files.\n\n"
if report.pods_by_error.count.zero?
UI.puts 'All the specs passed validation.'.green << "\n\n"
else
raise Informative, "#{report.pods_by_error.count} podspecs failed validation."
end
end
end
end
end
end
end
module Pod
class Command
class Repo < Command
class List < Repo
self.summary = 'List repos'
self.description = <<-DESC
List the repos from the local spec-repos directory at `~/.cocoapods/repos/.`
DESC
def self.options
[["--count-only", "Show the total number of repos"]].concat(super)
end
def initialize(argv)
@count_only = argv.flag?('count-only')
super
end
# @output Examples:
#
# master
# - type: git (origin)
# - URL: https://github.com/CocoaPods/Specs.git
# - path: /Users/lascorbe/.cocoapods/repos/master
#
# test
# - type: local copy
# - path: /Users/lascorbe/.cocoapods/repos/test
#
def run
sources = SourcesManager.all
print_sources(sources) unless @count_only
print_count_of_sources(sources)
end
private
# Pretty-prints the source at the given path.
#
# @param [String,Pathname] path
# The path of the source to be printed.
#
# @return [void]
#
def print_source_at_path(path)
Dir.chdir(path) do
if SourcesManager.git_repo?(path)
remote_name = branch_remote_name(branch_name)
if remote_name
UI.puts "- Type: git (#{remote_name})"
url = url_of_git_repo(remote_name)
UI.puts "- URL: #{url}"
else
UI.puts "- Type: git (no remote information available)"
end
else
UI.puts "- Type: local copy"
end
UI.puts "- Path: #{path}"
end
end
# Pretty-prints the given sources.
#
# @param [Array<Source>] sources
# The sources that should be printed.
#
# @return [void]
#
def print_sources(sources)
sources.each do |source|
UI.title source.name do
print_source_at_path source.repo
end
end
UI.puts "\n"
end
# Pretty-prints the number of sources.
#
# @param [Array<Source>] sources
# The sources whose count should be printed.
#
# @return [void]
#
def print_count_of_sources(sources)
number_of_repos = sources.length
repo_string = number_of_repos != 1 ? 'repos' : 'repo'
UI.puts "#{number_of_repos} #{repo_string}".green
end
end
end
end
end
module Pod
class Command
class Repo < Command
class Remove < Repo
self.summary = 'Remove a spec repo'
self.description = <<-DESC
Deletes the remote named `NAME` from the local spec-repos directory at `~/.cocoapods/repos/.`
DESC
self.arguments = [
CLAide::Argument.new('NAME', true),
]
def initialize(argv)
@name = argv.shift_argument
super
end
def validate!
super
help! 'Deleting a repo needs a `NAME`.' unless @name
help! "repo #{@name} does not exist" unless File.directory?(dir)
help! "You do not have permission to delete the #{@name} repository." \
'Perhaps try prefixing this command with sudo.' unless File.writable?(dir)
end
def run
UI.section("Removing spec repo `#{@name}`") do
FileUtils.rm_rf(dir)
end
end
end
end
end
end
module Pod
class Command
class Repo < Command
class Update < Repo
self.summary = 'Update a spec repo.'
self.description = <<-DESC
Updates the local clone of the spec-repo `NAME`. If `NAME` is omitted
this will update all spec-repos in `~/.cocoapods/repos`.
DESC
self.arguments = [
CLAide::Argument.new('NAME', false),
]
def initialize(argv)
@name = argv.shift_argument
super
end
def run
SourcesManager.update(@name, true)
end
end
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Repo::Add do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'adds a spec-repo' do
run_command('repo', 'add', 'private', test_repo_path)
Dir.chdir(config.repos_dir + 'private') do
`git config --get remote.origin.url`.chomp.should == test_repo_path.to_s
end
end
it 'adds a spec-repo with a specified branch' do
repo1 = repo_make('repo1')
Dir.chdir(repo1) do
`git checkout -b my-branch >/dev/null 2>&1`
`git checkout master >/dev/null 2>&1`
end
repo2 = command('repo', 'add', 'repo2', repo1.to_s, 'my-branch')
repo2.run
Dir.chdir(repo2.dir) { `git symbolic-ref HEAD` }.should.include? 'my-branch'
end
it 'adds a spec-repo by creating a shallow clone' do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
# Need to use file:// to test local use of --depth=1
run_command('repo', 'add', 'private', '--shallow', "file://#{test_repo_path}")
Dir.chdir(config.repos_dir + 'private') do
`git log --pretty=oneline`.strip.split("\n").size.should == 1
end
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Repo::Lint do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
require 'rest'
::REST.stubs(:head => stub(:success? => true))
end
it 'lints a repository' do
repo = fixture('spec-repos/test_repo').to_s
lambda { run_command('repo', 'lint', repo) }.should.not.raise
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Repo::List do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'lists a repository' do
lambda { run_command('repo', 'list') }.should.not.raise
end
it 'lists a repository (checking the output)' do
config.repos_dir = fixture('spec-repos')
output = run_command('repo', 'list')
output.should.include? '- Type:'
end
it 'only prints a count when invoked with --count-only' do
config.repos_dir = fixture('spec-repos')
output = run_command('repo', 'list', '--count-only')
output.should.include? 'repo'
output.should.not.include? '- Type:'
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Repo::Remove do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'complains when a repository name is missing' do
lambda { run_command('repo', 'remove') }.should.raise CLAide::Help
end
it "complains if the repository doesn't exist" do
lambda { run_command('repo', 'remove', 'nonexistant') }.should.raise CLAide::Help
end
it 'complains if we do not have permission' do
File.stubs(:writable?).returns(false)
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
lambda { run_command('repo', 'remove', upstream) }.should.raise CLAide::Help
FileUtils.rm_rf(upstream)
end
it 'removes a spec-repo' do
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
lambda { run_command('repo', 'remove', upstream) }.should.not.raise
File.directory?(test_repo_path + upstream).should.be.false?
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe Command::Repo::Update do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'updates a repository' do
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
Dir.chdir(test_repo_path) do
`git remote add origin #{upstream}`
`git remote -v`
`git fetch -q`
`git branch --set-upstream-to=origin/master master`
end
lambda { command('repo', 'update').run }.should.not.raise
end
it 'updates a spec-repo' do
repo1 = repo_make('repo1')
repo2 = repo_clone('repo1', 'repo2')
repo_make_readme_change(repo1, 'Updated')
Dir.chdir(repo1) { `git commit -a -m "Update"` }
run_command('repo', 'update', 'repo2')
(repo2 + 'README').read.should.include 'Updated'
end
end
end
......@@ -2,153 +2,8 @@ require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Command::Repo do
describe Command::Repo::Update do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'updates a repository' do
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
Dir.chdir(test_repo_path) do
`git remote add origin #{upstream}`
`git remote -v`
`git fetch -q`
`git branch --set-upstream-to=origin/master master`
end
lambda { command('repo', 'update').run }.should.not.raise
end
it 'updates a spec-repo' do
repo1 = repo_make('repo1')
repo2 = repo_clone('repo1', 'repo2')
repo_make_readme_change(repo1, 'Updated')
Dir.chdir(repo1) { `git commit -a -m "Update"` }
run_command('repo', 'update', 'repo2')
(repo2 + 'README').read.should.include 'Updated'
end
end
describe Command::Repo::Lint do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
require 'rest'
::REST.stubs(:head => stub(:success? => true))
end
it 'lints a repository' do
repo = fixture('spec-repos/test_repo').to_s
lambda { run_command('repo', 'lint', repo) }.should.not.raise
end
end
describe Command::Repo::Add do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'adds a spec-repo' do
run_command('repo', 'add', 'private', test_repo_path)
Dir.chdir(config.repos_dir + 'private') do
`git config --get remote.origin.url`.chomp.should == test_repo_path.to_s
end
end
it 'adds a spec-repo with a specified branch' do
repo1 = repo_make('repo1')
Dir.chdir(repo1) do
`git checkout -b my-branch >/dev/null 2>&1`
`git checkout master >/dev/null 2>&1`
end
repo2 = command('repo', 'add', 'repo2', repo1.to_s, 'my-branch')
repo2.run
Dir.chdir(repo2.dir) { `git symbolic-ref HEAD` }.should.include? 'my-branch'
end
it 'adds a spec-repo by creating a shallow clone' do
Dir.chdir(test_repo_path) do
`echo 'touch' > touch && git add touch && git commit -m 'updated'`
end
# Need to use file:// to test local use of --depth=1
run_command('repo', 'add', 'private', '--shallow', "file://#{test_repo_path}")
Dir.chdir(config.repos_dir + 'private') do
`git log --pretty=oneline`.strip.split("\n").size.should == 1
end
end
end
describe Command::Repo::Remove do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'complains when a repository name is missing' do
lambda { run_command('repo', 'remove') }.should.raise CLAide::Help
end
it "complains if the repository doesn't exist" do
lambda { run_command('repo', 'remove', 'nonexistant') }.should.raise CLAide::Help
end
it 'complains if we do not have permission' do
File.stubs(:writable?).returns(false)
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
lambda { run_command('repo', 'remove', upstream) }.should.raise CLAide::Help
FileUtils.rm_rf(upstream)
end
it 'removes a spec-repo' do
upstream = SpecHelper.temporary_directory + 'upstream'
FileUtils.cp_r(test_repo_path, upstream)
lambda { run_command('repo', 'remove', upstream) }.should.not.raise
File.directory?(test_repo_path + upstream).should.be.false?
end
end
describe Command::Repo::List do
extend SpecHelper::Command
extend SpecHelper::TemporaryRepos
before do
set_up_test_repo
config.repos_dir = SpecHelper.tmp_repos_path
end
it 'lists a repository' do
lambda { run_command('repo', 'list') }.should.not.raise
end
it 'lists a repository (checking the output)' do
config.repos_dir = fixture('spec-repos')
output = run_command('repo', 'list')
output.should.include? '- Type:'
end
it 'only prints a count when invoked with --count-only' do
config.repos_dir = fixture('spec-repos')
output = run_command('repo', 'list', '--count-only')
output.should.include? 'repo'
output.should.not.include? '- Type:'
end
it 'defaults to the list subcommand' do
Command::Repo.default_subcommand.should == 'list'
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment