Start of Python code to generate likely-looking pseudo random file
[rsync.git] / testhelp / maketree.py
1 #! /usr/bin/python2.2
2
3 # Copyright (C) 2002 by Martin Pool <mbp@samba.org>
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version
7 # 2 as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program; if not, write to the Free Software
16 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 # Populate a tree with pseudo-randomly distributed files to test
19 # rsync.
20
21 from __future__ import generators
22 import random, string, os, os.path
23
24 nfiles = 10000
25 depth = 5
26 n_children = 20
27 n_files = 20
28 n_symlinks = 10
29
30 name_chars = string.digits + string.letters
31
32 abuffer = 'a' * 1024
33
34 def random_name_chars():
35     a = ""
36     for i in range(10):
37         a = a + random.choice(name_chars)
38     return a
39
40     
41 def generate_names():
42     n = 0
43     while 1:
44         yield "%05d_%s" % (n, random_name_chars())
45         n += 1
46
47
48 class TreeBuilder:
49     def __init__(self):
50         self.n_children = 20
51         self.n_files = 100
52         self.total_entries = 100000 # long(1e8)
53         self.actual_size = 0
54         self.name_gen = generate_names()
55         self.all_files = []
56         self.all_dirs = []
57         self.all_symlinks = []
58
59
60     def random_size(self):
61         return random.lognormvariate(4, 4)
62
63
64     def random_symlink_target(self):
65         what = random.choice(['directory', 'file', 'symlink', 'none'])
66         try:
67             if what == 'directory':
68                 return random.choice(self.all_dirs)
69             elif what == 'file':
70                 return random.choice(self.all_files)
71             elif what == 'symlink':
72                 return random.choice(self.all_symlinks)
73             elif what == 'none':
74                 return self.name_gen.next()
75         except IndexError:
76             return self.name_gen.next()
77
78
79     def can_continue(self):
80         self.total_entries -= 1
81         return self.total_entries > 0
82
83         
84     def build_tree(self, prefix, depth):
85         """Generate a breadth-first tree"""
86         for count, function in [[n_files, self.make_file],
87                                 [n_children, self.make_child_recurse],
88                                 [n_symlinks, self.make_symlink]]:
89             for i in range(count):
90                 if not self.can_continue():
91                     return
92                 name = os.path.join(prefix, self.name_gen.next())
93                 function(name, depth)
94
95
96     def print_summary(self):
97         print "total bytes: %d" % self.actual_size
98
99
100     def make_child_recurse(self, dname, depth):
101         if depth > 1:
102             self.make_dir(dname)
103             self.build_tree(dname, depth-1)
104
105
106     def make_dir(self, dname, depth='ignore'):
107         print "%s/" % (dname)
108         os.mkdir(dname)
109         self.all_dirs.append(dname)
110
111
112     def make_symlink(self, lname, depth='ignore'):
113         print "%s -> %s" % (lname, self.random_symlink_target())
114
115
116     def make_file(self, fname, depth='ignore'):
117         size = long(self.random_size())
118         print "%-70s %d" % (fname, size)
119         f = open(fname, 'w')
120         f.truncate(size)
121         self.fill_file(f, size)
122         self.all_files.append(fname)
123         self.actual_size += size
124
125     def fill_file(self, f, size):
126         while size > 0:
127             f.write(abuffer[:size])
128             size -= len(abuffer)
129
130     
131 tb = TreeBuilder()
132 tb.build_tree('/tmp/foo', 3)
133 tb.print_summary()