xcodeproj 0.3.5 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/bin/xcodeproj +13 -0
  2. data/lib/xcodeproj.rb +13 -1
  3. data/lib/xcodeproj/command.rb +131 -0
  4. data/lib/xcodeproj/command/project_diff.rb +53 -0
  5. data/lib/xcodeproj/command/show.rb +35 -0
  6. data/lib/xcodeproj/command/target_diff.rb +43 -0
  7. data/lib/xcodeproj/config.rb +66 -38
  8. data/lib/xcodeproj/constants.rb +146 -0
  9. data/lib/xcodeproj/helper.rb +28 -0
  10. data/lib/xcodeproj/project.rb +462 -156
  11. data/lib/xcodeproj/project/object.rb +251 -138
  12. data/lib/xcodeproj/project/object/build_configuration.rb +27 -0
  13. data/lib/xcodeproj/project/object/build_file.rb +26 -0
  14. data/lib/xcodeproj/project/object/build_phase.rb +132 -61
  15. data/lib/xcodeproj/project/object/build_rule.rb +46 -0
  16. data/lib/xcodeproj/project/object/configuration_list.rb +47 -0
  17. data/lib/xcodeproj/project/object/container_item_proxy.rb +49 -0
  18. data/lib/xcodeproj/project/object/file_reference.rb +80 -48
  19. data/lib/xcodeproj/project/object/group.rb +213 -89
  20. data/lib/xcodeproj/project/object/native_target.rb +171 -114
  21. data/lib/xcodeproj/project/object/root_object.rb +66 -0
  22. data/lib/xcodeproj/project/object/target_dependency.rb +23 -0
  23. data/lib/xcodeproj/project/object_attributes.rb +382 -0
  24. data/lib/xcodeproj/project/object_list.rb +64 -118
  25. data/lib/xcodeproj/project/recursive_diff.rb +116 -0
  26. data/lib/xcodeproj/workspace.rb +56 -2
  27. metadata +38 -10
  28. data/lib/xcodeproj/project/association.rb +0 -54
  29. data/lib/xcodeproj/project/association/has_many.rb +0 -51
  30. data/lib/xcodeproj/project/association/has_one.rb +0 -39
  31. data/lib/xcodeproj/project/association/reflection.rb +0 -86
  32. data/lib/xcodeproj/project/object/configuration.rb +0 -97
data/bin/xcodeproj ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if $0 == __FILE__
4
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
5
+ require "rubygems"
6
+ require "bundler/setup"
7
+ $:.unshift File.expand_path('../../ext', __FILE__)
8
+ $:.unshift File.expand_path('../../lib', __FILE__)
9
+ end
10
+
11
+ require 'xcodeproj'
12
+
13
+ Xcodeproj::Command.run(*ARGV)
data/lib/xcodeproj.rb CHANGED
@@ -1,7 +1,19 @@
1
1
  module Xcodeproj
2
- VERSION = '0.3.5'
2
+ VERSION = '0.4.0.rc1'
3
+
4
+ class PlainInformative < StandardError
5
+ end
6
+
7
+ class Informative < PlainInformative
8
+ def message
9
+ super !~ /\[!\]/ ? "[!] #{super}\n".red : super
10
+ end
11
+ end
3
12
 
4
13
  autoload :Config, 'xcodeproj/config'
14
+ autoload :Command, 'xcodeproj/command'
15
+ autoload :Constants, 'xcodeproj/constants'
16
+ autoload :Helper, 'xcodeproj/helper'
5
17
  autoload :Project, 'xcodeproj/project'
6
18
  autoload :Workspace, 'xcodeproj/workspace'
7
19
  end
@@ -0,0 +1,131 @@
1
+ module Xcodeproj
2
+
3
+ require 'colored'
4
+
5
+ class Command
6
+ autoload :TargetDiff, 'xcodeproj/command/target_diff'
7
+ autoload :ProjectDiff, 'xcodeproj/command/project_diff'
8
+ autoload :Show, 'xcodeproj/command/show'
9
+
10
+ class Help < StandardError
11
+ def initialize(command_class, argv, unrecognized_command = nil)
12
+ @command_class, @argv, @unrecognized_command = command_class, argv, unrecognized_command
13
+ end
14
+
15
+ def message
16
+ message = [
17
+ '',
18
+ @command_class.banner.gsub(/\$ pod (.*)/, '$ pod \1'.green),
19
+ '',
20
+ 'Options:',
21
+ '',
22
+ options,
23
+ "\n",
24
+ ].join("\n")
25
+ message << "[!] Unrecognized command: `#{@unrecognized_command}'\n".red if @unrecognized_command
26
+ message << "[!] Unrecognized argument#{@argv.count > 1 ? 's' : ''}: `#{@argv.join(' - ')}'\n".red unless @argv.empty?
27
+ message
28
+ end
29
+
30
+ private
31
+
32
+ def options
33
+ options = @command_class.options
34
+ keys = options.map(&:first)
35
+ key_size = keys.inject(0) { |size, key| key.size > size ? key.size : size }
36
+ options.map { |key, desc| " #{key.ljust(key_size)} #{desc}" }.join("\n")
37
+ end
38
+ end
39
+
40
+ class ARGV < Array
41
+ def options; select { |x| x.to_s[0,1] == '-' }; end
42
+ def arguments; self - options; end
43
+ def option(name); !!delete(name); end
44
+ def shift_argument; (arg = arguments[0]) && delete(arg); end
45
+ end
46
+
47
+ def self.banner
48
+ commands = ['target-diff', 'project-diff', 'show']
49
+ banner = "To see help for the available commands run:\n\n"
50
+ banner + commands.map { |cmd| " * $ xcodeproj #{cmd.green} --help" }.join("\n")
51
+ end
52
+
53
+ def self.options
54
+ [
55
+ ['--help', 'Show help information'],
56
+ # ['--silent', 'Print nothing'],
57
+ # ['--no-color', 'Print output without color'],
58
+ # ['--verbose', 'Print more information while working'],
59
+ ['--version', 'Prints the version of CocoaPods'],
60
+ ]
61
+ end
62
+
63
+ def self.run(*argv)
64
+ sub_command = parse(*argv)
65
+ sub_command.run
66
+
67
+ rescue Interrupt
68
+ puts "[!] Cancelled".red
69
+ Config.instance.verbose? ? raise : exit(1)
70
+
71
+ rescue Exception => e
72
+ puts e.message
73
+ puts *e.backtrace
74
+ exit 1
75
+ end
76
+
77
+ def self.parse(*argv)
78
+ argv = ARGV.new(argv)
79
+ if argv.option('--version')
80
+ puts VERSION
81
+ exit!(0)
82
+ end
83
+
84
+ show_help = argv.option('--help')
85
+
86
+ String.send(:define_method, :colorize) { |string , _| string } if argv.option( '--no-color' )
87
+
88
+ command_class = case command_argument = argv.shift_argument
89
+ when 'target-diff' then TargetDiff
90
+ when 'project-diff' then ProjectDiff
91
+ when 'show' then Show
92
+ end
93
+
94
+ if command_class.nil?
95
+ raise Help.new(self, argv, command_argument)
96
+ elsif show_help
97
+ raise Help.new(command_class, argv)
98
+ else
99
+ command_class.new(argv)
100
+ end
101
+ end
102
+
103
+ def initialize(argv)
104
+ raise Help.new(self.class, argv)
105
+ end
106
+
107
+ def xcodeproj_path
108
+ unless @xcodeproj_path
109
+ projects = Dir.glob('*.xcodeproj')
110
+ if projects.size == 1
111
+ xcodeproj_path = projects.first
112
+ elsif projects.size > 1
113
+ raise Informative, 'There are more than one Xcode project documents ' \
114
+ 'in the current working directory. Please specify ' \
115
+ 'which to use with the `--project` option.'
116
+ else
117
+ raise Informative, 'No Xcode project document found in the current ' \
118
+ 'working directory. Please specify which to use ' \
119
+ 'with the `--project` option.'
120
+ end
121
+ @xcodeproj_path = File.expand_path(xcodeproj_path)
122
+ end
123
+ @xcodeproj_path
124
+ end
125
+
126
+ def xcodeproj
127
+ @xcodeproj ||= Project.new(xcodeproj_path)
128
+ end
129
+ end
130
+ end
131
+
@@ -0,0 +1,53 @@
1
+ module Xcodeproj
2
+ class Command
3
+ class ProjectDiff < Command
4
+ def self.banner
5
+ %{Installing dependencies of a project:
6
+
7
+ $ project-diff PROJECT_1 PROJECT_2
8
+
9
+ Shows the difference between two projects in an UUID agnostic fashion.
10
+
11
+ To reduce the noise (and to simplify implementation) differences in the
12
+ other of arrays are ignored.
13
+ }
14
+ end
15
+
16
+ def self.options
17
+ [ ["--ignore KEY", "A key to ignore in the comparison. Can be specified multiple times."] ].concat(super)
18
+ end
19
+
20
+ def initialize(argv)
21
+ @path_project1 = argv.shift_argument
22
+ @path_project2 = argv.shift_argument
23
+ @keys_to_ignore = []
24
+ while (idx = argv.index('--ignore'))
25
+ @keys_to_ignore << argv.delete_at(idx + 1)
26
+ argv.delete_at(idx)
27
+ end
28
+ super unless argv.empty?
29
+ end
30
+
31
+
32
+ def run
33
+ hash_1 = Project.new(@path_project1).to_tree_hash
34
+ hash_2 = Project.new(@path_project2).to_tree_hash
35
+ (@keys_to_ignore).each do |key|
36
+ hash_1.recursive_delete(key)
37
+ hash_2.recursive_delete(key)
38
+ end
39
+
40
+ diff = hash_1.recursive_diff(hash_2, @path_project1, @path_project2)
41
+ diff.recursive_delete('displayName')
42
+
43
+ require 'yaml'
44
+ yaml = diff.to_yaml
45
+ yaml = yaml.gsub(@path_project1, @path_project1.cyan)
46
+ yaml = yaml.gsub(@path_project2, @path_project2.magenta)
47
+ puts yaml
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+
@@ -0,0 +1,35 @@
1
+ module Xcodeproj
2
+ class Command
3
+ class Show < Command
4
+ def self.banner
5
+ %{Installing dependencies of a project:
6
+
7
+ $ project-diff PROJECT_1 PROJECT_2
8
+
9
+ Shows a YAML reppresentation of a project.
10
+ }
11
+ end
12
+
13
+ def self.options
14
+ [
15
+ ["--project PATH", "The Xcode project document to use."],
16
+ ].concat(super)
17
+ end
18
+
19
+ def initialize(argv)
20
+ if argv.option('--project')
21
+ @xcodeproj_path = File.expand_path(argv.shift_argument)
22
+ end
23
+ super unless argv.empty?
24
+ end
25
+
26
+ def run
27
+ require 'yaml'
28
+ yaml = xcodeproj.to_tree_hash.to_yaml
29
+ puts yaml
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+
@@ -0,0 +1,43 @@
1
+ module Xcodeproj
2
+ class Command
3
+ class TargetDiff < Command
4
+ def self.banner
5
+ %{Installing dependencies of a project:
6
+
7
+ $ targets-diff [target 1] [target 2]
8
+
9
+ Shows the difference between two targets. (Only build source files atm.)
10
+ }
11
+ end
12
+
13
+ def self.options
14
+ [
15
+ ["--project PATH", "The Xcode project document to use."],
16
+ ].concat(super)
17
+ end
18
+
19
+ def initialize(argv)
20
+ @target1 = argv.shift_argument
21
+ @target2 = argv.shift_argument
22
+ if argv.option('--project')
23
+ @xcodeproj_path = File.expand_path(argv.shift_argument)
24
+ end
25
+ super unless argv.empty?
26
+ end
27
+
28
+ def run
29
+ require 'yaml'
30
+ differ = Helper::TargetDiff.new(xcodeproj, @target1, @target2)
31
+ files = differ.new_source_build_files.map do |build_file|
32
+ {
33
+ 'Name' => build_file.file_ref.name,
34
+ 'Path' => build_file.file_ref.path,
35
+ 'Build settings' => build_file.settings,
36
+ }
37
+ end
38
+ puts files.to_yaml
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -1,14 +1,41 @@
1
1
  module Xcodeproj
2
+
2
3
  # This class holds the data for a Xcode build settings file (xcconfig) and
3
4
  # serializes it.
5
+ #
4
6
  class Config
5
- # Returns a new instance of Config
6
- #
7
- # @param [Hash, File, String] xcconfig_hash_or_file Initial data.
7
+
8
8
  require 'set'
9
9
 
10
- attr_accessor :attributes, :frameworks, :weak_frameworks ,:libraries
10
+ # @return [Hash{String => String}] The attributes of the settings file
11
+ # excluding frameworks, weak_framework and libraries.
12
+ #
13
+ attr_accessor :attributes
14
+
15
+ # @return [Array<String>] The list of the frameworks required by this
16
+ # settings file.
17
+ #
18
+ attr_accessor :frameworks
11
19
 
20
+ # @return [Array<String>] The list of the *weak* frameworks required by
21
+ # this settings file.
22
+ #
23
+ attr_accessor :weak_frameworks
24
+
25
+ # @return [Array<String>] The list of the libraries required by this
26
+ # settings file.
27
+ #
28
+ attr_accessor :libraries
29
+
30
+ # @return [Array] The list of the configuration files included by this
31
+ # configuration file (`#include "SomeConfig"`).
32
+ #
33
+ attr_accessor :includes
34
+
35
+ # Returns a new instance of Config
36
+ #
37
+ # @param [Hash, File, String] xcconfig_hash_or_file Initial data.
38
+ #
12
39
  def initialize(xcconfig_hash_or_file = {})
13
40
  @attributes = {}
14
41
  @includes = []
@@ -16,7 +43,34 @@ module Xcodeproj
16
43
  merge!(extract_hash(xcconfig_hash_or_file))
17
44
  end
18
45
 
19
- # @return [Hash] The internal data.
46
+
47
+ #@! group Serialization
48
+
49
+ # Serializes the internal data in the xcconfig format.
50
+ #
51
+ # @example
52
+ #
53
+ # config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
54
+ # config.to_s # => "PODS_ROOT = \"$(SRCROOT)/Pods\"\nOTHER_LDFLAGS = -lxml2"
55
+ #
56
+ # @return [String] The serialized internal data.
57
+ def to_s
58
+ to_hash.map { |key, value| "#{key} = #{value}" }.join("\n")
59
+ end
60
+
61
+ # @return [void] Writes the serialized representation of the internal data
62
+ # to the given path.
63
+ #
64
+ # @param [Pathname] pathname The file that the data should be written to.
65
+ #
66
+ def save_as(pathname)
67
+ pathname.open('w') { |file| file << to_s }
68
+ end
69
+
70
+ # @return [Hash] The hash reppresentation of the framework. The hash
71
+ # includes the frameworks, the weak frameworks and the libraries in the
72
+ # `Other Linker Flags` (`OTHER_LDFLAGS`).
73
+ #
20
74
  def to_hash
21
75
  hash = @attributes.dup
22
76
  flags = hash['OTHER_LDFLAGS'] || ''
@@ -29,23 +83,9 @@ module Xcodeproj
29
83
  hash
30
84
  end
31
85
 
32
- def ==(other)
33
- other.respond_to?(:to_hash) && other.to_hash == self.to_hash
34
- end
35
86
 
36
- # @return [Array] Config's include file list
37
- # @example
38
- #
39
- # Consider following xcconfig file:
40
- #
41
- # #include "SomeConfig"
42
- # Key1 = Value1
43
- # Key2 = Value2
44
- #
45
- # config.includes # => [ "SomeConfig" ]
46
- def includes
47
- @includes
48
- end
87
+
88
+ #@! group Merging
49
89
 
50
90
  # Merges the given xcconfig hash or Config into the internal data.
51
91
  #
@@ -59,6 +99,7 @@ module Xcodeproj
59
99
  # config.to_hash # => { 'PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2 -lz', 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers"' }
60
100
  #
61
101
  # @param [Hash, Config] xcconfig The data to merge into the internal data.
102
+ #
62
103
  def merge!(xcconfig)
63
104
  if xcconfig.is_a? Config
64
105
  @attributes.merge!(xcconfig.attributes) { |key, v1, v2| "#{v1} #{v2}" }
@@ -95,28 +136,15 @@ module Xcodeproj
95
136
  Xcodeproj::Config.new(self.to_hash.dup)
96
137
  end
97
138
 
98
- # Serializes the internal data in the xcconfig format.
99
- #
100
- # @example
101
- #
102
- # config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
103
- # config.to_s # => "PODS_ROOT = \"$(SRCROOT)/Pods\"\nOTHER_LDFLAGS = -lxml2"
104
- #
105
- # @return [String] The serialized internal data.
106
- def to_s
107
- to_hash.map { |key, value| "#{key} = #{value}" }.join("\n")
108
- end
139
+
140
+ #@! group Object methods
109
141
 
110
142
  def inspect
111
143
  to_hash.inspect
112
144
  end
113
145
 
114
- # Writes the serialized representation of the internal data to the given
115
- # path.
116
- #
117
- # @param [Pathname] pathname The file that the data should be written to.
118
- def save_as(pathname)
119
- pathname.open('w') { |file| file << to_s }
146
+ def ==(other)
147
+ other.respond_to?(:to_hash) && other.to_hash == self.to_hash
120
148
  end
121
149
 
122
150
  private