Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using the pod repo itself as a spec repo #677

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/cocoapods-core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Informative < PlainInformative; end
autoload :Podfile, 'cocoapods-core/podfile'
autoload :Source, 'cocoapods-core/source'
autoload :CDNSource, 'cocoapods-core/cdn_source'
autoload :SingleSource, 'cocoapods-core/single_source'
autoload :TrunkSource, 'cocoapods-core/trunk_source'
autoload :Specification, 'cocoapods-core/specification'
autoload :StandardError, 'cocoapods-core/standard_error'
Expand Down
29 changes: 29 additions & 0 deletions lib/cocoapods-core/podfile/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,35 @@ def pod(name = nil, *requirements)
current_target_definition.store_pod(name, *requirements)
end

def git_package(url, *requirements)
unless url
raise StandardError, 'A git package requires an URL.'
end

options = requirements.last
unless options.is_a?(Hash)
options = {}
requirements << options
end
options[:source] = url

name = options.delete(:name) || url.gsub(/.git$/, '').gsub(%r{^/}, '').split('/').last

unless name
raise StandardError, "Could not infer pod name from '#{url}' and no `:name` was specified."
end

current_target_definition.store_pod(name, *requirements)
end

def github_package(url_fragment, *requirements)
unless url_fragment
raise StandardError, 'A GitHub package requires an URL fragment, e.g. `username/reponame`.'
end

git_package("https://github.com/#{url_fragment}", *requirements)
end

# Use just the dependencies of a Pod defined in the given podspec file.
# If no arguments are passed the first podspec in the root of the Podfile
# is used. It is intended to be used by the project of a library. Note:
Expand Down
196 changes: 196 additions & 0 deletions lib/cocoapods-core/single_source.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
require 'cocoapods-core/source/acceptor'
require 'cocoapods-core/source/aggregate'
require 'cocoapods-core/source/health_reporter'
require 'cocoapods-core/source/manager'
require 'cocoapods-core/source/metadata'

module Pod
# The Source class is responsible to manage a collection of podspecs.
#
# The backing store of the podspecs collection is an implementation detail
# abstracted from the rest of CocoaPods.
#
# The default implementation uses a git repo as a backing store, where the
# podspecs are namespaced as:
#
# "#{SPEC_NAME}/#{VERSION}/#{SPEC_NAME}.podspec"
#
class SingleSource < Source
# @param [Pathname, String] repo @see #repo.
#
def initialize(repo)
super(repo)
spec_paths
end

private

def raw_versions
@version_tags ||= repo_git(%w(tag)).split(/\s+/).map do |v|
version = Version.new(v)
rescue ArgumentError
end.compact
end

def process_podspec(path, output_path)
spec = Specification.from_file(path)
File.open(output_path, 'w') { |f| f.write(spec.to_pretty_json) }
output_path
end

def preload_podspecs_at_version(version)
version_dir = repo.join('.git', '.specs', version.to_s)
if version_dir.exist?
Pathname.glob(version_dir.join('*'))
else
repo_git(['checkout', version.to_s])
version_dir.mkpath
Pathname.glob(repo.join('*.podspec')).map do |podspec_path|
name = podspec_path.basename('.podspec')
process_podspec(podspec_path, version_dir.join("#{name}.podspec.json"))
end.compact
end
end

def spec_paths
raw_versions.map do |version|
preload_podspecs_at_version(version)
end.flatten
end

public

# @!group Querying the source
#-------------------------------------------------------------------------#

# @return [Array<String>] the list of the name of all the Pods.
#
#
def pods
spec_paths.map do |spec_path|
spec_path.basename('.podspec.json').to_s
end.flatten.uniq.sort
end

# @return [Array<Version>] all the available versions for the Pod, sorted
# from highest to lowest.
#
# @param [String] name
# the name of the Pod.
#
def versions(name)
return nil unless pods.include?(name)
@versions_by_name[name] ||= raw_versions.map do |version|
if specification_path(name, version)
version
else
nil
end
end.compact.sort.reverse
end

# Returns the path of the specification with the given name and version.
#
# @param [String] name
# the name of the Pod.
#
# @param [Version,String] version
# the version for the specification.
#
# @return [Pathname] The path of the specification.
#
def specification_path(name, version)
raise ArgumentError, 'No name' unless name
raise ArgumentError, 'No version' unless version

preload_podspecs_at_version(version)

path = repo.join('.git', '.specs', version.to_s, "#{name}.podspec.json")

return nil unless path.exist?

path
end

# @return [Array<Specification>] all the specifications contained by the
# source.
#
def all_specs
specs = spec_paths.map do |path|
begin
Specification.from_file(path)
rescue
CoreUI.warn "Skipping `#{path.relative_path_from(repo)}` because the " \
'podspec contains errors.'
next
end
end
specs.compact
end


# @!group Searching the source
#-------------------------------------------------------------------------#

# @return [Set] a set for a given dependency. The set is identified by the
# name of the dependency and takes into account subspecs.
#
# @note This method is optimized for fast lookups by name, i.e. it does
# *not* require iterating through {#pod_sets}
#
# @todo Rename to #load_set
#
def search(query)
if query.is_a?(Dependency)
query = query.root_name
end

if (versions = versions(query)) && !versions.empty?
set = set(query)
return set if set.specification_name == query
end
end

# @return [Array<Set>] The list of the sets that contain the search term.
#
# @param [String] query
# the search term. Can be a regular expression.
#
# @param [Bool] full_text_search
# whether the search should be limited to the name of the Pod or
# should include also the author, the summary, and the description.
#
# @note full text search requires to load the specification for each pod,
# hence is considerably slower.
#
# @todo Rename to #search
#
def search_by_name(query, full_text_search = false)
regexp_query = /#{query}/i

names = pods.grep(regexp_query)
names.map { |pod_name| set(pod_name) }
end

# @!group Updating the source
#-------------------------------------------------------------------------#

# Updates the local clone of the source repo.
#
# @param [Bool] show_output
#
# @return [Array<String>] changed_spec_paths
# Returns the list of changed spec paths.
#
def update(show_output)
result = super(show_output)
repo.join('.git', '.specs').rmtree if repo.join('.git', '.specs').exist?
all_specs
result
end

def verify_compatibility!
end

end
end
3 changes: 3 additions & 0 deletions lib/cocoapods-core/source/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,10 @@ def source_from_path(path)
TrunkSource.new(key)
when (key + '.url').exist?
CDNSource.new(key)
when key.join('.git', '.specs').exist? || Dir[key.join('*.podspec')].count > 0
SingleSource.new(key)
else
require 'pry'; binding.pry
Source.new(key)
end
end
Expand Down