@@ -65,6 +65,7 @@ public structure LakeOptions where
6565 outFormat : OutFormat := .text
6666 offline : Bool := false
6767 outputsFile? : Option FilePath := none
68+ overwrite? : Option Bool := none
6869 forceDownload : Bool := false
6970 mappingsOnly : Bool := false
7071 service? : Option String := none
@@ -285,6 +286,8 @@ def lakeLongOption : (opt : String) → CliM PUnit
285286| "--offline" => modifyThe LakeOptions ({· with offline := true })
286287| "--wfail" => modifyThe LakeOptions ({· with failLv := .warning})
287288| "--iofail" => modifyThe LakeOptions ({· with failLv := .info})
289+ | "--no-overwrite" => modifyThe LakeOptions ({· with overwrite? := some false })
290+ | "--force-overwrite" => modifyThe LakeOptions ({· with overwrite? := some true })
288291| "--force-download" => modifyThe LakeOptions ({· with forceDownload := true })
289292| "--download-arts" => modifyThe LakeOptions ({· with mappingsOnly := false })
290293| "--mappings-only" => modifyThe LakeOptions ({· with mappingsOnly := true })
@@ -467,6 +470,10 @@ protected def get : CliM PUnit := do
467470 let cfg ← mkLoadConfig opts
468471 let ws ← loadWorkspace cfg
469472 let cache := ws.lakeCache
473+ let overwrite := opts.overwrite?.getD true
474+ unless overwrite do
475+ -- artifacts of skipped mappings with `--no-overwrite` cannot be cleanly handled
476+ error "`--no-overwrite` is not supported for `cache get`"
470477 if let some file := mappings? then liftM (m := LoggerIO) do
471478 if opts.mappingsOnly then
472479 error "`--mappings-only` is not supported with a mappings file; use `lake cache add` instead"
@@ -487,7 +494,7 @@ protected def get : CliM PUnit := do
487494 else
488495 return ws.defaultCacheService
489496 let map ← CacheMap.load file
490- cache.writeMap ws.root.cacheScope map service.name? (some remoteScope)
497+ cache.writeMap ws.root.cacheScope map service.name? (some remoteScope) overwrite
491498 let descrs ← map.collectOutputDescrs
492499 service.downloadArtifacts descrs cache remoteScope opts.forceDownload
493500 else
@@ -532,7 +539,7 @@ protected def get : CliM PUnit := do
532539 return map
533540 else
534541 findOutputs cache service pkg remoteScope opts platform toolchain
535- cache.writeMap pkg.cacheScope map service.name? (some remoteScope)
542+ cache.writeMap pkg.cacheScope map service.name? (some remoteScope) overwrite
536543 unless opts.mappingsOnly do
537544 let descrs ← map.collectOutputDescrs
538545 service.downloadArtifacts descrs cache remoteScope opts.forceDownload
@@ -546,7 +553,7 @@ protected def get : CliM PUnit := do
546553 let toolchain := cacheToolchain pkg toolchain
547554 try
548555 let map ← findOutputs cache service pkg remoteScope opts platform toolchain
549- cache.writeMap pkg.cacheScope map service.name? (some remoteScope)
556+ cache.writeMap pkg.cacheScope map service.name? (some remoteScope) overwrite
550557 unless opts.mappingsOnly do
551558 let descrs ← map.collectOutputDescrs
552559 service.downloadArtifacts descrs cache remoteScope opts.forceDownload
@@ -679,7 +686,8 @@ protected def add : CliM PUnit := do
679686 error (serviceNotFound service ws.lakeConfig.config.cache.services)
680687 return some (.ofString service)
681688 let map ← CacheMap.load file
682- ws.lakeCache.writeMap localScope map service? opts.scope?
689+ let overwrite := opts.overwrite?.getD true
690+ ws.lakeCache.writeMap localScope map service? opts.scope? overwrite
683691
684692private def stagingOutputsFile := "outputs.jsonl"
685693
@@ -701,9 +709,12 @@ protected def stage : CliM PUnit := do
701709 let descrs ← map.collectOutputDescrs
702710 IO.FS.createDirAll stagingDir
703711 copyFile mappingsFile (stagingDir / stagingOutputsFile)
712+ let overwrite := opts.overwrite?.getD false
704713 let ok ← descrs.foldlM (init := true ) fun ok descr => do
705714 let cachePath := cache.artifactDir / descr.relPath
706715 let stagingPath := stagingDir / descr.relPath
716+ unless overwrite || !(← stagingPath.pathExists) do
717+ return ok
707718 match (← copyFile cachePath stagingPath |>.toBaseIO) with
708719 | .ok _ =>
709720 return ok
@@ -741,9 +752,16 @@ protected def unstage : CliM PUnit := do
741752 let descrs ← map.collectOutputDescrs
742753 let artDir := ws.lakeCache.artifactDir
743754 IO.FS.createDirAll artDir
755+ let overwrite := opts.overwrite?.getD false
744756 let ok ← descrs.foldlM (init := true ) fun ok descr => do
745757 let cachePath := artDir/ descr.relPath
746758 let stagingPath := stagingDir / descr.relPath
759+ if (← cachePath.pathExists) then
760+ if overwrite then
761+ -- Cache artifacts are read-only, so the old artifact must be deleted first.
762+ IO.FS.removeFile cachePath
763+ else
764+ return ok
747765 match (← copyFile stagingPath cachePath |>.toBaseIO) with
748766 | .ok _ =>
749767 return ok
@@ -756,7 +774,7 @@ protected def unstage : CliM PUnit := do
756774 unless ok do
757775 logError "failed to copy all outputs to the staging directory"
758776 exit 1
759- ws.lakeCache.writeMap localScope map service? opts.scope?
777+ ws.lakeCache.writeMap localScope map service? opts.scope? overwrite
760778
761779protected def putStaged : CliM PUnit := do
762780 processOptions lakeOption
0 commit comments