2012-09-18 18:48:40 -05:00
|
|
|
use doc::ItemUtils;
|
2012-09-05 12:41:47 -05:00
|
|
|
use io::ReaderUtil;
|
2012-10-23 16:20:57 -05:00
|
|
|
use std::future;
|
2012-07-11 17:00:40 -05:00
|
|
|
|
2012-11-19 20:00:12 -06:00
|
|
|
pub enum WriteInstr {
|
2012-09-18 18:48:40 -05:00
|
|
|
Write(~str),
|
|
|
|
Done
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
2012-11-19 20:00:12 -06:00
|
|
|
pub type Writer = fn~(+v: WriteInstr);
|
2012-11-21 00:36:32 -06:00
|
|
|
pub type WriterFactory = fn~(+page: doc::Page) -> Writer;
|
2012-03-01 00:26:28 -06:00
|
|
|
|
2012-11-19 20:00:12 -06:00
|
|
|
pub trait WriterUtils {
|
2012-11-21 00:36:32 -06:00
|
|
|
fn write_str(+str: ~str);
|
|
|
|
fn write_line(+str: ~str);
|
2012-07-11 17:00:40 -05:00
|
|
|
fn write_done();
|
|
|
|
}
|
|
|
|
|
2012-09-18 18:48:40 -05:00
|
|
|
impl Writer: WriterUtils {
|
2012-11-21 00:36:32 -06:00
|
|
|
fn write_str(+str: ~str) {
|
2012-09-18 18:48:40 -05:00
|
|
|
self(Write(str));
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
fn write_line(+str: ~str) {
|
2012-07-14 00:57:48 -05:00
|
|
|
self.write_str(str + ~"\n");
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn write_done() {
|
2012-09-18 18:48:40 -05:00
|
|
|
self(Done)
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
pub fn make_writer_factory(+config: config::Config) -> WriterFactory {
|
2012-08-06 14:34:08 -05:00
|
|
|
match config.output_format {
|
2012-09-18 18:48:40 -05:00
|
|
|
config::Markdown => {
|
2012-03-04 01:56:38 -06:00
|
|
|
markdown_writer_factory(config)
|
2012-03-01 16:21:14 -06:00
|
|
|
}
|
2012-09-18 18:48:40 -05:00
|
|
|
config::PandocHtml => {
|
2012-03-04 01:56:38 -06:00
|
|
|
pandoc_writer_factory(config)
|
2012-03-01 16:21:14 -06:00
|
|
|
}
|
|
|
|
}
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
fn markdown_writer_factory(+config: config::Config) -> WriterFactory {
|
|
|
|
fn~(+page: doc::Page) -> Writer {
|
2012-03-04 01:56:38 -06:00
|
|
|
markdown_writer(config, page)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
fn pandoc_writer_factory(+config: config::Config) -> WriterFactory {
|
|
|
|
fn~(+page: doc::Page) -> Writer {
|
2012-03-04 01:56:38 -06:00
|
|
|
pandoc_writer(config, page)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn markdown_writer(
|
2012-11-21 00:36:32 -06:00
|
|
|
+config: config::Config,
|
|
|
|
+page: doc::Page
|
2012-09-18 18:48:40 -05:00
|
|
|
) -> Writer {
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_local_filename(config, page);
|
2012-06-30 18:19:07 -05:00
|
|
|
do generic_writer |markdown| {
|
2012-08-24 17:28:43 -05:00
|
|
|
write_file(&filename, markdown);
|
2012-03-01 16:21:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-04 01:56:38 -06:00
|
|
|
fn pandoc_writer(
|
2012-11-21 00:36:32 -06:00
|
|
|
+config: config::Config,
|
|
|
|
+page: doc::Page
|
2012-09-18 18:48:40 -05:00
|
|
|
) -> Writer {
|
2012-09-21 21:37:57 -05:00
|
|
|
assert config.pandoc_cmd.is_some();
|
|
|
|
let pandoc_cmd = config.pandoc_cmd.get();
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_local_filename(config, page);
|
2012-03-01 16:21:14 -06:00
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let pandoc_args = ~[
|
2012-07-14 00:57:48 -05:00
|
|
|
~"--standalone",
|
|
|
|
~"--section-divs",
|
|
|
|
~"--from=markdown",
|
|
|
|
~"--to=html",
|
|
|
|
~"--css=rust.css",
|
2012-08-24 17:28:43 -05:00
|
|
|
~"--output=" + filename.to_str()
|
2012-06-29 18:26:56 -05:00
|
|
|
];
|
2012-03-01 16:21:14 -06:00
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
do generic_writer |markdown| {
|
2012-09-07 20:08:21 -05:00
|
|
|
use io::WriterUtil;
|
2012-03-01 16:21:14 -06:00
|
|
|
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("pandoc cmd: %s", pandoc_cmd);
|
|
|
|
debug!("pandoc args: %s", str::connect(pandoc_args, ~" "));
|
2012-03-01 16:21:14 -06:00
|
|
|
|
|
|
|
let pipe_in = os::pipe();
|
|
|
|
let pipe_out = os::pipe();
|
|
|
|
let pipe_err = os::pipe();
|
|
|
|
let pid = run::spawn_process(
|
2012-08-20 14:23:37 -05:00
|
|
|
pandoc_cmd, pandoc_args, &None, &None,
|
2012-03-01 16:21:14 -06:00
|
|
|
pipe_in.in, pipe_out.out, pipe_err.out);
|
|
|
|
|
2012-03-04 00:09:31 -06:00
|
|
|
let writer = io::fd_writer(pipe_in.out, false);
|
|
|
|
writer.write_str(markdown);
|
2012-03-01 16:21:14 -06:00
|
|
|
|
|
|
|
os::close(pipe_in.in);
|
|
|
|
os::close(pipe_out.out);
|
|
|
|
os::close(pipe_err.out);
|
|
|
|
os::close(pipe_in.out);
|
2012-03-06 16:19:10 -06:00
|
|
|
|
2012-11-28 22:34:40 -06:00
|
|
|
let (stdout_ch, stdout_po) = pipes::stream();
|
|
|
|
do task::spawn_sched(task::SingleThreaded) |move stdout_ch| {
|
|
|
|
stdout_ch.send(readclose(pipe_out.in));
|
2012-03-06 17:01:30 -06:00
|
|
|
}
|
|
|
|
|
2012-11-28 22:34:40 -06:00
|
|
|
let (stderr_ch, stderr_po) = pipes::stream();
|
|
|
|
do task::spawn_sched(task::SingleThreaded) |move stderr_ch| {
|
|
|
|
stderr_ch.send(readclose(pipe_err.in));
|
2012-03-06 17:01:30 -06:00
|
|
|
}
|
2012-11-28 22:34:40 -06:00
|
|
|
let stdout = stdout_po.recv();
|
|
|
|
let stderr = stderr_po.recv();
|
2012-03-01 16:21:14 -06:00
|
|
|
|
|
|
|
let status = run::waitpid(pid);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("pandoc result: %i", status);
|
2012-03-01 16:21:14 -06:00
|
|
|
if status != 0 {
|
2012-08-22 19:24:52 -05:00
|
|
|
error!("pandoc-out: %s", stdout);
|
|
|
|
error!("pandoc-err: %s", stderr);
|
2012-07-14 00:57:48 -05:00
|
|
|
fail ~"pandoc failed";
|
2012-03-01 16:21:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn readclose(fd: libc::c_int) -> ~str {
|
2012-03-06 16:19:10 -06:00
|
|
|
// Copied from run::program_output
|
2012-03-12 22:04:27 -05:00
|
|
|
let file = os::fdopen(fd);
|
2012-03-06 16:19:10 -06:00
|
|
|
let reader = io::FILE_reader(file, false);
|
2012-10-18 08:13:01 -05:00
|
|
|
let buf = io::with_bytes_writer(|writer| {
|
|
|
|
let mut bytes = [mut 0, ..4096];
|
|
|
|
while !reader.eof() {
|
|
|
|
let nread = reader.read(bytes, bytes.len());
|
|
|
|
writer.write(bytes.view(0, nread));
|
|
|
|
}
|
|
|
|
});
|
2012-03-06 16:19:10 -06:00
|
|
|
os::fclose(file);
|
2012-10-18 08:13:01 -05:00
|
|
|
str::from_bytes(buf)
|
2012-03-06 16:19:10 -06:00
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
fn generic_writer(+process: fn~(+markdown: ~str)) -> Writer {
|
2012-11-28 22:34:40 -06:00
|
|
|
let (setup_ch, setup_po) = pipes::stream();
|
|
|
|
do task::spawn |move process, move setup_ch| {
|
|
|
|
let po: comm::Port<WriteInstr> = comm::Port();
|
|
|
|
let ch = comm::Chan(&po);
|
|
|
|
setup_ch.send(ch);
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut markdown = ~"";
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut keep_going = true;
|
2012-03-01 00:26:28 -06:00
|
|
|
while keep_going {
|
2012-11-28 22:34:40 -06:00
|
|
|
match po.recv() {
|
2012-09-18 18:48:40 -05:00
|
|
|
Write(s) => markdown += s,
|
|
|
|
Done => keep_going = false
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
}
|
2012-09-19 00:43:54 -05:00
|
|
|
process(move markdown);
|
2012-03-01 00:26:28 -06:00
|
|
|
};
|
2012-11-28 22:34:40 -06:00
|
|
|
let ch = setup_po.recv();
|
2012-03-01 00:26:28 -06:00
|
|
|
|
2012-09-18 18:48:40 -05:00
|
|
|
fn~(+instr: WriteInstr) {
|
2012-03-01 00:26:28 -06:00
|
|
|
comm::send(ch, instr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-06 17:57:36 -06:00
|
|
|
fn make_local_filename(
|
2012-11-21 00:36:32 -06:00
|
|
|
+config: config::Config,
|
|
|
|
+page: doc::Page
|
2012-08-24 17:28:43 -05:00
|
|
|
) -> Path {
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_filename(config, page);
|
2012-08-24 17:28:43 -05:00
|
|
|
config.output_dir.push_rel(&filename)
|
2012-03-06 17:57:36 -06:00
|
|
|
}
|
2012-03-01 00:26:28 -06:00
|
|
|
|
2012-11-19 20:00:12 -06:00
|
|
|
pub fn make_filename(
|
2012-11-21 00:36:32 -06:00
|
|
|
+config: config::Config,
|
|
|
|
+page: doc::Page
|
2012-08-24 17:28:43 -05:00
|
|
|
) -> Path {
|
2012-03-04 02:23:54 -06:00
|
|
|
let filename = {
|
2012-08-06 14:34:08 -05:00
|
|
|
match page {
|
2012-09-18 18:48:40 -05:00
|
|
|
doc::CratePage(doc) => {
|
|
|
|
if config.output_format == config::PandocHtml &&
|
|
|
|
config.output_style == config::DocPerMod {
|
2012-07-14 00:57:48 -05:00
|
|
|
~"index"
|
2012-03-04 02:23:54 -06:00
|
|
|
} else {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert doc.topmod.name() != ~"";
|
2012-03-04 02:23:54 -06:00
|
|
|
doc.topmod.name()
|
|
|
|
}
|
|
|
|
}
|
2012-09-18 18:48:40 -05:00
|
|
|
doc::ItemPage(doc) => {
|
2012-07-14 00:57:48 -05:00
|
|
|
str::connect(doc.path() + ~[doc.name()], ~"_")
|
2012-03-04 02:23:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2012-08-06 14:34:08 -05:00
|
|
|
let ext = match config.output_format {
|
2012-09-18 18:48:40 -05:00
|
|
|
config::Markdown => ~"md",
|
|
|
|
config::PandocHtml => ~"html"
|
2012-03-04 02:23:54 -06:00
|
|
|
};
|
2012-03-06 17:57:36 -06:00
|
|
|
|
2012-08-24 17:28:43 -05:00
|
|
|
Path(filename).with_filetype(ext)
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_use_markdown_file_name_based_off_crate() {
|
|
|
|
let config = {
|
2012-08-24 17:28:43 -05:00
|
|
|
output_dir: Path("output/dir"),
|
2012-09-18 18:48:40 -05:00
|
|
|
output_format: config::Markdown,
|
|
|
|
output_style: config::DocPerCrate,
|
2012-09-04 15:29:32 -05:00
|
|
|
.. config::default_config(&Path("input/test.rc"))
|
2012-03-01 00:26:28 -06:00
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
let doc = test::mk_doc(~"test", ~"");
|
2012-09-18 18:48:40 -05:00
|
|
|
let page = doc::CratePage(doc.CrateDoc());
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_local_filename(config, page);
|
2012-08-24 17:28:43 -05:00
|
|
|
assert filename.to_str() == ~"output/dir/test.md";
|
2012-03-04 02:23:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
|
|
|
|
let config = {
|
2012-08-24 17:28:43 -05:00
|
|
|
output_dir: Path("output/dir"),
|
2012-09-18 18:48:40 -05:00
|
|
|
output_format: config::PandocHtml,
|
|
|
|
output_style: config::DocPerMod,
|
2012-09-04 15:29:32 -05:00
|
|
|
.. config::default_config(&Path("input/test.rc"))
|
2012-03-04 02:23:54 -06:00
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
let doc = test::mk_doc(~"", ~"");
|
2012-09-18 18:48:40 -05:00
|
|
|
let page = doc::CratePage(doc.CrateDoc());
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_local_filename(config, page);
|
2012-08-24 17:28:43 -05:00
|
|
|
assert filename.to_str() == ~"output/dir/index.html";
|
2012-03-04 02:23:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_name_mod_file_names_by_path() {
|
|
|
|
let config = {
|
2012-08-24 17:28:43 -05:00
|
|
|
output_dir: Path("output/dir"),
|
2012-09-18 18:48:40 -05:00
|
|
|
output_format: config::PandocHtml,
|
|
|
|
output_style: config::DocPerMod,
|
2012-09-04 15:29:32 -05:00
|
|
|
.. config::default_config(&Path("input/test.rc"))
|
2012-03-04 02:23:54 -06:00
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
let doc = test::mk_doc(~"", ~"mod a { mod b { } }");
|
2012-03-04 02:23:54 -06:00
|
|
|
let modb = doc.cratemod().mods()[0].mods()[0];
|
2012-09-18 18:48:40 -05:00
|
|
|
let page = doc::ItemPage(doc::ModTag(modb));
|
2012-03-06 17:57:36 -06:00
|
|
|
let filename = make_local_filename(config, page);
|
2012-08-24 17:28:43 -05:00
|
|
|
assert filename == Path("output/dir/a_b.html");
|
2012-03-04 01:56:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2012-09-21 20:10:45 -05:00
|
|
|
#[legacy_exports];
|
2012-11-21 00:36:32 -06:00
|
|
|
fn mk_doc(+name: ~str, +source: ~str) -> doc::Doc {
|
2012-06-30 18:19:07 -05:00
|
|
|
do astsrv::from_str(source) |srv| {
|
2012-03-04 02:23:54 -06:00
|
|
|
let doc = extract::from_srv(srv, name);
|
2012-12-03 19:08:52 -06:00
|
|
|
let doc = (path_pass::mk_pass().f)(srv, doc);
|
2012-03-04 02:23:54 -06:00
|
|
|
doc
|
2012-03-04 01:56:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-21 00:36:32 -06:00
|
|
|
fn write_file(path: &Path, +s: ~str) {
|
2012-09-07 20:08:21 -05:00
|
|
|
use io::WriterUtil;
|
2012-03-04 02:23:54 -06:00
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
match io::file_writer(path, ~[io::Create, io::Truncate]) {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(writer) => {
|
2012-03-04 02:23:54 -06:00
|
|
|
writer.write_str(s);
|
|
|
|
}
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Err(e) => fail e
|
2012-03-04 02:23:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-19 20:00:12 -06:00
|
|
|
pub fn future_writer_factory(
|
2012-09-18 18:48:40 -05:00
|
|
|
) -> (WriterFactory, comm::Port<(doc::Page, ~str)>) {
|
2012-08-27 16:22:25 -05:00
|
|
|
let markdown_po = comm::Port();
|
2012-10-03 16:38:01 -05:00
|
|
|
let markdown_ch = comm::Chan(&markdown_po);
|
2012-11-21 00:36:32 -06:00
|
|
|
let writer_factory = fn~(+page: doc::Page) -> Writer {
|
2012-11-28 22:34:40 -06:00
|
|
|
let (writer_ch, writer_po) = pipes::stream();
|
|
|
|
do task::spawn |move writer_ch| {
|
2012-03-04 01:56:38 -06:00
|
|
|
let (writer, future) = future_writer();
|
2012-11-28 22:34:40 -06:00
|
|
|
writer_ch.send(move writer);
|
2012-08-13 21:06:57 -05:00
|
|
|
let s = future::get(&future);
|
2012-03-04 01:56:38 -06:00
|
|
|
comm::send(markdown_ch, (page, s));
|
|
|
|
}
|
2012-11-28 22:34:40 -06:00
|
|
|
writer_po.recv()
|
2012-03-04 01:56:38 -06:00
|
|
|
};
|
|
|
|
|
2012-09-19 00:43:54 -05:00
|
|
|
(move writer_factory, markdown_po)
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
|
|
|
|
2012-09-18 18:48:40 -05:00
|
|
|
fn future_writer() -> (Writer, future::Future<~str>) {
|
2012-08-28 08:43:58 -05:00
|
|
|
let (chan, port) = pipes::stream();
|
2012-09-19 00:43:54 -05:00
|
|
|
let writer = fn~(move chan, +instr: WriteInstr) {
|
2012-08-28 08:43:58 -05:00
|
|
|
chan.send(copy instr);
|
2012-03-01 00:26:28 -06:00
|
|
|
};
|
2012-09-19 00:43:54 -05:00
|
|
|
let future = do future::from_fn |move port| {
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut res = ~"";
|
2012-03-09 18:11:56 -06:00
|
|
|
loop {
|
2012-08-28 08:43:58 -05:00
|
|
|
match port.recv() {
|
2012-09-18 18:48:40 -05:00
|
|
|
Write(s) => res += s,
|
|
|
|
Done => break
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|
2012-03-26 05:39:20 -05:00
|
|
|
}
|
|
|
|
res
|
2012-03-01 00:26:28 -06:00
|
|
|
};
|
2012-09-19 00:43:54 -05:00
|
|
|
(move writer, move future)
|
2012-03-01 00:26:28 -06:00
|
|
|
}
|