5
5
{-# LANGUAGE RecordWildCards #-}
6
6
{-# LANGUAGE TupleSections #-}
7
7
{-# LANGUAGE DeriveTraversable #-}
8
+ {-# LANGUAGE ScopedTypeVariables #-}
8
9
9
10
module Main where
10
11
11
12
import qualified Control.Foldl as Foldl
12
13
import Control.Concurrent.Async (forConcurrently_ )
13
14
import qualified Data.Aeson as Aeson
15
+ import Data.Aeson.Types (fieldLabelModifier )
14
16
import Data.Aeson.Encode.Pretty
15
17
import Data.Foldable (fold , foldMap , traverse_ )
18
+ import qualified Data.Bifunctor as Bifunctor
16
19
import qualified Data.Graph as G
17
20
import Data.List (maximumBy , nub )
18
21
import qualified Data.List as List
@@ -36,7 +39,7 @@ import System.Environment (getArgs)
36
39
import qualified System.IO as IO
37
40
import qualified System.Process as Process
38
41
import qualified Text.ParserCombinators.ReadP as Read
39
- import Turtle hiding (arg , echo , fold , prefix , s , x )
42
+ import Turtle hiding (arg , fold , s , x )
40
43
import qualified Turtle
41
44
import Types (PackageName , mkPackageName , runPackageName , untitledPackageName , preludePackageName )
42
45
@@ -60,6 +63,9 @@ data PackageConfig = PackageConfig
60
63
pathToTextUnsafe :: Turtle. FilePath -> Text
61
64
pathToTextUnsafe = either (error " Path.toText failed" ) id . Path. toText
62
65
66
+ shellToIOText :: Turtle. Shell Line -> IO [Text ]
67
+ shellToIOText shellLines = Turtle. fold (fmap lineToText shellLines) Foldl. list
68
+
63
69
readPackageFile :: IO PackageConfig
64
70
readPackageFile = do
65
71
exists <- testfile packageFile
@@ -82,6 +88,7 @@ packageConfigToJSON =
82
88
, " source"
83
89
, " depends"
84
90
]
91
+ , confIndent = Spaces 2
85
92
}
86
93
87
94
packageSetToJSON :: PackageSet -> Text
@@ -90,7 +97,7 @@ packageSetToJSON =
90
97
. TB. toLazyText
91
98
. encodePrettyToTextBuilder' config
92
99
where
93
- config = defConfig { confCompare = compare }
100
+ config = defConfig { confCompare = compare , confIndent = Spaces 2 }
94
101
95
102
writePackageFile :: PackageConfig -> IO ()
96
103
writePackageFile =
@@ -203,7 +210,7 @@ installImpl config@PackageConfig{ depends } = do
203
210
getPureScriptVersion :: IO Version
204
211
getPureScriptVersion = do
205
212
let pursProc = inproc " purs" [ " --version" ] empty
206
- outputLines <- Turtle. fold ( fmap lineToText pursProc) Foldl. list
213
+ outputLines <- shellToIOText pursProc
207
214
case outputLines of
208
215
[onlyLine]
209
216
| results@ (_ : _) <- Read. readP_to_S parseVersion (T. unpack onlyLine) ->
@@ -462,6 +469,55 @@ verify arg = do
462
469
let srcGlobs = map (pathToTextUnsafe . (</> (" src" </> " **" </> " *.purs" )) . dirFor) dependencies
463
470
procs " purs" (" compile" : srcGlobs) empty
464
471
472
+ data BowerInfoRepo = BowerInfoRepo
473
+ { url :: Text
474
+ } deriving (Show , Eq , Generic , Aeson.FromJSON )
475
+
476
+ data BowerInfo = BowerInfo
477
+ { bower_name :: Text
478
+ , bower_repository :: BowerInfoRepo
479
+ , bower_dependencies :: Map. Map Text Text
480
+ , bower_version :: Text
481
+ } deriving (Show , Eq , Generic )
482
+ instance Aeson. FromJSON BowerInfo where
483
+ parseJSON = Aeson. genericParseJSON Aeson. defaultOptions
484
+ { fieldLabelModifier = drop 6
485
+ }
486
+
487
+ data BowerOutput = BowerOutput
488
+ { latest :: BowerInfo
489
+ } deriving (Show , Eq , Generic , Aeson.FromJSON )
490
+
491
+ addFromBower :: String -> IO ()
492
+ addFromBower name = do
493
+ let bowerProc = inproc " bower" [ " info" , T. pack name, " --json" , " -l=error" ] empty
494
+ result <- fold <$> shellToIOText bowerProc
495
+ if T. null result
496
+ then exitWithErr " Error: Does the package exist on Bower?"
497
+ else do
498
+ let result' = do
499
+ bowerOutput <- Aeson. eitherDecodeStrict $ encodeUtf8 result
500
+ let bowerInfo = latest bowerOutput
501
+ pkgName <- mkPackageName' $ bower_name bowerInfo
502
+ packageNames <- traverse mkPackageName' $ Map. keys (bower_dependencies bowerInfo)
503
+ pure $
504
+ ( pkgName
505
+ , PackageInfo
506
+ (url $ bower_repository bowerInfo)
507
+ (" v" <> bower_version bowerInfo)
508
+ packageNames
509
+ )
510
+ case result' of
511
+ Right (pkgName, info) -> do
512
+ pkg <- readPackageFile
513
+ db <- readPackageSet pkg
514
+ writePackageSet pkg $ Map. insert pkgName info db
515
+ echoT $ " Successfully wrote " <> runPackageName pkgName <> " to package set."
516
+ Left errors -> echoT $ " Errors processing Bower Info: " <> (T. pack errors)
517
+ where
518
+ stripBowerNamePrefix s = fromMaybe s $ T. stripPrefix " purescript-" s
519
+ mkPackageName' = Bifunctor. first show . mkPackageName . stripBowerNamePrefix
520
+
465
521
main :: IO ()
466
522
main = do
467
523
IO. hSetEncoding IO. stdout IO. utf8
@@ -526,6 +582,9 @@ main = do
526
582
<|> (VerifyAll <$> optional (fromString <$> after)))
527
583
Opts. <**> Opts. helper)
528
584
(Opts. progDesc " Verify that the named package builds correctly. If no package is specified, verify that all packages in the package set build correctly." ))
585
+ , Opts. command " add-from-bower"
586
+ (Opts. info (addFromBower <$> pkg Opts. <**> Opts. helper)
587
+ (Opts. progDesc " Add a package from the Bower registry to the package set. This requires Bower to be installed on your system." ))
529
588
]
530
589
where
531
590
pkg = Opts. strArgument $
0 commit comments