Last active
September 30, 2015 22:09
-
-
Save Kimserey/7c0790b9ff27575949df to your computer and use it in GitHub Desktop.
Sqlite backup script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@echo off | |
cls | |
C:\"Program Files (x86)"\"Microsoft SDKs"\F#\4.0\Framework\v4.0\Fsi.exe .\script.fsx %1 %2 %3 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Backup script | |
// Generate backup for Sqlite dbs | |
// | |
// Arguments [ 1:db path; 2:base output path; 3:instance name ] | |
// | |
open System | |
open System.Text | |
open System.IO | |
open System.Text.RegularExpressions | |
open System.Diagnostics | |
open System.Globalization | |
type BackupResult = | |
| BackupSuccess of TimeSpan | |
| BackupFailure of string * exn * TimeSpan | |
| BackupTimeout of TimeSpan | |
type ClearExpiredBackupResult = | |
| ExpiredBackupCleaningSuccess of string | |
| ExpiredBackupCleaningFailure of string * exn | |
| ExpiredBackupCleaningNotNeeded of string | |
type FileDb = { | |
name: string | |
path: string | |
} | |
let regexMath pattern input = Regex.IsMatch(input, pattern) | |
let masterdataRegexPattern = "masterdata.(\d+|\^).db" | |
let generateBackup dbPath bakupPath db = | |
let timer = Stopwatch.StartNew () | |
try | |
let psi = | |
new ProcessStartInfo( | |
"sqlite3", | |
sprintf """%s/%s ".timeout 20000" ".backup %s/%s""" dbPath db bakupPath db, | |
CreateNoWindow = false, ErrorDialog = false, LoadUserProfile = false, | |
UseShellExecute = false, WindowStyle = ProcessWindowStyle.Normal, | |
RedirectStandardInput = true, | |
RedirectStandardOutput = true, | |
RedirectStandardError = true (* set this to false to allow printing of verbose messages *)) | |
let proc = Process.Start psi | |
match proc.WaitForExit (TimeSpan.FromSeconds(20.).TotalMilliseconds |> int) with | |
| true when proc.ExitCode = 0 -> BackupSuccess timer.Elapsed | |
| true -> BackupFailure ("Exited with error code " + string proc.ExitCode, null, timer.Elapsed) | |
| false -> BackupTimeout timer.Elapsed | |
with | |
| ex -> BackupFailure ("Unexpected failure with " + ex.Message, ex, timer.Elapsed) | |
let deleteExpiredBackups basePath (date: DateTime) = | |
printfn "\nStart clearing expired backup:\n-------------------" | |
Directory.GetDirectories(basePath) | |
|> Seq.map (fun x -> | |
try | |
let backupDate = DateTime.Parse(x.Split([|'\\'; '/'|]) |> Seq.last, CultureInfo.InvariantCulture) | |
if backupDate < date.AddDays(-7.) then | |
Directory.Delete(x, true) | |
ExpiredBackupCleaningSuccess ("Success clearing: " + x) | |
else ExpiredBackupCleaningNotNeeded ("Not expired: " + x) | |
with | |
| ex -> ExpiredBackupCleaningFailure ("Failed to clear: " + x + " - " + ex.Message, ex)) | |
|> Seq.iter (function | |
| ExpiredBackupCleaningSuccess message -> printfn "%s" message | |
| ExpiredBackupCleaningFailure (message, ex) -> printfn "%s" message | |
| ExpiredBackupCleaningNotNeeded message -> printfn "%s" message) | |
basePath, date | |
let getBackupFolder instanceName (basePath: string, date: DateTime) = | |
let fullPath = basePath.Replace("\\", "/").TrimEnd('/') + "/" + date.ToString("yyyy-MM-dd") + "/" + instanceName | |
Directory.CreateDirectory(fullPath) |> ignore //create directory if does not exists | |
fullPath | |
let generateBackups dbPath backupFolder = | |
printfn "\nStart generating backups:\n-------------------" | |
Directory.GetFiles dbPath | |
|> Seq.map (fun x -> { path = x.Split([|'\\'; '/'|]) |> Seq.rev |> Seq.skip(1) |> Seq.rev |> String.concat "/" | |
name = x.Split([|'\\'; '/'|]) |> Seq.last }) | |
|> Seq.filter (fun x -> regexMath masterdataRegexPattern x.name |> not) | |
|> Seq.map (fun f -> | |
printfn "Generating backup for %s/%s" backupFolder f.name | |
generateBackup f.path backupFolder f.name) | |
|> Seq.iter (fun r -> match r with | |
| BackupSuccess i -> printfn "Sucess %f sec" i.TotalSeconds | |
| BackupFailure (message, ex, i) -> printfn "%s %f sec" message i.TotalSeconds | |
| BackupTimeout i -> printfn "Timeout after %f sec" i.TotalSeconds) | |
//Main function | |
match fsi.CommandLineArgs with | |
| [| script; dbPath; outputPath; instanceName |] -> | |
//delete expired backups - create backup folder - generates backups | |
DateTime.Now | |
|> deleteExpiredBackups outputPath | |
|> getBackupFolder instanceName | |
|> generateBackups dbPath | |
printfn "------\nDone" | |
| _ -> failwith "Arguments missing please specify 1:dbpath 2:outputpath 3:instanceName" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment