Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 663 lines (589 sloc) 22.534 kB
#!/usr/bin/perl
# FIXME: authenticated commenters aren't created
use strict;
use warnings;
use lib 'extlib', 'lib';
use Data::Dumper;
use Getopt::Long;
use MT;
use MT::Author;
use MT::Permission;
my $mt = MT->new() or die "No MT object " . MT->errstr();
my $blogs = 1;
my $destroy = 0;
my $authors = 3;
my $entries = 500;
my $cats = 5;
# this can be used to scale the default amount of data generated
my $weight_factor = 1;
my $bypass_confirm = 0;
my $help = 0;
my $silent = 0;
my $years = 1;
my $result = GetOptions("authors=i" => \$authors,
"blogs=i" => \$blogs,
"categories=i" => \$cats,
"entries=i" => \$entries,
"weight=i" => \$weight_factor,
"destroy" => \$destroy,
"yes-really" => \$bypass_confirm,
"help|?" => \$help,
"silent" => \$silent,
"years=i" => \$years,
);
if ($help) {
eval { require Pod::Usage };
die "No Pod::Usage available. Use the Source, Luke." if $@;
Pod::Usage::pod2usage(-exitstatus => 1);
}
use vars qw($this_blog $this_iter $this_obj $this_parent $tmpl_list);
# define objects and such...
use constant RAND_BOOL => [ 0, 1 ];
my @word_pool = qw(
cool tech blogging politics interesting video
perl python ruby web2.0 sixapart reference link audio
php javascript voip news
);
# Randomize the random number generator to make things nice and consistent.
srand(1);
# these are all the numbers that control how many of what are generated
my $blog_count = sub { $blogs * $weight_factor };
my $authors_per_blog = sub { $authors * $weight_factor };
my $categories_per_blog = sub { $cats + int(rand(10)) * $weight_factor };
my $entries_per_blog = sub { $entries + int(rand(30)) * $weight_factor };
my $notifications_per_blog = sub { 3 + int(rand(20)) };
my $bans_per_blog = sub { 2 + int(rand(10)) };
my $comments_per_entry = sub { int(rand(10)) * $weight_factor };
my $tags_per_entry = sub { int(rand(5)) * $weight_factor };
my $pings_per_trackback = sub { int(rand(10)) * $weight_factor };
my %defs = (
'MT::Blog' => {
table => 'blog',
as_of => 1.0,
needs => [
'MT::Author' => $authors_per_blog,
'MT::Category' => $categories_per_blog,
'MT::Entry' => $entries_per_blog,
'MT::Template' => \&template_loader,
'MT::Notification' => $notifications_per_blog,
'MT::IPBanList' => $bans_per_blog,
],
fields => [
field('name', \&random_blog_name),
field('description', sub { random_paragraph(int(rand(1))) } ),
field('archive_type', [ 'Individual,Category,Monthly',
'Individual,Monthly', 'Daily,Category,Monthly' ]),
field('archive_type_preferred', sub {
my @at = split /,/, $this_obj->archive_type;
$at[int(rand(scalar @at))]
} ),
field('site_path', sub { "/www/blog_$this_iter" } ),
field('archive_path', sub { $this_obj->site_path . '/archives' }),
field('site_url', sub { "http://www.blog${this_iter}.com/" } ),
field('archive_url', sub { $this_obj->site_url . 'archives/' }),
field('days_on_index', [ 7, 10, 14 ]),
field('entries_on_index', [ 10, 15, 20 ], 3.2),
field('file_extension', [ '', '', 'html', 'asp', 'jsp', 'php' ] ),
field('email_new_comments', RAND_BOOL),
field('allow_comment_html', RAND_BOOL),
field('autolink_urls', RAND_BOOL),
field('server_offset', [ -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 ]),
field('ping_blogs', RAND_BOOL, 2.5),
field('ping_others', RAND_BOOL, 2.5),
field('autodiscover_links', RAND_BOOL, 2.5),
field('convert_paras', RAND_BOOL),
field('convert_paras_comments', RAND_BOOL),
field('sanitize_spec', [ 'a href,br/,p', '' ], 2.6),
field('cc_license', sub {
if (MT->version_number < 3.16) {
[ '', 'by-nc-sa', 'nd', 'by', 'pd', 'sa',
'by-nd-nc', 'by-nc' ];
} else {
[ '', '' ], # FIXME: URLs for new cc licenses
}
}, 2.6),
field('is_dynamic', 0, 2.6),
field('require_comment_emails', RAND_BOOL, 3.0),
field('allow_unreg_comments', RAND_BOOL, 3.0),
field('allow_reg_comments', RAND_BOOL, 3.0),
field('manual_approve_commenters', RAND_BOOL, 3.0),
field('old_style_archive_links', RAND_BOOL, 3.0),
field('moderate_unreg_comments', RAND_BOOL, 3.0),
field('remote_auth_token', [ '', 'some_remote_token' ], 3.0),
field('ping_technorati', RAND_BOOL, 3.1),
field('children_modified_on', undef, 3.1),
field('custom_dynamic_templates',
[ 'none', 'archives', 'custom' ], 3.1),
],
},
'MT::Entry' => {
table => 'entry',
as_of => 1.0,
needs => [
'MT::Comment' => sub { $this_obj->allow_comments ? $comments_per_entry->() : 0 },
'MT::Trackback' => sub { $this_obj->allow_pings ? 1 : 0 },
#'MT::Placement' => [ 0, 1, 1, 1, 2 ],
],
fields => [
field('blog_id', sub { $this_blog->id } ),
field('author_id', \&random_author),
field('title', \&random_title),
field('text', sub { random_paragraph(2+int(rand(3)))} ),
field('text_more', sub { random_paragraph(int(rand(10))) } ),
field('excerpt', ''),
field('status', [ 1, 2, 2, 2, 2, 4 ]),
field('keywords', '', 2.5),
field('tangent_cache', '', 2.5),
field('allow_pings', [ 0, 1 ]),
field('allow_comments', [ 0, 1, 1, 1 ]),
field('convert_breaks', sub {
MT->version_number < 2.6 ? [ 0, 1 ] : [ '__default__', '0' ]
}),
field('created_on', \&random_date, 1.0 ),
field('basename', undef, 3.0), # auto-set upon save
field('tags', \&assign_random_tags, 3.3 ),
field('categories', \&assign_random_categories, 1.0 ),
],
},
'MT::Author' => {
table => 'author',
as_of => 1.0,
needs => [
'MT::Permission' => \&permission_check,
],
fields => [
field('name', \&random_username),
field('nickname', \&random_name),
field('email', \&random_email),
field('url', \&random_url),
field('type', sub { ref $this_parent eq 'MT::Comment' ? 2 : 1 }, 3.0),
field('password', sub { $this_obj->type == 1 ? crypt('Nelson', 'xx') : '' }),
field('preferred_language', sub { $this_obj->type == 1 ? ($this_obj->name eq 'Melody' ? 'en_US' : [ 'en_US', 'en_US', 'en-us', 'fr', 'de' ]) : undef }, 2.5),
field('can_create_blog', sub { $this_obj->type == 1 ? RAND_BOOL : undef }),
field('is_superuser', sub { $this_obj->type == 1 && $this_iter == 1 ? 1 : undef }, 3.2),
field('can_view_log', sub { $this_obj->type == 1 ? RAND_BOOL : undef }),
field('hint', sub { $this_obj->type == 1 ? 'hint' : undef } ),
field('public_key', undef),
field('api_password', sub { $this_obj->type == 1 ? 'Nelson' : undef }, 3.2),
field('remote_auth_username', undef, 3.0),
field('remote_auth_token', undef, 3.0),
],
},
'MT::Category' => {
table => 'category',
as_of => 1.0,
needs => [
'MT::Trackback' => [ 0, 0, 0, 0, 0, 1 ],
],
fields => [
field('blog_id', sub { $this_blog->id }),
field('label', \&random_category),
field('author_id', ),
field('description', sub { random_paragraph(int(rand(1))) }),
field('allow_pings', [ 0, 0, 0, 0, 1 ], 1.0), # FIXME: version #
field('parent', [ 0, 0, 0, \&random_category_id ], 3.1),
],
},
'MT::Permission' => {
table => 'permission',
as_of => 1.0,
fields => [
field('author_id', sub { $this_parent->id } ),
field('blog_id', sub { $this_blog->id } ),
field('permissions', sub { $this_parent->type == 1 ? ($this_iter == 1 ? 14334 : &random_role ) : [ 0, 1 ] } ),
field('entry_prefs', undef),
],
},
'MT::Comment' => {
table => 'comment',
as_of => 1.0,
needs => [
'MT::Author' => [ 0, 0, 0, 0, 1 ],
],
fields => [
field('blog_id', sub { $this_parent->blog_id }),
field('entry_id', sub { $this_parent->id }),
field('author', \&random_name),
field('commenter_id', \&random_commenter, 3.0),
field('email', \&random_email),
field('url', \&random_url),
field('text', sub { random_paragraph(1+int(rand(2))) } ),
field('ip', \&random_ip),
field('visible', [ 0, 1, 1, 1, 1 ], 3.0),
field('junk_status', [ -1, 1, 1, 1, 1 ], 3.2),
field('junk_score', sub { $this_obj->junk_status == -1 ? rand(2) * -1 : 0 }, 3.2),
field('junk_log', sub { $this_obj->junk_status == -1 ? 'Random (' . $this_obj->junk_score . "): Randomly scored as junk\n" : '' }, 3.2),
],
},
'MT::Trackback' => {
table => 'trackback',
as_of => 1.2, # ??
needs => [
'MT::TBPing' => $pings_per_trackback,
],
fields => [
field('blog_id', sub { $this_parent->blog_id }),
field('title', \&random_title),
field('description', undef),
field('rss_file', undef),
field('url', undef),
field('entry_id', sub { ref $this_parent eq 'MT::Entry' ? $this_parent->id : 0 }),
field('category_id', sub { ref $this_parent eq 'MT::Category' ? $this_parent->id : 0 }),
field('is_disabled', 0),
field('passphrase', undef),
],
},
'MT::TBPing' => {
table => 'tbping',
as_of => 1.2, # ??
fields => [
field('blog_id', sub { $this_parent->blog_id }),
field('tb_id', sub { $this_parent->id }),
field('title', \&random_title),
field('excerpt', \&random_paragraph ),
field('source_url', \&random_url),
field('ip', \&random_ip),
field('blog_name', \&random_blog_name),
field('visible', [ 0, 1, 1, 1, 1 ], 3.0),
field('junk_status', [ -1, 1, 1, 1, 1 ], 3.2),
field('junk_score', sub { $this_obj->junk_status == -1 ? rand(2) * -1 : 0 }, 3.2),
field('junk_log', sub { $this_obj->junk_status == -1 ? 'Random (' . $this_obj->junk_score . "): Randomly scored as junk\n" : '' }, 3.2),
],
},
'MT::Template' => {
table => 'template',
as_of => 1.0,
# fields => [
# field('build_dynamic', [], 3.1),
# ],
},
'MT::TemplateMap' => {
table => 'templatemap',
as_of => 2.0,
},
'MT::IPBanList' => {
table => 'ipbanlist',
as_of => 1.4, # ??
fields => [
field('blog_id', sub { $this_parent->id } ),
field('ip', \&random_ip),
],
},
'MT::Log' => {
table => 'log',
as_of => 1.0,
# fields => [
# field('blog_id', [], 3.2),
# ],
},
'MT::Session' => {
table => 'session',
as_of => 3.0,
},
'MT::Notification' => {
table => 'notification',
as_of => 1.0,
fields => [
field('blog_id', sub { $this_parent->id } ),
field('name', \&random_name),
field('email', \&random_email),
field('url', \&random_url),
],
},
'MT::Placement' => {
table => 'placement',
as_of => 2.0,
},
'MT::FileInfo' => {
table => 'fileinfo',
as_of => 3.1,
},
'MT::PluginData' => {
table => 'plugindata',
as_of => 2.6,
},
'MT::Tag' => {
table => 'tag',
as_of => 3.3,
},
'MT::ObjectTag' => {
table => 'objecttag',
as_of => 3.3,
},
# 'MT::Config' => {
# table => 'config',
# as_of => 3.2,
# },
);
if ($destroy) {
unless ($bypass_confirm) {
print <<'WARNING';
** WARNING **
You've chosen to clear all existing data in your database and populate
it with random, generated data. The system administrator login will be
Melody/Nelson. This tool is mainly used for testing MT performance and
usability with varying sizes of data.
To continue, type OK and press enter.
WARNING
my $confirm = <STDIN>;
chomp $confirm;
exit unless $confirm eq 'OK';
}
clean();
}
# kick off the build process
build( 'MT::Blog', $blog_count->(), 0);
sub field {
my ($name, $inputs, $as_of) = @_;
my $def = { inputs => $inputs };
$def->{as_of} = $as_of if defined $as_of;
( $name, $def );
}
sub clean {
# CLEAR ANY EXISTING DATA
print "Clearing existing data...\n" unless $silent;
my $driver = MT::Object->driver();
if (my $dbh = $driver->rw_handle) {
my @tables = map { $defs{$_}{table} } keys %defs;
foreach (@tables) {
print "\tWiping $_\n" unless $silent;
$dbh->do("delete from mt_$_");
}
if ($driver->isa('MT::ObjectDriver::Driver::DBD::Pg')) {
# reset sequences
$dbh->do("drop sequence mt_${_}_id") foreach @tables;
$dbh->do("create sequence mt_${_}_id") foreach @tables;
}
}
}
sub build {
my ($pkg, $num, $depth) = @_;
my $def = $defs{$pkg};
return unless $def->{as_of} <= MT->version_number();
print(("\t" x $depth) . "Creating $num $pkg objects...\n") unless $silent;
local $this_obj = $this_obj;
local $this_parent = $this_obj;
local $this_iter;
for (my $i = 0; $i < $num; $i++) {
$this_iter = $i + 1; # always indexed from 1...
my $obj;
# special case for MT::Author...
if ($pkg eq 'MT::Author') {
my $name = random_username();
my $user = MT::Author->load({name => $name, type => 1});
if ($user) {
$obj = $user;
}
}
unless ($obj) {
no strict 'refs';
no warnings;
eval("require $pkg") unless defined *{"$pkg::"};
$obj = $pkg->new();
}
$this_obj = $obj;
if (!$obj->id) {
my @fields = @{$def->{fields}};
while (my ($fld, $fld_def) = (shift @fields, shift @fields)) {
if ((!exists $fld_def->{as_of}) || ($fld_def->{as_of} && ($fld_def->{as_of} <= $MT::VERSION))) {
my $input = $fld_def->{inputs};
while (ref $input) {
if (ref $input eq 'ARRAY') {
$input = $input->[int(rand(scalar @$input))];
}
if (ref $input eq 'CODE') {
$input = $input->();
}
}
print "\tsetting $fld to [$input]\n" if !$silent && defined $input;
$obj->$fld($input) if defined $input;
}
last unless @fields;
}
$obj->save or die $obj->errstr;
}
if ($pkg eq 'MT::Blog') {
$this_blog = $obj; # assign for use in other objects...
}
# process needs...
if (my $needs = $def->{needs}) {
my @needs = @$needs;
while (my ($pkg, $num) = (shift @needs, shift @needs)) {
while (ref $num) {
if (ref $num eq 'ARRAY') {
$num = $num->[int(rand(scalar @$num))];
}
if (ref $num eq 'CODE') {
$num = $num->();
}
}
if ($num) {
build($pkg, $num, $depth+1);
}
last unless @needs;
}
}
}
}
sub permission_check {
my $author = $this_obj;
my $blog = $this_blog;
require MT::Permission;
my $num = MT::Permission->count({ author_id => $author->id,
blog_id => $blog->id });
$num ? 0 : 1;
}
sub template_loader {
my $blog = $this_blog;
print "\tCreating templates...\n" unless $silent;
$blog->create_default_templates();
0;
}
## some random routines
sub random_name {
$this_iter == 1 ? 'Melody Nelson' : 'Joe ' . $this_iter;
}
sub random_email {
"user" . $this_iter . '@gmail.com';
}
sub random_paragraph {
my $num = shift;
$num ||= 1 unless defined $num;
("Lorem ipsum blah blah blah.\n\n" x $num) || '';
}
sub random_username {
$this_iter == 1 ? 'Melody' : 'user' . $this_iter;
}
sub random_blog_name {
'Weblog ' . $this_iter;
}
sub random_category_id {
}
sub random_category {
'Category ' . $this_iter;
}
sub random_title {
'Title for ' . (ref $this_obj) . ' #' . $this_iter;
}
sub random_commenter {
my @c = MT::Author->load({ type => 2 });
return unless @c;
my $c = $c[int(rand(scalar @c))];
$c->id;
}
sub random_author {
my @a = MT::Author->load({ type => 1 });
my $a = $a[int(rand(scalar @a))];
$a->id;
}
sub random_role {
# [ 1, 'comment', 'Post Comments', ],
# [ 4096, 'administer_blog', 'Blog Administrator'],
# [ 2, 'post', 'Post', ],
# [ 4, 'upload', 'Upload File', ],
# [ 8, 'edit_all_posts', 'Edit All Posts', ],
# [ 16, 'edit_templates', 'Manage Templates', ],
## [ 32, 'edit_authors', 'Edit Authors & Permissions', ],
# [ 64, 'edit_config', 'Configure Weblog', ],
# [ 128, 'rebuild', 'Rebuild Files', ],
# [ 256, 'send_notifications', 'Send Notifications', ],
# [ 512, 'edit_categories', 'Manage Categories', ],
# [ 1024, 'edit_notifications', 'Manage Notification List' ],
# [ 2048, 'not_comment', ''], # not a real permission but a denial thereeof
# [ 8192, 'view_blog_log', 'View Activity Log For This Weblog']
my @roles;
if ($this_parent->type == 2) {
@roles = ("'comment'", "'comment'", "'comment'", "'comment'", "'not_comment'");
} else {
if (MT->version_number >= 3.2) {
push @roles, ("'post'", "'post'", "'post'", "'post'");
push @roles, ("'post','upload'");
push @roles, ("'post','upload','edit_all_posts'");
push @roles, ("'edit_templates','edit_all_posts','post','upload'");
push @roles, ("'edit_config','edit_templates','edit_all_posts','post','upload'");
push @roles, ("'edit_categories','edit_config','edit_templates','edit_all_posts','post','upload'");
push @roles, ("'view_blog_log','edit_config'");
} else {
push @roles, ("'post'", "'post'", "'post'", "'post'");
push @roles, ("'post','upload'");
push @roles, ("'edit_all_posts','post','upload'");
push @roles, ("'edit_templates','edit_all_posts','post','upload'");
push @roles, ("'edit_config','edit_templates','edit_all_posts','post','upload'");
push @roles, ("'edit_categories','edit_templates','edit_all_posts','post','upload'");
push @roles, ("'edit_config','edit_authors','edit_all_posts'");
}
}
$roles[int(rand(scalar @roles))];
}
sub random_url {
'http://www.example.com/user' . $this_iter . '/';
}
sub random_ip {
"192.168.0." . $this_iter;
}
sub assign_random_tags {
my @tags;
my $count = $tags_per_entry->();
for (my $i = 0; $i < $count; $i++) {
push @tags, $word_pool[rand(scalar @word_pool)];
}
$this_obj->tags(@tags);
undef;
}
sub assign_random_categories {
my @count = (0, 1, 1, 1, 1, 2);
# this is the last field; go ahead and save this object so
# we have an entry id.
$this_obj->save;
my $count = $count[int(rand(scalar @count))];
require MT::Category;
require MT::Placement;
my @cats = MT::Category->load({ blog_id => $this_obj->blog_id });
my %used;
$count = scalar @cats if scalar @cats < $count;
for (my $i = 0; $i < $count; $i++) {
my $cat = $cats[int(rand(scalar @cats))];
next if $used{$cat->id};
my $place = MT::Placement->new;
$place->category_id($cat->id);
$place->blog_id($this_obj->blog_id);
$place->entry_id($this_obj->id);
$place->is_primary(%used ? 0 : 1);
$place->save or die $place->errstr;
$used{$cat->id} = 1;
}
undef;
}
sub random_date {
my @date = localtime(time - int(rand($years * 365 * 24 * 60 * 60)));
return sprintf("%04d%02d%02d%02d%02d%02d",
$date[5] + 1900, $date[4] + 1, $date[3], $date[2], $date[1], $date[0]
);
}
1;
__END__
=head1 NAME
populate - A utility for creating pseudorandom weblog data.
=head1 SYNOPSIS
# Create 3 'random' weblogs with ~500 entries each
tools/populate --blogs 3 --destroy --yes-really
# Adds an addtional weblog
tools/populate --blogs 1
=head1 OPTIONS
=over 4
=item B<--destroy>
Wipes your existing database before populating it. This switch is confirmed
before execution. If this is done, the system admin becomes Melody Nelson.
=item --yes-really
Bypasses the confirmation for the '--destroy' switch.
=item --blogs E<lt>nE<gt>
Lets you specify the number of weblogs to create (default is 1).
=item --authors E<lt>nE<gt>
Specifies the number of user records to create (default is 3).
=item --entries E<lt>nE<gt>
Specifies the number of entries (approximately) to create (default is 500).
=item --categories E<lt>nE<gt>
Specifies the number of categories (approximately) to create (default is 5).
=item --years E<lt>nE<gt>
Specifies the number of years to post-date entry creation (default is 1).
=back
Jump to Line
Something went wrong with that request. Please try again.