3 * Copyright (C) 2008-2014 Florian Brosch
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian Brosch <flo.brosch@gmail.com>
23 using Valadoc
.Importer
;
26 public class ValaDoc
: Object
{
27 private const string DEFAULT_COLORS
= "error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01";
29 private static string wikidirectory
= null;
30 private static string pkg_version
= null;
31 private static string docletpath
= null;
32 [CCode (array_length
= false, array_null_terminated
= true)]
33 private static string[] pluginargs
;
34 private static string directory
= null;
35 private static string pkg_name
= null;
36 private static string gir_name
= null;
37 private static string gir_namespace
= null;
38 private static string gir_version
= null;
39 private static string driverpath
= null;
41 private static bool add_inherited
= false;
42 private static bool _protected
= true;
43 private static bool _internal
= false;
44 private static bool with_deps
= false;
45 private static bool _private
= false;
46 private static bool version
= false;
47 private static bool use_svg_images
= false;
49 private static bool disable_diagnostic_colors
= false;
50 private static bool verbose
= false;
51 private static bool force
= false;
53 private static string basedir
= null;
54 [CCode (array_length
= false, array_null_terminated
= true)]
55 private static string[] defines
;
56 private static bool experimental
;
57 private static bool experimental_non_null
= false;
58 private static string profile
;
59 [CCode (array_length
= false, array_null_terminated
= true)]
60 private static string[] import_packages
;
61 [CCode (array_length
= false, array_null_terminated
= true)]
62 private static string[] import_directories
;
63 [CCode (array_length
= false, array_null_terminated
= true)]
64 private static string[] vapi_directories
;
65 [CCode (array_length
= false, array_null_terminated
= true)]
66 private static string[] metadata_directories
;
67 [CCode (array_length
= false, array_null_terminated
= true)]
68 private static string[] gir_directories
;
69 [CCode (array_length
= false, array_null_terminated
= true)]
70 private static string[] tsources
;
71 [CCode (array_length
= false, array_null_terminated
= true)]
72 private static string[] packages
;
73 [CCode (array_length
= false, array_null_terminated
= true)]
74 private static string[] alternative_resource_dirs
;
75 static string target_glib
;
77 private const GLib
.OptionEntry
[] options
= {
78 { "directory", 'o', 0, OptionArg
.FILENAME
, ref directory
, "Output directory", "DIRECTORY" },
80 { "basedir", 'b', 0, OptionArg
.FILENAME
, ref basedir
, "Base source directory", "DIRECTORY" },
81 { "define", 'D', 0, OptionArg
.STRING_ARRAY
, ref defines
, "Define SYMBOL", "SYMBOL..." },
82 { "profile", 0, 0, OptionArg
.STRING
, ref profile
, "Use the given profile instead of the default", "PROFILE" },
84 { "enable-experimental", 0, 0, OptionArg
.NONE
, ref experimental
, "Enable experimental features", null },
85 { "enable-experimental-non-null", 0, 0, OptionArg
.NONE
, ref experimental_non_null
, "Enable experimental enhancements for non-null types", null },
87 { "metadatadir", 0, 0, OptionArg
.FILENAME_ARRAY
, ref metadata_directories
, "Look for GIR .metadata files in DIRECTORY", "DIRECTORY..." },
88 { "girdir", 0, 0, OptionArg
.FILENAME_ARRAY
, ref gir_directories
, "Look for .gir files in DIRECTORY", "DIRECTORY..." },
89 { "vapidir", 0, 0, OptionArg
.FILENAME_ARRAY
, ref vapi_directories
, "Look for package bindings in DIRECTORY", "DIRECTORY..." },
90 { "pkg", 0, 0, OptionArg
.STRING_ARRAY
, ref packages
, "Include binding for PACKAGE", "PACKAGE..." },
92 { "driver", 0, 0, OptionArg
.STRING
, ref driverpath
, "Name of an driver or path to a custom driver", null },
94 { "importdir", 0, 0, OptionArg
.FILENAME_ARRAY
, ref import_directories
, "Look for external documentation in DIRECTORY", "DIRECTORY..." },
95 { "import", 0, 0, OptionArg
.STRING_ARRAY
, ref import_packages
, "Include binding for PACKAGE", "PACKAGE..." },
96 { "alternative-resource-dir", 0, 0, OptionArg
.STRING_ARRAY
, ref alternative_resource_dirs
, "Alternative resource directories", "DIRECTORY..." },
98 { "wiki", 0, 0, OptionArg
.FILENAME
, ref wikidirectory
, "Wiki directory", "DIRECTORY" },
100 { "deps", 0, 0, OptionArg
.NONE
, ref with_deps
, "Adds packages to the documentation", null },
102 { "doclet", 0, 0, OptionArg
.STRING
, ref docletpath
, "Name of an included doclet or path to custom doclet", "PLUGIN"},
103 { "doclet-arg", 'X', 0, OptionArg
.STRING_ARRAY
, ref pluginargs
, "Pass arguments to the doclet", "ARG" },
105 { "no-protected", 0, OptionFlags
.REVERSE
, OptionArg
.NONE
, ref _protected
, "Removes protected elements from documentation", null },
106 { "internal", 0, 0, OptionArg
.NONE
, ref _internal
, "Adds internal elements to documentation", null },
107 { "private", 0, 0, OptionArg
.NONE
, ref _private
, "Adds private elements to documentation", null },
108 { "use-svg-images", 0, 0, OptionArg
.NONE
, ref use_svg_images
, "Generate SVG image charts instead of PNG", null },
110 { "package-name", 0, 0, OptionArg
.STRING
, ref pkg_name
, "package name", "NAME" },
111 { "package-version", 0, 0, OptionArg
.STRING
, ref pkg_version
, "package version", "VERSION" },
112 { "gir", 0, 0, OptionArg
.STRING
, ref gir_name
, "GObject-Introspection repository file name", "NAME-VERSION.gir" },
114 { "version", 0, 0, OptionArg
.NONE
, ref version
, "Display version number", null },
116 { "force", 0, 0, OptionArg
.NONE
, ref force
, "force", null },
117 { "verbose", 0, 0, OptionArg
.NONE
, ref verbose
, "Show all warnings", null },
118 { "no-color", 0, 0, OptionArg
.NONE
, ref disable_diagnostic_colors
, "Disable colored output", null },
119 { "target-glib", 0, 0, OptionArg
.STRING
, ref target_glib
, "Target version of glib for code generation", "MAJOR.MINOR" },
120 { OPTION_REMAINING
, 0, 0, OptionArg
.FILENAME_ARRAY
, ref tsources
, null, "FILE..." },
125 private static int quit (ErrorReporter reporter
) {
126 if (reporter
.errors
== 0) {
127 stdout
.printf ("Succeeded - %d warning(s)\n", reporter
.warnings
);
130 stdout
.printf ("Failed: %d error(s), %d warning(s)\n", reporter
.errors
, reporter
.warnings
);
135 private static bool check_pkg_name () {
136 if (pkg_name
== null) {
140 if (pkg_name
== "glib-2.0" || pkg_name
== "gobject-2.0") {
144 foreach (string package
in tsources
) {
145 if (pkg_name
== package
) {
152 private string get_pkg_name () {
153 if (ValaDoc
.pkg_name
== null) {
154 if (ValaDoc
.directory
.has_suffix ("/")) {
155 ValaDoc
.pkg_name
= GLib
.Path
.get_dirname (ValaDoc
.directory
);
157 ValaDoc
.pkg_name
= GLib
.Path
.get_basename (ValaDoc
.directory
);
161 return ValaDoc
.pkg_name
;
164 private ModuleLoader?
create_module_loader (ErrorReporter reporter
, out Doclet? doclet
, out Driver? driver
) {
165 ModuleLoader modules
= ModuleLoader
.get_instance ();
171 string? pluginpath
= ModuleLoader
.get_doclet_path (docletpath
, reporter
);
172 if (pluginpath
== null) {
176 doclet
= modules
.create_doclet (pluginpath
);
177 if (doclet
== null) {
178 reporter
.simple_error (null, "failed to load doclet");
184 driver
= new Valadoc
.Drivers
.Driver ();
186 assert (driver
!= null && doclet
!= null);
191 private int run (ErrorReporter reporter
) {
193 var settings
= new Valadoc
.Settings ();
194 reporter
.settings
= settings
;
196 settings
.pkg_name
= this
.get_pkg_name ();
197 settings
.gir_namespace
= ValaDoc
.gir_namespace
;
198 settings
.gir_version
= ValaDoc
.gir_version
;
199 if (ValaDoc
.gir_name
!= null) {
200 settings
.gir_name
= GLib
.Path
.get_basename (ValaDoc
.gir_name
);
201 settings
.gir_directory
= GLib
.Path
.get_dirname (ValaDoc
.gir_name
);
202 if (settings
.gir_directory
== "") {
203 settings
.gir_directory
= GLib
.Path
.get_dirname (ValaDoc
.directory
);
206 settings
.pkg_version
= ValaDoc
.pkg_version
;
207 settings
.add_inherited
= ValaDoc
.add_inherited
;
208 settings
._protected
= ValaDoc
._protected
;
209 settings
._internal
= ValaDoc
._internal
;
210 settings
.with_deps
= ValaDoc
.with_deps
;
211 settings
._private
= ValaDoc
._private
;
212 settings
.path
= Vala
.CodeContext
.realpath (ValaDoc
.directory
);
213 settings
.verbose
= ValaDoc
.verbose
;
214 settings
.wiki_directory
= ValaDoc
.wikidirectory
;
215 settings
.pluginargs
= ValaDoc
.pluginargs
;
217 settings
.experimental
= experimental
;
218 settings
.experimental_non_null
= experimental_non_null
;
219 settings
.basedir
= basedir
;
220 settings
.directory
= directory
;
221 settings
.vapi_directories
= vapi_directories
;
222 settings
.metadata_directories
= metadata_directories
;
223 settings
.gir_directories
= gir_directories
;
224 settings
.target_glib
= target_glib
;
225 settings
.use_svg_images
= use_svg_images
;
227 settings
.source_files
= tsources
;
228 settings
.packages
= packages
;
230 settings
.profile
= profile
;
231 settings
.defines
= defines
;
233 settings
.alternative_resource_dirs
= alternative_resource_dirs
;
237 Doclet? doclet
= null;
238 Driver? driver
= null;
240 ModuleLoader? modules
= create_module_loader (reporter
, out doclet
, out driver
);
241 if (reporter
.errors
> 0 || modules
== null) {
242 return quit (reporter
);
247 Valadoc
.Api
.Tree doctree
= driver
.build (settings
, reporter
);
248 if (reporter
.errors
> 0) {
251 return quit (reporter
);
254 // register child symbols:
255 Valadoc
.Api
.ChildSymbolRegistrar registrar
= new Valadoc
.Api
.ChildSymbolRegistrar ();
256 doctree
.accept (registrar
);
258 // process documentation
259 Valadoc
.DocumentationParser docparser
= new Valadoc
.DocumentationParser (settings
, reporter
, doctree
, modules
);
260 if (!doctree
.create_tree()) {
261 return quit (reporter
);
264 DocumentationImporter
[] importers
= {
265 new
ValadocDocumentationImporter (doctree
, docparser
, modules
, settings
, reporter
),
266 new
GirDocumentationImporter (doctree
, docparser
, modules
, settings
, reporter
)
269 doctree
.parse_comments (docparser
);
270 if (reporter
.errors
> 0) {
271 return quit (reporter
);
274 doctree
.import_comments (importers
, import_packages
, import_directories
);
275 if (reporter
.errors
> 0) {
276 return quit (reporter
);
279 doctree
.check_comments (docparser
);
280 if (reporter
.errors
> 0) {
281 return quit (reporter
);
284 if (ValaDoc
.gir_name
!= null) {
285 driver
.write_gir (settings
, reporter
);
286 if (reporter
.errors
> 0) {
287 return quit (reporter
);
291 doclet
.process (settings
, doctree
, reporter
);
292 return quit (reporter
);
295 static int main (string[] args
) {
296 Intl
.setlocale (LocaleCategory
.ALL
, "");
297 ErrorReporter reporter
= new
ErrorReporter();
300 var opt_context
= new
OptionContext ("- Vala Documentation Tool");
301 opt_context
.set_help_enabled (true);
302 opt_context
.add_main_entries (options
, null);
303 opt_context
.parse (ref args
);
304 } catch (OptionError e
) {
305 reporter
.simple_error (null, "%s", e
.message
);
306 stdout
.printf ("Run '%s --help' to see a full list of available command line options.\n", args
[0]);
307 return quit (reporter
);
310 if (disable_diagnostic_colors
== false) {
311 unowned
string env_colors
= Environment
.get_variable ("VALA_COLORS");
312 if (env_colors
!= null) {
313 reporter
.set_colors (env_colors
);
315 reporter
.set_colors (DEFAULT_COLORS
);
320 stdout
.printf ("Valadoc %s\n", Config
.BUILD_VERSION
);
324 if (directory
== null) {
325 reporter
.simple_error (null, "No output directory specified.");
326 return quit (reporter
);
329 if (!check_pkg_name ()) {
330 reporter
.simple_error (null, "File already exists");
331 return quit (reporter
);
334 if (FileUtils
.test (directory
, FileTest
.EXISTS
)) {
336 bool tmp
= remove_directory (directory
);
338 reporter
.simple_error (null, "Can't remove directory.");
339 return quit (reporter
);
342 reporter
.simple_error (null, "File already exists");
343 return quit (reporter
);
347 if (wikidirectory
!= null) {
348 if (!FileUtils
.test(wikidirectory
, FileTest
.IS_DIR
)) {
349 reporter
.simple_error (null, "Wiki-directory does not exist.");
350 return quit (reporter
);
354 foreach (unowned
string dir
in alternative_resource_dirs
) {
355 if (!FileUtils
.test(dir
, FileTest
.IS_DIR
)) {
356 reporter
.simple_error (null, "alternative resource directory '%s' does not exist.".printf (dir
));
357 return quit (reporter
);
360 if (reporter
.errors
> 0) {
361 return quit (reporter
);
364 if (gir_name
!= null) {
365 long gir_len
= gir_name
.length
;
366 int last_hyphen
= gir_name
.last_index_of_char ('-');
368 if (last_hyphen
== -1 || !gir_name
.has_suffix (".gir")) {
369 reporter
.simple_error (null, "GIR file name '%s' is not well-formed, expected NAME-VERSION.gir", gir_name
);
370 return quit (reporter
);
373 gir_namespace
= gir_name
.substring (0, last_hyphen
);
374 gir_version
= gir_name
.substring (last_hyphen
+ 1, gir_len
- last_hyphen
- 5);
375 gir_version
.canon ("0123456789.", '?');
377 if (gir_namespace
== "" || gir_version
== "" || !gir_version
[0].isdigit () || gir_version
.contains ("?")) {
378 reporter
.simple_error (null, "GIR file name '%s' is not well-formed, expected NAME-VERSION.gir", gir_name
);
379 return quit (reporter
);
383 bool report_warning
= true;
384 foreach (string source
in tsources
) {
385 if (source
.has_suffix (".vala") || source
.has_suffix (".gs")) {
386 report_warning
= false;
391 if (report_warning
== true) {
392 reporter
.simple_error (null, "No source file specified to be compiled to gir.");
393 return quit (reporter
);
398 var valadoc
= new
ValaDoc( );
399 return valadoc
.run (reporter
);