copr (empty) → 1.0.0
raw patch · 9 files changed
+379/−0 lines, 9 filesdep +aesondep +basedep +bytestringsetup-changed
Dependencies added: aeson, base, bytestring, containers, hlint, http-streams, io-streams, semigroups, text
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- copr.cabal +46/−0
- src/Fedora/Copr.hs +146/−0
- src/Fedora/Copr/CoprBuild.hs +38/−0
- src/Fedora/Copr/CoprProject.hs +43/−0
- src/Fedora/Copr/CoprStatus.hs +21/−0
- src/Fedora/Copr/ListCoprs.hs +41/−0
- tests/hlint.hs +12/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Ricky Elrod++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Ricky Elrod nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ copr.cabal view
@@ -0,0 +1,46 @@+name: copr+version: 1.0.0+synopsis: Haskell interface to the Fedora Copr system+description:+ This provides a Haskell interface to the Fedora Copr public build system.+homepage: https://github.com/CodeBlock/copr-hs+license: BSD3+license-file: LICENSE+author: Ricky Elrod+maintainer: ricky@elrod.me+copyright: 2014 Ricky Elrod+category: Fedora+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules: Fedora.Copr+ , Fedora.Copr.CoprBuild+ , Fedora.Copr.CoprProject+ , Fedora.Copr.CoprStatus+ , Fedora.Copr.ListCoprs++ build-depends: aeson >= 0.6+ , base >=4.6 && <4.7+ , bytestring >= 0.10+ , containers >= 0.5+ , http-streams >= 0.7+ , io-streams >= 1.1+ , semigroups >= 0.12+ , text >= 0.11+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall++test-suite hlint+ hs-source-dirs: tests+ main-is: hlint.hs+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ build-depends: base+ , hlint >= 1.7++source-repository head+ type: git+ location: git://github.com/CodeBlock/copr-hs.git
+ src/Fedora/Copr.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Fedora.Copr+-- Copyright : (c) Ricky Elrod 2014+-- License : BSD3+-- Maintainer : ricky@elrod.me+-- Stability : experimental+-- Portability : portable+--+-- Provides a Haskell interface to the Fedora+-- <http://copr.fedoraproject.org/ Copr> build system+-- <http://copr.fedoraproject.org/api API>.++module Fedora.Copr+ (+ module C+ , CoprConfig (..)+ , Username+ , defaultConfig+ , withConfig+ , addBuild+ , buildStatus+ , coprs+ , new+ ) where++import Fedora.Copr.CoprBuild as C (CoprBuild (), CoprBuildResponse ())+import Fedora.Copr.CoprProject as C (CoprProject (), NewCoprResponse ())+import Fedora.Copr.CoprStatus as C (CoprStatusResponse ())+import Fedora.Copr.ListCoprs as C (Coprs ())++import Data.Aeson+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as C8+import qualified Data.ByteString.Lazy as LS+import Data.Monoid (mappend)+import Network.Http.Client+import qualified System.IO.Streams.ByteString as SBS++data CoprConfig = CoprConfig {+ domain :: Hostname -- ^ The domain on which Copr is hosted.+ , port :: Port -- ^ The port on which Copr operates.+ , login :: S.ByteString -- ^ The API login (/not/ the same as username).+ , token :: S.ByteString -- ^ The API token.+} deriving (Eq, Show)++type Username = S.ByteString+type ProjectName = S.ByteString++defaultConfig :: CoprConfig+defaultConfig = CoprConfig {+ domain = "copr.fedoraproject.org"+ , port = 80+ , login = ""+ , token = ""+}++-- | A utility wrapper for calling API methods with a 'CoprConfig'.+--+-- You can use this to do things like:+--+-- >>> let c = defaultConfig { login = "your_login", token = "your_token" }+-- >>> withConfig c $ coprs "codeblock"+withConfig :: CoprConfig -> (CoprConfig -> IO a) -> IO a+withConfig = flip id++-- | Sets things that are common to all requests that we make.+prepareRequest :: CoprConfig -> Method -> S.ByteString -> RequestBuilder ()+prepareRequest c m url = do+ http m url+ setAccept "application/json"+ setContentType "application/json"+ setAuthorizationBasic (login c) (token c)++finishRequest :: FromJSON a => Connection -> IO a+finishRequest cnx = do+ x <- receiveResponse cnx jsonHandler+ closeConnection cnx+ return x++-- | Perform a GET request to the API, with authentication.+--+-- Requests that don't need authentication result in the authentication+-- details being ignored, so we don't have to worry about not sending them+-- in that case.+apiGet :: FromJSON a => S.ByteString -> CoprConfig -> IO a+apiGet url c = do+ cnx <- openConnection (domain c) (port c)+ q <- buildRequest $ prepareRequest c GET url+ sendRequest cnx q emptyBody+ finishRequest cnx++-- | Perform a POST request to the API, with authentication.+apiPost :: (ToJSON a, FromJSON b) => S.ByteString -> a -> CoprConfig -> IO b+apiPost url d c = do+ cnx <- openConnection (domain c) (port c)+ q <- buildRequest $ do+ prepareRequest c POST url+ setContentLength $ LS.length (encode d)+ body <- SBS.fromLazyByteString (encode d)+ sendRequest cnx q (inputStreamBody body)+ finishRequest cnx++-- | Retrieve a list of copr projects for an individual user.+--+-- This makes use of the @\/api\/coprs/[username]\/@ endpoint.+--+-- > withConfig c $ coprs "codeblock"+coprs :: Username -- ^ The username of the person whose projects we want to list.+ -> CoprConfig -- ^ The configuration to use.+ -> IO Coprs+coprs u = apiGet ("/api/coprs/" `mappend` u `mappend` "/")++-- | Create a new copr project.+--+-- This makes use of the @\/api\/coprs/[username]\/new\/@ endpoint.+--+-- > withConfig c $ new "codeblock" (CoprProject "testproject" [] [] (NEL.fromList ["fedora-20-x86_64"]))+new :: Username -- ^ The username of the person whose project should be created.+ -> CoprProject -- ^ The copr project to be created.+ -> CoprConfig -- ^ The configuration to use.+ -> IO NewCoprResponse+new u = apiPost ("/api/coprs/" `mappend` u `mappend` "/new/")++-- | Add a build to a copr project.+--+-- This makes use of the @\/api\/coprs/[username]\/[project]\/new_build\/@ endpoint.+--+-- > withConfig c $ addBuild "codeblock" "testproject" (CoprBuild (NEL.fromList ["http://example.com/foo-1.0.0.src.rpm"]) 2048 3600)+addBuild :: Username -- ^ The username of the person who owns the copr project.+ -> ProjectName -- ^ The project to add the build to.+ -> CoprBuild -- ^ A representation of the build to add.+ -> CoprConfig -- ^ The configuration to use.+ -> IO CoprBuildResponse+addBuild u p = apiPost ("/api/coprs/" `mappend` u `mappend` "/" `mappend` p `mappend` "/new_build/")++-- | Check the status of a copr build+--+-- This makes use of the @\/api\/coprs\/build_status/[build_id]\/@ endpoint.+--+-- > withConfig c $ buildStatus 1033+buildStatus :: Int -- ^ The build ID number to check.+ -> CoprConfig -- ^ The configuration to use.+ -> IO CoprStatusResponse+buildStatus i = apiGet ("/api/coprs/build_status/" `mappend` C8.pack (show i) `mappend` "/")
+ src/Fedora/Copr/CoprBuild.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE OverloadedStrings #-}++module Fedora.Copr.CoprBuild (+ CoprBuild (..)+ , CoprBuildResponse (..)) where++import Control.Applicative+import Control.Monad (mzero)+import Data.Aeson+import qualified Data.ByteString as S+import qualified Data.List.NonEmpty as NEL++data CoprBuildResponse = CoprBuildResponse {+ output :: String+ , buildId :: Maybe Int+ , message :: Maybe String+ , error :: Maybe String+} deriving (Eq, Show)++instance FromJSON CoprBuildResponse where+ parseJSON (Object v) = CoprBuildResponse <$>+ v .: "output"+ <*> v .:? "id"+ <*> v .:? "message"+ <*> v .:? "error"+ parseJSON _ = mzero++data CoprBuild = CoprBuild {+ packages :: NEL.NonEmpty S.ByteString+ , memory :: Int+ , timeout :: Int+} deriving (Eq, Show)++instance ToJSON CoprBuild where+ toJSON (CoprBuild p m t) = object [ "pkgs" .= S.intercalate " " (NEL.toList p)+ , "memory" .= m+ , "timeout" .= t+ ]
+ src/Fedora/Copr/CoprProject.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}++module Fedora.Copr.CoprProject (+ CoprProject (..)+ , NewCoprResponse (..)) where++import Control.Applicative+import Control.Monad (mzero)+import Data.Aeson+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as C8+import qualified Data.List.NonEmpty as NEL+import qualified Data.Text as T++data NewCoprResponse = NewCoprResponse {+ output :: String+ , message :: Maybe String+ , error :: Maybe String+} deriving (Eq, Show)++instance FromJSON NewCoprResponse where+ parseJSON (Object v) = NewCoprResponse <$>+ v .: "output"+ <*> v .:? "message"+ <*> v .:? "error"+ parseJSON _ = mzero++data CoprProject = CoprProject {+ name :: S.ByteString+ , repos :: [S.ByteString]+ , initialPackages :: [S.ByteString]+ , chroots :: NEL.NonEmpty S.ByteString+ , description :: Maybe S.ByteString+ , instructions :: Maybe S.ByteString+} deriving (Eq, Show)++instance ToJSON CoprProject where+ toJSON (CoprProject n r p c d i) = object $ [ "name" .= n+ , "repos" .= S.intercalate " " r+ , "initial_pkgs" .= S.intercalate " " p+ , "description" .= d+ , "instructions" .= i+ ] ++ map (\x -> T.pack (C8.unpack x) .= C8.pack "y") (NEL.toList c)
+ src/Fedora/Copr/CoprStatus.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE OverloadedStrings #-}++module Fedora.Copr.CoprStatus (+ CoprStatusResponse (..)) where++import Control.Applicative+import Control.Monad (mzero)+import Data.Aeson++data CoprStatusResponse = CoprStatusResponse {+ output :: String+ , status :: Maybe String+ , error :: Maybe String+} deriving (Eq, Show)++instance FromJSON CoprStatusResponse where+ parseJSON (Object v) = CoprStatusResponse <$>+ v .: "output"+ <*> v .:? "status"+ <*> v .:? "error"+ parseJSON _ = mzero
+ src/Fedora/Copr/ListCoprs.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE OverloadedStrings #-}++module Fedora.Copr.ListCoprs (+ Coprs (..)+ , Repo (..)) where++import Control.Applicative+import Control.Monad (mzero)+import Data.Aeson+import qualified Data.ByteString as S+import Data.Map (Map)++data Coprs = Coprs {+ output :: String+ , repos :: Maybe [Repo]+ , error :: Maybe String+} deriving (Eq, Show)++data Repo = Repo {+ yumRepos :: Map S.ByteString S.ByteString+ , additionalRepos :: S.ByteString+ , instructions :: S.ByteString+ , name :: S.ByteString+ , description :: S.ByteString+} deriving (Eq, Show)++instance FromJSON Repo where+ parseJSON (Object v) = Repo <$>+ v .: "yum_repos"+ <*> v .: "additional_repos"+ <*> v .: "instructions"+ <*> v .: "name"+ <*> v .: "description"+ parseJSON _ = mzero++instance FromJSON Coprs where+ parseJSON (Object v) = Coprs <$>+ v .: "output"+ <*> v .:? "repos"+ <*> v .:? "error"+ parseJSON _ = mzero
+ tests/hlint.hs view
@@ -0,0 +1,12 @@+module Main where++import Control.Monad+import Language.Haskell.HLint+import System.Environment+import System.Exit++main :: IO ()+main = do+ args <- getArgs+ hints <- hlint $ ["src", "--cpp-define=HLINT", "--cpp-ansi"] ++ args+ unless (null hints) exitFailure