Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ iron = "0"
log = "0"
markdown = "0"
mowl = "1"
lazy_static = "*"
rayon = "0"
uuid = { version = "0.5", features = ["v5"] }
13 changes: 9 additions & 4 deletions src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ global_settings:
args:
- input_directory:
default_value: .
help: The directory containing the markdown files to use
help: The directory containing the markdown files to use.
required: true
value_name: INPUT
- output_directory:
default_value: output
help: The directory where the HTML output is generated
help: The directory where the HTML output is generated.
long: output-directory
short: o
value_name: PATH
- verbose:
help: Set the verbosity level (maximum 4x `v`)
help: Set the verbosity level (maximum 4x `v`).
short: v
multiple: true
- www:
help: Enable integrated HTTP server to serve contents from output directory
help: Enable integrated HTTP server to serve contents from output directory.
long: www
short: w
- file_directory:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since input and output directory we have now additionally a file directory and as a user I would have no idea wherefore this is and the description is not really helpful.

default_value: files
help: The directory where files are stored.
short: f
long: file-directory
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::io;
use glob;
use iron::error::HttpError;
use iron::error::{HttpError, IronError};

error_chain! {
foreign_links {
Expand Down
160 changes: 134 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ extern crate markdown;
extern crate mowl;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lazy_static;
extern crate uuid;
extern crate rayon;

Expand All @@ -25,16 +27,16 @@ use markdown::to_html;
use iron::prelude::*;
use iron::status;
use iron::headers::ContentType;
use iron::mime::Mime;


use std::fs::{self, canonicalize, create_dir_all, File};
use std::fs::{self, canonicalize, create_dir_all, File, OpenOptions};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::io::prelude::*;
use std::str;
use filehash::Filehash;
use rayon::iter::{ParallelIterator, IntoParallelRefMutIterator};

static SHA_FILE: &str = ".files.sha";

pub struct InputPaths {
path: PathBuf,
hash: String,
Expand Down Expand Up @@ -114,6 +116,21 @@ impl InputPaths {
}
}

lazy_static! {
static ref PDF_MIME: Mime = "application/pdf".parse::<Mime>().unwrap();
static ref DOC_MIME: Mime = "application/msword".parse::<Mime>().unwrap();
static ref ODA_MIME: Mime = "application/oda".parse::<Mime>().unwrap();
static ref ZIP_MIME: Mime = "application/zip".parse::<Mime>().unwrap();
static ref WAV_MIME: Mime = "audio/x-wav".parse::<Mime>().unwrap();
static ref CSS_MIME: Mime = "text/css".parse::<Mime>().unwrap();
static ref GIF_MIME: Mime = "image/gif".parse::<Mime>().unwrap();
static ref MPG_MIME: Mime = "video/mpeg".parse::<Mime>().unwrap();
static ref AVI_MIME: Mime = "video/x-msvideo".parse::<Mime>().unwrap();
static ref PNG_MIME: Mime = "image/png".parse::<Mime>().unwrap();
static ref JPG_MIME: Mime = "image/jpeg".parse::<Mime>().unwrap();
static ref SHA_FILE: &'static str = ".files.sha";
}

#[derive(Default)]
/// Global processing structure
pub struct Wiki {
Expand All @@ -139,7 +156,6 @@ impl Wiki {

Ok(())
}

/// Reads all markdown files recursively from a given directory.
/// Clears the current available input_paths
pub fn read_from_directory(&mut self, directory: &str) -> Result<()> {
Expand All @@ -161,7 +177,6 @@ impl Wiki {

Ok(())
}

/// Print absolute path of all added md files
pub fn list_current_input_paths(&self) {
info!("Found the following markdown files:");
Expand All @@ -184,7 +199,7 @@ impl Wiki {
fs::create_dir(output_directory)?;
}

let sha_file_path = PathBuf::from(output_directory).join(SHA_FILE);
let sha_file_path = PathBuf::from(output_directory).join(*SHA_FILE);
let sha_file = sha_file_path.to_str()
.ok_or_else(|| "Unable to stringify the sha file path.")?;

Expand Down Expand Up @@ -225,20 +240,92 @@ impl Wiki {
Ok(())
}

/// Add a directory for storing files to the generated html sites or read stored
/// files of existing filestorage. Afterwards file links will be added to the
/// generated html site.
pub fn read_files(&mut self, file_folder: &str, output: &str) -> Result<()> {

//create the default file path
let output_path = PathBuf::from(output);
let file_directory = PathBuf::from(output).join(file_folder);

if !Path::new(file_folder).exists(){
info!("Creating directory for file input: {:?}.", file_directory.to_str());
fs::create_dir(&file_directory);
}

for path in &self.input_paths{
let mut count = 0;

//create the path for the html site or just find it
let page_files_path = file_directory.join(&path.path).to_str().ok_or_else(||
"Couldn't create Path to html file!")?.replace(".md","");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message is a bit weird. It would be also better to break the lines here for better reading.

file_directory.join(&path.path)
             .to_str()
             .ok_or_else(|| "Couldn't create Path to html file!")?
             .replace(".md","");


if !PathBuf::from(page_files_path.as_str()).exists(){
info!("Creating directory for {}'s files: {}.", path.path.to_str().ok_or_else(|| "Path not found!")?,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good when specifying which path can't be found. For this we should rework the error messages for the whole project, there are much things in like this ^^

page_files_path.as_str());
fs::create_dir_all(page_files_path.as_str());
}

//add the path
let file_path = Path::new(page_files_path.as_str());
//read all the files
let files = file_path.read_dir()?;

//now attach the files to the html sites folder
for entry in files {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can get rid of the extra var but write
for entry in file_path.read_dir()? { ...

let current_entry = match entry {
Ok(entry) => entry,
_ => panic!("Couldn't read the path!"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better return an error with a meaningful description here.

};

let link = format!(
"\n<a href='http://localhost:30000/files/{}/{}'>{}</a><br>\n",
path.path.to_str().ok_or_else(|| "Path not found!")?.replace(".md", ""),
current_entry.file_name().to_str().ok_or_else(|| "Entry is corrupted!")?.replace("\n","."),
current_entry.file_name().to_str().ok_or_else(|| "Entry is corrupted!")?
);
let mut html_file = OpenOptions::new().read(true).write(true).create(true).
open(output_path.join(&path.path).to_str().ok_or_else(|| "Entry is corrupted!")?.
replace(".md", ".html"))?;

let mut buffer = String::new();

html_file.read_to_string(&mut buffer);
buffer += &link.as_str();
info!("Creating link to {:?} for {:?}", current_entry.file_name(), path.path.to_str()
.ok_or_else(|| "Entry is corrupted!")?.replace(".md", ".html"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info!("Creating link to {:?} for {:?}",
      current_entry.file_name(),
      path.path.to_str()
               .ok_or_else(|| "Entry is corrupted!")?
               .replace(".md", ".html"));

html_file.write((&buffer).as_bytes());
count += 1;
}
//check if there are no files attached
if count == 0 {
info!("No files found so far for {}. Simply add your files to the folders in 'files'.",
path.path.to_str().ok_or_else(|| "Entry is corrupted!")?)
}
}
Ok(())
}

/// Create an HTTP server serving the generated files
pub fn serve(&self, output_directory: &str) -> Result<()> {

// Create a default listening address
let addr = "localhost:5000";
let addr = "localhost:30000";
info!("Listening on {}", addr);

// Moving the data into the closure
let output_directory_string = output_directory.to_owned();

// Create a new iron instance
Iron::new(move |request: &mut Request| {
// The owned path needs to created from the cloned string
let mut path = PathBuf::from(output_directory_string.clone());

///to load files in browser
fn get_file(mime_type: &Mime, body: File) -> iron::Response {
let mut resp = Response::with((status::Ok, body));
resp.headers.set(ContentType(mime_type.to_owned()));
resp
}
let mut path = PathBuf::from(&output_directory_string);
// Create the full path
for part in request.url.path() {
path.push(part);
Expand All @@ -251,27 +338,48 @@ impl Wiki {
path.push("index.html");
}

let mut f = match File::open(path) {
if !path.exists() {
return Ok(Response::with((ContentType::html().0,
status::NotFound, include_str!("html/404.html"))));
}
let mut f = match File::open(&path) {
Ok(v) => v,
_ => return Ok(Response::with((ContentType::html().0,
status::NotFound,
include_str!("html/404.html")))),
};

let mut buffer = String::new();
match f.read_to_string(&mut buffer) {
Ok(v) => v,
_ => return Ok(Response::with((ContentType::html().0,
status::InternalServerError,
include_str!("html/500.html")))),
};

// Content type needs to be determined from the file rather
// than assuming html
Ok(Response::with((ContentType::html().0, status::Ok, buffer)))

};

match path.to_str(){
Some(name) => {

if name.contains(".pdf") {return Ok(get_file(&(*PDF_MIME), f))};
if name.contains(".doc") {return Ok(get_file(&(*DOC_MIME), f))};
if name.contains(".oda") {return Ok(get_file(&(*ODA_MIME), f))};
if name.contains(".zip") {return Ok(get_file(&(*ZIP_MIME), f))};
if name.contains(".wav") {return Ok(get_file(&(*WAV_MIME), f))};
if name.contains(".css") {return Ok(get_file(&(*CSS_MIME), f))};
if name.contains(".mp") {return Ok(get_file(&(*MPG_MIME), f))};
if name.contains(".avi") {return Ok(get_file(&(*AVI_MIME), f))};
if name.contains(".png") {return Ok(get_file(&(*PNG_MIME), f))};
if name.contains(".jp") {return Ok(get_file(&(*JPG_MIME), f))};
if name.contains(".gif") {return Ok(get_file(&(*GIF_MIME), f))};

if name.contains(".html") {
let mut buffer = String::new();
match f.read_to_string(&mut buffer) {
Ok(v) => v,
_ => return Ok(Response::with((ContentType::html().0,
status::InternalServerError,
include_str!("html/500.html")))),
};
return Ok(Response::with((ContentType::html().0, status::Ok, buffer)))
}

else {Ok(Response::with((status::Ok, f)))}
},
_ => panic!("Invalid Path."),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here also return an Error.

}
}).http(addr)?;

Ok(())
}
}
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,16 @@ fn run() -> Result<()> {

let enable_httpd = matches.is_present("www");

let file_directory = matches.value_of("file_directory")
.ok_or_else(|| "CLI parameter 'file_directory' missing")?;

// Do first processing steps
let mut wiki = Wiki::new();

wiki.init_logging(log_level)?;
wiki.read_from_directory(input_directory)?;
wiki.read_content_from_current_paths(input_directory, output_directory)?;
wiki.read_files(file_directory, output_directory);
wiki.create_index_tree(output_directory)?;

if enable_httpd {
Expand Down
Binary file removed tests/example_md/real_md/example-image.jpg
Binary file not shown.
Empty file removed tests/example_md/real_md/test3.xml
Empty file.