[commit: packages/Cabal] ghc-head: Improve update performance, see issue #799 (547e7a3)

git at git.haskell.org git at git.haskell.org
Mon Aug 26 23:25:42 CEST 2013


Repository : ssh://git@git.haskell.org/Cabal

On branch  : ghc-head
Link       : http://git.haskell.org/?p=packages/Cabal.git;a=commit;h=547e7a375cad1b3b15ad4a04c52ef89eed9ca006

>---------------------------------------------------------------

commit 547e7a375cad1b3b15ad4a04c52ef89eed9ca006
Author: Thomas Dziedzic <gostrc at gmail.com>
Date:   Mon May 20 04:59:55 2013 +0000

    Improve update performance, see issue #799


>---------------------------------------------------------------

547e7a375cad1b3b15ad4a04c52ef89eed9ca006
 cabal-install/Distribution/Client/HttpUtils.hs |   52 ++++++++++++++++--------
 1 file changed, 34 insertions(+), 18 deletions(-)

diff --git a/cabal-install/Distribution/Client/HttpUtils.hs b/cabal-install/Distribution/Client/HttpUtils.hs
index 0fe0829..154baf4 100644
--- a/cabal-install/Distribution/Client/HttpUtils.hs
+++ b/cabal-install/Distribution/Client/HttpUtils.hs
@@ -11,7 +11,7 @@ module Distribution.Client.HttpUtils (
 
 import Network.HTTP
          ( Request (..), Response (..), RequestMethod (..)
-         , Header(..), HeaderName(..) )
+         , Header(..), HeaderName(..), lookupHeader )
 import Network.HTTP.Proxy ( Proxy(..), fetchProxy)
 import Network.URI
          ( URI (..), URIAuth (..) )
@@ -35,6 +35,10 @@ import Distribution.Text
 import Data.Char ( isSpace )
 import qualified System.FilePath.Posix as FilePath.Posix
          ( splitDirectories )
+import System.FilePath
+         ( (<.>) )
+import System.Directory
+         ( doesFileExist )
 
 -- Trime
 trim :: String -> String
@@ -53,17 +57,18 @@ proxy _verbosity = do
       if uri' == "" then NoProxy else Proxy uri' auth
     _ -> p
 
-mkRequest :: URI -> Request ByteString
-mkRequest uri = Request{ rqURI     = uri
-                       , rqMethod  = GET
-                       , rqHeaders = [Header HdrUserAgent userAgent]
-                       , rqBody    = ByteString.empty }
+mkRequest :: URI -> Maybe String -> Request ByteString
+mkRequest uri etag = Request{ rqURI     = uri
+                            , rqMethod  = GET
+                            , rqHeaders = Header HdrUserAgent userAgent : ifNoneMatchHdr
+                            , rqBody    = ByteString.empty }
   where userAgent = "cabal-install/" ++ display Paths_cabal_install.version
+        ifNoneMatchHdr = maybe [] (\t -> [Header HdrIfNoneMatch t]) etag
 
 -- |Carry out a GET request, using the local proxy settings
-getHTTP :: Verbosity -> URI -> IO (Result (Response ByteString))
-getHTTP verbosity uri = liftM (\(_, resp) -> Right resp) $
-                              cabalBrowse verbosity (return ()) (request (mkRequest uri))
+getHTTP :: Verbosity -> URI -> Maybe String -> IO (Result (Response ByteString))
+getHTTP verbosity uri etag = liftM (\(_, resp) -> Right resp) $
+                                   cabalBrowse verbosity (return ()) (request (mkRequest uri etag))
 
 cabalBrowse :: Verbosity
             -> BrowserAction s ()
@@ -86,25 +91,36 @@ downloadURI :: Verbosity
 downloadURI verbosity uri path | uriScheme uri == "file:" =
   copyFileVerbose verbosity (uriPath uri) path
 downloadURI verbosity uri path = do
-  result <- getHTTP verbosity uri
+  let etagPath = path <.> "etag"
+  etagPathExists <- doesFileExist etagPath
+  etag <- if etagPathExists
+            then liftM Just $ readFile etagPath
+            else return Nothing
+
+  result <- getHTTP verbosity uri etag
   let result' = case result of
         Left  err -> Left err
         Right rsp -> case rspCode rsp of
-          (2,0,0) -> Right (rspBody rsp)
-          (a,b,c) -> Left err
+          (2,0,0) -> Right rsp
+          (3,0,4) -> Left . ErrorMisc $ "Repo ETag matches. Nothing to do."
+          (a,b,c) -> Left . ErrorMisc $ "Failed to download " ++ show uri ++ " : " ++ err
             where
-              err = ErrorMisc $ "Unsucessful HTTP code: "
-                             ++ concatMap show [a,b,c]
+              err = "Unsucessful HTTP code: " ++ concatMap show [a,b,c]
+
+  case result' of
+    Left _ -> return ()
+    Right rsp -> case lookupHeader HdrETag (rspHeaders rsp) of
+      Nothing -> return ()
+      Just newEtag -> writeFile etagPath newEtag
 
   case result' of
-    Left err   -> die $ "Failed to download " ++ show uri ++ " : " ++ show err
-    Right body -> do
+    Left err   -> die $ show err
+    Right rsp -> do
       info verbosity ("Downloaded to " ++ path)
-      writeFileAtomic path body
+      writeFileAtomic path $ rspBody rsp
       --FIXME: check the content-length header matches the body length.
       --TODO: stream the download into the file rather than buffering the whole
       --      thing in memory.
-      --      remember the ETag so we can not re-download if nothing changed.
 
 -- Utility function for legacy support.
 isOldHackageURI :: URI -> Bool





More information about the ghc-commits mailing list