filediff 0.1.0.4 → 0.1.0.5
raw patch · 5 files changed
+124/−12 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Tests/test-filediff.hs +67/−0
- filediff.cabal +1/−1
- src/Filediff.hs +17/−7
- src/Filediff/Types.hs +0/−1
- src/Filediff/Utils.hs +39/−3
Tests/test-filediff.hs view
@@ -531,6 +531,65 @@ directoriesEqual <- areDirectoriesEqual "a" "b" (@?) directoriesEqual "Directories not equal after application" +-- assorted++setUpRelativePathTest :: IO ()+setUpRelativePathTest = do+ D.createDirectory "a"+ D.createDirectory "_"+ D.createDirectory "_/b"++ D.setCurrentDirectory "a"+ createFileWithContents "a" "a" + D.setCurrentDirectory ".."++ D.setCurrentDirectory "_/b"+ createFileWithContents "a" "b"+ D.setCurrentDirectory "../.."++relativePathExpectedDiff :: F.Diff+relativePathExpectedDiff = F.Diff {+ F.filediffs =+ [ F.Filediff+ { F.base = "a"+ , F.comp = "a"+ , F.change = F.Mod $ SeqDiff [0] [(0, T.pack "b")] } ]+ }++testRelativePathness :: Assertion+testRelativePathness = do+ setUpRelativePathTest++ let expectedDiff = relativePathExpectedDiff+ actualDiff <- F.diffDirectories "a" "_/b"+ actualDiff @?= expectedDiff++testRelativePathnessEdgeCases :: Assertion+testRelativePathnessEdgeCases = do+ setUpRelativePathTest+ test "a" "_/b"+ test "a/" "_/b"+ test "a" "_/b/"+ test "a/" "_/b/"+ test "./a" "_/b"+ test "./a/" "_/b"+ test "./a" "_/b/"+ test "./a/" "_/b/"+ test "a" "./_/b"+ test "a/" "./_/b"+ test "a" "./_/b/"+ test "a/" "./_/b/"+ test "./a" "./_/b"+ test "./a/" "./_/b"+ test "./a" "./_/b/"+ test "./a/" "./_/b/"+ test "./a/" "./_/b/"+ where+ test :: FilePath -> FilePath -> Assertion+ test a b = do+ actualDiff <- F.diffDirectories a b+ actualDiff @?= relativePathExpectedDiff+ -- tests tests :: TestTree@@ -636,6 +695,14 @@ , testCase "Testing directory diffing composition" (runTest testDirectoryDiffComposition)++ -- assorted+ , testCase+ "Testing that paths are relative"+ (runTest testRelativePathness)+ , testCase+ "Testing that paths are relative (edge cases)"+ (runTest testRelativePathnessEdgeCases) ] main :: IO ()
filediff.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: filediff-version: 0.1.0.4+version: 0.1.0.5 synopsis: Diffing and patching module description: `filediff` is a Haskell library for creating diffs, and applying diffs to files and directories. homepage: https://github.com/bgwines/filediff
src/Filediff.hs view
@@ -41,8 +41,12 @@ , createFileWithContents , dropUntil , removeFirstPathComponent+ , removePathComponents , getDirectoryContentsRecursiveSafe- , isPrefix)+ , isPrefix+ , dropPrefix+ , dropInitialSlash+ , dropTrailingSlash ) -- * basic operations @@ -106,7 +110,7 @@ -- `[FilePath]` parameter refers to the first `FilePath` parameter, -- and same for the second, respectively. diffDirectoriesWithIgnoredSubdirs :: FilePath -> FilePath -> [FilePath] -> [FilePath] -> IO Diff-diffDirectoriesWithIgnoredSubdirs a b aToIgnore bToIgnore = do+diffDirectoriesWithIgnoredSubdirs a' b' aToIgnore bToIgnore = do aIsFile <- D.doesFileExist a bIsFile <- D.doesFileExist b when (aIsFile || bIsFile) $ error $ "One or both of " ++ a ++ " and " ++ b ++ "is not a directory, but a file."@@ -122,10 +126,16 @@ bOnlyDiffs <- getDiffs $ bContents \\ aContents - let allDiffs = map removeFirstPathComponentFromDiff $ intersectionDiffs ++ aOnlyDiffs ++ bOnlyDiffs+ let allDiffs = map makeRelative $ intersectionDiffs ++ aOnlyDiffs ++ bOnlyDiffs return $ Diff allDiffs where+ a :: FilePath+ a = dropTrailingSlash a'++ b :: FilePath+ b = dropTrailingSlash b'+ -- | `x` is the prefix of the "base" of the diff; `y` is the -- | "compare". getDiffs :: [FilePath] -> IO [Filediff]@@ -136,11 +146,11 @@ isIdentityFileDiff :: Filediff -> Bool isIdentityFileDiff = (==) mempty . change - removeFirstPathComponentFromDiff :: Filediff -> Filediff- removeFirstPathComponentFromDiff (Filediff base comp change) =+ makeRelative :: Filediff -> Filediff+ makeRelative (Filediff base comp change) = Filediff- (removeFirstPathComponent base)- (removeFirstPathComponent comp)+ (dropInitialSlash $ dropPrefix a base)+ (dropInitialSlash $ dropPrefix b comp) change shouldIgnore :: [FilePath] -> FilePath -> Bool
src/Filediff/Types.hs view
@@ -38,7 +38,6 @@ } deriving (Eq, Show, Generic) -- | The types and sets of changes possible between two files.--- `CompositionAddDel` is hack to make `mappend` work properly :/ data FileChange = Del (SeqDiff Line) | Mod (SeqDiff Line)
src/Filediff/Utils.hs view
@@ -9,11 +9,17 @@ , removeDotDirs , createFileWithContents , removeFirstPathComponent+, removePathComponents , getDirectoryContentsRecursiveSafe --- * list operations+ -- * file path formatting+, dropInitialSlash+, dropTrailingSlash++ -- * list operations , dropUntil , isPrefix+, dropPrefix ) where import Data.List ((\\), inits)@@ -85,6 +91,16 @@ then error "path without '/' in it" else tail . dropUntil ((==) '/') $ path +-- | Removes the k oldest ancestors from a path component, e.g.+-- |+-- | > removePathComponents 2 "a/b/c"+-- | "c"+removePathComponents :: Int -> FilePath -> FilePath+removePathComponents k+ = last+ . take k+ . iterate removeFirstPathComponent+ -- | Gets paths to all files in or in subdirectories of the -- | specified directory. Returned paths are relative to the -- | given directory.@@ -96,9 +112,8 @@ then directory else directory </> "" let numPathComponents = length . filter ((==) '/') $ directoryWithTrailingSlash- let removePathComponents = last . take (numPathComponents + 1) . iterate removeFirstPathComponent - return . map removePathComponents $ contents+ return . map (removePathComponents $ numPathComponents + 1) $ contents getDirectoryContentsRecursiveSafe' :: FilePath -> IO [FilePath] getDirectoryContentsRecursiveSafe' directory = do@@ -116,6 +131,20 @@ return $ files ++ recFiles +-- * file path formatting++-- | If the parameter has a '/' as its first character, drop it.+dropInitialSlash :: String -> String+dropInitialSlash ('/':s) = s+dropInitialSlash s = s++-- | If the parameter has a '/' as its last character, drop it.+dropTrailingSlash :: String -> String+dropTrailingSlash [] = []+dropTrailingSlash s = if last s == '/'+ then init s+ else s+ -- * list operations -- | Drops elements from the given list until the predicate function@@ -130,3 +159,10 @@ -- | (intended to be used infix) isPrefix :: (Eq a) => [a] -> [a] -> Bool a `isPrefix` b = (==) (length a) . length . takeWhile id $ zipWith (==) a b++-- | assumes `a` is a prefix of `b`; errors if false+dropPrefix :: (Eq a) => [a] -> [a] -> [a]+dropPrefix [] bs = bs+dropPrefix (a:as) (b:bs)+ | a /= b = error "not a prefix"+ | otherwise = dropPrefix as bs