spinjector 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []