aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundling.java
blob: 3b5c6ba26395a4608fcb2582af68442b8b42e289 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.rules.objc;

import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.BundlingRule.FAMILIES_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.APP_ICON_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.BUNDLE_ID_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.DEFAULT_PROVISIONING_PROFILE_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.LAUNCH_IMAGE_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.LAUNCH_STORYBOARD_ATTR;
import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.PROVISIONING_PROFILE_ATTR;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.InvalidFamilyNameException;
import com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.RepeatedFamilyNameException;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Preconditions;
import java.util.List;

/**
 * Contains information regarding the creation of a released bundle such as an application or
 * extension. The information which generally includes app icons, launch image, targeted devices and
 * other data for potential signing is used to create a releasable bundle out of the bundle created
 * using {@link Bundling} object.
 *
 * @deprecated The native bundling rules have been deprecated. This class will be removed in the
 *     future.
 */
@Deprecated
@Immutable
final class ReleaseBundling {
  static final class Builder {
    private Artifact ipaArtifact;
    private String bundleId;
    private String primaryBundleId;
    private String fallbackBundleId;
    private String appIcon;
    private String launchImage;
    private Artifact launchStoryboard;
    private Artifact provisioningProfile;
    private String provisioningProfileAttributeName;
    private final NestedSetBuilder<Artifact> infoplistInputs = NestedSetBuilder.stableOrder();
    private Iterable<Artifact> infoPlistsFromRule;
    private ImmutableSet<TargetDeviceFamily> families;
    private IntermediateArtifacts intermediateArtifacts;
    private String artifactPrefix;
    private Artifact entitlements;
    private Artifact extraEntitlements;

    public Builder setIpaArtifact(Artifact ipaArtifact) {
      this.ipaArtifact = ipaArtifact;
      return this;
    }

    public Builder setBundleId(String bundleId) {
      this.bundleId = bundleId;
      return this;
    }

    public Builder setPrimaryBundleId(String primaryId) {
      this.primaryBundleId = primaryId;
      return this;
    }

    public Builder setFallbackBundleId(String fallbackId) {
      this.fallbackBundleId = fallbackId;
      return this;
    }

    public Builder setAppIcon(String appIcon) {
      this.appIcon = appIcon;
      return this;
    }

    public Builder setLaunchImage(String launchImage) {
      this.launchImage = launchImage;
      return this;
    }

    public Builder setLaunchStoryboard(Artifact launchStoryboard) {
      this.launchStoryboard = launchStoryboard;
      return this;
    }

    public Builder setProvisioningProfile(Artifact provisioningProfile) {
      this.provisioningProfile = provisioningProfile;
      return this;
    }

    public Builder setProvisioningProfileAttributeName(String provisioningProfileAttributeName) {
      this.provisioningProfileAttributeName = provisioningProfileAttributeName;
      return this;
    }

    public Builder addInfoplistInput(Artifact infoPlist) {
      this.infoplistInputs.add(infoPlist);
      return this;
    }

    public Builder addInfoplistInputs(Iterable<Artifact> infoplists) {
      this.infoplistInputs.addAll(infoplists);
      return this;
    }

    public Builder setInfoPlistsFromRule(Iterable<Artifact> infoPlistsFromRule) {
      this.infoPlistsFromRule = infoPlistsFromRule;
      return this;
    }

    public Builder setIntermediateArtifacts(IntermediateArtifacts intermediateArtifacts) {
      this.intermediateArtifacts = intermediateArtifacts;
      return this;
    }

    public Builder setTargetDeviceFamilies(ImmutableSet<TargetDeviceFamily> families) {
      this.families = families;
      return this;
    }

    public Builder setArtifactPrefix(String artifactPrefix) {
      this.artifactPrefix = artifactPrefix;
      return this;
    }

    public Builder setEntitlements(Artifact entitlements) {
      this.entitlements = entitlements;
      return this;
    }

    public ReleaseBundling build() {
      Preconditions.checkNotNull(intermediateArtifacts, "intermediateArtifacts");
      Preconditions.checkNotNull(families, FAMILIES_ATTR);
      return new ReleaseBundling(
          ipaArtifact,
          bundleId,
          primaryBundleId,
          fallbackBundleId,
          appIcon,
          launchImage,
          launchStoryboard,
          provisioningProfile,
          provisioningProfileAttributeName,
          infoplistInputs.build(),
          infoPlistsFromRule,
          families,
          intermediateArtifacts,
          artifactPrefix,
          entitlements,
          extraEntitlements);
    }
  }

  /**
   * Returns a {@link ReleaseBundling} object constructed using the information available in given
   * context.
   */
  public static ReleaseBundling releaseBundling(RuleContext ruleContext)
      throws InterruptedException {
    Preconditions.checkState(!Strings.isNullOrEmpty(
        ruleContext.attributes().get(BUNDLE_ID_ATTR, Type.STRING)),
        "requires a bundle_id value");
    String primaryBundleId = null;
    String fallbackBundleId = null;
    Artifact provisioningProfile;

    if (ruleContext.attributes().isAttributeValueExplicitlySpecified(BUNDLE_ID_ATTR)) {
      primaryBundleId = ruleContext.attributes().get(BUNDLE_ID_ATTR, Type.STRING);
    } else {
      fallbackBundleId = ruleContext.attributes().get(BUNDLE_ID_ATTR, Type.STRING);
    }

    Artifact explicitProvisioningProfile =
        ruleContext.getPrerequisiteArtifact(PROVISIONING_PROFILE_ATTR, Mode.TARGET);
    if (explicitProvisioningProfile != null) {
      provisioningProfile = explicitProvisioningProfile;
    } else {
      provisioningProfile = ruleContext.getPrerequisiteArtifact(DEFAULT_PROVISIONING_PROFILE_ATTR,
          Mode.TARGET);
    }

    ImmutableSet<TargetDeviceFamily> families = null;
    List<String> rawFamilies = ruleContext.attributes().get(FAMILIES_ATTR, Type.STRING_LIST);
    try {
      families = ImmutableSet.copyOf(TargetDeviceFamily.fromNamesInRule(rawFamilies));
    } catch (InvalidFamilyNameException | RepeatedFamilyNameException e) {
      families = ImmutableSet.of();
    }

    if (families.isEmpty()) {
      ruleContext.attributeError(FAMILIES_ATTR, INVALID_FAMILIES_ERROR);
    }

    return new ReleaseBundling.Builder()
        .setIpaArtifact(ruleContext.getImplicitOutputArtifact(ReleaseBundlingSupport.IPA))
        .setBundleId(ruleContext.attributes().get(BUNDLE_ID_ATTR, Type.STRING))
        .setPrimaryBundleId(primaryBundleId)
        .setFallbackBundleId(fallbackBundleId)
        .setAppIcon(Strings.emptyToNull(ruleContext.attributes().get(APP_ICON_ATTR, Type.STRING)))
        .setLaunchImage(Strings.emptyToNull(
            ruleContext.attributes().get(LAUNCH_IMAGE_ATTR, Type.STRING)))
        .setLaunchStoryboard(
            ruleContext.getPrerequisiteArtifact(LAUNCH_STORYBOARD_ATTR, Mode.TARGET))
        .setProvisioningProfile(provisioningProfile)
        .setProvisioningProfileAttributeName(PROVISIONING_PROFILE_ATTR)
        .setTargetDeviceFamilies(families)
        .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext))
        .setEntitlements(ruleContext.getPrerequisiteArtifact("entitlements", Mode.TARGET))
        .build();
  }

  @VisibleForTesting
  static final String INVALID_FAMILIES_ERROR =
      "Expected one or two strings from the list 'iphone', 'ipad'";
  private final Artifact ipaArtifact;
  private final String bundleId;
  private final String fallbackBundleId;
  private final String primaryBundleId;
  private final String appIcon;
  private final String launchImage;
  private final Artifact launchStoryboard;
  private final Artifact provisioningProfile;
  private final String provisioningProfileAttributeName;
  private final NestedSet<Artifact> infoplistInputs;
  private final ImmutableSet<TargetDeviceFamily> families;
  private final IntermediateArtifacts intermediateArtifacts;
  private final Iterable<Artifact> infoPlistsFromRule;
  private final String artifactPrefix;
  private final Artifact entitlements;

  private ReleaseBundling(
      Artifact ipaArtifact,
      String bundleId,
      String primaryBundleId,
      String fallbackBundleId,
      String appIcon,
      String launchImage,
      Artifact launchStoryboard,
      Artifact provisioningProfile,
      String provisioningProfileAttributeName,
      NestedSet<Artifact> infoplistInputs,
      Iterable<Artifact> infoPlistsFromRule,
      ImmutableSet<TargetDeviceFamily> families,
      IntermediateArtifacts intermediateArtifacts,
      String artifactPrefix,
      Artifact entitlements,
      Artifact extraEntitlements) {
    this.ipaArtifact = Preconditions.checkNotNull(ipaArtifact);
    this.bundleId = bundleId;
    this.primaryBundleId = primaryBundleId;
    this.fallbackBundleId = fallbackBundleId;
    this.appIcon = appIcon;
    this.launchImage = launchImage;
    this.launchStoryboard = launchStoryboard;
    this.provisioningProfile = provisioningProfile;
    this.provisioningProfileAttributeName =
        Preconditions.checkNotNull(provisioningProfileAttributeName);
    this.infoplistInputs = Preconditions.checkNotNull(infoplistInputs);
    this.infoPlistsFromRule = infoPlistsFromRule;
    this.families = Preconditions.checkNotNull(families);
    this.intermediateArtifacts = Preconditions.checkNotNull(intermediateArtifacts);
    this.artifactPrefix = artifactPrefix;
    this.entitlements = entitlements;
  }

  /**
   * Returns the {@link Artifact} containing the final ipa bundle.
   */
  public Artifact getIpaArtifact() {
    return ipaArtifact;
  }

  /**
   * Returns the identifier of this bundle.
   */
  public String getBundleId() {
    return bundleId;
  }

  /**
   * Returns primary bundle ID to use, can be null.
   */
  public String getPrimaryBundleId() {
    return primaryBundleId;
  }

  /**
   * Returns fallback bundle ID to use when primary isn't set.
   */
  public String getFallbackBundleId() {
    return fallbackBundleId;
  }

  /**
   * Returns the app icon name for this bundle, can be null.
   */
  public String getAppIcon() {
    return appIcon;
  }

  /**
   * Returns the launch image name for this bundle, can be null.
   */
  public String getLaunchImage() {
    return launchImage;
  }

  /**
   * Returns an {@link Artifact} containing launch storyboard for this bundle, can be null.
   */
  public Artifact getLaunchStoryboard() {
    return launchStoryboard;
  }

  /**
   * Returns an {@link Artifact} containing provisioning profile used to sign this bundle,
   * can be null.
   */
  public Artifact getProvisioningProfile() {
    return provisioningProfile;
  }

  /**
   * Returns the list of plists to be merged to final bundle.
   */
  public NestedSet<Artifact> getInfoplistInputs() {
    return infoplistInputs;
  }

  /**
   * Returns the list of {@link TargetDeviceFamily} values this bundle is targeting.
   * If empty, the default values specified by {@link FAMILIES_ATTR} will be used.
   */
  public ImmutableSet<TargetDeviceFamily> getTargetDeviceFamilies() {
    return families;
  }

  /**
   * Returns {@link IntermediateArtifacts} used to create this bundle.
   */
  public IntermediateArtifacts getIntermediateArtifacts() {
    return intermediateArtifacts;
  }

  /**
   * Returns the name of the attribute which is used to specifiy the provisioning profile.
   */
  public String getProvisioningProfileAttrName() {
    return provisioningProfileAttributeName;
  }

  /**
   * Adds any info plists specified in the given rule's {@code infoplists} attribute as inputs to
   * this bundle's {@code Info.plist} (which is merged from any such added plists plus some
   * additional information).
   */
  public Iterable<Artifact> getInfoPlistsFromRule() {
    return infoPlistsFromRule;
  }

  /**
   * Returns the prefix to be added to all generated artifact names, can be null. This is useful
   * to disambiguate artifacts for multiple bundles created with different names withing same rule. 
   */
  public String getArtifactPrefix() {
    return artifactPrefix;
  }

  /**
   * Returns an {@link Artifact} containing the entitlements used to sign this bundle for
   * non-simulator builds; can be null.
   */
  public Artifact getEntitlements() {
    return entitlements;
  }
}