xcodeproject 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +14 -0
- data/lib/xcodeproject/build_phase_node.rb +87 -0
- data/lib/xcodeproject/data.rb +87 -0
- data/lib/xcodeproject/exceptions.rb +5 -0
- data/lib/xcodeproject/extend/array.rb +8 -0
- data/lib/xcodeproject/extend/hash.rb +11 -0
- data/lib/xcodeproject/extend/string.rb +7 -0
- data/lib/xcodeproject/file_node.rb +63 -0
- data/lib/xcodeproject/formatter.rb +23 -0
- data/lib/xcodeproject/node.rb +15 -0
- data/lib/xcodeproject/pbx_build_file.rb +37 -0
- data/lib/xcodeproject/pbx_file_reference.rb +53 -0
- data/lib/xcodeproject/pbx_group.rb +169 -0
- data/lib/xcodeproject/pbx_native_target.rb +70 -0
- data/lib/xcodeproject/pbx_project.rb +33 -0
- data/lib/xcodeproject/project.rb +70 -0
- data/lib/xcodeproject/resources/example/dir1a/dir2a/dir3a/dir4a/file5a-a.h +1 -0
- data/lib/xcodeproject/resources/example/dir1a/dir2a/dir3a/dir4a/file5a-a.m +1 -0
- data/lib/xcodeproject/resources/example/dir1a/dir2a/dir3a/dir4a/file5a-r.h +1 -0
- data/lib/xcodeproject/resources/example/dir1a/dir2a/dir3a/dir4a/file5a-r.m +1 -0
- data/lib/xcodeproject/resources/example/dir1b/dir2b/file3b.m +0 -0
- data/lib/xcodeproject/resources/example/dir1b/file2b.m +0 -0
- data/lib/xcodeproject/resources/example/dir1c/file2c.h +0 -0
- data/lib/xcodeproject/resources/example/dir1c/file2c.m +0 -0
- data/lib/xcodeproject/resources/example/example/AppDelegate.h +15 -0
- data/lib/xcodeproject/resources/example/example/AppDelegate.m +57 -0
- data/lib/xcodeproject/resources/example/example/en.lproj/InfoPlist.strings +2 -0
- data/lib/xcodeproject/resources/example/example/example-Info.plist +45 -0
- data/lib/xcodeproject/resources/example/example/example-Prefix.pch +14 -0
- data/lib/xcodeproject/resources/example/example/main.m +18 -0
- data/lib/xcodeproject/resources/example/example.xcodeproj/project.pbxproj +324 -0
- data/lib/xcodeproject/root_node.rb +117 -0
- data/lib/xcodeproject/spec/build_phase_node_spec.rb +95 -0
- data/lib/xcodeproject/spec/file_node_spec.rb +83 -0
- data/lib/xcodeproject/spec/pbx_build_file_spec.rb +25 -0
- data/lib/xcodeproject/spec/pbx_file_reference_spec.rb +34 -0
- data/lib/xcodeproject/spec/pbx_group_spec.rb +274 -0
- data/lib/xcodeproject/spec/pbx_native_target_spec.rb +58 -0
- data/lib/xcodeproject/spec/pbx_project_spec.rb +34 -0
- data/lib/xcodeproject/spec/project_spec.rb +79 -0
- data/lib/xcodeproject/spec/spec_helper.rb +45 -0
- data/lib/xcodeproject/spec/xc_configuration_list_spec.rb +20 -0
- data/lib/xcodeproject/uuid_generator.rb +13 -0
- data/lib/xcodeproject/version.rb +3 -0
- data/lib/xcodeproject/xc_build_configuration.rb +15 -0
- data/lib/xcodeproject/xc_configuration_list.rb +23 -0
- data/lib/xcodeproject.rb +3 -0
- data/rakefile +3 -0
- data/xcodeproject.gemspec +26 -0
- metadata +166 -0
data/.gitignore
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# OSX
|
2
|
+
.DS_Store
|
3
|
+
._*
|
4
|
+
.Spotlight-V100
|
5
|
+
.Trashes
|
6
|
+
|
7
|
+
# .gitignore
|
8
|
+
.gitignore
|
9
|
+
|
10
|
+
# vim
|
11
|
+
.*.sw[a-z]
|
12
|
+
*.un~
|
13
|
+
Session.vim
|
14
|
+
|
15
|
+
# ruby
|
16
|
+
*.gem
|
17
|
+
*.rbc
|
18
|
+
.bundle
|
19
|
+
.config
|
20
|
+
.yardoc
|
21
|
+
Gemfile.lock
|
22
|
+
InstalledFiles
|
23
|
+
_yardoc
|
24
|
+
coverage
|
25
|
+
doc/
|
26
|
+
lib/bundler/man
|
27
|
+
pkg
|
28
|
+
rdoc
|
29
|
+
spec/reports
|
30
|
+
test/tmp
|
31
|
+
test/version_tmp
|
32
|
+
tmp
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Andrey Nesterov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
XCodeProject
|
2
|
+
===
|
3
|
+
Ruby API for working with Xcode project files
|
4
|
+
|
5
|
+
Installation
|
6
|
+
---
|
7
|
+
`gem install xcodeproject`
|
8
|
+
|
9
|
+
License
|
10
|
+
---
|
11
|
+
XCodeProject is provided under the terms of the [the MIT license][license]
|
12
|
+
|
13
|
+
[license]:http://www.opensource.org/licenses/MIT
|
14
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'xcodeproject/node'
|
2
|
+
require 'xcodeproject/pbx_build_file'
|
3
|
+
|
4
|
+
module XCodeProject
|
5
|
+
class BuildPhaseNode < Node
|
6
|
+
def initialize (root, uuid, data)
|
7
|
+
super(root, uuid, data)
|
8
|
+
@files = data['files']
|
9
|
+
end
|
10
|
+
|
11
|
+
def files
|
12
|
+
build_files.map {|obj| obj.file_ref }
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_file (file_obj)
|
16
|
+
case file_obj
|
17
|
+
when PBXFileReference
|
18
|
+
add_build_file(file_obj.uuid)
|
19
|
+
when PBXBuildFile
|
20
|
+
add_build_file_uuid(file_obj.uuid)
|
21
|
+
else
|
22
|
+
raise ArgumentError.new("Wrong argument type, expected the PBXFileReference or PBXBuildFile.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_file (file_obj)
|
27
|
+
case file_obj
|
28
|
+
when PBXFileReference
|
29
|
+
remove_build_file(file_obj.uuid)
|
30
|
+
when PBXBuildFile
|
31
|
+
remove_build_file_uuid(file_obj.uuid)
|
32
|
+
else
|
33
|
+
raise ArgumentError.new("Wrong argument type, expected the PBXFileReference or PBXBuildFile.")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def doctor
|
38
|
+
@files.each do |uuid|
|
39
|
+
obj = root.object(uuid)
|
40
|
+
if obj.nil?
|
41
|
+
remove_build_file_uuid(uuid)
|
42
|
+
puts "removed #{uuid}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def build_files
|
50
|
+
@files.map {|uuid| root.object!(uuid) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_file (file_ref_uuid)
|
54
|
+
build_files.select {|obj| obj.file_ref.uuid == file_ref_uuid }.first
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_build_file (file_ref_uuid)
|
58
|
+
obj = build_file(file_ref_uuid)
|
59
|
+
if obj.nil?
|
60
|
+
obj = PBXBuildFile.add(root, file_ref_uuid)
|
61
|
+
add_build_file_uuid(obj.uuid)
|
62
|
+
end
|
63
|
+
obj
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_build_file (file_ref_uuid)
|
67
|
+
obj = build_file(file_ref_uuid)
|
68
|
+
remove_build_file_uuid(obj.uuid) unless obj.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_build_file_uuid (build_file_uuid)
|
72
|
+
@files << build_file_uuid unless @files.include?(build_file_uuid)
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_build_file_uuid (build_file_uuid)
|
76
|
+
@files.delete(build_file_uuid)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class PBXSourcesBuildPhase < BuildPhaseNode; end
|
81
|
+
class PBXHeadersBuildPhase < BuildPhaseNode; end
|
82
|
+
class PBXResourcesBuildPhase < BuildPhaseNode; end
|
83
|
+
class PBXFrameworksBuildPhase < BuildPhaseNode; end
|
84
|
+
class PBXAppleScriptBuildPhase < BuildPhaseNode; end
|
85
|
+
class PBXShellScriptBuildPhase < BuildPhaseNode; end
|
86
|
+
class PBXCopyFilesBuildPhase < BuildPhaseNode; end
|
87
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2012 by Andrey Nesterov (ae.nesterov@gmail.com)
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to
|
6
|
+
# deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
8
|
+
# sell copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
19
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
20
|
+
# IN THE SOFTWARE.
|
21
|
+
#++
|
22
|
+
|
23
|
+
require 'xcodeproject/root_node'
|
24
|
+
|
25
|
+
module XCodeProject
|
26
|
+
class Data
|
27
|
+
def initialize (data, wd)
|
28
|
+
@root = RootNode.new(data, wd)
|
29
|
+
end
|
30
|
+
|
31
|
+
def project
|
32
|
+
@root.project
|
33
|
+
end
|
34
|
+
|
35
|
+
def targets
|
36
|
+
project.targets
|
37
|
+
end
|
38
|
+
|
39
|
+
def target (name)
|
40
|
+
project.target(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def main_group
|
44
|
+
project.main_group
|
45
|
+
end
|
46
|
+
|
47
|
+
def group (gpath)
|
48
|
+
main_group.group(gpath)
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_group (gpath)
|
52
|
+
main_group.add_group(gpath)
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_dir(parent_gpath, path)
|
56
|
+
main_group.add_group(parent_gpath).add_dir(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_group (gpath)
|
60
|
+
main_group.remove_group(gpath)
|
61
|
+
end
|
62
|
+
|
63
|
+
def file (gpath)
|
64
|
+
main_group.file(gpath)
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_file (parent_gpath, path)
|
68
|
+
main_group.add_group(parent_gpath).add_file(path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove_file (gpath)
|
72
|
+
main_group.remove_file(gpath)
|
73
|
+
end
|
74
|
+
|
75
|
+
def doctor
|
76
|
+
targets.each {|target| target.doctor }
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_plist (fmtr = Formatter.new)
|
80
|
+
@root.to_plist
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
attr_accessor :root
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'xcodeproject/formatter'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def to_plist (fmtr = XCodeProject::Formatter.new)
|
5
|
+
fmtr.inc
|
6
|
+
items = map { |key, value| "#{key.to_plist(fmtr)} = #{value.to_plist(fmtr)};" }
|
7
|
+
fmtr.dec
|
8
|
+
|
9
|
+
%{{#{fmtr.t2}#{items.join("#{fmtr.t2}")}#{fmtr.t1}}}
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'xcodeproject/node'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module XCodeProject
|
5
|
+
class FileNode < Node
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :path
|
8
|
+
attr_reader :source_tree
|
9
|
+
|
10
|
+
def initialize (root, uuid, data)
|
11
|
+
super(root, uuid, data)
|
12
|
+
|
13
|
+
@source_tree = data['sourceTree']
|
14
|
+
@name ||= data['name']
|
15
|
+
@path ||= data['path']
|
16
|
+
|
17
|
+
@name ||= File.basename(@path) unless @path.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def source_tree
|
21
|
+
SourceTreeMap[@source_tree]
|
22
|
+
end
|
23
|
+
|
24
|
+
def parent
|
25
|
+
root.select_objects do |uuid, data|
|
26
|
+
(data['children'].include?(self.uuid) if data['isa'] == 'PBXGroup') ? true : false
|
27
|
+
end.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def group_path
|
31
|
+
obj = self
|
32
|
+
res = ''
|
33
|
+
begin
|
34
|
+
pn = obj.name ? obj.name : ''
|
35
|
+
res = Pathname.new(pn).join(res)
|
36
|
+
end while obj = obj.parent;
|
37
|
+
res.cleanpath
|
38
|
+
end
|
39
|
+
|
40
|
+
def total_path
|
41
|
+
res = ''
|
42
|
+
case source_tree
|
43
|
+
when :source_root
|
44
|
+
res = path
|
45
|
+
when :group
|
46
|
+
pn = path.nil? ? '' : path
|
47
|
+
res = parent.total_path.join(pn) unless parent.nil?
|
48
|
+
else
|
49
|
+
raise ParseError.new("No such '#{source_tree}' source tree type.")
|
50
|
+
end
|
51
|
+
root.absolute_path(res)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
SourceTreeMap = {
|
57
|
+
'SOURCE_ROOT' => :source_root,
|
58
|
+
'<group>' => :group
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module XCodeProject
|
2
|
+
class Formatter
|
3
|
+
def initialize
|
4
|
+
@counter = 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def inc
|
8
|
+
@counter += 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def dec
|
12
|
+
@counter -= 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def t1
|
16
|
+
"\n" + "\t" * @counter
|
17
|
+
end
|
18
|
+
|
19
|
+
def t2
|
20
|
+
"\n" + "\t" * (@counter + 1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module XCodeProject
|
2
|
+
class Node
|
3
|
+
attr_reader :uuid
|
4
|
+
attr_reader :isa
|
5
|
+
|
6
|
+
def initialize (root, uuid, data)
|
7
|
+
@root, @uuid, @data = root, uuid, data
|
8
|
+
@isa = data['isa']
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
attr_accessor :root
|
13
|
+
attr_accessor :data
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'xcodeproject/node'
|
2
|
+
|
3
|
+
module XCodeProject
|
4
|
+
class PBXBuildFile < Node
|
5
|
+
attr_reader :file_ref
|
6
|
+
|
7
|
+
def initialize (root, uuid, data)
|
8
|
+
super(root, uuid, data)
|
9
|
+
|
10
|
+
@file_ref = data['fileRef']
|
11
|
+
end
|
12
|
+
|
13
|
+
def file_ref
|
14
|
+
root.object!(@file_ref)
|
15
|
+
end
|
16
|
+
|
17
|
+
def remove!
|
18
|
+
root.project.targets.each {|target| target.remove_source(self) }
|
19
|
+
root.remove_object(uuid)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add(root, file_ref_uuid)
|
23
|
+
uuid, data = root.add_object(self.create_object_hash(file_ref_uuid))
|
24
|
+
self.new(root, uuid, data)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def self.create_object_hash (file_ref_uuid)
|
30
|
+
data = []
|
31
|
+
data << ['isa', 'PBXBuildFile']
|
32
|
+
data << ['fileRef', file_ref_uuid]
|
33
|
+
|
34
|
+
Hash[ data ]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'xcodeproject/file_node'
|
2
|
+
require 'xcodeproject/exceptions'
|
3
|
+
|
4
|
+
module XCodeProject
|
5
|
+
class PBXFileReference < FileNode
|
6
|
+
def initialize (root, uuid, data)
|
7
|
+
super(root, uuid, data)
|
8
|
+
end
|
9
|
+
|
10
|
+
def remove!
|
11
|
+
root.build_files(uuid).each do |build_file_obj|
|
12
|
+
build_file_obj.remove!
|
13
|
+
end
|
14
|
+
|
15
|
+
parent.remove_child_uuid(uuid)
|
16
|
+
root.remove_object(uuid)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.add(root, path)
|
20
|
+
uuid, data = root.add_object(self.create_object_hash(path))
|
21
|
+
self.new(root, uuid, data)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def self.create_object_hash (path)
|
27
|
+
path = path.to_s
|
28
|
+
name = File.basename(path)
|
29
|
+
ext = File.extname(path)
|
30
|
+
raise ParseError.new("No such file type '#{name}'.") if !FileTypeMap.include?(ext)
|
31
|
+
|
32
|
+
data = []
|
33
|
+
data << ['isa', 'PBXFileReference']
|
34
|
+
data << ['sourceTree', '<group>']
|
35
|
+
data << ['fileEncoding', '4'] # utf-8
|
36
|
+
data << ['lastKnownFileType', FileTypeMap[ext]]
|
37
|
+
data << ['path', path]
|
38
|
+
data << ['name', name] if name != path
|
39
|
+
|
40
|
+
Hash[ data ]
|
41
|
+
end
|
42
|
+
|
43
|
+
FileTypeMap = {
|
44
|
+
'.h' => 'sourcecode.c.h',
|
45
|
+
'.c' => 'sourcecode.c.c',
|
46
|
+
'.m' => 'sourcecode.c.objc',
|
47
|
+
'.mm' => 'sourcecode.cpp.objcpp',
|
48
|
+
'.hpp' => 'sourcecode.cpp.h',
|
49
|
+
'.cpp' => 'sourcecode.cpp.cpp',
|
50
|
+
'.cc' => 'sourcecode.cpp.cpp'
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'xcodeproject/pbx_file_reference'
|
2
|
+
require 'xcodeproject/exceptions'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module XCodeProject
|
6
|
+
class PBXGroup < FileNode
|
7
|
+
def initialize (root, uuid, data)
|
8
|
+
super(root, uuid, data)
|
9
|
+
@children = data['children']
|
10
|
+
end
|
11
|
+
|
12
|
+
def children
|
13
|
+
@children.map {|uuid| root.object!(uuid)}
|
14
|
+
end
|
15
|
+
|
16
|
+
def child (gpath)
|
17
|
+
gpath = Pathname.new(gpath).cleanpath
|
18
|
+
|
19
|
+
if gpath == gpath.basename
|
20
|
+
name = gpath.to_s
|
21
|
+
case name
|
22
|
+
when '.'
|
23
|
+
self
|
24
|
+
when '..'
|
25
|
+
parent
|
26
|
+
else
|
27
|
+
chs = children.select {|obj| obj.name == name }
|
28
|
+
raise GroupPathError.new("The group contains two children with the same name.") if chs.size > 1
|
29
|
+
chs.first
|
30
|
+
end
|
31
|
+
else
|
32
|
+
pn, name = gpath.split
|
33
|
+
group = child(pn)
|
34
|
+
group.child(name) if group.is_a?(PBXGroup)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def file_ref (gpath)
|
39
|
+
obj = child(gpath)
|
40
|
+
obj.is_a?(PBXFileReference) ? obj : nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def group?
|
44
|
+
data['path'].nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def dir?
|
48
|
+
not group?
|
49
|
+
end
|
50
|
+
|
51
|
+
def group (gpath)
|
52
|
+
obj = child(gpath)
|
53
|
+
obj.is_a?(PBXGroup) ? obj : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_group (gpath)
|
57
|
+
create_group(gpath)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_dir (path, gpath = nil)
|
61
|
+
path = absolute_path(path)
|
62
|
+
raise FilePathError.new("No such directory '#{path}'.") unless path.exist?
|
63
|
+
|
64
|
+
gpath ||= path.basename
|
65
|
+
parent = create_group(gpath, path)
|
66
|
+
|
67
|
+
chs = path.entries.select {|obj| obj.to_s =~ /\A\./ ? false : true }
|
68
|
+
chs.each do |pn|
|
69
|
+
parent.absolute_path(pn).directory? ? parent.add_dir(pn) : parent.add_file(pn)
|
70
|
+
end
|
71
|
+
parent
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_group (gpath, path = nil)
|
75
|
+
gpath = Pathname.new(gpath).cleanpath
|
76
|
+
|
77
|
+
if gpath == gpath.basename
|
78
|
+
name = gpath.to_s
|
79
|
+
case name
|
80
|
+
when '.'
|
81
|
+
self
|
82
|
+
when '..'
|
83
|
+
parent
|
84
|
+
else
|
85
|
+
obj = group(name)
|
86
|
+
if obj.nil?
|
87
|
+
path = relative_path(path) unless path.nil?
|
88
|
+
obj = PBXGroup.add(root, name, path)
|
89
|
+
add_child_uuid(obj.uuid)
|
90
|
+
end
|
91
|
+
obj
|
92
|
+
end
|
93
|
+
else
|
94
|
+
pn, name = gpath.split
|
95
|
+
create_group(pn).create_group(name)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_child_uuid (uuid)
|
100
|
+
@children << uuid
|
101
|
+
end
|
102
|
+
|
103
|
+
def remove_child_uuid (uuid)
|
104
|
+
@children.delete(uuid)
|
105
|
+
end
|
106
|
+
|
107
|
+
def absolute_path (path)
|
108
|
+
path = Pathname.new(path)
|
109
|
+
path.absolute? ? path : root.absolute_path(total_path.join(path))
|
110
|
+
end
|
111
|
+
|
112
|
+
def relative_path (path)
|
113
|
+
path = Pathname.new(path)
|
114
|
+
path.relative? ? path : path.relative_path_from(total_path)
|
115
|
+
end
|
116
|
+
|
117
|
+
def remove_group (gpath)
|
118
|
+
obj = group(gpath)
|
119
|
+
obj.remove! unless obj.nil?
|
120
|
+
end
|
121
|
+
|
122
|
+
def remove!
|
123
|
+
return if parent.nil?
|
124
|
+
|
125
|
+
children.each do |obj|
|
126
|
+
obj.remove!
|
127
|
+
end
|
128
|
+
|
129
|
+
parent.remove_child_uuid(uuid)
|
130
|
+
root.remove_object(uuid)
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_file_ref (path)
|
134
|
+
raise FilePathError.new("No such file '#{absolute_path(path)}'.") unless absolute_path(path).exist?
|
135
|
+
|
136
|
+
name = File.basename(path)
|
137
|
+
obj = file_ref(name)
|
138
|
+
if obj.nil?
|
139
|
+
obj = PBXFileReference.add(root, relative_path(path))
|
140
|
+
add_child_uuid(obj.uuid)
|
141
|
+
end
|
142
|
+
obj
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.add(root, name, path = nil)
|
146
|
+
uuid, data = root.add_object(self.create_object_hash(name, path))
|
147
|
+
PBXGroup.new(root, uuid, data)
|
148
|
+
end
|
149
|
+
|
150
|
+
alias :file :file_ref
|
151
|
+
alias :add_file :add_file_ref
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def self.create_object_hash (name, path = nil)
|
156
|
+
path = path.to_s
|
157
|
+
|
158
|
+
data = []
|
159
|
+
data << ['isa', 'PBXGroup']
|
160
|
+
data << ['children', []]
|
161
|
+
data << ['name', name]
|
162
|
+
data << ['path', path] unless path.empty?
|
163
|
+
data << ['sourceTree', '<group>']
|
164
|
+
|
165
|
+
Hash[ data ]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|