xcodeproj 0.1.0 → 0.2.0

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,89 @@
1
+ module Xcodeproj
2
+ class Project
3
+ module Object
4
+
5
+ class PBXBuildFile < AbstractPBXObject
6
+ # [Hash] the list of build settings for this file
7
+ attribute :settings
8
+
9
+ has_one :file, :uuid => :file_ref
10
+ end
11
+
12
+ class PBXBuildPhase < AbstractPBXObject
13
+ has_many :build_files, :uuids => :files, :uuids_as => :build_file_references
14
+
15
+ # [String] some kind of magic number which seems to always be '2147483647'
16
+ attribute :build_action_mask
17
+
18
+ # [String] wether or not this should only be processed before deployment
19
+ # (I guess). This cane be either '0', or '1'
20
+ attribute :run_only_for_deployment_postprocessing
21
+
22
+ def initialize(*)
23
+ super
24
+ self.build_file_references ||= []
25
+ # These are always the same, no idea what they are.
26
+ self.build_action_mask ||= "2147483647"
27
+ self.run_only_for_deployment_postprocessing ||= "0"
28
+ end
29
+
30
+ def files
31
+ PBXObjectList.new(PBXFileReference, @project) do |list|
32
+ list.let(:uuid_scope) { self.build_files.map(&:file_ref) }
33
+ list.let(:push) do |file|
34
+ self.build_files << file.build_files.new
35
+ end
36
+ end
37
+ end
38
+
39
+ def <<(file)
40
+ files << file
41
+ end
42
+ end
43
+
44
+ class PBXCopyFilesBuildPhase < PBXBuildPhase
45
+ # [String] the path where this file should be copied to
46
+ attribute :dst_path
47
+
48
+ # [String] a magic number which always seems to be "16"
49
+ attribute :dst_subfolder_spec
50
+
51
+ def initialize(*)
52
+ super
53
+ self.dst_path ||= '$(PRODUCT_NAME)'
54
+ self.dst_subfolder_spec ||= "16"
55
+ end
56
+ end
57
+
58
+ class PBXSourcesBuildPhase < PBXBuildPhase; end
59
+ class PBXFrameworksBuildPhase < PBXBuildPhase; end
60
+
61
+ # @todo Should `files`, `input_paths`, and `output_paths` be has_many
62
+ # associations with file references?
63
+ class PBXShellScriptBuildPhase < PBXBuildPhase
64
+ attribute :name
65
+
66
+ attribute :files
67
+ attribute :input_paths
68
+ attribute :output_paths
69
+
70
+ # [String] The path to the script interpreter. Defaults to `/bin/sh`.
71
+ attribute :shell_path
72
+
73
+ # [String] The actual script to perform.
74
+ attribute :shell_script
75
+
76
+ def initialize(*)
77
+ super
78
+ self.files ||= []
79
+ self.input_paths ||= []
80
+ self.output_paths ||= []
81
+
82
+ self.shell_path ||= '/bin/sh'
83
+ self.shell_script ||= ''
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,100 @@
1
+ module Xcodeproj
2
+ class Project
3
+ module Object
4
+
5
+ class XCBuildConfiguration < AbstractPBXObject
6
+ COMMON_BUILD_SETTINGS = {
7
+ :all => {
8
+ 'GCC_VERSION' => 'com.apple.compilers.llvm.clang.1_0',
9
+ 'GCC_PRECOMPILE_PREFIX_HEADER' => 'YES',
10
+ 'PRODUCT_NAME' => '$(TARGET_NAME)',
11
+ 'SKIP_INSTALL' => 'YES',
12
+ 'DSTROOT' => '/tmp/xcodeproj.dst',
13
+ 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
14
+ 'GCC_C_LANGUAGE_STANDARD' => 'gnu99',
15
+ 'INSTALL_PATH' => "$(BUILT_PRODUCTS_DIR)",
16
+ 'GCC_WARN_ABOUT_MISSING_PROTOTYPES' => 'YES',
17
+ 'GCC_WARN_ABOUT_RETURN_TYPE' => 'YES',
18
+ 'GCC_WARN_UNUSED_VARIABLE' => 'YES',
19
+ 'OTHER_LDFLAGS' => '',
20
+ 'COPY_PHASE_STRIP' => 'YES',
21
+ }.freeze,
22
+ :debug => {
23
+ 'GCC_DYNAMIC_NO_PIC' => 'NO',
24
+ 'GCC_PREPROCESSOR_DEFINITIONS' => ["DEBUG=1", "$(inherited)"],
25
+ 'GCC_SYMBOLS_PRIVATE_EXTERN' => 'NO',
26
+ 'GCC_OPTIMIZATION_LEVEL' => '0',
27
+ 'COPY_PHASE_STRIP' => 'NO',
28
+ }.freeze,
29
+ :ios => {
30
+ 'ARCHS' => "$(ARCHS_STANDARD_32_BIT)",
31
+ 'IPHONEOS_DEPLOYMENT_TARGET' => '4.3',
32
+ 'PUBLIC_HEADERS_FOLDER_PATH' => "$(TARGET_NAME)",
33
+ 'SDKROOT' => 'iphoneos',
34
+ }.freeze,
35
+ :osx => {
36
+ 'ARCHS' => "$(ARCHS_STANDARD_64_BIT)",
37
+ 'GCC_ENABLE_OBJC_EXCEPTIONS' => 'YES',
38
+ 'GCC_WARN_64_TO_32_BIT_CONVERSION' => 'YES',
39
+ 'GCC_VERSION' => 'com.apple.compilers.llvm.clang.1_0',
40
+ 'MACOSX_DEPLOYMENT_TARGET' => '10.7',
41
+ 'SDKROOT' => 'macosx',
42
+ }.freeze,
43
+ [:osx, :debug] => {
44
+ 'ONLY_ACTIVE_ARCH' => 'YES',
45
+ }.freeze,
46
+ [:osx, :release] => {
47
+ 'DEBUG_INFORMATION_FORMAT' => 'dwarf-with-dsym',
48
+ }.freeze,
49
+ [:ios, :release] => {
50
+ 'VALIDATE_PRODUCT' => 'YES',
51
+ }.freeze,
52
+ }.freeze
53
+
54
+ def self.new_release(project)
55
+ new(project, nil,
56
+ 'name' => 'Release',
57
+ 'buildSettings' => COMMON_BUILD_SETTINGS[:all].dup
58
+ )
59
+ end
60
+
61
+ def self.new_debug(project)
62
+ new(project, nil,
63
+ 'name' => 'Debug',
64
+ 'buildSettings' => COMMON_BUILD_SETTINGS[:all].merge(COMMON_BUILD_SETTINGS[:debug])
65
+ )
66
+ end
67
+
68
+ # [Hash] the build settings used when building a target
69
+ attribute :build_settings
70
+
71
+ # TODO why do I need to specify the uuid here?
72
+ has_one :base_configuration, :uuid => :base_configuration_reference
73
+
74
+ def initialize(*)
75
+ super
76
+ self.build_settings ||= {}
77
+ end
78
+ end
79
+
80
+ class XCConfigurationList < AbstractPBXObject
81
+ attribute :default_configuration_is_visible
82
+ attribute :default_configuration_name
83
+
84
+ has_many :build_configurations
85
+
86
+ def initialize(*)
87
+ super
88
+ self.build_configuration_references ||= []
89
+ end
90
+
91
+ def build_settings(build_configuration_name)
92
+ if config = build_configurations.where(:name => build_configuration_name)
93
+ config.build_settings
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,71 @@
1
+ require 'xcodeproj/project/object/group'
2
+
3
+ module Xcodeproj
4
+ class Project
5
+ module Object
6
+
7
+ # @todo Add a list of all possible file types for `explicit_file_type`
8
+ # and `last_known_file_type`.
9
+ class PBXFileReference < AbstractGroupEntry
10
+ # [String] the path to the file relative to the source tree
11
+ attribute :path
12
+
13
+ # [String] the source tree to which the file is relative. It can be one
14
+ # of `SOURCE_ROOT` or `SDKROOT`
15
+ attribute :source_tree
16
+
17
+ # [String] the file type regardless of what Xcode might think it is
18
+ attribute :explicit_file_type
19
+
20
+ # [String] the file type guessed by Xcode
21
+ attribute :last_known_file_type
22
+
23
+ # [String] wether of not this file should be indexed. This can be
24
+ # either "0" or "1".
25
+ attribute :include_in_index
26
+
27
+ has_many :build_files, :inverse_of => :file
28
+
29
+ def self.new_static_library(project, product_name)
30
+ new(project, nil,
31
+ "includeInIndex" => "0",
32
+ "sourceTree" => "BUILT_PRODUCTS_DIR",
33
+ "path" => "lib#{product_name}.a"
34
+ )
35
+ end
36
+
37
+ def initialize(*)
38
+ super
39
+ self.path = path if path # sets default name
40
+ self.source_tree ||= 'SOURCE_ROOT'
41
+ self.include_in_index ||= "1"
42
+ set_default_file_type!
43
+ end
44
+
45
+ alias_method :_path=, :path=
46
+ def path=(path)
47
+ self._path = path
48
+ self.name ||= pathname.basename.to_s
49
+ path
50
+ end
51
+
52
+ def pathname
53
+ Pathname.new(path)
54
+ end
55
+
56
+ def set_default_file_type!
57
+ return if explicit_file_type || last_known_file_type
58
+ case path
59
+ when /\.a$/
60
+ self.explicit_file_type = 'archive.ar'
61
+ when /\.framework$/
62
+ self.last_known_file_type = 'wrapper.framework'
63
+ when /\.xcconfig$/
64
+ self.last_known_file_type = 'text.xcconfig'
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,102 @@
1
+ module Xcodeproj
2
+ class Project
3
+ module Object
4
+
5
+ class AbstractGroupEntry < AbstractPBXObject
6
+ has_one :group, :inverse_of => :children
7
+
8
+ def initialize(project, uuid, attributes)
9
+ is_new = uuid.nil?
10
+ super
11
+ # If there's no root_object yet, then this is probably the main group.
12
+ if is_new && @project.root_object
13
+ @project.main_group.children << self
14
+ end
15
+ end
16
+
17
+ def destroy
18
+ group.child_references.delete(uuid)
19
+ super
20
+ end
21
+
22
+ # Sorts groups before files and inside those sorts by name.
23
+ def <=>(other)
24
+ if self.is_a?(PBXGroup) && other.is_a?(PBXFileReference)
25
+ -1
26
+ elsif self.is_a?(PBXFileReference) && other.is_a?(PBXGroup)
27
+ 1
28
+ else
29
+ self.name <=> other.name
30
+ end
31
+ end
32
+ end
33
+
34
+ # @todo The `source_tree` can probably be more than just `<group>`.
35
+ class PBXGroup < AbstractGroupEntry
36
+ # [String] the source tree to which this group is relative. It can be
37
+ # `<group>`.
38
+ attribute :source_tree
39
+
40
+ has_many :children, :class => AbstractGroupEntry do |child|
41
+ # Associating the AbstractGroupEntry instance to this group through
42
+ # the inverse association will also remove it from the group it was
43
+ # in.
44
+ child.group = self
45
+ end
46
+
47
+ def initialize(*)
48
+ super
49
+ self.source_tree ||= '<group>'
50
+ self.child_references ||= []
51
+ end
52
+
53
+ def main_group?
54
+ @project.main_group.uuid == uuid
55
+ end
56
+
57
+ def name
58
+ if name = super
59
+ name
60
+ elsif attributes.has_key?('path')
61
+ File.basename(attributes['path'])
62
+ elsif main_group?
63
+ 'Main Group'
64
+ end
65
+ end
66
+
67
+ def files
68
+ children.list_by_class(PBXFileReference)
69
+ end
70
+
71
+ def create_file(path)
72
+ files.new("path" => path)
73
+ end
74
+
75
+ def create_files(paths)
76
+ paths.map { |path| create_file(path) }
77
+ end
78
+
79
+ def source_files
80
+ children.list_by_class(PBXFileReference) do |list|
81
+ list.let(:uuid_scope) do
82
+ files.reject { |file| file.build_files.empty? }.map(&:uuid)
83
+ end
84
+ end
85
+ end
86
+
87
+ def groups
88
+ children.list_by_class(PBXGroup)
89
+ end
90
+
91
+ def create_group(name)
92
+ groups.new("name" => name)
93
+ end
94
+
95
+ def <<(child)
96
+ children << child
97
+ end
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,158 @@
1
+ module Xcodeproj
2
+ class Project
3
+ module Object
4
+
5
+ class PBXNativeTarget < AbstractPBXObject
6
+ STATIC_LIBRARY = 'com.apple.product-type.library.static'
7
+
8
+ # [String] the name of the build product
9
+ attribute :product_name
10
+
11
+ # [String] the build product type identifier
12
+ attribute :product_type
13
+
14
+ has_many :build_phases
15
+ has_many :dependencies # TODO :class => ?
16
+ has_many :build_rules # TODO :class => ?
17
+ has_one :build_configuration_list, :class => XCConfigurationList
18
+ has_one :product, :uuid => :product_reference
19
+
20
+ def self.new_static_library(project, platform, name)
21
+ project.add_system_framework(platform == :ios ? 'Foundation' : 'Cocoa')
22
+
23
+ target = new(project, nil, 'productType' => STATIC_LIBRARY, 'productName' => name)
24
+ target.product.path = "lib#{name}.a"
25
+
26
+ target.build_configurations.each do |config|
27
+ config.build_settings.merge!(XCBuildConfiguration::COMMON_BUILD_SETTINGS[platform])
28
+
29
+ # E.g. [:ios, :release]
30
+ extra_settings_key = [platform, config.name.downcase.to_sym]
31
+ if extra_settings = XCBuildConfiguration::COMMON_BUILD_SETTINGS[extra_settings_key]
32
+ config.build_settings.merge!(extra_settings)
33
+ end
34
+ end
35
+
36
+ target
37
+ end
38
+
39
+ # You need to specify a product. For a static library you can use
40
+ # PBXFileReference.new_static_library.
41
+ def initialize(project, *)
42
+ super
43
+ self.name ||= product_name
44
+ self.build_rule_references ||= []
45
+ self.dependency_references ||= []
46
+
47
+ unless build_phase_references
48
+ self.build_phase_references = []
49
+
50
+ source_build_phases.new
51
+ copy_files_build_phases.new
52
+ #shell_script_build_phases.new
53
+
54
+ phase = frameworks_build_phases.new
55
+ if frameworks_group = @project.groups.where(:name => 'Frameworks')
56
+ frameworks_group.files.each { |framework| phase << framework }
57
+ end
58
+ end
59
+
60
+ unless build_configuration_list
61
+ self.build_configuration_list = project.objects.add(XCConfigurationList, {
62
+ 'defaultConfigurationIsVisible' => '0',
63
+ 'defaultConfigurationName' => 'Release',
64
+ })
65
+ # TODO or should this happen in buildConfigurationList?
66
+ build_configuration_list.build_configurations.new_debug
67
+ build_configuration_list.build_configurations.new_release
68
+ end
69
+
70
+ unless product
71
+ self.product = @project.files.new_static_library(product_name)
72
+ end
73
+ end
74
+
75
+ alias_method :_product=, :product=
76
+ def product=(product)
77
+ self._product = product
78
+ @project.products << product
79
+ end
80
+
81
+ def build_configurations
82
+ build_configuration_list.build_configurations
83
+ end
84
+
85
+ def build_settings(build_configuration_name)
86
+ build_configuration_list.build_settings(build_configuration_name)
87
+ end
88
+
89
+ def source_build_phases
90
+ build_phases.list_by_class(PBXSourcesBuildPhase)
91
+ end
92
+
93
+ def copy_files_build_phases
94
+ build_phases.list_by_class(PBXCopyFilesBuildPhase)
95
+ end
96
+
97
+ def frameworks_build_phases
98
+ build_phases.list_by_class(PBXFrameworksBuildPhase)
99
+ end
100
+
101
+ def shell_script_build_phases
102
+ build_phases.list_by_class(PBXShellScriptBuildPhase)
103
+ end
104
+
105
+ # Adds source files to the target.
106
+ #
107
+ # @note
108
+ # It finds an existing file reference or creates a new one.
109
+ #
110
+ # @param source_file_descriptions [Array<SourceFileDescription>] The
111
+ # description of the source files to add.
112
+ #
113
+ # @return [Array<PBXFileReference>]
114
+ #
115
+ def add_source_files(source_file_descriptions)
116
+ # Cache the files for performance.
117
+ files = @project.files.to_a
118
+ new_files = []
119
+ source_file_descriptions.each do |source_file_description|
120
+ path = source_file_description.path
121
+ copy_header_phase = source_file_description.copy_header_phase
122
+ compiler_flags = source_file_description.compiler_flags
123
+
124
+ file = (files + new_files).find { |file| file.path == path.to_s } || @project.files.new('path' => path.to_s)
125
+ build_file = file.build_files.new
126
+ if path.extname == '.h'
127
+ build_file.settings = { 'ATTRIBUTES' => ["Public"] }
128
+ # Working around a bug in Xcode 4.2 betas, remove this once the Xcode bug is fixed:
129
+ # https://github.com/alloy/cocoapods/issues/13
130
+ #phase = copy_header_phase || headers_build_phases.first
131
+ phase = copy_header_phase || copy_files_build_phases.first
132
+ phase.build_files << build_file
133
+ else
134
+ build_file.settings = { 'COMPILER_FLAGS' => compiler_flags } if compiler_flags && !compiler_flags.empty?
135
+ source_build_phases.first.build_files << build_file
136
+ end
137
+ new_files << file
138
+ end
139
+ new_files
140
+ end
141
+
142
+ # Struct representing the description needed to add a source file to
143
+ # the target.
144
+ #
145
+ # @!attribute path
146
+ # @return [Pathname] The path of the file.
147
+ #
148
+ # @!attribute compiler_flags
149
+ # @return [String] Any compiler flag.
150
+ #
151
+ # @!attribute copy_header_phase
152
+ # @return [PBXCopyFilesBuildPhase].
153
+ #
154
+ SourceFileDescription = Struct.new(:path, :compiler_flags, :copy_header_phase)
155
+ end
156
+ end
157
+ end
158
+ end