~/selfhut

0545f2a75112681c672deaa21abc769ac4b638b5 — Arthur Melton 8133eaae 2 years ago
start of stuff working
M .gitignore => .gitignore +14 -1
@@ 1,1 1,14 @@

/target
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

M Cargo.toml => Cargo.toml +7 -1
@@ 6,6 6,12 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dirs = "4.0.0"
git2 = "0.15.0"
lazy_static = "1.4.0"
markdown = "0.3.0"
rocket = "0.4.11"
rocket = "0.5.0-rc"
rocket_dyn_templates = {version = "0.1.0-rc.2", features=["handlebars"]}
serde = "1.0.145"
serde_derive = "1.0.145"
toml = "0.5.9"

A Rocket.toml +2 -0
@@ 0,0 1,2 @@

[default]
template_dir = "templates"

A src/config.rs +32 -0
@@ 0,0 1,32 @@

use lazy_static::lazy_static;
use serde_derive::{Serialize, Deserialize};
use std::fs;

lazy_static! {
    pub static ref CONFIG: Config = {
        let mut config = dirs::config_dir().expect("Could not get the config directory");
        config.push("git-server");
        config.push("git-server.toml");
        if config.exists() {
           let config:Config = toml::from_str(&String::from_utf8_lossy(&fs::read(config.as_path()).expect("Failed to read the config file"))).expect("Could not parse the toml in the config file");
           config
        }
        else {
            let config_struct = Config {
                name: "Example User".to_string(),
                description: "This is billy and he loves his [website](https://example.com)!!!".to_string()
            };
            config.pop();
            let _ = fs::create_dir_all(config.clone());
            config.push("git-server.toml");
            fs::write(config, toml::to_string(&config_struct).expect("Failed to stringify config")).expect("Failed to set the config content");
            config_struct
        }
    };
}

#[derive(Serialize, Deserialize)]
pub struct Config {
    pub name: String,
    pub description: String,
}

A src/git/mod.rs +1 -0
@@ 0,0 1,1 @@

pub mod repos;

A src/git/repos.rs +38 -0
@@ 0,0 1,38 @@

use std::fs;
use serde_derive::Serialize;

pub fn get_repos() -> Option<Vec<Repo>> {
    let home = dirs::home_dir()?;
    Some(fs::read_dir(home.clone()).ok()?
        .filter(|path| path.is_ok())
        .map(|path| path.unwrap())
        .filter(|path| path.file_type().is_ok())
        .filter(|path| path.file_type().unwrap().is_dir())
        .map(|path| path.file_name().into_string())
        .filter(|path| path.is_ok())
        .map(|path| path.unwrap())
        .filter(|path| !path.starts_with("."))
        .filter(|path| path.ends_with(".git"))
        .map(|path| {
            let mut description_path = home.clone();
            description_path.push(path.clone());
            description_path.push("DESCRIPTION");
            let description = match fs::read(description_path.clone()) {
                Ok(content) => {
                    String::from_utf8_lossy(&content).parse().unwrap_or("".to_string())
                },
                Err(_) => "".to_string()
            };
            Repo {
                name: path[0..path.len() - 4].to_string(),
                description
            }
        })
        .collect::<Vec<Repo>>())
}

#[derive(Serialize, Clone)]
pub struct Repo {
    name: String,
    description: String,
}

A src/index.rs +22 -0
@@ 0,0 1,22 @@

use crate::git::repos::get_repos;
use crate::config::CONFIG;

use rocket_dyn_templates::{Template, context};

#[get("/?<page>")]
pub fn index(page: Option<usize>) -> Option<Template> {
    let repos = get_repos()?;
    let page = page.unwrap_or(0);
    let last_item = if repos.len() > (page+1)*25 {
        (page+1)*25
    }
    else {
        repos.len()
    };
    Some(Template::render("index", context! {
        title: "Me",
        user: CONFIG.name.clone(),
        description: markdown::to_html(&CONFIG.description.clone()),
        repos: repos[page*25..last_item].to_vec(),
    }))
}

M src/main.rs => src/main.rs +12 -2
@@ 1,3 1,13 @@

fn main() {
    println!("Hello, world!");
#[macro_use] extern crate rocket;
mod git;
mod index;
mod config;

use rocket_dyn_templates::Template;

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index::index])
        .attach(Template::fairing())
}

A templates/index.html.hbs +18 -0
@@ 0,0 1,18 @@

{{#*inline "page"}}

<section id="hello">
    <h1>{{ user }}!</h1>
    <h2>{{{ description }}}</h2>
    <h3>Here are your repos:</h3>
    <ul>
    {{#each repos}}
        <div>  
            <a href="/{{this.name}}">{{ this.name }}</a>
            <p>{{ this.description }}</p>
        </div>
    {{/each}}
    </ul>
</section>

{{/inline}}
{{> layout}}

A templates/layout.html.hbs +9 -0
@@ 0,0 1,9 @@

<!doctype html>
<html>
  <head>
    <title>{{ title }} :: Arthur Melton Git</title>
  </head>
  <body>
    {{~> page}}
  </body>
</html>