Skip to content

Commit

Permalink
[Fastlane.swift] fixes issues with running on Apple Silicon #18502 (#…
Browse files Browse the repository at this point in the history
…19555)

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Update to swift 5

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Xcode recommedation. Enabling Base Internationalization is recommended for all projects.

* Migrating the “English, deprecated” localization to “English” is recommended for all projects.
   This will ensure localized resources are placed in “en.lproj” directories instead of deprecated “English.lproj” directories.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Xcode recommendation. Enable recommended warnings.
  Implicit retain of self within blocks
  Overriding deprecated Objective-C methods
  Quoted Include in framework header.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Xcode recommendation. Enable code signing. It's recommended for macOS executables. This setting will cause executable's code signature to be trusted by your Mac.
   Currently, macOS on M1 is killing the binary at launch. According to console traces, reason is ASP Security policy would not allow process.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Fix waring Using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Fix waring 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Fix waring Switch covers known cases, but 'DispatchTimeInterval' may have additional unknown values, possibly added in future versions. Handle unknown values using "@unknown default"

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Update protocol generator to use AnyObject

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Update swift package to swift 5

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Fix thread data race using a thread safe storage

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] On verbose mode, allow output from the runner thread. It allows traces and ease feedback from fastlane swift.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Fastlane.Swift] Replace Build Phase - ShellScript with Build Phase - CopyFiles. This allows to copy the executable signed.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Testing] Add some useful help to debug problems on FastlaneSwiftRunner

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Testing] Fix ensure_actions_config_items_formatting

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Fix style

* Update fastlane/lib/fastlane/swift_lane_manager.rb

Include review comments

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>

* Update fastlane/lib/fastlane/swift_lane_manager.rb

Include review comments

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>

* Update Testing.md

Include review comments

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>

* Include review comments

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Replace DispatchQueue with os_unfair_lock as suggested in review.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Stick to swift 4, as suggested by reviewers.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Keep naming to AtomicDictionary as suggested by reviewers.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Fix CI detected error

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Implement subscript as suggested by reviewers.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Restore values previous to this PR

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Integrate the required steps to only upgrade the Xcode project build phase and flags needed.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Fix CI. Package deployment set to macOS 10.12

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Fix CI warnings.

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Add again support for swift-tools-version 4.0 implementing a OSSpinLockAtomicDictionary for macos versions under 10.12

* Add Atomic Dictionary generic capabilities

* [Fastlane.Swift] Swift fastlane does not run on Apple Silicon #18502

* [Swift] Add Atomic.swift to upgrade_manifest.json

* [Fastlane.swift] Overriding doesn't call specialized extensions, fallback to #available

* Cleanup hacky code

Co-authored-by: Roger Oba <rogerluan.oba@gmail.com>
Co-authored-by: Jorge Revuelta Herrero <minuscorp@gmail.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
  • Loading branch information
4 people committed Feb 2, 2022
1 parent bce3bb8 commit 77e732c
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 44 deletions.
4 changes: 4 additions & 0 deletions Testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ If you'd like to see your changes reflect on `FastlaneSwiftRunner`, the Swift se

Do not commit the changes generated by the `generate_swift_api` command, as this is part of the release process of a new version of _fastlane_, so your PR shouldn't include those changes.

If you need to see any output from FastlaneSwiftRunner, activate the flag `--verbose` when launching `FastlaneSwiftRunner` or any of its lanes.

Remember that to debug `FastlaneSwiftRunner` on Xcode, you can set a flag to wait for the executable to be launched by _fastlane_. You can go to next path and set a tick on Scheme → `FastlaneSwiftRunner` → Run → Launch → Wait for the executable to be launched.

<!-- Make sure that this section is the same as the one in `ToolsAndDebugging.md` -->

## Test your local _fastlane_ code base with your setup
Expand Down
2 changes: 1 addition & 1 deletion fastlane/lib/fastlane/swift_fastlane_api_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ def generate_tool_protocol(tool_swift_function: nil)
protocol_content_array = []
protocol_name = tool_swift_function.protocol_name

protocol_content_array << "public protocol #{protocol_name}: class {"
protocol_content_array << "public protocol #{protocol_name}: AnyObject {"
protocol_content_array += tool_swift_function.swift_vars
protocol_content_array << "}"
protocol_content_array << ""
Expand Down
14 changes: 11 additions & 3 deletions fastlane/lib/fastlane/swift_lane_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def self.cruise_lane(lane, parameters = nil, env = nil, disable_runner_upgrades:
# wait on socket_thread to be in ready state, then start the runner thread
self.cruise_swift_lane_in_thread(lane, parameters, swift_server_port)

socket_thread.join
socket_thread.value
rescue Exception => ex # rubocop:disable Lint/RescueException
e = ex
end
Expand Down Expand Up @@ -74,7 +74,10 @@ def self.cruise_lane(lane, parameters = nil, env = nil, disable_runner_upgrades:

def self.display_lanes
self.ensure_runner_built!
Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lanes))
return_value = Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lanes))
if FastlaneCore::Globals.verbose?
UI.message("runner output: ".yellow + return_value)
end
end

def self.cruise_swift_lane_in_thread(lane, parameters = nil, swift_server_port)
Expand All @@ -94,7 +97,12 @@ def self.cruise_swift_lane_in_thread(lane, parameters = nil, swift_server_port)
parameter_string += " swiftServerPort #{swift_server_port}"

return Thread.new do
Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lane #{lane}#{parameter_string} > /dev/null))
if FastlaneCore::Globals.verbose?
return_value = Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lane #{lane}#{parameter_string}))
UI.message("runner output: ".yellow + return_value)
else
Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lane #{lane}#{parameter_string} > /dev/null))
end
end
end

Expand Down
56 changes: 55 additions & 1 deletion fastlane/lib/fastlane/swift_runner_upgrader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def initialize
end

def upgrade_if_needed!(dry_run: false)
upgraded = add_missing_groups_and_files!(dry_run: dry_run)
upgraded = add_missing_flags!(dry_run: dry_run)
upgraded = add_missing_copy_phase!(dry_run: dry_run) || upgraded
upgraded = add_missing_groups_and_files!(dry_run: dry_run) || upgraded
upgraded = upgrade_files!(dry_run: dry_run) || upgraded
upgraded = add_new_files_to_groups! || upgraded

Expand Down Expand Up @@ -208,5 +210,57 @@ def add_missing_groups_and_files!(dry_run: false)

return true # yup, we definitely updated groups
end

# adds build_settings flags to fastlane_runner_target
def add_missing_flags!(dry_run: false)
# Check if upgrade is needed
# If fastlane build settings exists already, we don't need any more changes to the Xcode project
self.fastlane_runner_target.build_configurations.each { |config|
return false if dry_run && config.build_settings["CODE_SIGN_IDENTITY"].nil?
return false if dry_run && config.build_settings["MACOSX_DEPLOYMENT_TARGET"].nil?
}
return true if dry_run

# Proceed to upgrade
self.fastlane_runner_target.build_configurations.each { |config|
config.build_settings["CODE_SIGN_IDENTITY"] = "-"
config.build_settings["MACOSX_DEPLOYMENT_TARGET"] = "10.12"
}
target_project.save
end

# adds new copy files build phase to fastlane_runner_target
def add_missing_copy_phase!(dry_run: false)
# Check if upgrade is needed
# If fastlane copy files build phase exists already, we don't need any more changes to the Xcode project
phase_copy_sign = self.fastlane_runner_target.copy_files_build_phases.select { |phase_copy| phase_copy.name == "FastlaneRunnerCopySigned" }.first

old_phase_copy_sign = self.fastlane_runner_target.shell_script_build_phases.select { |phase_copy| phase_copy.shell_script == "cd \"${SRCROOT}\"\ncd ../..\ncp \"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\" .\n" }.first
unless phase_copy_sign
return false if dry_run
end

return true if dry_run

# Proceed to upgrade
old_phase_copy_sign.remove_from_project unless old_phase_copy_sign.nil?

unless phase_copy_sign
# Create a copy files build phase
phase_copy_sign = self.fastlane_runner_target.new_copy_files_build_phase("FastlaneRunnerCopySigned")
phase_copy_sign.dst_path = "$SRCROOT/../.."
phase_copy_sign.dst_subfolder_spec = "0"
phase_copy_sign.run_only_for_deployment_postprocessing = "0"
targetBinaryReference = self.fastlane_runner_target.product_reference
phase_copy_sign.add_file_reference(targetBinaryReference)

# Set "Code sign on copy" flag on Xcode for fastlane_runner_target
targetBinaryReference.build_files.each { |target_binary_build_file_reference|
target_binary_build_file_reference.settings = { "ATTRIBUTES": ["CodeSignOnCopy"] }
}
end

target_project.save
end
end
end
151 changes: 151 additions & 0 deletions fastlane/swift/Atomic.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Atomic.swift
// Copyright (c) 2021 FastlaneTools

import Foundation

protocol DictionaryProtocol: class {
associatedtype Key: Hashable
associatedtype Value

subscript(_: Key) -> Value? { get set }

@discardableResult
func removeValue(forKey key: Key) -> Value?

func get(_ key: Key) -> Value?
func set(_ key: Key, value: Value?)
}

extension DictionaryProtocol {
subscript(_ key: Key) -> Value? {
get {
get(key)
}
set {
set(key, value: newValue)
}
}
}

protocol LockProtocol: DictionaryProtocol {
associatedtype Lock

var _lock: Lock { get set }

func lock()
func unlock()
}

protocol AnyLock {}

extension UnsafeMutablePointer: AnyLock {
@available(macOS, deprecated: 10.12)
static func make() -> Self where Pointee == OSSpinLock {
let spin = UnsafeMutablePointer<OSSpinLock>.allocate(capacity: 1)
spin.initialize(to: OS_SPINLOCK_INIT)
return spin
}

@available(macOS, introduced: 10.12)
static func make() -> Self where Pointee == os_unfair_lock {
let unfairLock = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
unfairLock.initialize(to: os_unfair_lock())
return unfairLock
}

@available(macOS, deprecated: 10.12)
static func lock(_ lock: Self) where Pointee == OSSpinLock {
OSSpinLockLock(lock)
}

@available(macOS, deprecated: 10.12)
static func unlock(_ lock: Self) where Pointee == OSSpinLock {
OSSpinLockUnlock(lock)
}

@available(macOS, introduced: 10.12)
static func lock(_ lock: Self) where Pointee == os_unfair_lock {
os_unfair_lock_lock(lock)
}

@available(macOS, introduced: 10.12)
static func unlock(_ lock: Self) where Pointee == os_unfair_lock {
os_unfair_lock_unlock(lock)
}
}

// MARK: - Classes

class AtomicDictionary<Key: Hashable, Value>: LockProtocol {

typealias Lock = AnyLock

var _lock: Lock

private var storage: [Key: Value] = [:]

init(_ lock: Lock) {
self._lock = lock
}

@discardableResult
func removeValue(forKey key: Key) -> Value? {
lock()
defer { unlock() }
return storage.removeValue(forKey: key)
}

func get(_ key: Key) -> Value? {
lock()
defer { unlock() }
return storage[key]
}

func set(_ key: Key, value: Value?) {
lock()
defer { unlock() }
storage[key] = value
}

func lock() {
fatalError()
}

func unlock() {
fatalError()
}
}

@available(macOS, introduced: 10.12)
final class UnfairAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
typealias Lock = UnsafeMutablePointer<os_unfair_lock>

init() {
super.init(Lock.make())
}

override func lock() {
Lock.lock(_lock as! Lock)
}

override func unlock() {
Lock.unlock(_lock as! Lock)
}
}

@available(macOS, deprecated: 10.12)
final class OSSPinAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
typealias Lock = UnsafeMutablePointer<OSSpinLock>

init() {
super.init(Lock.make())
}

override func lock() {
Lock.lock(_lock as! Lock)
}

override func unlock() {
Lock.unlock(_lock as! Lock)
}
}
2 changes: 1 addition & 1 deletion fastlane/swift/DeliverfileProtocol.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// DeliverfileProtocol.swift
// Copyright (c) 2022 FastlaneTools

public protocol DeliverfileProtocol: class {
public protocol DeliverfileProtocol: AnyObject {
/// Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
var apiKeyPath: String? { get }

Expand Down
Loading

0 comments on commit 77e732c

Please sign in to comment.