0 | module Pack.Config.Environment
  1 |
  2 | import Data.Maybe
  3 | import Data.SortedMap as SM
  4 | import Data.String
  5 | import Idris.Package.Types
  6 | import Pack.CmdLn
  7 | import Pack.Config.TOML
  8 | import Pack.Config.Types
  9 | import public Pack.Config.Environment.Variable
 10 | import Pack.Core
 11 | import Pack.Database
 12 | import System
 13 | import System.Clock
 14 |
 15 | %default total
 16 |
 17 | --------------------------------------------------------------------------------
 18 | --          Files and Directories
 19 | --------------------------------------------------------------------------------
 20 |
 21 | ||| File body of all `pack.toml` files.
 22 | export
 23 | packToml : Body
 24 | packToml = "pack.toml"
 25 |
 26 | ||| Directory where databases are stored.
 27 | export %inline
 28 | dbDir : (pd : PackDirs) => Path Abs
 29 | dbDir = pd.state /> "db"
 30 |
 31 | ||| Directory where cached data is stored
 32 | export %inline
 33 | cacheDir : (pd : PackDirs) => Path Abs
 34 | cacheDir = pd.cache
 35 |
 36 | ||| Path to cached `.ipkg` file.
 37 | export
 38 | ipkgCachePath : PackDirs => PkgName -> Commit -> File Rel -> File Abs
 39 | ipkgCachePath p com = toAbsFile (cacheDir <//> p <//> com)
 40 |
 41 | ||| Path where the cached compiler version is stored.
 42 | export
 43 | versionCachePath : PackDirs => (db : DB) => File Abs
 44 | versionCachePath = MkF (cacheDir <//> IdrisApi <//> db.idrisCommit) "version"
 45 |
 46 | ||| Path to cached core library `.ipkg` file
 47 | export
 48 | coreCachePath : PackDirs => (db : DB) => CorePkg -> File Abs
 49 | coreCachePath n =
 50 |   MkF (cacheDir <//> n <//> db.idrisCommit) (coreIpkgFile n)
 51 |
 52 | ||| Directory where user settings are stored.
 53 | export %inline
 54 | userDir : (pd : PackDirs) => Path Abs
 55 | userDir = pd.user
 56 |
 57 | ||| Path to global `pack.toml` file.
 58 | export %inline
 59 | globalPackToml : PackDirs => File Abs
 60 | globalPackToml = MkF userDir packToml
 61 |
 62 | ||| Path to global `pack.toml` file containing the global pack collection.
 63 | export %inline
 64 | collectionToml : (pd : PackDirs) => File Abs
 65 | collectionToml = MkF pd.state packToml
 66 |
 67 | ||| File where package DB is located
 68 | export
 69 | dbFile : PackDirs => (c : MetaConfig) => File Abs
 70 | dbFile = MkF dbDir $ c.collection.value <+> ".toml"
 71 |
 72 | ||| Directory where wrapper scripts to binaries
 73 | ||| managed by pack are being stored. The only exception
 74 | ||| is pack itself, which is stored as a symbolic link.
 75 | export %inline
 76 | packBinDir : (pd : PackDirs) => Path Abs
 77 | packBinDir = pd.bin
 78 |
 79 | ||| Where packages and built applications will be installed
 80 | export %inline
 81 | installDir : (pd : PackDirs) => Path Abs
 82 | installDir = pd.state </> "install"
 83 |
 84 | ||| Where all pack versions are installed
 85 | export %inline
 86 | packParentDir : PackDirs => Path Abs
 87 | packParentDir = installDir </> "pack"
 88 |
 89 | ||| Where the actual pack application is installed.
 90 | export %inline
 91 | packInstallDir : PackDirs => Commit -> Path Abs
 92 | packInstallDir com = packParentDir </> cast com
 93 |
 94 | ||| Executable for an application
 95 | export %inline
 96 | pathExec : PackDirs => Body -> File Abs
 97 | pathExec b = MkF packBinDir b
 98 |
 99 | ||| Symbolic link to the current pack executable.
100 | export
101 | packExec : PackDirs => File Abs
102 | packExec = pathExec "pack"
103 |
104 | ||| Directory where `.ipkg` patches are stored.
105 | export
106 | patchesDir : PackDirs => Path Abs
107 | patchesDir = userDir /> "patches"
108 |
109 | export
110 | commitsDir : PackDirs => Path Abs
111 | commitsDir = cacheDir </> "commits"
112 |
113 | ||| Path to file storing the last fetched commit of a Git
114 | ||| repo given as a URL and branch name.
115 | export
116 | commitFile : PackDirs => URL -> Branch -> File Abs
117 | commitFile url b =
118 |   let relPath := the (Path Rel) $ cast "\{url}/\{b}"
119 |    in MkF (commitsDir </> relPath) "commit"
120 |
121 | ||| File where the patch (if any) for an `.ipkg` file is stored.
122 | export
123 | patchFile : PackDirs => (c : Config) => PkgName -> File Rel -> File Abs
124 | patchFile n (MkF p b) =
125 |   MkF
126 |     (patchesDir //> c.collection <//> n </> p)
127 |     (b <+> ".patch")
128 |
129 | ||| Directory where all packages (and Idris2) built with the
130 | ||| current Idris2 commit will be installed.
131 | export %inline
132 | commitDir : PackDirs => (db : DB) => Path Abs
133 | commitDir = installDir <//> db.idrisCommit
134 |
135 | ||| The directory where Idris2 and core libraries will be installed.
136 | export %inline
137 | idrisPrefixDir : PackDirs => DB => Path Abs
138 | idrisPrefixDir = commitDir /> "idris2"
139 |
140 | ||| The directory where the Idris2 binary will be installed.
141 | export %inline
142 | idrisBinDir : PackDirs => DB => Path Abs
143 | idrisBinDir = idrisPrefixDir /> "bin"
144 |
145 | ||| Location of the Idris2 executable used to build packages.
146 | |||
147 | ||| Notice that if you need an Idris command, you may need `idrisCmd` function
148 | ||| instead because it takes extra arguments into account.
149 | export
150 | idrisExec : PackDirs => DB => File Abs
151 | idrisExec = MkF idrisBinDir "idris2"
152 |
153 | export %inline
154 | idrisDir : (db : DB) => Body
155 | idrisDir = the Body "idris2" <-> db.idrisVersion
156 |
157 | ||| The directory where Idris2 packages will be installed.
158 | export %inline
159 | idrisInstallDir : PackDirs => DB => Path Abs
160 | idrisInstallDir = idrisPrefixDir /> idrisDir
161 |
162 | ||| The `lib` directory in the Idris2 installation folder
163 | export %inline
164 | idrisLibDir : PackDirs => DB => Path Abs
165 | idrisLibDir = idrisInstallDir /> "lib"
166 |
167 | ||| The `support` directory in the Idris2 installation folder
168 | export %inline
169 | idrisDataDir : PackDirs => DB => Path Abs
170 | idrisDataDir = idrisInstallDir /> "support"
171 |
172 | ||| Directory where an installed library or app goes
173 | export %inline
174 | pkgPrefixDir : PackDirs => DB => PkgName -> Hash -> Package -> Path Abs
175 | pkgPrefixDir n h (Git {})   = commitDir <//> n <//> h
176 | pkgPrefixDir n h (Local {}) = commitDir <//> n <//> h
177 | pkgPrefixDir n h (Core _)   = idrisPrefixDir
178 |
179 | ||| Directory to be used with the `IDRIS2_PACKAGE_PATH` variable, so that
180 | ||| Idris finds a library even though it is being installed in a
181 | ||| custom location.
182 | export %inline
183 | pkgPathDir : PackDirs => DB => PkgName -> Hash -> Package -> Path Abs
184 | pkgPathDir n h p = pkgPrefixDir n h p /> idrisDir
185 |
186 | ||| Directory where the binary of an Idris application is installed.
187 | export %inline
188 | pkgBinDir : PackDirs => DB => PkgName -> Hash -> Package -> Path Abs
189 | pkgBinDir n h p = pkgPrefixDir n h p /> "bin"
190 |
191 | ||| Directory to be used with the `IDRIS2_LIBS` variable, so that
192 | ||| Idris finds a libraries `.so` files even though they have been
193 | ||| installed in a custom location.
194 | export %inline
195 | pkgLibDir : PackDirs => DB => PkgName -> Hash -> Package -> Path Abs
196 | pkgLibDir n h p = pkgPathDir n h p /> "lib"
197 |
198 | ||| Directory to be used with the `IDRIS2_DATA` variable, so that
199 | ||| Idris finds a libraries support files even though they have been
200 | ||| installed in a custom location.
201 | export %inline
202 | pkgDataDir : PackDirs => DB => PkgName -> Hash -> Package -> Path Abs
203 | pkgDataDir n h p = pkgPathDir n h p /> "support"
204 |
205 | ||| Timestamp used to monitor if a local library has been
206 | ||| modified and requires reinstalling.
207 | export %inline
208 | libTimestamp :  PackDirs => DB => PkgName -> File Abs
209 | libTimestamp n = MkF (cacheDir </> "local" <//> n) ".timestamp"
210 |
211 | ||| Directory where the sources of a local package are
212 | ||| stored.
213 | export %inline
214 | localSrcDir : Desc t -> Path Abs
215 | localSrcDir d = sourcePath d
216 |
217 | pkgRelDir : Desc t -> Path Rel
218 | pkgRelDir d = case Body.parse d.desc.name of
219 |   Just b  => neutral /> (b <-> d.desc.version)
220 |   Nothing => cast d.desc.name //> d.desc.version
221 |
222 | ||| Returns the directory where a package for the current
223 | ||| package collection is installed.
224 | export
225 | pkgInstallDir : PackDirs => (db : DB) => PkgName -> Hash -> Package -> Desc t -> Path Abs
226 | pkgInstallDir n h p d =
227 |   let vers := db.idrisVersion
228 |       dir  := pkgPrefixDir n h p /> idrisDir
229 |    in case p of
230 |         Core c          => dir /> (c <-> vers)
231 |         Git _ _ _ _ _ _ => dir </> pkgRelDir d
232 |         Local _ _ _ _   => dir </> pkgRelDir d
233 |
234 | ||| Directory where the API docs of the package will be installed.
235 | export %inline
236 | pkgDocs : PackDirs => DB => PkgName -> Hash -> Package -> Desc t -> Path Abs
237 | pkgDocs n h p d = pkgInstallDir n h p d /> "docs"
238 |
239 | ||| Location of an executable of the given name.
240 | export
241 | pkgExec : PackDirs => DB => PkgName -> Hash -> Package -> (exe : Body) -> File Abs
242 | pkgExec n h p exe = MkF (pkgBinDir n h p) exe
243 |
244 | ||| Path to the executable of an Idris application
245 | export
246 | resolvedExec : PackDirs => DB => ResolvedApp t -> File Abs
247 | resolvedExec (RA p h n d _ exe _) = pkgExec n h p exe
248 |
249 | ||| URL of the pack repository to use
250 | export %inline
251 | packRepo : (c : Config) => URL
252 | packRepo = fromMaybe defaultPackRepo c.packURL
253 |
254 | ||| Commit of pack to use
255 | export %inline
256 | packCommit : (c : Config) => Maybe Commit
257 | packCommit = c.packCommit
258 |
259 | ||| True if the path to the scheme executable actually points
260 | ||| to `racket`.
261 | export
262 | useRacket : (c : Config) => Bool
263 | useRacket = map snd (split c.scheme) == Just "racket"
264 |
265 | ||| Bootstrap command to use
266 | export
267 | bootstrapCmd : (c : Config) => String
268 | bootstrapCmd = if useRacket then "bootstrap-racket" else "bootstrap"
269 |
270 | --------------------------------------------------------------------------------
271 | --          Environment Variables
272 | --------------------------------------------------------------------------------
273 |
274 | ||| `$PREFIX` variable during Idris2 installation, unquoted
275 | export
276 | prefixVar : PackDirs => DB => EnvVar
277 | prefixVar = PrefixVar idrisPrefixDir
278 |
279 | ||| `$IDRIS2_BOOT` variable during Idris2 installation, unquoted
280 | export
281 | idrisBootVar : PackDirs => DB => EnvVar
282 | idrisBootVar = IdrisBootVar idrisExec
283 |
284 | ||| `$SCHEME` variable during Idris2 installation, unquoted
285 | export
286 | schemeVar : (c : Config) => EnvVar
287 | schemeVar = if useRacket then IdrisCodegenVar Racket else SchemeVar c.scheme
288 |
289 | ||| `IDRIS2_PREFIX` to be used with Idris when installing a library
290 | ||| to a custom location.
291 | export
292 | libInstallPrefix : PackDirs => DB => ResolvedLib t -> List EnvVar
293 | libInstallPrefix rl = [IdrisPrefixVar $ pkgPrefixDir rl.name rl.hash rl.pkg]
294 |
295 | ||| Idris executable with extra arguments, if they are present in the config.
296 | export
297 | idrisCmd : (e : Env) => CmdArgList
298 | idrisCmd = idrisExec :: e.config.extraArgs
299 |
300 | ||| Idris executable to use together with the
301 | ||| `--cg` (codegen) command line option.
302 | export
303 | idrisWithCG : (e : Env) => CmdArgList
304 | idrisWithCG = case e.config.codegen of
305 |   Default => idrisCmd
306 |   cg      => idrisCmd ++ ["--cg", cg]
307 |
308 | --------------------------------------------------------------------------------
309 | --          Environment
310 | --------------------------------------------------------------------------------
311 |
312 | getEnvPath : HasIO io => String -> io (Maybe (Path Abs))
313 | getEnvPath s = (>>= parse) <$> getEnv s
314 |
315 | getUserDir  : HasIO io => (home : Path Abs) -> io (Path Abs)
316 | getUserDir home = do
317 |   Nothing <- getEnvPath "PACK_USER_DIR"   | Just p => pure p
318 |   Nothing <- getEnvPath "XDG_CONFIG_HOME" | Just p => pure (p </> "pack")
319 |   pure (home </> ".config/pack")
320 |
321 | getStateDir : HasIO io => (home : Path Abs) -> io (Path Abs)
322 | getStateDir home = do
323 |   Nothing <- getEnvPath "PACK_STATE_DIR" | Just p => pure p
324 |   Nothing <- getEnvPath "XDG_STATE_HOME" | Just p => pure (p </> "pack")
325 |   pure (home </> ".local/state/pack")
326 |
327 | getCacheDir : HasIO io => (home : Path Abs) -> io (Path Abs)
328 | getCacheDir home = do
329 |   Nothing <- getEnvPath "PACK_CACHE_DIR" | Just p => pure p
330 |   Nothing <- getEnvPath "XDG_CACHE_HOME" | Just p => pure (p </> "pack")
331 |   pure (home </> ".cache/pack")
332 |
333 | getBinDir   : HasIO io => (home : Path Abs) -> io (Path Abs)
334 | getBinDir home = do
335 |   Nothing <- getEnvPath "PACK_BIN_DIR"   | Just p => pure p
336 |   pure (home </> ".local/bin")
337 |
338 | ||| Return the path of the pack root directory,
339 | ||| either from environment variable `$PACK_DIR`, or
340 | ||| as `$HOME/.pack`.
341 | export
342 | getPackDirs : HasIO io => EitherT PackErr io PackDirs
343 | getPackDirs = do
344 |   Just h <- getEnvPath "HOME" | Nothing => throwE NoPackDir
345 |   u      <- getUserDir h
346 |   s      <- getStateDir h
347 |   c      <- getCacheDir h
348 |   b      <- getBinDir h
349 |   pure (PD u s c b)
350 |
351 | ||| Update the package database.
352 | export
353 | updateDB : HasIO io => TmpDir => PackDirs => EitherT PackErr io ()
354 | updateDB = do
355 |   rmDir dbDir
356 |   commit <- gitLatest dbRepo "main"
357 |   withGit packDB dbRepo commit True $ \d =>
358 |     copyDir (d /> "collections") dbDir
359 |
360 | ||| Extract the name of the latest collection from a directory
361 | export
362 | latestCollection : HasIO io => (dir : Path Abs) -> EitherT PackErr io DBName
363 | latestCollection dir = do
364 |   (x :: xs) <- filter ("HEAD.toml" /=) <$> tomlFiles dir
365 |     | [] => pure Head
366 |   pure
367 |     . maybe Head MkDBName
368 |     . fileStem
369 |     $ foldl max x xs
370 |
371 | ||| Update the package database.
372 | export
373 | copyLatest : HasIO io => TmpDir => PackDirs => EitherT PackErr io DBName
374 | copyLatest = do
375 |   commit <- gitLatest dbRepo "main"
376 |   withGit packDB dbRepo commit True $ \d => do
377 |     db <- latestCollection (d /> "collections")
378 |     let body := cast {to = Body} db <+> ".toml"
379 |     copyFile (d /> "collections" /> body) (dbDir /> body)
380 |     pure db
381 |
382 | ||| Loads the name of the default collection (currently the latest
383 | ||| nightly)
384 | export
385 | defaultColl : HasIO io => TmpDir => PackDirs => EitherT PackErr io DBName
386 | defaultColl = do
387 |   when !(missing dbDir) updateDB
388 |   latestCollection dbDir
389 |
390 | ||| Resolve a meta commit by fetching the hash of the latest commit
391 | ||| from a Git repo in case of an `Fetch x` commit. In case of a `Latest x`
392 | ||| meta commit, the hash is only fetched, if the corresponding commit
393 | ||| file is missing or `fetch` is set to `True`.
394 | export
395 | resolveMeta :
396 |      {auto _ : HasIO io}
397 |   -> {auto _ : PackDirs}
398 |   -> (fetch : Bool)
399 |   -> URL
400 |   -> MetaCommit
401 |   -> EitherT PackErr io Commit
402 | resolveMeta _ u (MC x)     = pure x
403 | resolveMeta _ u (Fetch x)  = gitLatest u x
404 | resolveMeta b u (Latest x) = do
405 |   let cfile := commitFile u x
406 |   commitMissing <- fileMissing cfile
407 |   case commitMissing || b of
408 |     True  => do
409 |       c <- gitLatest u x
410 |       write cfile c.value
411 |       pure c
412 |     False => (\s => MkCommit $ trim s) <$> read cfile
413 |
414 | ||| Content of pack-generated `pack.toml` containing the globally
415 | ||| set pack collection.
416 | export
417 | collectionTomlContent : DBName -> String
418 | collectionTomlContent db =
419 |   """
420 |   # Warning: This file was auto-generated and is maintained by pack.
421 |   #          Any changes could be overwritten by pack at any time.
422 |   #          Custom settings should go to the global `pack.toml` file
423 |   #          or any `pack.toml` file local to a project.
424 |   collection = \{quote db}
425 |   """
426 |
427 | ||| Read application config from command line arguments.
428 | export covering
429 | getConfig :
430 |      (0 c : Type)
431 |   -> {auto _   : Command c}
432 |   -> (args : ParsedArgs c)
433 |   -> {auto _   : HasIO io}
434 |   -> {auto pd  : PackDirs}
435 |   -> {auto td  : TmpDir}
436 |   -> EitherT PackErr io MetaConfig
437 | getConfig c args = do
438 |   -- relevant directories
439 |   coll       <- defaultColl
440 |   let cur = args.curDir
441 |
442 |   -- Initialize `pack.toml` if none exists
443 |   when !(fileMissing globalPackToml) $
444 |     write globalPackToml (initToml "scheme")
445 |
446 |   -- Initialize collection `pack.toml` if none exists
447 |   when !(fileMissing collectionToml) $
448 |     write collectionToml (collectionTomlContent coll)
449 |
450 |   localTomls  <- findInAllParentDirs (packToml ==) curDir
451 |   localConfs  <- for localTomls $ readFromTOML UserConfig
452 |   collToml    <- readOptionalFromTOML UserConfig collectionToml
453 |   global      <- readOptionalFromTOML UserConfig globalPackToml
454 |
455 |   let ini = foldl update (init coll) (global::collToml::localConfs)
456 |
457 |   conf' <- liftEither $ applyArgs c ini args
458 |   conf  <- adjConfig args.cmd conf'
459 |
460 |   let logRef := MkLogRef conf.logLevel
461 |
462 |   debug "Pack user dir is \{pd.user}"
463 |   debug "Pack state dir is \{pd.state}"
464 |   debug "Pack cache dir is \{pd.cache}"
465 |   debug "Pack bin dir is \{pd.bin}"
466 |   debug "Current directory is \{cur}"
467 |   case localTomls of
468 |     _::_ =>
469 |       logMany
470 |         Info
471 |         {inlineSingle=True}
472 |         "Found local config at"
473 |         (interpolate <$> localTomls)
474 |     []   => debug "No local config found"
475 |   info "Using package collection \{conf.collection}"
476 |   debug "Config loaded"
477 |   mkDir pd.user
478 |   mkDir pd.state
479 |   mkDir pd.cache
480 |   mkDir pd.bin
481 |   pure conf
482 |
483 | export
484 | getLineBufferingCmd : HasIO io => io LineBufferingCmd
485 | getLineBufferingCmd = findCmd variants
486 |
487 |   where
488 |     findCmd : List (String, CmdArgList) -> io LineBufferingCmd
489 |     findCmd [] = pure $ MkLineBufferingCmd []
490 |     findCmd ((cmd, args)::rest) = do
491 |       0 <- system $ escapeCmd
492 |              ["type", cmd, NoEscape ">", "/dev/null", NoEscape "2>", "/dev/null"]
493 |         | _ => findCmd rest
494 |       0 <- system $ escapeCmd
495 |              [ cmd, "-oL", "ls", NoEscape ">", "/dev/null", NoEscape "2>", "/dev/null"]
496 |         | _ => findCmd rest
497 |       pure $ MkLineBufferingCmd $ [cmd] ++ args
498 |
499 |     variants : List (String, CmdArgList)
500 |     variants =
501 |       [ ("stdbuf",  ["-oL"])
502 |       , ("gstdbuf", ["-oL"])
503 |       ]
504 |
505 | --------------------------------------------------------------------------------
506 | --          Environment
507 | --------------------------------------------------------------------------------
508 |
509 | pkgs : SortedMap PkgName Package
510 | pkgs = fromList $ (\c => (corePkgName c, Core c)) <$> corePkgs
511 |
512 | ||| Load the package collection as given in the (auto-implicit) user config.
513 | export covering
514 | loadDB :
515 |      {auto _ : HasIO io}
516 |   -> {auto _ : TmpDir}
517 |   -> {auto _ : PackDirs}
518 |   -> MetaConfig
519 |   -> EitherT PackErr io MetaDB
520 | loadDB mc = do
521 |   when !(missing dbDir) updateDB
522 |   debug "reading package collection"
523 |   raw <- readFromTOML MetaDB dbFile
524 |   case fileStem dbFile of
525 |     Just "HEAD" => pure $ map toLatest raw
526 |     _           => pure raw
527 |
528 | ||| Run a pack action in the directory of the cloned Idris repository.
529 | export
530 | withCoreGit :
531 |      {auto _ : HasIO io}
532 |   -> {auto e : Env}
533 |   -> (Path Abs -> EitherT PackErr io a)
534 |   -> EitherT PackErr io a
535 | withCoreGit = withGit compiler e.db.idrisURL e.db.idrisCommit False
536 |
537 | ||| Caches the `.ipkg` files of the core libraries to make them
538 | ||| quickly available when running queries.
539 | export
540 | cacheCoreIpkgFiles : HasIO io => Env => Path Abs -> EitherT PackErr io ()
541 | cacheCoreIpkgFiles dir = do
542 |   for_ corePkgs $ \c =>
543 |     copyFile (toAbsFile dir (coreIpkgPath c)) (coreCachePath c)
544 |   let api := coreCachePath IdrisApi
545 |   desc <- parseIpkgFile api api
546 |   write versionCachePath (maybe "0.0.0" show desc.desc.version)
547 |
548 |
549 | export
550 | notCached : HasIO io => (e : Env) => PkgName -> Package -> io Bool
551 | notCached n (Git u c i _ _ _) = fileMissing $ ipkgCachePath n c i
552 | notCached n (Local d i _ _) = pure False
553 | notCached n (Core c)        = fileMissing $ coreCachePath c
554 |
555 | export
556 | cachePkg :
557 |      {auto _ : HasIO io}
558 |   -> {auto e : Env}
559 |   -> PkgName
560 |   -> Package
561 |   -> EitherT PackErr io ()
562 | cachePkg n (Git u c i _ _ _) =
563 |   let cache  := ipkgCachePath n c i
564 |       tmpLoc := gitTmpDir n </> i
565 |    in withGit n u c False $ \dir => do
566 |         let pf := patchFile n i
567 |         when !(fileExists pf) (patch tmpLoc pf)
568 |         copyFile tmpLoc cache
569 | cachePkg n (Local d i _ _)    = pure ()
570 | cachePkg n (Core c)           =
571 |   let cache  := coreCachePath c
572 |       tmpLoc := gitTmpDir compiler </> coreIpkgPath c
573 |    in withCoreGit cacheCoreIpkgFiles
574 |
575 | export
576 | cachePkgs : HasIO io => (e : Env) => EitherT PackErr io PkgVersion
577 | cachePkgs =
578 |   let pkgs := toList e.all
579 |    in do
580 |      (S n,ml,ps) <- needCaching Lin 0 60 pkgs | (0,_,_) => readIdrisVersion
581 |      traverse_ (doCache (S n) ml) ps
582 |      readIdrisVersion
583 |
584 |   where
585 |     needCaching :
586 |          SnocList (Nat,PkgName,Package)
587 |       -> (count : Nat)
588 |       -> (maxLen : Nat)
589 |       -> List (PkgName,Package)
590 |       -> EitherT PackErr io (Nat,Nat,List (Nat,PkgName,Package))
591 |     needCaching sp n ml []               = pure (n, ml, sp <>> [])
592 |     needCaching sp n ml ((pn,pkg) :: ps) = do
593 |       True <- notCached pn pkg | False => needCaching sp n ml ps
594 |       let n'  := S n
595 |           ml' := max ml (length (interpolate pn) + 26)
596 |       needCaching (sp :< (n', pn, pkg)) n' ml' ps
597 |
598 |     cacheInfo : (tot, maxLength, ix : Nat) -> PkgName -> String
599 |     cacheInfo tot ml ix pn =
600 |       let line := padRight ml '.' "Caching package info for \{pn} "
601 |           stot := show tot
602 |           six  := padLeft (length stot) ' ' (show ix)
603 |        in "\{line} (\{six}/\{stot})"
604 |
605 |     doCache :
606 |           (tot : Nat)
607 |        -> (maxLenght : Nat)
608 |        -> (Nat,PkgName,Package)
609 |        -> EitherT PackErr io ()
610 |     doCache tot ml (n,pn,pkg) = do
611 |       cache (cacheInfo tot ml n pn)
612 |       cachePkg pn pkg
613 |
614 |     readIdrisVersion : EitherT PackErr io PkgVersion
615 |     readIdrisVersion = do
616 |       when !(fileMissing versionCachePath)
617 |         (cachePkg (corePkgName IdrisApi) $ Core IdrisApi)
618 |       s <- trim <$> read versionCachePath
619 |       let vers := MkPkgVersion $ map cast $ split ('.' ==) s
620 |       debug "compiler version is \{show vers}"
621 |       pure vers
622 |
623 | ||| Load the package collection as given in the (auto-implicit) user config
624 | ||| and convert the result to a pack environment.
625 | export covering
626 | env :
627 |      {auto _   : HasIO io}
628 |   -> {auto pd  : PackDirs}
629 |   -> {auto td  : TmpDir}
630 |   -> {auto ch  : LibCache}
631 |   -> {auto lbf : LineBufferingCmd}
632 |   -> (mc       : MetaConfig)
633 |   -> (fetch    : FetchMethod)
634 |   -> EitherT PackErr io Env
635 | env mc fetch = do
636 |   mdb <- loadDB mc
637 |   clk <- liftIO $ clockTime UTC
638 |   debug "clock time is \{show $ toNano clk}"
639 |   when (fetch == ClearCommits) (rmDir commitsDir)
640 |   db  <- traverseDB (resolveMeta $ fetch > MissingOnly) mdb
641 |   c   <- traverse (resolveMeta $ fetch > MissingOnly) db.idrisURL mc
642 |
643 |   let url    := fromMaybe db.idrisURL c.idrisURL
644 |       commit := fromMaybe db.idrisCommit c.idrisCommit
645 |       -- take the DB's idris commit into account
646 |       c'     := {allIdrisCommits $= (db.idrisCommit ::)} c
647 |       -- adjust the idrisCommit and URL to use according to user overrides
648 |       db'    := {idrisURL := url, idrisCommit := commit} db
649 |       pkgs   := SortedMap.fromList $ (\c => (corePkgName c, Core c)) <$> corePkgs
650 |       all    := fromMaybe empty $ lookup All c'.custom
651 |       loc    := fromMaybe empty $ lookup c'.collection c.custom
652 |       allps  := db.packages `mergeRight` all `mergeRight` loc `mergeRight` pkgs
653 |       env    := MkEnv pd td c' ch db' allps lbf clk
654 |
655 |   vers <- cachePkgs
656 |   pure $ {db $= setVersion vers} env
657 |
658 | ||| Update the `collection` field in file `PACK_DIR/user/pack.toml`
659 | ||| with the name of the package collection given in config `c`.
660 | export covering
661 | writeCollection :
662 |      {auto _ : HasIO io}
663 |   -> {auto _ : PackDirs}
664 |   -> {auto c : Config}
665 |   -> EitherT PackErr io ()
666 | writeCollection = do
667 |   str <- read globalPackToml
668 |   write collectionToml (collectionTomlContent c.collection)
669 |