Merge remote-tracking branch 'upstream/dev' into feature/groups-rebuild

# Conflicts:
#	Session.xcodeproj/project.pbxproj
#	Session/Conversations/ConversationVC+Interaction.swift
#	Session/Conversations/ConversationViewModel.swift
#	Session/Media Viewing & Editing/GIFs/GifPickerCell.swift
#	Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift
#	Session/Media Viewing & Editing/PhotoCapture.swift
#	Session/Media Viewing & Editing/PhotoLibrary.swift
#	Session/Meta/Settings.bundle/Root.plist
#	Session/Meta/Translations/InfoPlist.xcstrings
#	SessionMessagingKit/Database/Models/Attachment.swift
#	SessionMessagingKit/Database/Models/LinkPreview.swift
#	SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift
#	SessionMessagingKitTests/LibSession/LibSessionUtilSpec.swift
#	SessionShareExtension/ShareNavController.swift
#	SessionShareExtension/ThreadPickerVC.swift
#	SessionSnodeKit/LibSession/LibSession+Networking.swift
#	SessionUtilitiesKit/Configuration.swift
#	SessionUtilitiesKit/Media/Data+Image.swift
#	SessionUtilitiesKit/Media/DataSource.swift
#	SignalUtilitiesKit/Configuration.swift
#	SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentApprovalViewController.swift
#	SignalUtilitiesKit/Media Viewing & Editing/Image Editing/ImageEditorModel.swift
#	_SharedTestUtilities/NimbleExtensions.swift
pull/894/head
Morgan Pretty 7 months ago
commit 840e01d847

@ -75,32 +75,9 @@ local sim_delete_cmd = 'if [ -f build/artifacts/sim_uuid ]; then rm -f /Users/$U
name: 'Unit Test Summary',
commands: [
sim_delete_cmd,
|||
if [[ -d ./build/artifacts/testResults.xcresult ]]; then
xcresultparser --output-format cli --failed-tests-only ./build/artifacts/testResults.xcresult
else
echo -e "\n\n\n\e[31;1mUnit test results not found\e[0m"
fi
|||,
],
depends_on: ['Build and Run Tests'],
when: {
status: ['failure', 'success'],
},
},
{
name: 'Install Codecov CLI',
commands: [
'mkdir -p build/artifacts',
'pip3 install codecov-cli',
'find $HOME/Library/Python -name codecovcli -print -quit > ./build/artifacts/codecov_path',
|||
if [[ ! -s ./build/artifacts/codecov_path ]]; then
which codecovcli > ./build/artifacts/codecov_path
fi
|||,
'$(<./build/artifacts/codecov_path) --version',
'xcresultparser --output-format cli --failed-tests-only ./build/artifacts/testResults.xcresult'
],
depends_on: ['Build and Run Tests']
},
{
name: 'Convert xcresult to xml',
@ -109,17 +86,6 @@ local sim_delete_cmd = 'if [ -f build/artifacts/sim_uuid ]; then rm -f /Users/$U
],
depends_on: ['Build and Run Tests'],
},
{
// No token needed for public repos
name: 'Upload coverage to Codecov',
commands: [
'$(<./build/artifacts/codecov_path) upload-process --fail-on-error -f ./build/artifacts/coverage.xml',
],
depends_on: [
'Convert xcresult to xml',
'Install Codecov CLI',
],
},
],
},
// Validate build artifact was created by the direct branch push (PRs only)

@ -1 +1 @@
Subproject commit f19df114e5f4f6c29112f49c0b4897d7b93b78f1
Subproject commit 10f15aeb1f9712452adf55a8d0826be6271c10e4

@ -0,0 +1,150 @@
#!/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)")

@ -311,7 +311,7 @@ enum ScriptAction: String {
return
}
if let data: Data = try? JSONSerialization.data(withJSONObject: updatedInfoPlistJSON, options: [ .fragmentsAllowed ]) {
if let data: Data = try? JSONSerialization.data(withJSONObject: updatedInfoPlistJSON, options: [ .fragmentsAllowed, .sortedKeys ]) {
do {
try data.write(to: URL(fileURLWithPath: projectState.infoPlistLocalizationFile.path), options: [.atomic])
} catch {

@ -1441,6 +1441,7 @@
94367C422C6C828500814252 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
943C6D812B75E061004ACE64 /* Message+DisappearingMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+DisappearingMessages.swift"; sourceTree = "<group>"; };
943C6D832B86B5F1004ACE64 /* Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = "<group>"; };
9471CAA72CACFB4E00090FB7 /* GenerateLicenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateLicenses.swift; sourceTree = "<group>"; };
9473386D2BDF5F3E00B9E169 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = "<group>"; };
947AD68F2C8968FF000B2730 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
94B3DC162AF8592200C88531 /* QuoteView_SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteView_SwiftUI.swift; sourceTree = "<group>"; };
@ -4567,6 +4568,7 @@
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */,
FD5CE3442A3C5D96001A6DE3 /* DecryptExportedKey.swift */,
FDEF57642C44B8C200131302 /* ProcessIP2CountryData.swift */,
9471CAA72CACFB4E00090FB7 /* GenerateLicenses.swift */,
);
path = Scripts;
sourceTree = "<group>";
@ -4829,7 +4831,6 @@
FD5E93D52C12D8120038C25A /* Add Commit Hash To Build Info Plist */,
FD5E93D72C12DA400038C25A /* Add App Group To Build Info Plist */,
FDC498C12AC1775400EDD897 /* Ensure Localizable.strings included */,
943BC5A02C6F26370066A56A /* Ensure InfoPlist.xcstrings updated */,
);
buildRules = (
);
@ -4974,6 +4975,8 @@
FDD82C422A2085B900425F05 /* Add Commit Hash To Build Info Plist */,
FD5E93D32C12D3990038C25A /* Add App Group To Build Info Plist */,
FDC498BF2AC1747900EDD897 /* Ensure Localizable.strings included */,
FD0B1FA92CA3805C00F60F46 /* Ensure InfoPlist.xcstrings updated */,
9471CAA62CACFB0600090FB7 /* Generate Licenses Plist */,
);
buildRules = (
);
@ -5460,7 +5463,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
943BC5A02C6F26370066A56A /* Ensure InfoPlist.xcstrings updated */ = {
FD0B1FA92CA3805C00F60F46 /* Ensure InfoPlist.xcstrings updated */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
@ -5480,6 +5483,26 @@
shellScript = "\"${SRCROOT}/Scripts/LintLocalizableStrings.swift\" update\n";
showEnvVarsInLog = 0;
};
9471CAA62CACFB0600090FB7 /* Generate Licenses Plist */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Generate Licenses Plist";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Scripts/GenerateLicenses.swift\"\n";
showEnvVarsInLog = 0;
};
FD5E93D32C12D3990038C25A /* Add App Group To Build Info Plist */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;

@ -87,8 +87,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/oxen-io/session-grdb-swift",
"state" : {
"revision" : "426149dd868219517df20eebeca27ff385fee34a",
"version" : "106.29.2"
"revision" : "04f480b95263b7c517085100ceb249f879c021d8",
"version" : "106.29.3"
}
},
{

@ -142,7 +142,6 @@ class PhotoCollectionContents {
private func requestImageDataSource(for asset: PHAsset, using dependencies: Dependencies) -> AnyPublisher<(dataSource: (any DataSource), type: UTType), Error> {
return Deferred {
Future { [weak self] resolver in
let options: PHImageRequestOptions = PHImageRequestOptions()
options.isNetworkAccessAllowed = true
@ -173,7 +172,6 @@ class PhotoCollectionContents {
private func requestVideoDataSource(for asset: PHAsset, using dependencies: Dependencies) -> AnyPublisher<(dataSource: (any DataSource), type: UTType), Error> {
return Deferred {
Future { [weak self] resolver in
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true

@ -78,7 +78,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// Configure the different targets
SNUtilitiesKit.configure(
maxFileSize: Network.maxFileSize,
networkMaxFileSize: Network.maxFileSize,
localizedFormatted: { helper, font in SessionSNUIKitConfig.localizedFormatted(helper, font) },
localizedDeformatted: { helper in SessionSNUIKitConfig.localizedDeformatted(helper) },
using: dependencies

@ -8,7 +8,7 @@
<array>
<dict>
<key>File</key>
<string>Dependencies-settings-metadata</string>
<string>ThirdPartyLicenses</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -472,9 +472,9 @@ fileprivate extension LibSessionUtilSpec {
let pushData7: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData7.pointee.seqno).to(equal(3))
let pushData6Str: String = String(pointer: pushData6.pointee.config, length: pushData6.pointee.config_len, encoding: .ascii)!
let pushData7Str: String = String(pointer: pushData7.pointee.config, length: pushData7.pointee.config_len, encoding: .ascii)!
expect(pushData6Str).toNot(equal(pushData7Str))
let pushData6Data: Data = Data(bytes: pushData6.pointee.config, count: pushData6.pointee.config_len)
let pushData7Data: Data = Data(bytes: pushData7.pointee.config, count: pushData7.pointee.config_len)
expect(pushData6Data).toNot(equal(pushData7Data))
expect([String](pointer: pushData6.pointee.obsolete, count: pushData6.pointee.obsolete_len))
.to(equal([fakeHash2]))
expect([String](pointer: pushData7.pointee.obsolete, count: pushData7.pointee.obsolete_len))
@ -515,9 +515,9 @@ fileprivate extension LibSessionUtilSpec {
let pushData9: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData9.pointee.seqno).to(equal(pushData8.pointee.seqno))
let pushData8Str: String = String(pointer: pushData8.pointee.config, length: pushData8.pointee.config_len, encoding: .ascii)!
let pushData9Str: String = String(pointer: pushData9.pointee.config, length: pushData9.pointee.config_len, encoding: .ascii)!
expect(pushData8Str).to(equal(pushData9Str))
let pushData8Data: Data = Data(bytes: pushData8.pointee.config, count: pushData8.pointee.config_len)
let pushData9Data: Data = Data(bytes: pushData9.pointee.config, count: pushData9.pointee.config_len)
expect(pushData8Data).to(equal(pushData9Data))
expect([String](pointer: pushData8.pointee.obsolete, count: pushData8.pointee.obsolete_len))
.to(equal([fakeHash3b, fakeHash3a]))
expect([String](pointer: pushData9.pointee.obsolete, count: pushData9.pointee.obsolete_len))
@ -793,9 +793,9 @@ fileprivate extension LibSessionUtilSpec {
// Since we set different things, we're going to get back different serialized data to be
// pushed:
let pushData3Str: String? = String(pointer: pushData3.pointee.config, length: pushData3.pointee.config_len, encoding: .ascii)
let pushData4Str: String? = String(pointer: pushData4.pointee.config, length: pushData4.pointee.config_len, encoding: .ascii)
expect(pushData3Str).toNot(equal(pushData4Str))
let pushData3Data: Data = Data(bytes: pushData3.pointee.config, count: pushData3.pointee.config_len)
let pushData4Data: Data = Data(bytes: pushData4.pointee.config, count: pushData4.pointee.config_len)
expect(pushData3Data).toNot(equal(pushData4Data))
// Now imagine that each client pushed its `seqno=2` config to the swarm, but then each client
// also fetches new messages and pulls down the other client's `seqno=2` value.

@ -345,7 +345,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// Configure the different targets
SNUtilitiesKit.configure(
maxFileSize: Network.maxFileSize,
networkMaxFileSize: Network.maxFileSize,
localizedFormatted: { helper, font in NSAttributedString() },
localizedDeformatted: { helper in NSENotificationPresenter.localizedDeformatted(helper) },
using: dependencies

@ -60,7 +60,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate {
// Configure the different targets
SNUtilitiesKit.configure(
maxFileSize: Network.maxFileSize,
networkMaxFileSize: Network.maxFileSize,
localizedFormatted: { helper, font in SAESNUIKitConfig.localizedFormatted(helper, font) },
localizedDeformatted: { helper in SAESNUIKitConfig.localizedDeformatted(helper) },
using: dependencies
@ -722,7 +722,6 @@ private extension NSItemProvider {
}
}
// MARK: - SAESNUIKitConfig
private struct SAESNUIKitConfig: SNUIKit.ConfigType {

@ -38,12 +38,12 @@ public enum SNUtilitiesKit: MigratableTarget { // Just to make the external API
}
public static func configure(
maxFileSize: UInt,
networkMaxFileSize: UInt,
localizedFormatted: @escaping (LocalizationHelper, UIFont) -> NSAttributedString,
localizedDeformatted: @escaping (LocalizationHelper) -> String,
using dependencies: Dependencies
) {
self.maxFileSize = maxFileSize
self.maxFileSize = networkMaxFileSize
self.localizedFormatted = localizedFormatted
self.localizedDeformatted = localizedDeformatted
}

@ -91,8 +91,8 @@ public enum Log {
private static var pendingStartupLogs: Atomic<[LogInfo]> = Atomic([])
public static func setup(with logger: Logger) {
logger.retrievePendingStartupLogs.mutate {
$0 = {
logger.pendingLogsRetriever.mutate { callback in
callback = {
pendingStartupLogs.mutate { pendingStartupLogs in
let logs: [LogInfo] = pendingStartupLogs
pendingStartupLogs = []
@ -368,7 +368,7 @@ public class Logger {
private let systemLoggers: Atomic<[String: SystemLoggerType]> = Atomic([:])
fileprivate let fileLogger: DDFileLogger
fileprivate let isSuspended: Atomic<Bool> = Atomic(true)
fileprivate let retrievePendingStartupLogs: Atomic<(() -> [Log.LogInfo])?> = Atomic(nil)
fileprivate let pendingLogsRetriever: Atomic<(() -> [Log.LogInfo])?> = Atomic(nil)
public init(
primaryPrefix: String,
@ -509,11 +509,7 @@ public class Logger {
isSuspended = false
// Retrieve any logs that were added during
return retrievePendingStartupLogs.mutate { retriever in
let result: [Log.LogInfo] = (retriever?() ?? [])
retriever = nil
return result
}
return pendingLogsRetriever.mutate { retriever in (retriever?() ?? []) }
}
// If we had an error loading the extension logs then actually log it

Loading…
Cancel
Save