@@ -8,15 +8,12 @@ import Data.Array.NonEmpty as NEA
8
8
import Data.Array.NonEmpty as NonEmptyArray
9
9
import Data.Codec.Argonaut.Common as CA.Common
10
10
import Data.Foldable as Foldable
11
- import Data.JSDate as JSDate
12
11
import Data.List as List
13
12
import Data.Map as Map
14
13
import Data.Maybe as Maybe
15
14
import Data.String as String
16
15
import Effect.Aff as Aff
17
16
import Effect.Now as Now
18
- import Effect.Ref as Ref
19
- import Node.FS.Stats (Stats (..))
20
17
import Node.Path as Path
21
18
import Node.Process as Process
22
19
import Options.Applicative (CommandFields , Mod , Parser , ParserPrefs (..))
@@ -27,6 +24,7 @@ import Registry.Constants as Registry.Constants
27
24
import Registry.ManifestIndex as ManifestIndex
28
25
import Registry.Metadata as Metadata
29
26
import Registry.PackageName as PackageName
27
+ import Registry.Version as Version
30
28
import Spago.Bin.Flags as Flags
31
29
import Spago.Command.Build as Build
32
30
import Spago.Command.Bundle as Bundle
@@ -912,18 +910,44 @@ mkRegistryEnv offline = do
912
910
-- Make sure we have git and purs
913
911
git <- Git .getGit
914
912
purs <- Purs .getPurs
913
+ { logOptions } <- ask
914
+
915
+ -- Connect to the database - we need it to keep track of when to pull the Registry,
916
+ -- so we don't do it too often
917
+ db <- liftEffect $ Db .connect
918
+ { database: Paths .databasePath
919
+ , logger: \str -> Reader .runReaderT (logDebug $ " DB: " <> str) { logOptions }
920
+ }
921
+
922
+ -- we keep track of how old the latest pull was - if the last pull was recent enough
923
+ -- we just move on, otherwise run the fibers
924
+ fetchingFreshRegistry <- Registry .shouldFetchRegistryRepos db
925
+ when fetchingFreshRegistry do
926
+ -- clone the registry and index repo, or update them
927
+ logInfo " Refreshing the Registry Index..."
928
+ runSpago { logOptions, git, offline } $ parallelise
929
+ [ Git .fetchRepo { git: " https://github.com/purescript/registry-index.git" , ref: " main" } Paths .registryIndexPath >>= case _ of
930
+ Right _ -> pure unit
931
+ Left _err -> logWarn " Couldn't refresh the registry-index, will proceed anyways"
932
+ , Git .fetchRepo { git: " https://github.com/purescript/registry.git" , ref: " main" } Paths .registryPath >>= case _ of
933
+ Right _ -> pure unit
934
+ Left _err -> logWarn " Couldn't refresh the registry, will proceed anyways"
935
+ ]
936
+
937
+ -- Now that we are up to date with the Registry we init/refresh the database
938
+ Registry .updatePackageSetsDb db
915
939
916
- -- we make a Ref for the Index so that we can memoize the lookup of packages
917
- -- and we don't have to read it all together
918
- indexRef <- liftEffect $ Ref .new (Map .empty :: Map PackageName (Map Version Manifest ))
940
+ -- Prepare the functions to read the manifests and metadata - here we memoize as much
941
+ -- as we can in the DB, so we don't have to read the files every time
919
942
let
943
+ -- Manifests are immutable so we can just lookup in the DB or read from file if not there
920
944
getManifestFromIndex :: PackageName -> Version -> Spago (LogEnv ()) (Maybe Manifest )
921
945
getManifestFromIndex name version = do
922
- indexMap <- liftEffect (Ref .read indexRef)
923
- case Map .lookup name indexMap of
924
- Just meta -> pure (Map .lookup version meta)
946
+ liftEffect (Db .getManifest db name version) >>= case _ of
947
+ Just manifest -> pure (Just manifest)
925
948
Nothing -> do
926
- -- if we don't have it we try reading it from file
949
+ -- if we don't have it we need to read it from file
950
+ -- (note that we have all the versions of a package in the same file)
927
951
logDebug $ " Reading package from Index: " <> PackageName .print name
928
952
maybeManifests <- liftAff $ ManifestIndex .readEntryFile Paths .registryIndexPath name
929
953
manifests <- map (map (\m@(Manifest m') -> Tuple m'.version m)) case maybeManifests of
@@ -932,50 +956,36 @@ mkRegistryEnv offline = do
932
956
logWarn $ " Could not read package manifests from index, proceeding anyways. Error: " <> err
933
957
pure []
934
958
let versions = Map .fromFoldable manifests
935
- liftEffect (Ref .write (Map .insert name versions indexMap) indexRef)
959
+ -- and memoize it
960
+ for_ manifests \(Tuple _ manifest@(Manifest m)) -> do
961
+ logDebug $ " Inserting manifest in DB: " <> PackageName .print name <> " v" <> Version .print m.version
962
+ liftEffect $ Db .insertManifest db name m.version manifest
936
963
pure (Map .lookup version versions)
937
964
938
- -- same deal for the metadata files
939
- metadataRef <- liftEffect $ Ref .new ( Map .empty :: Map PackageName Metadata )
965
+ -- Metadata can change over time (unpublished packages, and new packages), so we need
966
+ -- to read it from file every time we have a fresh Registry
940
967
let
968
+ metadataFromFile name = do
969
+ let metadataFilePath = Path .concat [ Paths .registryPath, Registry.Constants .metadataDirectory, PackageName .print name <> " .json" ]
970
+ logDebug $ " Reading metadata from file: " <> metadataFilePath
971
+ liftAff (FS .readJsonFile Metadata .codec metadataFilePath)
972
+
941
973
getMetadata :: PackageName -> Spago (LogEnv ()) (Either String Metadata )
942
974
getMetadata name = do
943
- metadataMap <- liftEffect (Ref .read metadataRef)
944
- case Map .lookup name metadataMap of
945
- Just meta -> pure (Right meta)
946
- Nothing -> do
975
+ -- we first try reading it from the DB
976
+ liftEffect (Db .getMetadata db name) >>= case _ of
977
+ Just metadata | not fetchingFreshRegistry -> do
978
+ logDebug $ " Got metadata from DB: " <> PackageName .print name
979
+ pure (Right metadata)
980
+ _ -> do
947
981
-- if we don't have it we try reading it from file
948
- let metadataFilePath = Path .concat [ Paths .registryPath, Registry.Constants .metadataDirectory, PackageName .print name <> " .json" ]
949
- logDebug $ " Reading metadata from file: " <> metadataFilePath
950
- liftAff (FS .readJsonFile Metadata .codec metadataFilePath) >>= case _ of
982
+ metadataFromFile name >>= case _ of
951
983
Left e -> pure (Left e)
952
984
Right m -> do
953
985
-- and memoize it
954
- liftEffect (Ref .write ( Map .insert name m metadataMap) metadataRef )
986
+ liftEffect (Db .insertMetadata db name m)
955
987
pure (Right m)
956
988
957
- { logOptions } <- ask
958
- -- we keep track of how old the latest pull was - if the last pull was recent enough
959
- -- we just move on, otherwise run the fibers
960
- whenM shouldFetchRegistryRepos do
961
- -- clone the registry and index repo, or update them
962
- logInfo " Refreshing the Registry Index..."
963
- runSpago { logOptions, git, offline } $ parallelise
964
- [ Git .fetchRepo { git: " https://github.com/purescript/registry-index.git" , ref: " main" } Paths .registryIndexPath >>= case _ of
965
- Right _ -> pure unit
966
- Left _err -> logWarn " Couldn't refresh the registry-index, will proceed anyways"
967
- , Git .fetchRepo { git: " https://github.com/purescript/registry.git" , ref: " main" } Paths .registryPath >>= case _ of
968
- Right _ -> pure unit
969
- Left _err -> logWarn " Couldn't refresh the registry, will proceed anyways"
970
- ]
971
-
972
- -- Now that we are up to date with the Registry we init/refresh the database
973
- db <- liftEffect $ Db .connect
974
- { database: Paths .databasePath
975
- , logger: \str -> Reader .runReaderT (logDebug $ " DB: " <> str) { logOptions }
976
- }
977
- Registry .updatePackageSetsDb db
978
-
979
989
pure
980
990
{ getManifestFromIndex
981
991
, getMetadata
@@ -1020,32 +1030,4 @@ mkDocsEnv args dependencies = do
1020
1030
, open: args.open
1021
1031
}
1022
1032
1023
- shouldFetchRegistryRepos :: forall a . Spago (LogEnv a ) Boolean
1024
- shouldFetchRegistryRepos = do
1025
- let freshRegistryCanary = Path .concat [ Paths .globalCachePath, " fresh-registry-canary.txt" ]
1026
- FS .stat freshRegistryCanary >>= case _ of
1027
- Left err -> do
1028
- -- If the stat fails the file probably does not exist
1029
- logDebug [ " Could not stat " <> freshRegistryCanary, show err ]
1030
- -- in which case we touch it and fetch
1031
- touch freshRegistryCanary
1032
- pure true
1033
- Right (Stats { mtime }) -> do
1034
- -- it does exist here, see if it's old enough, and fetch if it is
1035
- now <- liftEffect $ JSDate .now
1036
- let minutes = 15.0
1037
- let staleAfter = 1000.0 * 60.0 * minutes -- need this in millis
1038
- let isOldEnough = (JSDate .getTime now) > (JSDate .getTime mtime + staleAfter)
1039
- if isOldEnough then do
1040
- logDebug " Registry index is old, refreshing canary"
1041
- touch freshRegistryCanary
1042
- pure true
1043
- else do
1044
- logDebug " Registry index is fresh enough, moving on..."
1045
- pure false
1046
- where
1047
- touch path = do
1048
- FS .ensureFileSync path
1049
- FS .writeTextFile path " "
1050
-
1051
1033
foreign import supportsColor :: Effect Boolean
0 commit comments