Class: XCRes::InstallCommand

Inherits:
ProjectCommand show all
Defined in:
lib/xcres/command/install_command.rb

Overview

The InstallCommand integrates a build phase to the Xcode project, so that on each build the resources index will be rebuild, if needed.

Constant Summary collapse

BUILD_PHASE_NAME =
'Build Resource-Index'

Instance Method Summary collapse

Methods inherited from ProjectCommand

#application_targets, #discover_xcodeproj_file_path!, #discover_xcodeproj_file_path_in_dir!, #find_xcodeproj, inherit_parameters!, #native_targets, #project, #target

Methods inherited from Command

#configure_logger, #logger, #run

Instance Method Details

#attribute_valuesHash{Clamp::Attribute::Definition => #to_s}

Return a hash of attribute values

Returns:

  • (Hash{Clamp::Attribute::Definition => #to_s})


160
161
162
163
164
165
166
167
168
# File 'lib/xcres/command/install_command.rb', line 160

def attribute_values
  attribute_values = {}
  self.class.recognised_options.each do |attribute|
    if attribute.of(self).defined?
      attribute_values[attribute] = attribute.of(self).get
    end
  end
  attribute_values
end

#build(output_path) ⇒ void

This method returns an undefined value.

Trigger a build for the current project

Parameters:

  • output_path (Pathname)

    the argument OUTPUT_PATH for the build subcommand



73
74
75
76
77
# File 'lib/xcres/command/install_command.rb', line 73

def build(output_path)
  build_cmd = XCRes::BuildCommand.new("#{invocation_path} build", context, attribute_values)
  build_cmd.logger.indentation = '    '
  build_cmd.run([project_path.to_s, output_path.relative_path_from(Pathname.pwd).to_s])
end

#executevoid

This method returns an undefined value.

Execute the command



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/xcres/command/install_command.rb', line 17

def execute
  super

  # Locate the parent group, where the built files will been added to
  parent_group = find_parent_group

  # Locate the output path
  output_path = parent_group.real_path + 'Resources/R'

  inform 'Execute build first:'
  build(output_path)

  integrate!(output_path, parent_group)

  success 'Successfully integrated into %s', project_path
end

#find_parent_groupPBXGroup

Find parent group, where the built files will been added to. It will return the first group, which was found of the following list.

* 'Supporting Files' group
* target-specific group
* main group

Returns:

  • (PBXGroup)

Raises:

  • (ArgumentError)

    if no main group exists, which means that the project is invalid



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/xcres/command/install_command.rb', line 45

def find_parent_group
  # Get main group and ensure that it exists
  main_group = project.main_group
  raise ArgumentError, "Didn't find main group" if main_group.nil?

  # Get target-specific group, if the default project layout is in use
  src_group = main_group.groups.find { |g| g.path == target.name }
  if src_group != nil
    log "Found target group, will use its path as base output path."
  else
    log "Didn't find target group, expected a group with path '#{target.name}'."
  end

  # Find 'Supporting Files' group
  groups = main_group.recursive_children_groups
  support_files_group = groups.find { |g| g.name == 'Supporting Files' }
  warn "Didn't find support files group" if support_files_group.nil?

  support_files_group || src_group || main_group
end

#integrate!(output_path, parent_group) ⇒ void

This method returns an undefined value.

Integrate the build phase and add the built files to the project

Parameters:

  • output_path (Pathname)

    the argument OUTPUT_PATH for the build subcommand

  • parent_group (PBXGroup)

    the group where to integrate



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/xcres/command/install_command.rb', line 89

def integrate!(output_path, parent_group)
  # Find or create shell script build phase
  build_phase = target.shell_script_build_phases.find do |bp|
    bp.name == BUILD_PHASE_NAME
  end
  build_phase ||= target.new_shell_script_build_phase(BUILD_PHASE_NAME)

  # Remove build phase to re-insert before compile sources
  target.build_phases.delete(build_phase)
  index = target.build_phases.index(target.source_build_phase)
  target.build_phases.insert(index, build_phase)

  # Set shell script
  script_output_path = output_path.relative_path_from(src_root_path)
  documented_argument = documented? ? "--documented" : "--no-documented"
  swift_argument = swift? ? "--swift" : "--no-swift"
  build_phase.shell_script = "xcres --no-ansi build #{documented_argument} #{swift_argument} $PROJECT_FILE_PATH $SRCROOT/#{script_output_path}\n"
  build_phase.show_env_vars_in_log = '0'

  # Find or create 'Resources' group in 'Supporting Files'
  res_group = parent_group.groups.find { |g| g.name == 'Resources' }
  res_group ||= parent_group.new_group('Resources', Pathname('Resources'))

  if swift?
    # Find or create references to resources index files
    swift_file = res_group.find_file_by_path('R.swift') || res_group.new_file('R.swift')
    # Add .swift file to source build phase, if it doesn't not already exist there
    target.source_build_phase.add_file_reference(swift_file, true)
  else
    # Find or create references to resources index files
    h_file = res_group.find_file_by_path('R.h') || res_group.new_file('R.h')
    m_file = res_group.find_file_by_path('R.m') || res_group.new_file('R.m')
    # Add .m file to source build phase, if it doesn't not already exist there
    target.source_build_phase.add_file_reference(m_file, true)
    # Add .h file to prefix header
    prefix_headers.each do |path|
      realpath = src_root_path + path
      next unless File.exist?(realpath)
      File.open(realpath, 'a+') do |f|
        import_snippet = "#import \"#{h_file.path}\"\n"
        unless f.readlines.include?(import_snippet)
          f.write "\n#{import_snippet}"
        end
      end
    end
  end

  project.save()
end

#prefix_headersSet<Pathname>

Discover prefix header by build settings of the application target

Returns:

  • (Set<Pathname>)

    the relative paths to the .pch files



175
176
177
178
179
180
# File 'lib/xcres/command/install_command.rb', line 175

def prefix_headers
  @prefix_headers ||= target.build_configurations.map do |config|
    setting = config.build_settings['GCC_PREFIX_HEADER']
    setting ? Pathname(setting) : nil
  end.flatten.compact.to_set
end

#project_pathPathname

Return a relative path to the project

Returns:

  • (Pathname)


143
144
145
# File 'lib/xcres/command/install_command.rb', line 143

def project_path
  project.path.relative_path_from(Pathname.pwd)
end

#src_root_pathPathname

Return the path, which would be represented by the value of the build setting ‘$SRCROOT`.

Returns:

  • (Pathname)


152
153
154
# File 'lib/xcres/command/install_command.rb', line 152

def src_root_path
  project_path.realpath + '..'
end