F#

Misc app setup

Wait for a debugger to be attached and then create a breakpoint

This is especially useful during application startup, giving you time to attach a debugger.

// NB: This assumes a Serilog.ILogger is in scope
if System.Environment.GetEnvironmentVariable "AWAIT_DEBUGGER" = "true" then
logger.Warning "Waiting for debugger to be attached"
while not System.Diagnostics.Debugger.IsAttached do System.Threading.Thread.Sleep 100
System.Diagnostics.Debugger.Break ()

Google Cloud Storage

Count images by creation time

#r "nuget: Google.Cloud.Storage.V1"
fsi.ShowIEnumerable <- false
fsi.ShowProperties <- false
open System
open Google.Apis.Auth.OAuth2
open Google.Cloud.Storage.V1
open System.Text.RegularExpressions
let bucket = "bucket-name"
// gcloud auth application-default login
let creds =
Environment.SpecialFolder.UserProfile
|> Environment.GetFolderPath
|> fun home -> GoogleCredential.FromFile $"{home}/.config/gcloud/application_default_credentials.json"
let client = StorageClient.Create creds
let objects = client.ListObjects bucket
let extensionMatch input = Regex.IsMatch (input, ".jpg|.jpeg|.png|.avif", RegexOptions.Compiled)
let images =
objects
|> Seq.filter (fun obj -> extensionMatch obj.Name)
|> Array.ofSeq
let (|DateAfterOrOn|_|) compare dateTime =
let cutoff = DateTime.ParseExact (compare, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)
if dateTime >= cutoff then Some () else None
images
|> Array.groupBy (fun obj ->
match obj.TimeCreated |> Option.ofNullable with
| Some (DateAfterOrOn "2022-01-01") -> "2022"
| Some (DateAfterOrOn "2021-01-01") -> "2021"
| Some (DateAfterOrOn "2020-01-01") -> "2020"
| Some (DateAfterOrOn "2019-01-01") -> "2019"
| Some (DateAfterOrOn "2018-01-01") -> "2018"
| Some (DateAfterOrOn "2017-01-01") -> "2017"
| Some _ -> "Pre-2018"
| None -> "NoDate"
)
|> Array.iter (fun (group, objects) ->
printfn "%s: %s" group (String.Format("{0:n}", objects.Length))
)