1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.sap.prd.mobile.ios.mios;
21
22 import static com.sap.prd.mobile.ios.mios.XCodeVersionUtil.checkVersions;
23 import static com.sap.prd.mobile.ios.mios.XCodeVersionUtil.getVersion;
24 import static com.sap.prd.mobile.ios.mios.XCodeVersionUtil.getXCodeVersionString;
25
26 import java.io.File;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
36 import org.apache.maven.execution.MavenSession;
37 import org.apache.maven.plugin.MojoExecutionException;
38
39
40
41
42
43
44 public abstract class BuildContextAwareMojo extends AbstractXCodeMojo
45 {
46
47 private static final String PREFIX_XCODE_OPTIONS = "xcode.options.";
48 private static final String PREFIX_XCODE_SETTINGS = "xcode.settings.";
49 public final static String MIN_XCODE_VERSION = "8.0";
50
51
52 protected final static List<String> DEFAULT_BUILD_ACTIONS = Collections.unmodifiableList(Arrays.asList("clean",
53 "build"));
54
55
56
57
58
59
60
61 protected List<String> buildActions;
62
63
64
65
66
67
68
69
70 protected String codeSignIdentity;
71
72
73
74
75
76
77
78
79
80 protected boolean codeSigningRequired;
81
82
83
84
85
86
87
88
89 protected String provisioningProfile;
90
91
92
93
94
95
96
97
98 protected String target;
99
100
101
102
103 private String productName;
104
105
106
107
108
109
110
111
112 private Map<String, String> settings;
113
114
115
116
117
118
119
120
121 private Map<String, String> options;
122
123
124
125
126
127
128 private MavenSession session;
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 private String watchapp;
148
149
150
151
152
153
154
155 private String symRootDir;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 private String xcconfigDir;
176
177
178
179
180
181
182
183
184 private String defaultxcconfig;
185
186 protected XCodeContext getXCodeContext(final XCodeContext.SourceCodeLocation sourceCodeLocation,
187 String configuration, String sdk)
188 {
189 final String projectName = project.getArtifactId();
190 File projectDirectory = null;
191
192 if (sourceCodeLocation == XCodeContext.SourceCodeLocation.WORKING_COPY) {
193 projectDirectory = getXCodeCompileDirectory();
194 }
195 else if (sourceCodeLocation == XCodeContext.SourceCodeLocation.ORIGINAL) {
196 projectDirectory = getXCodeSourceDirectory();
197 }
198 else {
199 throw new IllegalStateException("Invalid source code location: '" + sourceCodeLocation + "'");
200 }
201
202 HashMap<String, String> managedSettings = new HashMap<String, String>();
203 if (codeSignIdentity != null)
204 managedSettings.put(Settings.ManagedSetting.CODE_SIGN_IDENTITY.name(), codeSignIdentity);
205
206 if (symRootDir != null)
207 managedSettings.put(Settings.ManagedSetting.SYMROOT.name(), symRootDir);
208
209 if (!codeSigningRequired)
210 managedSettings.put(Settings.ManagedSetting.CODE_SIGNING_REQUIRED.name(), "NO");
211
212 if (provisioningProfile != null)
213 managedSettings.put(Settings.ManagedSetting.PROVISIONING_PROFILE.name(), provisioningProfile);
214
215 HashMap<String, String> managedOptions = new HashMap<String, String>();
216
217 if (configuration != null && !configuration.trim().isEmpty())
218 managedOptions.put(Options.ManagedOption.CONFIGURATION.getOptionName(), configuration);
219 try {
220
221 String xCodeVersionString = getXCodeVersionString();
222 DefaultArtifactVersion version = getVersion(xCodeVersionString);
223 File file;
224 if (checkVersions(version, MIN_XCODE_VERSION)) {
225
226 if (xcconfigDir != null) {
227 getLog().info("Using xccconfig provided by the dev team: " + xcconfigDir);
228
229 file = new File(xcconfigDir);
230 if (file.exists()) {
231 managedOptions.put(Options.ManagedOption.XCCONFIG.getOptionName(), xcconfigDir);
232 } else {
233 getLog().error("xcconfig file not found in locaion " + xcconfigDir);
234 }
235 } else if (defaultxcconfig != null) {
236 getLog().info("Using xccconfig provided by the central team: " + defaultxcconfig);
237
238 file = new File(defaultxcconfig);
239 if (file.exists()) {
240 managedOptions.put(Options.ManagedOption.XCCONFIG.getOptionName(), defaultxcconfig);
241 } else {
242 getLog().error("xcconfig file not found in locaion " + defaultxcconfig);
243 }
244 } else
245 getLog().info(
246 "To build the application using Xcode 8 and above, plugin expects xcconfig file /n For simple app: Central team manages it in settings.xml "
247 + "For apps with entitlement dev needs to provide the xcconfig content in pom.xml");
248 }
249 } catch (XCodeException e) {
250 throw new IllegalStateException("Could not get xcodebuild version", e);
251 }
252
253
254
255
256
257
258 if (sdk != null && !sdk.trim().isEmpty() && watchapp ==null)
259 managedOptions.put(Options.ManagedOption.SDK.getOptionName(), sdk);
260 if (target != null && !target.trim().isEmpty())
261 managedOptions.put(Options.ManagedOption.TARGET.getOptionName(), target);
262
263 Map<String, String> _settings = new HashMap<String, String>(settings == null ? new HashMap<String, String>()
264 : settings);
265
266 for (String key : getKeys(PREFIX_XCODE_SETTINGS)) {
267 _settings.put(key.substring(PREFIX_XCODE_SETTINGS.length()), getProperty(key));
268 }
269
270 Map<String, String> _options = new HashMap<String, String>(options == null ? new HashMap<String, String>()
271 : options);
272
273 for (String key : getKeys(PREFIX_XCODE_OPTIONS)) {
274 _options.put(key.substring(PREFIX_XCODE_OPTIONS.length()), getProperty(key));
275 }
276
277 if (null == _options.get("scheme"))
278 managedOptions.put(Options.ManagedOption.PROJECT.getOptionName(), projectName + ".xcodeproj");
279
280
281 return new XCodeContext(getBuildActions(), projectDirectory, System.out, new Settings(_settings, managedSettings),
282 new Options(_options, managedOptions));
283 }
284
285 protected List<String> getBuildActions()
286 {
287 return (buildActions == null || buildActions.isEmpty()) ? DEFAULT_BUILD_ACTIONS : Collections
288 .unmodifiableList(buildActions);
289 }
290
291
292
293
294
295 protected PListAccessor getInfoPListAccessor(XCodeContext.SourceCodeLocation location, String configuration,
296 String sdk)
297 throws MojoExecutionException, XCodeException
298 {
299 File plistFile = getPListFile(location, configuration, sdk);
300 if (!plistFile.isFile()) {
301 throw new MojoExecutionException("The Xcode project refers to the Info.plist file '" + plistFile
302 + "' that does not exist.");
303 }
304 return new PListAccessor(plistFile);
305 }
306
307 protected File getPListFile(XCodeContext.SourceCodeLocation location, String configuration, String sdk)
308 throws XCodeException
309 {
310
311 XCodeContext context = getXCodeContext(location, configuration, sdk);
312
313 String plistFileName = EffectiveBuildSettings.getBuildSetting(context, EffectiveBuildSettings.INFOPLIST_FILE);
314 File srcRoot = new File(EffectiveBuildSettings.getBuildSetting(context, EffectiveBuildSettings.SRC_ROOT));
315
316 final File plistFile = new File(plistFileName);
317
318 if (!plistFile.isAbsolute()) {
319 return new File(srcRoot, plistFileName);
320 }
321
322 if (FileUtils.isChild(srcRoot, plistFile))
323 return plistFile;
324
325 throw new IllegalStateException("Plist file " + plistFile + " is not located inside the xcode project " + srcRoot
326 + ".");
327
328 }
329
330 protected File getProjectRootDirectory(XCodeContext.SourceCodeLocation location, String configuration, String sdk)
331 throws XCodeException {
332 XCodeContext context = getXCodeContext(location, configuration, sdk);
333
334 File srcRoot = new File(EffectiveBuildSettings.getBuildSetting(context, EffectiveBuildSettings.SRC_ROOT));
335 return srcRoot;
336 }
337
338 protected String getProductName(final String configuration, final String sdk) throws MojoExecutionException
339 {
340
341 final String productName;
342
343 if (this.productName != null) {
344 productName = this.productName;
345 getLog().info("Production name obtained from pom file");
346 }
347 else {
348
349 try {
350 productName = EffectiveBuildSettings.getBuildSetting(
351 getXCodeContext(XCodeContext.SourceCodeLocation.WORKING_COPY, configuration, sdk), EffectiveBuildSettings.PRODUCT_NAME);
352 getLog().info("Product name obtained from effective build settings file");
353
354 }
355 catch (final XCodeException ex) {
356 throw new MojoExecutionException("Cannot get product name: " + ex.getMessage(), ex);
357 }
358 }
359
360 if (productName == null || productName.trim().length() == 0)
361 throw new MojoExecutionException("Invalid product name. Was null or empty.");
362
363 return productName;
364 }
365
366
367
368
369
370
371
372
373 @SuppressWarnings("unchecked")
374 protected Set<String> getKeys(String prefix)
375 {
376
377 Set<String> result = new HashSet<String>();
378
379 @SuppressWarnings("rawtypes")
380 final Set keys = new HashSet();
381 keys.addAll(session.getUserProperties().keySet());
382 keys.addAll(project.getProperties().keySet());
383
384 if (prefix == null) return keys;
385
386 for (Object key : keys) {
387 if (((String) key).startsWith(prefix))
388 result.add((String) key);
389 }
390
391 return result;
392 }
393
394 protected String getProperty(String key)
395 {
396 String value = session.getUserProperties().getProperty(key);
397
398 if (value == null)
399 {
400 value = project.getProperties().getProperty(key);
401 }
402
403 return value;
404 }
405
406 }