summaryrefslogtreecommitdiff
path: root/Omni/Bild.hs
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-12-16 08:06:09 -0500
committerBen Sima <ben@bensima.com>2025-12-16 08:06:09 -0500
commita7dcb30c7a465d9fce72b7fc3e605470b2b59814 (patch)
tree57a6436de34062773483dbd0cb745ac103c6bb48 /Omni/Bild.hs
parent4caefe45756fdc21df990b8d6e826c40db1b9c78 (diff)
feat(deploy): Complete mini-PaaS deployment system (t-266)
- Add Omni/Deploy/ with Manifest, Deployer, Systemd, Caddy modules - Manifest CLI: show, update, add-service, list, rollback commands - Deployer: polls S3 manifest, pulls closures, manages systemd units - Caddy integration for dynamic reverse proxy routes - bild: auto-cache to S3, outputs STORE_PATH for push.sh - push.sh: supports both NixOS and service deploys - Biz.nix: simplified to base OS + deployer only - Services (podcastitlater-web/worker) now deployer-managed - Documentation: README.md with operations guide
Diffstat (limited to 'Omni/Bild.hs')
-rw-r--r--Omni/Bild.hs60
1 files changed, 49 insertions, 11 deletions
diff --git a/Omni/Bild.hs b/Omni/Bild.hs
index e1f5c46..1ebeb05 100644
--- a/Omni/Bild.hs
+++ b/Omni/Bild.hs
@@ -249,7 +249,7 @@ move args = do
forM_ skippedNamespaces <| \ns -> LogC.updateLineState ns LogC.Skipped
action
runWithManager <| do
- pipelineBuild isTest isLoud 8 jobs (cpus nproc) namespaces analyzeOne
+ pipelineBuild isTest isLoud (not noCache) 8 jobs (cpus nproc) namespaces analyzeOne
|> Timeout.timeout (toMillis minutes)
+> \case
Nothing ->
@@ -285,6 +285,7 @@ move args = do
Just n -> n
isTest = args `Cli.has` Cli.longOption "test"
isLoud = args `Cli.has` Cli.longOption "loud"
+ noCache = args `Cli.has` Cli.longOption "no-cache"
putJSON = Aeson.encode .> ByteString.Lazy.toStrict .> Char8.putStrLn
-- | Don't try to build stuff that isn't part of the git repo.
@@ -363,6 +364,7 @@ Options:
--test, -t Run tests on a target after building
--loud, -l Show all output from compiler
--plan, -p Print the build plan as JSON, don't build
+ --no-cache Skip signing and pushing to S3 binary cache
--time N Set timeout to N minutes, 0 means never timeout [default: 10]
--jobs N, -j N Build up to N jobs at once [default: 6]
--cpus N, -c N Allocate up to N cpu cores per job (default: (nproc-4)/jobs)
@@ -1297,8 +1299,8 @@ pipelineAnalysisWorker coord@Coordinator {..} analyzeFn = loop
else modifyTVar' coStates (Map.insert ns (TSWaitingForDeps target pendingDeps))
loop
-pipelineBuildWorker :: Bool -> Bool -> Int -> Int -> Coordinator -> IO ()
-pipelineBuildWorker andTest loud jobs cpus coord@Coordinator {..} = loop
+pipelineBuildWorker :: Bool -> Bool -> Bool -> Int -> Int -> Coordinator -> IO ()
+pipelineBuildWorker andTest loud andCache jobs cpus coord@Coordinator {..} = loop
where
loop = do
remaining <- readTVarIO coRemaining
@@ -1319,7 +1321,7 @@ pipelineBuildWorker andTest loud jobs cpus coord@Coordinator {..} = loop
Nothing -> loop
Just target -> do
LogC.updateLineState ns LogC.Building
- exitCode <- pipelineBuildOne andTest loud jobs cpus target
+ exitCode <- pipelineBuildOne andTest loud andCache jobs cpus target
atomically <| do
modifyTVar' coStates (Map.insert ns (TSComplete target exitCode))
modifyTVar' coResults (exitCode :)
@@ -1342,8 +1344,8 @@ promoteWaiters Coordinator {..} completedNs = do
else modifyTVar' coStates (Map.insert ns (TSWaitingForDeps target deps'))
_ -> pure ()
-pipelineBuildOne :: Bool -> Bool -> Int -> Int -> Target -> IO Exit.ExitCode
-pipelineBuildOne andTest loud jobs cpus target@Target {..} = do
+pipelineBuildOne :: Bool -> Bool -> Bool -> Int -> Int -> Target -> IO Exit.ExitCode
+pipelineBuildOne andTest loud andCache jobs cpus target@Target {..} = do
root <- getCoderoot
result <- case compiler of
CPython -> case out of
@@ -1392,14 +1394,50 @@ pipelineBuildOne andTest loud jobs cpus target@Target {..} = do
nixBuild loud jobs cpus target
Sbcl ->
proc loud namespace (toNixFlag compiler) compilerFlags
- pure (fst result)
-
-pipelineBuild :: Bool -> Bool -> Int -> Int -> Int -> [Namespace] -> (Namespace -> IO (Maybe Target)) -> IO [Exit.ExitCode]
-pipelineBuild andTest loud analysisWorkers buildWorkers cpus namespaces analyzeFn = do
+ let exitCode = fst result
+ when (andCache && isSuccess exitCode) <| do
+ storePath <- Dir.canonicalizePath (nixdir </> outname out)
+ cacheStorePath loud namespace storePath
+ pure exitCode
+
+cacheStorePath :: Bool -> Namespace -> FilePath -> IO ()
+cacheStorePath loud ns storePath = do
+ mKeyPath <- Env.lookupEnv "NIX_CACHE_KEY"
+ case mKeyPath of
+ Nothing -> Log.warn ["cache", "NIX_CACHE_KEY not set, skipping"]
+ Just keyPath -> do
+ let s3Url = "s3://omni-nix-cache?profile=digitalocean&scheme=https&endpoint=nyc3.digitaloceanspaces.com"
+ LogC.updateLine ns "signing..."
+ (signExit, _, signErr) <-
+ Process.readProcessWithExitCode
+ "nix"
+ ["store", "sign", "--key-file", keyPath, storePath]
+ ""
+ case signExit of
+ Exit.ExitSuccess -> do
+ LogC.updateLine ns "pushing to cache..."
+ (pushExit, _, pushErr) <-
+ Process.readProcessWithExitCode
+ "nix"
+ ["copy", "--to", s3Url, storePath]
+ ""
+ case pushExit of
+ Exit.ExitSuccess -> do
+ loud ?| Log.good ["cache", "pushed", Text.pack storePath]
+ Text.IO.putStrLn <| "STORE_PATH=" <> Text.pack storePath
+ Exit.ExitFailure _ -> do
+ Log.fail ["cache", "push failed", Text.pack storePath]
+ loud ?| putStrLn pushErr
+ Exit.ExitFailure _ -> do
+ Log.fail ["cache", "sign failed", Text.pack storePath]
+ loud ?| putStrLn signErr
+
+pipelineBuild :: Bool -> Bool -> Bool -> Int -> Int -> Int -> [Namespace] -> (Namespace -> IO (Maybe Target)) -> IO [Exit.ExitCode]
+pipelineBuild andTest loud andCache analysisWorkers buildWorkers cpus namespaces analyzeFn = do
root <- getCoderoot
coord <- initCoordinator root namespaces
let spawnAnalysis = replicateM analysisWorkers (Async.async (pipelineAnalysisWorker coord analyzeFn))
- let spawnBuild = replicateM buildWorkers (Async.async (pipelineBuildWorker andTest loud buildWorkers cpus coord))
+ let spawnBuild = replicateM buildWorkers (Async.async (pipelineBuildWorker andTest loud andCache buildWorkers cpus coord))
threads <- (<>) </ spawnAnalysis <*> spawnBuild
let waitLoop = do
remaining <- readTVarIO (coRemaining coord)