lean4-htt/Lake/Load/Materialize.lean
2022-11-23 20:56:40 -05:00

102 lines
3.4 KiB
Text

/-
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 Lake.Util.Git
import Lake.Load.Manifest
import Lake.Config.Dependency
import Lake.Config.Package
open System Lean
namespace Lake
/-- Update the Git package in `repo` to `rev` if not already at it. -/
def updateGitPkg (repo : GitRepo) (rev? : Option String) : LogIO PUnit := do
let rev ← repo.findRemoteRevision rev?
if (← repo.headRevision) == rev then return
logInfo s!"updating {repo} to revision {rev}"
repo.checkoutDetach rev
/-- Clone the Git package as `repo`. -/
def cloneGitPkg (repo : GitRepo) (url : String) (rev? : Option String) : LogIO PUnit := do
logInfo s!"cloning {url} to {repo}"
repo.clone url
if let some rev := rev? then
let hash ← repo.resolveRemoteRevision rev
repo.checkoutDetach hash
def updateGitRepo (repo : GitRepo) (url : String)
(rev? : Option String) (name : String) : LogIO Unit := do
if (← repo.dirExists) then
if (← repo.getRemoteUrl?) = url then
updateGitPkg repo rev?
else
-- TODO: git resolves local file paths so we always hit this case for local repos
if System.Platform.isWindows then
-- Deleting git repositories via IO.FS.removeDirAll does not work reliably on windows
logInfo s!"{name}: URL has changed; you might need to delete {repo.dir} manually"
updateGitPkg repo rev?
else
logInfo s!"{name}: URL has changed; deleting {repo.dir} and cloning again"
IO.FS.removeDirAll repo.dir
cloneGitPkg repo url rev?
else
cloneGitPkg repo url rev?
def updateSource (relParentDir packagesDir : FilePath) (name : String) (source : Source) : LogIO PackageEntry :=
match source with
| .path dir => return .path name (relParentDir / dir)
| .git url inputRev? subDir? => do
let dir := packagesDir / name
let repo := GitRepo.mk dir
updateGitRepo repo url inputRev? name
let rev ← repo.headRevision
return .git name url rev inputRev? subDir?
structure MaterializeResult where
pkgDir : FilePath
relPkgDir : FilePath
remoteUrl? : Option String
gitTag? : Option String
manifestEntry : PackageEntry
deriving Repr, Inhabited
/--
Materializes a package entry, cloning and/or checkout it out as necessary.
-/
def materializePackageEntry (rootPkgDir packagesDir : FilePath) (manifestEntry : PackageEntry) : LogIO MaterializeResult :=
match manifestEntry with
| .path _name pkgDir =>
return {
pkgDir := rootPkgDir / pkgDir
relPkgDir := pkgDir
remoteUrl? := none
gitTag? := none
manifestEntry
}
| .git name url rev _inputRev? subDir? => do
let relGitDir := packagesDir / name
let gitDir := rootPkgDir / relGitDir
let repo := GitRepo.mk gitDir
/-
Do not update (fetch remote) if already on revision
Avoids errors when offline e.g. [leanprover/lake#104][104]
[104]: https://github.com/leanprover/lake/issues/104
-/
let updateNecessary ← id do
if (← repo.dirExists) then
return (← repo.headRevision?) != rev
return true
if updateNecessary then
updateGitRepo repo url rev name
let relPkgDir := match subDir? with | .some subDir => relGitDir / subDir | .none => relGitDir
return {
pkgDir := rootPkgDir / relPkgDir
relPkgDir
remoteUrl? := url
gitTag? := ← repo.findTag?
manifestEntry
}