indentation foo, and a new coding style page. no code changes

This commit is contained in:
Joey Hess 2012-10-28 21:27:15 -04:00
parent dd63cbb7bc
commit 6eca362c5d
11 changed files with 395 additions and 301 deletions

View file

@ -73,8 +73,8 @@ instance MonadBaseControl IO Annex where
liftBaseWith f = Annex $ liftBaseWith $ \runInIO -> liftBaseWith f = Annex $ liftBaseWith $ \runInIO ->
f $ liftM StAnnex . runInIO . runAnnex f $ liftM StAnnex . runInIO . runAnnex
restoreM = Annex . restoreM . unStAnnex restoreM = Annex . restoreM . unStAnnex
where where
unStAnnex (StAnnex st) = st unStAnnex (StAnnex st) = st
type Matcher a = Either [Utility.Matcher.Token a] (Utility.Matcher.Matcher a) type Matcher a = Either [Utility.Matcher.Token a] (Utility.Matcher.Matcher a)

View file

@ -95,24 +95,24 @@ repoSyncable r = fromMaybe True . Git.Config.isTrue
- in git config. forcenumcopies overrides everything. -} - in git config. forcenumcopies overrides everything. -}
getNumCopies :: Maybe Int -> Annex Int getNumCopies :: Maybe Int -> Annex Int
getNumCopies v = perhaps (use v) =<< Annex.getState Annex.forcenumcopies getNumCopies v = perhaps (use v) =<< Annex.getState Annex.forcenumcopies
where where
use (Just n) = return n use (Just n) = return n
use Nothing = perhaps (return 1) =<< use Nothing = perhaps (return 1) =<<
readish <$> getConfig (annexConfig "numcopies") "1" readish <$> getConfig (annexConfig "numcopies") "1"
perhaps fallback = maybe fallback (return . id) perhaps fallback = maybe fallback (return . id)
{- Gets the trust level set for a remote in git config. -} {- Gets the trust level set for a remote in git config. -}
getTrustLevel :: Git.Repo -> Annex (Maybe String) getTrustLevel :: Git.Repo -> Annex (Maybe String)
getTrustLevel r = fromRepo $ Git.Config.getMaybe key getTrustLevel r = fromRepo $ Git.Config.getMaybe key
where where
(ConfigKey key) = remoteConfig r "trustlevel" (ConfigKey key) = remoteConfig r "trustlevel"
{- Gets annex.diskreserve setting. -} {- Gets annex.diskreserve setting. -}
getDiskReserve :: Annex Integer getDiskReserve :: Annex Integer
getDiskReserve = fromMaybe megabyte . readSize dataUnits getDiskReserve = fromMaybe megabyte . readSize dataUnits
<$> getConfig (annexConfig "diskreserve") "" <$> getConfig (annexConfig "diskreserve") ""
where where
megabyte = 1000000 megabyte = 1000000
{- Gets annex.httpheaders or annex.httpheaders-command setting, {- Gets annex.httpheaders or annex.httpheaders-command setting,
- splitting it into lines. -} - splitting it into lines. -}

View file

@ -75,16 +75,16 @@ updateEncryptedCipher keyid encipher@(EncryptedCipher _ ks) = do
ks' <- Gpg.findPubKeys keyid ks' <- Gpg.findPubKeys keyid
cipher <- decryptCipher encipher cipher <- decryptCipher encipher
encryptCipher cipher (merge ks ks') encryptCipher cipher (merge ks ks')
where where
merge (KeyIds a) (KeyIds b) = KeyIds $ a ++ b merge (KeyIds a) (KeyIds b) = KeyIds $ a ++ b
describeCipher :: StorableCipher -> String describeCipher :: StorableCipher -> String
describeCipher (SharedCipher _) = "shared cipher" describeCipher (SharedCipher _) = "shared cipher"
describeCipher (EncryptedCipher _ (KeyIds ks)) = describeCipher (EncryptedCipher _ (KeyIds ks)) =
"with gpg " ++ keys ks ++ " " ++ unwords ks "with gpg " ++ keys ks ++ " " ++ unwords ks
where where
keys [_] = "key" keys [_] = "key"
keys _ = "keys" keys _ = "keys"
{- Encrypts a Cipher to the specified KeyIds. -} {- Encrypts a Cipher to the specified KeyIds. -}
encryptCipher :: Cipher -> KeyIds -> IO StorableCipher encryptCipher :: Cipher -> KeyIds -> IO StorableCipher
@ -92,20 +92,20 @@ encryptCipher (Cipher c) (KeyIds ks) = do
let ks' = nub $ sort ks -- gpg complains about duplicate recipient keyids let ks' = nub $ sort ks -- gpg complains about duplicate recipient keyids
encipher <- Gpg.pipeStrict (encrypt++recipients ks') c encipher <- Gpg.pipeStrict (encrypt++recipients ks') c
return $ EncryptedCipher encipher (KeyIds ks') return $ EncryptedCipher encipher (KeyIds ks')
where where
encrypt = [ Params "--encrypt" ] encrypt = [ Params "--encrypt" ]
recipients l = force_recipients : recipients l = force_recipients :
concatMap (\k -> [Param "--recipient", Param k]) l concatMap (\k -> [Param "--recipient", Param k]) l
-- Force gpg to only encrypt to the specified -- Force gpg to only encrypt to the specified
-- recipients, not configured defaults. -- recipients, not configured defaults.
force_recipients = Params "--no-encrypt-to --no-default-recipient" force_recipients = Params "--no-encrypt-to --no-default-recipient"
{- Decrypting an EncryptedCipher is expensive; the Cipher should be cached. -} {- Decrypting an EncryptedCipher is expensive; the Cipher should be cached. -}
decryptCipher :: StorableCipher -> IO Cipher decryptCipher :: StorableCipher -> IO Cipher
decryptCipher (SharedCipher t) = return $ Cipher t decryptCipher (SharedCipher t) = return $ Cipher t
decryptCipher (EncryptedCipher t _) = Cipher <$> Gpg.pipeStrict decrypt t decryptCipher (EncryptedCipher t _) = Cipher <$> Gpg.pipeStrict decrypt t
where where
decrypt = [ Param "--decrypt" ] decrypt = [ Param "--decrypt" ]
{- Generates an encrypted form of a Key. The encryption does not need to be {- Generates an encrypted form of a Key. The encryption does not need to be
- reversable, nor does it need to be the same type of encryption used - reversable, nor does it need to be the same type of encryption used
@ -136,8 +136,12 @@ withEncryptedContent = pass withEncryptedHandle
withDecryptedContent :: Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a withDecryptedContent :: Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a
withDecryptedContent = pass withDecryptedHandle withDecryptedContent = pass withDecryptedHandle
pass :: (Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a) pass
-> Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a :: (Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a)
-> Cipher
-> IO L.ByteString
-> (L.ByteString -> IO a)
-> IO a
pass to n s a = to n s $ a <=< L.hGetContents pass to n s a = to n s $ a <=< L.hGetContents
hmacWithCipher :: Cipher -> String -> String hmacWithCipher :: Cipher -> String -> String
@ -148,5 +152,5 @@ hmacWithCipher' c s = showDigest $ hmacSha1 (fromString c) (fromString s)
{- Ensure that hmacWithCipher' returns the same thing forevermore. -} {- Ensure that hmacWithCipher' returns the same thing forevermore. -}
prop_hmacWithCipher_sane :: Bool prop_hmacWithCipher_sane :: Bool
prop_hmacWithCipher_sane = known_good == hmacWithCipher' "foo" "bar" prop_hmacWithCipher_sane = known_good == hmacWithCipher' "foo" "bar"
where where
known_good = "46b4ec586117154dacd49d664e5d63fdc88efb51" known_good = "46b4ec586117154dacd49d664e5d63fdc88efb51"

10
Init.hs
View file

@ -52,11 +52,11 @@ uninitialize = do
repos that did not intend to use it. -} repos that did not intend to use it. -}
ensureInitialized :: Annex () ensureInitialized :: Annex ()
ensureInitialized = getVersion >>= maybe needsinit checkVersion ensureInitialized = getVersion >>= maybe needsinit checkVersion
where where
needsinit = ifM Annex.Branch.hasSibling needsinit = ifM Annex.Branch.hasSibling
( initialize Nothing ( initialize Nothing
, error "First run: git-annex init" , error "First run: git-annex init"
) )
{- Checks if a repository is initialized. Does not check version for ugrade. -} {- Checks if a repository is initialized. Does not check version for ugrade. -}
isInitialized :: Annex Bool isInitialized :: Annex Bool

View file

@ -100,10 +100,10 @@ gitAnnexLocation key r
- don't need to do any work to check if the file is - don't need to do any work to check if the file is
- present. -} - present. -}
return $ inrepo $ annexLocation key hashDirMixed return $ inrepo $ annexLocation key hashDirMixed
where where
inrepo d = Git.localGitDir r </> d inrepo d = Git.localGitDir r </> d
check locs@(l:_) = fromMaybe l <$> firstM doesFileExist locs check locs@(l:_) = fromMaybe l <$> firstM doesFileExist locs
check [] = error "internal" check [] = error "internal"
{- The annex directory of a repository. -} {- The annex directory of a repository. -}
gitAnnexDir :: Git.Repo -> FilePath gitAnnexDir :: Git.Repo -> FilePath
@ -204,8 +204,8 @@ gitAnnexAssistantDefaultDir = "annex"
{- Checks a symlink target to see if it appears to point to annexed content. -} {- Checks a symlink target to see if it appears to point to annexed content. -}
isLinkToAnnex :: FilePath -> Bool isLinkToAnnex :: FilePath -> Bool
isLinkToAnnex s = ('/':d) `isInfixOf` s || d `isPrefixOf` s isLinkToAnnex s = ('/':d) `isInfixOf` s || d `isPrefixOf` s
where where
d = ".git" </> objectDir d = ".git" </> objectDir
{- Converts a key into a filename fragment without any directory. {- Converts a key into a filename fragment without any directory.
- -
@ -232,8 +232,8 @@ keyFile key = replace "/" "%" $ replace ":" "&c" $
-} -}
keyPath :: Key -> Hasher -> FilePath keyPath :: Key -> Hasher -> FilePath
keyPath key hasher = hasher key </> f </> f keyPath key hasher = hasher key </> f </> f
where where
f = keyFile key f = keyFile key
{- All possibile locations to store a key using different directory hashes. -} {- All possibile locations to store a key using different directory hashes. -}
keyPaths :: Key -> [FilePath] keyPaths :: Key -> [FilePath]
@ -249,7 +249,8 @@ fileKey file = file2key $
{- for quickcheck -} {- for quickcheck -}
prop_idempotent_fileKey :: String -> Bool prop_idempotent_fileKey :: String -> Bool
prop_idempotent_fileKey s = Just k == fileKey (keyFile k) prop_idempotent_fileKey s = Just k == fileKey (keyFile k)
where k = stubKey { keyName = s, keyBackendName = "test" } where
k = stubKey { keyName = s, keyBackendName = "test" }
{- Two different directory hashes may be used. The mixed case hash {- Two different directory hashes may be used. The mixed case hash
- came first, and is fine, except for the problem of case-strict - came first, and is fine, except for the problem of case-strict
@ -262,14 +263,14 @@ annexHashes = [hashDirLower, hashDirMixed]
hashDirMixed :: Hasher hashDirMixed :: Hasher
hashDirMixed k = addTrailingPathSeparator $ take 2 dir </> drop 2 dir hashDirMixed k = addTrailingPathSeparator $ take 2 dir </> drop 2 dir
where where
dir = take 4 $ display_32bits_as_dir =<< [a,b,c,d] dir = take 4 $ display_32bits_as_dir =<< [a,b,c,d]
ABCD (a,b,c,d) = md5 $ md5FilePath $ key2file k ABCD (a,b,c,d) = md5 $ md5FilePath $ key2file k
hashDirLower :: Hasher hashDirLower :: Hasher
hashDirLower k = addTrailingPathSeparator $ take 3 dir </> drop 3 dir hashDirLower k = addTrailingPathSeparator $ take 3 dir </> drop 3 dir
where where
dir = take 6 $ md5s $ md5FilePath $ key2file k dir = take 6 $ md5s $ md5FilePath $ key2file k
{- modified version of display_32bits_as_hex from Data.Hash.MD5 {- modified version of display_32bits_as_hex from Data.Hash.MD5
- Copyright (C) 2001 Ian Lynagh - Copyright (C) 2001 Ian Lynagh
@ -277,13 +278,13 @@ hashDirLower k = addTrailingPathSeparator $ take 3 dir </> drop 3 dir
-} -}
display_32bits_as_dir :: Word32 -> String display_32bits_as_dir :: Word32 -> String
display_32bits_as_dir w = trim $ swap_pairs cs display_32bits_as_dir w = trim $ swap_pairs cs
where where
-- Need 32 characters to use. To avoid inaverdently making -- Need 32 characters to use. To avoid inaverdently making
-- a real word, use letters that appear less frequently. -- a real word, use letters that appear less frequently.
chars = ['0'..'9'] ++ "zqjxkmvwgpfZQJXKMVWGPF" chars = ['0'..'9'] ++ "zqjxkmvwgpfZQJXKMVWGPF"
cs = map (\x -> getc $ (shiftR w (6*x)) .&. 31) [0..7] cs = map (\x -> getc $ (shiftR w (6*x)) .&. 31) [0..7]
getc n = chars !! fromIntegral n getc n = chars !! fromIntegral n
swap_pairs (x1:x2:xs) = x2:x1:swap_pairs xs swap_pairs (x1:x2:xs) = x2:x1:swap_pairs xs
swap_pairs _ = [] swap_pairs _ = []
-- Last 2 will always be 00, so omit. -- Last 2 will always be 00, so omit.
trim = take 6 trim = take 6

View file

@ -84,7 +84,7 @@ showSideAction m = Annex.getState Annex.output >>= go
where where
go (MessageState v StartBlock) = do go (MessageState v StartBlock) = do
p p
Annex.changeState $ \s -> s { Annex.output = MessageState v InBlock } Annex.changeState $ \s -> s { Annex.output = MessageState v InBlock }
go (MessageState _ InBlock) = return () go (MessageState _ InBlock) = return ()
go _ = p go _ = p
p = handle q $ putStrLn $ "(" ++ m ++ "...)" p = handle q $ putStrLn $ "(" ++ m ++ "...)"

View file

@ -46,18 +46,18 @@ common =
, Option ['b'] ["backend"] (ReqArg setforcebackend paramName) , Option ['b'] ["backend"] (ReqArg setforcebackend paramName)
"specify key-value backend to use" "specify key-value backend to use"
] ]
where where
setforce v = Annex.changeState $ \s -> s { Annex.force = v } setforce v = Annex.changeState $ \s -> s { Annex.force = v }
setfast v = Annex.changeState $ \s -> s { Annex.fast = v } setfast v = Annex.changeState $ \s -> s { Annex.fast = v }
setauto v = Annex.changeState $ \s -> s { Annex.auto = v } setauto v = Annex.changeState $ \s -> s { Annex.auto = v }
setforcebackend v = Annex.changeState $ \s -> s { Annex.forcebackend = Just v } setforcebackend v = Annex.changeState $ \s -> s { Annex.forcebackend = Just v }
setdebug = liftIO $ do setdebug = liftIO $ do
s <- simpledebug s <- simpledebug
updateGlobalLogger rootLoggerName updateGlobalLogger rootLoggerName
(setLevel DEBUG . setHandlers [s]) (setLevel DEBUG . setHandlers [s])
simpledebug = setFormatter simpledebug = setFormatter
<$> streamHandler stderr DEBUG <$> streamHandler stderr DEBUG
<*> pure (simpleLogFormatter "[$time] $msg") <*> pure (simpleLogFormatter "[$time] $msg")
matcher :: [Option] matcher :: [Option]
matcher = matcher =
@ -67,9 +67,9 @@ matcher =
, shortopt "(" "open group of options" , shortopt "(" "open group of options"
, shortopt ")" "close group of options" , shortopt ")" "close group of options"
] ]
where where
longopt o = Option [] [o] $ NoArg $ addToken o longopt o = Option [] [o] $ NoArg $ addToken o
shortopt o = Option o [] $ NoArg $ addToken o shortopt o = Option o [] $ NoArg $ addToken o
{- An option that sets a flag. -} {- An option that sets a flag. -}
flag :: String -> String -> String -> Option flag :: String -> String -> String -> Option

View file

@ -80,10 +80,10 @@ byName (Just n) = either error Just <$> byName' n
byName' :: String -> Annex (Either String Remote) byName' :: String -> Annex (Either String Remote)
byName' "" = return $ Left "no remote specified" byName' "" = return $ Left "no remote specified"
byName' n = handle . filter matching <$> remoteList byName' n = handle . filter matching <$> remoteList
where where
handle [] = Left $ "there is no available git remote named \"" ++ n ++ "\"" handle [] = Left $ "there is no available git remote named \"" ++ n ++ "\""
handle match = Right $ Prelude.head match handle match = Right $ Prelude.head match
matching r = n == name r || toUUID n == uuid r matching r = n == name r || toUUID n == uuid r
{- Looks up a remote by name (or by UUID, or even by description), {- Looks up a remote by name (or by UUID, or even by description),
- and returns its UUID. Finds even remotes that are not configured in - and returns its UUID. Finds even remotes that are not configured in
@ -93,17 +93,17 @@ nameToUUID "." = getUUID -- special case for current repo
nameToUUID "here" = getUUID nameToUUID "here" = getUUID
nameToUUID "" = error "no remote specified" nameToUUID "" = error "no remote specified"
nameToUUID n = byName' n >>= go nameToUUID n = byName' n >>= go
where where
go (Right r) = return $ uuid r go (Right r) = return $ uuid r
go (Left e) = fromMaybe (error e) <$> bydescription go (Left e) = fromMaybe (error e) <$> bydescription
bydescription = do bydescription = do
m <- uuidMap m <- uuidMap
case M.lookup n $ transform swap m of case M.lookup n $ transform swap m of
Just u -> return $ Just u Just u -> return $ Just u
Nothing -> return $ byuuid m Nothing -> return $ byuuid m
byuuid m = M.lookup (toUUID n) $ transform double m byuuid m = M.lookup (toUUID n) $ transform double m
transform a = M.fromList . map a . M.toList transform a = M.fromList . map a . M.toList
double (a, _) = (a, a) double (a, _) = (a, a)
{- Pretty-prints a list of UUIDs of remotes, for human display. {- Pretty-prints a list of UUIDs of remotes, for human display.
- -
@ -115,23 +115,23 @@ prettyPrintUUIDs desc uuids = do
m <- uuidDescriptions m <- uuidDescriptions
maybeShowJSON [(desc, map (jsonify m hereu) uuids)] maybeShowJSON [(desc, map (jsonify m hereu) uuids)]
return $ unwords $ map (\u -> "\t" ++ prettify m hereu u ++ "\n") uuids return $ unwords $ map (\u -> "\t" ++ prettify m hereu u ++ "\n") uuids
where where
finddescription m u = M.findWithDefault "" u m finddescription m u = M.findWithDefault "" u m
prettify m hereu u prettify m hereu u
| not (null d) = fromUUID u ++ " -- " ++ d | not (null d) = fromUUID u ++ " -- " ++ d
| otherwise = fromUUID u | otherwise = fromUUID u
where where
ishere = hereu == u ishere = hereu == u
n = finddescription m u n = finddescription m u
d d
| null n && ishere = "here" | null n && ishere = "here"
| ishere = addName n "here" | ishere = addName n "here"
| otherwise = n | otherwise = n
jsonify m hereu u = toJSObject jsonify m hereu u = toJSObject
[ ("uuid", toJSON $ fromUUID u) [ ("uuid", toJSON $ fromUUID u)
, ("description", toJSON $ finddescription m u) , ("description", toJSON $ finddescription m u)
, ("here", toJSON $ hereu == u) , ("here", toJSON $ hereu == u)
] ]
{- List of remote names and/or descriptions, for human display. -} {- List of remote names and/or descriptions, for human display. -}
prettyListUUIDs :: [UUID] -> Annex [String] prettyListUUIDs :: [UUID] -> Annex [String]
@ -139,13 +139,13 @@ prettyListUUIDs uuids = do
hereu <- getUUID hereu <- getUUID
m <- uuidDescriptions m <- uuidDescriptions
return $ map (\u -> prettify m hereu u) uuids return $ map (\u -> prettify m hereu u) uuids
where where
finddescription m u = M.findWithDefault "" u m finddescription m u = M.findWithDefault "" u m
prettify m hereu u prettify m hereu u
| u == hereu = addName n "here" | u == hereu = addName n "here"
| otherwise = n | otherwise = n
where where
n = finddescription m u n = finddescription m u
{- Gets the git repo associated with a UUID. {- Gets the git repo associated with a UUID.
- There's no associated remote when this is the UUID of the local repo. -} - There's no associated remote when this is the UUID of the local repo. -}
@ -213,12 +213,12 @@ showLocations key exclude = do
ppuuidswanted <- Remote.prettyPrintUUIDs "wanted" uuidswanted ppuuidswanted <- Remote.prettyPrintUUIDs "wanted" uuidswanted
ppuuidsskipped <- Remote.prettyPrintUUIDs "skipped" uuidsskipped ppuuidsskipped <- Remote.prettyPrintUUIDs "skipped" uuidsskipped
showLongNote $ message ppuuidswanted ppuuidsskipped showLongNote $ message ppuuidswanted ppuuidsskipped
where where
filteruuids l x = filter (`notElem` x) l filteruuids l x = filter (`notElem` x) l
message [] [] = "No other repository is known to contain the file." message [] [] = "No other repository is known to contain the file."
message rs [] = "Try making some of these repositories available:\n" ++ rs message rs [] = "Try making some of these repositories available:\n" ++ rs
message [] us = "Also these untrusted repositories may contain the file:\n" ++ us message [] us = "Also these untrusted repositories may contain the file:\n" ++ us
message rs us = message rs [] ++ message [] us message rs us = message rs [] ++ message [] us
showTriedRemotes :: [Remote] -> Annex () showTriedRemotes :: [Remote] -> Annex ()
showTriedRemotes [] = noop showTriedRemotes [] = noop
@ -242,6 +242,6 @@ logStatus remote key = logChange key (uuid remote)
{- Orders remotes by cost, with ones with the lowest cost grouped together. -} {- Orders remotes by cost, with ones with the lowest cost grouped together. -}
byCost :: [Remote] -> [[Remote]] byCost :: [Remote] -> [[Remote]]
byCost = map snd . sort . M.toList . costmap byCost = map snd . sort . M.toList . costmap
where where
costmap = M.fromListWith (++) . map costpair costmap = M.fromListWith (++) . map costpair
costpair r = (cost r, [r]) costpair r = (cost r, [r])

View file

@ -55,15 +55,15 @@ list = do
c <- fromRepo Git.config c <- fromRepo Git.config
rs <- mapM (tweakurl c) =<< fromRepo Git.remotes rs <- mapM (tweakurl c) =<< fromRepo Git.remotes
mapM configRead rs mapM configRead rs
where where
annexurl n = "remote." ++ n ++ ".annexurl" annexurl n = "remote." ++ n ++ ".annexurl"
tweakurl c r = do tweakurl c r = do
let n = fromJust $ Git.remoteName r let n = fromJust $ Git.remoteName r
case M.lookup (annexurl n) c of case M.lookup (annexurl n) c of
Nothing -> return r Nothing -> return r
Just url -> inRepo $ \g -> Just url -> inRepo $ \g ->
Git.Construct.remoteNamed n $ Git.Construct.remoteNamed n $
Git.Construct.fromRemoteLocation url g Git.Construct.fromRemoteLocation url g
{- It's assumed to be cheap to read the config of non-URL remotes, so this is {- It's assumed to be cheap to read the config of non-URL remotes, so this is
- done each time git-annex is run in a way that uses remotes. - done each time git-annex is run in a way that uses remotes.
@ -85,28 +85,27 @@ repoCheap = not . Git.repoIsUrl
gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex Remote gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex Remote
gen r u _ = new <$> remoteCost r defcst gen r u _ = new <$> remoteCost r defcst
where where
defcst = if repoCheap r then cheapRemoteCost else expensiveRemoteCost defcst = if repoCheap r then cheapRemoteCost else expensiveRemoteCost
new cst = Remote new cst = Remote
{ uuid = u { uuid = u
, cost = cst , cost = cst
, name = Git.repoDescribe r , name = Git.repoDescribe r
, storeKey = copyToRemote r , storeKey = copyToRemote r
, retrieveKeyFile = copyFromRemote r , retrieveKeyFile = copyFromRemote r
, retrieveKeyFileCheap = copyFromRemoteCheap r , retrieveKeyFileCheap = copyFromRemoteCheap r
, removeKey = dropKey r , removeKey = dropKey r
, hasKey = inAnnex r , hasKey = inAnnex r
, hasKeyCheap = repoCheap r , hasKeyCheap = repoCheap r
, whereisKey = Nothing , whereisKey = Nothing
, config = Nothing , config = Nothing
, localpath = if Git.repoIsLocal r || Git.repoIsLocalUnknown r , localpath = if Git.repoIsLocal r || Git.repoIsLocalUnknown r
then Just $ Git.repoPath r then Just $ Git.repoPath r
else Nothing else Nothing
, repo = r , repo = r
, readonly = Git.repoIsHttp r , readonly = Git.repoIsHttp r
, remotetype = remote , remotetype = remote
} }
{- Checks relatively inexpensively if a repository is available for use. -} {- Checks relatively inexpensively if a repository is available for use. -}
repoAvail :: Git.Repo -> Annex Bool repoAvail :: Git.Repo -> Annex Bool
@ -149,40 +148,40 @@ tryGitConfigRead r
| otherwise = store $ safely $ onLocal r $ do | otherwise = store $ safely $ onLocal r $ do
ensureInitialized ensureInitialized
Annex.getState Annex.repo Annex.getState Annex.repo
where where
-- Reading config can fail due to IO error or -- Reading config can fail due to IO error or
-- for other reasons; catch all possible exceptions. -- for other reasons; catch all possible exceptions.
safely a = either (const $ return r) return safely a = either (const $ return r) return
=<< liftIO (try a :: IO (Either SomeException Git.Repo)) =<< liftIO (try a :: IO (Either SomeException Git.Repo))
pipedconfig cmd params = pipedconfig cmd params =
withHandle StdoutHandle createProcessSuccess p $ withHandle StdoutHandle createProcessSuccess p $
Git.Config.hRead r Git.Config.hRead r
where where
p = proc cmd $ toCommand params p = proc cmd $ toCommand params
pipedsshconfig cmd params = pipedsshconfig cmd params =
liftIO (try (pipedconfig cmd params) :: IO (Either SomeException Git.Repo)) liftIO (try (pipedconfig cmd params) :: IO (Either SomeException Git.Repo))
geturlconfig headers = do geturlconfig headers = do
s <- Url.get (Git.repoLocation r ++ "/config") headers s <- Url.get (Git.repoLocation r ++ "/config") headers
withTempFile "git-annex.tmp" $ \tmpfile h -> do withTempFile "git-annex.tmp" $ \tmpfile h -> do
hPutStr h s hPutStr h s
hClose h hClose h
safely $ pipedconfig "git" [Param "config", Param "--null", Param "--list", Param "--file", File tmpfile] safely $ pipedconfig "git" [Param "config", Param "--null", Param "--list", Param "--file", File tmpfile]
store = observe $ \r' -> do store = observe $ \r' -> do
g <- gitRepo g <- gitRepo
let l = Git.remotes g let l = Git.remotes g
let g' = g { Git.remotes = exchange l r' } let g' = g { Git.remotes = exchange l r' }
Annex.changeState $ \s -> s { Annex.repo = g' } Annex.changeState $ \s -> s { Annex.repo = g' }
exchange [] _ = [] exchange [] _ = []
exchange (old:ls) new exchange (old:ls) new
| Git.remoteName old == Git.remoteName new = | Git.remoteName old == Git.remoteName new =
new : exchange ls new new : exchange ls new
| otherwise = | otherwise =
old : exchange ls new old : exchange ls new
{- Checks if a given remote has the content for a key inAnnex. {- Checks if a given remote has the content for a key inAnnex.
- If the remote cannot be accessed, or if it cannot determine - If the remote cannot be accessed, or if it cannot determine
@ -193,32 +192,32 @@ inAnnex r key
| Git.repoIsHttp r = checkhttp =<< getHttpHeaders | Git.repoIsHttp r = checkhttp =<< getHttpHeaders
| Git.repoIsUrl r = checkremote | Git.repoIsUrl r = checkremote
| otherwise = checklocal | otherwise = checklocal
where where
checkhttp headers = liftIO $ go undefined $ keyUrls r key checkhttp headers = liftIO $ go undefined $ keyUrls r key
where where
go e [] = return $ Left e go e [] = return $ Left e
go _ (u:us) = do go _ (u:us) = do
res <- catchMsgIO $ res <- catchMsgIO $
Url.check u headers (keySize key) Url.check u headers (keySize key)
case res of case res of
Left e -> go e us Left e -> go e us
v -> return v v -> return v
checkremote = do checkremote = do
showAction $ "checking " ++ Git.repoDescribe r showAction $ "checking " ++ Git.repoDescribe r
onRemote r (check, unknown) "inannex" [Param (key2file key)] [] onRemote r (check, unknown) "inannex" [Param (key2file key)] []
where where
check c p = dispatch <$> safeSystem c p check c p = dispatch <$> safeSystem c p
dispatch ExitSuccess = Right True dispatch ExitSuccess = Right True
dispatch (ExitFailure 1) = Right False dispatch (ExitFailure 1) = Right False
dispatch _ = unknown dispatch _ = unknown
checklocal = guardUsable r unknown $ dispatch <$> check checklocal = guardUsable r unknown $ dispatch <$> check
where where
check = liftIO $ catchMsgIO $ onLocal r $ check = liftIO $ catchMsgIO $ onLocal r $
Annex.Content.inAnnexSafe key Annex.Content.inAnnexSafe key
dispatch (Left e) = Left e dispatch (Left e) = Left e
dispatch (Right (Just b)) = Right b dispatch (Right (Just b)) = Right b
dispatch (Right Nothing) = unknown dispatch (Right Nothing) = unknown
unknown = Left $ "unable to check " ++ Git.repoDescribe r unknown = Left $ "unable to check " ++ Git.repoDescribe r
{- Runs an action on a local repository inexpensively, by making an annex {- Runs an action on a local repository inexpensively, by making an annex
- monad using that repository. -} - monad using that repository. -}
@ -233,8 +232,8 @@ onLocal r a = do
keyUrls :: Git.Repo -> Key -> [String] keyUrls :: Git.Repo -> Key -> [String]
keyUrls r key = map tourl (annexLocations key) keyUrls r key = map tourl (annexLocations key)
where where
tourl l = Git.repoLocation r ++ "/" ++ l tourl l = Git.repoLocation r ++ "/" ++ l
dropKey :: Git.Repo -> Key -> Annex Bool dropKey :: Git.Repo -> Key -> Annex Bool
dropKey r key dropKey r key
@ -271,44 +270,44 @@ copyFromRemote r key file dest
=<< rsyncParamsRemote r True key dest file =<< rsyncParamsRemote r True key dest file
| Git.repoIsHttp r = Annex.Content.downloadUrl (keyUrls r key) dest | Git.repoIsHttp r = Annex.Content.downloadUrl (keyUrls r key) dest
| otherwise = error "copying from non-ssh, non-http repo not supported" | otherwise = error "copying from non-ssh, non-http repo not supported"
where where
{- Feed local rsync's progress info back to the remote, {- Feed local rsync's progress info back to the remote,
- by forking a feeder thread that runs - by forking a feeder thread that runs
- git-annex-shell transferinfo at the same time - git-annex-shell transferinfo at the same time
- git-annex-shell sendkey is running. - git-annex-shell sendkey is running.
- -
- Note that it actually waits for rsync to indicate - Note that it actually waits for rsync to indicate
- progress before starting transferinfo, in order - progress before starting transferinfo, in order
- to ensure ssh connection caching works and reuses - to ensure ssh connection caching works and reuses
- the connection set up for the sendkey. - the connection set up for the sendkey.
- -
- Also note that older git-annex-shell does not support - Also note that older git-annex-shell does not support
- transferinfo, so stderr is dropped and failure ignored. - transferinfo, so stderr is dropped and failure ignored.
-} -}
feedprogressback a = do feedprogressback a = do
u <- getUUID u <- getUUID
let fields = (Fields.remoteUUID, fromUUID u) let fields = (Fields.remoteUUID, fromUUID u)
: maybe [] (\f -> [(Fields.associatedFile, f)]) file : maybe [] (\f -> [(Fields.associatedFile, f)]) file
Just (cmd, params) <- git_annex_shell r "transferinfo" Just (cmd, params) <- git_annex_shell r "transferinfo"
[Param $ key2file key] fields [Param $ key2file key] fields
v <- liftIO $ newEmptySV v <- liftIO $ newEmptySV
tid <- liftIO $ forkIO $ void $ tryIO $ do tid <- liftIO $ forkIO $ void $ tryIO $ do
bytes <- readSV v bytes <- readSV v
p <- createProcess $ p <- createProcess $
(proc cmd (toCommand params)) (proc cmd (toCommand params))
{ std_in = CreatePipe { std_in = CreatePipe
, std_err = CreatePipe , std_err = CreatePipe
} }
hClose $ stderrHandle p hClose $ stderrHandle p
let h = stdinHandle p let h = stdinHandle p
let send b = do let send b = do
hPutStrLn h $ show b hPutStrLn h $ show b
hFlush h hFlush h
send bytes send bytes
forever $ forever $
send =<< readSV v send =<< readSV v
let feeder = writeSV v let feeder = writeSV v
bracketIO noop (const $ tryIO $ killThread tid) (a feeder) bracketIO noop (const $ tryIO $ killThread tid) (a feeder)
copyFromRemoteCheap :: Git.Repo -> Key -> FilePath -> Annex Bool copyFromRemoteCheap :: Git.Repo -> Key -> FilePath -> Annex Bool
copyFromRemoteCheap r key file copyFromRemoteCheap r key file
@ -359,26 +358,26 @@ rsyncHelper callback params = do
rsyncOrCopyFile :: [CommandParam] -> FilePath -> FilePath -> MeterUpdate -> Annex Bool rsyncOrCopyFile :: [CommandParam] -> FilePath -> FilePath -> MeterUpdate -> Annex Bool
rsyncOrCopyFile rsyncparams src dest p = rsyncOrCopyFile rsyncparams src dest p =
ifM (sameDeviceIds src dest) (docopy, dorsync) ifM (sameDeviceIds src dest) (docopy, dorsync)
where where
sameDeviceIds a b = (==) <$> (getDeviceId a) <*> (getDeviceId b) sameDeviceIds a b = (==) <$> (getDeviceId a) <*> (getDeviceId b)
getDeviceId f = deviceID <$> liftIO (getFileStatus $ parentDir f) getDeviceId f = deviceID <$> liftIO (getFileStatus $ parentDir f)
dorsync = rsyncHelper (Just p) $ dorsync = rsyncHelper (Just p) $
rsyncparams ++ [Param src, Param dest] rsyncparams ++ [Param src, Param dest]
docopy = liftIO $ bracket docopy = liftIO $ bracket
(forkIO $ watchfilesize 0) (forkIO $ watchfilesize 0)
(void . tryIO . killThread) (void . tryIO . killThread)
(const $ copyFileExternal src dest) (const $ copyFileExternal src dest)
watchfilesize oldsz = do watchfilesize oldsz = do
threadDelay 500000 -- 0.5 seconds threadDelay 500000 -- 0.5 seconds
v <- catchMaybeIO $ v <- catchMaybeIO $
fromIntegral . fileSize fromIntegral . fileSize
<$> getFileStatus dest <$> getFileStatus dest
case v of case v of
Just sz Just sz
| sz /= oldsz -> do | sz /= oldsz -> do
p sz p sz
watchfilesize sz watchfilesize sz
_ -> watchfilesize oldsz _ -> watchfilesize oldsz
{- Generates rsync parameters that ssh to the remote and asks it {- Generates rsync parameters that ssh to the remote and asks it
- to either receive or send the key's content. -} - to either receive or send the key's content. -}
@ -397,44 +396,43 @@ rsyncParamsRemote r sending key file afile = do
if sending if sending
then return $ o ++ rsyncopts eparam dummy (File file) then return $ o ++ rsyncopts eparam dummy (File file)
else return $ o ++ rsyncopts eparam (File file) dummy else return $ o ++ rsyncopts eparam (File file) dummy
where where
rsyncopts ps source dest rsyncopts ps source dest
| end ps == [dashdash] = ps ++ [source, dest] | end ps == [dashdash] = ps ++ [source, dest]
| otherwise = ps ++ [dashdash, source, dest] | otherwise = ps ++ [dashdash, source, dest]
dashdash = Param "--" dashdash = Param "--"
-- The rsync shell parameter controls where rsync {- The rsync shell parameter controls where rsync
-- goes, so the source/dest parameter can be a dummy value, - goes, so the source/dest parameter can be a dummy value,
-- that just enables remote rsync mode. - that just enables remote rsync mode.
-- For maximum compatability with some patched rsyncs, - For maximum compatability with some patched rsyncs,
-- the dummy value needs to still contain a hostname, - the dummy value needs to still contain a hostname,
-- even though this hostname will never be used. - even though this hostname will never be used. -}
dummy = Param "dummy:" dummy = Param "dummy:"
rsyncParams :: Git.Repo -> Annex [CommandParam] rsyncParams :: Git.Repo -> Annex [CommandParam]
rsyncParams r = do rsyncParams r = do
o <- getRemoteConfig r "rsync-options" "" o <- getRemoteConfig r "rsync-options" ""
return $ options ++ map Param (words o) return $ options ++ map Param (words o)
where where
-- --inplace to resume partial files -- --inplace to resume partial files
options = [Params "-p --progress --inplace"] options = [Params "-p --progress --inplace"]
commitOnCleanup :: Git.Repo -> Annex a -> Annex a commitOnCleanup :: Git.Repo -> Annex a -> Annex a
commitOnCleanup r a = go `after` a commitOnCleanup r a = go `after` a
where where
go = Annex.addCleanup (Git.repoLocation r) cleanup go = Annex.addCleanup (Git.repoLocation r) cleanup
cleanup cleanup
| not $ Git.repoIsUrl r = liftIO $ onLocal r $ | not $ Git.repoIsUrl r = liftIO $ onLocal r $
doQuietSideAction $ doQuietSideAction $
Annex.Branch.commit "update" Annex.Branch.commit "update"
| otherwise = void $ do | otherwise = void $ do
Just (shellcmd, shellparams) <- Just (shellcmd, shellparams) <-
git_annex_shell r "commit" [] [] git_annex_shell r "commit" [] []
-- Throw away stderr, since the remote may not -- Throw away stderr, since the remote may not
-- have a new enough git-annex shell to -- have a new enough git-annex shell to
-- support committing. -- support committing.
liftIO $ catchMaybeIO $ do liftIO $ catchMaybeIO $ do
print "!!!!!!!!!!!!!" withQuietOutput createProcessSuccess $
withQuietOutput createProcessSuccess $ proc shellcmd $
proc shellcmd $ toCommand shellparams
toCommand shellparams

86
doc/coding_style.mdwn Normal file
View file

@ -0,0 +1,86 @@
If you do nothing else, avoid use of partial functions from the Prelude!
`import Utility.PartialPrelude` helps avoid this by defining conflicting
functions for all the common ones. Also avoid `!!`, it's partial too.
Use tabs for indentation. The one exception to this rule are
the Hamlet format files in `templates/*`. Hamlet, infuriatingly, refuses
to allow tabs to be used for indentation.
Code should make sense with any tab stop setting, but 8 space tabs are
the default. With 8 space tabs, code should not exceed 80 characters
per line. (With larger tabs, it may of course.)
Use spaces for layout. For example, here spaces (indicated with `.`
are used after the initial tab to make the third test line up with
the others.
when (foo_test || bar_test ||
......some_other_long_test)
print "hi"
As a special Haskell-specific rule, "where" clauses are indented with two
spaces, rather than a tab. This makes them stand out from the main body
of the function, and avoids excessive indentation of the where cause content.
The definitions within the where clause should be put on separate lines,
each indented with a tab.
foo = do
foo
bar
foo
where
foo = ...
bar = ...
Where clauses for instance definitions and modules tend to appear at the end
of a line, rather than on a separate line.
instance MonadBaseControl IO Annex where
When a function's type signature needs to be wrapped to another line,
it's typical to switch to displaying one parameter per line.
foo :: Bar -> Baz -> (Bar -> Baz) -> IO Baz
foo'
:: Bar
-> Baz
-> (Bar -> Baz)
-> IO Baz
Note that the "::" then starts its own line. It is not put on the same
line as the function name because then it would not be guaranteed to line
up with the "->" at all tab width settings. Similarly, guards are put
on their own lines:
splat i
| odd i = error "splat!"
| otherwise = i
Multiline lists and record syntax are written with leading commas,
that line up with the open and close punctuation.
list =
[ item1
, item2
, item3
]
foo = DataStructure
{ name = "bar"
, address = "baz"
}
Module imports are separated into two blocks, one for third-party modules,
and one for modules that are part of git-annex. (Additional blocks can be used
if it makes sense.)
Using tabs for indentation makes use of `let .. in` particularly tricky.
There's no really good way to bind multiple names in a let clause with
tab indentation. Instead, a where clause is typically used. To bind a single
name in a let clause, this is sometimes used:
foo = let x = 42
in x + (x-1) + x
(Of course, monadic let binding are no problem.)

View file

@ -33,3 +33,8 @@ The git repository has some branches:
* `setup` contains configuration for this website * `setup` contains configuration for this website
* `pristine-tar` contains [pristine-tar](http://kitenet.net/~joey/code/pristine-tar) * `pristine-tar` contains [pristine-tar](http://kitenet.net/~joey/code/pristine-tar)
data to create tarballs of any past git-annex release. data to create tarballs of any past git-annex release.
----
Developing git-annex? Patches are very welcome.
You should read [[coding_style]].