Skip to content

Tech stack

Language: Go for core + CLI, Swift for host app and File Provider Extension

After explicit evaluation of Go vs Rust, we chose Go:

Criterion Go Rust
Familiar to maintainer Yes (Sam) No (would be learning project)
Azure SDK maturity azidentity GA, msal-go mature azure_identity preview/beta
MSAL maturity msal-go is the official Microsoft library Community crates only
Compile time / iteration Fast Slow
FFI to Swift cgo, slightly rough cbindgen + C-ABI, cleaner
File-provider-like memory safety wins Limited (GC, race detector helps) Strong (compile-time guarantees)
Async story Goroutines, simple tokio, sharper learning curve
Time to first MVP Faster Slower (4-6 weeks ramp-up)

Rust was the riskier "learning opportunity" path; Go is the safer "ship the product" path. Both can do FUSE-T integration (relevant only if we ever revisit) and FFI to Swift. Sam confirmed Go.

The macOS .app host and the File Provider Extension must be in Swift (or Objective-C). The Go core ships as a static library (libofemcore.a) plus a generated C header (via cgo's //export directives) that Swift imports.

Go libraries

Authentication

HTTP & OneLake

  • net/http from stdlib for the OneLake DFS calls. Custom client wrapper for:
  • Token injection (Authorization: Bearer …).
  • Retry-After honoring on 429 / 503.
  • Per-account concurrency limiter (default 4, configurable).
  • github.com/hashicorp/go-retryablehttp — battle-tested retry wrapper that respects Retry-After.
  • Native JSON via stdlib encoding/json (no need for a faster JSON lib at our volume).

CLI

Config & data

Logging

  • log/slog from stdlib (Go 1.21+). Structured logging with JSON or text handler. No external dependency.
  • Log files in ~/Library/Logs/dev.debruyn.ofem/ofem.log, rotated with gopkg.in/natefinch/lumberjack.v2.

Telemetry

IPC (CLI ↔ daemon)

  • net.Listen("unix", …) from stdlib for the Unix domain socket.
  • JSON-RPC 2.0 over the socket using net/rpc/jsonrpc from stdlib, or a lightweight custom protocol if jsonrpc proves limiting.

LaunchAgent

  • We ship a dev.debruyn.ofem.plist template. The CLI writes the resolved plist to ~/Library/LaunchAgents/ and runs launchctl bootstrap gui/$UID … to register it. No external dependency needed.

Testing

  • testing from stdlib.
  • github.com/stretchr/testify for assertions and table-driven test ergonomics.
  • github.com/jarcoal/httpmock for HTTP-level mocking of OneLake responses in unit tests.
  • Integration tests use a real Fabric workspace dedicated to OFEM testing, gated behind an env var OFEM_INTEGRATION=1 so they only run when explicitly requested.

Code quality

Swift libraries

Host app

  • SwiftUI (macOS 14+ baseline) for the account-management UI in Phase 2.
  • Sparkle is not used — updates are Homebrew-only by decision.

File Provider Extension

  • Apple's FileProvider framework (built-in).
  • Apple's os.log for unified logging that integrates with Console.app.

Bridge to Go

  • cgo's //export Foo produces Foo symbols callable from C. We generate a header libofemcore.h during go build -buildmode=c-archive.
  • Swift imports libofemcore.h via a bridging header.
  • All callbacks across the boundary use C primitives (char*, int64_t, opaque pointers) — no Go strings or Swift String directly.

Build & release

  • GoReleaser builds the Go binaries.
  • A separate xcodebuild step builds the Swift .app and .appex, linking against the Go static library.
  • codesign --force --options runtime --sign "Developer ID Application: …".
  • xcrun notarytool submit … --wait and xcrun stapler staple.
  • DMG via create-dmg (Homebrew formula create-dmg).
  • GoReleaser uploads the DMG to GitHub Releases and bumps the cask in the homebrew-ofem tap repo.

See docs/packaging-homebrew.md for the full pipeline.

Repository layout (planned)

onelake-explorer-macos/
├── cmd/
│   └── ofem/                 # CLI entrypoint (main package)
├── internal/
│   ├── auth/                # MSAL wrapper, Keychain cache, account registry
│   ├── onelake/             # DFS API client, retries, pagination
│   ├── fabric/              # Fabric REST API client (discovery)
│   ├── cache/               # SQLite metadata cache, LRU eviction
│   ├── sync/                # Sync engine, write queue, conflict resolution
│   ├── ipc/                 # Unix socket server + client
│   ├── telemetry/           # App Insights client
│   ├── config/              # TOML config loading
│   └── log/                 # slog setup, lumberjack rotation
├── core/                    # cgo-exported façade for Swift
│   ├── core.go              # //export symbols
│   └── core.h               # generated
├── apple/
│   ├── OneLake.xcodeproj
│   ├── OneLake/             # host app (Swift)
│   └── OneLakeFileProvider/ # extension (.appex, Swift)
├── docs/
├── homebrew/
│   └── ofem.rb               # cask template, updated by GoReleaser
├── .github/
├── .goreleaser.yaml
├── go.mod
├── go.sum
├── LICENSE
├── README.md
├── CONTRIBUTING.md
├── SECURITY.md
├── CODE_OF_CONDUCT.md
├── CHANGELOG.md
├── CLAUDE.md
└── PLAN.md