cocoapods 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.md +184 -0
- data/bin/pod +9 -0
- data/lib/cocoapods.rb +32 -0
- data/lib/cocoapods/command.rb +88 -0
- data/lib/cocoapods/command/install.rb +48 -0
- data/lib/cocoapods/command/repo.rb +60 -0
- data/lib/cocoapods/command/setup.rb +32 -0
- data/lib/cocoapods/command/spec.rb +28 -0
- data/lib/cocoapods/config.rb +49 -0
- data/lib/cocoapods/dependency.rb +39 -0
- data/lib/cocoapods/downloader.rb +55 -0
- data/lib/cocoapods/executable.rb +13 -0
- data/lib/cocoapods/installer.rb +62 -0
- data/lib/cocoapods/resolver.rb +24 -0
- data/lib/cocoapods/source.rb +31 -0
- data/lib/cocoapods/specification.rb +203 -0
- data/lib/cocoapods/specification/set.rb +82 -0
- data/lib/cocoapods/version.rb +9 -0
- data/lib/cocoapods/xcode/config.rb +33 -0
- data/lib/cocoapods/xcode/project.rb +132 -0
- data/xcode-project-templates/cocoa-touch-static-library/Pods-Prefix.pch +7 -0
- data/xcode-project-templates/cocoa-touch-static-library/Pods.xcconfig +1 -0
- data/xcode-project-templates/cocoa-touch-static-library/Pods.xcodeproj/project.pbxproj +232 -0
- metadata +90 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module Pod
|
2
|
+
class Command
|
3
|
+
class Setup < Command
|
4
|
+
def self.banner
|
5
|
+
%{Setup CocoaPods environment:
|
6
|
+
|
7
|
+
$ pod setup
|
8
|
+
|
9
|
+
Creates a directory at `~/.cocoapods' which will hold your spec-repos.
|
10
|
+
This is where it will create a clone of the public `master' spec-repo from:
|
11
|
+
|
12
|
+
https://github.com/alloy/cocoapods-specs}
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(argv)
|
16
|
+
super unless argv.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def master_repo_url
|
20
|
+
'git://github.com/alloy/cocoapods-specs.git'
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_master_repo_command
|
24
|
+
@command ||= Repo.new(ARGV.new(['add', 'master', master_repo_url]))
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
add_master_repo_command.run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Pod
|
2
|
+
class Command
|
3
|
+
class Spec < Command
|
4
|
+
def self.banner
|
5
|
+
%{Managing PodSpec files:
|
6
|
+
|
7
|
+
$ pod help spec
|
8
|
+
|
9
|
+
pod spec create NAME
|
10
|
+
Creates a directory for your new pod, named `NAME', with a default
|
11
|
+
directory structure and accompanying `NAME.podspec'.
|
12
|
+
|
13
|
+
pod spec init NAME
|
14
|
+
Creates a PodSpec, in the current working dir, called `NAME.podspec'.
|
15
|
+
Use this for existing libraries.
|
16
|
+
|
17
|
+
pod spec lint NAME
|
18
|
+
Validates `NAME.podspec' from a local spec-repo. In case `NAME' is
|
19
|
+
omitted, it defaults to the PodSpec in the current working dir.
|
20
|
+
|
21
|
+
pod spec push REMOTE
|
22
|
+
Validates `NAME.podspec' in the current working dir, copies it to the
|
23
|
+
local clone of the `REMOTE' spec-repo, and pushes it to the `REMOTE'
|
24
|
+
spec-repo. In case `REMOTE' is omitted, it defaults to `master'.}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Config
|
5
|
+
def self.instance
|
6
|
+
@instance ||= new
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.instance=(instance)
|
10
|
+
@instance = instance
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :repos_dir, :project_pods_root, :clean, :verbose, :silent
|
14
|
+
alias_method :clean?, :clean
|
15
|
+
alias_method :verbose?, :verbose
|
16
|
+
alias_method :silent?, :silent
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@repos_dir = Pathname.new(File.expand_path("~/.cocoapods"))
|
20
|
+
@clean = true
|
21
|
+
@verbose = false
|
22
|
+
@silent = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def project_root
|
26
|
+
Pathname.pwd
|
27
|
+
end
|
28
|
+
|
29
|
+
def project_pods_root
|
30
|
+
@project_pods_root ||= project_root + 'Pods'
|
31
|
+
end
|
32
|
+
|
33
|
+
def project_podfile
|
34
|
+
unless @project_podfile
|
35
|
+
@project_podfile = project_root + 'Podfile'
|
36
|
+
unless @project_podfile.exist?
|
37
|
+
@project_podfile = project_root.glob('*.podspec').first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
@project_podfile
|
41
|
+
end
|
42
|
+
|
43
|
+
module Mixin
|
44
|
+
def config
|
45
|
+
Config.instance
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Gem
|
2
|
+
end
|
3
|
+
require 'rubygems/dependency'
|
4
|
+
|
5
|
+
module Pod
|
6
|
+
class Dependency < Gem::Dependency
|
7
|
+
attr_accessor :only_part_of_other_pod
|
8
|
+
alias_method :only_part_of_other_pod?, :only_part_of_other_pod
|
9
|
+
|
10
|
+
def initialize(name, *version_requirements)
|
11
|
+
super
|
12
|
+
@only_part_of_other_pod = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
super && @only_part_of_other_pod == other.only_part_of_other_pod
|
17
|
+
end
|
18
|
+
|
19
|
+
# Taken from a newer version of RubyGems
|
20
|
+
unless public_method_defined?(:merge)
|
21
|
+
def merge other
|
22
|
+
unless name == other.name then
|
23
|
+
raise ArgumentError,
|
24
|
+
"#{self} and #{other} have different names"
|
25
|
+
end
|
26
|
+
|
27
|
+
default = Gem::Requirement.default
|
28
|
+
self_req = self.requirement
|
29
|
+
other_req = other.requirement
|
30
|
+
|
31
|
+
return self.class.new name, self_req if other_req == default
|
32
|
+
return self.class.new name, other_req if self_req == default
|
33
|
+
|
34
|
+
self.class.new name, self_req.as_list.concat(other_req.as_list)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Pod
|
2
|
+
class Downloader
|
3
|
+
def self.for_source(pod_root, source)
|
4
|
+
options = source.dup
|
5
|
+
if url = options.delete(:git)
|
6
|
+
Git.new(pod_root, url, options)
|
7
|
+
else
|
8
|
+
raise "Unsupported download strategy `#{source.inspect}'."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :pod_root, :url, :options
|
13
|
+
|
14
|
+
def initialize(pod_root, url, options)
|
15
|
+
@pod_root, @url, @options = pod_root, url, options
|
16
|
+
end
|
17
|
+
|
18
|
+
class Git < Downloader
|
19
|
+
extend Executable
|
20
|
+
executable :git
|
21
|
+
|
22
|
+
def download
|
23
|
+
if @options[:tag]
|
24
|
+
download_tag
|
25
|
+
elsif @options[:commit]
|
26
|
+
download_commit
|
27
|
+
else
|
28
|
+
raise "Either a tag or a commit has to be specified."
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def download_tag
|
33
|
+
@pod_root.mkdir
|
34
|
+
Dir.chdir(@pod_root) do
|
35
|
+
git "init"
|
36
|
+
git "remote add origin '#{@url}'"
|
37
|
+
git "fetch origin tags/#{@options[:tag]}"
|
38
|
+
git "reset --hard FETCH_HEAD"
|
39
|
+
git "checkout -b activated-pod-commit"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def download_commit
|
44
|
+
git "clone '#{@url}' '#{@pod_root}'"
|
45
|
+
Dir.chdir(@pod_root) do
|
46
|
+
git "checkout -b activated-pod-commit #{@options[:commit]}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def clean
|
51
|
+
(@pod_root + '.git').rmtree
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Pod
|
2
|
+
# TODO the static library needs an extra xcconfig which sets the values from issue #1.
|
3
|
+
# Or we could edit the project.pbxproj file, but that seems like more work...
|
4
|
+
class Installer
|
5
|
+
include Config::Mixin
|
6
|
+
|
7
|
+
def initialize(specification)
|
8
|
+
@specification = specification
|
9
|
+
end
|
10
|
+
|
11
|
+
def dependent_specification_sets
|
12
|
+
@dependent_specification_sets ||= Resolver.new(@specification).resolve
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_specification_sets
|
16
|
+
dependent_specification_sets.reject(&:only_part_of_other_pod?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def source_files
|
20
|
+
source_files = []
|
21
|
+
build_specification_sets.each do |set|
|
22
|
+
spec = set.specification
|
23
|
+
spec.read(:source_files).each do |pattern|
|
24
|
+
pattern = spec.pod_destroot + pattern
|
25
|
+
pattern = pattern + '*.{h,m,mm,c,cpp}' if pattern.directory?
|
26
|
+
pattern.glob.each do |file|
|
27
|
+
source_files << file.relative_path_from(config.project_pods_root)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
source_files
|
32
|
+
end
|
33
|
+
|
34
|
+
def xcconfig
|
35
|
+
@xcconfig ||= Xcode::Config.new({
|
36
|
+
# in a workspace this is where the static library headers should be found
|
37
|
+
'USER_HEADER_SEARCH_PATHS' => '$(BUILT_PRODUCTS_DIR)',
|
38
|
+
# search the user headers
|
39
|
+
'ALWAYS_SEARCH_USER_PATHS' => 'YES',
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
def xcodeproj
|
44
|
+
@xcodeproj ||= Xcode::Project.ios_static_library
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_project
|
48
|
+
source_files.each { |file| xcodeproj.add_source_file(file) }
|
49
|
+
build_specification_sets.each do |set|
|
50
|
+
xcconfig << set.specification.read(:xcconfig)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def install!
|
55
|
+
puts "Installing dependencies of: #{@specification.defined_in_file}" unless config.silent?
|
56
|
+
generate_project
|
57
|
+
build_specification_sets.each { |set| set.specification.install! }
|
58
|
+
xcodeproj.create_in(config.project_pods_root)
|
59
|
+
xcconfig.create_in(config.project_pods_root)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Pod
|
2
|
+
class Resolver
|
3
|
+
def initialize(specification)
|
4
|
+
@specification = specification
|
5
|
+
end
|
6
|
+
|
7
|
+
def resolve
|
8
|
+
@sets = []
|
9
|
+
find_dependency_sets(@specification)
|
10
|
+
@sets
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_dependency_sets(specification)
|
14
|
+
specification.read(:dependencies).each do |dependency|
|
15
|
+
set = Source.search(dependency)
|
16
|
+
set.required_by(specification)
|
17
|
+
unless @sets.include?(set)
|
18
|
+
@sets << set
|
19
|
+
find_dependency_sets(set.specification)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Pod
|
2
|
+
class Source
|
3
|
+
def self.all
|
4
|
+
@sources ||= begin
|
5
|
+
repos_dir = Config.instance.repos_dir
|
6
|
+
unless repos_dir.exist?
|
7
|
+
raise Informative, "No spec repos found in `#{repos_dir}'. " \
|
8
|
+
"To fetch the `master' repo run: $ pod setup"
|
9
|
+
end
|
10
|
+
repos_dir.children.select(&:directory?).map { |repo| new(repo) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.search(dependency)
|
15
|
+
all.map { |source| source.search(dependency) }.compact.first ||
|
16
|
+
raise(Informative, "Unable to find a pod named `#{dependency.name}'")
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :repo
|
20
|
+
|
21
|
+
def initialize(repo)
|
22
|
+
@repo = repo
|
23
|
+
end
|
24
|
+
|
25
|
+
def search(dependency)
|
26
|
+
if dir = @repo.children.find { |c| c.basename.to_s == dependency.name }
|
27
|
+
Specification::Set.by_pod_dir(dir)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module Pod
|
2
|
+
class Specification
|
3
|
+
autoload :Set, 'cocoapods/specification/set'
|
4
|
+
|
5
|
+
def self.from_podfile(path)
|
6
|
+
if path.exist?
|
7
|
+
spec = new
|
8
|
+
spec.instance_eval(path.read)
|
9
|
+
spec.defined_in_file = path
|
10
|
+
spec
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from_podspec(path)
|
15
|
+
spec = eval(path.read, nil, path.to_s)
|
16
|
+
spec.defined_in_file = path
|
17
|
+
spec
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_accessor :defined_in_file
|
21
|
+
|
22
|
+
def initialize(&block)
|
23
|
+
@dependencies = []
|
24
|
+
@xcconfig = {}
|
25
|
+
instance_eval(&block) if block_given?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Attributes
|
29
|
+
|
30
|
+
def read(name)
|
31
|
+
instance_variable_get("@#{name}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def name(name)
|
35
|
+
@name = name
|
36
|
+
end
|
37
|
+
|
38
|
+
def version(version)
|
39
|
+
@version = Version.new(version)
|
40
|
+
end
|
41
|
+
|
42
|
+
def authors(*names_and_email_addresses)
|
43
|
+
list = names_and_email_addresses
|
44
|
+
unless list.first.is_a?(Hash)
|
45
|
+
authors = list.last.is_a?(Hash) ? list.pop : {}
|
46
|
+
list.each { |name| authors[name] = nil }
|
47
|
+
end
|
48
|
+
@authors = authors || list
|
49
|
+
end
|
50
|
+
alias_method :author, :authors
|
51
|
+
|
52
|
+
def homepage(url)
|
53
|
+
@homepage = url
|
54
|
+
end
|
55
|
+
|
56
|
+
def summary(summary)
|
57
|
+
@summary = summary
|
58
|
+
@description ||= summary
|
59
|
+
end
|
60
|
+
|
61
|
+
def description(description)
|
62
|
+
@description = description
|
63
|
+
end
|
64
|
+
|
65
|
+
def part_of(name, *version_requirements)
|
66
|
+
part_of_dependency(name, *version_requirements)
|
67
|
+
@part_of.only_part_of_other_pod = true
|
68
|
+
end
|
69
|
+
|
70
|
+
def part_of_dependency(name, *version_requirements)
|
71
|
+
@part_of = dependency(name, *version_requirements)
|
72
|
+
end
|
73
|
+
|
74
|
+
def source_files(*patterns)
|
75
|
+
@source_files = patterns.map { |p| Pathname.new(p) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def source(remote)
|
79
|
+
@source = remote
|
80
|
+
end
|
81
|
+
|
82
|
+
attr_reader :dependencies
|
83
|
+
def dependency(name, *version_requirements)
|
84
|
+
dep = Dependency.new(name, *version_requirements)
|
85
|
+
@dependencies << dep
|
86
|
+
dep
|
87
|
+
end
|
88
|
+
|
89
|
+
def xcconfig(hash)
|
90
|
+
@xcconfig = hash
|
91
|
+
end
|
92
|
+
|
93
|
+
# Not attributes
|
94
|
+
|
95
|
+
include Config::Mixin
|
96
|
+
|
97
|
+
def ==(other)
|
98
|
+
self.class === other &&
|
99
|
+
@name && @name == other.read(:name) &&
|
100
|
+
@version && @version == other.read(:version)
|
101
|
+
end
|
102
|
+
|
103
|
+
def dependency_by_name(name)
|
104
|
+
@dependencies.find { |d| d.name == name }
|
105
|
+
end
|
106
|
+
|
107
|
+
def part_of_specification_set
|
108
|
+
if @part_of
|
109
|
+
Set.by_specification_name(@part_of.name)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the specification for the pod that this pod's source is a part of.
|
114
|
+
def part_of_specification
|
115
|
+
(set = part_of_specification_set) && set.specification
|
116
|
+
end
|
117
|
+
|
118
|
+
def pod_destroot
|
119
|
+
return if from_podfile?
|
120
|
+
if part_of_other_pod?
|
121
|
+
part_of_specification.pod_destroot
|
122
|
+
else
|
123
|
+
config.project_pods_root + "#{@name}-#{@version}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def part_of_other_pod?
|
128
|
+
!@part_of.nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
def from_podfile?
|
132
|
+
@name.nil? && @version.nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_s
|
136
|
+
if from_podfile?
|
137
|
+
"podfile at `#{@defined_in_file}'"
|
138
|
+
else
|
139
|
+
"`#{@name}' version `#{@version}'"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def inspect
|
144
|
+
"#<#{self.class.name} for #{to_s}>"
|
145
|
+
end
|
146
|
+
|
147
|
+
# Install and download hooks
|
148
|
+
|
149
|
+
# Places the activated specification in the project's pods directory.
|
150
|
+
#
|
151
|
+
# Override this if you need to perform work before or after activating the
|
152
|
+
# pod. Eg:
|
153
|
+
#
|
154
|
+
# Pod::Spec.new do
|
155
|
+
# def install!
|
156
|
+
# # pre-install
|
157
|
+
# super
|
158
|
+
# # post-install
|
159
|
+
# end
|
160
|
+
# end
|
161
|
+
def install!
|
162
|
+
puts "==> Installing: #{self}" unless config.silent?
|
163
|
+
config.project_pods_root.mkpath
|
164
|
+
require 'fileutils'
|
165
|
+
FileUtils.cp(@defined_in_file, config.project_pods_root)
|
166
|
+
|
167
|
+
# In case this spec is part of another pod's source, we need to dowload
|
168
|
+
# the other pod's source.
|
169
|
+
(part_of_specification || self).download_if_necessary!
|
170
|
+
end
|
171
|
+
|
172
|
+
def download_if_necessary!
|
173
|
+
if pod_destroot.exist?
|
174
|
+
puts " * Skipping download of #{self}, pod already downloaded" unless config.silent?
|
175
|
+
else
|
176
|
+
puts " * Downloading: #{self}" unless config.silent?
|
177
|
+
download!
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Downloads the source of the pod and places it in the project's pods
|
182
|
+
# directory.
|
183
|
+
#
|
184
|
+
# Override this if you need to perform work before or after downloading the
|
185
|
+
# pod, or if you need to implement custom dowloading. Eg:
|
186
|
+
#
|
187
|
+
# Pod::Spec.new do
|
188
|
+
# def download!
|
189
|
+
# # pre-download
|
190
|
+
# super # or custom downloading
|
191
|
+
# # post-download
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
def download!
|
195
|
+
downloader = Downloader.for_source(pod_destroot, @source)
|
196
|
+
downloader.download
|
197
|
+
downloader.clean if config.clean
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
Spec = Specification
|
203
|
+
end
|