xcode-archive-cache 0.0.6
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.
- checksums.yaml +7 -0
- data/bin/xcode-archive-cache +11 -0
- data/lib/artifact_cache/abstract_storage.rb +18 -0
- data/lib/artifact_cache/archiver.rb +110 -0
- data/lib/artifact_cache/artifact_extractor.rb +31 -0
- data/lib/artifact_cache/local_storage.rb +46 -0
- data/lib/build/performer.rb +48 -0
- data/lib/build/product_extractor.rb +129 -0
- data/lib/build_graph/builder.rb +154 -0
- data/lib/build_graph/graph.rb +37 -0
- data/lib/build_graph/native_target_finder.rb +101 -0
- data/lib/build_graph/node.rb +104 -0
- data/lib/build_graph/rebuild_evaluator.rb +30 -0
- data/lib/build_graph/sha_calculator.rb +102 -0
- data/lib/build_settings/extractor.rb +80 -0
- data/lib/build_settings/filter.rb +289 -0
- data/lib/build_settings/loader.rb +80 -0
- data/lib/build_settings/parser.rb +77 -0
- data/lib/build_settings/string_interpolator.rb +36 -0
- data/lib/command/command.rb +45 -0
- data/lib/command/inject.rb +52 -0
- data/lib/config/config.rb +211 -0
- data/lib/config/dsl.rb +69 -0
- data/lib/injection/build_flags_changer.rb +172 -0
- data/lib/injection/dependency_remover.rb +146 -0
- data/lib/injection/framework_embedder.rb +47 -0
- data/lib/injection/headers_mover.rb +65 -0
- data/lib/injection/injector.rb +220 -0
- data/lib/injection/pods_script_fixer.rb +52 -0
- data/lib/injection/storage.rb +122 -0
- data/lib/logs/logs.rb +47 -0
- data/lib/runner/runner.rb +139 -0
- data/lib/shell/executor.rb +69 -0
- data/lib/xcode-archive-cache.rb +59 -0
- data/lib/xcodebuild/executor.rb +146 -0
- metadata +133 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
module XcodeArchiveCache
|
2
|
+
class Command < CLAide::Command
|
3
|
+
|
4
|
+
include XcodeArchiveCache::Logs
|
5
|
+
|
6
|
+
self.abstract_command = true
|
7
|
+
self.command = "xcode-archive-cache"
|
8
|
+
self.description = "XcodeArchiveCache, cache for Xcode archive action"
|
9
|
+
|
10
|
+
def self.options
|
11
|
+
[
|
12
|
+
["--log-level=[nothing|info|verbose]", "Level of log verbosity, defaults to info"]
|
13
|
+
].concat(super.reject { |(name, _)| name != "--help" })
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.run(argv)
|
17
|
+
help! "You cannot run XcodeArchiveCache as root." if Process.uid == 0 && !Gem.win_platform?
|
18
|
+
|
19
|
+
super(argv)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(argv)
|
23
|
+
super
|
24
|
+
log_level = argv.option("log-level", "info")
|
25
|
+
set_log_level(log_level)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.report_error(exception)
|
30
|
+
case exception
|
31
|
+
when Interrupt
|
32
|
+
info("Cancelled")
|
33
|
+
exit 1
|
34
|
+
when SystemExit
|
35
|
+
raise
|
36
|
+
else
|
37
|
+
if ENV["XCODE_ARCHIVE_CACHE_ENV"] != "development"
|
38
|
+
error(exception.message)
|
39
|
+
exit 1
|
40
|
+
else
|
41
|
+
raise exception
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module XcodeArchiveCache
|
2
|
+
class Command
|
3
|
+
class Inject < Command
|
4
|
+
|
5
|
+
include XcodeArchiveCache::Logs
|
6
|
+
|
7
|
+
self.description = "Setup workspace or project for being built using cached dependencies"
|
8
|
+
|
9
|
+
def self.options
|
10
|
+
[
|
11
|
+
["--cachefile=/path/to/Cachefile", "Explicit Cachefile location, defaults to $PWD/Cachefile"],
|
12
|
+
["--configuration", "Name of configuration from Cachefile, required"],
|
13
|
+
["--destination=[<full destination specifier>|generic]", "xcodebuild-style destination. Defaults to 'generic', ignored for archive action"],
|
14
|
+
["--storage=/path/to/storage", "Storage dir path, required"]
|
15
|
+
].concat(super)
|
16
|
+
end
|
17
|
+
|
18
|
+
DEFAULT_CACHEFILE = "Cachefile"
|
19
|
+
|
20
|
+
def initialize(argv)
|
21
|
+
super
|
22
|
+
|
23
|
+
@configuration_name = argv.option("configuration")
|
24
|
+
if @configuration_name == nil
|
25
|
+
error("configuration is required")
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
@storage = argv.option("storage")
|
30
|
+
if @storage == nil
|
31
|
+
error("storage parameter is required")
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
@cachefile_path = argv.option("cachefile", DEFAULT_CACHEFILE)
|
36
|
+
@destination = argv.option("destination", XcodeArchiveCache::Xcodebuild::GENERIC_DESTINATION)
|
37
|
+
end
|
38
|
+
|
39
|
+
def run
|
40
|
+
config = XcodeArchiveCache::Config.from_file(@cachefile_path).entry
|
41
|
+
config.settings.destination = @destination
|
42
|
+
config.active_configuration_name = @configuration_name
|
43
|
+
config.storage.type = :local
|
44
|
+
config.storage.path = @storage
|
45
|
+
|
46
|
+
debug(config)
|
47
|
+
|
48
|
+
XcodeArchiveCache::Runner.new(config).run
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module XcodeArchiveCache
|
2
|
+
class Config
|
3
|
+
|
4
|
+
include XcodeArchiveCache::Config::DSL
|
5
|
+
|
6
|
+
class Entry
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
#
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [Array<Configuration>]
|
13
|
+
#
|
14
|
+
attr_reader :configurations
|
15
|
+
|
16
|
+
# @return [String]
|
17
|
+
#
|
18
|
+
attr_accessor :active_configuration_name
|
19
|
+
|
20
|
+
# @return [Array<Target>]
|
21
|
+
#
|
22
|
+
attr_reader :targets
|
23
|
+
|
24
|
+
# @return [Settings]
|
25
|
+
#
|
26
|
+
attr_reader :settings
|
27
|
+
|
28
|
+
# @return [Storage]
|
29
|
+
#
|
30
|
+
attr_reader :storage
|
31
|
+
|
32
|
+
def initialize(name)
|
33
|
+
@name = name
|
34
|
+
@configurations = []
|
35
|
+
@active_configuration_name = nil
|
36
|
+
@settings = Settings.new
|
37
|
+
@storage = Storage.new
|
38
|
+
@targets = []
|
39
|
+
@file_extname = ""
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
def file_path
|
45
|
+
return name if File.extname(name) == file_extname
|
46
|
+
|
47
|
+
name + file_extname
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Configuration]
|
51
|
+
#
|
52
|
+
def active_configuration
|
53
|
+
configuration = configurations.select{|config| config.name == active_configuration_name }.first
|
54
|
+
if configuration == nil
|
55
|
+
raise Informative, "Found no configuration with name \"#{active_configuration_name}\""
|
56
|
+
end
|
57
|
+
|
58
|
+
configuration
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
"path: #{file_path}\nactive configuration: #{active_configuration_name}\nconfigurations:\n\t#{configurations.join("\n\t")}\n#{settings}\nstorage: #{storage}\ntargets:\n\t#{targets.join("\n\t")}"
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# @return [String]
|
68
|
+
#
|
69
|
+
attr_reader :file_extname
|
70
|
+
end
|
71
|
+
|
72
|
+
class Workspace < Entry
|
73
|
+
def initialize(path)
|
74
|
+
super(path)
|
75
|
+
@file_extname = ".xcworkspace"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Project < Entry
|
80
|
+
def initialize(path)
|
81
|
+
super(path)
|
82
|
+
@file_extname = ".xcodeproj"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class Configuration
|
87
|
+
# @return [String]
|
88
|
+
#
|
89
|
+
attr_reader :name
|
90
|
+
|
91
|
+
# @return [String]
|
92
|
+
#
|
93
|
+
attr_accessor :build_configuration
|
94
|
+
|
95
|
+
# @return [String]
|
96
|
+
#
|
97
|
+
attr_accessor :action
|
98
|
+
|
99
|
+
# @return [String]
|
100
|
+
#
|
101
|
+
attr_accessor :xcodebuild_args
|
102
|
+
|
103
|
+
# @param [String] name
|
104
|
+
#
|
105
|
+
def initialize(name)
|
106
|
+
@name = name
|
107
|
+
@action = "archive"
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_s
|
111
|
+
"#{name}, build configuration: #{build_configuration}, action: #{action}, xcodebuild args: \"#{xcodebuild_args}\""
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class Settings
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
attr_accessor :derived_data_path
|
119
|
+
|
120
|
+
# @return [String]
|
121
|
+
#
|
122
|
+
attr_accessor :destination
|
123
|
+
|
124
|
+
def to_s
|
125
|
+
"destination: #{destination}, derived data path: #{derived_data_path}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class Storage
|
130
|
+
|
131
|
+
# @return [Symbol]
|
132
|
+
#
|
133
|
+
attr_accessor :type
|
134
|
+
|
135
|
+
# @return [String]
|
136
|
+
#
|
137
|
+
attr_accessor :path
|
138
|
+
|
139
|
+
def to_s
|
140
|
+
"#{type}, path: #{path}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Target
|
145
|
+
|
146
|
+
# @return [String]
|
147
|
+
#
|
148
|
+
attr_reader :name
|
149
|
+
|
150
|
+
# @return [Array<String>]
|
151
|
+
#
|
152
|
+
attr_reader :dependencies
|
153
|
+
|
154
|
+
# @param [String] name
|
155
|
+
#
|
156
|
+
def initialize(name)
|
157
|
+
@name = name
|
158
|
+
@dependencies = []
|
159
|
+
end
|
160
|
+
|
161
|
+
def to_s
|
162
|
+
"#{name}, dependencies: #{dependencies.join(", ")}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# @param [String] path
|
167
|
+
#
|
168
|
+
def self.from_file(path)
|
169
|
+
contents = File.open(path, "r:utf-8", &:read)
|
170
|
+
|
171
|
+
config = Config.new do
|
172
|
+
begin
|
173
|
+
eval(contents, nil, path)
|
174
|
+
rescue Exception => e
|
175
|
+
raise Informative, "Invalid #{File.basename(path)} file: #{e.message}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
config
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [Entry]
|
183
|
+
#
|
184
|
+
attr_reader :entry
|
185
|
+
|
186
|
+
def initialize(&block)
|
187
|
+
@entry = nil
|
188
|
+
@current_target = nil
|
189
|
+
|
190
|
+
if block
|
191
|
+
instance_eval(&block)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
attr_writer :entry
|
198
|
+
|
199
|
+
# @return [Configuration]
|
200
|
+
#
|
201
|
+
def current_configuration
|
202
|
+
entry.configurations.last
|
203
|
+
end
|
204
|
+
|
205
|
+
# @return [Target]
|
206
|
+
#
|
207
|
+
def current_target
|
208
|
+
entry.targets.last
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
data/lib/config/dsl.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module XcodeArchiveCache
|
2
|
+
class Config
|
3
|
+
module DSL
|
4
|
+
|
5
|
+
# @param [String] name
|
6
|
+
#
|
7
|
+
def workspace(name)
|
8
|
+
self.entry = Workspace.new(name)
|
9
|
+
|
10
|
+
yield
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param [String] name
|
14
|
+
#
|
15
|
+
def project(name)
|
16
|
+
self.entry = Project.new(name)
|
17
|
+
|
18
|
+
yield
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [String] name
|
22
|
+
#
|
23
|
+
def configuration(name)
|
24
|
+
entry.configurations.push(Configuration.new(name))
|
25
|
+
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [String] name
|
30
|
+
#
|
31
|
+
def build_configuration(name)
|
32
|
+
current_configuration.build_configuration = name
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [String] name
|
36
|
+
#
|
37
|
+
def action(name)
|
38
|
+
current_configuration.action = name
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param [String] args
|
42
|
+
#
|
43
|
+
def xcodebuild_args(args)
|
44
|
+
current_configuration.xcodebuild_args = args
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param [String] path
|
48
|
+
#
|
49
|
+
def derived_data_path(path)
|
50
|
+
entry.settings.derived_data_path = path
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String]
|
54
|
+
#
|
55
|
+
def target(name)
|
56
|
+
target = Target.new(name)
|
57
|
+
entry.targets.push(target)
|
58
|
+
|
59
|
+
yield
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param [String] name
|
63
|
+
#
|
64
|
+
def cache(name)
|
65
|
+
current_target.dependencies.push(name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module XcodeArchiveCache
|
2
|
+
module Injection
|
3
|
+
class BuildFlagsChanger
|
4
|
+
|
5
|
+
include XcodeArchiveCache::Logs
|
6
|
+
|
7
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
8
|
+
# @param [String] path
|
9
|
+
#
|
10
|
+
def add_framework_search_path(build_configuration, path)
|
11
|
+
debug("using framework search path #{path}")
|
12
|
+
add_flag_to_configuration(build_configuration, FRAMEWORK_SEARCH_PATHS_KEY, path_to_search_path(path))
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
16
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] node
|
17
|
+
#
|
18
|
+
def add_framework_linker_flag(build_configuration, node)
|
19
|
+
linker_flag = get_framework_linker_flag(node)
|
20
|
+
if linker_flag
|
21
|
+
debug("using linker flag #{linker_flag}")
|
22
|
+
add_linker_flag(build_configuration, linker_flag)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
27
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] node
|
28
|
+
#
|
29
|
+
def add_framework_headers_iquote(build_configuration, artifact_location, node)
|
30
|
+
headers_search_path = get_framework_headers_iquote(artifact_location, node)
|
31
|
+
debug("using -iquote path #{headers_search_path}")
|
32
|
+
add_cflag(build_configuration, headers_search_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
36
|
+
# @param [String] path
|
37
|
+
#
|
38
|
+
def add_library_search_path(build_configuration, path)
|
39
|
+
debug("using library search path #{path}")
|
40
|
+
add_flag_to_configuration(build_configuration, LIBRARY_SEARCH_PATHS_KEY, path_to_search_path(path))
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
44
|
+
# @param [String] path
|
45
|
+
#
|
46
|
+
def add_headers_search_path(build_configuration, path)
|
47
|
+
debug("using headers search path #{path}")
|
48
|
+
add_flag_to_configuration(build_configuration, HEADER_SEARCH_PATHS_KEY, path)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
52
|
+
# @param [String] path
|
53
|
+
#
|
54
|
+
def add_iquote_path(build_configuration, path)
|
55
|
+
debug("using -iquote path #{path}")
|
56
|
+
add_cflag(build_configuration, path_to_iquote(path))
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
60
|
+
# @param [String] path
|
61
|
+
#
|
62
|
+
def add_capital_i_path(build_configuration, path)
|
63
|
+
debug("using -I path #{path}")
|
64
|
+
add_cflag(build_configuration, path_to_capital_i(path))
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
FRAMEWORK_SEARCH_PATHS_KEY = "FRAMEWORK_SEARCH_PATHS"
|
70
|
+
LIBRARY_SEARCH_PATHS_KEY = "LIBRARY_SEARCH_PATHS"
|
71
|
+
HEADER_SEARCH_PATHS_KEY = "HEADER_SEARCH_PATHS"
|
72
|
+
OTHER_CFLAGS_KEY = "OTHER_CFLAGS"
|
73
|
+
OTHER_LDFLAGS_KEY = "OTHER_LDFLAGS"
|
74
|
+
INHERITED_SETTINGS_VALUE = "$(inherited)"
|
75
|
+
|
76
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
77
|
+
# @param [String] flag
|
78
|
+
#
|
79
|
+
def add_linker_flag(build_configuration, flag)
|
80
|
+
add_flag_to_configuration(build_configuration, OTHER_LDFLAGS_KEY, flag)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
84
|
+
# @param [String] flag
|
85
|
+
#
|
86
|
+
def add_cflag(build_configuration, flag)
|
87
|
+
add_flag_to_configuration(build_configuration, OTHER_CFLAGS_KEY, flag)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param [Xcodeproj::Project::Object::XCBuildConfiguration] build_configuration
|
91
|
+
# @param [String] key
|
92
|
+
# @param [String] flag
|
93
|
+
#
|
94
|
+
def add_flag_to_configuration(build_configuration, key, flag)
|
95
|
+
flags = build_configuration.build_settings[key]
|
96
|
+
build_configuration.build_settings[key] = add_flag(flags, flag)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param [Object] flags
|
100
|
+
# @param [String] new_flag
|
101
|
+
#
|
102
|
+
# @return [Array<String>]
|
103
|
+
#
|
104
|
+
def add_flag(flags, new_flag)
|
105
|
+
if flags && flags.length > 0
|
106
|
+
if flags.is_a?(String)
|
107
|
+
flags = [flags, new_flag]
|
108
|
+
elsif flags.is_a?(Array)
|
109
|
+
flags += [new_flag] unless flags.include?(new_flag)
|
110
|
+
else
|
111
|
+
raise StandardError.new, "Flags value is neither string nor array: #{flags.class}"
|
112
|
+
end
|
113
|
+
else
|
114
|
+
flags = [INHERITED_SETTINGS_VALUE, new_flag]
|
115
|
+
end
|
116
|
+
|
117
|
+
flags
|
118
|
+
end
|
119
|
+
|
120
|
+
# @param [String] path
|
121
|
+
#
|
122
|
+
# @return [String]
|
123
|
+
#
|
124
|
+
def path_to_search_path(path)
|
125
|
+
"\"#{path}\""
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param [String] path
|
129
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] node
|
130
|
+
#
|
131
|
+
# @return [String]
|
132
|
+
#
|
133
|
+
def get_framework_headers_iquote(path, node)
|
134
|
+
if node.has_framework_product?
|
135
|
+
headers_dir_path = File.join(path, node.product_file_name, "Headers")
|
136
|
+
path_to_iquote(headers_dir_path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param [String] path
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
#
|
144
|
+
def path_to_iquote(path)
|
145
|
+
"-iquote \"#{path}\""
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param [String] path
|
149
|
+
#
|
150
|
+
# @return [Stirng]
|
151
|
+
#
|
152
|
+
def path_to_capital_i(path)
|
153
|
+
"-I\"#{path}\""
|
154
|
+
end
|
155
|
+
|
156
|
+
# @param [XcodeArchiveCache::BuildGraph::Node] node
|
157
|
+
#
|
158
|
+
# @return [String]
|
159
|
+
#
|
160
|
+
# Something.framework -> -framework "Something"
|
161
|
+
#
|
162
|
+
def get_framework_linker_flag(node)
|
163
|
+
return unless node.product_file_name
|
164
|
+
|
165
|
+
framework_name = File.basename(node.product_file_name, File.extname(node.product_file_name))
|
166
|
+
return unless framework_name
|
167
|
+
|
168
|
+
"-framework \"#{framework_name}\""
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|