/[drupal]/contributions/tricks/slash2drupal/slash2drupal.pl.txt
ViewVC logotype

Contents of /contributions/tricks/slash2drupal/slash2drupal.pl.txt

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download)
Tue Dec 14 20:55:46 2004 UTC (4 years, 11 months ago) by killes
Branch: MAIN
CVS Tags: HEAD
File MIME type: text/plain
Initial commit of slash2drupal.pl, a perl Skript to migrate from Slash to Drupal.
Author: Rob Israel
See: http://www.scylla.org/?q=slash2drupal
1 #!/usr/local/bin/perl -w
2
3 # This is a script to convert a slash site's database content
4 # to a Drupal database schema. Use at your own risk! I make
5 # absolutely no claims to it's ability to do what you expect.
6
7 # Conversion will migrate stories, journals, and comments.
8 # Topics to catagories, polls, and RSS feeds are not currently
9 # migrated, but should be fairly easy to implement.
10
11 # Initial creation 11/5/2004 Rob Israel
12
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
17
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
27 # slash2drupal version 0.1, Copyright (C) 2004 Rob Israel
28 # slash2drupal comes with ABSOLUTELY NO WARRANTY
29 # This is free software, and you are welcome to redistribute it
30 # under certain conditions;
31
32
33 use DBI;
34 use Getopt::Long;
35
36 # Get the command line options
37 # When I get time, I should really add the ability to use a different
38 # database port than the default. Maybe later.
39
40 my %optctl=
41 (
42 "h" => \$help,
43 "sh=s" => \$slash_host,
44 "dh=s" => \$drupal_host,
45 "su=s" => \$slash_user,
46 "du=s" => \$drupal_user,
47 "sp=s" => \$slash_pass,
48 "dp=s" => \$drupal_pass,
49 "sd=s" => \$slash_database,
50 "dd=s" => \$drupal_database,
51 "td=s" => \$tempdir,
52 "v" => \$verbose,
53 );
54
55 if (!Getopt::Long::GetOptions(%optctl)) {
56 Usage();
57 exit();
58 }
59
60 if ($help) {
61 Usage();
62 exit();
63 }
64
65 sub Usage {
66 print("Usage: slash2drupal options
67 Where options are:
68 -h Show this message
69 -td temporary directory
70 -sh slash host
71 -dh drupal host
72 -su slash user
73 -du drupal user
74 -sp slash database password
75 -dp drupal database password
76 -sd slash database
77 -dd drupal database
78 -td temporary directory
79 -v verbose (optional)
80 ex: convert -sh localhost -dh localhost -su slash -du drupal -sp passwd -dp passw0rd -sd slash -dd drupal\n");
81 }
82
83 # Set options if not specified
84 if (!$slash_host) {
85 print ("Slash database hostname [localhost]? ");
86 $value = <STDIN>;
87 chomp($value);
88 if ($value eq "") {
89 $slash_host = "localhost";
90 } else {
91 $slash_host = $value;
92 }
93 }
94
95 if (!$drupal_host) {
96 print ("Drupal database hostname [localhost]? ");
97 $value = <STDIN>;
98 chomp($value);
99 if ($value eq "") {
100 $drupal_host = "localhost";
101 } else {
102 $drupal_host = $value;
103 }
104 }
105
106 if (!$slash_user) {
107 print ("Slash database username [slash]? ");
108 $value = <STDIN>;
109 chomp($value);
110 if ($value eq "") {
111 $slash_user = "slash";
112 } else {
113 $slash_user = $value;
114 }
115 }
116
117 if (!$drupal_user) {
118 print ("Drupal database username [drupal] ");
119 $value = <STDIN>;
120 chomp($value);
121 if ($value eq "") {
122 $drupal_user = "drupal";
123 } else {
124 $drupal_user = $value;
125 }
126 }
127
128 if (!$slash_pass) {
129 print ("Slash database password: [slash] ");
130 $value = <STDIN>;
131 chomp($value);
132 if ($value eq "") {
133 $slash_pass = "slash";
134 } else {
135 $slash_pass = $value;
136 }
137 }
138
139 if (!$drupal_pass) {
140 print ("Drupal database password: [drupal] ");
141 $value = <STDIN>;
142 chomp($value);
143 if ($value eq "") {
144 $drupal_pass = "drupal";
145 } else {
146 $drupal_pass = $value;
147 }
148 }
149
150 if (!$slash_database) {
151 print ("Slash database: [slash] ");
152 $value = <STDIN>;
153 chomp($value);
154 if ($value eq "") {
155 $slash_database = "slash";
156 } else {
157 $slash_database = $value;
158 }
159 }
160
161 if (!$drupal_database) {
162 print ("Drupal database: [drupal] ");
163 $value = <STDIN>;
164 chomp($value);
165 if ($value eq "") {
166 $drupal_database = "drupal";
167 } else {
168 $drupal_database = $value;
169 }
170 }
171
172 if (!$tempdir) {
173 print ("Temporary file directory: [/tmp] ");
174 $value = <STDIN>;
175 chomp($value);
176 if ($value eq "") {
177 $tempdir = "/tmp";
178 } else {
179 $tempdir = $value;
180 }
181 }
182
183 # Print a sanity check for the user if we're verbose
184
185 ($verbose) && print ("The slash user is $slash_user, on $slash_host, using database $slash_database with password $slash_database.\n");
186 ($verbose) && print ("The drupal user is $drupal_user, on $drupal_host, using database $drupal_database with password $drupal_database.\n");
187
188
189 # Set up the database objects and test connection.
190 my $slashdbh = DBI->connect("DBI:mysql:$slash_database:$slash_host",$slash_user,$slash_pass) or die "Cannot connect to Slash database: " . $DBI::errstr;
191 ($verbose) && print ("Connected to slash database!\n");
192 my $drupaldbh = DBI->connect("DBI:mysql:$drupal_database:$drupal_host",$drupal_user,$drupal_pass) or die "Cannot connect to Drupal database: " . $DBI::errstr;
193 ($verbose) && print ("Connected to drupal database!\n");
194
195 ## Nuke the contents of the drupal database for tables we're working on.
196 ## This is necessary to prevent collisions in id of users and stories
197 $sth = $drupaldbh->prepare("delete from users where uid > 1") or die "Cannot prepare SQL for user delete: " . $drupaldbh->errstr();
198 $sth->execute() or die "Cannot wipe out user data: " . $drupaldbh->errstr();
199 $sth = $drupaldbh->prepare("delete from users_roles where uid > 1") or die "Cannot prepare SQL for role delete: " . $drupaldbh->errstr();
200 $sth->execute() or die "Cannot wipe out user role data: " . $drupaldbh->errstr();
201 $sth = $drupaldbh->prepare("delete from node") or die "Cannot prepare SQL for node delete: " . $drupaldbh->errstr();
202 $sth->execute() or die "Cannot wipe out node data: " . $drupaldbh->errstr();
203 $sth = $drupaldbh->prepare("delete from comments") or die "Cannot prepare SQL for comment delete: " . $drupaldbh->errstr();
204 $sth->execute() or die "Cannot wipe out comment data: " . $drupaldbh->errstr();
205 $sth->finish();
206
207 ## First, we attempt to migrate the users
208
209 # Fetch user data from slash and dump it to a temp file
210
211 open (USERS,">$tempdir/.convert.users") or die "Cannot open /tmp/.convert.users for writing!\n";
212 ($verbose) && print ("Reading user data and writing to disk....\n");
213 $sth = $slashdbh->prepare("select uid,nickname,realemail,passwd,sig from users where uid > 1") or die "Cannot prepare slash database for read: " . $slashdbh->errstr();
214 $sth->execute() or die "Cannot execute sql on slash database: " . $slashdbh->errstr();
215 $i=0;
216 while (($uid,$name,$email,$passwd,$sig) = $sth->fetchrow_array ) {
217 (!$sig) && ($sig = "Sigless");
218 $sigquote = $drupaldbh->quote("$sig");
219 $namequote = $drupaldbh->quote("$name");
220 $emailquote = $drupaldbh->quote("$email");
221 print USERS ($uid . "ZxZ" . $namequote . "ZxZ" . $emailquote . "ZxZ" .$passwd . "ZxZ" .$sigquote . "\n");
222 $i++;
223 }
224 $sth->finish();
225 close USERS;
226 ($verbose) && print ("Wrote $i users to disk....");
227
228 # Take fetched data and slap it in drupal
229
230 open (USERS,"<$tempdir/.convert.users") or die "Cannot open /tmp/.convert.users for reading! $!\n";
231 ($verbose) && print ("Writing user data to drupal database....\n");
232 $i = 0;
233 while ($line = <USERS>) {
234 chomp $line;
235 ($uid,$name,$email,$passwd,$sig) = split(/ZxZ/,$line,5);
236 ($verbose) && print ("Migrating user $name:\n");
237 $sql1 = ("INSERT INTO users (uid,name,pass,mail,mode,sort,threshold,signature,created,changed,status,timezone,init,data) VALUES ($uid,$name,'$passwd',$email,0,0,0,$sig,1101753125,1101753125,1,'0',$email,'N;')");
238 $sql2 = ("INSERT INTO users_roles (uid,rid) VALUES ($uid,2)");
239 $sth = $drupaldbh->prepare("$sql1") or die "Cannot prepare for database insertion: " . $drupaldbh-errstr();
240 $sth->execute() or die "Cannot execute update sql: " . $drupaldbh->errstr();
241 $sth = $drupaldbh->prepare("$sql2") or die "Cannot prepare for database insertion: " . $drupaldbh-errstr();
242 $sth->execute() or die "Cannot execute update sql: " . $drupaldbh->errstr();
243 $i++;
244 }
245 $sth->finish();
246 close USERS;
247
248 # Clean up and report
249 print ("Added $i users to drupal database!\n");
250 ($verbose) && print ("Removing temporary files:\n");
251 unlink("$tempdir/.convert.users") or warn "Hey! I can't delete $tempdir/.convert.users for some reason: $!\n";
252 ($verbose) && print ("User update completed.\n");
253
254 ## Now perform story migration
255
256 # Fetch story data from slash and dump it to a temp file
257 open (STORIES,">$tempdir/.convert.stories") or die "Cannot open $tempdir/.convert.stories for writing!\n";
258 $sth = $slashdbh->prepare("select discussion,title,uid,unix_timestamp(time),introtext,bodytext from stories,story_text where stories.sid = story_text.sid") or die "Cannot prepare slash database for read: " . $slashdbh->errstr();
259 $sth->execute() or die "Cannot execute sql on slash database: " . $slashdbh->errstr();
260 $i=0;
261 while (($discussion,$title,$uid,$time,$teaser,$body) = $sth->fetchrow_array ) {
262 $titlequote = $drupaldbh->quote("$title");
263 $teaserquote = $drupaldbh->quote("$teaser");
264 $bodyquote = $drupaldbh->quote("$body");
265 print STORIES ($discussion . "ZxZ" . $uid . "ZxZ" . $time . "ZxZ" . $titlequote . "ZxZ" . $teaserquote . "ZxZ" . $bodyquote . "\n");
266 $i++;
267 }
268 $sth->finish();
269 close STORIES;
270 ($verbose) && print ("Wrote $i stories to disk....");
271
272 # Take disk story data and slap it into drupal
273 open (STORIES,"<$tempdir/.convert.stories") or die "Cannot open $tempdir/.convert.stories for reading! $!\n";
274 ($verbose) && print ("Writing story data to drupal database....\n");
275 $i = 0;
276 while ($line = <STORIES>) {
277 chomp $line;
278 ($nid,$uid,$time,$title,$teaser,$body) = split(/ZxZ/,$line,6);
279 if ( $body eq "''") {
280 $body = $teaser;
281 }
282 ($verbose) && print ("Migrating story $time:\n");
283 $sql = ("INSERT INTO node (nid,type,title,uid,status,created,changed,comment,promote,moderate,teaser,body,format) VALUES ($nid,'story',$title,$uid,1,$time,$time,2,1,0,$teaser,$body,3)");
284 $sth = $drupaldbh->prepare("$sql") or die "Cannot prepare for database insertion: " . $drupaldbh->errstr();
285 $sth->execute() or die "Cannot execute update sql: " . $drupaldbh->errstr();
286 $i++;
287 }
288 $sth->finish();
289 close STORIES;
290
291 # Clean up and report
292 print ("Wrote $i stories to drupal database!\n");
293 ($verbose) && print ("Removing temporary files:\n");
294 unlink("$tempdir/.convert.stories") or warn "Hey! I can't delete $tempdir/.convert.stories for some reason: $!\n";
295 ($verbose) && print ("Story update completed.\n");
296
297 ## Now for the journals
298
299 # Fetch journal data from slash and dump to temp file
300 open (JOURNALS,">$tempdir/.convert.journals") or die "Cannot open $tempdir/.convert.journals for writing! $!\n";
301 $sql = ("select discussion,uid,unix_timestamp(date),description,article from journals,journals_text where journals.id = journals_text.id");
302 $sth = $slashdbh->prepare("$sql") or die "Cannot prepare SQL for read: " . $slashdbh->errstr();
303 $sth->execute() or die "Cannot execute SQL on slash database: " . $slashdbh->errstr();
304 $i=0;
305 while (($discussion,$uid,$time,$description,$article) = $sth->fetchrow_array ) {
306 $descriptionquote = $drupaldbh->quote("$description");
307 $articlequote = $drupaldbh->quote("$article");
308 print JOURNALS ($discussion . "ZxZ" . $uid . "ZxZ" . $time . "ZxZ" . $descriptionquote . "ZxZ" . $articlequote . "\n");
309 $i++;
310 }
311 $sth->finish();
312 close JOURNALS;
313 ($verbose) && print ("Wrote $i journal entries to disk....\n");
314
315 # Now dump the journals into Drupal
316 open (JOURNALS,"<$tempdir/.convert.journals") or die "Cannot open $tempdir/.convert.stories for reading! $!\n";
317 ($verbose) && print ("Writing journal data to drupal database....\n");
318 $i=0;
319 while ($line = <JOURNALS>) {
320 chomp $line;
321 ($nid,$uid,$time,$title,$teaser) = split(/ZxZ/,$line,5);
322 ($verbose) && print ("Migrating journal entry for user $uid\n");
323 $sql = ("INSERT INTO node (nid,type,title,uid,status,created,changed,comment,promote,moderate,teaser,body,format) VALUES ($nid,'blog',$title,$uid,1,$time,$time,2,0,0,$teaser,$teaser,3)");
324 $sth = $drupaldbh->prepare("$sql") or die "Cannot prepare for database insertion: " . $drupaldbh->errstr();
325 $sth->execute() or die "Cannot execute update sql: " . $drupaldbh->errstr();
326 $i++;
327 }
328 $sth->finish();
329 close JOURNALS;
330
331 # Clean up and report
332 print ("Wrote $i journals to drupal database!\n");
333 ($verbose) && print ("Removing temporary files:\n");
334 unlink("$tempdir/.convert.journals") or warn "Hey! I can't delete $tempdir/.convert.journals for some reason: $!\n";
335 ($verbose) && print ("Journal update completed.\n");
336
337 ## Tough part now, gotta add the comments
338
339 # Fetch comment data from slash and dump to file
340 open (COMMENTS,">$tempdir/.convert.comments") or die "Cannot open $tempdir/.convert.comments for writing! $!\n";
341 $sql = ("SELECT sid,comments.cid,pid,unix_timestamp(date),subject,uid,comment FROM comments,comment_text WHERE comment_text.cid = comments.cid ORDER BY comments.cid");
342 $sth = $slashdbh->prepare("$sql") or die "Cannot prepare SQL for read: " . $slashdbh->errstr();
343 $sth->execute() or die "Cannot execute SQL on slash database: " . $slashdbh->errstr();
344 $i=0;
345 while (($sid,$cid,$pid,$time,$subject,$uid,$comment) = $sth->fetchrow_array ) {
346 $subjectquote = $drupaldbh->quote("$subject");
347 $commentquote = $drupaldbh->quote("$comment");
348 print COMMENTS ($sid . "ZxZ" . $cid . "ZxZ" . $pid . "ZxZ" . $time . "ZxZ" . $subjectquote . "ZxZ" . $uid . "ZxZ" . $commentquote . "\n");
349 $i++;
350 }
351 $sth->finish();
352 close COMMENTS;
353 ($verbose) && print ("Wrote $i comment entries to disk....\n");
354
355 # Dump comments into database
356 open (COMMENTS,"<$tempdir/.convert.comments") or die "Cannot open $tempdir/.convert.comments for reading! $!\n";
357 ($verbose) && print ("Writing comment data to drupal database....\n");
358 $i=0; # Comment counter
359 while ($line = <COMMENTS>) {
360 chomp $line;
361
362 # Determining depth of thread here. Real pain in the ass.
363 # OK, so I gave up on this because my site doesn't have a lot of
364 # nested comments in it. Future users may want to revisit making
365 # this work. It really shouldn't be too hard. I'm just lazy.
366 ($nid,$cid,$pid,$timestamp,$subject,$uid,$comment) = split(/ZxZ/,$line,7);
367 if ( $pid == 0 ) {
368 $thread = "1/";
369 } else {
370 #$j=0; # Parent comment counter
371 #$pidcheck = $pid;
372 #print ("PIDCHECK is $pidcheck!\n");
373 #while ( $pidcheck != 0 ) {
374 # print ("PIDCHECK is now $pidcheck!\n");
375 # $sth1 = $drupaldbh->prepare("select pid from comments where cid = $pidcheck");
376 # $sth1->execute() or die "Cannot execute SQL for parent comment check: " . $drupaldbh->errstr();
377 # $pidcheck = $sth1->dump_results or die "Hey! This is broke! " . $drupaldbh->errstr();
378 # ($pidcheck) || ($pidcheck = 0);
379 # $sth1->finish()
380 #}
381 $thread = "1.1/";
382 }
383 ($verbose) && print ("Migrating comment for comment ID $uid\n");
384 $sql = ("INSERT INTO comments (cid,pid,nid,uid,subject,comment,timestamp,status,format,thread) VALUES ($cid,$pid,$nid,$uid,$subject,$comment,$timestamp,0,3,'$thread')");
385 $sth = $drupaldbh->prepare("$sql") or die "Cannot prepare for database insertion: " . $drupaldbh->errstr();
386 $sth->execute() or die "Cannot execute update sql: " . $drupaldbh->errstr();
387 $sth->finish();
388 $i++;
389 }
390 $sth->finish();
391 close COMMENTS;
392
393 # Clean up and report
394 print ("Wrote $i comments to drupal database!\n");
395 ($verbose) && print ("Removing temporary files:\n");
396 unlink("$tempdir/.convert.comments") or warn "Hey! I can't delete $tempdir/.convert.comments for some reason: $!\n";
397 ($verbose) && print ("Comment update completed.\n");
398
399 ## Now we have to update the sequences table so new content can be added
400
401 # Update sequences for node id
402 $sth = $drupaldbh->prepare("SELECT MAX(nid) AS nid FROM node") or die "Cannot prepare SQL for read: " . $drupaldbh->errstr();
403 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
404 while (($last_nid) = $sth->fetchrow_array ) {
405 $sql = "UPDATE sequences SET id = $last_nid WHERE name = 'node_nid'";
406 ($verbose) && (print ("Set last node id to $last_nid in sequences.\n"));
407 }
408 $sth = $drupaldbh->prepare("$sql");
409 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
410
411 # Update sequences table for comment id
412 $sth = $drupaldbh->prepare("SELECT MAX(cid) AS cid FROM comments") or die "Cannot prepare SQL for read: " . $drupaldbh->errstr();
413 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
414 while (($last_cid) = $sth->fetchrow_array ) {
415 $sql = "UPDATE sequences SET id = $last_cid WHERE name = 'comments_cid'";
416 ($verbose) && (print ("Set last comment id to $last_cid in sequences.\n"));
417 }
418 $sth = $drupaldbh->prepare("$sql");
419 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
420
421 # Update sequences table for user id
422 $sth = $drupaldbh->prepare("SELECT MAX(uid) AS uid FROM users") or die "Cannot prepare SQL for read: " . $drupaldbh->errstr();
423 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
424 while (($last_uid) = $sth->fetchrow_array ) {
425 $sql = "UPDATE sequences SET id = $last_uid WHERE name = 'users_uid'";
426 ($verbose) && (print ("Set last user id to $last_uid in sequences.\n"));
427 }
428 $sth = $drupaldbh->prepare("$sql");
429 $sth->execute() or die "Cannot execute SQL on drupal database: " . $drupaldbh->errstr();
430
431 $sth->finish();
432
433 # Report and we're done!
434 print ("Set last user, node, and comment ids in sequences table.\n");
435 print ("Conversion complete!\n");

  ViewVC Help
Powered by ViewVC 1.1.2