spinjector 0.0.1

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/spinjector.rb +141 -0
  3. metadata +43 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1df47e374d69631e9106daf013bd0b2e57cea05f9e99e4f2fa3fd5d019a5036c
4
+ data.tar.gz: 8b29d180bab07ea5b1d40c14cca971674f9b5cffba2cc918fbb2dec59074ed64
5
+ SHA512:
6
+ metadata.gz: c71c9217b566eba894bc6ea1d9e6173c1a3ae6e1039ee0073e533d115861199364c7692e0d1753a1fcd655582b190c4955199668d3d7c055a940140444eba7fe
7
+ data.tar.gz: 464e24d8fb992378ee8fe306daca6e1241363e38771290e7004eef0eea731ff622355636db8f2025a560cd8835d8cfe9872ce98924897f49953b3a1d5e573bb7
data/lib/spinjector.rb ADDED
@@ -0,0 +1,141 @@
1
+ # Inject script phases into your Xcode project
2
+ #
3
+ # @author Guillaume Berthier
4
+ #
5
+
6
+ require 'xcodeproj'
7
+ require 'yaml'
8
+
9
+ # @return [String] prefix used for all the build phase injected by this script
10
+ # [SPI] stands for Script Phase Injector
11
+ #
12
+ BUILD_PHASE_PREFIX = '[SPI] '.freeze
13
+
14
+ CONFIGURATION_FILE_PATH = 'Configuration/spinjector_configuration.yaml'.freeze
15
+
16
+ # @param [Xcodeproj::Project] project
17
+ #
18
+ def remove_all_spi_script_phases(project)
19
+ project.targets.each do |target|
20
+ # Delete script phases no longer present in the target.
21
+ native_target_script_phases = target.shell_script_build_phases.select do |bp|
22
+ !bp.name.nil? && bp.name.start_with?(BUILD_PHASE_PREFIX)
23
+ end
24
+ native_target_script_phases.each do |script_phase|
25
+ target.build_phases.delete(script_phase)
26
+ end
27
+ end
28
+ end
29
+
30
+ # @param [Xcodeproj::Project] project
31
+ #
32
+ def inject_script_phases(project)
33
+ configuration_file = load_yml_content(CONFIGURATION_FILE_PATH)
34
+ configuration_file.each do |target_name, script_paths|
35
+ return unless !target_name.nil?
36
+ script_phases = (script_paths || []).flat_map do |script_path|
37
+ load_yml_content(script_path)
38
+ end
39
+ target = app_target(project, target_name)
40
+ create_script_phases(script_phases, target)
41
+ end
42
+ end
43
+
44
+ # @param [String] configuration_path
45
+ # @return [Hash] the hash in the configuration file
46
+ #
47
+ def load_yml_content(configuration_path)
48
+ if !File.exist?(configuration_path)
49
+ puts "Script phase #{configuration_path} unknown"
50
+ return {}
51
+ end
52
+ YAML.load(File.read(configuration_path)) || {}
53
+ end
54
+
55
+ # @param [Xcodeproj::Project] project
56
+ # @param [String] target_name
57
+ # @return [Xcodeproj::Project::Object::PBXNativeTarget] the target named by target_name
58
+ #
59
+ def app_target(project, target_name)
60
+ target = project.targets.find { |t| t.name == target_name }
61
+ puts "Invalid #{target_name} target." unless !target.nil?
62
+ return target
63
+ end
64
+
65
+ # @param [Array<Hash>] script_phases the script phases defined in configuration files
66
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target to add the script phases
67
+ #
68
+ def create_script_phases(script_phases, target)
69
+ script_phases.each do |script_phase|
70
+ name_with_prefix = BUILD_PHASE_PREFIX + script_phase["name"]
71
+ phase = target.new_shell_script_build_phase(name_with_prefix)
72
+ script = File.read(script_phase["script_path"])
73
+ phase.shell_script = script
74
+ phase.shell_path = script_phase["shell_path"] || '/bin/sh'
75
+ phase.input_paths = script_phase["input_paths"]
76
+ phase.output_paths = script_phase["output_paths"]
77
+ phase.input_file_list_paths = script_phase["input_file_list_paths"]
78
+ phase.output_file_list_paths = script_phase["output_file_list_paths"]
79
+ phase.dependency_file = script_phase["dependency_file"]
80
+ # At least with Xcode 10 `showEnvVarsInLog` is *NOT* set to any value even if it's checked and it only
81
+ # gets set to '0' if the user has explicitly disabled this.
82
+ if (show_env_vars_in_log = script_phase.fetch("show_env_vars_in_log", '1')) == '0'
83
+ phase.show_env_vars_in_log = show_env_vars_in_log
84
+ end
85
+
86
+ execution_position = script_phase["execution_position"] || :before_compile
87
+ reorder_script_phase(target, phase, execution_position)
88
+ end
89
+ end
90
+
91
+ # @param [Xcodeproj::Project::Object::PBXNativeTarget] target where build phases should be reordered
92
+ # @param [Hash] script_phase to reorder
93
+ # @param [Symbol] execution_position could be :before_compile, :after_compile, :before_headers, :after_headers
94
+ #
95
+ def reorder_script_phase(target, script_phase, execution_position)
96
+ return if execution_position == :any || execution_position.to_s.empty?
97
+
98
+ # Find the point P where to add the script phase
99
+ target_phase_type = case execution_position
100
+ when :before_compile, :after_compile
101
+ Xcodeproj::Project::Object::PBXSourcesBuildPhase
102
+ when :before_headers, :after_headers
103
+ Xcodeproj::Project::Object::PBXHeadersBuildPhase
104
+ else
105
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
106
+ end
107
+
108
+ # Decide whether to add script_phase before or after point P
109
+ order_before = case execution_position
110
+ when :before_compile, :before_headers
111
+ true
112
+ when :after_compile, :after_headers
113
+ false
114
+ else
115
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
116
+ end
117
+
118
+ # Get the first build phase index of P
119
+ target_phase_index = target.build_phases.index do |bp|
120
+ bp.is_a?(target_phase_type)
121
+ end
122
+ return if target_phase_index.nil?
123
+
124
+ # Get the script phase we want to reorder index
125
+ script_phase_index = target.build_phases.index do |bp|
126
+ bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && !bp.name.nil? && bp.name == script_phase.name
127
+ end
128
+
129
+ # Move script phase to P if needed
130
+ if (order_before && script_phase_index > target_phase_index) ||
131
+ (!order_before && script_phase_index < target_phase_index)
132
+ target.build_phases.move_from(script_phase_index, target_phase_index)
133
+ end
134
+ end
135
+
136
+ project_path = Dir.glob("*.xcodeproj").first
137
+ project = Xcodeproj::Project.open(project_path)
138
+ remove_all_spi_script_phases(project)
139
+ inject_script_phases(project)
140
+ project.save()
141
+ puts "Success"
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spinjector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Guillaume Berthier, Fabernovel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ''
14
+ email: guillaume.berthier@fabernovel.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/spinjector.rb
20
+ homepage: https://www.fabernovel.com
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubygems_version: 3.0.3
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: Inject script phases into your Xcode project
43
+ test_files: []