Use TOML configuration

This commit is contained in:
Eugen Wissner 2023-08-09 20:59:42 +02:00
parent 69ba04a731
commit 43ebbc5e67
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
8 changed files with 150 additions and 17 deletions

2
.gitignore vendored
View File

@ -15,12 +15,12 @@
*.pk3
*.run
*.deb
*.jar
*~
.directory
*.phar
/slackbuilds/
/config/config.toml
/config/config.rb
/vendor/
/.bundle/

View File

@ -6,14 +6,23 @@ import qualified Data.Text.IO as Text.IO
import Data.Maybe (fromMaybe)
import Options.Applicative (execParser)
import SlackBuilder.CommandLine
import SlackBuilder.Config
import SlackBuilder.Updater
import qualified Toml
import qualified Data.Text as Text
main :: IO ()
main = do
programCommand <- execParser slackBuilderParser
settings <- Toml.decodeFile settingsCodec "config/config.toml"
latestVersion <- case programCommand of
PackagistCommand packagistArguments ->
latestPackagist packagistArguments
TextCommand textArguments -> latestText textArguments
GhCommand ghArguments -> latestGitHub settings ghArguments (stripPrefix "v")
Text.IO.putStrLn $ fromMaybe "" latestVersion
where
stripPrefix prefix string = Just
$ fromMaybe string
$ Text.stripPrefix prefix string

View File

@ -1,5 +1,6 @@
module SlackBuilder.CommandLine
( SlackBuilderCommand(..)
( GhArguments(..)
, SlackBuilderCommand(..)
, PackagistArguments(..)
, TextArguments(..)
, slackBuilderParser
@ -21,12 +22,18 @@ import Options.Applicative
data SlackBuilderCommand
= PackagistCommand PackagistArguments
| TextCommand TextArguments
| GhCommand GhArguments
data PackagistArguments = PackagistArguments
{ vendor :: Text
, name :: Text
} deriving (Eq, Show)
data GhArguments = GhArguments
{ owner :: Text
, name :: Text
} deriving (Eq, Show)
newtype TextArguments = TextArguments Text
packagistArguments :: Parser PackagistArguments
@ -37,6 +44,11 @@ packagistArguments = PackagistArguments
textArguments :: Parser TextArguments
textArguments = TextArguments <$> argument str (metavar "URL")
ghArguments :: Parser GhArguments
ghArguments = GhArguments
<$> argument str (metavar "OWNER")
<*> argument str (metavar "NAME")
slackBuilderParser :: ParserInfo SlackBuilderCommand
slackBuilderParser = info slackBuilderCommand fullDesc
@ -44,3 +56,4 @@ slackBuilderCommand :: Parser SlackBuilderCommand
slackBuilderCommand = subparser
$ command "packagist" (info (PackagistCommand <$> packagistArguments) mempty)
<> command "text" (info (TextCommand <$> textArguments) mempty)
<> command "github" (info (GhCommand <$> ghArguments) mempty)

View File

@ -0,0 +1,16 @@
module SlackBuilder.Config
( Settings(..)
, settingsCodec
) where
import Data.Text (Text)
import Toml ((.=))
import qualified Toml
newtype Settings = Settings
{ ghToken :: Text
} deriving (Eq, Show)
settingsCodec :: Toml.TomlCodec Settings
settingsCodec = Settings
<$> Toml.text "gh_token" .= ghToken

View File

@ -1,18 +1,23 @@
module SlackBuilder.Updater
( latestPackagist
( latestGitHub
, latestPackagist
, latestText
) where
import SlackBuilder.Config
import qualified Data.Aeson as Aeson
import Data.Aeson ((.:))
import Data.Aeson.TH (defaultOptions, deriveJSON)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text.Encoding
import Data.Vector (Vector)
import Data.Vector (Vector, (!?))
import qualified Data.Vector as Vector
import Network.HTTP.Req
( runReq
( header
, runReq
, defaultHttpConfig
, req
, GET(..)
@ -20,10 +25,12 @@ import Network.HTTP.Req
, jsonResponse
, NoReqBody(..)
, (/:)
, responseBody, useHttpsURI, bsResponse
, responseBody, useHttpsURI, bsResponse, POST (POST), ReqBodyJson (ReqBodyJson)
)
import Text.URI (mkURI)
import SlackBuilder.CommandLine
import qualified Data.Aeson.KeyMap as KeyMap
import GHC.Records (HasField(..))
newtype PackagistPackage = PackagistPackage
{ version :: Text
@ -37,6 +44,48 @@ newtype PackagistResponse = PackagistResponse
$(deriveJSON defaultOptions ''PackagistResponse)
newtype GhRefNode = GhRefNode
{ name :: Text
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRefNode)
newtype GhRef = GhRef
{ nodes :: Vector GhRefNode
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRef)
newtype GhRepository = GhRepository
{ refs :: GhRef
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRepository)
newtype GhData = GhData
{ repository :: GhRepository
} deriving (Eq, Show)
instance Aeson.FromJSON GhData where
parseJSON (Aeson.Object keyMap)
| Just data' <- KeyMap.lookup "data" keyMap =
GhData <$> Aeson.withObject "GhData" (.: "repository") data'
parseJSON v = fail "data key not found in the response"
data GhVariables = GhVariables
{ name :: Text
, owner :: Text
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhVariables)
data GhQuery = GhQuery
{ query :: Text
, variables :: GhVariables
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhQuery)
latestPackagist :: PackagistArguments -> IO (Maybe Text)
latestPackagist PackagistArguments{..} = do
packagistResponse <- runReq defaultHttpConfig $
@ -59,3 +108,37 @@ latestText (TextArguments textArguments) = do
<$> packagistResponse
where
go uri = req GET uri NoReqBody bsResponse mempty
latestGitHub :: Settings -> GhArguments -> (Text -> Maybe Text) -> IO (Maybe Text)
latestGitHub Settings{..} GhArguments{..} versionTransform = do
ghResponse <- runReq defaultHttpConfig $
let uri = https "api.github.com" /: "graphql"
query = GhQuery
{ query = githubQuery
, variables = GhVariables
{ owner = owner
, name = name
}
}
authorizationHeader = header "authorization"
$ Text.Encoding.encodeUtf8
$ "Bearer " <> ghToken
in req POST uri (ReqBodyJson query) jsonResponse
$ authorizationHeader <> header "User-Agent" "SlackBuilder"
let ghNodes = nodes $ refs $ repository $ responseBody ghResponse
refs' = Vector.reverse
$ Vector.catMaybes
$ versionTransform . getField @"name" <$> ghNodes
pure $ refs' !? 0
where
githubQuery =
"query ($name: String!, $owner: String!) {\n\
\ repository(name: $name, owner: $owner) {\n\
\ refs(last: 10, refPrefix: \"refs/tags/\", orderBy: { field: TAG_COMMIT_DATE, direction: ASC }) {\n\
\ nodes {\n\
\ id,\n\
\ name\n\
\ }\n\
\ }\n\
\ }\n\
\}"

View File

@ -0,0 +1 @@
gh_token = ""

View File

@ -36,7 +36,7 @@ module SlackBuilder
GQL
private_constant :GITHUB_QUERY
def initialize(owner, name, version_transform = ->(v) { v.delete_prefix 'v' })
def initialize(owner, name, version_transform = nil)
super()
@owner = owner
@ -45,6 +45,16 @@ module SlackBuilder
end
def latest
if @version_transform.nil?
`./bin/slackbuilder github #{@owner} #{@name}`.strip
else
latest_with_transform
end
end
private
def latest_with_transform
post_data = {
'query' => GITHUB_QUERY,
'variables' => { 'name' => @name, 'owner' => @owner }
@ -57,8 +67,6 @@ module SlackBuilder
filter_versions_from_response JSON.parse(response.body)
end
private
def filter_versions_from_response(response)
response['data']['repository']['refs']['nodes']
.map { |node| @version_transform.call node['name'] }

View File

@ -2,12 +2,10 @@ cabal-version: 2.4
name: slackbuilder
version: 0.1.0.0
-- A short (one-line) description of the package.
-- synopsis:
-- A longer description of the package.
-- description:
synopsis: Slackware build scripts and configuration files.
bug-reports: https://git.caraus.tech/OSS/slackbuilder/issues
license: MPL-2.0
@ -25,11 +23,15 @@ executable slackbuilder
other-modules:
SlackBuilder.CommandLine
SlackBuilder.Config
SlackBuilder.Updater
default-extensions:
DataKinds
DuplicateRecordFields
OverloadedStrings
RecordWildCards
TemplateHaskell
TypeApplications
build-depends:
aeson ^>= 2.2.0,
base ^>= 4.16.4.0,
@ -38,6 +40,7 @@ executable slackbuilder
optparse-applicative ^>= 0.18.1,
req ^>=3.13,
text ^>= 2.0,
tomland ^>= 1.3.3,
unordered-containers ^>= 0.2.19,
vector ^>= 0.13.0
hs-source-dirs: app