1{-# LANGUAGE OverloadedStrings #-}
26import Prelude hiding (zip)
27import qualified Codec.Archive.Zip as Zip
28import Control.Exception (SomeException, handle)
29import qualified Data.Binary as Binary
30import qualified Data.Binary.Get as Binary
31import qualified Data.ByteString.Char8 as BS
32import qualified Data.Digest.Pure.SHA as SHA
33import qualified Data.String as String
34import Network.HTTP (urlEncodeVars)
35import Network.HTTP.Client
36import Network.HTTP.Client.TLS (tlsManagerSettings)
37import Network.HTTP.Types.Header (Header, hAccept, hAcceptEncoding, hUserAgent)
38import Network.HTTP.Types.Method (methodPost)
39import qualified Network.HTTP.Client.MultipartFormData as Multi
40import qualified System.Directory as Dir
42import qualified Elm.Version as V
49getManager :: IO Manager
51 newManager tlsManagerSettings
58toUrl :: String -> [(String,String)] -> String
62 _:_ -> url ++ "?" ++ urlEncodeVars params
74 -> (BS.ByteString -> IO (Either e a))
76post manager url headers onError onSuccess =
77 handle (handleSomeException url onError) $
78 handle (handleHttpException url onError) $
79 do req0 <- parseUrlThrow url
83 , requestHeaders = addDefaultHeaders headers
85 withResponse req1 manager $ \response ->
86 do chunks <- brConsume (responseBody response)
87 onSuccess (BS.concat chunks)
97 -> (BodyReader -> IO (Either e a))
99post' manager url headers timeout body onError onSuccess =
100 handle (handleSomeException url onError) $
101 handle (handleHttpException url onError) $
102 do req0 <- parseUrlThrow url
107 { method = methodPost
108 , requestHeaders = addDefaultHeaders headers
110 withResponse req1 manager (onSuccess . responseBody)
117addDefaultHeaders :: [Header] -> [Header]
118addDefaultHeaders headers =
119 (hUserAgent, userAgent) : (hAcceptEncoding, "gzip") : headers
122{-# NOINLINE userAgent #-}
123userAgent :: BS.ByteString
125 BS.pack ("elm/" ++ V.toChars V.compiler)
128accept :: BS.ByteString -> Header
142addTimeout :: Timeout -> Request -> Request
143addTimeout timeout req =
149 req { responseTimeout = responseTimeoutNone }
158 | FormDataBody [Multi.Part]
161addBody :: Body -> Request -> IO Request
167 FormDataBody parts ->
168 Multi.formDataBody parts req
171filePart :: String -> FilePath -> Multi.Part
172filePart name filePath =
173 Multi.partFileSource (String.fromString name) filePath
176stringPart :: String -> String -> Multi.Part
177stringPart name string =
178 Multi.partBS (String.fromString name) (BS.pack string)
186 = BadUrl String String
187 | BadHttp String HttpExceptionContent
188 | BadMystery String SomeException
191handleHttpException :: String -> (Error -> e) -> HttpException -> IO (Either e a)
192handleHttpException url onError httpException =
193 case httpException of
194 InvalidUrlException _ reason ->
195 return (Left (onError (BadUrl url reason)))
197 HttpExceptionRequest _ content ->
198 return (Left (onError (BadHttp url content)))
201handleSomeException :: String -> (Error -> e) -> SomeException -> IO (Either e a)
202handleSomeException url onError exception =
203 return (Left (onError (BadMystery url exception)))
210readByteString :: BodyReader -> IO BS.ByteString
211readByteString bodyReader =
212 BS.concat <$> brConsume bodyReader
215type Sha = SHA.Digest SHA.SHA1State
218shaToChars :: Sha -> String
223readArchive :: BodyReader -> IO (Maybe (Sha, Zip.Archive))
225 readArchiveHelp body $
226 AS 0 SHA.sha1Incremental (Binary.runGetIncremental Binary.get)
232 , _sha :: !(Binary.Decoder SHA.SHA1State)
233 , _zip :: !(Binary.Decoder Zip.Archive)
237readArchiveHelp :: BodyReader -> ArchiveState -> IO (Maybe (Sha, Zip.Archive))
238readArchiveHelp body (AS len sha zip) =
244 do chunk <- brRead body
245 readArchiveHelp body $
247 { _len = len + BS.length chunk
248 , _sha = Binary.pushChunk sha chunk
249 , _zip = k (if BS.null chunk then Nothing else Just chunk)
252 Binary.Done _ _ archive ->
253 return $ Just ( SHA.completeSha1Incremental sha len, archive )
260writeArchive :: Zip.Archive -> FilePath -> FilePath -> IO ()
261writeArchive archive destination newRoot =
262 do Dir.createDirectoryIfMissing True destination
263 let opts = [Zip.OptDestination destination]
264 mapM_ (Zip.writeEntry opts . replaceRoot newRoot) (Zip.zEntries archive)
267replaceRoot :: String -> Zip.Entry -> Zip.Entry
268replaceRoot root entry =
271 dropWhile (/='/') (Zip.eRelativePath entry)
273 entry { Zip.eRelativePath = root ++ rootless }
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list