Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a9547d7
Add FreeBSD platform support
Jun 20, 2026
f64d756
FreeBSD: fix CA cert paths and enable test mocks
Jun 20, 2026
4f25b50
FreeBSD: use .when(platforms: [.custom("freebsd")]) for FreeBSDPlatfo…
yarshure Jun 21, 2026
109b2db
FreeBSD: handle FreeBSD in SelfUpdate instead of trapping
yarshure Jun 21, 2026
8317a43
FreeBSD: add FreeBSD to platform mock data and platformDef lookup
yarshure Jun 23, 2026
ab476a6
CI: add FreeBSD aarch64 test job via Cloudflare Tunnel
yarshure Jun 24, 2026
a9569be
CI: fix SSH config setup (use env vars + printf, avoid heredoc)
yarshure Jun 24, 2026
365c193
CI: pre-create build dir on board before rsync
yarshure Jun 24, 2026
d90c618
CI: switch cloudflared access ssh → tcp (no Access auth needed)
yarshure Jun 24, 2026
3fc010f
CI: debug - simplify Build step to ssh uname with -v
yarshure Jun 24, 2026
25bf1b5
FreeBSDPlatform: apply swiftformat (pre-existing style issues)
yarshure Jun 24, 2026
9f211af
FreeBSDPlatform: reformat with swiftformat 0.49.18 (matches CI version)
yarshure Jun 24, 2026
c541769
CI: run swift test on FreeBSD aarch64 via Cloudflare tunnel
yarshure Jun 24, 2026
64341de
CI: fix FreeBSD shell (tcsh→sh) and swiftformat indent
yarshure Jun 24, 2026
b532ac5
CI: force-include sys/time.h for BoringSSL on FreeBSD
yarshure Jun 24, 2026
df18aee
CI: patch CNIOBoringSSL ssl_lib.cc for FreeBSD gettimeofday
yarshure Jun 24, 2026
bb850fb
CI: patch swift-log Locks.swift for FreeBSD pthread opaque types
yarshure Jun 24, 2026
a7e6a2d
CI: fix ReadWriteLock rwlock pointer type on FreeBSD
yarshure Jun 24, 2026
2f744fc
CI: fix YAML indentation bug in Locks.swift patch step
yarshure Jun 24, 2026
9acccf2
CI: patch all Locks.swift copies for FreeBSD pthread opaque types
yarshure Jun 24, 2026
424017c
CI: patch swift-log Logging.swift for non-optional stdout/stderr on F…
yarshure Jun 24, 2026
51a00f3
CI: extend lock patch to NIOLock.swift and fix LockPrimitive typealias
yarshure Jun 24, 2026
e6c2ce1
CI: fix ssl_lib.cc patch to use awk + angle-bracket system include
yarshure Jun 24, 2026
8a5e1be
CI: fix pthread_mutexattr_t() init in NIOLock.swift without OpenBSD b…
yarshure Jun 24, 2026
c2ff794
CI: fix ssl_lib.cc gettimeofday by injecting include at line 1
yarshure Jun 24, 2026
aa5ccc5
CI: fix gettimeofday - define _XOPEN_SOURCE 600 before sys/time.h
yarshure Jun 24, 2026
0f1f45e
CI: patch swift-subprocess Thread.swift pthread typealias for FreeBSD
yarshure Jun 24, 2026
de025de
CI: forward-declare getentropy for FreeBSD in getentropy.cc
yarshure Jun 24, 2026
0b67b0d
CI: fix pthread_t() init in Thread.swift for FreeBSD
yarshure Jun 24, 2026
4b6471d
CI: fix pthread_t in Thread.swift - exclude FreeBSD from canImport(Gl…
yarshure Jun 24, 2026
ae995fe
CI: trigger FreeBSD aarch64 job for pthread_t? fix
yarshure Jun 24, 2026
fb237ca
CI: add workflow_dispatch trigger for manual runs
yarshure Jun 24, 2026
acc821d
CI: re-trigger after PR reopen
yarshure Jun 24, 2026
da8a452
FreeBSDPlatform: address jakepetroules review feedback
yarshure Jun 25, 2026
0f6df5c
tests: replace Foundation.Process with Subprocess to fix FreeBSD SIGTRAP
yarshure Jun 25, 2026
616193e
ci: update FreeBSD CI workflow to v2 — dual-board, CA certs, cleanup
yarshure Jun 25, 2026
9a94218
ci: fix Subprocess.run hang on FreeBSD 15.1 (kqueue EVFILT_PROC race)
yarshure Jun 25, 2026
2927a00
Drop board-specific FreeBSD CI job from PR — keep it out of the platf…
networkextension Jun 30, 2026
e5a0660
Merge upstream/main into freebsd-platform
yarshure Aug 17, 2026
0f20a86
Tests: migrate version() to the Subprocess 1.0.0 non-optional standar…
yarshure Aug 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ let package = Package(
.target(name: "SwiftlyCore"),
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
.target(name: "FreeBSDPlatform", condition: .when(platforms: [.custom("freebsd")])),
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
.product(name: "SystemPackage", package: "swift-system"),
],
Expand All @@ -55,6 +56,7 @@ let package = Package(
.target(name: "SwiftlyCore"),
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
.target(name: "FreeBSDPlatform", condition: .when(platforms: [.custom("freebsd")])),
],
swiftSettings: swiftSettings
),
Expand Down Expand Up @@ -138,6 +140,7 @@ let package = Package(
.target(name: "SwiftlyCore"),
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
.target(name: "FreeBSDPlatform", condition: .when(platforms: [.custom("freebsd")])),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "_NIOFileSystem", package: "swift-nio"),
],
Expand All @@ -164,6 +167,18 @@ let package = Package(
],
swiftSettings: swiftSettings
),
.target(
name: "FreeBSDPlatform",
dependencies: [
"SwiftlyCore",
"CLibArchive",
.product(name: "SystemPackage", package: "swift-system"),
],
swiftSettings: swiftSettings,
linkerSettings: [
.linkedLibrary("z"),
]
),
.systemLibrary(
name: "CLibArchive",
pkgConfig: "libarchive",
Expand Down
104 changes: 104 additions & 0 deletions Sources/FreeBSDPlatform/Extract.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#if os(FreeBSD)
import CLibArchive
import Foundation
import SystemPackage

// The code in this file consists mainly of a Swift port of the "Complete Extractor" example included in the libarchive
// documentation: https://github.com/libarchive/libarchive/wiki/Examples#a-complete-extractor

struct ExtractError: Error {
let message: String?

init(archive: OpaquePointer?) {
self.message = archive_error_string(archive).map { err in
String(cString: err)
}
}

init(message: String) {
self.message = message
}
}

/// Write the data from the given readArchive into the writeArchive.
func copyData(readArchive: OpaquePointer?, writeArchive: OpaquePointer?) throws {
var r = 0
var buff: UnsafeRawPointer?
var size = 0
var offset: Int64 = 0

while true {
r = Int(archive_read_data_block(readArchive, &buff, &size, &offset))
if r == ARCHIVE_EOF {
return
}
guard r == ARCHIVE_OK else {
throw ExtractError(archive: readArchive)
}
r = Int(archive_write_data_block(writeArchive, buff, size, offset))
guard r == ARCHIVE_OK else {
throw ExtractError(archive: writeArchive)
}
}
}

/// Extract the archive at the provided path. The name of each file included in the archive will be passed to
/// the provided closure which will return the path the file will be written to.
///
/// This uses libarchive under the hood, so a wide variety of archive formats are supported (e.g. .tar.gz).
func extractArchive(atPath archivePath: FilePath, transform: (String) -> FilePath) throws {
var flags = Int32(0)
flags = ARCHIVE_EXTRACT_TIME
flags |= ARCHIVE_EXTRACT_PERM
flags |= ARCHIVE_EXTRACT_ACL
flags |= ARCHIVE_EXTRACT_FFLAGS

let a = archive_read_new()
archive_read_support_format_all(a)
archive_read_support_filter_all(a)

let ext = archive_write_disk_new()
archive_write_disk_set_options(ext, flags)
archive_write_disk_set_standard_lookup(ext)

defer {
archive_read_close(a)
archive_read_free(a)
archive_write_close(ext)
archive_write_free(ext)
}

if archive_read_open_filename(a, archivePath.string, 10240) != 0 {
throw ExtractError(message: "Failed to open \"\(archivePath)\"")
}

while true {
var r = Int32(0)
var entry: OpaquePointer?
r = archive_read_next_header(a, &entry)
if r == ARCHIVE_EOF {
break
}
guard r == ARCHIVE_OK else {
throw ExtractError(archive: a)
}

let currentPath = String(cString: archive_entry_pathname(entry))
archive_entry_set_pathname(entry, transform(currentPath).string)
r = archive_write_header(ext, entry)
guard r == ARCHIVE_OK else {
throw ExtractError(archive: ext)
}

if archive_entry_size(entry) > 0 {
try copyData(readArchive: a, writeArchive: ext)
}

r = archive_write_finish_entry(ext)
guard r == ARCHIVE_OK else {
throw ExtractError(archive: ext)
}
}
}

#endif
Loading