5 // Jonathan Pryor <jpryor@novell.com>
7 // Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Collections
.Generic
;
31 using System
.Diagnostics
;
36 using System
.Xml
.Linq
;
39 using Mono
.Documentation
;
44 using ICSharpCode
.SharpZipLib
.Zip
;
46 namespace Mono
.Documentation
48 public class MDocExportWebdocHtml
: MDocCommand
51 public Dictionary
<string, List
<string>> Formats
= new Dictionary
<string, List
<string>>();
52 public List
<string> Sources
= new List
<string>();
53 public bool UseSystemSources
= true;
54 public bool ForceUpdate
= false;
55 public string OutputDirectory
= null;
58 public override void Run (IEnumerable
<string> args
)
60 var opts
= new Options ();
61 var formatOptions
= MDocAssembler
.CreateFormatOptions (this, opts
.Formats
);
62 var options
= new OptionSet () {
64 "Always generate new files. If not specified, will only generate " +
65 "files if the write time of the output directory is older than the " +
66 "write time of the source .tree/.zip files.",
67 v
=> opts
.ForceUpdate
= v
!= null },
71 "The {PREFIX} to place the generated files and directories. " +
72 "Default: \"`dirname FILE`/cache/\".\n" +
73 "Underneath {PREFIX}, `basename FILE .tree` directories will be " +
74 "created which will contain the pre-generated HTML content.",
75 v
=> opts
.OutputDirectory
= v
},
77 "A {SOURCE} file to use for reference purposes.\n" +
78 "Extension methods are searched for among all {SOURCE}s which are referenced.\n" +
79 "This option may be specified multiple times.",
80 v
=> opts
.Sources
.Add (v
) },
81 { "use-system-sources",
82 "Use the system-wide .source files for reference purposes. " +
83 "Default is " + (opts
.UseSystemSources
? "enabled" : "disabled") + ".",
84 v
=> opts
.UseSystemSources
= v
!= null },
86 Parse (options
, args
, "export-html-webdoc",
88 "Export mdoc documentation within FILES to HTML for use by ASP.NET webdoc.\n\n" +
89 "FILES are .tree or .zip files as produced by 'mdoc assemble', or .source files\n" +
90 "which reference .tree and .zip files produced by 'mdoc assemble'.\n\n" +
91 "See mdoc(5) or mdoc-assemble(1) for information about the .source file format.");
92 if (opts
.Formats
.Values
.All (files
=> files
.Count
== 0))
93 Error ("No files specified.");
94 ProcessSources (opts
);
95 HelpSource
.use_css
= true;
96 HelpSource
.FullHtml
= false;
97 SettingsHandler
.Settings
.EnableEditing
= false;
98 foreach (var p
in opts
.Formats
)
99 ProcessFiles (opts
, p
.Key
, p
.Value
);
102 void ProcessSources (Options opts
)
104 foreach (var p
in opts
.Formats
) {
106 foreach (var f
in files
.Where (f
=> f
.EndsWith (".source")).ToList ()) {
108 foreach (var tfi
in GetTreeFilesFromSource (f
)) {
109 List
<string> treeFiles
;
110 if (!opts
.Formats
.TryGetValue (tfi
.Key
, out treeFiles
))
111 opts
.Formats
.Add (tfi
.Key
, treeFiles
= new List
<string> ());
112 treeFiles
.Add (tfi
.Value
);
118 IEnumerable
<KeyValuePair
<string, string>> GetTreeFilesFromSource (string sourceFile
)
121 var source
= XElement
.Load (sourceFile
);
122 return source
.Descendants ("source")
123 .Select (e
=> new KeyValuePair
<string, string>(e
.Attribute ("provider").Value
,
124 Path
.Combine (Path
.GetDirectoryName (sourceFile
), e
.Attribute ("basefile").Value
+ ".tree")));
126 catch (Exception e
) {
127 Message (TraceLevel
.Error
, "mdoc: error parsing file {0}: {1}", sourceFile
, e
.Message
);
128 return new KeyValuePair
<string, string>[0];
132 void ProcessFiles (Options opts
, string format
, List
<string> files
)
134 foreach (var basePath
in
136 Path
.Combine (Path
.GetDirectoryName (f
), Path
.GetFileNameWithoutExtension (f
)))
138 string treeFile
= basePath
+ ".tree";
139 string zipFile
= basePath
+ ".zip";
140 if (!Exists (treeFile
) || !Exists (zipFile
))
142 string outDir
= opts
.OutputDirectory
!= null
143 ? Path
.Combine (opts
.OutputDirectory
, Path
.GetFileName (basePath
))
144 : XmlDocUtils
.GetCacheDirectory (basePath
);
145 if (!opts
.ForceUpdate
&& Directory
.Exists (outDir
) &&
146 MaxWriteTime (treeFile
, zipFile
) < Directory
.GetLastWriteTime (outDir
))
148 Message (TraceLevel
.Warning
, "Processing files: {0}, {1}", treeFile
, zipFile
);
149 Directory
.CreateDirectory (outDir
);
150 ExtractZipFile (zipFile
, outDir
);
151 GenerateCache (opts
, basePath
, format
, outDir
);
155 bool Exists (string file
)
157 if (!File
.Exists (file
)) {
158 Message (TraceLevel
.Error
,
159 "mdoc: Could not find file: {0}", file
);
165 DateTime
MaxWriteTime (params string[] files
)
167 return files
.Select (f
=> File
.GetLastWriteTime (f
)).Max ();
170 void ExtractZipFile (string zipFile
, string outDir
)
172 ZipInputStream zip
= new ZipInputStream (File
.OpenRead (zipFile
));
175 while ((entry
= zip
.GetNextEntry ()) != null) {
176 string file
= Path
.Combine (outDir
, entry
.Name
);
177 Directory
.CreateDirectory (Path
.GetDirectoryName (file
));
178 using (var output
= File
.OpenWrite (file
))
179 zip
.WriteTo (output
);
183 void GenerateCache (Options opts
, string basePath
, string format
, string outDir
)
185 var hs
= RootTree
.GetHelpSource (format
, basePath
);
187 Error ("Unable to find a HelpSource for provider '{0}' and file '{1}.tree'.", format
, basePath
);
190 RootTree docRoot
= null;
191 if (!opts
.UseSystemSources
)
192 docRoot
= RootTree
.LoadTree (null, null, opts
.Sources
);
194 docRoot
= RootTree
.LoadTree ();
195 foreach (var source
in opts
.Sources
)
196 docRoot
.AddSourceFile (source
);
198 hs
.RootTree
= docRoot
;
199 string helpSourceName
= Path
.GetFileName (basePath
);
200 foreach (Node node
in tree
.TraverseDepthFirst
<Node
, Node
> (t
=> t
, t
=> t
.Nodes
.Cast
<Node
> ())) {
202 Message (TraceLevel
.Info
, "\tProcessing URL: {0}", url
);
203 if (string.IsNullOrEmpty (url
))
205 var file
= XmlDocUtils
.GetCachedFileName (outDir
, url
);
206 using (var o
= File
.AppendText (file
)) {
208 string contents
= hs
.GetText (url
, out _
) ?? hs
.RenderNamespaceLookup (url
, out _
);