{- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. -} module Main ( main ) where import Data.Char (isNumber) import Data.List.NonEmpty (NonEmpty(..)) import Control.Monad.Catch (MonadThrow(..)) import Control.Monad.IO.Class (MonadIO(..)) 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 Data.Text (Text) import qualified Data.Text as Text import qualified Data.Text.IO as Text.IO import Control.Monad.Trans.Reader (ReaderT(..)) import SlackBuilder.Package (PackageDescription(..)) import qualified SlackBuilder.Package as Package import Text.URI.QQ (uri) import Data.Foldable (for_, find) import GHC.Records (HasField(..)) import System.Process (CmdSpec(..)) autoUpdatable :: [PackageDescription] autoUpdatable = [ PackageDescription { latest = let ghArguments = PackageOwner{ owner = "universal-ctags", name = "ctags" } templateTail = [ Package.VersionPlaceholder , Package.StaticPlaceholder "/ctags-" , Package.VersionPlaceholder , Package.StaticPlaceholder ".tar.gz" ] template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/universal-ctags/ctags/archive/" :| templateTail in Package.Updater { detectLatest = latestGitHub ghArguments "(v)\\." , getVersion = reuploadWithTemplate template [] , is64 = False } , name = "universal-ctags" , downloaders = mempty } , PackageDescription { latest = let packagistArguments = PackageOwner{ owner = "composer", name = "composer" } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://getcomposer.org/download/" :| [Package.VersionPlaceholder, Package.StaticPlaceholder "/composer.phar"] in Package.Updater { detectLatest = latestPackagist packagistArguments , getVersion = downloadWithTemplate template , is64 = False } , name = "composer" , downloaders = mempty } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "jitsi" , name = "jitsi-meet-electron" } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/jitsi/jitsi-meet-electron/releases/download/v" :| Package.VersionPlaceholder : [Package.StaticPlaceholder "/jitsi-meet-x86_64.AppImage"] in Package.Updater { detectLatest = latestGitHub ghArguments "(v)*" , getVersion = downloadWithTemplate template , is64 = True } , name = "jitsi-meet-desktop" , downloaders = mempty } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "php" , name = "php-src" } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://www.php.net/distributions/php-" :| Package.VersionPlaceholder : [Package.StaticPlaceholder ".tar.xz"] in Package.Updater { detectLatest = latestGitHub ghArguments "(php-)8.2.\\d" , getVersion = downloadWithTemplate template , is64 = False } , name = "php82" , downloaders = mempty } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "kovidgoyal" , name = "kitty" } templateTail = [ Package.StaticPlaceholder "/kitty-" , Package.VersionPlaceholder , Package.StaticPlaceholder ".tar.xz" ] template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/kovidgoyal/kitty/releases/download/v" :| Package.VersionPlaceholder : templateTail in Package.Updater { detectLatest = latestGitHub ghArguments "(v)\\." , getVersion = reuploadWithTemplate template [RawCommand "go" ["mod", "vendor"]] , is64 = False } , name = "kitty" , downloaders = mempty } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "rdiff-backup" , name = "rdiff-backup" } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/rdiff-backup/rdiff-backup/releases/download/v" :| Package.VersionPlaceholder : Package.StaticPlaceholder "/rdiff-backup-" : Package.VersionPlaceholder : [Package.StaticPlaceholder ".tar.gz"] in Package.Updater { detectLatest = latestGitHub ghArguments "(v)\\." , getVersion = reuploadWithTemplate template [] , is64 = False } , name = "rdiff-backup" , downloaders = mempty } , PackageDescription { latest = let needle = "Linux—" textArguments = TextArguments { textURL = "https://help.webex.com/en-us/article/mqkve8/Webex-App-%7C-Release-notes" , versionPicker = Text.takeWhile (liftA2 (||) (== '.') isNumber) . Text.drop (Text.length needle) . snd . Text.breakOn needle } template = Package.DownloadTemplate $ pure $ Package.StaticPlaceholder "https://binaries.webex.com/WebexDesktop-Ubuntu-Official-Package/Webex.deb" in Package.Updater { detectLatest = latestText textArguments , getVersion = downloadWithTemplate template , is64 = True } , name = "webex" , downloaders = mempty } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "librsync" , name = "librsync" } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/librsync/librsync/archive/v" :| Package.VersionPlaceholder : Package.StaticPlaceholder "/librsync-" : Package.VersionPlaceholder : [Package.StaticPlaceholder ".tar.gz"] in Package.Updater { detectLatest = latestGitHub ghArguments "(v)\\." , getVersion = reuploadWithTemplate template [] , is64 = True } , name = "librsync" , downloaders = mempty } , PackageDescription { latest = let textArguments = TextArguments { textURL = "https://downloads.dlang.org/releases/LATEST" , versionPicker = Text.strip } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://downloads.dlang.org/releases/2.x/" :| Package.VersionPlaceholder : Package.StaticPlaceholder "/dmd." : Package.VersionPlaceholder : [Package.StaticPlaceholder ".linux.tar.xz"] in Package.Updater { detectLatest = latestText textArguments , getVersion = downloadWithTemplate template , is64 = False } , name = "dmd" , downloaders = mempty } , PackageDescription { latest = let textArguments = TextArguments { textURL = "https://downloads.dlang.org/releases/LATEST" , versionPicker = Text.strip } template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://codeload.github.com/dlang/tools/tar.gz/v" :| [Package.VersionPlaceholder] in Package.Updater { detectLatest = latestText textArguments , getVersion = reuploadWithTemplate template [] , is64 = False } , name = "d-tools" , downloaders = let dubArguments = PackageOwner{ owner = "dlang", name = "dub" } dscannerArguments = PackageOwner{ owner = "dlang-community", name = "D-Scanner" } dcdArguments = PackageOwner{ owner = "dlang-community", name = "DCD" } latestDub = Package.Updater { detectLatest = latestGitHub dubArguments "(v)\\." , getVersion = reuploadWithTemplate dubTemplate [] , is64 = False } latestDscanner = Package.Updater { detectLatest = latestGitHub dscannerArguments "(v)\\." , getVersion = cloneFromGit dscannerURI "v" , is64 = False } dcdURI = [uri|https://github.com/dlang-community/DCD.git|] latestDcd = Package.Updater { detectLatest = latestGitHub dcdArguments "(v)\\." , getVersion = cloneFromGit dcdURI "v" , is64 = False } dubTemplate = Package.DownloadTemplate $ Package.StaticPlaceholder "https://codeload.github.com/dlang/dub/tar.gz/v" :| [Package.VersionPlaceholder] dscannerURI = [uri|https://github.com/dlang-community/D-Scanner.git|] in Map.fromList [ ("DUB", latestDub) , ("DSCANNER", latestDscanner) , ("DCD", latestDcd) ] } , PackageDescription { latest = let ghArguments = PackageOwner { owner = "simd-everywhere" , name = "simde" } templateTail = [ Package.StaticPlaceholder "/simde-amalgamated-" , Package.VersionPlaceholder , Package.StaticPlaceholder ".tar.xz" ] template = Package.DownloadTemplate $ Package.StaticPlaceholder "https://github.com/simd-everywhere/simde/releases/download/v" :| Package.VersionPlaceholder : templateTail in Package.Updater { detectLatest = latestGitHub ghArguments "(v)\\." , getVersion = downloadWithTemplate template , is64 = False } , name = "simde" , downloaders = mempty } ] up2Date :: Maybe Text -> SlackBuilderT () up2Date = \case Nothing -> for_ autoUpdatable go Just packageName | Just foundPackage <- find ((packageName ==) . getField @"name") autoUpdatable -> go foundPackage | otherwise -> throwM $ UpdaterNotFound packageName where go package = getAndLogLatest package >>= mapM_ updatePackageIfRequired >> liftIO (putStrLn "") check :: SlackBuilderT () check = for_ autoUpdatable go where go package = getAndLogLatest package >>= mapM_ checkUpdateAvailability >> liftIO (putStrLn "") main :: IO () main = do programCommand <- execParser slackBuilderParser settings <- Toml.decodeFile settingsCodec "config/config.toml" latestVersion <- flip runReaderT settings $ runSlackBuilderT $ executeCommand programCommand maybe (pure ()) Text.IO.putStrLn latestVersion where executeCommand = \case CheckCommand -> check >> pure Nothing Up2DateCommand packageName -> up2Date packageName >> pure Nothing