/- Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone -/ import Leanpkg2.Proc import Leanpkg2.Package open System namespace Leanpkg2 def lockfile : FilePath := ".leanpkg-lock" partial def withLockFile (x : IO α) : IO α := do acquire try x finally IO.removeFile lockfile where acquire (firstTime := true) := try -- TODO: lock file should ideally contain PID if !Platform.isWindows then discard <| IO.Prim.Handle.mk lockfile "wx" else -- `x` mode doesn't seem to work on Windows even though it's listed at -- https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-160 -- ...? Let's use the slightly racy approach then. if ← lockfile.pathExists then throw <| IO.Error.alreadyExists 0 "" discard <| IO.Prim.Handle.mk lockfile "w" catch | IO.Error.alreadyExists _ _ => do if firstTime then IO.eprintln s!"Waiting for prior leanpkg invocation to finish... (remove '{lockfile}' if stuck)" IO.sleep (ms := 300) acquire (firstTime := false) | e => throw e def execMake (pkg : Package) (deps : List Package) (makeArgs leanArgs : List String := []) : IO Unit := withLockFile do let timeoutArgs := match pkg.timeout with | some t => ["-T", toString t] | none => [] let leanmake := (← IO.appDir) / "leanmake" let leanOptsStr := " ".intercalate <| timeoutArgs ++ leanArgs let leanPathStr := SearchPath.toString <| deps.map (·.buildDir) let makeArgsStr := " ".intercalate makeArgs let moreDepsStr := " ".intercalate $ deps.filter (·.dir.toString != pkg.dir) |>.map (·.oleanRoot.toString) let mut spawnArgs := { cmd := "sh" cwd := pkg.dir args := #["-c", s!"\"{leanmake}\" PKG={pkg.module} LEAN_OPTS=\"{leanOptsStr}\" LEAN_PATH=\"{leanPathStr}\" {makeArgsStr} MORE_DEPS+=\"{moreDepsStr}\" >&2"] } execCmd spawnArgs