~evan-hoose/SSSSS

1abb589a6ccb558fb035064531b2d46637a39117 — Evan 1 year, 1 month ago
On branch master

Initial commit
 Changes to be committed:
	new file:   README.md
	new file:   S5.png
	new file:   s5-generate.sh
	new file:   s5-render
	new file:   s5-render.rs
5 files changed, 226 insertions(+), 0 deletions(-)

A README.md
A S5.png
A s5-generate.sh
A s5-render
A s5-render.rs
A  => README.md +109 -0
@@ 1,109 @@
#SSSSS

*Stupid*
*Simple*
*Static*
*Site*
*Starter* 

IMPORTANT: SSSSS requires that a markdown renderer be installed, and be 
executable from a shell as 'markdown'. SSSSS assumes that the renderer will
only render exactly what is in the file, and not add anything like \<body> 
tags.

In addition to this assumption, SSSSS assumes that

```
$markdown file.md
```
will output the generated html to stdout.

EQUALLY IMPORTANT: SSSSS assumes that it can use 'sh' in both scripts and 'cat'
be available in s5-render.py . What this means is that this won't work on 
Windows. I don't really care about this, and wont fix it personally. I wrote
this as a quick and dirty tool for myself, and I don't use Windows for anything 
other than the occasional gaming. If somebody else wants to add Windows support,
open a PR and I'll probably merge it. 

LESS IMPORTANT, BUT STILL IMPORTANT: Many (most?) sites may still require some 
sort of manual modification in order to add things like tabbing at the top. 
This tool is not a all in one site generater, but simply a helper tool to 
remove _some_ of the drudge work in setting up a simple site. I may further
extend this to the point where it does do some more things automatically, but
this is subject to my time/interest.

##About        
This program will take a directory structure consisting of directories with
images and markdown files and render it to an html website.

The top level directory will include templates for:

* The html \<!doctype>, \<html> and \<head> tags.
* The document header. (\<body> and whatever html you want to be included in the
  header of your website.)
* The document/html footer. (Your html for the footer, followed by \</body> and
  \</head>.)


When SSSSS renders a given Markdown file it will place the templates and
markdown in this order:

1. html-header.html
2. document-header.html
3. input.md
4. footer.html

There must be exactly one markdown file in each directory of the structure that
SSSSS is called on. SSSSS will take this:

DemoSite
|- html-header.html
|- document-header.html
|- footer.html
|-top
| |- index.md
| |-about
| | |- about.md
| |-blog
| | |- blog.md
| |-other
| | |- other.md

and turn it to:

DemoSite
|- html-header.html
|- document-header.html
|- footer.html
|-top
| |- index.md
| |- index.html
| |-about
| | |- about.md
| | |- index.html
| |-blog
| | |- blog.md
| | |- index.html
| |-other
| | |- other.md
| | |- index.html

Although it seems strange that it would render every markdown file to a file
called index.html, there are actually two reasons. First, it allows you to have
nice looking URI's without needing to do any extra configuration in your 
webserver. Second, it allows for less and simpler code, which makes this easier
to hack on for anyone who feels interested.

##Tutorial

So you read through all that and still want to try this out? Cool. Start by
cloning this repository. After you have cloned the repository, move the scripts
s5-generate.sh and s5-render.py into your path somewhere.

Next, run  
    s5-generate.sh HelloWorld

This will create a new site called, you guessed it, HelloWorld. Move into the
HelloWorld Directory you just created, you should see the template files
mentioned above, and a directory called top. The interior of top is where your
site will start.

A  => S5.png +0 -0
A  => s5-generate.sh +11 -0
@@ 1,11 @@
#! /bin/sh
#Make a directory to hold the site
mkdir $1

#Create templates for templates
echo "<doctype html>\n<head>\n<title>$1</title>\n<style>\n</style>\n</head>" > $1/html-header.html
echo "<body>" > $1/document-header.html
echo "</body>" > $1/footer.html

#This is the top level of the actual site
mkdir $1/top

A  => s5-render +0 -0
A  => s5-render.rs +106 -0
@@ 1,106 @@
use std::ffi::OsStr;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    //This is the path to the file that we use as the document header.
    let document_header = fs::canonicalize("./document-header.html").unwrap();
    //use the absolute path for the current directory
    render(fs::canonicalize("./").unwrap(), document_header);
}

//render() will descend through the directory structure, rendering *.md to
//index.html as it goes.
//
//Didn't think I needed to say this, but I apparently forgot.
//
//THIS CODE USES RECURSION.
//
//IT WON'T WORK IF YOU PUT IT IN main(). Stupid.
fn render(directory: PathBuf,mut document_header: PathBuf) {
    
    //iterate over files in the current directory. We call clone on directory
    //so that we can use it again while testing for new header files.
    for name in fs::read_dir(directory.clone()).unwrap() {
        //Check if there is a file called document-header.html in the current
        //directory. If so, use it instead of the one at the top.
        //Subdirectories will inherit the new document-header.
        //
        //This functionality is so that tabbing can be implemented 
        //automatically. See README.md at https://git.sr.ht/~evan-hoose/sssss
        //for more details/usage warnings.
        for file in fs::read_dir(directory.clone()).unwrap() {
            //do this here so we don't have to do it every time below.
            let file = file.unwrap();
            let file_path = PathBuf::from(file.path());
            //Create a PathBuf of the file name of file_path. This calls clone 
            //so that we can just set document_header to file_path if the name 
            //matches.
            let file_name = &file_path.file_name();
            if Some(OsStr::new("document-header.html")) == *file_name {
                document_header = file_path;
            }
        }

        //returns a pathbuf for whatever file we are on
        let path = PathBuf::from(name.unwrap().path());
        //Let us find the metadata for path, so that we can later test if it's
        //a directory or some other kind of file.
        let file_metadata = fs::metadata(path.as_path()).unwrap();
        let file_type = file_metadata.file_type();

        //If it's a dir, continue down. Otherwise, if it's an md file, render
        //it to html, while using the headers and footers at the top.
        //
        //Also, skip the .git directory. It breaks the attempts to look at file
        //metadata. Yes, I really should just write error handling. However,
        //I'm stupid and can't figure it out.
        if file_type.is_dir() && path.clone().as_os_str() != OsStr::new(".git") {
            render(path, document_header.clone()) //If the path is a dir, continue down.
        } else {
            //If it's not a dir, it must be a file
            if path.extension() == Some(OsStr::new("md")) {
                //leads to index.html in the same directory as path
                //We declare it here instead of above, because why use it before we
                //need it.
                let mut write_path = path.clone();
                write_path.set_file_name("index.html");
                let markdown_path = path.as_path();

                //Shell magic. shell() takes an &str and executes it as if it
                //were being run in the systems /bin/sh. May make it work for
                //Windows some day, but I don't care that much.

                //cat ./html-header.html > $write_path
                let append_html_header =
                    format!("cat ./html-header.html > {}", write_path.display());
                shell(&append_html_header);
                //cat ./document-header.html >> $write_path
                let append_doc_header =
                    format!("cat {} >> {}", document_header.display(), write_path.display());
                shell(&append_doc_header);
                //markdown $markdown_path >> $write_path
                let append_markdown = format!(
                    "markdown {} >> {}",
                    markdown_path.display(),
                    write_path.display()
                );
                shell(&append_markdown);
                //cat ./document-footer.html >> $write_path
                let append_footer =
                    format!("cat ./document-footer.html >> {}", write_path.display());
                shell(&append_footer);
            }
        }
    } //This is where the for loop ends
}

fn shell(command: &str) {
    let _status = Command::new("/bin/sh")
        .arg("-c")
        .arg(&command)
        .status()
        .expect("Unable to execute shell");

}