Commit 9ba06f2c authored by Fabio Pelosin's avatar Fabio Pelosin

Merge branch 'DirList' into 0.17

* DirList:
  [DirList] Support for excluded patterns
  [LocalPod] Added DirList class.
  [Git] UI improvements.
  [Installer] Show project genration step.

Conflicts:
	lib/cocoapods/local_pod.rb
parents cc958fde 9b118f86
......@@ -21,6 +21,7 @@ module Pod
# returns absolute paths.
#
class LocalPod
autoload :DirList, 'cocoapods/local_pod/dir_list'
# @return [Specification] The specification that describes the pod.
#
......@@ -94,6 +95,10 @@ module Pod
@sandbox.root + top_specification.name
end
def dir_list
@dir_list ||= DirList.new(root)
end
# @return [String] A string representation of the pod which indicates if
# the pods comes from a local source or has a preferred
# dependency.
......@@ -156,6 +161,7 @@ module Pod
def clean!
clean_paths.each { |path| FileUtils.rm_rf(path) }
@cleaned = true
dir_list.read_file_system
end
# Finds the absolute paths, including hidden ones, of the files
......@@ -242,7 +248,7 @@ module Pod
#
def source_files_by_spec
options = {:glob => '*.{h,hpp,hh,m,mm,c,cpp}'}
paths_by_spec(:source_files, options)
@source_files_by_spec ||= paths_by_spec(:source_files, '*.{h,hpp,hh,m,mm,c,cpp}')
end
# @return [Array<Pathname>] The paths of the header files.
......@@ -277,7 +283,7 @@ module Pod
# header files (i.e. the build ones) are intended to be public.
#
def public_header_files_by_spec
public_headers = paths_by_spec(:public_header_files, :glob => '*.{h,hpp,hh}')
public_headers = paths_by_spec(:public_header_files, '*.{h,hpp,hh}')
build_headers = header_files_by_spec
result = {}
......@@ -331,11 +337,14 @@ module Pod
# specification or automatically detected.
#
def license_file
if top_specification.license && top_specification.license[:file]
root + top_specification.license[:file]
else
expanded_paths(%w[ licen{c,s}e{*,.*} ]).first
unless @license_file
if top_specification.license && top_specification.license[:file]
@license_file = root + top_specification.license[:file]
else
@license_file = expanded_paths(%w[ licen{c,s}e{*,.*} ]).first
end
end
@license_file
end
# @return [String] The text of the license of the pod from the
......@@ -372,8 +381,8 @@ module Pod
end
specs = [top_specification] + top_specification.recursive_subspecs
source_files = paths_by_spec(:source_files, { :glob => '*.{h}'}, specs)
public_headers = paths_by_spec(:public_header_files,{ :glob => '*.{h}'}, specs)
source_files = paths_by_spec(:source_files, '*.{h}', specs)
public_headers = paths_by_spec(:public_header_files, '*.{h}', specs)
result = []
specs.each do |spec|
......@@ -474,7 +483,7 @@ module Pod
end
# @return Hash{Pathname => [Array<Pathname>]} A hash containing the headers
# folders as the keys and the the absolute paths of the header files
# folders as the keys and the absolute paths of the header files
# as the values.
#
# @todo this is being overridden in the RestKit 0.9.4 spec, need to do
......@@ -507,27 +516,27 @@ module Pod
# included in the linker search paths.
#
def headers_excluded_from_search_paths
options = { :glob => '*.{h,hpp,hh}' }
paths = paths_by_spec(:exclude_header_search_paths, options)
paths = paths_by_spec(:exclude_header_search_paths, '*.{h,hpp,hh}')
paths.values.compact.uniq
end
# @!group Paths Patterns
# The paths obtained by resolving the patterns of an attribute
# groupped by spec.
# grouped by spec.
#
# @param [Symbol] accessor The accessor to use to obtain the paths patterns.
#
# @param [Hash] options (see #expanded_paths)
#
def paths_by_spec(accessor, options = {}, specs = nil)
def paths_by_spec(accessor, dir_pattern = nil, specs = nil)
specs ||= specifications
paths_by_spec = {}
processed_paths = []
specs = specs.sort_by { |s| s.name.length }
specs.each do |spec|
paths = expanded_paths(spec.send(accessor), options)
paths = expanded_paths(spec.send(accessor), dir_pattern, spec.excluded_patterns)
unless paths.empty?
paths_by_spec[spec] = paths - processed_paths
processed_paths += paths
......@@ -552,34 +561,29 @@ module Pod
#
# @return [Array<Pathname>] A list of the paths.
#
def expanded_paths(patterns, options = {})
def expanded_paths(patterns, dir_pattern = nil, exclude_patterns = nil)
unless exists?
raise Informative, "[Local Pod] Attempt to resolve paths for nonexistent pod.\n" \
"\tSpecifications: #{@specifications.inspect}\n" \
"\t Patterns: #{patterns.inspect}\n" \
"\t Options: #{options.inspect}"
"\t Patterns: #{patterns.inspect}"
end
# Noticeable impact on performance
return [] if patterns.empty?
patterns = [ patterns ] if patterns.is_a?(String)
file_lists = patterns.select { |p| p.is_a?(FileList) }
glob_patterns = patterns - file_lists
result = []
result << dir_list.glob(glob_patterns, dir_pattern, exclude_patterns)
result << file_lists.map do |file_list|
file_list.prepend_patterns(root)
file_list.glob
end
result << glob_patterns.map do |pattern|
pattern = root + pattern
if pattern.directory? && options[:glob]
pattern += options[:glob]
end
Pathname.glob(pattern, File::FNM_CASEFOLD)
end.flatten
result.flatten.compact.uniq
end
......@@ -616,5 +620,5 @@ module Pod
true
end
end
end
end
end # LocalPod
end # Pod
module Pod
class LocalPod
# The {DirList} class is designed to perform multiple glob matches against
# a given directory. Basically, it generates a list of all the children
# paths and matches the globs patterns against them, resulting in just
# one access to the file system.
#
# @note A {DirList} once it has generated the list of the paths this is
# updated only if explicitly requested by calling
# {DirList#read_file_system}
#
class DirList
# @return [Pathname] The root of the list whose files and directories
# are used to perform the matching operations.
#
attr_accessor :root
# @param [Pathname] root The root of the DirList.
#
def initialize(root)
@root = root
end
# @return [Array<String>] The list of absolute the path of all the files
# contained in {root}.
#
def files
read_file_system unless @files
@files
end
# @return [Array<String>] The list of absolute the path of all the
# directories contained in {root}.
#
def dirs
read_file_system unless @dirs
@dirs
end
# @return [void] Reads the file system and populates the files and paths
# lists.
#
def read_file_system
root_length = root.to_s.length+1
paths = Dir.glob(root + "**/*", File::FNM_DOTMATCH)
paths = paths.map { |p| p[root_length..-1] }
paths = paths.reject do |p|
p == '.' || p == '..'
end
dirs_entries = paths.select { |path| path.end_with?('/.', '/..') }
@files = paths - dirs_entries
@dirs = dirs_entries.map { |d| d.gsub(/\/\.\.?$/,'') }.uniq
end
# @return [Array<Pathname>] Similar to {glob} but returns the absolute
# paths.
#
def glob(patterns, dir_pattern = nil, exclude_patterns = nil)
relative_glob(patterns, dir_pattern, exclude_patterns).map {|p| root + p }
end
# @return [Array<Pathname>] The list of the relative paths that are
# case insensitively matched by a given pattern. This method emulates
# {Dir#glob} with the {File::FNM_CASEFOLD} option.
#
# @param [Array<String>] patterns A {Dir#glob} like pattern.
#
# @param [String] dir_pattern An optional pattern to append to
# pattern, if this one is the path of a
# directory.
#
def relative_glob(patterns, dir_pattern = nil, exclude_patterns = nil)
return [] if patterns.empty?
patterns = [ patterns ] if patterns.is_a? String
list = patterns.map do |pattern|
if pattern.is_a?(String)
pattern += '/' + dir_pattern if directory?(pattern) && dir_pattern
expanded_patterns = dir_glob_equivalent_patterns(pattern)
files.select do |path|
expanded_patterns.any? do |p|
File.fnmatch(p, path, File::FNM_CASEFOLD | File::FNM_PATHNAME)
end
end
else
pattern.to_s.cyan
files.select { |path| path.match(pattern) }
end
end.flatten
if exclude_patterns
excluded = relative_glob(exclude_patterns)
list = exclude_patterns ? list - excluded : list
end
list.map { |path| Pathname.new(path) }
end
# @return [Bool] Wether a path is a directory. The result of this method
# computed without accessing the file system and is case insensitive.
#
# @param [String, Pathname] sub_path The path that could be a directory.
#
def directory?(sub_path)
sub_path = sub_path.to_s.downcase.gsub(/\/$/, '')
dirs.any? { |dir| dir.downcase == sub_path }
end
# @return [Array<String>] An array containing the list of patterns for
# necessary to emulate {Dir#glob} with #{File.fnmatch}. If
# #{File.fnmatch} invoked with the File::FNM_PATHNAME matches any of
# the returned patterns {Dir#glob} would have matched the original
# pattern.
#
# The expansion provides support for:
#
# - Literals
#
# expand_pattern_literals('{file1,file2}.{h,m}')
# => ["file1.h", "file1.m", "file2.h", "file2.m"]
#
# expand_pattern_literals('file*.*')
# => ["file*.*"]
#
# - Matching the direct children of a directory with `**`
#
# expand_pattern_literals('Classes/**/file.m')
# => ["Classes/**/file.m", "Classes/file.m"]
#
# @param [String] pattern A {Dir#glob} like pattern.
#
def dir_glob_equivalent_patterns(pattern)
pattern.gsub!('/**/', '{/**/,/}')
values_by_set = {}
pattern.scan(/\{[^}]*\}/) do |set|
values = set.gsub(/[{}]/, '').split(',')
values_by_set[set] = values
end
if values_by_set.empty?
[ pattern ]
else
patterns = [ pattern ]
values_by_set.each do |set, values|
patterns = patterns.map do |pattern|
values.map do |value|
pattern.gsub(set, value)
end
end.flatten
end
patterns
end
end
end # DirList
end # LocalPod
end # Pod
......@@ -40,6 +40,7 @@ module Pod
# multi-platform attributes
%w[ source_files
excluded_patterns
public_header_files
resources
preserve_paths
......@@ -136,6 +137,7 @@ module Pod
end
%w{ source_files=
excluded_patterns=
public_header_files=
resource=
resources=
......@@ -259,6 +261,7 @@ module Pod
top_attr_accessor :prefix_header_contents
pltf_chained_attr_accessor :source_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :excluded_patterns, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :public_header_files, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :resources, lambda {|value, current| pattern_list(value) }
pltf_chained_attr_accessor :preserve_paths, lambda {|value, current| pattern_list(value) } # Paths that should not be cleaned
......
require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::LocalPod::DirList do
before do
@dir_list = Pod::LocalPod::DirList.new(fixture('banana-lib'))
end
it "creates the list of all the files" do
files = @dir_list.files
files.reject! do |f|
f.include?('libPusher') || f.include?('.git') || f.include?('DS_Store')
end
files.sort.should == %w|
BananaLib.podspec
Classes Classes/Banana.h Classes/Banana.m Classes/BananaLib.pch
README
Resources Resources/logo-sidebar.png
sub-dir sub-dir/sub-dir-2 sub-dir/sub-dir-2/somefile.txt |
end
it "creates theh list of the directories" do
dirs = @dir_list.dirs
dirs.reject! do |f|
f.include?('libPusher') || f.include?('.git')
end
dirs.sort.should == %w| Classes Resources sub-dir sub-dir/sub-dir-2 |
end
it "detects a directory" do
@dir_list.directory?('classes').should == true
end
it "doesn't reports as a directory a file" do
@dir_list.directory?('Classes/Banana.m').should == false
end
it "can glob the root for a given pattern" do
paths = @dir_list.relative_glob('Classes/*.{h,m}').map(&:to_s)
paths.should == %w| Classes/Banana.h Classes/Banana.m |
end
it "supports the `**` glob pattern" do
paths = @dir_list.relative_glob('Classes/**/*.{h,m}').map(&:to_s)
paths.should == %w| Classes/Banana.h Classes/Banana.m |
end
it "supports an optional pattern for globbing directories" do
paths = @dir_list.relative_glob('Classes', '*.{h,m}').map(&:to_s)
paths.should == %w| Classes/Banana.h Classes/Banana.m |
end
it "can return the absolute paths from glob" do
paths = @dir_list.glob('Classes/*.{h,m}')
paths.all? { |p| p.absolute? }.should == true
end
it "can return the relative paths from glob" do
paths = @dir_list.relative_glob('Classes/*.{h,m}')
paths.any? { |p| p.absolute? }.should == false
end
it "expands a pattern into all the combinations of Dir#glob literals" do
patterns = @dir_list.dir_glob_equivalent_patterns('{file1,file2}.{h,m}')
patterns.sort.should == %w| file1.h file1.m file2.h file2.m |
end
it "returns the original patter if there are no Dir#glob expansions" do
patterns = @dir_list.dir_glob_equivalent_patterns('file*.*')
patterns.sort.should == %w| file*.* |
end
it "expands `**`" do
patterns = @dir_list.dir_glob_equivalent_patterns('Classes/**/file.m')
patterns.sort.should == %w| Classes/**/file.m Classes/file.m |
end
it "supports a combination of `**` and literals" do
patterns = @dir_list.dir_glob_equivalent_patterns('Classes/**/file.{h,m}')
patterns.sort.should == %w| Classes/**/file.h Classes/**/file.m Classes/file.h Classes/file.m |
end
end
require File.expand_path('../../spec_helper', __FILE__)
describe Pod::LocalPod do
# a LocalPod represents a local copy of the dependency, inside the pod root, built from a spec
describe "in general" do
before do
@sandbox = temporary_sandbox
......
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