cocoapods 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,13 @@
1
+ module Pod
2
+ module Executable
3
+ def executable(name)
4
+ define_method(name) do |command|
5
+ if Config.instance.verbose?
6
+ `#{name} #{command} 1>&2`
7
+ else
8
+ `#{name} #{command} 2> /dev/null`
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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