Commit f8065208 authored by Fabio Pelosin's avatar Fabio Pelosin

[SourcesManager] Add support for the search index

parent 2714e56d
## 0.17.0.rc4 ## 0.17
### 0.17.0.rc6
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc5...0.17.0.rc6)
[cocoapods-core](https://github.com/CocoaPods/Core/compare/0.17.0.rc5...0.17.0.rc6)
###### Bug fixes
###### Ancillary enhancements
- CocoaPods now maintains a search index which is updated incrementally instead
of analyzing all the specs every time. The search index can be updated
manually with the `pod ipc update-search-index` command.
- Enhancements to the `pod repo lint` command.
- CocoaPods will not create anymore the pre commit hook in the master repo
during setup. If already created it is possible remove it deleting the
`~/.cocoapods/master/.git/hooks/pre-commit` path.
- Improved support for linting and validating specs repo.
### 0.17.0.rc5
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc4...0.17.0.rc5)
[cocoapods-core](https://github.com/CocoaPods/Core/compare/0.17.0.rc4...0.17.0.rc5)
###### Bug fixes
- The `--no-clean` argument is not ignored anymore by the installer.
- Proper handling of file patterns ending with a slash.
- More user errors are raised as an informative.
### 0.17.0.rc4
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc3...0.17.0.rc4) [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc3...0.17.0.rc4)
###### Bug fixes ###### Bug fixes
...@@ -23,7 +52,7 @@ ...@@ -23,7 +52,7 @@
- The `podspec` option of the `pod` directive of the Podfile DSL now accepts - The `podspec` option of the `pod` directive of the Podfile DSL now accepts
folders. folders.
## 0.17.0.rc3 ### 0.17.0.rc3
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc2...0.17.0.rc3 [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc2...0.17.0.rc3
[Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.5.0...0.5.1)) [Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.5.0...0.5.1))
...@@ -46,7 +75,7 @@ ...@@ -46,7 +75,7 @@
- General improvements to `pod ipc`. - General improvements to `pod ipc`.
- Added `pod ipc repl` subcommand. - Added `pod ipc repl` subcommand.
## 0.17.0.rc2 ### 0.17.0.rc2
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc1...0.17.0.rc2) [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.17.0.rc1...0.17.0.rc2)
[cocoapods-core](https://github.com/CocoaPods/Core/compare/0.17.0.rc1...0.17.0.rc2) [cocoapods-core](https://github.com/CocoaPods/Core/compare/0.17.0.rc1...0.17.0.rc2)
...@@ -61,7 +90,7 @@ ...@@ -61,7 +90,7 @@
attribute. attribute.
[#823](https://github.com/CocoaPods/CocoaPods/issues/823) [#823](https://github.com/CocoaPods/CocoaPods/issues/823)
## 0.17.0.rc1 ### 0.17.0.rc1
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.16.4...0.17.0.rc1) [CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.16.4...0.17.0.rc1)
[Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.4.3...0.5.0) [Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.4.3...0.5.0)
[cocoapods-core](https://github.com/CocoaPods/Core) [cocoapods-core](https://github.com/CocoaPods/Core)
......
...@@ -100,6 +100,30 @@ module Pod ...@@ -100,6 +100,30 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
class UpdateSearchIndex < IPC
self.summary = 'Updates the search index.'
self.description = <<-DESC
Updates the search index and prints its path to standard output.
The search index is a YAML encoded dictionary where the keys
are the names of the Pods and the values are a dictionary containing
the following information:
- version
- summary
- description
- authors
DESC
def run
SourcesManager.updated_search_index
output_pipe.puts(SourcesManager.search_index_path)
end
end
#-----------------------------------------------------------------------#
class Repl < IPC class Repl < IPC
END_OF_OUTPUT_SIGNAL = "\n\r" END_OF_OUTPUT_SIGNAL = "\n\r"
......
...@@ -63,17 +63,58 @@ module Pod ...@@ -63,17 +63,58 @@ module Pod
# @return [Array<Set>] The sets that contain the search term. # @return [Array<Set>] The sets that contain the search term.
# #
def search_by_name(query, full_text_search = false) def search_by_name(query, full_text_search = false)
result = aggregate.search_by_name(query, full_text_search) set_names = []
if result.empty? updated_search_index.each do |name, set_data|
text = name.dup
if full_text_search
text << set_data['authors'].to_s if set_data['authors']
text << set_data['summary'] if set_data['summary']
text << set_data['description'] if set_data['description']
end
set_names << name if text.downcase.include?(query.downcase)
end
sets = set_names.map { |name| aggregate.represenative_set(name) }
if sets.empty?
extra = ", author, summary, or description" if full_text_search extra = ", author, summary, or description" if full_text_search
raise Informative "Unable to find a pod with name#{extra} matching `#{query}`" raise Informative, "Unable to find a pod with name#{extra} matching `#{query}`"
end end
result sets
end end
#-----------------------------------------------------------------------# # Creates or updates the search data and returns it. The search data
# groups by name the following information for each set:
#
# - version
# - summary
# - description
# - authors
#
# @return [Hash{String => String}] The up to date search data.
#
def updated_search_index
if search_index_path.exist?
stored_index = YAML.load(search_index_path.read)
search_index = aggregate.update_search_index(stored_index)
else
search_index = aggregate.generate_search_index
end
File.open(search_index_path, 'w') {|f| f.write(search_index.to_yaml) }
search_index
end
# @return [Pathname] The path where the search index should be stored.
#
def search_index_path
caches_path = Pathname.new(File.expand_path(CACHE_ROOT))
caches_path + 'search_index.yaml'
end
public
# @!group Updating Sources # @!group Updating Sources
#-----------------------------------------------------------------------#
extend Executable extend Executable
executable :git executable :git
...@@ -87,10 +128,10 @@ module Pod ...@@ -87,10 +128,10 @@ module Pod
# #
def update(source_name = nil, show_output = false) def update(source_name = nil, show_output = false)
if source_name if source_name
source = aggregate.all.find { |s| s.name == source_name } specified_source = aggregate.all.find { |s| s.name == source_name }
raise Informative, "Unable to find the `#{source_name}` repo." unless source raise Informative, "Unable to find the `#{source_name}` repo." unless specified_source
raise Informative, "The `#{source_name}` repo is not a git repo." unless git_repo?(source.repo) raise Informative, "The `#{source_name}` repo is not a git repo." unless git_repo?(specified_source.repo)
sources = [source] sources = [specified_source]
else else
sources = aggregate.all.select { |source| git_repo?(source.repo) } sources = aggregate.all.select { |source| git_repo?(source.repo) }
end end
...@@ -195,9 +236,10 @@ module Pod ...@@ -195,9 +236,10 @@ module Pod
yaml_file.exist? ? YAML.load_file(yaml_file) : {} yaml_file.exist? ? YAML.load_file(yaml_file) : {}
end end
#-----------------------------------------------------------------------# public
# @!group Master repo # @!group Master repo
#-----------------------------------------------------------------------#
# @return [Pathname] The path of the master repo. # @return [Pathname] The path of the master repo.
# #
...@@ -213,6 +255,10 @@ module Pod ...@@ -213,6 +255,10 @@ module Pod
def master_repo_functional? def master_repo_functional?
master_repo_dir.exist? && repo_compatible?(master_repo_dir) master_repo_dir.exist? && repo_compatible?(master_repo_dir)
end end
#-----------------------------------------------------------------------#
end end
end end
end end
...@@ -7,6 +7,7 @@ module Pod ...@@ -7,6 +7,7 @@ module Pod
Command::IPC::Spec.any_instance.stubs(:output_pipe).returns(UI) Command::IPC::Spec.any_instance.stubs(:output_pipe).returns(UI)
Command::IPC::Podfile.any_instance.stubs(:output_pipe).returns(UI) Command::IPC::Podfile.any_instance.stubs(:output_pipe).returns(UI)
Command::IPC::List.any_instance.stubs(:output_pipe).returns(UI) Command::IPC::List.any_instance.stubs(:output_pipe).returns(UI)
Command::IPC::UpdateSearchIndex.any_instance.stubs(:output_pipe).returns(UI)
Command::IPC::Repl.any_instance.stubs(:output_pipe).returns(UI) Command::IPC::Repl.any_instance.stubs(:output_pipe).returns(UI)
end end
...@@ -56,6 +57,18 @@ module Pod ...@@ -56,6 +57,18 @@ module Pod
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
describe Command::IPC::UpdateSearchIndex do
it "updates the search index and prints its path to STDOUT" do
SourcesManager.expects(:updated_search_index)
out = run_command('ipc', 'update-search-index')
out.should.include(SourcesManager.search_index_path.to_s)
end
end
#-------------------------------------------------------------------------#
describe Command::IPC::Repl do describe Command::IPC::Repl do
it "prints the version of CocoaPods as its first message" do it "prints the version of CocoaPods as its first message" do
......
...@@ -3,31 +3,74 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -3,31 +3,74 @@ require File.expand_path('../../spec_helper', __FILE__)
module Pod module Pod
describe SourcesManager do describe SourcesManager do
before do
@test_source = Source.new(fixture('spec-repos/test_repo'))
SourcesManager.stubs(:search_index_path).returns(temporary_directory + 'search_index.yaml')
end
#-------------------------------------------------------------------------#
describe "In general" do describe "In general" do
before do
Source::Aggregate.any_instance.stubs(:all).returns([@test_source])
end
#--------------------------------------#
it "returns all the sources" do it "returns all the sources" do
Source::Aggregate.any_instance.unstub(:all)
SourcesManager.all.map(&:name).should == %w[master test_repo] SourcesManager.all.map(&:name).should == %w[master test_repo]
end end
it "returns all the sets" do it "returns all the sets" do
SourcesManager.all_sets.map(&:name).should.include?('Chameleon') SourcesManager.all_sets.map(&:name).should.include?('BananaLib')
end end
it "searches for the set of a dependency" do it "searches for the set of a dependency" do
set = SourcesManager.search(Dependency.new('Chameleon')) set = SourcesManager.search(Dependency.new('BananaLib'))
set.class.should == Specification::Set set.class.should == Specification::Set
set.name.should == 'Chameleon' set.name.should == 'BananaLib'
end
it "raises if it not able to find a pod for the given dependency" do
should.raise Informative do
set = SourcesManager.search(Dependency.new('Windows-Lib'))
end.message.should.match /Unable to find.*Windows-Lib/
end end
it "searches sets by name" do it "searches sets by name" do
sets = SourcesManager.search_by_name('Chameleon') sets = SourcesManager.search_by_name('BananaLib')
sets.all?{ |s| s.class == Specification::Set}.should.be.true sets.all?{ |s| s.class == Specification::Set}.should.be.true
sets.any?{ |s| s.name == 'Chameleon'}.should.be.true sets.any?{ |s| s.name == 'BananaLib'}.should.be.true
end end
it "can perform a full text search of the sets" do it "can perform a full text search of the sets" do
sets = SourcesManager.search_by_name('Drop in sharing', true) Source::Aggregate.any_instance.stubs(:all).returns([@test_source])
sets = SourcesManager.search_by_name('Chunky', true)
sets.all?{ |s| s.class == Specification::Set}.should.be.true sets.all?{ |s| s.class == Specification::Set}.should.be.true
sets.any?{ |s| s.name == 'ShareKit'}.should.be.true sets.any?{ |s| s.name == 'BananaLib'}.should.be.true
end
it "generates the search index before performing a search if it doesn't exits" do
Source::Aggregate.any_instance.stubs(:all).returns([@test_source])
Source::Aggregate.any_instance.expects(:generate_search_index).returns({'BananaLib' => {}})
Source::Aggregate.any_instance.expects(:update_search_index).never
sets = SourcesManager.search_by_name('BananaLib')
end
it "updates the search index before performing a search if it exits" do
FileUtils.touch(SourcesManager.search_index_path)
Source::Aggregate.any_instance.stubs(:all).returns([@test_source])
Source::Aggregate.any_instance.expects(:generate_search_index).never
Source::Aggregate.any_instance.expects(:update_search_index).returns({'BananaLib' => {}})
sets = SourcesManager.search_by_name('BananaLib')
end
it "returns the path of the search index" do
SourcesManager.unstub(:search_index_path)
path = SourcesManager.search_index_path.to_s
path.should.match %r[Library/Caches/CocoaPods/search_index.yaml]
end 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