Skip to content

Instantly share code, notes, and snippets.

@tallpeak
Last active February 4, 2020 18:27
Show Gist options
  • Save tallpeak/53d729a40181c25380040b5663622320 to your computer and use it in GitHub Desktop.
Save tallpeak/53d729a40181c25380040b5663622320 to your computer and use it in GitHub Desktop.
Compare directories
// compare.fsx
// for each file, get name-only and hash.
// eliminate files with matching hashes
// display differences for files with the same name-only
// display files not found in destination by name-only
// display files not found in source by name-only
let srcDir = @"C:\temp\xxxx_ProductionInitializeDeploymentScripts"
let destDir = @"C:\Users\[myusername]\Source\Repos\[DH-ODP]\Main\Scripts"
open System
open System.IO
open System.Security.Cryptography
// synchronous file hashing
let hashFile f =
use fs = new FileStream(f, FileMode.Open)
use hashFunction = new SHA1Managed()
hashFunction.ComputeHash fs |> Convert.ToBase64String
let rec listFiles dir = seq {
yield! Directory.GetFiles(dir)
for subdir in Directory.GetDirectories(dir) do
yield! listFiles subdir
}
let hashFiles sq = seq {
for f in sq do
yield (hashFile f, (f , IO.DirectoryInfo(f).Name ) )
}
let destFiles = listFiles destDir |> hashFiles |> Map
let srcFiles = listFiles srcDir |> hashFiles |> Map
// buggy
//printfn "Eliminating matching files from destination collection"
// for kv in srcFiles do
// destFiles <- destFiles.Remove kv.Key
// printfn "%s" (snd kv.Value)
// printfn "Eliminating matching files from source collection"
// for kv in destFiles do
// srcFiles <- srcFiles.Remove kv.Key
// printfn "%s" (snd kv.Value)
// let's make this a bit shorter:
// let destFilesUniq = Map.fold (fun mp k v -> Map.remove k mp) destFiles srcFiles
// let srcFilesUniq = Map.fold (fun mp k v -> Map.remove k mp) srcFiles destFiles
// a set-subtraction operator for Map:
let inline (-) (dMap:Map<'k,'v>) (sMap:Map<'k,'v> ) =
Map.fold (fun mp k _ -> Map.remove k mp) dMap sMap
let destFilesUniq = destFiles - srcFiles
let srcFilesUniq = srcFiles - destFiles
printfn "Uniq in source: %d" srcFilesUniq.Count
printfn "Uniq in destination: %d" destFilesUniq.Count
destFilesUniq
|> Seq.map (fun kv -> kv.Value |> fst )
|> Seq.iter (printfn "%s")
// need to move the filename to the key of the tuple. No longer need hashes, since we deleted all filesnames that match by hash:
let srcByFilename =
srcFilesUniq
|> Map.toList
|> List.map (fun (h,(fullname,nm)) -> (nm,fullname))
|> Map
let destByFilename =
destFilesUniq
|> Map.toList
|> List.map (fun (h,(fullname,nm)) -> (nm,fullname))
|> Map
let inSrcOnly = srcByFilename - destByFilename
let inDestOnly = destByFilename - srcByFilename
printfn "\nIn source only (%s):" srcDir
inSrcOnly |> Seq.iter (fun kv-> printfn "%s" kv.Value)
printfn "\nIn destination only (%s):" destDir
inDestOnly |> Seq.iter (fun kv-> printfn "%s" kv.Value)
let differing =
query { for kv in srcByFilename do
where ( Option.isSome(destByFilename.TryFind kv.Key) )
select (kv.Value, (destByFilename.Item kv.Key) )
}
differing |> Seq.length |> printfn "count of differing files: %d"
differing
|> Seq.iter (fun (src,dst) -> printfn "%s\t%s" src dst )
let repl (s:string) = s.Replace("C:\\temp", @"\\[servername]\Shared\Prism\ODP\Projects\CDLZ_30_PRD")
let sb = System.Text.StringBuilder()
differing
|> Seq.iter (fun (src,dst) -> sb.Append (sprintf " \"%s\" \"%s\"\n" (repl src) dst) |> ignore )
printfn "%s" (sb.ToString())
open System.Windows.Forms
Clipboard.SetText(sb.ToString())
let mapValuesToClipboard (mp:Map<string,string>) =
let sb = System.Text.StringBuilder()
mp |> Seq.iter (fun kv -> sb.Append (sprintf "%s\n" kv.Value) |> ignore)
Clipboard.SetText(sb.ToString())
let mapValuesToClipboard2 (mp:Map<string,string>) =
let ar = mp |> Map.toArray |> Array.map snd
let str = String.Join("\n",ar)
Clipboard.SetText(str)
inSrcOnly |> mapValuesToClipboard
inDestOnly |> mapValuesToClipboard
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment