/- 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 (wsDir packagesDir : FilePath) (manifestEntry : PackageEntry) : LogIO MaterializeResult := match manifestEntry with | .path _name pkgDir => return { pkgDir := wsDir / pkgDir relPkgDir := pkgDir remoteUrl? := none gitTag? := none manifestEntry } | .git name url rev _inputRev? subDir? => do let relGitDir := packagesDir / name let gitDir := wsDir / 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 := wsDir / relPkgDir relPkgDir remoteUrl? := url gitTag? := ← repo.findTag? manifestEntry }