Skip to content
This repository was archived by the owner on Oct 25, 2023. It is now read-only.

Commit 3454c01

Browse files
committed
refactor: move all manifest code to its file + split Package.load
1 parent c625851 commit 3454c01

File tree

6 files changed

+166
-125
lines changed

6 files changed

+166
-125
lines changed

Diff for: Lake/CLI/Main.lean

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ protected def printPaths : CliM PUnit := do
319319
protected def clean : CliM PUnit := do
320320
processOptions lakeOption
321321
let config ← mkLoadConfig (← getThe LakeOptions)
322-
noArgsRem (← loadPkg config).clean
322+
noArgsRem (← loadWorkspace config).root.clean
323323

324324
protected def script : CliM PUnit := do
325325
if let some cmd ← takeArg? then

Diff for: Lake/Load/Manifest.lean

+65-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Authors: Mac Malone
55
-/
66
import Lean.Data.Json
77

8-
open Lean
8+
open System Lean
99

1010
namespace Lake
1111

@@ -18,15 +18,72 @@ structure PackageEntry where
1818

1919
/-- Manifest file format. -/
2020
structure Manifest where
21-
version : Nat := 1
22-
packages : Array PackageEntry
23-
deriving Inhabited, Repr, FromJson, ToJson
21+
map : NameMap PackageEntry
2422

2523
namespace Manifest
2624

25+
/-- Current version of the manifest format. -/
26+
def version : Nat :=
27+
1
28+
29+
def empty : Manifest :=
30+
⟨{}⟩
31+
32+
instance : EmptyCollection Manifest := ⟨Manifest.empty⟩
33+
34+
def isEmpty (self : Manifest) : Bool :=
35+
self.map.isEmpty
36+
37+
def ofMap (map : NameMap PackageEntry) : Manifest :=
38+
⟨map⟩
39+
2740
def toMap (self : Manifest) : NameMap PackageEntry :=
28-
self.packages.foldl (fun map entry => map.insert entry.name entry) {}
41+
self.map
42+
43+
def ofArray (entries : Array PackageEntry) : Manifest :=
44+
ofMap (entries.foldl (fun map entry => map.insert entry.name entry) {})
45+
46+
def toArray (self : Manifest) : Array PackageEntry :=
47+
self.toMap.fold (fun a _ v => a.push v) #[]
48+
49+
def find? (packageName : Name) (self : Manifest) : Option PackageEntry :=
50+
self.map.find? packageName
51+
52+
def insert (entry : PackageEntry) (self : Manifest) : Manifest :=
53+
⟨self.map.insert entry.name entry⟩
54+
55+
protected def toJson (self : Manifest) : Json :=
56+
Json.mkObj [
57+
("version", version),
58+
("packages", toJson self.toArray)
59+
]
60+
61+
instance : ToJson Manifest := ⟨Manifest.toJson⟩
62+
63+
protected def fromJson? (json : Json) : Except String Manifest := do
64+
let ver ← (← json.getObjVal? "version").getNat?
65+
match ver with
66+
| 1 =>
67+
let packages : Array PackageEntry ←
68+
(← (← json.getObjVal? "packages").getArr?).mapM fromJson?
69+
return ofArray packages
70+
| v =>
71+
throw s!"unknown manifest version `{v}`"
72+
73+
instance : FromJson Manifest := ⟨Manifest.fromJson?⟩
74+
75+
def loadFromFile (manifestFile : FilePath) : IO Manifest := do
76+
let contents ← IO.FS.readFile manifestFile
77+
match Json.parse contents with
78+
| .ok json =>
79+
match fromJson? json with
80+
| .ok manifest =>
81+
return manifest
82+
| .error e =>
83+
throw <| IO.userError <| s!"improperly formatted manifest: {e}"
84+
| .error e =>
85+
throw <| IO.userError <| s!"invalid JSON in manifest: {e}"
2986

30-
def fromMap (map : NameMap PackageEntry) : Manifest := {
31-
packages := map.fold (fun a _ v => a.push v) #[]
32-
}
87+
def saveToFile (self : Manifest) (manifestFile : FilePath) : IO PUnit := do
88+
let jsonString := Json.pretty self.toJson
89+
IO.FS.writeFile manifestFile <| jsonString.push '\n'

Diff for: Lake/Load/Materialize.lean

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ open Std System Lean
1111

1212
namespace Lake
1313

14-
abbrev ResolveM := StateT (NameMap PackageEntry) <| LogIO
14+
abbrev ManifestM := StateT Manifest <| LogIO
1515

1616
/-- Update the Git package in `repo` to `rev` if not already at it. -/
1717
def updateGitPkg (repo : GitRepo) (rev? : Option String) : LogIO PUnit := do
@@ -36,7 +36,7 @@ Attempts to reproduce the `PackageEntry` in the manifest (if one exists) unless
3636
and saves the result to the manifest.
3737
-/
3838
def materializeGitPkg (name : String) (dir : FilePath)
39-
(url : String) (rev? : Option String) (shouldUpdate := true) : ResolveM PUnit := do
39+
(url : String) (rev? : Option String) (shouldUpdate := true) : ManifestM PUnit := do
4040
let repo := GitRepo.mk dir
4141
if let some entry := (← get).find? name then
4242
if shouldUpdate then
@@ -50,7 +50,7 @@ def materializeGitPkg (name : String) (dir : FilePath)
5050
else
5151
cloneGitPkg repo url rev?
5252
let rev ← repo.headRevision
53-
modify (·.insert name {entry with url, rev})
53+
modify (·.insert {entry with url, rev})
5454
else
5555
if (← repo.dirExists) then
5656
if url = entry.url then
@@ -78,15 +78,15 @@ def materializeGitPkg (name : String) (dir : FilePath)
7878
else
7979
cloneGitPkg repo url rev?
8080
let rev ← repo.headRevision
81-
modify (·.insert name {name, url, rev})
81+
modify (·.insert {name, url, rev})
8282

8383
/--
8484
Materializes a `Dependency`, downloading nd/or updating it as necessary.
8585
Local dependencies are materialized relative to `localRoot` and remote
8686
dependencies are stored in `packagesDir`.
8787
-/
8888
def materializeDep (packagesDir localRoot : FilePath)
89-
(dep : Dependency) (shouldUpdate := true) : ResolveM FilePath :=
89+
(dep : Dependency) (shouldUpdate := true) : ManifestM FilePath :=
9090
match dep.src with
9191
| Source.path dir => return localRoot / dir
9292
| Source.git url rev? subDir? => do

Diff for: Lake/Load/Package.lean

+87-80
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def processHeader (header : Syntax) (opts : Options) (trustLevel : UInt32)
3737
mkEmptyEnvironment
3838

3939
/-- Like `Lean.Environment.evalConstCheck` but with plain universe-polymorphic `Except`. -/
40-
unsafe def evalConstCheck (α) (env : Environment) (opts : Options) (type : Name) (const : Name) : Except String α :=
40+
unsafe def evalConstCheck (env : Environment) (opts : Options) (α) (type : Name) (const : Name) : Except String α :=
4141
match env.find? const with
4242
| none => throw s!"unknown constant '{const}'"
4343
| some info =>
@@ -52,115 +52,122 @@ where
5252
throwUnexpectedType : Except String α :=
5353
throw s!"unexpected type at '{const}', `{type}` expected"
5454

55-
namespace Package
56-
57-
/-- Unsafe implementation of `load`. -/
58-
unsafe def loadUnsafe (dir : FilePath) (configOpts : NameMap String)
59-
(configFile := dir / defaultConfigFile) (leanOpts := Options.empty)
60-
: LogIO Package := do
61-
62-
-- Read File & Initialize Environment
63-
let input ← IO.FS.readFile configFile
64-
let inputCtx := Parser.mkInputContext input configFile.toString
65-
let (header, parserState, messages) ← Parser.parseHeader inputCtx
66-
let (env, messages) ← processHeader header leanOpts 1024 inputCtx messages
67-
let env := env.setMainModule configModuleName
68-
69-
-- Configure Extensions
70-
let env := dirExt.setState env dir
71-
let env := optsExt.setState env configOpts
72-
73-
-- Elaborate File
74-
let commandState := Elab.Command.mkState env messages leanOpts
75-
let s ← Elab.IO.processCommands inputCtx parserState commandState
76-
for msg in s.commandState.messages.toList do
77-
match msg.severity with
78-
| MessageSeverity.information => logInfo (← msg.toString)
79-
| MessageSeverity.warning => logWarning (← msg.toString)
80-
| MessageSeverity.error => logError (← msg.toString)
81-
82-
-- Extract Configuration
83-
if s.commandState.messages.hasErrors then
84-
error s!"package configuration `{configFile}` has errors"
85-
86-
-- Load Package Configuration
87-
let env := s.commandState.env
55+
/-- Construct a `NameMap` from the declarations tagged with `attr`. -/
56+
def mkTagMap
57+
(env : Environment) (attr : TagAttribute)
58+
[Monad m] (f : Name → m α) : m (NameMap α) :=
59+
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
60+
return map.insert declName <| ← f declName
61+
62+
/-- Construct a `DNameMap` from the declarations tagged with `attr`. -/
63+
def mkDTagMap
64+
(env : Environment) (attr : TagAttribute)
65+
[Monad m] (f : (n : Name) → m (β n)) : m (DNameMap β) :=
66+
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
67+
return map.insert declName <| ← f declName
68+
69+
/-- Unsafe implementation of `loadFromEnv`. -/
70+
unsafe def Package.unsafeLoadFromEnv
71+
(env : Environment) (leanOpts := Options.empty) : LogIO Package := do
72+
73+
-- Load Configuration
8874
let pkgDeclName ←
8975
match packageAttr.ext.getState env |>.toList with
9076
| [] => error s!"configuration file is missing a `package` declaration"
9177
| [name] => pure name
9278
| _ => error s!"configuration file has multiple `package` declarations"
9379
let config ← IO.ofExcept <|
94-
evalConstCheck PackageConfig env leanOpts ``PackageConfig pkgDeclName
95-
if config.extraDepTarget.isSome then
96-
logWarning <| "`extraDepTarget` has been deprecated. " ++
97-
"Try to use a custom target or raise an issue about your use case."
80+
evalConstCheck env leanOpts PackageConfig ``PackageConfig pkgDeclName
9881

99-
-- Tag Load Helpers
100-
let mkTagMap {α} (attr) (f : Name → IO α) : IO (NameMap α) :=
101-
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
102-
return map.insert declName <| ← f declName
103-
let mkDTagMap {β} (attr : TagAttribute) (f : (n : Name) → IO (β n)) : IO (DNameMap β) :=
104-
attr.ext.getState env |>.foldM (init := {}) fun map declName =>
105-
return map.insert declName <| ← f declName
106-
let evalConst (α typeName declName) : IO α :=
107-
IO.ofExcept (evalConstCheck α env leanOpts typeName declName)
108-
let evalConstMap {α β} (f : α → β) (declName) : IO β :=
109-
match env.evalConst α leanOpts declName with
110-
| .ok a => pure <| f a
111-
| .error e => throw <| IO.userError e
112-
113-
-- Load Dependency, Script, Facet, & Target Configurations
114-
let dependencies ←
82+
-- Load Dependencies
83+
let dependencies ← IO.ofExcept <|
11584
packageDepAttr.ext.getState env |>.foldM (init := #[]) fun arr name => do
116-
return arr.push <| ← evalConst Dependency ``Dependency name
117-
let scripts ← mkTagMap scriptAttr fun declName => do
118-
let fn ← IO.ofExcept <| evalConstCheck ScriptFn env leanOpts ``ScriptFn declName
119-
return {fn, doc? := (← findDocString? env declName)}
120-
let leanLibConfigs ← mkTagMap leanLibAttr
121-
(evalConst LeanLibConfig ``LeanLibConfig)
122-
let leanExeConfigs ← mkTagMap leanExeAttr
123-
(evalConst LeanExeConfig ``LeanExeConfig)
124-
let externLibConfigs ← mkTagMap externLibAttr
125-
(evalConst ExternLibConfig ``ExternLibConfig)
126-
let opaqueModuleFacetConfigs ← mkDTagMap moduleFacetAttr fun name => do
127-
match evalConstCheck ModuleFacetDecl env leanOpts ``ModuleFacetDecl name with
85+
return arr.push <| ← evalConstCheck env leanOpts Dependency ``Dependency name
86+
87+
-- Load Script, Facet, & Target Configurations
88+
let scripts ← mkTagMap env scriptAttr fun name => do
89+
let fn ← IO.ofExcept <| evalConstCheck env leanOpts ScriptFn ``ScriptFn name
90+
return {fn, doc? := (← findDocString? env name)}
91+
let leanLibConfigs ← IO.ofExcept <| mkTagMap env leanLibAttr fun name =>
92+
evalConstCheck env leanOpts LeanLibConfig ``LeanLibConfig name
93+
let leanExeConfigs ← IO.ofExcept <| mkTagMap env leanExeAttr fun name =>
94+
evalConstCheck env leanOpts LeanExeConfig ``LeanExeConfig name
95+
let externLibConfigs ← IO.ofExcept <| mkTagMap env externLibAttr fun name =>
96+
evalConstCheck env leanOpts ExternLibConfig ``ExternLibConfig name
97+
let opaqueModuleFacetConfigs ← mkDTagMap env moduleFacetAttr fun name => do
98+
match evalConstCheck env leanOpts ModuleFacetDecl ``ModuleFacetDecl name with
12899
| .ok decl =>
129100
if h : name = decl.name then
130101
return OpaqueModuleFacetConfig.mk (h ▸ decl.config)
131102
else
132-
error s!"Facet was defined as `{decl.name}`, but was registered as `{name}`"
103+
error s!"facet was defined as `{decl.name}`, but was registered as `{name}`"
133104
| .error e => throw <| IO.userError e
134-
let opaquePackageFacetConfigs ← mkDTagMap packageFacetAttr fun name => do
135-
match evalConstCheck PackageFacetDecl env leanOpts ``PackageFacetDecl name with
105+
let opaquePackageFacetConfigs ← mkDTagMap env packageFacetAttr fun name => do
106+
match evalConstCheck env leanOpts PackageFacetDecl ``PackageFacetDecl name with
136107
| .ok decl =>
137108
if h : name = decl.name then
138109
return OpaquePackageFacetConfig.mk (h ▸ decl.config)
139110
else
140-
error s!"Facet was defined as `{decl.name}`, but was registered as `{name}`"
111+
error s!"facet was defined as `{decl.name}`, but was registered as `{name}`"
112+
| .error e => throw <| IO.userError e
113+
let opaqueTargetConfigs ← mkTagMap env targetAttr fun declName =>
114+
match evalConstCheck env leanOpts TargetConfig ``TargetConfig declName with
115+
| .ok a => pure <| OpaqueTargetConfig.mk a
141116
| .error e => throw <| IO.userError e
142-
let opaqueTargetConfigs ← mkTagMap targetAttr
143-
(evalConstMap OpaqueTargetConfig.mk)
144-
let defaultTargets :=
145-
defaultTargetAttr.ext.getState env |>.fold (init := #[]) fun arr name =>
146-
arr.push name
117+
let defaultTargets := defaultTargetAttr.ext.getState env |>.fold (·.push ·) #[]
147118

148-
-- Construct the Package
119+
-- Issue Warnings
120+
if config.extraDepTarget.isSome then
121+
logWarning <| "`extraDepTarget` has been deprecated. " ++
122+
"Try to use a custom target or raise an issue about your use case."
149123
if leanLibConfigs.isEmpty && leanExeConfigs.isEmpty && config.defaultFacet ≠ .none then
150124
logWarning <| "Package targets are deprecated. " ++
151125
"Add a `lean_exe` and/or `lean_lib` default target to the package instead."
126+
127+
-- Construct the Package
128+
let some dir := dirExt.getState env
129+
| error "configuration environment has no package directory set"
152130
return {
153131
dir, config, scripts, dependencies,
154132
leanLibConfigs, leanExeConfigs, externLibConfigs,
155133
opaqueModuleFacetConfigs, opaquePackageFacetConfigs, opaqueTargetConfigs,
156134
defaultTargets
157135
}
158136

137+
/-- Load a `Package` from a configuration environment. -/
138+
@[implementedBy unsafeLoadFromEnv] opaque Package.loadFromEnv
139+
(env : Environment) (leanOpts := Options.empty) : LogIO Package
159140

160141
/--
161-
Load the package located in
142+
Load the `Package` located in
162143
the given directory with the given configuration file.
163144
-/
164-
@[implementedBy loadUnsafe]
165-
opaque load (dir : FilePath) (configOpts : NameMap String)
166-
(configFile := dir / defaultConfigFile) (leanOpts := Options.empty) : LogIO Package
145+
def Package.load (dir : FilePath) (configOpts : NameMap String)
146+
(configFile := dir / defaultConfigFile) (leanOpts := Options.empty) : LogIO Package := do
147+
148+
-- Read file and initialize environment
149+
let input ← IO.FS.readFile configFile
150+
let inputCtx := Parser.mkInputContext input configFile.toString
151+
let (header, parserState, messages) ← Parser.parseHeader inputCtx
152+
let (env, messages) ← processHeader header leanOpts 1024 inputCtx messages
153+
let env := env.setMainModule configModuleName
154+
155+
-- Configure extensions
156+
let env := dirExt.setState env dir
157+
let env := optsExt.setState env configOpts
158+
159+
-- Elaborate File
160+
let commandState := Elab.Command.mkState env messages leanOpts
161+
let s ← Elab.IO.processCommands inputCtx parserState commandState
162+
163+
-- Report errors
164+
for msg in s.commandState.messages.toList do
165+
match msg.severity with
166+
| MessageSeverity.information => logInfo (← msg.toString)
167+
| MessageSeverity.warning => logWarning (← msg.toString)
168+
| MessageSeverity.error => logError (← msg.toString)
169+
if s.commandState.messages.hasErrors then
170+
error s!"package configuration `{configFile}` has errors"
171+
172+
-- Load package from the environment
173+
Package.loadFromEnv s.commandState.env

Diff for: Lake/Load/Resolve.lean

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Resolves a `Dependency` relative to the given `Package`
1919
in the same `Workspace`, downloading and/or updating it as necessary.
2020
-/
2121
def resolveDep (ws : Workspace)
22-
(pkg : Package) (dep : Dependency) (shouldUpdate := true) : ResolveM Package := do
22+
(pkg : Package) (dep : Dependency) (shouldUpdate := true) : ManifestM Package := do
2323
let dir ← materializeDep ws.packagesDir pkg.dir dep shouldUpdate
2424
let depPkg ← Package.load dir dep.options
2525
unless depPkg.name == dep.name do
@@ -33,7 +33,7 @@ Resolves the package's dependencies,
3333
downloading and/or updating them as necessary.
3434
-/
3535
def resolveDeps (ws : Workspace) (pkg : Package)
36-
(shouldUpdate := true) : ResolveM (NameMap Package) := do
36+
(shouldUpdate := true) : ManifestM (NameMap Package) := do
3737
let resolve dep resolve := do
3838
let pkg ← resolveDep ws pkg dep shouldUpdate
3939
pkg.dependencies.forM fun dep => discard <| resolve dep

0 commit comments

Comments
 (0)