diff --git a/Rakefile b/Rakefile index 45da38b..29f9aaf 100644 --- a/Rakefile +++ b/Rakefile @@ -101,7 +101,7 @@ module SlackBuilder checksum = SlackBuilder.download URI(uri), tarball download = "https://download.dlackware.com/hosted-sources/universal-ctags/ctags-#{version}.tar.gz" - write_info package, downloads: [Download.new(download, checksum.hexdigest)] + write_info package, downloads: [Download.new(download, checksum)] update_slackbuild_version 'development/universal-ctags', version sh 'scp', tarball, "#{CONFIG[:remote_path]}/universal-ctags" @@ -126,7 +126,7 @@ module SlackBuilder uri = "https://getcomposer.org/download/#{version}/composer.phar" checksum = SlackBuilder.download URI(uri), 'slackbuilds/development/composer/composer.phar' - write_info package, downloads: [Download.new(uri, checksum.hexdigest)] + write_info package, downloads: [Download.new(uri, checksum)] update_slackbuild_version 'development/composer', version commit 'development/composer', version @@ -141,7 +141,7 @@ module SlackBuilder uri = "https://github.com/jitsi/jitsi-meet-electron/releases/download/v#{version}/jitsi-meet-x86_64.AppImage" checksum = SlackBuilder.download URI(uri), 'slackbuilds/network/jitsi-meet-desktop/jitsi-meet-x86_64.AppImage' - write_info package, downloads: [Download.new(uri, checksum.hexdigest, is64: true)] + write_info package, downloads: [Download.new(uri, checksum, is64: true)] update_slackbuild_version 'network/jitsi-meet-desktop', version commit 'network/jitsi-meet-desktop', version end diff --git a/app/Main.hs b/app/Main.hs index 654dcf7..76c985f 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -45,6 +45,8 @@ main = do | otherwise -> pure Nothing CloneCommand repo tarball tagPrefix -> fmap (Text.pack . show) <$> clone repo tarball tagPrefix + DownloadAndDeployCommand uri tarball -> fmap (Text.pack . show) + <$> downloadAndDeploy uri tarball chooseTransformFunction (Just "php") = phpTransform chooseTransformFunction (Just "rdiff-backup") = Text.stripPrefix "v" chooseTransformFunction _ = stripPrefix "v" diff --git a/app/SlackBuilder/CommandLine.hs b/app/SlackBuilder/CommandLine.hs index 1b0d7ed..23bf840 100644 --- a/app/SlackBuilder/CommandLine.hs +++ b/app/SlackBuilder/CommandLine.hs @@ -29,6 +29,7 @@ data SlackBuilderCommand | ArchiveCommand Text Text String Text | DownloadCommand Text String | CloneCommand Text Text Text + | DownloadAndDeployCommand Text Text deriving (Eq, Show) data PackagistArguments = PackagistArguments @@ -73,6 +74,7 @@ slackBuilderCommand = subparser <> command "archive" (info archiveCommand mempty) <> command "download" (info downloadCommand mempty) <> command "clone" (info cloneCommand mempty) + <> command "deploy" (info deployCommand mempty) where slackBuildCommand = SlackBuildCommand <$> argument str (metavar "PATH") @@ -93,3 +95,6 @@ slackBuilderCommand = subparser <$> argument str (metavar "REPO") <*> argument str (metavar "TARBALL") <*> argument str (metavar "TAG_PREFIX") + deployCommand = DownloadAndDeployCommand + <$> argument str (metavar "URI") + <*> argument str (metavar "TARBALL") diff --git a/app/SlackBuilder/Config.hs b/app/SlackBuilder/Config.hs index d7652e8..c2a7f0b 100644 --- a/app/SlackBuilder/Config.hs +++ b/app/SlackBuilder/Config.hs @@ -1,5 +1,6 @@ module SlackBuilder.Config ( Settings(..) + , MaintainerSettings(..) , settingsCodec ) where @@ -13,6 +14,12 @@ data Settings = Settings , branch :: Text , downloadURL :: Text , remotePath :: Text + , maintainer :: MaintainerSettings + } deriving (Eq, Show) + +data MaintainerSettings = MaintainerSettings + { name :: !Text + , email :: !Text } deriving (Eq, Show) settingsCodec :: Toml.TomlCodec Settings @@ -22,3 +29,9 @@ settingsCodec = Settings <*> Toml.text "branch" .= branch <*> Toml.text "download_url" .= downloadURL <*> Toml.text "remote_path" .= remotePath + <*> Toml.table maintainerSettingsCodec "maintainer" .= maintainer + +maintainerSettingsCodec :: Toml.TomlCodec MaintainerSettings +maintainerSettingsCodec = MaintainerSettings + <$> Toml.text "name" .= name + <*> Toml.text "email" .= email diff --git a/app/SlackBuilder/Download.hs b/app/SlackBuilder/Download.hs index c6516d4..2201c25 100644 --- a/app/SlackBuilder/Download.hs +++ b/app/SlackBuilder/Download.hs @@ -3,6 +3,7 @@ module SlackBuilder.Download , cloneAndArchive , commit , download + , downloadAndDeploy , hostedSources , remoteFileExists , updateSlackBuildVersion @@ -173,10 +174,11 @@ download uri target = traverse (runReq defaultHttpConfig . go . fst) clone :: Text -> Text -> Text -> SlackBuilderT (Maybe (Digest MD5)) clone repo tarball tagPrefix = do + repository' <- SlackBuilderT $ asks repository let tarballPath = Text.unpack tarball nameVersion = Text.pack $ takeBaseName tarballPath remotePath = Text.pack $ joinPath $ ("/" :) $ drop 1 $ splitPath tarballPath - localPath = "slackbuilds" tarballPath + localPath = repository' tarballPath remoteFileExists' <- remoteFileExists remotePath if remoteFileExists' @@ -187,3 +189,19 @@ clone repo tarball tagPrefix = do in cloneAndArchive repo nameVersion tarballPath tagPrefix >> uploadCommand tarball remotePath >> liftIO (runConduitRes go) <&> Just + +downloadAndDeploy :: Text -> Text -> SlackBuilderT (Maybe (Digest MD5)) +downloadAndDeploy uri tarball = do + repository' <- SlackBuilderT $ asks repository + let tarballPath = Text.unpack tarball + remotePath = Text.pack $ joinPath $ ("/" :) $ drop 1 $ splitPath tarballPath + localPath = repository' tarballPath + remoteFileExists' <- remoteFileExists remotePath + + if remoteFileExists' + then + hostedSources remotePath >>= flip download localPath + else do + checksum <- liftIO (mkURI uri) >>= flip download localPath + uploadCommand tarball remotePath + pure checksum diff --git a/app/SlackBuilder/Package.hs b/app/SlackBuilder/Package.hs new file mode 100644 index 0000000..cc07cc5 --- /dev/null +++ b/app/SlackBuilder/Package.hs @@ -0,0 +1,104 @@ +module SlackBuilder.Package + ( DownloadPlaceholder(..) + , Download(..) + , PackageInfo(..) + , Maintainer(..) + , Updater(..) + , infoTemplate + ) where + +import Data.List.NonEmpty (NonEmpty) +import Data.Text (Text) +import qualified Data.Text as Text +import Text.URI (URI(..)) +import qualified Text.URI as URI +import Crypto.Hash (Digest, MD5) +import GHC.Records (HasField(..)) +import System.FilePath (takeBaseName) +import Data.List (partition) +import SlackBuilder.Trans + +-- | Download URI with the MD5 checksum of the target. +data Download = Download + { download :: URI + , md5sum :: Digest MD5 + , is64 :: Bool + } deriving (Eq, Show) + +-- | Data used to generate an .info file. +data PackageInfo = PackageInfo + { path :: FilePath + , version :: Text + , homepage :: Text + , requires :: [Text] + , maintainer :: Maintainer + } deriving (Eq, Show) + +-- | Package maintainer information. +data Maintainer = Maintainer + { name :: Text + , email :: Text + } deriving (Eq, Show) + +-- | Appears in the download URI template and specifies which part of the URI +-- should be replaced with the package version. +data DownloadPlaceholder + = StaticPlaceholder Text + | VersionPlaceholder + deriving Eq + +instance Show DownloadPlaceholder + where + show (StaticPlaceholder staticPlaceholder) = Text.unpack staticPlaceholder + show VersionPlaceholder = "{version}" + +-- | List of URI components, including version placeholders. +newtype DownloadTemplate = DownloadTemplate (NonEmpty DownloadPlaceholder) + deriving Eq + +instance Show DownloadTemplate + where + show (DownloadTemplate components) = concatMap show components + +-- | Function used to get the latest version of a source. +newtype Updater = Updater (SlackBuilderT (Maybe Text)) + +packageName :: PackageInfo -> Text +packageName PackageInfo{ path } = Text.pack $ takeBaseName path + +infoTemplate :: PackageInfo -> [Download] -> Text +infoTemplate package downloads = + let (downloads64, downloads32) = partition (getField @"is64") downloads + (download32, md5sum32, download64, md5sum64) = downloadEntries downloads64 downloads32 + + in Text.unlines + [ "PRGNAM=\"" <> packageName package <> "\"" + , "VERSION=\"" <> getField @"version" package <> "\"" + , "HOMEPAGE=\"" <> getField @"homepage" package <> "\"" + , "DOWNLOAD=\"" <> download32 <> "\"" + , "MD5SUM=\"" <> md5sum32 <> "\"" + , "DOWNLOAD_x86_64=\"" <> download64 <> "\"" + , "MD5SUM_x86_64=\"" <> md5sum64 <> "\"" + , "REQUIRES=\"" <> Text.unwords (getField @"requires" package) <> "\"" + , "MAINTAINER=\"" <> getField @"name" (getField @"maintainer" package) <> "\"" + , "EMAIL=\"" <> getField @"email" (getField @"maintainer" package) <> "\"" + ] + +downloadEntries :: [Download] -> [Download] -> (Text, Text, Text, Text) +downloadEntries downloads64 downloads32 = + let download32 = + if null downloads32 && not (null downloads64) + then + "UNSUPPORTED" + else + Text.intercalate " \\\n " + $ URI.render . getField @"download" <$> downloads32 + + md5sum32 = Text.intercalate " \\\n " + $ Text.pack . show . getField @"md5sum" <$> downloads32 + download64 = Text.intercalate " \\\n " + $ URI.render . getField @"download" <$> downloads64 + md5sum64 = Text.intercalate " \\\n " + $ Text.pack . show . getField @"md5sum" <$> downloads64 + + in (download32, md5sum32, download64, md5sum64) diff --git a/config/config.toml.example b/config/config.toml.example index 7efe248..dce29ef 100644 --- a/config/config.toml.example +++ b/config/config.toml.example @@ -3,3 +3,7 @@ repository = "./slackbuilds" branch = "user/nick/updates" download_url = "https://example.com/some/path" remote_path = "example.com:/srv/httpd/some/path" + +[maintainer] +name = "Maintainer Name" +email = "maintainer@example.com" diff --git a/lib/download.rb b/lib/download.rb index ef255f6..80ff30b 100644 --- a/lib/download.rb +++ b/lib/download.rb @@ -31,16 +31,7 @@ module SlackBuilder end def self.download_and_deploy(uri, tarball) - remote_path = tarball[tarball.index('/')..] - - if remote_file_exists?(remote_path) - uri = URI hosted_sources(remote_path) - return download(uri, "slackbuilds/#{tarball}").hexdigest - end - - checksum = download uri, "slackbuilds/#{tarball}" - sh(*upload_command(tarball, remote_path)) - checksum.hexdigest + `./bin/slackbuilder deploy #{uri} #{tarball}`.strip end private_class_method def self.upload_command(local_path, remote_path) diff --git a/slackbuilder.cabal b/slackbuilder.cabal index 076707c..ddf3135 100644 --- a/slackbuilder.cabal +++ b/slackbuilder.cabal @@ -1,6 +1,6 @@ cabal-version: 2.4 name: slackbuilder -version: 0.1.0.0 +version: 1.0.0.0 synopsis: Slackware build scripts and configuration files. bug-reports: https://git.caraus.tech/OSS/slackbuilder/issues @@ -22,6 +22,7 @@ executable slackbuilder SlackBuilder.CommandLine SlackBuilder.Config SlackBuilder.Download + SlackBuilder.Package SlackBuilder.Trans SlackBuilder.Updater default-extensions: