cachix-api 0.4.0 → 0.5.0
raw patch · 26 files changed
+352/−549 lines, 26 filesdep +nix-narinfodep +time
Dependencies added: nix-narinfo, time
Files
- CHANGELOG.md +6/−0
- cachix-api.cabal +16/−25
- cachix-gen-swagger/Main.hs +0/−8
- src/Cachix/API.hs +132/−0
- src/Cachix/API/Error.hs +25/−0
- src/Cachix/API/Signing.hs +45/−0
- src/Cachix/Api.hs +0/−235
- src/Cachix/Api/Error.hs +0/−26
- src/Cachix/Api/Signing.hs +0/−47
- src/Cachix/Api/Types.hs +0/−90
- src/Cachix/Types/BinaryCache.hs +17/−0
- src/Cachix/Types/BinaryCacheAuthenticated.hs +0/−22
- src/Cachix/Types/BinaryCacheCreate.hs +0/−20
- src/Cachix/Types/ByteStringStreaming.hs +15/−0
- src/Cachix/Types/ContentTypes.hs +18/−9
- src/Cachix/Types/CreateToken.hs +0/−17
- src/Cachix/Types/GitHubTeam.hs +0/−18
- src/Cachix/Types/NarFileName.hs +10/−5
- src/Cachix/Types/NarInfo.hs +22/−0
- src/Cachix/Types/NarInfoCreate.hs +1/−1
- src/Cachix/Types/NarInfoHash.hs +22/−0
- src/Cachix/Types/NixCacheInfo.hs +13/−0
- src/Cachix/Types/Permission.hs +8/−0
- src/Cachix/Types/Servant.hs +2/−2
- src/Cachix/Types/SwaggerOrphans.hs +0/−23
- test/Main.hs +0/−1
CHANGELOG.md view
@@ -7,6 +7,12 @@ ## [Unreleased] +## [0.5.0] - 2020-11-06++- Rewrite, cachix-api now serves as the base for cachix package but doesn't contain the full HTTP API anymore.+ This is mainly to improve development feedback loop of the backend.+ See https://app.cachix.org/api/v1/ for the full HTTP API spec.+ ## [0.4.0] - 2020-01-10 - #249 Serve nar content
cachix-api.cabal view
@@ -1,12 +1,13 @@ cabal-version: 2.2 name: cachix-api-version: 0.4.0+version: 0.5.0 synopsis: Servant HTTP API specification for https://cachix.org homepage: https://github.com/cachix/cachix#readme bug-reports: https://github.com/cachix/cachix/issues author: Domen Kožar maintainer: domen@enlambda.com copyright: 2018 Domen Kožar+category: Nix license: Apache-2.0 license-file: LICENSE build-type: Simple@@ -36,29 +37,29 @@ library import: defaults exposed-modules:- Cachix.Api- Cachix.Api.Error- Cachix.Api.Signing- Cachix.Api.Types- Cachix.Types.BinaryCacheAuthenticated- Cachix.Types.BinaryCacheCreate+ Cachix.API+ Cachix.API.Error+ Cachix.API.Signing+ Cachix.Types.BinaryCache+ Cachix.Types.ByteStringStreaming Cachix.Types.ContentTypes- Cachix.Types.CreateToken- Cachix.Types.GitHubTeam Cachix.Types.NarFileName+ Cachix.Types.NarInfo Cachix.Types.NarInfoCreate+ Cachix.Types.NarInfoHash+ Cachix.Types.NixCacheInfo+ Cachix.Types.Permission Cachix.Types.Servant Cachix.Types.Session Cachix.Types.SigningKeyCreate- Cachix.Types.SwaggerOrphans hs-source-dirs: src build-depends: , aeson- , base >=4.7 && <5+ , base >=4.7 && <5 , base16-bytestring , bytestring- , conduit >=1.3.0+ , conduit >=1.3.0 , cookie , cryptonite , deepseq@@ -68,28 +69,18 @@ , jose , lens , memory+ , nix-narinfo , protolude , resourcet- , servant >=0.14.1+ , servant >=0.14.1 , servant-auth , servant-auth-server- , servant-auth-swagger , servant-client- , servant-swagger , string-conv , swagger2 , text+ , time , transformers--executable cachix-gen-swagger- import: defaults- main-is: Main.hs- hs-source-dirs: cachix-gen-swagger- build-depends:- , aeson- , base >=4.7 && <5- , cachix-api- , protolude test-suite cachix-api-test import: defaults
− cachix-gen-swagger/Main.hs
@@ -1,8 +0,0 @@-module Main (main) where--import Cachix.Api (swaggerDoc)-import Data.Aeson (encode)-import Protolude--main :: IO ()-main = print $ encode swaggerDoc
+ src/Cachix/API.hs view
@@ -0,0 +1,132 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeOperators #-}++module Cachix.API+ ( api,+ BinaryCacheAPI (..),+ API,+ CachixAuth,+ )+where++import qualified Cachix.Types.BinaryCache as BinaryCache+import qualified Cachix.Types.ByteStringStreaming as ByteStringStreaming+import Cachix.Types.ContentTypes+import Cachix.Types.NarFileName (NarFileName (..))+import qualified Cachix.Types.NarInfo as NarInfo+import qualified Cachix.Types.NarInfoCreate as NarInfoCreate+import qualified Cachix.Types.NarInfoHash as NarInfoHash+import qualified Cachix.Types.NixCacheInfo as NixCacheInfo+import Cachix.Types.Servant (Head)+import Cachix.Types.Session (Session)+import qualified Cachix.Types.SigningKeyCreate as SigningKeyCreate+import Control.Monad.Trans.Resource+import Data.Conduit (ConduitT)+import Protolude+import Servant.API hiding (BasicAuth)+import Servant.API.Generic+import Servant.Auth++type CachixAuth = Auth '[Cookie, JWT, BasicAuth] Session++-- Nix CLI + Cachix CLI+data BinaryCacheAPI route+ = BinaryCacheAPI+ { -- https://cache.nixos.org/nix-cache-info+ nixCacheInfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nix-cache-info"+ :> Get '[XNixCacheInfo, JSON] NixCacheInfo.NixCacheInfo,+ -- Hydra: src/lib/Hydra/View/NARInfo.pm+ narinfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> Get '[XNixNarInfo, JSON] NarInfo.CachixNarInfo,+ narinfoHead ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> Head,+ -- Hydra: src/lib/Hydra/View/NixNAR.pm+ nar ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nar"+ :> Capture "nar" NarFileName+ :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ()),+ -- cachix specific+ getCache ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Get '[JSON] BinaryCache.BinaryCache,+ narinfoBulk ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "narinfo"+ :> Summary "Given a list of store hashes, return a list of those that are missing"+ :> ReqBody '[JSON] [Text]+ :> Post '[JSON] [Text],+ narURL ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "narurl"+ :> Capture "nar" NarFileName+ :> Get '[JSON] Text,+ createNarinfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate+ :> Post '[JSON] NoContent,+ createNar ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nar"+ :> StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ())+ :> Post '[JSON] NoContent,+ serveNarContent ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "serve"+ :> Capture "storehash" Text+ :> CaptureAll "filepath" Text+ :> Summary "Serve a file from a given store path"+ :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text] ByteStringStreaming.LazyByteStringStreaming),+ createKey ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "key"+ :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate+ :> Post '[JSON] NoContent+ }+ deriving (Generic)++type API = "api" :> "v1" :> ToServantApi BinaryCacheAPI++api :: Proxy API+api = Proxy
+ src/Cachix/API/Error.hs view
@@ -0,0 +1,25 @@+module Cachix.API.Error+ ( escalate,+ escalateAs,+ )+where++import Control.Monad.Catch (MonadThrow (throwM))+import Protolude++-- | Examples:+-- > escalate . maybeToEither err404+--+-- | Note that exceptions gets handled by warp and logged (user sees just "Internal server")+escalateAs ::+ (Exception exc, MonadThrow m) =>+ (l -> exc) ->+ Either l a ->+ m a+escalateAs f = either (throwM . f) pure++escalate ::+ (Exception exc, MonadThrow m) =>+ Either exc a ->+ m a+escalate = escalateAs identity
+ src/Cachix/API/Signing.hs view
@@ -0,0 +1,45 @@+module Cachix.API.Signing+ ( fingerprint,+ passthroughSizeSink,+ passthroughHashSinkB16,+ passthroughHashSink,+ )+where++import Crypto.Hash+import qualified Data.ByteArray as BA+import Data.ByteArray.Encoding (Base (..), convertToBase)+import qualified Data.ByteString as BS+import Data.Conduit+import qualified Data.Conduit.Combinators as CC+import Data.IORef+import qualified Data.Text as T+import Protolude++-- perl/lib/Nix/Manifest.pm:fingerprintPath+-- NB: references must be sorted+fingerprint :: Text -> Text -> Integer -> [Text] -> ByteString+fingerprint storePath narHash narSize references =+ toS $+ T.intercalate+ ";"+ ["1", storePath, narHash, show narSize, T.intercalate "," references]++-- Useful sinks for streaming nars+sizeSink :: MonadIO m => ConduitT ByteString o m Integer+sizeSink = CC.foldM (\p n -> return (p + fromIntegral (BS.length n))) 0++hashSink :: MonadIO m => ConduitT ByteString o m (Context SHA256)+hashSink = CC.foldM (\p n -> return (hashUpdate p n)) hashInit++passthroughSizeSink :: MonadIO m => IORef Integer -> ConduitT ByteString ByteString m ()+passthroughSizeSink ioref = passthroughSink sizeSink (liftIO . writeIORef ioref)++passthroughHashSinkBase :: MonadIO m => (Digest SHA256 -> ByteString) -> IORef ByteString -> ConduitT ByteString ByteString m ()+passthroughHashSinkBase f ioref = passthroughSink hashSink (liftIO . writeIORef ioref . f . hashFinalize)++passthroughHashSink :: MonadIO m => IORef ByteString -> ConduitT ByteString ByteString m ()+passthroughHashSink = passthroughHashSinkBase BA.convert++passthroughHashSinkB16 :: MonadIO m => IORef ByteString -> ConduitT ByteString ByteString m ()+passthroughHashSinkB16 = passthroughHashSinkBase (convertToBase Base16)
− src/Cachix/Api.hs
@@ -1,235 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE TypeOperators #-}--module Cachix.Api- ( servantApi,- swaggerDoc,- CachixAPI (..),- CachixServantAPI,- CachixAuth,- InstallAPI (..),- GitHubAPI (..),- BinaryCacheAPI (..),- BinaryCacheStreamingAPI (..),- BinaryCachStreamingServantAPI,- module Cachix.Api.Types,- module Cachix.Types.ContentTypes,- module Cachix.Types.NarFileName,- )-where--import Cachix.Api.Types-import qualified Cachix.Types.BinaryCacheAuthenticated as BinaryCacheAuthenticated-import qualified Cachix.Types.BinaryCacheCreate as BinaryCacheCreate-import Cachix.Types.ContentTypes-import qualified Cachix.Types.CreateToken as CreateToken-import qualified Cachix.Types.GitHubTeam as GitHubTeam-import Cachix.Types.NarFileName (NarFileName (..))-import qualified Cachix.Types.NarInfoCreate as NarInfoCreate-import Cachix.Types.Servant (Get302, Head, Post302)-import Cachix.Types.Session (Session)-import qualified Cachix.Types.SigningKeyCreate as SigningKeyCreate-import Cachix.Types.SwaggerOrphans ()-import Control.Lens-import Control.Monad.Trans.Resource-import Data.ByteString (ByteString)-import qualified Data.ByteString.Lazy as BSL-import Data.Conduit (ConduitT)-import Data.Swagger hiding (Header)-import Protolude-import Servant.API hiding (BasicAuth)-import Servant.API.Generic-import Servant.Auth-import Servant.Auth.Swagger ()-import Servant.Swagger-import Web.Cookie (SetCookie)--type CachixAuth = Auth '[Cookie, JWT, BasicAuth] Session--data BinaryCacheAPI route- = BinaryCacheAPI- { get ::- route- :- CachixAuth- :> Get '[JSON] BinaryCache,- create ::- route- :- CachixAuth- :> ReqBody '[JSON] BinaryCacheCreate.BinaryCacheCreate- :> Post '[JSON] NoContent,- delete ::- route- :- CachixAuth- :> Delete '[JSON] NoContent,- -- https://cache.nixos.org/nix-cache-info- nixCacheInfo ::- route- :- CachixAuth- :> "nix-cache-info"- :> Get '[XNixCacheInfo, JSON] NixCacheInfo,- -- Hydra: src/lib/Hydra/View/NARInfo.pm- narinfo ::- route- :- CachixAuth- :> Capture "narinfo" NarInfoC- :> Get '[XNixNarInfo, JSON] NarInfo,- narinfoHead ::- route- :- CachixAuth- :> Capture "narinfo" NarInfoC- :> Head,- narinfoBulk ::- route- :- CachixAuth- :> "narinfo"- :> Summary "Given a list of store hashes, return a list of those that are missing"- :> ReqBody '[JSON] [Text]- :> Post '[JSON] [Text],- createNarinfo ::- route- :- Capture "narinfo" NarInfoC- :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate- :> Post '[JSON] NoContent,- createKey ::- route- :- CachixAuth- :> "key"- :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate- :> Post '[JSON] NoContent- }- deriving (Generic)---- | Streaming endpoints-data BinaryCacheStreamingAPI route- = BinaryCacheStreamingAPI- { -- Hydra: src/lib/Hydra/View/NixNAR.pm- nar ::- route- :- CachixAuth- :> "nar"- :> Capture "nar" NarFileName- :> StreamGet NoFraming OctetStream (ConduitT () ByteString (ResourceT IO) ()),- createNar ::- route- :- "nar"- :> StreamBody NoFraming XNixNar (ConduitT () ByteString (ResourceT IO) ())- :> Post '[JSON] NoContent,- serveNarContent ::- route- :- CachixAuth- :> "serve"- :> Capture "storehash" Text- :> CaptureAll "filepath" Text- :> Summary "Serve a file from a given store path"- :> Get '[OctetStream] (Headers '[Header "X-Content-Type-Options" Text] BSL.ByteString)- }- deriving (Generic)--data InstallAPI route- = InstallAPI- { installGetLatest ::- route- :- Summary "Redirects to a tarball containing nix expression to build the latest version of cachix cli"- :> Get302 '[JSON] '[],- installGetVersion ::- route- :- Summary "Redirects to a tarball containing nix expression to build given version of cachix cli"- :> Capture "version" Text- :> Get302 '[JSON] '[]- }- deriving (Generic)--data GitHubAPI route- = GitHubAPI- { githubOrganizations ::- route- :- CachixAuth- :> "orgs"- :> Get '[JSON] [Text],- githubTeams ::- route- :- CachixAuth- :> "orgs"- :> Capture "org" Text- :> "teams"- :> Get '[JSON] [GitHubTeam.GitHubTeam]- }- deriving (Generic)--data CachixAPI route- = CachixAPI- { logout ::- route- :- "logout"- :> CachixAuth- :> Post302 '[JSON]- '[ Header "Set-Cookie" SetCookie,- Header "Set-Cookie" SetCookie- ],- login ::- route- :- "login"- :> Get302 '[JSON] '[],- loginCallback ::- route- :- "login"- :> "callback"- :> QueryParam "code" Text- :> QueryParam "state" Text- :> Get302 '[JSON]- '[ Header "Set-Cookie" SetCookie,- Header "Set-Cookie" SetCookie- ],- user ::- route- :- CachixAuth- :> "user"- :> Get '[JSON] User,- createToken ::- route- :- CachixAuth- :> "token"- :> ReqBody '[JSON] CreateToken.CreateToken- :> Post '[JSON] Text,- caches ::- route- :- CachixAuth- :> "cache"- :> Get '[JSON] [BinaryCacheAuthenticated.BinaryCacheAuthenticated],- cache ::- route- :- "cache"- :> Capture "name" Text- :> ToServantApi BinaryCacheAPI,- install ::- route- :- "install"- :> ToServantApi InstallAPI,- github ::- route- :- "github"- :> ToServantApi GitHubAPI- }- deriving (Generic)--type CachixServantAPI = "api" :> "v1" :> ToServantApi CachixAPI--type BinaryCachStreamingServantAPI =- "api" :> "v1" :> "cache" :> Capture "name" Text :> ToServantApi BinaryCacheStreamingAPI--servantApi :: Proxy CachixServantAPI-servantApi = Proxy--swaggerDoc :: Swagger-swaggerDoc =- toSwagger servantApi- & info- . title- .~ "cachix.org API"- & info- . version- .~ "1.0"- & info- . description- ?~ "TODO"
− src/Cachix/Api/Error.hs
@@ -1,26 +0,0 @@-module Cachix.Api.Error- ( escalate,- escalateAs,- )-where--import Control.Exception (Exception)-import Control.Monad.Catch (MonadThrow (throwM))-import Protolude---- | Examples:--- > escalate . maybeToEither err404------ | Note that exceptions gets handled by warp and logged (user sees just "Internal server")-escalateAs ::- (Exception exc, MonadThrow m) =>- (l -> exc) ->- Either l a ->- m a-escalateAs f = either (throwM . f) pure--escalate ::- (Exception exc, MonadThrow m) =>- Either exc a ->- m a-escalate = escalateAs identity
− src/Cachix/Api/Signing.hs
@@ -1,47 +0,0 @@-module Cachix.Api.Signing- ( fingerprint,- passthroughSizeSink,- passthroughHashSinkB16,- passthroughHashSink,- )-where--import Control.Monad.IO.Class (MonadIO, liftIO)-import Crypto.Hash-import qualified Data.ByteArray as BA-import Data.ByteArray.Encoding (Base (..), convertToBase)-import qualified Data.ByteString as BS-import Data.ByteString (ByteString)-import Data.Conduit-import qualified Data.Conduit.Combinators as CC-import Data.IORef-import qualified Data.Text as T-import Protolude---- perl/lib/Nix/Manifest.pm:fingerprintPath--- NB: references must be sorted-fingerprint :: Text -> Text -> Integer -> [Text] -> ByteString-fingerprint storePath narHash narSize references =- toS $- T.intercalate- ";"- ["1", storePath, narHash, show narSize, T.intercalate "," references]---- Useful sinks for streaming nars-sizeSink :: MonadIO m => ConduitT ByteString o m Integer-sizeSink = CC.foldM (\p n -> return (p + fromIntegral (BS.length n))) 0--hashSink :: MonadIO m => ConduitT ByteString o m (Context SHA256)-hashSink = CC.foldM (\p n -> return (hashUpdate p n)) hashInit--passthroughSizeSink :: MonadIO m => IORef Integer -> ConduitT ByteString ByteString m ()-passthroughSizeSink ioref = passthroughSink sizeSink (liftIO . writeIORef ioref)--passthroughHashSinkBase :: MonadIO m => (Digest SHA256 -> ByteString) -> IORef ByteString -> ConduitT ByteString ByteString m ()-passthroughHashSinkBase f ioref = passthroughSink hashSink (liftIO . writeIORef ioref . f . hashFinalize)--passthroughHashSink :: MonadIO m => IORef ByteString -> ConduitT ByteString ByteString m ()-passthroughHashSink = passthroughHashSinkBase BA.convert--passthroughHashSinkB16 :: MonadIO m => IORef ByteString -> ConduitT ByteString ByteString m ()-passthroughHashSinkB16 = passthroughHashSinkBase (convertToBase Base16)
− src/Cachix/Api/Types.hs
@@ -1,90 +0,0 @@-module Cachix.Api.Types where--import Control.DeepSeq (NFData)-import Data.Aeson (FromJSON, ToJSON)-import Data.Swagger (ToParamSchema, ToSchema)-import Data.Text (dropEnd, takeEnd)-import Protolude-import Servant.API--data NixCacheInfo- = NixCacheInfo- { storeDir :: Text,- wantMassQuery :: Integer,- priority :: Integer- }- deriving (Generic, Show, FromJSON, ToJSON, ToSchema)---- narinfo url includes storePath hash and .narinfo suffix-data NarInfo- = NarInfo- { -- | absolute path of the derivation in nix store- storePath :: Text,- -- | relative url (to current domain) to download nar file- url :: Text,- -- | name of the compression algorithm, eg. xz- compression :: Text,- -- | sha256 hash of the compressed nar file- -- NOTE: to compute use "nix-hash --type sha256 --flat"- fileHash :: Text,- -- | file size of compressed nar file- -- NOTE: du -b- fileSize :: Integer,- -- | sha256 hash of the decompressed nar file- -- NOTE: to compute use "nix-hash --type sha256 --flat --base32"- narHash :: Text,- -- | file size of decompressed nar file- -- NOTE: du -b- narSize :: Integer,- -- | immediate dependencies of the storePath- -- NOTE: nix-store -q --references- references :: [Text],- -- | relative store path (to nix store root) of the deriver- -- NOTE: nix-store -q --deriver- deriver :: Text,- -- | signature of fields: storePath, narHash, narSize, refs- sig :: Text- }- deriving (Generic, Show, FromJSON, ToJSON, ToSchema)--data BinaryCache- = BinaryCache- { name :: Text,- uri :: Text,- isPublic :: Bool,- publicSigningKeys :: [Text],- githubUsername :: Text- }- deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)--newtype BinaryCacheError- = BinaryCacheError- { error :: Text- }- deriving (Generic, FromJSON, ToJSON)---- | Store path hash-newtype NarInfoC = NarInfoC Text deriving (Generic, ToSchema, ToParamSchema)--instance FromHttpApiData NarInfoC where- parseUrlPiece s =- if takeEnd 8 s == ".narinfo"- then Right $ NarInfoC (dropEnd 8 s)- else Left ""--instance ToHttpApiData NarInfoC where- toUrlPiece (NarInfoC n) = n <> ".narinfo"--data User- = User- { fullname :: Maybe Text,- username :: Text,- email :: Maybe Text,- hasOrgsAcccess :: Bool,- activeSubscription :: SubscriptionType,- subscriptionAccountId :: Maybe Text- }- deriving (Generic, FromJSON, ToJSON, ToSchema)--data SubscriptionType = Community | Starter | Basic | Pro- deriving (Generic, FromJSON, ToJSON, ToSchema, Show, Read)
+ src/Cachix/Types/BinaryCache.hs view
@@ -0,0 +1,17 @@+module Cachix.Types.BinaryCache where++import Cachix.Types.Permission (Permission)+import Data.Aeson (FromJSON, ToJSON)+import Data.Swagger (ToSchema)+import Protolude++data BinaryCache+ = BinaryCache+ { name :: Text,+ uri :: Text,+ isPublic :: Bool,+ publicSigningKeys :: [Text],+ githubUsername :: Text,+ permission :: Permission+ }+ deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
− src/Cachix/Types/BinaryCacheAuthenticated.hs
@@ -1,22 +0,0 @@-module Cachix.Types.BinaryCacheAuthenticated- ( BinaryCacheAuthenticated (..),- )-where--import Data.Aeson- ( FromJSON,- ToJSON,- )-import Data.Swagger-import Protolude---- | Binary Cache response content when user is authenticated-data BinaryCacheAuthenticated- = BinaryCacheAuthenticated- { name :: Text,- uri :: Text,- publicSigningKeys :: [Text],- isPublic :: Bool,- totalFileSize :: Integer- }- deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
− src/Cachix/Types/BinaryCacheCreate.hs
@@ -1,20 +0,0 @@-module Cachix.Types.BinaryCacheCreate- ( BinaryCacheCreate (..),- )-where--import Data.Aeson- ( FromJSON,- ToJSON,- )-import Data.Swagger-import Protolude--data BinaryCacheCreate- = BinaryCacheCreate- { publicSigningKey :: Maybe Text,- isPublic :: Bool,- githubOrganization :: Maybe Text,- githubTeamId :: Maybe Int- }- deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
+ src/Cachix/Types/ByteStringStreaming.hs view
@@ -0,0 +1,15 @@+module Cachix.Types.ByteStringStreaming where++import qualified Data.ByteString.Lazy as LBS+import Data.Swagger (NamedSchema (..), ToSchema (..), binarySchema)+import Protolude++newtype ByteStringStreaming = ByteStringStreaming ByteString++instance ToSchema ByteStringStreaming where+ declareNamedSchema _ = pure $ NamedSchema (Just "ByteString") binarySchema++newtype LazyByteStringStreaming = LazyByteStringStreaming LBS.ByteString++instance ToSchema LazyByteStringStreaming where+ declareNamedSchema _ = pure $ NamedSchema (Just "lazyByteString") binarySchema
src/Cachix/Types/ContentTypes.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} module Cachix.Types.ContentTypes@@ -7,9 +8,11 @@ ) where -import Cachix.Api.Types+import qualified Cachix.Types.ByteStringStreaming as ByteStringStreaming+import qualified Cachix.Types.NarInfo as NarInfo+import qualified Cachix.Types.NixCacheInfo as NixCacheInfo import qualified Data.ByteString.Lazy as BSL-import Data.Typeable (Typeable)+import Data.Coerce (coerce) import qualified Network.HTTP.Media as M import Protolude import Servant.API@@ -27,16 +30,22 @@ contentType _ = "text" M.// "x-nix-narinfo" instance Accept XNixNar where- contentType _ = "application" M.// "x-nix-nar"+ contentType _ = "application" M.// "octet-stream" -instance MimeUnrender XNixCacheInfo NixCacheInfo where+instance MimeUnrender XNixCacheInfo NixCacheInfo.NixCacheInfo where mimeUnrender _ _ = Left "TODO" -instance MimeUnrender XNixNarInfo NarInfo where+instance MimeUnrender XNixNarInfo NarInfo.CachixNarInfo where mimeUnrender _ _ = Left "TODO" -instance MimeRender XNixNar ByteString where- mimeRender _ = BSL.fromStrict+instance MimeRender XNixNar ByteStringStreaming.ByteStringStreaming where+ mimeRender _ = BSL.fromStrict . coerce -instance MimeUnrender XNixNar ByteString where- mimeUnrender _ = Right . BSL.toStrict+instance MimeUnrender XNixNar ByteStringStreaming.ByteStringStreaming where+ mimeUnrender _ = Right . coerce . BSL.toStrict++instance MimeUnrender XNixNar ByteStringStreaming.LazyByteStringStreaming where+ mimeUnrender _ = Right . coerce++instance MimeRender XNixNar ByteStringStreaming.LazyByteStringStreaming where+ mimeRender _ = coerce
− src/Cachix/Types/CreateToken.hs
@@ -1,17 +0,0 @@-module Cachix.Types.CreateToken- ( CreateToken (..),- )-where--import Data.Aeson- ( FromJSON,- ToJSON,- )-import Data.Swagger-import Protolude--data CreateToken- = CreateToken- { description :: Text- }- deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
− src/Cachix/Types/GitHubTeam.hs
@@ -1,18 +0,0 @@-module Cachix.Types.GitHubTeam- ( GitHubTeam (..),- )-where--import Data.Aeson- ( FromJSON,- ToJSON,- )-import Data.Swagger-import Protolude--data GitHubTeam- = GitHubTeam- { id :: Int,- name :: Text- }- deriving (Generic, FromJSON, ToJSON, ToSchema)
src/Cachix/Types/NarFileName.hs view
@@ -3,11 +3,12 @@ ) where -import Data.Text (dropEnd, takeEnd)+import Data.Swagger (ToParamSchema (..))+import qualified Data.Text as T import Protolude import Servant.API --- | <hash>.nar.xz file+-- | <hash>.nar.<extension> file data NarFileName = NarFileName { contentHash :: Text,@@ -17,9 +18,13 @@ instance FromHttpApiData NarFileName where parseUrlPiece s =- if takeEnd 7 s == ".nar.xz"- then Right $ NarFileName (dropEnd 7 s) "xz"- else Left "Wrong extension"+ case T.splitOn "." s of+ [filename, "nar", ext] ->+ Right $ NarFileName filename ext+ _ -> Left $ "Wrong nar filename: " <> s instance ToHttpApiData NarFileName where toUrlPiece narfilename = contentHash narfilename <> ".nar." <> extension narfilename++instance ToParamSchema NarFileName where+ toParamSchema _ = toParamSchema (Proxy :: Proxy Text)
+ src/Cachix/Types/NarInfo.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Cachix.Types.NarInfo+ ( CachixNarInfo,+ NarInfo (..),+ )+where++import Data.Aeson (FromJSON, ToJSON)+import Data.Swagger (ToSchema)+import Data.Text (Text)+import Nix.NarInfo (NarInfo (..))++deriving instance ToSchema CachixNarInfo++deriving instance ToJSON CachixNarInfo++deriving instance FromJSON CachixNarInfo++type CachixNarInfo = NarInfo Text Text Text
src/Cachix/Types/NarInfoCreate.hs view
@@ -27,7 +27,7 @@ cFileSize :: Integer, cReferences :: [Text], cDeriver :: Text,- cSig :: Text+ cSig :: Maybe Text } deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
+ src/Cachix/Types/NarInfoHash.hs view
@@ -0,0 +1,22 @@+module Cachix.Types.NarInfoHash+ ( NarInfoHash (..),+ )+where++import Data.Swagger (ToParamSchema, ToSchema)+import Data.Text (dropEnd, takeEnd)+import Protolude+import Servant.API++-- | Store path hash+newtype NarInfoHash = NarInfoHash {unnarinfohash :: Text}+ deriving (Generic, ToSchema, ToParamSchema)++instance FromHttpApiData NarInfoHash where+ parseUrlPiece s =+ if takeEnd 8 s == ".narinfo"+ then Right $ NarInfoHash (dropEnd 8 s)+ else Left ""++instance ToHttpApiData NarInfoHash where+ toUrlPiece (NarInfoHash n) = n <> ".narinfo"
+ src/Cachix/Types/NixCacheInfo.hs view
@@ -0,0 +1,13 @@+module Cachix.Types.NixCacheInfo where++import Data.Aeson (FromJSON, ToJSON)+import Data.Swagger (ToSchema)+import Protolude++data NixCacheInfo+ = NixCacheInfo+ { storeDir :: Text,+ wantMassQuery :: Integer,+ priority :: Integer+ }+ deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
+ src/Cachix/Types/Permission.hs view
@@ -0,0 +1,8 @@+module Cachix.Types.Permission where++import Data.Aeson (FromJSON, ToJSON)+import Data.Swagger (ToSchema)+import Protolude++data Permission = Read | Write | Admin+ deriving (Generic, Show, FromJSON, ToJSON, ToSchema, NFData, Eq, Ord)
src/Cachix/Types/Servant.hs view
@@ -14,9 +14,9 @@ import Servant.API -- Location header as per https://github.com/haskell-servant/servant/issues/117#issuecomment-381398666-type Get302 (cts :: [*]) (hs :: [*]) = Verb 'GET 302 cts (Headers (Header "Location" Text ': hs) NoContent)+type Get302 (cts :: [Type]) (hs :: [Type]) = Verb 'GET 302 cts (Headers (Header "Location" Text ': hs) NoContent) -type Post302 (cts :: [*]) (hs :: [*]) = Verb 'POST 302 cts (Headers (Header "Location" Text ': hs) NoContent)+type Post302 (cts :: [Type]) (hs :: [Type]) = Verb 'POST 302 cts (Headers (Header "Location" Text ': hs) NoContent) -- TODO: allow empty CT with HEAD type Head = Verb 'HEAD 200 '[JSON] NoContent
− src/Cachix/Types/SwaggerOrphans.hs
@@ -1,23 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-module Cachix.Types.SwaggerOrphans- where--import Protolude-import Data.Conduit (ConduitT)-import Data.Swagger (ToSchema(..))---- TODO: upstream to servant-conduit-instance ToSchema i => ToSchema (ConduitT i o m r) where- declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy i)- -- TODO: Proxy o---- https://github.com/haskell-servant/servant/pull/1090-#if !MIN_VERSION_servant_client(0,16,0)-instance NFData NoContent-#endif
test/Main.hs view
@@ -2,7 +2,6 @@ import Protolude import qualified Spec-import Test.Hspec.Formatters import Test.Hspec.Runner main :: IO ()