refactor catfile code
split into generic IO code, and a thin Annex wrapper
This commit is contained in:
		
					parent
					
						
							
								4f4eaf387a
							
						
					
				
			
			
				commit
				
					
						ad245a6375
					
				
			
		
					 5 changed files with 96 additions and 48 deletions
				
			
		
							
								
								
									
										3
									
								
								Annex.hs
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Annex.hs
									
										
									
									
									
								
							|  | @ -24,6 +24,7 @@ import Control.Monad.IO.Control | ||||||
| import Control.Applicative hiding (empty) | import Control.Applicative hiding (empty) | ||||||
| 
 | 
 | ||||||
| import qualified Git | import qualified Git | ||||||
|  | import Git.CatFile | ||||||
| import Git.Queue | import Git.Queue | ||||||
| import Types.Backend | import Types.Backend | ||||||
| import qualified Types.Remote | import qualified Types.Remote | ||||||
|  | @ -55,6 +56,7 @@ data AnnexState = AnnexState | ||||||
| 	, fast :: Bool | 	, fast :: Bool | ||||||
| 	, auto :: Bool | 	, auto :: Bool | ||||||
| 	, branchstate :: BranchState | 	, branchstate :: BranchState | ||||||
|  | 	, catfilehandle :: Maybe CatFileHandle | ||||||
| 	, forcebackend :: Maybe String | 	, forcebackend :: Maybe String | ||||||
| 	, forcenumcopies :: Maybe Int | 	, forcenumcopies :: Maybe Int | ||||||
| 	, defaultkey :: Maybe String | 	, defaultkey :: Maybe String | ||||||
|  | @ -79,6 +81,7 @@ newState gitrepo = AnnexState | ||||||
| 	, fast = False | 	, fast = False | ||||||
| 	, auto = False | 	, auto = False | ||||||
| 	, branchstate = startBranchState | 	, branchstate = startBranchState | ||||||
|  | 	, catfilehandle = Nothing | ||||||
| 	, forcebackend = Nothing | 	, forcebackend = Nothing | ||||||
| 	, forcenumcopies = Nothing | 	, forcenumcopies = Nothing | ||||||
| 	, defaultkey = Nothing | 	, defaultkey = Nothing | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								Branch.hs
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								Branch.hs
									
										
									
									
									
								
							|  | @ -18,7 +18,7 @@ module Branch ( | ||||||
| 	name	 | 	name	 | ||||||
| ) where | ) where | ||||||
| 
 | 
 | ||||||
| import Control.Monad (when, unless, liftM) | import Control.Monad (unless, liftM) | ||||||
| import Control.Monad.State (liftIO) | import Control.Monad.State (liftIO) | ||||||
| import Control.Applicative ((<$>)) | import Control.Applicative ((<$>)) | ||||||
| import System.FilePath | import System.FilePath | ||||||
|  | @ -31,7 +31,6 @@ import System.IO | ||||||
| import System.IO.Binary | import System.IO.Binary | ||||||
| import System.Posix.Process | import System.Posix.Process | ||||||
| import System.Exit | import System.Exit | ||||||
| import qualified Data.ByteString.Char8 as B |  | ||||||
| 
 | 
 | ||||||
| import Types.BranchState | import Types.BranchState | ||||||
| import qualified Git | import qualified Git | ||||||
|  | @ -43,6 +42,7 @@ import Utility.SafeCommand | ||||||
| import Types | import Types | ||||||
| import Messages | import Messages | ||||||
| import Locations | import Locations | ||||||
|  | import CatFile | ||||||
| 
 | 
 | ||||||
| type GitRef = String | type GitRef = String | ||||||
| 
 | 
 | ||||||
|  | @ -244,49 +244,10 @@ get file = do | ||||||
| 					setCache file content | 					setCache file content | ||||||
| 					return content | 					return content | ||||||
| 				Nothing -> withIndexUpdate $ do | 				Nothing -> withIndexUpdate $ do | ||||||
| 					content <- catFile file | 					content <- catFile fullname file | ||||||
| 					setCache file content | 					setCache file content | ||||||
| 					return content | 					return content | ||||||
| 
 | 
 | ||||||
| {- Uses git cat-file in batch mode to read the content of a file. |  | ||||||
|  - |  | ||||||
|  - Only one process is run, and it persists and is used for all accesses. -} |  | ||||||
| catFile :: FilePath -> Annex String |  | ||||||
| catFile file = do |  | ||||||
| 	state <- getState |  | ||||||
| 	maybe (startup state) ask (catFileHandles state) |  | ||||||
| 	where |  | ||||||
| 		startup state = do |  | ||||||
| 			g <- Annex.gitRepo |  | ||||||
| 			(_, from, to) <- liftIO $ hPipeBoth "git" $ |  | ||||||
| 				toCommand $ Git.gitCommandLine g |  | ||||||
| 					[Param "cat-file", Param "--batch"] |  | ||||||
| 			setState state { catFileHandles = Just (from, to) } |  | ||||||
| 			ask (from, to) |  | ||||||
| 		ask (from, to) = liftIO $ do |  | ||||||
| 			let want = fullname ++ ":" ++ file |  | ||||||
| 			hPutStrLn to want |  | ||||||
| 			hFlush to |  | ||||||
| 			header <- hGetLine from |  | ||||||
| 			case words header of |  | ||||||
| 				[sha, blob, size] |  | ||||||
| 					| length sha == Git.shaSize && |  | ||||||
| 					  blob == "blob" -> handle from size |  | ||||||
| 					| otherwise -> empty |  | ||||||
| 				_ |  | ||||||
| 					| header == want ++ " missing" -> empty |  | ||||||
| 					| otherwise -> error $ "unknown response from git cat-file " ++ header |  | ||||||
| 		handle from size = case reads size of |  | ||||||
| 			[(bytes, "")] -> readcontent from bytes |  | ||||||
| 			_ -> empty |  | ||||||
| 		readcontent from bytes = do |  | ||||||
| 			content <- B.hGet from bytes |  | ||||||
| 			c <- hGetChar from |  | ||||||
| 			when (c /= '\n') $ |  | ||||||
| 				error "missing newline from git cat-file" |  | ||||||
| 			return $ B.unpack content |  | ||||||
| 		empty = return "" |  | ||||||
| 
 |  | ||||||
| {- Lists all files on the branch. There may be duplicates in the list. -} | {- Lists all files on the branch. There may be duplicates in the list. -} | ||||||
| files :: Annex [FilePath] | files :: Annex [FilePath] | ||||||
| files = withIndexUpdate $ do | files = withIndexUpdate $ do | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								CatFile.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								CatFile.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | {- git cat-file interface, with handle automatically stored in the Annex monad | ||||||
|  |  - | ||||||
|  |  - Copyright 2011 Joey Hess <joey@kitenet.net> | ||||||
|  |  - | ||||||
|  |  - Licensed under the GNU GPL version 3 or higher. | ||||||
|  |  -} | ||||||
|  | 
 | ||||||
|  | module CatFile ( | ||||||
|  | 	catFile | ||||||
|  | ) where | ||||||
|  | 
 | ||||||
|  | import Control.Monad.State | ||||||
|  | 
 | ||||||
|  | import qualified Git.CatFile | ||||||
|  | import Types | ||||||
|  | import qualified Annex | ||||||
|  | 
 | ||||||
|  | catFile :: String -> FilePath -> Annex String | ||||||
|  | catFile branch file = maybe startup go =<< Annex.getState Annex.catfilehandle | ||||||
|  | 	where | ||||||
|  | 		startup = do | ||||||
|  | 			g <- Annex.gitRepo | ||||||
|  | 			h <- liftIO $ Git.CatFile.catFileStart g | ||||||
|  | 			Annex.changeState $ \s -> s { Annex.catfilehandle = Just h } | ||||||
|  | 			go h | ||||||
|  | 		go h = liftIO $ Git.CatFile.catFile h branch file | ||||||
							
								
								
									
										63
									
								
								Git/CatFile.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Git/CatFile.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | {- git cat-file interface | ||||||
|  |  - | ||||||
|  |  - Copyright 2011 Joey Hess <joey@kitenet.net> | ||||||
|  |  - | ||||||
|  |  - Licensed under the GNU GPL version 3 or higher. | ||||||
|  |  -} | ||||||
|  | 
 | ||||||
|  | module Git.CatFile ( | ||||||
|  | 	CatFileHandle, | ||||||
|  | 	catFileStart, | ||||||
|  | 	catFileStop, | ||||||
|  | 	catFile | ||||||
|  | ) where | ||||||
|  | 
 | ||||||
|  | import Control.Monad.State | ||||||
|  | import System.Cmd.Utils | ||||||
|  | import System.IO | ||||||
|  | import qualified Data.ByteString.Char8 as B | ||||||
|  | 
 | ||||||
|  | import Git | ||||||
|  | import Utility.SafeCommand | ||||||
|  | 
 | ||||||
|  | type CatFileHandle = (PipeHandle, Handle, Handle) | ||||||
|  | 
 | ||||||
|  | {- Starts git cat-file running in batch mode in a repo and returns a handle. -} | ||||||
|  | catFileStart :: Repo -> IO CatFileHandle | ||||||
|  | catFileStart repo = hPipeBoth "git" $ toCommand $ | ||||||
|  | 	Git.gitCommandLine repo [Param "cat-file", Param "--batch"] | ||||||
|  | 
 | ||||||
|  | {- Stops git cat-file. -} | ||||||
|  | catFileStop :: CatFileHandle -> IO () | ||||||
|  | catFileStop (pid, from, to) = do | ||||||
|  | 	hClose to | ||||||
|  | 	hClose from | ||||||
|  | 	forceSuccess pid | ||||||
|  | 
 | ||||||
|  | {- Uses a running git cat-file read the content of a file from a branch. | ||||||
|  |  - Files that do not exist on the branch will have "" returned. -} | ||||||
|  | catFile :: CatFileHandle -> String -> FilePath -> IO String | ||||||
|  | catFile (_, from, to) branch file = do | ||||||
|  | 	hPutStrLn to want | ||||||
|  | 	hFlush to | ||||||
|  | 	header <- hGetLine from | ||||||
|  | 	case words header of | ||||||
|  | 		[sha, blob, size] | ||||||
|  | 			| length sha == Git.shaSize && | ||||||
|  | 			  blob == "blob" -> handle size | ||||||
|  | 			| otherwise -> empty | ||||||
|  | 		_ | ||||||
|  | 			| header == want ++ " missing" -> empty | ||||||
|  | 			| otherwise -> error $ "unknown response from git cat-file " ++ header | ||||||
|  | 	where | ||||||
|  | 		want = branch ++ ":" ++ file | ||||||
|  | 		handle size = case reads size of | ||||||
|  | 			[(bytes, "")] -> readcontent bytes | ||||||
|  | 			_ -> empty | ||||||
|  | 		readcontent bytes = do | ||||||
|  | 			content <- B.hGet from bytes | ||||||
|  | 			c <- hGetChar from | ||||||
|  | 			when (c /= '\n') $ | ||||||
|  | 				error "missing newline from git cat-file" | ||||||
|  | 			return $ B.unpack content | ||||||
|  | 		empty = return "" | ||||||
|  | @ -7,18 +7,13 @@ | ||||||
| 
 | 
 | ||||||
| module Types.BranchState where | module Types.BranchState where | ||||||
| 
 | 
 | ||||||
| import System.IO |  | ||||||
| 
 |  | ||||||
| data BranchState = BranchState { | data BranchState = BranchState { | ||||||
| 	branchUpdated :: Bool, -- has the branch been updated this run? | 	branchUpdated :: Bool, -- has the branch been updated this run? | ||||||
| 
 | 
 | ||||||
| 	-- (from, to) handles used to talk to a git-cat-file process |  | ||||||
| 	catFileHandles :: Maybe (Handle, Handle), |  | ||||||
| 
 |  | ||||||
| 	-- the content of one file is cached | 	-- the content of one file is cached | ||||||
| 	cachedFile :: Maybe FilePath, | 	cachedFile :: Maybe FilePath, | ||||||
| 	cachedContent :: String | 	cachedContent :: String | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| startBranchState :: BranchState | startBranchState :: BranchState | ||||||
| startBranchState = BranchState False Nothing Nothing "" | startBranchState = BranchState False Nothing "" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Joey Hess
				Joey Hess