lean4-htt/src/Leanpkg/Resolve.lean
2021-01-19 19:06:01 +01:00

91 lines
3.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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
-/
import Leanpkg.Manifest
import Leanpkg.Proc
import Leanpkg.Git
namespace Leanpkg
def Assignment := List (String × String)
namespace Assignment
def empty : Assignment := []
def contains (a : Assignment) (s : String) : Bool :=
(a.lookup s).isSome
def insert (a : Assignment) (k v : String) : Assignment :=
if a.contains k then a else (k, v) :: a
def fold {α} (i : α) (f : α → String → String → α) : Assignment → α :=
List.foldl (fun a ⟨k, v⟩ => f a k v) i
end Assignment
abbrev Solver := StateT Assignment IO
def notYetAssigned (d : String) : Solver Bool := do
¬ (← get).contains d
def resolvedPath (d : String) : Solver String := do
let some path ← pure ((← get).lookup d) | unreachable!
path
-- TODO(gabriel): windows?
def resolveDir (absOrRel : String) (base : String) : String :=
if absOrRel.front = '/' then
absOrRel -- absolute
else
base ++ "/" ++ absOrRel
def materialize (relpath : String) (dep : Dependency) : Solver Unit :=
match dep.src with
| Source.path dir => do
let depdir := resolveDir dir relpath
IO.eprintln s!"{dep.name}: using local path {depdir}"
modify (·.insert dep.name depdir)
| Source.git url rev branch => do
let depdir := "build/deps/" ++ dep.name
let alreadyThere ← IO.isDir depdir
if alreadyThere then
IO.eprint s!"{dep.name}: trying to update {depdir} to revision {rev}"
IO.eprintln (match branch with | none => "" | some branch => "@" ++ branch)
let hash ← gitParseOriginRevision depdir rev
let revEx ← gitRevisionExists depdir hash
unless revEx do
execCmd {cmd := "git", args := #["fetch"], cwd := depdir}
else
IO.eprintln s!"{dep.name}: cloning {url} to {depdir}"
execCmd {cmd := "git", args := #["clone", url, depdir]}
let hash ← gitParseOriginRevision depdir rev
execCmd {cmd := "git", args := #["checkout", "--detach", hash], cwd := depdir}
modify (·.insert dep.name depdir)
def solveDepsCore (relPath : String) (d : Manifest) : (maxDepth : Nat) → Solver Unit
| 0 => throw <| IO.userError "maximum dependency resolution depth reached"
| maxDepth + 1 => do
let deps ← d.dependencies.filterM (notYetAssigned ·.name)
deps.forM (materialize relPath)
for dep in deps do
let p ← resolvedPath dep.name
let d' ← Manifest.fromFile $ p ++ "/" ++ "leanpkg.toml"
unless d'.name = dep.name do
throw <| IO.userError <| d.name ++ " (in " ++ relPath ++ ") depends on " ++ d'.name ++
", but resolved dependency has name " ++ dep.name ++ " (in " ++ p ++ ")"
solveDepsCore p d' maxDepth
def solveDeps (d : Manifest) : IO Assignment := do
let (_, assg) ← (solveDepsCore "." d 1024).run <| Assignment.empty.insert d.name "."
assg
def constructPathCore (depname : String) (dirname : String) : IO String := do
let path ← Manifest.effectivePath (← Manifest.fromFile $ dirname ++ "/" ++ leanpkgTomlFn)
return dirname ++ "/" ++ path
def constructPath (assg : Assignment) : IO (List String) := do
assg.reverse.mapM fun ⟨depname, dirname⟩ => constructPathCore depname dirname
end Leanpkg