cocoapods 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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