<commit_before>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate core;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::collections::HashMap;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;
use rustc_serialize::json::{self, ToJson, Json};
use std::fmt::Display;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [--json] [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
    flag_json: bool,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[..]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[..]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        let mut output = vec![];
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
            let detected = find_moves(&repo, old.clone(), new.clone()).unwrap();
            for item in detected {
                output.push(item);
            }
        }
        if args.flag_json {
            make_json(output);
        } else {
            make_output(output);
        }
    }
}

fn make_output(output: Vec<Output>) {
    println!("make_output: output.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
            println!("\tnew_filename={}",       output[i].new_filename);
            println!("\told_filename={}",       output[i].old_filename);
    }
}

fn make_json(output: Vec<Output>) {
    println!("{}", json::encode(&output).unwrap());
}

#[derive(Debug, PartialEq, Eq)]
enum FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // 'origin' is wrapped in pipes to ease displaying space characters.
    print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
             line.old_lineno(), line.new_lineno(), line.content_offset(),
             line.origin(), str::from_utf8(line.content()).unwrap());
}

fn dump_diffdelta(delta: &DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn dump_diffhunk(hunk: &DiffHunk) {
    println!("hunk: old_start={} old_lines={} new_start={} new_lines={} header={}",
            hunk.old_start(), hunk.old_lines(),
            hunk.new_start(), hunk.new_lines(),
            str::from_utf8(hunk.header()).unwrap());
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    let trim = regex!(r"^[\s]+|[\s]+$");
    let result = remove_whitespace.replace_all(key.as_slice(), "");
    trim.replace_all(result.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: Path,
    key: String,
    state: FoundState,
    start_position: u32,
    line_count: u32,
}

fn find_additions_and_deletions(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

    let mut line_count: u32 = 0;
    let mut start_position: u32 = 0;

    // Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
    // It's a bit weird, but I think it will provide the necessary information.
    diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        // if delta.nfiles() != 2 {
        //     // This is diff with only one side, and thus can't have a move.
        //     return true;
        // }
        // assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files. Found {} files.", delta.nfiles());

        // Thinking:
        //  * If is not a hunk, keep going.
        //  * If it's a hunk, do regex magic.
        //  * Stick regex output into a hashmap as a hash.
        //  * Later, we will iterate through and output pased on the values.
        // Filter out all the boring context lines.
        // If we're not interested in this line just return since it will iterate to the next.
        if maybe_hunk.is_none() { return true }; // Return early.

        //dump_diffline(&line);
        //dump_diffdelta(&delta);
        //dump_diffhunk(&maybe_hunk.unwrap());

        old_path = match delta.old_file().path() {
            Some(path) => path,
            None => return false,
        };
        new_path = match delta.new_file().path() {
            Some(path) => path,
            None => return false,
        };

        match line.origin() {
            // Additions
            '+' | '>' => {
                added.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for added"));

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                        line_count = 0;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Addition => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Addition;
                true
            },
            // Deletions
            '-' | '<' => {
                deleted.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for deleted"));

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                        line_count = 0;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Deletion => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Deletion;
                true
            },
            // Other
            _         => {
                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
        }
    });

    // Grab last one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn path_to_string(path: Path) -> String {
    String::from_utf8(path.into_vec()).unwrap()
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, git2::Error> {
    let old_tree = try!(old.tree());
    let new_tree = try!(new.tree());
    // Build up a diff of the two trees.
    let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let founds: Vec<Found> = find_additions_and_deletions(diff);

    let mut moves: Vec<Output> = Vec::new();
    let mut map: HashMap<String, Found> = HashMap::new();

    for f in founds {
        if f.key.len() == 0 { continue; }

        if map.contains_key(&f.key) {
            let q = map.get(&f.key).unwrap();

            // If both states are added, there are no moves.
            // assert!(f.state != q.state, format!("States {:?}, {:?}. Should be Addition/Deletion ", f.state, q.state));
            if (f.state == q.state) {
                return Ok(Vec::<Output>::new())
            }

            let output: Output;

            match f.state {
                FoundState::Added => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: path_to_string(q.filename.clone()),
                        new_filename: path_to_string(f.filename.clone()),
                        origin_line: q.start_position,
                        destination_line: f.start_position,
                        num_lines: f.line_count,
                    };
                },
                FoundState::Deleted => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: path_to_string(f.filename.clone()),
                        new_filename: path_to_string(q.filename.clone()),
                        origin_line: f.start_position,
                        destination_line: q.start_position,
                        num_lines: f.line_count,
                    };
                },
            }

            moves.push(output);
        } else {
            map.insert(f.key.clone(), f);
        }
    }

    return Ok(moves);
}

#[derive(Debug, RustcEncodable)]
struct Output {
    old_commit: TransitOid,
    new_commit: TransitOid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}

#[derive(Debug)]
struct TransitOid(Oid);
impl Display for TransitOid {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        Display::fmt(&self.0, f)
    }
}

impl rustc_serialize::Encodable for TransitOid {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_str(&format!("{}", self)[..])
    }
}
<commit_msg>Prune empty moves<commit_after>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate core;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::collections::HashMap;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;
use rustc_serialize::json::{self, ToJson, Json};
use std::fmt::Display;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [--json] [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
    flag_json: bool,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[..]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[..]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        let mut output = vec![];
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
            let detected = find_moves(&repo, old.clone(), new.clone()).unwrap();
            for item in detected {
                if item.num_lines == 0 { continue };
                output.push(item);
            }
        }
        if args.flag_json {
            make_json(output);
        } else {
            make_output(output);
        }
    }
}

fn make_output(output: Vec<Output>) {
    println!("make_output: output.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
            println!("\tnew_filename={}",       output[i].new_filename);
            println!("\told_filename={}",       output[i].old_filename);
    }
}

fn make_json(output: Vec<Output>) {
    println!("{}", json::encode(&output).unwrap());
}

#[derive(Debug, PartialEq, Eq)]
enum FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // 'origin' is wrapped in pipes to ease displaying space characters.
    print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
             line.old_lineno(), line.new_lineno(), line.content_offset(),
             line.origin(), str::from_utf8(line.content()).unwrap());
}

fn dump_diffdelta(delta: &DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn dump_diffhunk(hunk: &DiffHunk) {
    println!("hunk: old_start={} old_lines={} new_start={} new_lines={} header={}",
            hunk.old_start(), hunk.old_lines(),
            hunk.new_start(), hunk.new_lines(),
            str::from_utf8(hunk.header()).unwrap());
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    let trim = regex!(r"^[\s]+|[\s]+$");
    let result = remove_whitespace.replace_all(key.as_slice(), "");
    trim.replace_all(result.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: Path,
    key: String,
    state: FoundState,
    start_position: u32,
    line_count: u32,
}

fn find_additions_and_deletions(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

    let mut line_count: u32 = 0;
    let mut start_position: u32 = 0;

    // Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
    // It's a bit weird, but I think it will provide the necessary information.
    diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        // if delta.nfiles() != 2 {
        //     // This is diff with only one side, and thus can't have a move.
        //     return true;
        // }
        // assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files. Found {} files.", delta.nfiles());

        // Thinking:
        //  * If is not a hunk, keep going.
        //  * If it's a hunk, do regex magic.
        //  * Stick regex output into a hashmap as a hash.
        //  * Later, we will iterate through and output pased on the values.
        // Filter out all the boring context lines.
        // If we're not interested in this line just return since it will iterate to the next.
        if maybe_hunk.is_none() { return true }; // Return early.

        //dump_diffline(&line);
        //dump_diffdelta(&delta);
        //dump_diffhunk(&maybe_hunk.unwrap());

        old_path = match delta.old_file().path() {
            Some(path) => path,
            None => return false,
        };
        new_path = match delta.new_file().path() {
            Some(path) => path,
            None => return false,
        };

        match line.origin() {
            // Additions
            '+' | '>' => {
                added.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for added"));

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                        line_count = 0;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Addition => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.new_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Addition;
                true
            },
            // Deletions
            '-' | '<' => {
                deleted.push_str(str::from_utf8(line.content())
                    .ok().expect("Couldn't parse line content for deleted"));

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                        line_count = 0;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                    State::Deletion => {
                        line_count += 1;
                    },
                    State::Other => {
                        line_count = 1;
                        start_position = match line.old_lineno() {
                            Some(lineno) => lineno,
                            None => return false, // Can't be a move if deleted.
                        }
                    },
                }

                state = State::Deletion;
                true
            },
            // Other
            _         => {
                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            start_position: start_position,
                            line_count: line_count,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
        }
    });

    // Grab last one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    start_position: start_position,
                    line_count: line_count,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn path_to_string(path: Path) -> String {
    String::from_utf8(path.into_vec()).unwrap()
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, git2::Error> {
    let old_tree = try!(old.tree());
    let new_tree = try!(new.tree());
    // Build up a diff of the two trees.
    let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let founds: Vec<Found> = find_additions_and_deletions(diff);

    let mut moves: Vec<Output> = Vec::new();
    let mut map: HashMap<String, Found> = HashMap::new();

    for f in founds {
        if f.key.len() == 0 { continue; }

        if map.contains_key(&f.key) {
            let q = map.get(&f.key).unwrap();

            // If both states are added, there are no moves.
            // assert!(f.state != q.state, format!("States {:?}, {:?}. Should be Addition/Deletion ", f.state, q.state));
            if (f.state == q.state) {
                return Ok(Vec::<Output>::new())
            }

            let output: Output;

            match f.state {
                FoundState::Added => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: path_to_string(q.filename.clone()),
                        new_filename: path_to_string(f.filename.clone()),
                        origin_line: q.start_position,
                        destination_line: f.start_position,
                        num_lines: f.line_count,
                    };
                },
                FoundState::Deleted => {
                    output = Output {
                        old_commit: TransitOid(old.id()),
                        new_commit: TransitOid(new.id()),
                        old_filename: path_to_string(f.filename.clone()),
                        new_filename: path_to_string(q.filename.clone()),
                        origin_line: f.start_position,
                        destination_line: q.start_position,
                        num_lines: f.line_count,
                    };
                },
            }

            moves.push(output);
        } else {
            map.insert(f.key.clone(), f);
        }
    }

    return Ok(moves);
}

#[derive(Debug, RustcEncodable)]
struct Output {
    old_commit: TransitOid,
    new_commit: TransitOid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}

#[derive(Debug)]
struct TransitOid(Oid);
impl Display for TransitOid {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        Display::fmt(&self.0, f)
    }
}

impl rustc_serialize::Encodable for TransitOid {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_str(&format!("{}", self)[..])
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate colored;
extern crate tdo_core;
extern crate tdo_export;

#[macro_use]
mod macros;
mod cli;
mod filesystem;

use std::env;
use colored::*;
use clap::Shell;
mod subcommands;
use std::process::exit;
use tdo_core::{tdo, error};

#[allow(unused_variables)]
fn main() {
    // initialize the clap App handle
    // let yml = load_yaml!("cli.yml");
    let app = cli::cli().get_matches();

    let save_path = match env::home_dir() {
        Some(path) => path.join(".tdo/list.json"),
        None => {
            errorprint!("You seem to have no home directory. Unfortunately this is required \
                      in order to use tdo.");
            exit(1);
        }
    };
    let mut tdo: tdo::Tdo = match tdo::Tdo::load(save_path.to_str().unwrap()) {
        Ok(loaded) => loaded,
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::FileNotFound), _)) => tdo::Tdo::new(),
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::FileCorrupted), _)) => {
            errorprint!("The saved JSON could not be parsed.");
            errorprint!("Please fix the saved json file manually or delete it to continue.");
            exit(1);
        }
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::UnableToConvert), _)) => {
            errorprint!("The File could not be converted to the new version automatically.");
            errorprint!("Please fix the saved json file manually or delete it to continue.");
            exit(1);
        }
        Err(e) => {
            println!("{:?}", e);
            panic!();
        }
    };

    match app.subcommand {
        None => {
            match app.value_of("task") {
                Some(task_string) => subcommands::add(&mut tdo, task_string, app.value_of("list")),
                None => subcommands::print_out(&tdo, false),
            }
        }
        Some(_) => {
            match app.subcommand() {
                ("all", Some(_)) => subcommands::print_out(&tdo, true),
                ("add", Some(sub_m)) => {
                    let task_string = sub_m.value_of("task").unwrap();
                    subcommands::add(&mut tdo, task_string, sub_m.value_of("list"));
                }
                ("edit", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::edit(&mut tdo, id);
                }
                ("done", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::done(&mut tdo, id);
                }
                ("newlist", Some(sub_m)) => {
                    let new_list = match sub_m.value_of("listname") {
                        Some(name) => name,
                        None => {
                            errorprint!("listname could not be parsed.");
                            exit(1);
                        }
                    };
                    subcommands::newlist(&mut tdo, new_list);
                }
                ("move", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::move_todo(&mut tdo, id, sub_m.value_of("listname").unwrap());
                }
                ("remove", Some(sub_m)) => {
                    let list_name = match sub_m.value_of("listname") {
                        Some(name) => name,
                        None => {
                            errorprint!("listname could not be parsed.");
                            exit(1);
                        }
                    };
                    subcommands::remove(&mut tdo, list_name);
                }
                ("completions", Some(sub_m)) => {
                    if let Some(shell) = sub_m.value_of("shell") {
                        cli::cli().gen_completions_to("rustup",
                                                      shell.parse::<Shell>().unwrap(),
                                                      &mut std::io::stdout());
                    }
                }
                ("github", Some(sub_m)) => {
                    match sub_m.subcommand {
                        None => {
                            let repo = sub_m.value_of("repository").unwrap();
                            let title = sub_m.value_of("title").unwrap();
                            subcommands::github(&mut tdo, repo, title, sub_m.value_of("body"));
                        }
                        Some(_) => {
                            match sub_m.subcommand() {
                                ("set", Some(subs)) => {
                                    subcommands::github_set(&mut tdo, subs.value_of("token"))
                                }
                                _ => println!("{:?}", sub_m),
                            }
                        }
                    }
                }
                ("clean", Some(sub_m)) => subcommands::clean(&mut tdo, sub_m.value_of("listname")),
                ("lists", Some(_)) => subcommands::lists(&tdo),
                ("export", Some(sub_m)) => {
                    let filepath = match sub_m.value_of("destination") {
                        Some(path) => path,
                        None => {
                            errorprint!("destination could not be parsed");
                            exit(1);
                        }
                    };
                    subcommands::export(&tdo, filepath, sub_m.is_present("undone"));
                }
                ("reset", Some(_)) => {
                    match subcommands::reset(&mut tdo) {
                        Some(x) => tdo = x,
                        None => {}
                    }
                }
                _ => println!("{}", app.usage()),
            }
        }
    }

    let target = match filesystem::validate_target_file(save_path.to_str().unwrap()) {
        Ok(path) => path,
        Err(e) => {
            errorprint!(e);
            return;
        }
    };
    match tdo.save(target.to_str().unwrap()) {
        Err(e) => errorprint!(e),
        _ => {}
    }
}
<commit_msg>fixed autocompletion 🙈<commit_after>#[macro_use]
extern crate clap;
extern crate colored;
extern crate tdo_core;
extern crate tdo_export;

#[macro_use]
mod macros;
mod cli;
mod filesystem;

use std::env;
use colored::*;
use clap::Shell;
mod subcommands;
use std::process::exit;
use tdo_core::{tdo, error};

#[allow(unused_variables)]
fn main() {
    // initialize the clap App handle
    // let yml = load_yaml!("cli.yml");
    let app = cli::cli().get_matches();

    let save_path = match env::home_dir() {
        Some(path) => path.join(".tdo/list.json"),
        None => {
            errorprint!("You seem to have no home directory. Unfortunately this is required \
                      in order to use tdo.");
            exit(1);
        }
    };
    let mut tdo: tdo::Tdo = match tdo::Tdo::load(save_path.to_str().unwrap()) {
        Ok(loaded) => loaded,
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::FileNotFound), _)) => tdo::Tdo::new(),
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::FileCorrupted), _)) => {
            errorprint!("The saved JSON could not be parsed.");
            errorprint!("Please fix the saved json file manually or delete it to continue.");
            exit(1);
        }
        Err(error::Error(error::ErrorKind::StorageError(
            error::storage_error::ErrorKind::UnableToConvert), _)) => {
            errorprint!("The File could not be converted to the new version automatically.");
            errorprint!("Please fix the saved json file manually or delete it to continue.");
            exit(1);
        }
        Err(e) => {
            println!("{:?}", e);
            panic!();
        }
    };

    match app.subcommand {
        None => {
            match app.value_of("task") {
                Some(task_string) => subcommands::add(&mut tdo, task_string, app.value_of("list")),
                None => subcommands::print_out(&tdo, false),
            }
        }
        Some(_) => {
            match app.subcommand() {
                ("all", Some(_)) => subcommands::print_out(&tdo, true),
                ("add", Some(sub_m)) => {
                    let task_string = sub_m.value_of("task").unwrap();
                    subcommands::add(&mut tdo, task_string, sub_m.value_of("list"));
                }
                ("edit", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::edit(&mut tdo, id);
                }
                ("done", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::done(&mut tdo, id);
                }
                ("newlist", Some(sub_m)) => {
                    let new_list = match sub_m.value_of("listname") {
                        Some(name) => name,
                        None => {
                            errorprint!("listname could not be parsed.");
                            exit(1);
                        }
                    };
                    subcommands::newlist(&mut tdo, new_list);
                }
                ("move", Some(sub_m)) => {
                    let id: u32 = match sub_m.value_of("id").unwrap().parse() {
                        Ok(id) => id,
                        Err(_) => {
                            errorprint!("id must be va valid integer.");
                            exit(1);
                        }
                    };
                    subcommands::move_todo(&mut tdo, id, sub_m.value_of("listname").unwrap());
                }
                ("remove", Some(sub_m)) => {
                    let list_name = match sub_m.value_of("listname") {
                        Some(name) => name,
                        None => {
                            errorprint!("listname could not be parsed.");
                            exit(1);
                        }
                    };
                    subcommands::remove(&mut tdo, list_name);
                }
                ("completions", Some(sub_m)) => {
                    if let Some(shell) = sub_m.value_of("shell") {
                        cli::cli().gen_completions_to("tdo",
                                                      shell.parse::<Shell>().unwrap(),
                                                      &mut std::io::stdout());
                    }
                }
                ("github", Some(sub_m)) => {
                    match sub_m.subcommand {
                        None => {
                            let repo = sub_m.value_of("repository").unwrap();
                            let title = sub_m.value_of("title").unwrap();
                            subcommands::github(&mut tdo, repo, title, sub_m.value_of("body"));
                        }
                        Some(_) => {
                            match sub_m.subcommand() {
                                ("set", Some(subs)) => {
                                    subcommands::github_set(&mut tdo, subs.value_of("token"))
                                }
                                _ => println!("{:?}", sub_m),
                            }
                        }
                    }
                }
                ("clean", Some(sub_m)) => subcommands::clean(&mut tdo, sub_m.value_of("listname")),
                ("lists", Some(_)) => subcommands::lists(&tdo),
                ("export", Some(sub_m)) => {
                    let filepath = match sub_m.value_of("destination") {
                        Some(path) => path,
                        None => {
                            errorprint!("destination could not be parsed");
                            exit(1);
                        }
                    };
                    subcommands::export(&tdo, filepath, sub_m.is_present("undone"));
                }
                ("reset", Some(_)) => {
                    match subcommands::reset(&mut tdo) {
                        Some(x) => tdo = x,
                        None => {}
                    }
                }
                _ => println!("{}", app.usage()),
            }
        }
    }

    let target = match filesystem::validate_target_file(save_path.to_str().unwrap()) {
        Ok(path) => path,
        Err(e) => {
            errorprint!(e);
            return;
        }
    };
    match tdo.save(target.to_str().unwrap()) {
        Err(e) => errorprint!(e),
        _ => {}
    }
}
<|endoftext|>


<commit_before>extern crate dotenv;
#[macro_use]
extern crate diesel;
extern crate argonautica;
#[macro_use]
extern crate anyhow;

use actix_files as fs;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::rt::Arbiter;
use actix_web::{guard, middleware, web, App, HttpResponse, HttpServer};
use background_jobs::memory_storage::Storage;
use background_jobs::{create_server, WorkerConfig};
use models::Picture;
use std::{env, io};
use webmentions::send::WebmenentionSenderJob;

use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};

use dotenv::dotenv;

use uri_helpers::webmentions_endpoint_uri;

pub mod multipart;
pub mod uri_helpers;
pub mod utils;

pub mod models;
pub mod schema;

pub mod articles;
pub mod likes;
pub mod notes;
pub mod pages;
pub mod pictures;
pub mod session;
pub mod static_handlers;
pub mod webmentions;

pub type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
pub type DbError = Box<dyn std::error::Error + Send + Sync>;

const DEFAULT_QUEUE: &str = "default";

#[actix_web::main]
async fn main() -> io::Result<()> {
    dotenv().ok();

    env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");
    env_logger::init();

    let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL");
    let manager = ConnectionManager::<PgConnection>::new(connspec);
    let pool = r2d2::Pool::builder().build(manager).expect("Failed to create pool.");

    HttpServer::new(move || {
        let static_path = utils::static_path();

        let storage = Storage::new();
        let queue = create_server(storage);

        WorkerConfig::new(|| ())
            .register::<WebmenentionSenderJob>()
            .register::<Picture>()
            .set_worker_count(DEFAULT_QUEUE, 1)
            .start_in_arbiter(&Arbiter::default(), queue.clone());

        App::new()
            .wrap(IdentityService::new(
                CookieIdentityPolicy::new(&[0; 32]).name("wwwtech").secure(false),
            ))
            .data(pool.clone())
            .data(queue.clone())
            .wrap(middleware::Logger::default())
            .wrap(
                middleware::DefaultHeaders::new()
                    .header("link", format!("<{}>; rel=\"webmention\"", webmentions_endpoint_uri())),
            )
            .service(static_handlers::favicon)
            .service(static_handlers::robots_txt)
            .service(static_handlers::gpgkey)
            .service(static_handlers::humans_txt)
            .service(fs::Files::new("/static", static_path).show_files_listing())
            .configure(session::routes)
            .configure(pages::routes)
            .configure(articles::routes)
            .configure(notes::routes)
            .configure(pictures::routes)
            .configure(likes::routes)
            .configure(webmentions::routes)
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(static_handlers::p404))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
<commit_msg>call dotenv only in dev and test mode<commit_after>#[cfg(debug_assertions)]
extern crate dotenv;
#[macro_use]
extern crate diesel;
extern crate argonautica;
#[macro_use]
extern crate anyhow;

use actix_files as fs;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::rt::Arbiter;
use actix_web::{guard, middleware, web, App, HttpResponse, HttpServer};
use background_jobs::memory_storage::Storage;
use background_jobs::{create_server, WorkerConfig};
use models::Picture;
use std::{env, io};
use webmentions::send::WebmenentionSenderJob;

use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};

#[cfg(debug_assertions)]
use dotenv::dotenv;

use uri_helpers::webmentions_endpoint_uri;

pub mod multipart;
pub mod uri_helpers;
pub mod utils;

pub mod models;
pub mod schema;

pub mod articles;
pub mod likes;
pub mod notes;
pub mod pages;
pub mod pictures;
pub mod session;
pub mod static_handlers;
pub mod webmentions;

pub type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
pub type DbError = Box<dyn std::error::Error + Send + Sync>;

const DEFAULT_QUEUE: &str = "default";

#[actix_web::main]
async fn main() -> io::Result<()> {
    #[cfg(debug_assertions)]
    dotenv().ok();

    env::set_var("RUST_LOG", "actix_web=debug,actix_server=info");
    env_logger::init();

    let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL");
    let manager = ConnectionManager::<PgConnection>::new(connspec);
    let pool = r2d2::Pool::builder().build(manager).expect("Failed to create pool.");

    HttpServer::new(move || {
        let static_path = utils::static_path();

        let storage = Storage::new();
        let queue = create_server(storage);

        WorkerConfig::new(|| ())
            .register::<WebmenentionSenderJob>()
            .register::<Picture>()
            .set_worker_count(DEFAULT_QUEUE, 1)
            .start_in_arbiter(&Arbiter::default(), queue.clone());

        App::new()
            .wrap(IdentityService::new(
                CookieIdentityPolicy::new(&[0; 32]).name("wwwtech").secure(false),
            ))
            .data(pool.clone())
            .data(queue.clone())
            .wrap(middleware::Logger::default())
            .wrap(
                middleware::DefaultHeaders::new()
                    .header("link", format!("<{}>; rel=\"webmention\"", webmentions_endpoint_uri())),
            )
            .service(static_handlers::favicon)
            .service(static_handlers::robots_txt)
            .service(static_handlers::gpgkey)
            .service(static_handlers::humans_txt)
            .service(fs::Files::new("/static", static_path).show_files_listing())
            .configure(session::routes)
            .configure(pages::routes)
            .configure(articles::routes)
            .configure(notes::routes)
            .configure(pictures::routes)
            .configure(likes::routes)
            .configure(webmentions::routes)
            .default_service(
                // 404 for GET request
                web::resource("")
                    .route(web::get().to(static_handlers::p404))
                    // all requests that are not `GET`
                    .route(
                        web::route()
                            .guard(guard::Not(guard::Get()))
                            .to(HttpResponse::MethodNotAllowed),
                    ),
            )
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate curl;
extern crate rusqlite;

pub mod config;
mod inoreader;
mod telegram;
mod store;

use std::thread;
use std::process;
use std::time::Duration;
use std::thread::sleep;

fn main() {
    // получаем список аргументов командной строки
    let cmd_args: Vec<_> = std::env::args().collect();

    if cmd_args.len() < 2 {
        println!("Illegal parameter use: inobot <config_path>");
        process::exit(1);
    }
    let cfg = config::Config::new(&cmd_args[1]);
    let store = store::Store::connect(&cfg);

    let mut inoreader_client = inoreader::InoReaderClient::new(&cfg);
    let mut telegram_bot = telegram::TelegramBotClient::new(&cfg);

    loop {
        let new_chats = telegram_bot.get_chart_ids();
        let mut saved_charts = store.get_chart_ids();
        for c in new_chats {
            if !saved_charts.contains(&c) {
                store.add_chart(c);
                saved_charts.push(c);
            }
        }

        let unread_count = inoreader_client.get_unread_count();
        let news: Vec<inoreader::News> = inoreader_client.get_last_news(unread_count);

        for c in saved_charts {
            let sending_news = news.clone();
            let mut bot = telegram::TelegramBotClient::new(&cfg);
            let _ = thread::spawn(move || {
                for n in sending_news {
                    bot.send_message(n, c);
                }
            }).join();
        }

        // ждем timeout в секундах для следующего обращения
        sleep(Duration::from_secs(cfg.timeout));
    }
}
<commit_msg>fix так как не нужен результат потоков<commit_after>#[macro_use]
extern crate serde_derive;
extern crate curl;
extern crate rusqlite;

pub mod config;
mod inoreader;
mod telegram;
mod store;

use std::thread;
use std::process;
use std::time::Duration;
use std::thread::sleep;

fn main() {
    // получаем список аргументов командной строки
    let cmd_args: Vec<_> = std::env::args().collect();

    if cmd_args.len() < 2 {
        println!("Illegal parameter use: inobot <config_path>");
        process::exit(1);
    }
    let cfg = config::Config::new(&cmd_args[1]);
    let store = store::Store::connect(&cfg);

    let mut inoreader_client = inoreader::InoReaderClient::new(&cfg);
    let mut telegram_bot = telegram::TelegramBotClient::new(&cfg);

    loop {
        let new_chats = telegram_bot.get_chart_ids();
        let mut saved_charts = store.get_chart_ids();
        for c in new_chats {
            if !saved_charts.contains(&c) {
                store.add_chart(c);
                saved_charts.push(c);
            }
        }

        let unread_count = inoreader_client.get_unread_count();
        let news: Vec<inoreader::News> = inoreader_client.get_last_news(unread_count);

        for c in saved_charts {
            let sending_news = news.clone();
            let mut bot = telegram::TelegramBotClient::new(&cfg);
            thread::spawn(move || {
                for n in sending_news {
                    bot.send_message(n, c);
                }
            });
        }

        // ждем timeout в секундах для следующего обращения
        sleep(Duration::from_secs(cfg.timeout));
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(phase)]
#![feature(unboxed_closures)]
#![feature(macro_rules)]
extern crate regex;
#[phase(plugin)] extern crate peruse;
extern crate peruse;

use std::collections::HashMap;
use peruse::parsers::*;
use grammar::*;
use parser::block;
use lexer::token;
use std::os;
use std::io::File;

pub mod lexer;
pub mod grammar;
pub mod parser;

fn main() {

  let args = os::args();

  let file = &args[1];

  let contents = File::open(&Path::new(file.as_slice())).read_to_string();

  match contents {
    Ok(raw) => {
      let lexer = token();
      match lexer.parse(raw.as_slice()) {
        Ok((tokens, rest)) => {
          if rest != "" {
            println!("Parser error at: {}", rest)
          } else {
            let parser = block();
            match parser.parse(tokens.as_slice()) {
              Ok((Block(stmts), rest)) => {
                if rest.len() > 0 {
                  println!("Error: unexpected token {}", rest[0]);
                } else {
                  run(&stmts);
                }
              }
              Err(err) => {println!("Parse Error: {}", err);}
            };
          }
        },
        Err(err) => {
          println!("Lexer error: {}", err);
        }
      }
    }
    Err(err) => {println!("Error Reading File: {}", err);}
  }

}

type Environment = HashMap<String, int>;

fn run(prog: &Vec<Statement>) {
  fn run_internal(prog: &Vec<Statement>, env: &mut Environment) {
    for s in prog.iter() {
      match *s {
        Assign(ref var, ref expr) => {
          match eval(expr, env) {
            Ok(res)   => {env.insert(var.clone(), res);}
            Err(err)  => {
              println!("ERROR: {}", err);
              return;
            }
          }
        },
        Output(ref expr) => match eval(expr, env) {
          Ok(val) => {println!("{}", val)}
          Err(err) => {
            println!("ERROR: {}", err)
            return;
          }
        },
        If(ref lhs, ref cmp, ref rhs, ref then_block, ref else_block) => {
          let is_true = compare(lhs, cmp, rhs, env);
          if (is_true) {
            let &Block(ref p) = then_block;
            run_internal(p, env);
          } else {
            match else_block {
              &Some(Block(ref p)) => {run_internal(p, env);}
              &None => {}
            }
          }
        }
        While(ref lhs, ref cmp, ref rhs, ref block) => {
          let &Block(ref stmts) = block;
          while(compare(lhs, cmp, rhs, env)) {
            run_internal(stmts, env);
          }
        }
      }
    }
  }
  let mut env: HashMap<String, int> = HashMap::new();
  run_internal(prog, &mut env);
}

fn compare(lhs: &Expr, cmp: &Comparator, rhs: &Expr, env: &Environment) -> bool {
  let l = eval(lhs, env);
  let r = eval(rhs, env);
  match *cmp {
    CEq   => l == r,
    CNeq  => l != r,
    CLt   => l < r,
    CGt   => l > r,
    CLeq  => l <= r,
    CGeq  => l >= r,
  }
}

fn eval(expr: &Expr, env: &HashMap<String, int>) -> Result<int, String> {
  match *expr {
    Variable(ref var) => match env.find(var) {
      Some(val) => Ok(*val),
      None => Err(format!("Undefined var {}", var)),
    },
    Num(val) => Ok(val),
    AddSub(ref ops) => {
      let mut sum = 0i;
      for &AddTerm(ref sign, ref op) in ops.iter() {
        match eval(op, env) {
          Ok(value) => match *sign {
            Add => {sum += value;}
            Subtract => {sum -= value;}
          },
          Err(err) => {
            return Err(err);
          }
        }
      }
      Ok(sum)
    },
    MultDiv(ref ops) => {
      let mut total = 1i;
      for &MultTerm(ref sign,ref op) in ops.iter() {
        match eval(op, env) {
          Ok(value) => match *sign{
            Multiply  => {total *= value;}
            Divide    => {total /= value;}
            Modulo    => {total %= value;}
          },
          Err(err) => {
            return Err(err);
          }
        }
      }
      Ok(total)
    }
  }
}

<commit_msg>adding benchmark<commit_after>#![feature(globs)]
#![feature(phase)]
#![feature(unboxed_closures)]
#![feature(macro_rules)]
extern crate regex;
#[phase(plugin)] extern crate peruse;
extern crate peruse;
extern crate test;

use std::mem::replace;
use test::Bencher;

use std::collections::HashMap;
use peruse::parsers::*;
use grammar::*;
use parser::block;
use lexer::token;
use std::os;
use std::io::File;

pub mod lexer;
pub mod grammar;
pub mod parser;

fn main() {

  let args = os::args();

  let file = &args[1];

  let contents = File::open(&Path::new(file.as_slice())).read_to_string();

  match contents {
    Ok(raw) => {
      interp(raw.as_slice());
    }
    Err(err) => {println!("Error Reading File: {}", err);}
  }

}

type Environment = HashMap<String, int>;

fn interp<'a>(raw: &'a str) {
  let lexer = token();
  match lexer.parse(raw) {
    Ok((tokens, rest)) => {
      if rest != "" {
        println!("Parser error at: {}", rest)
      } else {
        let parser = block();
        match parser.parse(tokens.as_slice()) {
          Ok((Block(stmts), rest)) => {
            if rest.len() > 0 {
              println!("Error: unexpected token {}", rest[0]);
            } else {
              run(&stmts);
            }
          }
          Err(err) => {println!("Parse Error: {}", err);}
        };
      }
    },
    Err(err) => {
      println!("Lexer error: {}", err);
    }
  }

}

fn run(prog: &Vec<Statement>) {
  fn run_internal(prog: &Vec<Statement>, env: &mut Environment) {
    for s in prog.iter() {
      match *s {
        Assign(ref var, ref expr) => {
          match eval(expr, env) {
            Ok(res)   => {env.insert(var.clone(), res);}
            Err(err)  => {
              println!("ERROR: {}", err);
              return;
            }
          }
        },
        Output(ref expr) => match eval(expr, env) {
          Ok(val) => {println!("{}", val)}
          Err(err) => {
            println!("ERROR: {}", err)
            return;
          }
        },
        If(ref lhs, ref cmp, ref rhs, ref then_block, ref else_block) => {
          let is_true = compare(lhs, cmp, rhs, env);
          if (is_true) {
            let &Block(ref p) = then_block;
            run_internal(p, env);
          } else {
            match else_block {
              &Some(Block(ref p)) => {run_internal(p, env);}
              &None => {}
            }
          }
        }
        While(ref lhs, ref cmp, ref rhs, ref block) => {
          let &Block(ref stmts) = block;
          while(compare(lhs, cmp, rhs, env)) {
            run_internal(stmts, env);
          }
        }
      }
    }
  }
  let mut env: HashMap<String, int> = HashMap::new();
  run_internal(prog, &mut env);
}

fn compare(lhs: &Expr, cmp: &Comparator, rhs: &Expr, env: &Environment) -> bool {
  let l = eval(lhs, env);
  let r = eval(rhs, env);
  match *cmp {
    CEq   => l == r,
    CNeq  => l != r,
    CLt   => l < r,
    CGt   => l > r,
    CLeq  => l <= r,
    CGeq  => l >= r,
  }
}

fn eval(expr: &Expr, env: &HashMap<String, int>) -> Result<int, String> {
  match *expr {
    Variable(ref var) => match env.find(var) {
      Some(val) => Ok(*val),
      None => Err(format!("Undefined var {}", var)),
    },
    Num(val) => Ok(val),
    AddSub(ref ops) => {
      let mut sum = 0i;
      for &AddTerm(ref sign, ref op) in ops.iter() {
        match eval(op, env) {
          Ok(value) => match *sign {
            Add => {sum += value;}
            Subtract => {sum -= value;}
          },
          Err(err) => {
            return Err(err);
          }
        }
      }
      Ok(sum)
    },
    MultDiv(ref ops) => {
      let mut total = 1i;
      for &MultTerm(ref sign,ref op) in ops.iter() {
        match eval(op, env) {
          Ok(value) => match *sign{
            Multiply  => {total *= value;}
            Divide    => {total /= value;}
            Modulo    => {total %= value;}
          },
          Err(err) => {
            return Err(err);
          }
        }
      }
      Ok(total)
    }
  }
}

#[bench]
fn bench_run(b: &mut Bencher) {
    let prog = "x = 2
    y = 1
    z = x + (y * 2)
    ";
    b.iter(|| {
      interp(prog);
    })
}

<|endoftext|>


<commit_before>#[macro_use] extern crate glium;
#[macro_use] extern crate nalgebra as na;
extern crate obj;

use std::f32::consts::{FRAC_PI_2};

use obj::SimplePolygon;

use na::{Pnt3, Vec3, Mat3, Iso3, PerspMat3};
use na::{Eye};

const PI_4: f32 = std::f32::consts::FRAC_PI_4;

#[derive(Copy, Clone)]
struct Vert {
    position: [f32;3],
    normal: [f32;3],
    color: [f32;3],
}

implement_vertex!(Vert, position, normal, color);

fn setup_icosohedron(meshes_dir: String, window: &glium::backend::glutin_backend::GlutinFacade) -> glium::vertex::VertexBuffer<Vert> {
    let mut p = std::path::PathBuf::from(meshes_dir);
    p.push("icosohedron.obj");
    let o = obj::load::<SimplePolygon>(&p).unwrap();

    let green = [0f32, 1.0, 0.0];

    let size = o.position().len();
    let mut data = Vec::with_capacity(size);

    for ob in o.object_iter() {
        for g in ob.group_iter() {
            for tri in g.indices() {
                data.push(
                    Vert {
                        position: o.position()[tri[0].0],
                        normal: o.normal()[(tri[0].2).unwrap()],
                        color: green.clone(),
                    }
                );
                data.push(
                    Vert {
                        position: o.position()[tri[1].0],
                        normal: o.normal()[(tri[1].2).unwrap()],
                        color: green.clone(),
                    }
                );
                data.push(
                    Vert {
                        position: o.position()[tri[2].0],
                        normal: o.normal()[(tri[2].2).unwrap()],
                        color: green.clone(),
                    }
                );
            }
        }
    }

    glium::vertex::VertexBuffer::new(window, &data).unwrap()
}

fn setup_plane(window: &glium::backend::glutin_backend::GlutinFacade) -> glium::vertex::VertexBuffer<Vert> {
    let tr = [1f32, 1.0, 0.0];
    let tl = [-1f32, 1.0, 0.0];
    let bl = [-1f32, -1.0, 0.0];
    let br = [1f32, -1.0, 0.0];

    let n = [0f32, 0.0, 1.0];

    let white = [1f32, 1.0, 1.0];

    let data = &[
        Vert {
            position: tr,
            normal: n,
            color: white,
        },
        Vert {
            position: tl,
            normal: n,
            color: white,
        },
        Vert {
            position: bl,
            normal: n,
            color: white,
        },

        Vert {
            position: tr,
            normal: n,
            color: white,
        },
        Vert {
            position: bl,
            normal: n,
            color: white,
        },
        Vert {
            position: br,
            normal: n,
            color: white,
        },
    ];
    glium::vertex::VertexBuffer::new(window, data).unwrap()
}

fn setup_shaders(window: &glium::backend::glutin_backend::GlutinFacade) -> glium::program::Program {
    let v_shader = "
        #version 150

        uniform mat4 perspective;
        uniform mat4 mv;
        uniform mat4 m_invt;
        uniform vec3 light_dir;

        in vec3 position;
        in vec3 normal;
        in vec3 color;

        out vec3 f_color;

        void main() {
            gl_Position = perspective*mv*vec4(position, 1.0);

            vec3 mv_normal = normalize(vec3(m_invt * vec4(normal, 0.0)));
            float diffuse = 0.6*max( dot(mv_normal, light_dir), 0.1);

            f_color = diffuse*color;
        }
    ";
    let f_shader = "
        #version 150

        in vec3 f_color;

        void main() {
            gl_FragColor = vec4(f_color, 1.0);
        }
    ";
    glium::program::Program::from_source(window, v_shader, f_shader, None).unwrap()
}

fn main() {
    use glium::{DisplayBuild,Surface};

    let meshes_dir = match std::env::args().nth(1) {
        Some(dir) => dir,
        None => {
            println!("Usage: ./triangle [path_to_meshes_directory]");
            return;
        },
    };

    const WIDTH: u32 = 1280;
    const HEIGHT: u32 = 720;
    const ASPECT: f32 = 1.78;

	let params = glium::DrawParameters {
		backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
		depth: glium::Depth {
			test: glium::draw_parameters::DepthTest::IfLess,
			write: true,
			.. Default::default()
		},
		.. Default::default()
	};

    let window = glium::glutin::WindowBuilder::new()
        .with_dimensions(WIDTH, HEIGHT)
        .with_depth_buffer(24)
        .with_title(format!("Hello world"))
        .build_glium()
        .unwrap();

    let icosohedron = setup_icosohedron(meshes_dir, &window);
    let plane = setup_plane(&window);
    let program = setup_shaders(&window);
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let persp = PerspMat3::new(ASPECT, PI_4, 1.0, 100.0).to_mat();

    let mut position = Pnt3::new(0.0f32, 1.0f32, 5.0f32);
    let dir = Vec3::new(0.0f32, 0.0f32, -1.0f32);
    let up = Vec3::new(0.0f32, 1.0f32, 0.0f32);

    let mut t = 0f32;

    let mut exit = false;
    loop {
        for event in window.poll_events() {
            use glium::glutin::Event;
			use glium::glutin::VirtualKeyCode as KC;
            match event {
                Event::Closed => (exit = true),
				Event::KeyboardInput(state, _, key) => {
                    if state == glium::glutin::ElementState::Pressed {
                        match key.unwrap() {
                            KC::PageUp => {position = position + Vec3::new(0f32, 0.2f32, 0f32);},
                            KC::PageDown => {position = position + Vec3::new(0f32, -0.2f32, 0f32);},
							KC::Left => position = position + Vec3::new(-0.2f32, 0f32, 0f32),
							KC::Right => position = position + Vec3::new(0.2f32, 0f32, 0f32),
							KC::Up => position = position + Vec3::new(0f32, 0f32, -0.2f32),
							KC::Down => position = position + Vec3::new(0f32, 0f32, 0.2f32),
                            KC::Space => {println!("hello");}
                            KC::Escape => {exit = true;},
                            _ => ()
                        }
                    }
				}
                _ => ()
            }
        }

        t += 0.05;

        let mut frame = window.draw();
        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        // camera
        let view = na::inv(&Iso3::look_at_z(&position, &(position + dir), &up)).unwrap();
        let view = na::to_homogeneous(&view);
        let light_dir = [0.5, 0.866025, 0f32];

        // draw tetrahedrons
        for i in 0..10 {
            let model = Iso3::new(Vec3::new(0f32, 0.0, -5f32*i as f32), Vec3::new(0f32, 1.0, 0.0) * t);
            let model = na::to_homogeneous(&model);
            let modelview = view*model;

            let uniforms = uniform! {
                perspective: persp.as_ref().clone(),
                mv: modelview.as_ref().clone(),
                m_invt: na::transpose(&na::inv(&model).unwrap()).as_ref().clone(),
                light_dir: light_dir,
            };

            frame.draw(&icosohedron, &indices, &program, &uniforms,
                                &params).unwrap();
        }

        // draw plane below icosohedron
        let scale = 50f32;
        let plane_scale = na::to_homogeneous(&(Mat3::<f32>::new_identity(3)*scale));
        let plane_rot = na::to_homogeneous(&(Iso3::new(Vec3::new(0f32, -1.0, 0.0), Vec3::new(1f32, 0.0, 0.0)*-FRAC_PI_2)));
        let plane_model = plane_rot*plane_scale;
        let modelview = view*plane_model;

        let uniforms = uniform! {
            perspective: persp.as_ref().clone(),
            mv: modelview.as_ref().clone(),
            m_invt: na::transpose(&na::inv(&plane_model).unwrap()).as_ref().clone(),
            light_dir: light_dir,
        };
        frame.draw(&plane, &indices, &program, &uniforms,
                            &params).unwrap();

        frame.finish().unwrap();
        window.swap_buffers().unwrap();

        if exit {
            break;
        }
    }
}
<commit_msg>Fix formatting<commit_after>#[macro_use] extern crate glium;
#[macro_use] extern crate nalgebra as na;
extern crate obj;

use std::f32::consts::{FRAC_PI_2};

use obj::SimplePolygon;

use na::{Pnt3, Vec3, Mat3, Iso3, PerspMat3};
use na::{Eye};

const PI_4: f32 = std::f32::consts::FRAC_PI_4;

#[derive(Copy, Clone)]
struct Vert {
    position: [f32;3],
    normal: [f32;3],
    color: [f32;3],
}

implement_vertex!(Vert, position, normal, color);

fn setup_icosohedron(meshes_dir: String, window: &glium::backend::glutin_backend::GlutinFacade) -> glium::vertex::VertexBuffer<Vert> {
    let mut p = std::path::PathBuf::from(meshes_dir);
    p.push("icosohedron.obj");
    let o = obj::load::<SimplePolygon>(&p).unwrap();

    let green = [0f32, 1.0, 0.0];

    let size = o.position().len();
    let mut data = Vec::with_capacity(size);

    for ob in o.object_iter() {
        for g in ob.group_iter() {
            for tri in g.indices() {
                data.push(
                    Vert {
                        position: o.position()[tri[0].0],
                        normal: o.normal()[(tri[0].2).unwrap()],
                        color: green.clone(),
                    }
                );
                data.push(
                    Vert {
                        position: o.position()[tri[1].0],
                        normal: o.normal()[(tri[1].2).unwrap()],
                        color: green.clone(),
                    }
                );
                data.push(
                    Vert {
                        position: o.position()[tri[2].0],
                        normal: o.normal()[(tri[2].2).unwrap()],
                        color: green.clone(),
                    }
                );
            }
        }
    }

    glium::vertex::VertexBuffer::new(window, &data).unwrap()
}

fn setup_plane(window: &glium::backend::glutin_backend::GlutinFacade) -> glium::vertex::VertexBuffer<Vert> {
    let tr = [1f32, 1.0, 0.0];
    let tl = [-1f32, 1.0, 0.0];
    let bl = [-1f32, -1.0, 0.0];
    let br = [1f32, -1.0, 0.0];

    let n = [0f32, 0.0, 1.0];

    let white = [1f32, 1.0, 1.0];

    let data = &[
        Vert {
            position: tr,
            normal: n,
            color: white,
        },
        Vert {
            position: tl,
            normal: n,
            color: white,
        },
        Vert {
            position: bl,
            normal: n,
            color: white,
        },

        Vert {
            position: tr,
            normal: n,
            color: white,
        },
        Vert {
            position: bl,
            normal: n,
            color: white,
        },
        Vert {
            position: br,
            normal: n,
            color: white,
        },
    ];
    glium::vertex::VertexBuffer::new(window, data).unwrap()
}

fn setup_shaders(window: &glium::backend::glutin_backend::GlutinFacade) -> glium::program::Program {
    let v_shader = "
        #version 150

        uniform mat4 perspective;
        uniform mat4 mv;
        uniform mat4 m_invt;
        uniform vec3 light_dir;

        in vec3 position;
        in vec3 normal;
        in vec3 color;

        out vec3 f_color;

        void main() {
            gl_Position = perspective*mv*vec4(position, 1.0);

            vec3 mv_normal = normalize(vec3(m_invt * vec4(normal, 0.0)));
            float diffuse = 0.6*max( dot(mv_normal, light_dir), 0.1);

            f_color = diffuse*color;
        }
    ";
    let f_shader = "
        #version 150

        in vec3 f_color;

        void main() {
            gl_FragColor = vec4(f_color, 1.0);
        }
    ";
    glium::program::Program::from_source(window, v_shader, f_shader, None).unwrap()
}

fn main() {
    use glium::{DisplayBuild,Surface};

    let meshes_dir = match std::env::args().nth(1) {
        Some(dir) => dir,
        None => {
            println!("Usage: ./triangle [path_to_meshes_directory]");
            return;
        },
    };

    const WIDTH: u32 = 1280;
    const HEIGHT: u32 = 720;
    const ASPECT: f32 = 1.78;

    let params = glium::DrawParameters {
        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    let window = glium::glutin::WindowBuilder::new()
        .with_dimensions(WIDTH, HEIGHT)
        .with_depth_buffer(24)
        .with_title(format!("Hello world"))
        .build_glium()
        .unwrap();

    let icosohedron = setup_icosohedron(meshes_dir, &window);
    let plane = setup_plane(&window);
    let program = setup_shaders(&window);
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let persp = PerspMat3::new(ASPECT, PI_4, 1.0, 100.0).to_mat();

    let mut position = Pnt3::new(0.0f32, 1.0f32, 5.0f32);
    let dir = Vec3::new(0.0f32, 0.0f32, -1.0f32);
    let up = Vec3::new(0.0f32, 1.0f32, 0.0f32);

    let mut t = 0f32;

    let mut exit = false;
    loop {
        for event in window.poll_events() {
            use glium::glutin::Event;
			use glium::glutin::VirtualKeyCode as KC;
            match event {
                Event::Closed => (exit = true),
				Event::KeyboardInput(state, _, key) => {
                    if state == glium::glutin::ElementState::Pressed {
                        match key.unwrap() {
                            KC::PageUp => {position = position + Vec3::new(0f32, 0.2f32, 0f32);},
                            KC::PageDown => {position = position + Vec3::new(0f32, -0.2f32, 0f32);},
							KC::Left => position = position + Vec3::new(-0.2f32, 0f32, 0f32),
							KC::Right => position = position + Vec3::new(0.2f32, 0f32, 0f32),
							KC::Up => position = position + Vec3::new(0f32, 0f32, -0.2f32),
							KC::Down => position = position + Vec3::new(0f32, 0f32, 0.2f32),
                            KC::Space => {println!("hello");}
                            KC::Escape => {exit = true;},
                            _ => ()
                        }
                    }
				}
                _ => ()
            }
        }

        t += 0.05;

        let mut frame = window.draw();
        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);

        // camera
        let view = na::inv(&Iso3::look_at_z(&position, &(position + dir), &up)).unwrap();
        let view = na::to_homogeneous(&view);
        let light_dir = [0.5, 0.866025, 0f32];

        // draw tetrahedrons
        for i in 0..10 {
            let model = Iso3::new(Vec3::new(0f32, 0.0, -5f32*i as f32), Vec3::new(0f32, 1.0, 0.0) * t);
            let model = na::to_homogeneous(&model);
            let modelview = view*model;

            let uniforms = uniform! {
                perspective: persp.as_ref().clone(),
                mv: modelview.as_ref().clone(),
                m_invt: na::transpose(&na::inv(&model).unwrap()).as_ref().clone(),
                light_dir: light_dir,
            };

            frame.draw(&icosohedron, &indices, &program, &uniforms,
                                &params).unwrap();
        }

        // draw plane below icosohedron
        let scale = 50f32;
        let plane_scale = na::to_homogeneous(&(Mat3::<f32>::new_identity(3)*scale));
        let plane_rot = na::to_homogeneous(&(Iso3::new(Vec3::new(0f32, -1.0, 0.0), Vec3::new(1f32, 0.0, 0.0)*-FRAC_PI_2)));
        let plane_model = plane_rot*plane_scale;
        let modelview = view*plane_model;

        let uniforms = uniform! {
            perspective: persp.as_ref().clone(),
            mv: modelview.as_ref().clone(),
            m_invt: na::transpose(&na::inv(&plane_model).unwrap()).as_ref().clone(),
            light_dir: light_dir,
        };
        frame.draw(&plane, &indices, &program, &uniforms,
                            &params).unwrap();

        frame.finish().unwrap();
        window.swap_buffers().unwrap();

        if exit {
            break;
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use std::fmt;

use rocket::Outcome;
use rocket::request::{self, Request, FromRequest};

struct IndexData(String);

impl<'a, 'r> FromRequest<'a, 'r> for IndexData {
    type Error = ();
    fn from_request(request: &'a Request<'r>) -> request::Outcome<IndexData, ()> {
        Outcome::Success(IndexData(format!("{}", request)))
    }
}

impl fmt::Display for IndexData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[get("/")]
fn index(data: IndexData) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>{}", data)
}

#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

#[get("/get")]
fn get() -> String {
    String::from("method")
}

#[get("/status/<status>")]
pub fn status(status: String) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>Status: {} (FIX ME)", status)
}

fn main() {
    rocket::ignite().mount("/", routes![index, origin, get, status]).launch();
}
<commit_msg>Static index.html and /test for experimenting<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use std::fmt;

use rocket::Outcome;
use rocket::request::{self, Request, FromRequest};

struct IndexData(String);

impl<'a, 'r> FromRequest<'a, 'r> for IndexData {
    type Error = ();
    fn from_request(request: &'a Request<'r>) -> request::Outcome<IndexData, ()> {
        Outcome::Success(IndexData(format!("{}", request)))
    }
}

impl fmt::Display for IndexData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[get("/")]
fn index() -> &'static str {
    "<!DOCTYPE html><title>HTTPTIN></title>{}"
}

#[get("/test")]
fn test(data: IndexData) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>{}", data)
}

#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

#[get("/get")]
fn get() -> String {
    String::from("method")
}

#[get("/status/<status>")]
pub fn status(status: &str) -> String {
    format!("<!DOCTYPE html><title>HTTPTIN></title>Status: {} (FIX ME)", status)
}

fn main() {
    rocket::ignite().mount("/", routes![index, origin, get, status, test]).launch();
}
<|endoftext|>


<commit_before>#![deny(unused_extern_crates)]

use std::env;
use std::path::{Path, PathBuf};

use mdblog::{log_error, Mdblog, Result};
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "mdblog")]
/// static site generator from markdown files
enum Opt {
    #[structopt(name = "init")]
    /// Initialize the blog directory layout
    Init {
        /// the blog directory name
        name: String,
    },
    #[structopt(name = "new")]
    /// Create a blog post
    New {
        #[structopt(short = "t", long = "tag", default_value = "")]
        /// Post tags
        tags: Vec<String>,
        #[structopt(parse(from_os_str))]
        /// Post path relative to blog `posts` directory
        path: PathBuf,
    },
    #[structopt(name = "build")]
    /// Build the blog static files
    Build,
    #[structopt(name = "serve")]
    /// Serve the blog, rebuild on change
    Serve {
        #[structopt(short = "p", long = "port", default_value = "5000")]
        /// Serve the blog at http://127.0.0.1:<port>
        port: u16,
    },
    #[structopt(name = "theme")]
    /// Blog theme operations
    Theme(SubCommandTheme),
}

#[derive(StructOpt, Debug)]
enum SubCommandTheme {
    #[structopt(name = "list")]
    /// list blog themes
    List,
    #[structopt(name = "new")]
    /// Create a new theme
    New {
        /// theme name
        name: String,
    },
    #[structopt(name = "delete")]
    /// Delete a theme
    Delete {
        /// theme name
        name: String,
    },
    #[structopt(name = "set")]
    /// Set blog use the theme
    Set {
        /// theme name
        name: String,
    },
}

fn main() {
    env_logger::Builder::from_default_env().filter(None, log::LevelFilter::Info).init();

    let opt = Opt::from_args();
    let res = match opt {
        Opt::Init { ref name } => init(name),
        Opt::New { ref tags, ref path } => new(path, tags),
        Opt::Build => build(),
        Opt::Serve { port } => serve(port),
        Opt::Theme(ref subcmd) => theme(subcmd),
    };

    if let Err(ref e) = res {
        log_error(e);
        std::process::exit(1);
    }
}

fn init(name: &str) -> Result<()> {
    let root_dir = env::current_dir()?.join(name);
    let mut mb = Mdblog::new(root_dir)?;
    mb.init()?;
    Ok(())
}

fn new(path: &Path, tags: &[String]) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.create_post(path, tags)?;
    Ok(())
}

fn build() -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.build()?;
    Ok(())
}

fn serve(port: u16) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.serve(port)?;
    Ok(())
}

fn theme(cmd: &SubCommandTheme) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;

    match *cmd {
        SubCommandTheme::List => mb.list_blog_theme()?,
        SubCommandTheme::New { ref name } => mb.create_blog_theme(name)?,
        SubCommandTheme::Delete { ref name } => mb.delete_blog_theme(name)?,
        SubCommandTheme::Set { ref name } => mb.set_blog_theme(name)?,
    }
    Ok(())
}
<commit_msg>format code<commit_after>#![deny(unused_extern_crates)]

use std::env;
use std::path::{Path, PathBuf};

use mdblog::{log_error, Mdblog, Result};
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "mdblog")]
/// static site generator from markdown files
enum Opt {
    #[structopt(name = "init")]
    /// Initialize the blog directory layout
    Init {
        /// the blog directory name
        name: String,
    },
    #[structopt(name = "new")]
    /// Create a blog post
    New {
        #[structopt(short = "t", long = "tag", default_value = "")]
        /// Post tags
        tags: Vec<String>,
        #[structopt(parse(from_os_str))]
        /// Post path relative to blog `posts` directory
        path: PathBuf,
    },
    #[structopt(name = "build")]
    /// Build the blog static files
    Build,
    #[structopt(name = "serve")]
    /// Serve the blog, rebuild on change
    Serve {
        #[structopt(short = "p", long = "port", default_value = "5000")]
        /// Serve the blog at http://127.0.0.1:<port>
        port: u16,
    },
    #[structopt(name = "theme")]
    /// Blog theme operations
    Theme(SubCommandTheme),
}

#[derive(StructOpt, Debug)]
enum SubCommandTheme {
    #[structopt(name = "list")]
    /// list blog themes
    List,
    #[structopt(name = "new")]
    /// Create a new theme
    New {
        /// theme name
        name: String,
    },
    #[structopt(name = "delete")]
    /// Delete a theme
    Delete {
        /// theme name
        name: String,
    },
    #[structopt(name = "set")]
    /// Set blog use the theme
    Set {
        /// theme name
        name: String,
    },
}

fn main() {
    env_logger::Builder::from_default_env()
        .filter(None, log::LevelFilter::Info)
        .init();

    let opt = Opt::from_args();
    let res = match opt {
        Opt::Init { ref name } => init(name),
        Opt::New { ref tags, ref path } => new(path, tags),
        Opt::Build => build(),
        Opt::Serve { port } => serve(port),
        Opt::Theme(ref subcmd) => theme(subcmd),
    };

    if let Err(ref e) = res {
        log_error(e);
        std::process::exit(1);
    }
}

fn init(name: &str) -> Result<()> {
    let root_dir = env::current_dir()?.join(name);
    let mut mb = Mdblog::new(root_dir)?;
    mb.init()?;
    Ok(())
}

fn new(path: &Path, tags: &[String]) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.create_post(path, tags)?;
    Ok(())
}

fn build() -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.build()?;
    Ok(())
}

fn serve(port: u16) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;
    mb.serve(port)?;
    Ok(())
}

fn theme(cmd: &SubCommandTheme) -> Result<()> {
    let root_dir = env::current_dir()?;
    let mut mb = Mdblog::new(&root_dir)?;
    mb.load_customize_settings()?;

    match *cmd {
        SubCommandTheme::List => mb.list_blog_theme()?,
        SubCommandTheme::New { ref name } => mb.create_blog_theme(name)?,
        SubCommandTheme::Delete { ref name } => mb.delete_blog_theme(name)?,
        SubCommandTheme::Set { ref name } => mb.set_blog_theme(name)?,
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate rustyprefetch;
extern crate clap;
extern crate serde_json;
extern crate serde;
use serde::Serializer;
use serde::ser::SerializeSeq;
use rustyprefetch::librp;
use clap::{App, Arg};
use std::fs;
use std::io;

fn process_directory<S>(directory: &str, serializer: S) where S: serde::Serializer {
    let mut seq = serializer.serialize_seq(None).unwrap();
    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.is_file() {
            let path_string = path.into_os_string().into_string().unwrap();
            if path_string.ends_with(".pf"){
                process_file(&path_string,&mut seq);
            }
        }
    }
    seq.end().unwrap();
}

fn process_file<S: serde::ser::SerializeSeq>(filename: &str, serializer: &mut S) -> bool {
    // Check if file is a prefetch file
    let prefetch_file = match librp::prefetch::PrefetchHandle::new(filename) {
        Ok(prefetch_file) => prefetch_file,
        Err(error) => {
            warn!("Could not parse file: {} [error: {}]", filename, error);
            return false;
        }
    };
    let prefetch = prefetch_file.get_prefetch().unwrap();
    serializer.serialize_element(&prefetch).unwrap();
    return true;
}

fn is_directory(source: &str)->bool{
    let metadata = fs::metadata(source).unwrap();

    let file_type = metadata.file_type();

    file_type.is_dir()
}

fn main() {
    let prefetch_arg = Arg::with_name("source")
        .short("s")
        .long("source")
        .value_name("FILE")
        .help("The source path. Can be a file or a directory.")
        .required(true)
        .takes_value(true);

    let metrics_arg = Arg::with_name("pipe")
        .short("t")
        .long("tracechain")
        .help("Output Tracechains");

    let options = App::new("RustyPrefetch")
        .version("0.0.0")
        .author("Matthew Seyer <https://github.com/forensicmatt/RustyPrefetch>")
        .about("Parse prefetch.")
        .arg(prefetch_arg)
        .arg(metrics_arg)
        .get_matches();

    if options.is_present("metrics"){
        unsafe {
            librp::metrics::SKIP_TRACECHAIN = true;
        }
    }

    let source = options.value_of("source").unwrap();

    let mut serializer = serde_json::Serializer::pretty(
        io::stdout()
    );

    if is_directory(source) {
        process_directory(source,&mut serializer);
    } else {
        let mut seq = serializer.serialize_seq(None).unwrap();
        process_file(source,&mut seq);
        seq.end().unwrap();
    }
}
<commit_msg>tracechain option fix<commit_after>#[macro_use] extern crate log;
extern crate rustyprefetch;
extern crate clap;
extern crate serde_json;
extern crate serde;
use serde::Serializer;
use serde::ser::SerializeSeq;
use rustyprefetch::librp;
use clap::{App, Arg};
use std::fs;
use std::io;

fn process_directory<S>(directory: &str, serializer: S) where S: serde::Serializer {
    let mut seq = serializer.serialize_seq(None).unwrap();
    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.is_file() {
            let path_string = path.into_os_string().into_string().unwrap();
            if path_string.ends_with(".pf"){
                process_file(&path_string,&mut seq);
            }
        }
    }
    seq.end().unwrap();
}

fn process_file<S: serde::ser::SerializeSeq>(filename: &str, serializer: &mut S) -> bool {
    // Check if file is a prefetch file
    let prefetch_file = match librp::prefetch::PrefetchHandle::new(filename) {
        Ok(prefetch_file) => prefetch_file,
        Err(error) => {
            warn!("Could not parse file: {} [error: {}]", filename, error);
            return false;
        }
    };
    let prefetch = prefetch_file.get_prefetch().unwrap();
    serializer.serialize_element(&prefetch).unwrap();
    return true;
}

fn is_directory(source: &str)->bool{
    let metadata = fs::metadata(source).unwrap();

    let file_type = metadata.file_type();

    file_type.is_dir()
}

fn main() {
    let prefetch_arg = Arg::with_name("source")
        .short("s")
        .long("source")
        .value_name("FILE")
        .help("The source path. Can be a file or a directory.")
        .required(true)
        .takes_value(true);

    let metrics_arg = Arg::with_name("tracechain")
        .short("t")
        .long("tracechain")
        .help("Output Tracechains");

    let options = App::new("RustyPrefetch")
        .version("0.0.0")
        .author("Matthew Seyer <https://github.com/forensicmatt/RustyPrefetch>")
        .about("Parse prefetch.")
        .arg(prefetch_arg)
        .arg(metrics_arg)
        .get_matches();

    if options.is_present("tracechain"){
        unsafe {
            librp::metrics::SKIP_TRACECHAIN = true;
        }
    }

    let source = options.value_of("source").unwrap();

    let mut serializer = serde_json::Serializer::pretty(
        io::stdout()
    );

    if is_directory(source) {
        process_directory(source,&mut serializer);
    } else {
        let mut seq = serializer.serialize_seq(None).unwrap();
        process_file(source,&mut seq);
        seq.end().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate pnet;
extern crate "rust-icmptime" as icmptime;

use getopts::Options;
use std::os;
use std::old_io::net::ip::{IpAddr, Ipv4Addr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};
use pnet::old_packet::{Packet};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};

use icmptime::packet::{MutIcmpRequestPacket};

use std::iter::repeat;

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    match matches.free.len() {
        0 => panic!("must provide ip address"),
        _ => {}
    }
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Icmp);
    let (mut icmp_sender, mut icmp_receiver) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
    // let packet_vec: Vec<u8> = vec![];
    // let packet = build_icmp_time_request_packet(packet_vec.as_slice());
    let size = MutIcmpRequestPacket::allocation_size();
    let mut vec: Vec<u8> = repeat(0u8).take(size).collect();
    let mut packet = MutIcmpRequestPacket::new(vec.as_mut_slice());
    packet.prepare_for_sending(&addr);

    match icmp_sender.send_to(packet, addr) {
        Ok(n) => println!("sent"),
        Err(e) => panic!("failed to send packet: {}", e)
    }
}
<commit_msg>cruft removal<commit_after>extern crate getopts;
extern crate pnet;
extern crate "rust-icmptime" as icmptime;

use getopts::Options;
use std::os;
use std::old_io::net::ip::{IpAddr, Ipv4Addr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};
use pnet::old_packet::{Packet};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};

use icmptime::packet::{MutIcmpRequestPacket};

use std::iter::repeat;

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    match matches.free.len() {
        0 => panic!("must provide ip address"),
        _ => {}
    }
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Icmp);
    let (mut icmp_sender, mut icmp_receiver) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
    let size = MutIcmpRequestPacket::allocation_size();
    let mut vec: Vec<u8> = repeat(0u8).take(size).collect();
    let mut packet = MutIcmpRequestPacket::new(vec.as_mut_slice());
    packet.prepare_for_sending(&addr);

    match icmp_sender.send_to(packet, addr) {
        Ok(n) => println!("sent"),
        Err(e) => panic!("failed to send packet: {}", e)
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::io::{self, Read, BufReader};
use std::fs::File;

mod wires;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() == 2 {
        // let result = wires::strings_from_file(&args[1]);
        let fs_result = File::open(&args[1]);
        match fs_result {
            Ok(file) =>  {
                let mut reader = BufReader::new(file);
                let mut contents : Vec<u8> = Vec::new();
                let read_result = reader.read_to_end(&mut contents);
                match read_result {
                    Ok(_) => {
                        let stdout = io::stdout();
                        let mut handle = stdout.lock();
                        wires::bytes_to_strings(&contents, &mut handle);
                    },
                    Err(_) => println!("An error occurred reading the buffer")
                }
            },
            Err(_) => println!("Could not read from file.")

        }

    } else {
        println!("Please specify a path");
    }
}

<commit_msg>exit 1 if read fails<commit_after>use std::env;
use std::io::{self, Read, BufReader};
use std::fs::File;
use std::process;

mod wires;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() == 2 {
        // let result = wires::strings_from_file(&args[1]);
        let fs_result = File::open(&args[1]);
        match fs_result {
            Ok(file) =>  {
                let mut reader = BufReader::new(file);
                let mut contents : Vec<u8> = Vec::new();
                let read_result = reader.read_to_end(&mut contents);
                match read_result {
                    Ok(_) => {
                        let stdout = io::stdout();
                        let mut handle = stdout.lock();
                        wires::bytes_to_strings(&contents, &mut handle);
                    },
                    Err(_) => {
                        println!("An error occurred reading the buffer");
                        process::exit(1);
                    }
                }
            },
            Err(_) => {
                println!("Could not read from file.");
                process::exit(1);
            }

        }

    } else {
        println!("Please specify a path");
        process::exit(1);
    }
}

<|endoftext|>