github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/bin/make_test_files.go (about) 1 // +build ignore 2 3 // Build a directory structure with the required number of files in 4 // 5 // Run with go run make_test_files.go [flag] <directory> 6 package main 7 8 import ( 9 cryptrand "crypto/rand" 10 "flag" 11 "io" 12 "log" 13 "math/rand" 14 "os" 15 "path/filepath" 16 ) 17 18 var ( 19 // Flags 20 numberOfFiles = flag.Int("n", 1000, "Number of files to create") 21 averageFilesPerDirectory = flag.Int("files-per-directory", 10, "Average number of files per directory") 22 maxDepth = flag.Int("max-depth", 10, "Maximum depth of directory heirachy") 23 minFileSize = flag.Int64("min-size", 0, "Minimum size of file to create") 24 maxFileSize = flag.Int64("max-size", 100, "Maximum size of files to create") 25 minFileNameLength = flag.Int("min-name-length", 4, "Minimum size of file to create") 26 maxFileNameLength = flag.Int("max-name-length", 12, "Maximum size of files to create") 27 28 directoriesToCreate int 29 totalDirectories int 30 fileNames = map[string]struct{}{} // keep a note of which file name we've used already 31 ) 32 33 // randomString create a random string for test purposes 34 func randomString(n int) string { 35 const ( 36 vowel = "aeiou" 37 consonant = "bcdfghjklmnpqrstvwxyz" 38 digit = "0123456789" 39 ) 40 pattern := []string{consonant, vowel, consonant, vowel, consonant, vowel, consonant, digit} 41 out := make([]byte, n) 42 p := 0 43 for i := range out { 44 source := pattern[p] 45 p = (p + 1) % len(pattern) 46 out[i] = source[rand.Intn(len(source))] 47 } 48 return string(out) 49 } 50 51 // fileName creates a unique random file or directory name 52 func fileName() (name string) { 53 for { 54 length := rand.Intn(*maxFileNameLength-*minFileNameLength) + *minFileNameLength 55 name = randomString(length) 56 if _, found := fileNames[name]; !found { 57 break 58 } 59 } 60 fileNames[name] = struct{}{} 61 return name 62 } 63 64 // dir is a directory in the directory heirachy being built up 65 type dir struct { 66 name string 67 depth int 68 children []*dir 69 parent *dir 70 } 71 72 // Create a random directory heirachy under d 73 func (d *dir) createDirectories() { 74 for totalDirectories < directoriesToCreate { 75 newDir := &dir{ 76 name: fileName(), 77 depth: d.depth + 1, 78 parent: d, 79 } 80 d.children = append(d.children, newDir) 81 totalDirectories++ 82 switch rand.Intn(4) { 83 case 0: 84 if d.depth < *maxDepth { 85 newDir.createDirectories() 86 } 87 case 1: 88 return 89 } 90 } 91 return 92 } 93 94 // list the directory heirachy 95 func (d *dir) list(path string, output []string) []string { 96 dirPath := filepath.Join(path, d.name) 97 output = append(output, dirPath) 98 for _, subDir := range d.children { 99 output = subDir.list(dirPath, output) 100 } 101 return output 102 } 103 104 // writeFile writes a random file at dir/name 105 func writeFile(dir, name string) { 106 err := os.MkdirAll(dir, 0777) 107 if err != nil { 108 log.Fatalf("Failed to make directory %q: %v", dir, err) 109 } 110 path := filepath.Join(dir, name) 111 fd, err := os.Create(path) 112 if err != nil { 113 log.Fatalf("Failed to open file %q: %v", path, err) 114 } 115 size := rand.Int63n(*maxFileSize-*minFileSize) + *minFileSize 116 _, err = io.CopyN(fd, cryptrand.Reader, size) 117 if err != nil { 118 log.Fatalf("Failed to write %v bytes to file %q: %v", size, path, err) 119 } 120 err = fd.Close() 121 if err != nil { 122 log.Fatalf("Failed to close file %q: %v", path, err) 123 } 124 } 125 126 func main() { 127 flag.Parse() 128 args := flag.Args() 129 if len(args) != 1 { 130 log.Fatalf("Require 1 directory argument") 131 } 132 outputDirectory := args[0] 133 log.Printf("Output dir %q", outputDirectory) 134 135 directoriesToCreate = *numberOfFiles / *averageFilesPerDirectory 136 log.Printf("directoriesToCreate %v", directoriesToCreate) 137 root := &dir{name: outputDirectory, depth: 1} 138 for totalDirectories < directoriesToCreate { 139 root.createDirectories() 140 } 141 dirs := root.list("", []string{}) 142 for i := 0; i < *numberOfFiles; i++ { 143 dir := dirs[rand.Intn(len(dirs))] 144 writeFile(dir, fileName()) 145 } 146 }