Class: Mysigner::Build::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/mysigner/build/parser.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_info) ⇒ Parser

Returns a new instance of Parser.



8
9
10
11
# File 'lib/mysigner/build/parser.rb', line 8

def initialize(project_info)
  @project_info = project_info
  @project = open_project
end

Instance Attribute Details

#projectObject (readonly)

Returns the value of attribute project.



6
7
8
# File 'lib/mysigner/build/parser.rb', line 6

def project
  @project
end

#project_infoObject (readonly)

Returns the value of attribute project_info.



6
7
8
# File 'lib/mysigner/build/parser.rb', line 6

def project_info
  @project_info
end

Instance Method Details

#all_app_targetsObject

Get all app + extension targets (everything that needs signing)



41
42
43
# File 'lib/mysigner/build/parser.rb', line 41

def all_app_targets
  app_targets + extension_targets
end

#app_targetsObject

Get all application targets (main apps only, no extensions)



19
20
21
22
23
# File 'lib/mysigner/build/parser.rb', line 19

def app_targets
  @project.targets.select do |target|
    target.product_type == 'com.apple.product-type.application'
  end
end

#build_settings(target_name = nil, configuration = 'Release') ⇒ Object

Get build settings for a target and configuration



115
116
117
118
119
120
121
122
# File 'lib/mysigner/build/parser.rb', line 115

def build_settings(target_name = nil, configuration = 'Release')
  target = find_target(target_name)
  config = target.build_configurations.find { |c| c.name == configuration }

  raise "Configuration '#{configuration}' not found" unless config

  config.build_settings
end

#bundle_id(target_name = nil, configuration = 'Release') ⇒ Object

Get bundle identifier



125
126
127
128
# File 'lib/mysigner/build/parser.rb', line 125

def bundle_id(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['PRODUCT_BUNDLE_IDENTIFIER']
end

#code_sign_identity(target_name = nil, configuration = 'Release') ⇒ Object

Get code sign identity



137
138
139
140
# File 'lib/mysigner/build/parser.rb', line 137

def code_sign_identity(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['CODE_SIGN_IDENTITY']
end

#code_sign_style(target_name = nil, configuration = 'Release') ⇒ Object

Get code sign style (Automatic or Manual)



149
150
151
152
# File 'lib/mysigner/build/parser.rb', line 149

def code_sign_style(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['CODE_SIGN_STYLE']
end

#configurations(target_name = nil) ⇒ Object

Get all configurations



155
156
157
158
# File 'lib/mysigner/build/parser.rb', line 155

def configurations(target_name = nil)
  target = find_target(target_name)
  target.build_configurations.map(&:name)
end

#extension_targetsObject

Get all extension targets (widgets, share extensions, etc.)



32
33
34
35
36
37
38
# File 'lib/mysigner/build/parser.rb', line 32

def extension_targets
  @project.targets.select do |target|
    target.product_type&.include?('app-extension') ||
      target.product_type&.include?('widget-extension') ||
      target.product_type == 'com.apple.product-type.watchkit2-extension'
  end
end

#find_target(target_name) ⇒ Object

Find a target by name (public method for use by other classes)



175
176
177
178
179
180
181
182
# File 'lib/mysigner/build/parser.rb', line 175

def find_target(target_name)
  return main_target if target_name.nil?

  target = @project.targets.find { |t| t.name == target_name }
  raise "Target '#{target_name}' not found" unless target

  target
end

#has_extensions?Boolean

Check if project has extensions

Returns:

  • (Boolean)


46
47
48
# File 'lib/mysigner/build/parser.rb', line 46

def has_extensions?
  extension_targets.any?
end

#has_multiple_apps?Boolean

Check if project has multiple apps

Returns:

  • (Boolean)


51
52
53
# File 'lib/mysigner/build/parser.rb', line 51

def has_multiple_apps?
  app_targets.count > 1
end

#main_targetObject

Get main app target (exclude test targets, extensions, etc.)



26
27
28
29
# File 'lib/mysigner/build/parser.rb', line 26

def main_target
  # Return first app target, or first target if no app targets found
  app_targets.first || @project.targets.first
end

#open_projectObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/mysigner/build/parser.rb', line 184

def open_project
  require 'xcodeproj'

  if @project_info[:type] == :workspace
    # Workspace contains multiple projects
    # Get the main project (not Pods)
    workspace = Xcodeproj::Workspace.new_from_xcworkspace(@project_info[:path])

    project_ref = workspace.file_references.find do |ref|
      !ref.path.include?('Pods') && ref.path.end_with?('.xcodeproj')
    end

    raise 'No main project found in workspace' unless project_ref

    project_path = File.join(File.dirname(@project_info[:path]), project_ref.path)
    Xcodeproj::Project.open(project_path)
  else
    Xcodeproj::Project.open(@project_info[:path])
  end
end

#product_name(target_name = nil, configuration = 'Release') ⇒ Object

Get product name



169
170
171
172
# File 'lib/mysigner/build/parser.rb', line 169

def product_name(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['PRODUCT_NAME'] || find_target(target_name).name
end

#product_type(target_name = nil) ⇒ Object

Detect product type (app, framework, library)



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/mysigner/build/parser.rb', line 90

def product_type(target_name = nil)
  target = find_target(target_name)

  case target.product_type
  when 'com.apple.product-type.application'
    :app
  when /framework/
    :framework
  when /library/
    :library
  when /app-extension/
    :extension
  else
    :unknown
  end
end

#provisioning_profile(target_name = nil, configuration = 'Release') ⇒ Object

Get provisioning profile specifier



143
144
145
146
# File 'lib/mysigner/build/parser.rb', line 143

def provisioning_profile(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['PROVISIONING_PROFILE_SPECIFIER']
end

#schemesObject

Get schemes (simplified - assume scheme name matches target name)



108
109
110
111
112
# File 'lib/mysigner/build/parser.rb', line 108

def schemes
  # In reality, schemes are in xcshareddata/xcschemes/
  # For now, return target names as potential schemes
  targets
end

#signable_targets(configuration = 'Release') ⇒ Object

Get a list of all signable targets with their info



71
72
73
74
75
# File 'lib/mysigner/build/parser.rb', line 71

def signable_targets(configuration = 'Release')
  all_app_targets.map do |target|
    target_info(target.name, configuration)
  end
end

#signing_configured?(target_name = nil, configuration = 'Release') ⇒ Boolean

Check if signing is configured

Returns:

  • (Boolean)


161
162
163
164
165
166
# File 'lib/mysigner/build/parser.rb', line 161

def signing_configured?(target_name = nil, configuration = 'Release')
  profile = provisioning_profile(target_name, configuration)
  identity = code_sign_identity(target_name, configuration)

  !profile.to_s.empty? && !identity.to_s.empty?
end

#target_info(target_name, configuration = 'Release') ⇒ Object

Get detailed info about a target



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/mysigner/build/parser.rb', line 56

def target_info(target_name, configuration = 'Release')
  target = find_target(target_name)

  {
    name: target.name,
    type: product_type(target_name),
    platform: target_platform(target_name),
    bundle_id: bundle_id(target_name, configuration),
    team_id: team_id(target_name, configuration),
    signing_style: code_sign_style(target_name, configuration),
    product_type: target.product_type
  }
end

#target_platform(target_name = nil) ⇒ Object

Detect target platform (iOS, macOS, tvOS, watchOS)



78
79
80
81
82
83
84
85
86
87
# File 'lib/mysigner/build/parser.rb', line 78

def target_platform(target_name = nil)
  target = find_target(target_name)
  sdk = target.sdk

  return :macos if sdk&.include?('macosx')
  return :tvos if sdk&.include?('appletvos')
  return :watchos if sdk&.include?('watchos')

  :ios # default
end

#targetsObject

Get all target names



14
15
16
# File 'lib/mysigner/build/parser.rb', line 14

def targets
  @project.targets.map(&:name)
end

#team_id(target_name = nil, configuration = 'Release') ⇒ Object

Get development team



131
132
133
134
# File 'lib/mysigner/build/parser.rb', line 131

def team_id(target_name = nil, configuration = 'Release')
  settings = build_settings(target_name, configuration)
  settings['DEVELOPMENT_TEAM']
end