summaryrefslogtreecommitdiff
path: root/src/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Main.hs')
-rw-r--r--src/Main.hs243
1 files changed, 7 insertions, 236 deletions
diff --git a/src/Main.hs b/src/Main.hs
index fb3a814..b51d4cd 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -7,66 +7,28 @@ module Main
) where
import Data.Char (isNumber)
-import Control.Applicative (Applicative(liftA2))
+import Control.Applicative (Applicative(..))
import Data.List.NonEmpty (NonEmpty(..))
-import qualified Data.List.NonEmpty as NonEmpty
import Control.Monad.Catch (MonadThrow(..))
import Control.Monad.IO.Class (MonadIO(..))
-import Data.Maybe (fromJust, fromMaybe)
import qualified Data.Map as Map
import Options.Applicative (execParser)
import SlackBuilder.CommandLine
import SlackBuilder.Config
import SlackBuilder.Trans
import SlackBuilder.LatestVersionCheck
+import SlackBuilder.Update
import qualified Toml
-import qualified Data.ByteString as ByteString
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text.IO
-import Control.Monad.Trans.Reader (ReaderT(..), asks)
-import SlackBuilder.Download
-import SlackBuilder.Package (PackageDescription(..), PackageUpdateData(..))
+import Control.Monad.Trans.Reader (ReaderT(..))
+import SlackBuilder.Package (PackageDescription(..))
import qualified SlackBuilder.Package as Package
-import Text.URI (URI(..), mkURI)
import Text.URI.QQ (uri)
-import Data.Foldable (Foldable(..), for_, find)
-import qualified Text.URI as URI
-import System.FilePath
- ( (</>)
- , (<.>)
- , dropExtension
- , takeBaseName
- , splitFileName
- , takeDirectory
- , takeFileName
- , dropTrailingPathSeparator
- )
-import SlackBuilder.Info
-import Text.Megaparsec (parse, errorBundlePretty)
+import Data.Foldable (for_, find)
import GHC.Records (HasField(..))
-import System.Process
- ( CmdSpec(..)
- , CreateProcess(..)
- , StdStream(..)
- , withCreateProcess
- , waitForProcess
- )
-import System.Console.ANSI
- ( setSGR
- , SGR(..)
- , ColorIntensity(..)
- , Color(..)
- , ConsoleLayer(..)
- )
-import System.Directory (listDirectory, doesDirectoryExist, withCurrentDirectory, removeDirectoryRecursive)
-import Control.Monad (filterM, void)
-import Data.List (isPrefixOf, isSuffixOf, partition)
-import Conduit (runConduitRes, (.|), yield)
-import Data.Functor ((<&>))
-import Data.Bifunctor (Bifunctor(..))
-import Data.Conduit.Tar (tarFilePath)
-import qualified Data.Conduit.Lzma as Lzma
+import System.Process (CmdSpec(..))
autoUpdatable :: [PackageDescription]
autoUpdatable =
@@ -180,7 +142,7 @@ autoUpdatable =
: Package.VersionPlaceholder
: [Package.StaticPlaceholder ".tar.gz"]
in Package.Updater
- { detectLatest = latestGitHub ghArguments $ Text.stripPrefix "v"
+ { detectLatest = latestGitHub ghArguments stableTagTransform
, getVersion = reuploadWithTemplate template []
, is64 = False
}
@@ -314,197 +276,6 @@ check = for_ autoUpdatable go
>>= mapM_ checkUpdateAvailability
>> liftIO (putStrLn "")
-getAndLogLatest :: PackageDescription -> SlackBuilderT (Maybe PackageUpdateData)
-getAndLogLatest description = do
- let PackageDescription{ latest = Package.Updater{ detectLatest }, name } = description
- liftIO (putStrLn $ Text.unpack name <> ": Retreiving the latest version.")
- detectedVersion <- detectLatest
- category <- fmap Text.pack
- <$> findCategory (Text.unpack name)
- pure $ PackageUpdateData description
- <$> category
- <*> detectedVersion
-
-checkUpdateAvailability :: PackageUpdateData -> SlackBuilderT (Maybe PackageInfo)
-checkUpdateAvailability PackageUpdateData{..} = do
- let name' = Text.unpack $ getField @"name" description
- packagePath = Text.unpack category </> name' </> (name' <.> "info")
- repository' <- SlackBuilderT $ asks repository
- infoContents <- liftIO $ ByteString.readFile $ repository' </> packagePath
-
- case parse parseInfoFile packagePath infoContents of
- Right parsedInfoFile
- | version == getField @"version" parsedInfoFile ->
- liftIO $ do
- setSGR [SetColor Foreground Dull Green]
- Text.IO.putStrLn
- $ getField @"name" description <> " is up to date (Version " <> version <> ")."
- setSGR [Reset]
- pure Nothing
- | otherwise ->
- liftIO $ do
- setSGR [SetColor Foreground Dull Yellow]
- Text.IO.putStr
- $ "A new version of "
- <> getField @"name" description
- <> " " <> getField @"version" parsedInfoFile
- <> " is available (" <> version <> ")."
- setSGR [Reset]
- putStrLn ""
- pure $ Just parsedInfoFile
- Left errorBundle -> liftIO (putStr $ errorBundlePretty errorBundle)
- >> pure Nothing
-
-updatePackageIfRequired :: PackageUpdateData -> SlackBuilderT ()
-updatePackageIfRequired updateData
- = checkUpdateAvailability updateData
- >>= mapM_ (updatePackage updateData)
-
-data DownloadUpdated = DownloadUpdated
- { result :: Package.Download
- , version :: Text
- , is64 :: Bool
- } deriving (Eq, Show)
-
-updateDownload :: Text -> Package.Updater -> SlackBuilderT DownloadUpdated
-updateDownload packagePath Package.Updater{..} = do
- latestDownloadVersion <- fromJust <$> detectLatest
- result <- getVersion packagePath latestDownloadVersion
- pure $ DownloadUpdated
- { result = result
- , version = latestDownloadVersion
- , is64 = is64
- }
-
-cloneFromGit :: URI -> Text -> Text -> Text -> SlackBuilderT Package.Download
-cloneFromGit repo tagPrefix packagePath version = do
- let downloadFileName = URI.unRText
- $ NonEmpty.last $ snd $ fromJust $ URI.uriPath repo
- relativeTarball = Text.unpack packagePath
- </> (dropExtension (Text.unpack downloadFileName) <> "-" <> Text.unpack version)
- (uri', checksum) <- cloneAndUpload (URI.render repo) relativeTarball tagPrefix
- pure $ Package.Download
- { md5sum = checksum
- , download = uri'
- }
-
-downloadWithTemplate :: Package.DownloadTemplate -> Text -> Text -> SlackBuilderT Package.Download
-downloadWithTemplate downloadTemplate packagePath version = do
- repository' <- SlackBuilderT $ asks repository
- uri' <- liftIO $ Package.renderDownloadWithVersion downloadTemplate version
- checksum <- download uri' $ repository' </> Text.unpack packagePath
- pure $ Package.Download uri' $ snd checksum
-
-reuploadWithTemplate :: Package.DownloadTemplate -> [CmdSpec] -> Text -> Text -> SlackBuilderT Package.Download
-reuploadWithTemplate downloadTemplate commands packagePath version = do
- repository' <- SlackBuilderT $ asks repository
- uri' <- liftIO $ Package.renderDownloadWithVersion downloadTemplate version
- let downloadFileName = Text.unpack
- $ URI.unRText
- $ NonEmpty.last $ snd $ fromJust $ URI.uriPath uri'
- packagePathRelativeToCurrent = repository' </> Text.unpack packagePath
-
- (relativeTarball', checksum) <- case commands of
- [] -> do
- (downloadedFileName, checksum) <- download uri' packagePathRelativeToCurrent
- pure (packagePathRelativeToCurrent </> downloadedFileName, checksum)
- _ -> do
- changedArchiveRootName <- extractRemote uri' packagePathRelativeToCurrent
- let relativeTarball = packagePathRelativeToCurrent
- </> fromMaybe downloadFileName changedArchiveRootName
- prepareSource relativeTarball
-
- download' <- handleReupload relativeTarball' downloadFileName
- pure $ Package.Download download' checksum
- where
- name' = Text.pack $ takeBaseName $ Text.unpack packagePath
- prepareSource tarballPath =
- liftIO (traverse (defaultCreateProcess tarballPath) commands)
- >> liftIO (tarCompress tarballPath)
- <* liftIO (removeDirectoryRecursive tarballPath)
- tarCompress tarballPath =
- let archiveBaseFilename = takeFileName tarballPath
- appendTarExtension = (<.> "tar.xz")
- in fmap (appendTarExtension tarballPath,)
- $ withCurrentDirectory (takeDirectory tarballPath)
- $ runConduitRes $ yield archiveBaseFilename
- .| void tarFilePath
- .| Lzma.compress Nothing
- .| sinkFileAndHash (appendTarExtension archiveBaseFilename)
- handleReupload relativeTarball downloadFileName = do
- downloadURL' <- SlackBuilderT $ asks downloadURL
-
- liftIO $ putStrLn $ "Upload the source tarball " <> relativeTarball
- uploadCommand relativeTarball ("/" <> name')
- liftIO $ mkURI $ downloadURL' <> "/" <> name' <> "/" <> Text.pack downloadFileName
- defaultCreateProcess cwd' cmdSpec
- = flip withCreateProcess (const . const . const waitForProcess)
- $ CreateProcess
- { use_process_jobs = False
- , std_out = Inherit
- , std_in = NoStream
- , std_err = Inherit
- , new_session = False
- , env = Nothing
- , detach_console = False
- , delegate_ctlc = False
- , cwd = Just cwd'
- , create_new_console = False
- , create_group = False
- , cmdspec = cmdSpec
- , close_fds = True
- , child_user = Nothing
- , child_group = Nothing
- }
-
-updatePackage :: PackageUpdateData -> PackageInfo -> SlackBuilderT ()
-updatePackage PackageUpdateData{..} info = do
- let packagePath = category <> "/" <> getField @"name" description
- latest' = getField @"latest" description
-
- repository' <- SlackBuilderT $ asks repository
- mainDownload <- (, getField @"is64" latest')
- <$> getField @"getVersion" latest' packagePath version
- moreDownloads <- traverse (updateDownload packagePath)
- $ getField @"downloaders" description
- let (downloads64, allDownloads) = partition snd
- $ mainDownload
- : (liftA2 (,) (getField @"result") (getField @"is64") <$> toList moreDownloads)
- let infoFilePath = repository' </> Text.unpack packagePath
- </> (Text.unpack (getField @"name" description) <.> "info")
- package' = info
- { version = version
- , downloads = getField @"download" . fst <$> allDownloads
- , checksums = getField @"md5sum" . fst <$> allDownloads
- , downloadX64 = getField @"download" . fst <$> downloads64
- , checksumX64 = getField @"md5sum" . fst <$> downloads64
- }
- liftIO $ Text.IO.writeFile infoFilePath $ generate package'
- updateSlackBuildVersion packagePath version
- $ getField @"version" <$> moreDownloads
-
- commit packagePath version
-
-findCategory :: FilePath -> SlackBuilderT (Maybe FilePath)
-findCategory packageName = do
- repository' <- SlackBuilderT $ asks repository
- go repository' [] "" <&> fmap fst . find ((packageName ==) . snd)
- where
- go currentDirectory found accumulatedDirectory = do
- let fullDirectory = currentDirectory </> accumulatedDirectory
- contents <- liftIO $ listDirectory fullDirectory
- case find (isSuffixOf ".info") contents of
- Just _ ->
- let result = first dropTrailingPathSeparator
- $ splitFileName accumulatedDirectory
- in pure $ result : found
- Nothing ->
- let accumulatedDirectories = (accumulatedDirectory </>)
- <$> filter (not . isPrefixOf ".") contents
- directoryFilter = liftIO . doesDirectoryExist
- . (currentDirectory </>)
- in filterM directoryFilter accumulatedDirectories
- >>= traverse (go currentDirectory found) <&> concat
main :: IO ()
main = do