fix(macos): regenerate the app's compose file instead of treating it as a repo's

Config.repoPath fell back to the data directory when no repo clone was
found, and DockerCompose then picked up the compose file it had generated
there as if it belonged to a repo. The generator therefore only ran on
first launch, so upgraded installs kept their original compose, including
the old ghcr.io/gitlawb/node image, which no longer serves anonymous pulls.

repoPath now returns nil when there is no clone, and the app regenerates
its compose file whenever no repo compose is in use. Project directory and
named volumes are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
jatmnandClaude Opus 5.5 committed 2026-11-04 10:15:03 -08:00
1 parent f837d63153
commit e04efe4ec3
2 files changed
+20 -12

No files matched your search

+8 -3
View File
@@ -28,8 +28,13 @@ class Config {
// MARK: - Paths
/// Path to the gitlawb-node repo clone (for local builds).
var repoPath: URL {
/// Path to the gitlawb-node repo clone (for local builds), or nil when there is none.
///
/// Must not fall back to `dataDirectory`: the app writes its generated compose
/// file there, and treating that file as a repo's own would stop it from ever
/// being regenerated, pinning upgraded installs to the compose (and image)
/// they first started with.
var repoPath: URL? {
if !repoPathString.isEmpty {
return URL(fileURLWithPath: repoPathString)
}
@@ -48,7 +53,7 @@ class Config {
FileManager.default.fileExists(atPath: dockerfile.path) {
return repoRoot
}
return dataDirectory
return nil
}
var dataDirectory: URL {
@@ -39,11 +39,11 @@ class DockerCompose {
/// Path to the docker-compose.yml — uses the repo's file if available, otherwise generates one.
var composeFilePath: String {
// Prefer the repo's own docker-compose.yml (supports `build: .`)
let repoCompose = Config.shared.repoPath.appendingPathComponent("docker-compose.yml")
if FileManager.default.fileExists(atPath: repoCompose.path) {
return repoCompose.path
if let repo = repoWithCompose {
return repo.appendingPathComponent("docker-compose.yml").path
}
// Fallback: generate a compose file with pre-built image
// Fallback: (re)generate the compose file with the pre-built image each time,
// so an app upgrade also upgrades the stack it runs.
let userPath = Config.shared.dataDirectory.appendingPathComponent("docker-compose.yml").path
try? FileManager.default.createDirectory(at: Config.shared.dataDirectory, withIntermediateDirectories: true)
let content = Self.generateComposeFile()
@@ -53,11 +53,14 @@ class DockerCompose {
/// Project directory for docker compose (needed for `build: .` context).
var projectDirectory: String {
let repoCompose = Config.shared.repoPath.appendingPathComponent("docker-compose.yml")
if FileManager.default.fileExists(atPath: repoCompose.path) {
return Config.shared.repoPath.path
}
return Config.shared.dataDirectory.path
(repoWithCompose ?? Config.shared.dataDirectory).path
}
/// The repo clone, if there is one and it has its own docker-compose.yml.
private var repoWithCompose: URL? {
guard let repo = Config.shared.repoPath else { return nil }
let compose = repo.appendingPathComponent("docker-compose.yml")
return FileManager.default.fileExists(atPath: compose.path) ? repo : nil
}
/// Path to the .env file with user configuration.