mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			151 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			151 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Swift
		
	
| #!/usr/bin/xcrun --sdk macosx swift
 | |
| 
 | |
| // Copyright © 2024 Rangeproof Pty Ltd. All rights reserved.
 | |
| //
 | |
| // stringlint:disable
 | |
| 
 | |
| import Foundation
 | |
| 
 | |
| // Get the Derived Data path and the project's name
 | |
| let derivedDataPath = getDerivedDataPath() ?? ""
 | |
| let projectName = ProcessInfo.processInfo.environment["PROJECT_NAME"] ?? ""
 | |
| let projectPath = ProcessInfo.processInfo.environment["PROJECT_DIR"] ?? FileManager.default.currentDirectoryPath
 | |
| 
 | |
| let packageResolutionFilePath = "\(projectPath)/\(projectName).xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved"
 | |
| let packageCheckoutsPath = "\(derivedDataPath)/SourcePackages/checkouts/"
 | |
| let packageArtifactsPath = "\(derivedDataPath)/SourcePackages/artifacts/"
 | |
| 
 | |
| func getDerivedDataPath() -> String? {
 | |
|     // Define the regular expression pattern to extract the DerivedData path
 | |
|     let regexPattern = ".*DerivedData/[^/]*"
 | |
|     guard
 | |
|         let buildDir = ProcessInfo.processInfo.environment["BUILD_DIR"],
 | |
|         let regex = try? NSRegularExpression(pattern: regexPattern)
 | |
|     else { return nil }
 | |
|     
 | |
|     let range = NSRange(location: 0, length: buildDir.utf16.count)
 | |
|     
 | |
|     // Perform the regex matching
 | |
|     if let match = regex.firstMatch(in: buildDir, options: [], range: range) {
 | |
|         // Extract the matching portion (the DerivedData path)
 | |
|         if let range = Range(match.range, in: buildDir) {
 | |
|             return String(buildDir[range])
 | |
|         }
 | |
|     } else {
 | |
|         print("No DerivedData path found in BUILD_DIR")
 | |
|     }
 | |
|     
 | |
|     return nil
 | |
| }
 | |
| 
 | |
| // Function to list all directories (Swift package checkouts) inside the SourcePackages/checkouts directory
 | |
| func listDirectories(atPath path: String) -> [String] {
 | |
|     let fileManager = FileManager.default
 | |
|     do {
 | |
|         let items = try fileManager.contentsOfDirectory(atPath: path)
 | |
|         return items.filter { item in
 | |
|             var isDir: ObjCBool = false
 | |
|             let fullPath = path + "/" + item
 | |
|             return fileManager.fileExists(atPath: fullPath, isDirectory: &isDir) && isDir.boolValue
 | |
|         }
 | |
|     } catch {
 | |
|         print("Error reading contents of directory: \(error)")
 | |
|         return []
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Function to find and read LICENSE files in each package
 | |
| func findLicenses(in packagesPath: String) -> [(package: String, licenseContent: String)] {
 | |
|     var licenses: [(package: String, licenseContent: String)] = []
 | |
|     let packages: [String] = listDirectories(atPath: packagesPath)
 | |
|     
 | |
|     print("\(packages.count) packages found in \(packagesPath)")
 | |
| 
 | |
|     packages.forEach { package in
 | |
|         let packagePath = "\(packagesPath)/\(package)"
 | |
|         scanDirectory(atPath: packagePath) { filePath in
 | |
|             if filePath.lowercased().contains("license") || filePath.lowercased().contains("copying") {
 | |
|                 if let licenseContent = try? String(contentsOfFile: filePath, encoding: .utf8) {
 | |
|                     licenses.append((package, licenseContent))
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return licenses
 | |
| }
 | |
| 
 | |
| func findPackageDependencyNames(in resolutionFilePath: String) throws -> Set<String> {
 | |
|     struct ResolvedPackages: Codable {
 | |
|         struct Pin: Codable {
 | |
|             struct State: Codable {
 | |
|                 let revision: String
 | |
|                 let version: String
 | |
|             }
 | |
|             
 | |
|             let identity: String
 | |
|             let kind: String
 | |
|             let location: String
 | |
|             let state: State
 | |
|         }
 | |
|         
 | |
|         let originHash: String
 | |
|         let pins: [Pin]
 | |
|         let version: Int
 | |
|     }
 | |
|     
 | |
|     do {
 | |
|         let data: Data = try Data(contentsOf: URL(fileURLWithPath: resolutionFilePath))
 | |
|         let resolvedPackages: ResolvedPackages = try JSONDecoder().decode(ResolvedPackages.self, from: data)
 | |
|         
 | |
|         print("Found \(resolvedPackages.pins.count) resolved packages.")
 | |
|         return Set(resolvedPackages.pins.map { $0.identity.lowercased() })
 | |
|     }
 | |
|     catch {
 | |
|         print("error: Failed to load list of resolved packages")
 | |
|         throw error
 | |
|     }
 | |
| }
 | |
| 
 | |
| func scanDirectory(atPath path: String, foundFile: (String) -> Void) {
 | |
|     if let enumerator = FileManager.default.enumerator(atPath: path) {
 | |
|         for case let file as String in enumerator {
 | |
|             let fullPath = "\(path)/\(file)"
 | |
|             if FileManager.default.fileExists(atPath: fullPath, isDirectory: nil) {
 | |
|                 foundFile(fullPath)
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Write licenses to a plist file
 | |
| func writePlist(licenses: [(package: String, licenseContent: String)], resolvedPackageNames: Set<String>, outputPath: String) {
 | |
|     var plistArray: [[String: String]] = []
 | |
|     let finalLicenses: [(package: String, licenseContent: String)] = licenses
 | |
|         .filter { resolvedPackageNames.contains($0.package.lowercased()) }
 | |
|         .sorted(by: { $0.package.lowercased() < $1.package.lowercased() })
 | |
|     
 | |
|     print("\(finalLicenses.count) being written to plist.")
 | |
|     
 | |
|     finalLicenses.forEach { license in
 | |
|         plistArray.append([
 | |
|             "Title": license.package,
 | |
|             "License": license.licenseContent
 | |
|         ])
 | |
|     }
 | |
|     
 | |
|     let plistData = try! PropertyListSerialization.data(fromPropertyList: plistArray, format: .xml, options: 0)
 | |
|     let plistURL = URL(fileURLWithPath: outputPath)
 | |
|     try? plistData.write(to: plistURL)
 | |
| }
 | |
| 
 | |
| // Execute the license discovery process
 | |
| let licenses = findLicenses(in: packageCheckoutsPath) + findLicenses(in: packageArtifactsPath)
 | |
| let resolvedPackageNames = try findPackageDependencyNames(in: packageResolutionFilePath)
 | |
| 
 | |
| // Specify the path for the output plist
 | |
| let outputPlistPath = "\(projectPath)/\(projectName)/Meta/Settings.bundle/ThirdPartyLicenses.plist"
 | |
| writePlist(licenses: licenses, resolvedPackageNames: resolvedPackageNames, outputPath: outputPlistPath)
 | |
| 
 | |
| print("Licenses generated successfully at \(outputPlistPath)")
 |