]> git.donarmstrong.com Git - debbugs.git/blob - Debbugs/DBase.pm
[project @ 2000-05-01 23:28:02 by doogie]
[debbugs.git] / Debbugs / DBase.pm
1 # TODO: Implement 'stale' checks, so that there is no need to explicitly
2 #       write out a record, before closing.
3
4 package Debbugs::DBase;  # assumes Some/Module.pm
5
6 use strict;
7
8 BEGIN {
9         use Exporter   ();
10         use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
11
12         # set the version for version checking
13         $VERSION     = 1.00;
14
15         @ISA         = qw(Exporter);
16         @EXPORT      = qw( %Record );
17         %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
18
19         # your exported package globals go here,
20         # as well as any optionally exported functions
21         @EXPORT_OK   = qw( %Record );
22 }
23
24 use vars      @EXPORT_OK;
25 use Fcntl ':flock';
26 use Debbugs::Config;
27 use Debbugs::Email;
28 use Debbugs::Common;
29 use Debbugs::DBase::Log;
30 use Debbugs::DBase::Log::Html;
31 use Debbugs::DBase::Log::Message;
32 use Debbugs::DBase::Log::Mail;
33
34 use FileHandle;
35 use File::Basename qw(&dirname);
36 use File::Path;
37
38 %Record = ();
39
40 my $LoadedRecord = 0;
41 my $OpenedRecord = 0;
42 my $OpenedLog = 0;
43 my $FileLocked = 0;
44 my $FileHandle = new FileHandle;
45 my $LogfileHandle = new FileHandle;
46
47 sub ParseVersion1Record
48 {
49     my @data = @_;
50     my @fields = ( "originator", "date", "subject", "msgid", "package",
51                 "keywords", "done", "forwarded", "mergedwith", "severity" );
52     my $i = 0;
53     my $tag;
54
55     print "D2: (DBase) Record Fields:\n" if $Globals{ 'debug' } > 1;
56     foreach my $line ( @data )
57     {
58         chop( $line );
59         $tag = $fields[$i];
60         $Record{ $tag } = $line;
61         print "\t $tag = $line\n" if $Globals{ 'debug' } > 1;
62         $i++;
63         $GTags{ "BUG_$tag" } = $line;
64     }
65 }
66
67 sub ParseVersion2Record
68 {
69     # I envision the next round of records being totally different in
70     # meaning.  In order to maintain compatability, version tagging will be
71     # implemented in thenext go around and different versions will be sent
72     # off to different functions to be parsed and interpreted into a format
73     # that the rest of the system will understand.  All data will be saved
74     # in whatever 'new" format ixists.  The difference will be a "Version: x"
75     # at the top of the file.
76
77     print "No version 2 records are understood at this time\n";
78     exit 1;
79 }
80
81 sub ReadRecord
82 {
83     my $record = $_[0];
84     print "V: Reading status $record\n" if $Globals{ 'verbose' };
85     if ( $record ne $LoadedRecord )
86     {
87         my @data;
88
89         seek( $FileHandle, 0, 0 );
90         @data = <$FileHandle>;
91         if ( scalar( @data ) =~ /Version: (\d*)/ )
92         {
93             if ( $1 == 2 )
94             { &ParseVersion2Record( @data ); }
95             else
96             { &fail( "Unknown record version: $1\n"); }
97         }
98         else { &ParseVersion1Record( @data ); }
99         $LoadedRecord = $record;
100     }
101     else { print "D1: (DBase) $record is already loaded\n" if $Globals{ 'debug' }; }
102
103 }
104
105 sub WriteRecord
106 {
107     my @fields = ( "originator", "date", "subject", "msgid", "package",
108                 "keywords", "done", "forwarded", "mergedwith", "severity" );
109     print "V: Writing status $LoadedRecord\n" if $Globals{ 'verbose' };
110     seek( $FileHandle, 0, 0 );
111     for( my $i = 0; $i < $#fields; $i++ )
112     {
113         if ( defined( $fields[$i] ) )
114         { print $FileHandle $Record{ $fields[$i] } . "\n"; }
115         else { print $FileHandle "\n"; }
116     }
117 }
118
119 sub GetFileName
120 {
121     my ($prePaths, $stub, $postPath, $desc, $new) = (shift, shift, shift, shift, shift);
122     my $path;
123     foreach my $prePath (@$prePaths) {
124         $path = "/" . $prePath . "/" . $stub . $postPath;
125         print "V: Opening $desc $stub\n" if $Globals{ 'verbose' };
126         print "D2: (DBase) trying $path\n" if $Globals{ 'debug' } > 1;
127         if( ! -r $Globals{ "work-dir" } . $path ) {
128             $path = "/" . $prePath . "/" . &NameToPathHash($stub) . $postPath;
129             print "D2: (DBase) trying $path\n" if $Globals{ 'debug' } > 1;
130             if( ! -r $Globals{ "work-dir" } . $path ) {
131                 next if( !$new =~ "new" );
132             }
133         }
134         if( -r $Globals{ "work-dir" } . $path ) {
135             return $path;
136         }
137         if( ( ! -r $Globals{ "work-dir" } . $path ) && defined($new) && $new =~ "new") {
138             my $dir = dirname( $path );
139             if ( ! -d $Globals{ "work-dir" } . $dir ) {
140                 mkpath($Globals{ "work-dir" } . $dir);
141             }
142             return $path;
143         }
144     }
145     return undef;
146 }
147 sub OpenFile
148 {
149     my ($prePaths, $stub, $postPath, $desc, $new) = (shift, shift, shift, shift, shift);
150     my $fileName = GetFileName($prePaths, $stub, $postPath, $desc, $new);
151     my $handle = new FileHandle;
152     open( $handle, $Globals{ "work-dir" } . $fileName ) && return $handle;
153     return undef;
154 }
155
156 sub OpenRecord
157 {
158     my $record = $_[0];
159     if ( $record ne $OpenedRecord )
160     {
161         $FileHandle = OpenFile ["db", "archive"], $record, ".status", "status", $_[1];
162         flock( $FileHandle, LOCK_EX ) || &fail( "Unable to lock record $record\n" );
163         $OpenedRecord = $record;
164     }
165 }
166
167 sub CloseRecord
168 {
169     print "V: Closing status $LoadedRecord\n" if $Globals{ 'verbose' };
170     close $FileHandle;
171     $OpenedRecord = 0;
172 }
173
174 sub OpenLogfile
175 {
176     my $record = $_[0];
177     if ( $record ne $OpenedLog )
178     {
179         $LogfileHandle = OpenFile(["db", "archive"], $record, ".log", "log");
180         $OpenedLog = $record;
181     }
182 }
183
184 sub ReadLogfile
185 {
186     my $record = $_[0];
187     if ( $record eq $OpenedLog )
188     {
189         seek( $LogfileHandle, 0, 0 );
190         my $log = new Debbugs::DBase::Log;
191         $log->Load($LogfileHandle);
192     }
193 }
194
195 sub CloseLogfile
196 {
197     print "V: Closing log $OpenedLog\n" if $Globals{ 'verbose' };
198     close $LogfileHandle;
199     $OpenedLog = 0;
200 }
201 sub GetBugList
202 {
203 # TODO: This is ugly, but the easiest for me to implement.
204 #       If you have a better way, then please send a patch.
205 #
206     my $dir = new FileHandle;
207
208     my $prefix;
209     my $paths = shift;
210     my @paths;
211     if ( !defined($paths) ) {
212         @paths = ("db");
213     } else {
214         @paths = @$paths;
215     }
216     my @ret;
217     my $path;
218     foreach $path (@paths) {
219         $prefix = $Globals{ "work-dir" } . "/" . $path . "/";
220         opendir $dir, $prefix;
221         my @files = readdir($dir);
222         closedir $dir;
223         foreach (grep { /\d*\d\d.status/ } @files) {
224             next if ( ! -s $prefix . "/" . $_ );
225             s/.status$//;
226             push @ret, $_;
227 #           print "$_ -> $_\n";
228         }
229         foreach (grep { /^[s0-9]$/ } @files) {
230             my $_1 = $_;
231             opendir $dir, $prefix . $_1;
232             my @files = grep { /^\d$/ } readdir($dir);
233             closedir $dir;
234             foreach (@files) {
235                 my $_2 = $_;
236                 opendir $dir, "$prefix$_1/$_2";
237                 my @files = grep { /^\d$/ } readdir($dir);
238                 close $dir;
239                 foreach (@files) {
240                     my $_3 = $_;
241                     opendir $dir, "$prefix$_1/$_2/$_3";
242                     my @files = grep { /\d*\d\d.status/ } readdir($dir);
243                     close $dir;
244                     foreach (@files) {
245                         next if ( ! -s "$prefix$_1/$_2/$_3/$_" );
246                         s/.status$//;
247                         push @ret, $_;
248 #                       print "$_ -> $_1/$_2/$_3/$_\n";
249                     }
250                 }
251             }
252         }
253     }
254     return @ret;
255 }
256
257 1;
258
259 END { }       # module clean-up code here (global destructor)