rxcode 0.0.5
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.
- data/Gemfile +17 -0
- data/LICENSE.txt +12 -0
- data/README.md +7 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/rxcode +9 -0
- data/lib/rxcode.rb +17 -0
- data/lib/rxcode/command.rb +179 -0
- data/lib/rxcode/commands.rb +4 -0
- data/lib/rxcode/commands/env.rb +45 -0
- data/lib/rxcode/commands/init.rb +74 -0
- data/lib/rxcode/commands/unwrap.rb +76 -0
- data/lib/rxcode/environment.rb +80 -0
- data/lib/rxcode/macruby.rb +16 -0
- data/lib/rxcode/models.rb +8 -0
- data/lib/rxcode/models/archive.rb +78 -0
- data/lib/rxcode/models/archived_object.rb +62 -0
- data/lib/rxcode/models/build_configuration.rb +19 -0
- data/lib/rxcode/models/build_configuration_list.rb +15 -0
- data/lib/rxcode/models/file_reference.rb +23 -0
- data/lib/rxcode/models/model.rb +66 -0
- data/lib/rxcode/models/project.rb +71 -0
- data/lib/rxcode/models/target.rb +47 -0
- data/lib/rxcode/preferences.rb +32 -0
- data/lib/rxcode/spec/nserror_helpers.rb +19 -0
- data/lib/rxcode/spec/rake_ext.rb +27 -0
- data/lib/rxcode/spec/rake_task.rb +20 -0
- data/lib/rxcode/spec_helper.rb +19 -0
- data/lib/rxcode/tasks.rb +24 -0
- data/lib/rxcode/tasks/bridge_support.rb +39 -0
- data/lib/rxcode/tasks/ios_framework.rb +266 -0
- data/lib/rxcode/tasks/spec.rb +3 -0
- data/lib/rxcode/templates/Gemfile +4 -0
- data/lib/rxcode/templates/Rakefile +4 -0
- data/lib/rxcode/templates/spec/spec_helper.rb +14 -0
- data/lib/rxcode/templates/spec/support/.gitkeep +0 -0
- data/lib/rxcode/workspace.rb +173 -0
- metadata +184 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
#
|
4
|
+
# Represents an XCode environment rooted at a particular path in a filesystem -- typically a project/workspace root
|
5
|
+
# directory.
|
6
|
+
#
|
7
|
+
class Environment
|
8
|
+
|
9
|
+
def initialize(root)
|
10
|
+
@root = root
|
11
|
+
@preferences = Preferences.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# ===== ROOT =======================================================================================================
|
15
|
+
|
16
|
+
attr_reader :root
|
17
|
+
|
18
|
+
def name
|
19
|
+
File.basename(root)
|
20
|
+
end
|
21
|
+
|
22
|
+
# ===== PREFERENCES ================================================================================================
|
23
|
+
|
24
|
+
attr_reader :preferences
|
25
|
+
|
26
|
+
# ===== DERIVED DATA ===============================================================================================
|
27
|
+
|
28
|
+
def global_derived_data_location
|
29
|
+
self.preferences.derived_data_location unless preferences.derived_data_location_is_relative_to_workspace?
|
30
|
+
end
|
31
|
+
|
32
|
+
# ===== WORKSPACE ==================================================================================================
|
33
|
+
|
34
|
+
def workspace
|
35
|
+
@workspace ||=
|
36
|
+
if ws_path = self.workspace_path
|
37
|
+
Workspace.new(ws_path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def workspace_path
|
42
|
+
workspace_paths = Dir[File.join(self.root, '*.xcworkspace')]
|
43
|
+
preferred_workspace_path = File.join(root, "#{name}.xcworkspace")
|
44
|
+
|
45
|
+
if workspace_paths.include?(preferred_workspace_path)
|
46
|
+
|
47
|
+
preferred_workspace_path
|
48
|
+
|
49
|
+
elsif workspace_paths.length == 1
|
50
|
+
|
51
|
+
workspace_paths.first
|
52
|
+
|
53
|
+
else
|
54
|
+
project_paths = Dir[File.join(self.root, '*.xcodeproj')]
|
55
|
+
preferred_project_path = File.join(root, "#{name}.xcodeproj")
|
56
|
+
|
57
|
+
project_path =
|
58
|
+
if project_paths.include?(preferred_project_path)
|
59
|
+
preferred_project_path
|
60
|
+
elsif project_paths.length == 1
|
61
|
+
project_paths.first
|
62
|
+
end
|
63
|
+
|
64
|
+
if project_path
|
65
|
+
project_workspace_path = File.join(project_path, 'project.xcworkspace')
|
66
|
+
if RXCode::Workspace.is_workspace_at_path?(project_workspace_path)
|
67
|
+
project_workspace_path
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.env
|
77
|
+
@env ||= Environment.new(Dir.pwd)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
def self.framework(framework_name)
|
4
|
+
if workspace = RXCode.env.workspace
|
5
|
+
|
6
|
+
framework_path = File.join(workspace.built_products_dir, 'Debug', "#{framework_name}.framework")
|
7
|
+
::Kernel.framework(framework_path)
|
8
|
+
|
9
|
+
else
|
10
|
+
|
11
|
+
raise "Unable to determine current XCode workspace."
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rxcode/models/archive'
|
2
|
+
require 'rxcode/models/archived_object'
|
3
|
+
require 'rxcode/models/model'
|
4
|
+
require 'rxcode/models/project'
|
5
|
+
require 'rxcode/models/target'
|
6
|
+
require 'rxcode/models/file_reference'
|
7
|
+
require 'rxcode/models/build_configuration'
|
8
|
+
require 'rxcode/models/build_configuration_list'
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
#
|
4
|
+
# Processes an NSKeyedArchive file into a set of Ruby objects
|
5
|
+
#
|
6
|
+
class Archive
|
7
|
+
|
8
|
+
def initialize(archive_path_or_hash, &object_mapper)
|
9
|
+
if archive_path_or_hash.is_a?(String)
|
10
|
+
|
11
|
+
if File.exist?(archive_path_or_hash)
|
12
|
+
@archive_path = archive_path_or_hash
|
13
|
+
@archive_hash = Plist::parse_xml(`plutil -convert xml1 -o - '#{archive_path_or_hash}'`)
|
14
|
+
else
|
15
|
+
@archive_hash = Plist::parse_xml(archive_path_or_hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
elsif archive_path_or_hash.is_a?(Hash)
|
19
|
+
|
20
|
+
@archive_hash = archive_path_or_hash
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
@objects = {}
|
25
|
+
@object_mapper = object_mapper
|
26
|
+
end
|
27
|
+
|
28
|
+
# ===== ARCHIVE PATH ===============================================================================================
|
29
|
+
|
30
|
+
attr_reader :archive_path
|
31
|
+
|
32
|
+
attr_reader :archive_hash
|
33
|
+
|
34
|
+
attr_accessor :object_mapper
|
35
|
+
|
36
|
+
# ===== ROOT OBJECT ================================================================================================
|
37
|
+
|
38
|
+
def root_object_archive_id
|
39
|
+
@archive_hash['rootObject']
|
40
|
+
end
|
41
|
+
|
42
|
+
def root_object
|
43
|
+
object_with_id(root_object_archive_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
# ===== OBJECTS ====================================================================================================
|
47
|
+
|
48
|
+
def object_with_id(object_id)
|
49
|
+
@objects[object_id] ||=
|
50
|
+
if object_hashes[object_id]
|
51
|
+
ArchivedObject.new(self, object_id)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def model_object_with_id(object_id)
|
56
|
+
if o = object_with_id(object_id)
|
57
|
+
o.model_object
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def object_hashes
|
62
|
+
archive_hash['objects']
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.archive_at_path(archive_path)
|
66
|
+
self.new(archive_path)
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Returns the object archived in the file identified by +archive_path+.
|
71
|
+
#
|
72
|
+
def self.object_at_path(archive_path)
|
73
|
+
archive_at_path(archive_path).root_object
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class ArchivedObject
|
4
|
+
|
5
|
+
def initialize(archive, archived_object_id)
|
6
|
+
@archive = archive
|
7
|
+
@archived_object_id = archived_object_id
|
8
|
+
end
|
9
|
+
|
10
|
+
# ===== ARCHIVE ====================================================================================================
|
11
|
+
|
12
|
+
attr_reader :archive
|
13
|
+
|
14
|
+
# ===== ARCHIVE OBJECT ID ==========================================================================================
|
15
|
+
|
16
|
+
attr_reader :archived_object_id
|
17
|
+
|
18
|
+
# ===== DATA =======================================================================================================
|
19
|
+
|
20
|
+
def data
|
21
|
+
@data ||= archive.object_hashes[self.archived_object_id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
data[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_key?(key)
|
29
|
+
data.has_key?(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
def object_for_key(key)
|
33
|
+
object_id = self[key]
|
34
|
+
archive.object_with_id(object_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def array_of_objects_for_key(key)
|
38
|
+
self[key].map { |object_id| archive.object_with_id(object_id) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def model_object_for_key(key)
|
42
|
+
if o = object_for_key(key)
|
43
|
+
o.model_object
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def array_of_model_objects_for_key(key)
|
48
|
+
array_of_objects_for_key(key).map { |o| o.model_object }
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_accessor :model_object
|
52
|
+
|
53
|
+
def model_object
|
54
|
+
@model_object ||=
|
55
|
+
if archive.object_mapper
|
56
|
+
archive.object_mapper.call(self)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class BuildConfiguration < Model
|
4
|
+
|
5
|
+
# ===== NAME =======================================================================================================
|
6
|
+
|
7
|
+
def name
|
8
|
+
archive_object['name']
|
9
|
+
end
|
10
|
+
|
11
|
+
# ===== BUILD SETTINGS =============================================================================================
|
12
|
+
|
13
|
+
def build_settings
|
14
|
+
archive_object['buildSettings']
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class BuildConfigurationList < Model
|
4
|
+
|
5
|
+
def default_configuration_name
|
6
|
+
archive_object['defaultConfigurationName']
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_configurations
|
10
|
+
archive_object.array_of_model_objects_for_key('buildConfigurations')
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class FileReference < Model
|
4
|
+
|
5
|
+
def name
|
6
|
+
archive_object['name']
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
archive_object['path']
|
11
|
+
end
|
12
|
+
|
13
|
+
def source_tree
|
14
|
+
archive_object['sourceTree']
|
15
|
+
end
|
16
|
+
|
17
|
+
def last_known_file_type
|
18
|
+
archive_object['lastKnownFileType']
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class Model
|
4
|
+
|
5
|
+
def initialize(source)
|
6
|
+
case source
|
7
|
+
when ArchivedObject, NilClass
|
8
|
+
@archive_object = source
|
9
|
+
when Archive
|
10
|
+
@archive_object = source.root_object
|
11
|
+
when String, Hash
|
12
|
+
archive = Archive.new(source)
|
13
|
+
@archive_object = archive.rootObject
|
14
|
+
else
|
15
|
+
raise "Unable to initialize #{self.class.name} from #{source.class.name}: #{source.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
if @archive_object
|
19
|
+
@archive_object.model_object = self
|
20
|
+
@archive_object.archive.object_mapper ||=
|
21
|
+
Proc.new { |archived_object| self.class.map_archived_object(archived_object) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# ===== ARCHIVE ====================================================================================================
|
26
|
+
|
27
|
+
attr_reader :archive_object
|
28
|
+
|
29
|
+
def archive
|
30
|
+
archive_object.archive
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.class_for_archived_object_type(type)
|
34
|
+
case type
|
35
|
+
when "PBXProject"
|
36
|
+
Project
|
37
|
+
when "PBXFileReference"
|
38
|
+
FileReference
|
39
|
+
when "PBXNativeTarget"
|
40
|
+
Target
|
41
|
+
when "XCConfigurationList"
|
42
|
+
BuildConfigurationList
|
43
|
+
when "XCBuildConfiguration"
|
44
|
+
BuildConfiguration
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.map_archived_object(archived_object)
|
49
|
+
if klass = class_for_archived_object_type(archived_object['isa'])
|
50
|
+
klass.new(archived_object)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.object_at_path(archive_path)
|
55
|
+
Archive.new(archive_path).rootObject.model_object
|
56
|
+
end
|
57
|
+
|
58
|
+
# ===== ROOT =======================================================================================================
|
59
|
+
|
60
|
+
def root
|
61
|
+
self.archive.root_object.model_object
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module RXCode
|
2
|
+
|
3
|
+
class Project < Model
|
4
|
+
|
5
|
+
def initialize(path, options = nil)
|
6
|
+
raise "#{path.inspect} is not a valid XCode project path" unless self.class.is_project_at_path?(path)
|
7
|
+
|
8
|
+
super nil
|
9
|
+
|
10
|
+
@path = path
|
11
|
+
|
12
|
+
if options && options[:workspace]
|
13
|
+
@workspace = options[:workspace]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# ===== WORKSPACE ==================================================================================================
|
18
|
+
|
19
|
+
attr_reader :workspace
|
20
|
+
|
21
|
+
# ===== PROJECT DISCOVERY & LOOKUP =================================================================================
|
22
|
+
|
23
|
+
XCODE_PROJECT_EXTENSION = '.xcodeproj'.freeze
|
24
|
+
|
25
|
+
#
|
26
|
+
# Determines if the provided file path is an XCode project
|
27
|
+
#
|
28
|
+
def self.is_project_at_path?(project_path)
|
29
|
+
File.directory?(project_path) && File.extname(project_path) == XCODE_PROJECT_EXTENSION
|
30
|
+
end
|
31
|
+
|
32
|
+
# ===== PROJECT PATH ===============================================================================================
|
33
|
+
|
34
|
+
attr_reader :path
|
35
|
+
|
36
|
+
def project_archive_path
|
37
|
+
File.join(self.path, 'project.pbxproj')
|
38
|
+
end
|
39
|
+
|
40
|
+
def archive
|
41
|
+
@archive ||=
|
42
|
+
begin
|
43
|
+
a = Archive.new(project_archive_path) { |archived_object| Model.map_archived_object(archived_object) }
|
44
|
+
a.root_object.model_object = self
|
45
|
+
a
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def archive_object
|
50
|
+
archive.root_object
|
51
|
+
end
|
52
|
+
|
53
|
+
# ===== TARGETS ====================================================================================================
|
54
|
+
|
55
|
+
def targets
|
56
|
+
archive_object.array_of_model_objects_for_key('targets')
|
57
|
+
end
|
58
|
+
|
59
|
+
def target_names
|
60
|
+
targets.map(&:name)
|
61
|
+
end
|
62
|
+
|
63
|
+
# ===== BUILD CONFIGURATIONS =======================================================================================
|
64
|
+
|
65
|
+
def build_configuration_list
|
66
|
+
archive_object.model_object_for_key('buildConfigurationList')
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|