1 ###############################################################################
3 # Package: NaturalDocs::Builder
5 ###############################################################################
7 # A package that takes parsed source file and builds the output for it.
9 # Usage and Dependencies:
11 # - <Add()> can be called immediately.
12 # - <OutputPackages()> and <OutputPackageOf()> can be called once all sub-packages have been registered via <Add()>.
13 # Since this is normally done in their INIT functions, they should be available to all normal functions immediately.
15 # - Prior to calling <Run()>, <NaturalDocs::Settings>, <NaturalDocs::Project>, <NaturalDocs::Menu>, and
16 # <NaturalDocs::Parser> must be initialized. <NaturalDocs::Settings->GenerateDirectoryNames()> must be called.
17 # <NaturalDocs::SymbolTable> and <NaturalDocs::ClassHierarchy> must be initialized and fully resolved.
19 ###############################################################################
21 # This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
22 # Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
23 # Refer to License.txt for the complete details
29 use NaturalDocs::Builder::Base;
30 use NaturalDocs::Builder::HTML;
31 use NaturalDocs::Builder::FramedHTML;
33 package NaturalDocs::Builder;
36 ###############################################################################
40 # Array: outputPackages
42 # An array of the output packages available for use.
47 ###############################################################################
52 # Function: OutputPackages
54 # Returns an arrayref of the output packages available for use. The arrayref is not a copy of the data, so don't change it.
56 # Add output packages to this list with the <Add()> function.
59 { return \@outputPackages; };
63 # Function: OutputPackageOf
65 # Returns the output package corresponding to the passed command line option, or undef if none.
67 sub OutputPackageOf #(commandLineOption)
69 my ($self, $commandLineOption) = @_;
71 $commandLineOption = lc($commandLineOption);
73 foreach my $package (@outputPackages)
75 if (lc($package->CommandLineOption()) eq $commandLineOption)
87 # Adds an output package to those available for use. All output packages must call this function in order to be recognized.
91 # package - The package name.
95 my ($self, $package) = @_;
97 # Output packages shouldn't register themselves more than once, so we don't need to check for it.
98 push @outputPackages, $package;
105 # Runs the build process. This must be called *every time* Natural Docs is run, regardless of whether any source files changed
106 # or not. Some output packages have dependencies on files outside of the source tree that need to be checked.
108 # Since there are multiple stages to the build process, this function will handle its own status messages. There's no need to print
109 # "Building files..." or something similar beforehand.
116 # Determine what we're doing.
118 my $buildTargets = NaturalDocs::Settings->BuildTargets();
120 my $filesToBuild = NaturalDocs::Project->FilesToBuild();
121 my $numberOfFilesToBuild = (scalar keys %$filesToBuild) * (scalar @$buildTargets);
123 my $filesToPurge = NaturalDocs::Project->FilesToPurge();
124 my $numberOfFilesToPurge = (scalar keys %$filesToPurge) * (scalar @$buildTargets);
126 my $imagesToUpdate = NaturalDocs::Project->ImageFilesToUpdate();
127 my $numberOfImagesToUpdate = (scalar keys %$imagesToUpdate) * (scalar @$buildTargets);
129 my $imagesToPurge = NaturalDocs::Project->ImageFilesToPurge();
130 my $numberOfImagesToPurge = (scalar keys %$imagesToPurge) * (scalar @$buildTargets);
135 my $currentIndexes = NaturalDocs::Menu->Indexes();
136 my $previousIndexes = NaturalDocs::Menu->PreviousIndexes();
138 foreach my $index (keys %$currentIndexes)
140 if (NaturalDocs::SymbolTable->IndexChanged($index) || !exists $previousIndexes->{$index})
142 $indexesToBuild{$index} = 1;
146 # All indexes that still exist should have been deleted.
147 foreach my $index (keys %$previousIndexes)
149 if (!exists $currentIndexes->{$index})
151 $indexesToPurge{$index} = 1;
155 my $numberOfIndexesToBuild = (scalar keys %indexesToBuild) * (scalar @$buildTargets);
156 my $numberOfIndexesToPurge = (scalar keys %indexesToPurge) * (scalar @$buildTargets);
159 # Start the build process
161 foreach my $buildTarget (@$buildTargets)
163 $buildTarget->Builder()->BeginBuild( $numberOfFilesToBuild || $numberOfFilesToPurge ||
164 $numberOfImagesToUpdate || $numberOfImagesToPurge ||
165 $numberOfIndexesToBuild || $numberOfIndexesToPurge ||
166 NaturalDocs::Menu->HasChanged() );
169 if ($numberOfFilesToPurge)
171 NaturalDocs::StatusMessage->Start('Purging ' . $numberOfFilesToPurge
172 . ' file' . ($numberOfFilesToPurge > 1 ? 's' : '') . '...',
173 scalar @$buildTargets);
175 foreach my $buildTarget (@$buildTargets)
177 $buildTarget->Builder()->PurgeFiles($filesToPurge);
178 NaturalDocs::StatusMessage->CompletedItem();
182 if ($numberOfIndexesToPurge)
184 NaturalDocs::StatusMessage->Start('Purging ' . $numberOfIndexesToPurge
185 . ' index' . ($numberOfIndexesToPurge > 1 ? 'es' : '') . '...',
186 scalar @$buildTargets);
188 foreach my $buildTarget (@$buildTargets)
190 $buildTarget->Builder()->PurgeIndexes(\%indexesToPurge);
191 NaturalDocs::StatusMessage->CompletedItem();
195 if ($numberOfImagesToPurge)
197 NaturalDocs::StatusMessage->Start('Purging ' . $numberOfImagesToPurge
198 . ' image' . ($numberOfImagesToPurge > 1 ? 's' : '') . '...',
199 scalar @$buildTargets);
201 foreach my $buildTarget (@$buildTargets)
203 $buildTarget->Builder()->PurgeImages($imagesToPurge);
204 NaturalDocs::StatusMessage->CompletedItem();
208 if ($numberOfFilesToBuild)
210 NaturalDocs::StatusMessage->Start('Building ' . $numberOfFilesToBuild
211 . ' file' . ($numberOfFilesToBuild > 1 ? 's' : '') . '...',
212 $numberOfFilesToBuild);
214 foreach my $file (keys %$filesToBuild)
216 my $parsedFile = NaturalDocs::Parser->ParseForBuild($file);
218 NaturalDocs::Error->OnStartBuilding($file);
220 foreach my $buildTarget (@$buildTargets)
222 $buildTarget->Builder()->BuildFile($file, $parsedFile);
223 NaturalDocs::StatusMessage->CompletedItem();
226 NaturalDocs::Error->OnEndBuilding($file);
230 if ($numberOfIndexesToBuild)
232 NaturalDocs::StatusMessage->Start('Building ' . $numberOfIndexesToBuild
233 . ' index' . ($numberOfIndexesToBuild > 1 ? 'es' : '') . '...',
234 $numberOfIndexesToBuild);
236 foreach my $index (keys %indexesToBuild)
238 foreach my $buildTarget (@$buildTargets)
240 $buildTarget->Builder()->BuildIndex($index);
241 NaturalDocs::StatusMessage->CompletedItem();
246 if ($numberOfImagesToUpdate)
248 NaturalDocs::StatusMessage->Start('Updating ' . $numberOfImagesToUpdate
249 . ' image' . ($numberOfImagesToUpdate > 1 ? 's' : '') . '...',
250 $numberOfImagesToUpdate);
252 foreach my $image (keys %$imagesToUpdate)
254 foreach my $buildTarget (@$buildTargets)
256 $buildTarget->Builder()->UpdateImage($image);
257 NaturalDocs::StatusMessage->CompletedItem();
262 if (NaturalDocs::Menu->HasChanged())
264 if (!NaturalDocs::Settings->IsQuiet())
265 { print "Updating menu...\n"; };
267 foreach my $buildTarget (@$buildTargets)
268 { $buildTarget->Builder()->UpdateMenu(); };
271 foreach my $buildTarget (@$buildTargets)
273 $buildTarget->Builder()->EndBuild($numberOfFilesToBuild || $numberOfFilesToPurge ||
274 $numberOfIndexesToBuild || $numberOfIndexesToPurge ||
275 $numberOfImagesToUpdate || $numberOfImagesToPurge ||
276 NaturalDocs::Menu->HasChanged());