/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/appiconset.go

https://github.com/bitrise-io/codesigndoc · Go · 172 lines · 141 code · 25 blank · 6 comment · 55 complexity · 3d4fd229f2fa3e51d3d8a71ad6f7f388 MD5 · raw file

  1. package xcodeproj
  2. import (
  3. "fmt"
  4. "path"
  5. "path/filepath"
  6. "regexp"
  7. "strings"
  8. "github.com/bitrise-io/go-utils/pathutil"
  9. "github.com/bitrise-io/go-utils/sliceutil"
  10. "github.com/bitrise-io/go-xcode/xcodeproject/serialized"
  11. )
  12. // TargetsToAppIconSets maps target names to an array app icon set absolute paths.
  13. type TargetsToAppIconSets map[string][]string
  14. // AppIconSetPaths parses an Xcode project and returns targets mapped to app icon set absolute paths.
  15. func AppIconSetPaths(projectPath string) (TargetsToAppIconSets, error) {
  16. absPth, err := pathutil.AbsPath(projectPath)
  17. if err != nil {
  18. return TargetsToAppIconSets{}, err
  19. }
  20. proj, err := Open(absPth)
  21. if err != nil {
  22. return TargetsToAppIconSets{}, err
  23. }
  24. objects, err := proj.RawProj.Object("objects")
  25. if err != nil {
  26. return TargetsToAppIconSets{}, err
  27. }
  28. return appIconSetPaths(proj.Proj, projectPath, objects)
  29. }
  30. func appIconSetPaths(project Proj, projectPath string, objects serialized.Object) (TargetsToAppIconSets, error) {
  31. targetToAppIcons := map[string][]string{}
  32. for _, target := range project.Targets {
  33. appIconSetNames := getAppIconSetNames(target)
  34. if len(appIconSetNames) == 0 {
  35. continue
  36. }
  37. assetCatalogs, err := assetCatalogs(target, project.ID, objects)
  38. if err != nil {
  39. return nil, err
  40. } else if len(assetCatalogs) == 0 {
  41. continue
  42. }
  43. appIcons := []string{}
  44. for _, appIconSetName := range appIconSetNames {
  45. appIconSetPaths, err := lookupAppIconPaths(projectPath, assetCatalogs, appIconSetName, project.ID, objects)
  46. if err != nil {
  47. return nil, err
  48. } else if len(appIconSetPaths) == 0 {
  49. return nil, fmt.Errorf("not found app icon set (%s) on paths: %s", appIconSetName, assetCatalogs)
  50. }
  51. appIcons = append(appIcons, appIconSetPaths...)
  52. }
  53. targetToAppIcons[target.ID] = sliceutil.UniqueStringSlice(appIcons)
  54. }
  55. return targetToAppIcons, nil
  56. }
  57. func lookupAppIconPaths(projectPath string, assetCatalogs []fileReference, appIconSetName string, projectID string, objects serialized.Object) ([]string, error) {
  58. var icons []string
  59. for _, fileReference := range assetCatalogs {
  60. resolvedPath, err := resolveObjectAbsolutePath(fileReference.id, projectID, projectPath, objects)
  61. if err != nil {
  62. return nil, err
  63. } else if resolvedPath == "" {
  64. return nil, fmt.Errorf("could not resolve path")
  65. }
  66. re := regexp.MustCompile(`\$\{(.+)\}`)
  67. wildcharAppIconSetName := re.ReplaceAllString(appIconSetName, "*")
  68. matches, err := filepath.Glob(path.Join(regexp.QuoteMeta(resolvedPath), wildcharAppIconSetName+".appiconset"))
  69. if err != nil {
  70. return nil, err
  71. }
  72. icons = append(icons, matches...)
  73. }
  74. return icons, nil
  75. }
  76. func assetCatalogs(target Target, projectID string, objects serialized.Object) ([]fileReference, error) {
  77. if target.Type == NativeTargetType { // Ignoring PBXAggregateTarget and PBXLegacyTarget as may not contain buildPhases key
  78. resourcesBuildPhase, err := filterResourcesBuildPhase(target.buildPhaseIDs, objects)
  79. if err != nil {
  80. return nil, fmt.Errorf("getting resource build phases failed, error: %s", err)
  81. }
  82. assetCatalogs, err := filterAssetCatalogs(resourcesBuildPhase, projectID, objects)
  83. if err != nil {
  84. return nil, err
  85. }
  86. return assetCatalogs, nil
  87. }
  88. return nil, nil
  89. }
  90. func filterResourcesBuildPhase(buildPhases []string, objects serialized.Object) (resourcesBuildPhase, error) {
  91. for _, buildPhaseUUID := range buildPhases {
  92. rawBuildPhase, err := objects.Object(buildPhaseUUID)
  93. if err != nil {
  94. return resourcesBuildPhase{}, err
  95. }
  96. if isResourceBuildPhase(rawBuildPhase) {
  97. buildPhase, err := parseResourcesBuildPhase(buildPhaseUUID, objects)
  98. if err != nil {
  99. return resourcesBuildPhase{}, fmt.Errorf("failed to parse ResourcesBuildPhase, error: %s", err)
  100. }
  101. return buildPhase, nil
  102. }
  103. }
  104. return resourcesBuildPhase{}, fmt.Errorf("resource build phase not found")
  105. }
  106. func filterAssetCatalogs(buildPhase resourcesBuildPhase, projectID string, objects serialized.Object) ([]fileReference, error) {
  107. assetCatalogs := []fileReference{}
  108. for _, fileUUID := range buildPhase.files {
  109. buildFile, err := parseBuildFile(fileUUID, objects)
  110. if err != nil {
  111. // ignore:
  112. // D0177B971F26869C0044446D /* (null) in Resources */ = {isa = PBXBuildFile; };
  113. continue
  114. }
  115. // can be PBXVariantGroup or PBXFileReference
  116. rawElement, err := objects.Object(buildFile.fileRef)
  117. if err != nil {
  118. return nil, err
  119. }
  120. if ok, err := isFileReference(rawElement); err != nil {
  121. return nil, err
  122. } else if !ok {
  123. // ignore PBXVariantGroup
  124. continue
  125. }
  126. fileReference, err := parseFileReference(buildFile.fileRef, objects)
  127. if err != nil {
  128. return nil, err
  129. }
  130. if strings.HasSuffix(fileReference.path, ".xcassets") {
  131. assetCatalogs = append(assetCatalogs, fileReference)
  132. }
  133. }
  134. return assetCatalogs, nil
  135. }
  136. func getAppIconSetNames(target Target) []string {
  137. const appIconSetNameKey = "ASSETCATALOG_COMPILER_APPICON_NAME"
  138. appIconSetNames := []string{}
  139. for _, configuration := range target.BuildConfigurationList.BuildConfigurations {
  140. appIconSetName, err := configuration.BuildSettings.String(appIconSetNameKey)
  141. if err != nil {
  142. return nil
  143. }
  144. appIconSetNames = append(appIconSetNames, appIconSetName)
  145. }
  146. return appIconSetNames
  147. }