Makefile: add pickrand
[cmccabe-bin] / pickrand.go
index a21efda..e51bf26 100644 (file)
@@ -1,23 +1,44 @@
 package main
 
 import (
+       "bytes"
+       "crypto/rand"
+    "flag"
        "fmt"
+       "math/big"
        "os"
        "path/filepath"
-       "math/rand"
        "time"
 )
 
 func main() {
-       root := "."
-       if len(os.Args) > 1 {
-               root = os.Args[1]
-       }
+    flag.Usage = func() {
+        fmt.Fprintf(os.Stdout, "pickrand.go: picks a random file.\n")
+        fmt.Fprintf(os.Stdout, "\n")
+        flag.PrintDefaults()
+    }
+    prevDays := flag.Int("n", 0, "The number of days back to look.")
+    flag.Parse()
+    var maxDuration time.Duration
+    if (*prevDays != 0) {
+        maxDuration = time.Duration(int64(*prevDays) * (24 * 60 * 60 * 1e9))
+    }
+    
+       root := flag.Arg(0)
+    if (root == "") {
+        root = "."
+    }
        files := make([]string, 0, 32)
        err := filepath.Walk(root, func(p string, f os.FileInfo, err error) error {
                if err != nil {
                        return err
                }
+        if maxDuration != 0 {
+            var duration = time.Now().Sub(f.ModTime())
+            if duration > maxDuration {
+                return nil
+            }
+        }
                if !f.IsDir() {
                        files = append(files, p)
                }
@@ -27,7 +48,23 @@ func main() {
                fmt.Fprintf(os.Stderr, "** Error: %s\n", err.Error())
                os.Exit(1)
        }
-       rand.Seed(time.Now().UTC().UnixNano())
-       i := rand.Int31n(int32(len(files)))
-       fmt.Printf("%s\n", root + "/" + files[i])
+    if len(files) == 0 {
+               fmt.Fprintf(os.Stderr, "No matching files found.\n")
+               os.Exit(1)
+    }
+       var b [16]byte
+       _, err = rand.Read(b[:])
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Failed to access cryptographic randomness.  " +
+                       "Error: %s\n\n", err.Error())
+               os.Exit(1)
+       }
+       i, err := rand.Int(bytes.NewReader(b[:]), big.NewInt(int64(len(files))))
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Failed to get a random int.  Error: %s\n", err.Error())
+               os.Exit(1)
+       }
+       j := int(i.Uint64())
+
+       fmt.Printf("%s\n", files[j])
 }