Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(495)

Side by Side Diff: common/dirwalk/tests/tools/gendir/generate.go

Issue 2054763004: luci-go/common/dirwalk: Code for walking a directory tree efficiently Base URL: https://github.com/luci/luci-go@master
Patch Set: Rebase onto master. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package main
6
7 // Tools for generating test directories.
8
9 import (
10 "fmt"
11 "log"
12 "math/rand"
13 "os"
14 "path"
15
16 "github.com/dustin/go-humanize"
17 )
18
19 func min(a uint64, b uint64) uint64 {
20 if a > b {
21 return b
22 }
23 return a
24 }
25 func max(a uint64, b uint64) uint64 {
26 if a < b {
27 return b
28 }
29 return a
30 }
31
32 func randChar(r *rand.Rand, runes []rune) rune {
33 return runes[r.Intn(len(runes))]
34 }
35
36 func randStr(r *rand.Rand, length uint64, runes []rune) string {
37 str := make([]rune, length)
38 for i := range str {
39 str[i] = randChar(r, runes)
40 }
41 return string(str)
42 }
43
44 func randBetween(r *rand.Rand, min uint64, max uint64) uint64 {
45 if min == max {
46 return min
47 }
48 return uint64(r.Int63n(int64(max-min))) + min
49 }
50
51 // FIXME: Maybe some UTF-8 characters?
52 var filenameChars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-")
53
54 func filenameRandom(r *rand.Rand, length uint64) string {
55 return randStr(r, length, filenameChars)
56 }
57
58 type DirGen interface {
59 Create(seed uint64, num int)
60 }
61
62 type FileType int
63
64 const (
65 FILETYPE_BIN_RAND FileType = iota // Truly random binary data (totally uncompressible)
66 FILETYPE_TXT_RAND // Truly random text data (mostly un compressible)
67 FILETYPE_BIN_REPEAT // Repeated binary data (compressibl e)
68 FILETYPE_TXT_REPEAT // Repeated text data (very compress ible)
69 FILETYPE_TXT_LOREM // Lorem Ipsum txt data (very compre ssible)
70
71 FILETYPE_MAX
72 )
73
74 var FileTypeName []string = []string{
75 "Random Binary",
76 "Random Text",
77 "Repeated Binary",
78 "Repeated Text",
79 "Lorem Text",
80 }
81
82 func (f FileType) String() string {
83 return FileTypeName[int(f)]
84 }
85
86 // FIXME: Maybe some UTF-8 characters?
87 var textChars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123 456789-.")
88
89 const (
90 BLOCKSIZE uint64 = 1 * 1024 * 1024 // 1 Megabyte
91
92 // Maximum 4k long repeated sequences
93 SEQUENCE_MINSIZE uint64 = 16
94 SEQUENCE_MAXSIZE uint64 = 4 * 1024
95 )
96
97 func writeFile(r *rand.Rand, filename string, filetype FileType, filesize uint64 ) {
98 f, err := os.Create(filename)
99 if err != nil {
100 log.Fatal(err)
101 }
102 defer f.Close()
103
104 var written uint64 = 0
105 for written < filesize {
106 content := make([]byte, min(filesize-written, BLOCKSIZE))
107
108 // Generate a block of content
109 switch filetype {
110 case FILETYPE_BIN_RAND:
111 r.Read(content)
112
113 case FILETYPE_TXT_RAND:
114 // Runes can be multiple bytes long
115 for i := 0; i < len(content); {
116 bytes := []byte(string(randChar(r, textChars)))
117 for j := range bytes {
118 content[i+j] = bytes[j]
119 }
120 i += len(bytes)
121 }
122
123 case FILETYPE_BIN_REPEAT:
124 var sequence []byte = make([]byte, randBetween(r, SEQUEN CE_MINSIZE, SEQUENCE_MAXSIZE))
125 r.Read(sequence)
126
127 for i := range content {
128 content[i] = sequence[i%len(sequence)]
129 }
130
131 case FILETYPE_TXT_REPEAT, FILETYPE_TXT_LOREM:
132 var sequence []byte
133
134 switch filetype {
135 case FILETYPE_TXT_REPEAT:
136 // FIXME: As runes can be multiple bytes long, t his could technical
137 // be longer then SEQUENCE_MAXSIZE, but don't th ink we care?
138 sequence = []byte(randStr(r, randBetween(r, SEQU ENCE_MINSIZE, SEQUENCE_MAXSIZE), textChars))
139 case FILETYPE_TXT_LOREM:
140 sequence = []byte(lorem)
141 }
142
143 for i := range content {
144 content[i] = sequence[i%len(sequence)]
145 }
146 }
147 f.Write(content)
148 written += uint64(len(content))
149 }
150 }
151
152 const (
153 FILENAME_MINSIZE uint64 = 4
154 FILENAME_MAXSIZE uint64 = 20
155 )
156
157 // Generate num files between (min, max) size
158 func GenerateFiles(r *rand.Rand, dir string, num uint64, filesize_min uint64, fi lesize_max uint64) {
159 for i := uint64(0); i < num; i++ {
160 var filename string
161 var filepath string
162 for true {
163 filename = filenameRandom(r, randBetween(r, FILENAME_MIN SIZE, FILENAME_MAXSIZE))
164 filepath = path.Join(dir, filename)
165 if _, err := os.Stat(filepath); os.IsNotExist(err) {
166 break
167 }
168 }
169 filetype := FileType(r.Intn(int(FILETYPE_MAX)))
170 filesize := randBetween(r, filesize_min, filesize_max)
171
172 if num < 1000 {
173 fmt.Printf("File: %-40s %-20s (%s)\n", filename, filetyp e.String(), humanize.Bytes(filesize))
174 }
175 writeFile(r, filepath, filetype, filesize)
176 }
177 }
178
179 // Generate num directories
180 func GenerateDirs(r *rand.Rand, dir string, num uint64) []string {
181 var result []string
182
183 for i := uint64(0); i < num; i++ {
184 var dirname string
185 var dirpath string
186 for true {
187 dirname = filenameRandom(r, randBetween(r, FILENAME_MINS IZE, FILENAME_MAXSIZE))
188 dirpath = path.Join(dir, dirname)
189 if _, err := os.Stat(dirpath); os.IsNotExist(err) {
190 break
191 }
192 }
193
194 if err := os.MkdirAll(dirpath, 0755); err != nil {
195 log.Fatal(err)
196 }
197 result = append(result, dirpath)
198 }
199 return result
200 }
201
202 type FileSettings struct {
203 MinNumber uint64
204 MaxNumber uint64
205 MinSize uint64
206 MaxSize uint64
207 }
208
209 type DirSettings struct {
210 Number []uint64
211 MinFileDepth uint64
212 }
213
214 type TreeSettings struct {
215 Files []FileSettings
216 Dir DirSettings
217 }
218
219 func generateTreeInternal(r *rand.Rand, dir string, depth uint64, settings *Tree Settings) {
220 fmt.Printf("%04d:%s -->\n", depth, dir)
221 // Generate the files in this directory
222 if depth >= settings.Dir.MinFileDepth {
223 for _, files := range settings.Files {
224 numfiles := randBetween(r, files.MinNumber, files.MaxNum ber)
225 fmt.Printf("%04d:%s: Generating %d files (between %s and %s)\n", depth, dir, numfiles, humanize.Bytes(files.MinSize), humanize.Bytes(fil es.MaxSize))
226 GenerateFiles(r, dir, numfiles, files.MinSize, files.Max Size)
227 }
228 }
229
230 // Generate another depth of directories
231 if depth < uint64(len(settings.Dir.Number)) {
232 numdirs := settings.Dir.Number[depth]
233 fmt.Printf("%04d:%s: Generating %d directories\n", depth, dir, n umdirs)
234 for _, childpath := range GenerateDirs(r, dir, numdirs) {
235 generateTreeInternal(r, childpath, depth+1, settings)
236 }
237 }
238 fmt.Printf("%04d:%s <--\n", depth, dir)
239 }
240
241 func GenerateTree(r *rand.Rand, rootdir string, settings *TreeSettings) {
242 generateTreeInternal(r, rootdir, 0, settings)
243 return
244 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698