Skip to content

Commit

Permalink
Merge pull request #49 from macblazer/46-crash-with-undefined-method-…
Browse files Browse the repository at this point in the history
…empty-for-nilnilclass

Fix crashes with two edge cases of Podfile and pods configuration
  • Loading branch information
macblazer authored Oct 12, 2022
2 parents 88a6212 + a6e8529 commit 79d31c7
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 15 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.1]

### Changed
- Better error messaging when a problem is encountered while gathering pod information ([Issue #48](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/48)) [@macblazer](https://github.com/macblazer).

### Fixed
- Including a pod that has a platform-specific dependency for an unused platform no longer causes a crash ([Issue #46](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/46)) [@macblazer](https://github.com/macblazer).
- Analyzing a Podfile that has no pods defined in it no longer causes a crash [@macblazer](https://github.com/macblazer).

## [1.1.0]

### Added
- Can now eliminate Podfile targets that include "test" in their name ([Issue #43](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/43)) [@macblazer](https://github.com/macblazer).

## [1.0.0]
Expand Down
6 changes: 3 additions & 3 deletions lib/cyclonedx/cocoapods/pod_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ def self.searchable_source(url:, source_manager:)

def attributes_for(pod:)
specification_sets = @source_manager.search_by_name("^#{Regexp.escape(pod.root_name)}$")
raise SearchError, "No pod found named #{pod.name}" if specification_sets.length == 0
raise SearchError, "More than one pod found named #{pod.name}" if specification_sets.length > 1
raise SearchError, "No pod found named #{pod.name}; run 'pod repo update' and try again" if specification_sets.length == 0
raise SearchError, "More than one pod found named #{pod.name}; a pod in a private spec repo should not have the same name as a public pod" if specification_sets.length > 1

paths = specification_sets[0].specification_paths_for_version(pod.version)
raise SearchError, "Version #{pod.version} not found for pod #{pod.name}" if paths.length == 0
raise SearchError, "Version #{pod.version} not found for pod #{pod.name}; run 'pod repo update' and try again" if paths.length == 0

::Pod::Specification.from_file(paths[0]).attributes_hash
end
Expand Down
8 changes: 5 additions & 3 deletions lib/cyclonedx/cocoapods/podfile_analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def simple_hash_of_lockfile_pods(lockfile)
pods_hash = { }

pods_used = lockfile.internal_data['PODS']
pods_used.each { |pod|
pods_used&.each { |pod|
if pod.is_a?(String)
# Pods stored as String have no dependencies
pod_name = pod.split.first
Expand All @@ -109,11 +109,13 @@ def append_all_pod_dependencies(pods_used, pods_cache)
original_number = 0
# Loop adding pod dependencies until we are not adding any more dependencies to the result
# This brings in all the transitive dependencies of every top level pod.
# Note this also handles the edge case of having a Podfile with no pods used.
# Note this also handles two edge cases:
# 1. Having a Podfile with no pods used.
# 2. Having a pod that has a platform-specific dependency that is unused for this Podfile.
while result.length != original_number
original_number = result.length
pods_used.each { |pod_name|
result.push(*pods_cache[pod_name]) unless pods_cache[pod_name].empty?
result.push(*pods_cache[pod_name]) unless !pods_cache.key?(pod_name) || pods_cache[pod_name].empty?
}
result = result.uniq
pods_used = result
Expand Down
2 changes: 1 addition & 1 deletion lib/cyclonedx/cocoapods/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

module CycloneDX
module CocoaPods
VERSION = '1.1.0'
VERSION = '1.1.1'
DEPENDENCIES = {
cocoapods: '~> 1.10.1',
nokogiri: '~> 1.11.2'
Expand Down
6 changes: 3 additions & 3 deletions spec/cyclonedx/cocoapods/pod_attributes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
it 'should raise an error' do
expect {
@source.attributes_for(pod: pod)
}.to raise_error(CycloneDX::CocoaPods::SearchError, "No pod found named #{pod.name}")
}.to raise_error(CycloneDX::CocoaPods::SearchError, "No pod found named #{pod.name}; run 'pod repo update' and try again")
end
end

Expand All @@ -76,7 +76,7 @@
it 'should raise an error' do
expect {
@source.attributes_for(pod: pod)
}.to raise_error(CycloneDX::CocoaPods::SearchError, "More than one pod found named #{pod.name}")
}.to raise_error(CycloneDX::CocoaPods::SearchError, "More than one pod found named #{pod.name}; a pod in a private spec repo should not have the same name as a public pod")
end
end

Expand All @@ -89,7 +89,7 @@
it 'should raise an error' do
expect {
@source.attributes_for(pod: pod)
}.to raise_error(CycloneDX::CocoaPods::SearchError, "Version #{pod.version} not found for pod #{pod.name}")
}.to raise_error(CycloneDX::CocoaPods::SearchError, "Version #{pod.version} not found for pod #{pod.name}; run 'pod repo update' and try again")
end
end

Expand Down
40 changes: 35 additions & 5 deletions spec/cyclonedx/cocoapods/podfile_analyzer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

RSpec.describe CycloneDX::CocoaPods::PodfileAnalyzer do
let(:fixtures) { Pathname.new(File.expand_path('../../../fixtures/', __FILE__)) }
let(:empty_podfile) { 'EmptyPodfile/Podfile' }
let(:simple_pod) { 'SimplePod/Podfile' }
let(:restricted_pod) { 'RestrictedPod/Podfile' }
let(:tests_pod) { 'TestingPod/Podfile' }

::Pod::Config.instance.installation_root = File.expand_path('../../../fixtures/', __FILE__) + '/'
Expand All @@ -34,20 +36,48 @@

context 'parsing pods' do
context 'when created with standard parameters' do
it 'should handle no pods correctly' do
analyzer = ::CycloneDX::CocoaPods::PodfileAnalyzer.new(logger: @logger)

pod_file = ::Pod::Podfile.from_file(fixtures + empty_podfile)
expect(pod_file).not_to be_nil
lock_file = ::Pod::Lockfile.from_file(fixtures + (empty_podfile + '.lock'))
expect(lock_file).not_to be_nil

included_pods = analyzer.parse_pods(pod_file, lock_file)

pod_names = included_pods.map(&:name)
expect(pod_names).to eq([])
end

it 'should find all simple pods' do
analyzer = ::CycloneDX::CocoaPods::PodfileAnalyzer.new(logger: @logger)

simple_pod_file = ::Pod::Podfile.from_file(fixtures + simple_pod)
expect(simple_pod_file).not_to be_nil
simple_lock_file = ::Pod::Lockfile.from_file(fixtures + (simple_pod + '.lock'))
expect(simple_lock_file).not_to be_nil
pod_file = ::Pod::Podfile.from_file(fixtures + simple_pod)
expect(pod_file).not_to be_nil
lock_file = ::Pod::Lockfile.from_file(fixtures + (simple_pod + '.lock'))
expect(lock_file).not_to be_nil

included_pods = analyzer.parse_pods(simple_pod_file, simple_lock_file)
included_pods = analyzer.parse_pods(pod_file, lock_file)

pod_names = included_pods.map(&:name)
expect(pod_names).to eq(['Alamofire', 'MSAL', 'MSAL/app-lib'])
end

it 'should find all pods actually used' do
analyzer = ::CycloneDX::CocoaPods::PodfileAnalyzer.new(logger: @logger)

pod_file = ::Pod::Podfile.from_file(fixtures + restricted_pod)
expect(pod_file).not_to be_nil
lock_file = ::Pod::Lockfile.from_file(fixtures + (restricted_pod + '.lock'))
expect(lock_file).not_to be_nil

included_pods = analyzer.parse_pods(pod_file, lock_file)

pod_names = included_pods.map(&:name)
expect(pod_names).to eq(['EFQRCode'])
end

it 'should find all pods' do
analyzer = ::CycloneDX::CocoaPods::PodfileAnalyzer.new(logger: @logger)

Expand Down
6 changes: 6 additions & 0 deletions spec/fixtures/EmptyPodfile/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
project 'SampleProject.xcodeproj'
platform :ios, '16.0'

target 'SampleProject' do
# No pods specified!
end
3 changes: 3 additions & 0 deletions spec/fixtures/EmptyPodfile/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PODFILE CHECKSUM: f88bba0bd98b5e52e9e9d8ae347b4c8274976c54

COCOAPODS: 1.11.3
7 changes: 7 additions & 0 deletions spec/fixtures/RestrictedPod/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project 'SampleProject.xcodeproj'
platform :ios, '13.0'

target 'SampleProject' do
# EFQRCode has a dependency only for watchOS so it's not actually included in this iOS project
pod 'EFQRCode'
end
17 changes: 17 additions & 0 deletions spec/fixtures/RestrictedPod/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
PODS:
- EFQRCode (6.2.1):
- swift_qrcodejs (~> 2.2.2)

DEPENDENCIES:
- EFQRCode

SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- EFQRCode

SPEC CHECKSUMS:
EFQRCode: a4d39ec3466b68dffa71de3b5caef7c9ceefdc53

PODFILE CHECKSUM: 3e93ab9c0580591da64eca6661a70cd9abb23c67

COCOAPODS: 1.10.2

0 comments on commit 79d31c7

Please sign in to comment.