packages feed

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 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 ()