@@ -10,17 +10,19 @@ import Control.Arrow (first, (***))
10import Control.Monad (when)
10import Control.Monad (when)
11import Control.Monad.Error.Class (catchError)
11import Control.Monad.Error.Class (catchError)
13−import Data.Monoid ((<>))
14import Data.Aeson ((.=))
13import Data.Aeson ((.=))
15import Data.Aeson.BetterErrors
14import Data.Aeson.BetterErrors
16import Data.ByteString.Lazy (ByteString)
15import Data.ByteString.Lazy (ByteString)
17import Data.Either (isLeft, isRight)
16import Data.Either (isLeft, isRight)
18−import Data.Maybe (mapMaybe, fromMaybe)
17+import Data.Maybe (mapMaybe, fromMaybe, maybeToList)
18+import Data.Monoid ((<>))
19import Data.Text (Text)
19import Data.Text (Text)
20+import Data.Time.Clock (UTCTime)
21+import qualified Data.Time.Format as TimeFormat
20import Data.Version
22import Data.Version
21−import qualified Data.Vector as V
22import qualified Data.Aeson as A
23import qualified Data.Aeson as A
23import qualified Data.Text as T
24import qualified Data.Text as T
25+import qualified Data.Vector as V
25import qualified Language.PureScript as P
27import qualified Language.PureScript as P
@@ -40,6 +42,10 @@ data Package a = Package
40 { pkgMeta :: PackageMeta
42 { pkgMeta :: PackageMeta
41 , pkgVersion :: Version
43 , pkgVersion :: Version
42 , pkgVersionTag :: Text
44 , pkgVersionTag :: Text
45+ -- TODO: When this field was introduced, it was given the Maybe type for the
46+ -- sake of backwards compatibility, as older JSON blobs will not include the
47+ -- field. It should eventually be changed to just UTCTime.
48+ , pkgTagTime :: Maybe UTCTime
43 , pkgModules :: [Module]
49 , pkgModules :: [Module]
44 , pkgBookmarks :: [Bookmark]
50 , pkgBookmarks :: [Bookmark]
45 , pkgResolvedDependencies :: [(PackageName, Version)]
51 , pkgResolvedDependencies :: [(PackageName, Version)]
@@ -62,6 +68,7 @@ verifyPackage verifiedUser Package{..} =
62 Package pkgMeta
68 Package pkgMeta
63 pkgVersion
69 pkgVersion
64 pkgVersionTag
70 pkgVersionTag
65 pkgModules
72 pkgModules
66 pkgBookmarks
73 pkgBookmarks
67 pkgResolvedDependencies
74 pkgResolvedDependencies
@@ -72,6 +79,29 @@ verifyPackage verifiedUser Package{..} =
72packageName :: Package a -> PackageName
79packageName :: Package a -> PackageName
73packageName = bowerName . pkgMeta
80packageName = bowerName . pkgMeta
83+-- The time format used for serializing package tag times in the JSON format.
84+-- This is the ISO 8601 date format which includes a time and a timezone.
86+jsonTimeFormat :: String
87+jsonTimeFormat = "%Y-%m-%dT%H:%M:%S%z"
90+-- Convenience function for formatting a time in the format expected by this
93+formatTime :: UTCTime -> String
95+ TimeFormat.formatTime TimeFormat.defaultTimeLocale jsonTimeFormat
98+-- Convenience function for parsing a time in the format expected by this
101+parseTime :: String -> Maybe UTCTime
103+ TimeFormat.parseTimeM False TimeFormat.defaultTimeLocale jsonTimeFormat
75data Module = Module
105data Module = Module
76 { modName :: P.ModuleName
106 { modName :: P.ModuleName
77 , modComments :: Maybe Text
107 , modComments :: Maybe Text
@@ -275,6 +305,7 @@ data PackageError
275 | InvalidFixity
305 | InvalidFixity
276 | InvalidKind Text
306 | InvalidKind Text
277 | InvalidDataDeclType Text
307 | InvalidDataDeclType Text
278 deriving (Show, Eq, Ord)
309 deriving (Show, Eq, Ord)
280type Bookmark = InPackage (P.ModuleName, Text)
311type Bookmark = InPackage (P.ModuleName, Text)
@@ -320,6 +351,7 @@ asPackage minimumVersion uploader = do
320 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
351 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
321 <*> key "version" asVersion
352 <*> key "version" asVersion
322 <*> key "versionTag" asText
353 <*> key "versionTag" asText
354+ <*> keyMay "tagTime" (withString parseTimeEither)
323 <*> key "modules" (eachInArray asModule)
355 <*> key "modules" (eachInArray asModule)
324 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
356 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
325 <*> key "resolvedDependencies" asResolvedDependencies
357 <*> key "resolvedDependencies" asResolvedDependencies
@@ -327,6 +359,10 @@ asPackage minimumVersion uploader = do
327 <*> key "uploader" uploader
359 <*> key "uploader" uploader
328 <*> pure compilerVersion
360 <*> pure compilerVersion
362+parseTimeEither :: String -> Either PackageError UTCTime
364+ maybe (Left InvalidTime) Right . parseTime
330asUploadedPackage :: Version -> Parse PackageError UploadedPackage
366asUploadedPackage :: Version -> Parse PackageError UploadedPackage
331asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
367asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
@@ -359,6 +395,8 @@ displayPackageError e = case e of
359 "Invalid kind: \"" <> str <> "\""
395 "Invalid kind: \"" <> str <> "\""
360 InvalidDataDeclType str ->
396 InvalidDataDeclType str ->
361 "Invalid data declaration type: \"" <> str <> "\""
397 "Invalid data declaration type: \"" <> str <> "\""
363instance A.FromJSON a => A.FromJSON (Package a) where
401instance A.FromJSON a => A.FromJSON (Package a) where
364 parseJSON = toAesonParser displayPackageError
402 parseJSON = toAesonParser displayPackageError
@@ -550,7 +588,7 @@ asSourceSpan = P.SourceSpan <$> key "name" asString
551instance A.ToJSON a => A.ToJSON (Package a) where
589instance A.ToJSON a => A.ToJSON (Package a) where
552 toJSON Package{..} =
590 toJSON Package{..} =
553− A.object
591+ A.object $
554 [ "packageMeta" .= pkgMeta
592 [ "packageMeta" .= pkgMeta
555 , "version" .= showVersion pkgVersion
593 , "version" .= showVersion pkgVersion
556 , "versionTag" .= pkgVersionTag
594 , "versionTag" .= pkgVersionTag
@@ -562,7 +600,8 @@ instance A.ToJSON a => A.ToJSON (Package a) where
562 , "github" .= pkgGithub
600 , "github" .= pkgGithub
563 , "uploader" .= pkgUploader
601 , "uploader" .= pkgUploader
564 , "compilerVersion" .= showVersion P.version
602 , "compilerVersion" .= showVersion P.version
604+ fmap (\t -> "tagTime" .= formatTime t) (maybeToList pkgTagTime)
567instance A.ToJSON NotYetKnown where
606instance A.ToJSON NotYetKnown where
568 toJSON _ = A.Null
607 toJSON _ = A.Null