<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

struct FileEntry {
    inode: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {
    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            println!("{}: invalid directory", dir);
            return
        },
    };

    for path in  entries.filter( |x| x.is_ok() ).map( |x| x.unwrap().path() )
                .collect::<Vec<PathBuf>>() {
        if let Some(path_str) = path.to_str() {
            if let Ok(metadata) = path.symlink_metadata() {
                let ft = metadata.file_type();
                if ft.is_symlink() {
                    continue;
                } else if ft.is_file() {
                    match metadata.len() {
                        0 => continue,
                        i => h.entry(i).or_insert_with(Vec::new)
                              .push(
                               FileEntry{
                                   inode : metadata.ino(),
                                   dev   : metadata.dev(),
                                   path  : String::from(path_str),
                               }),
                    };
                } else if ft.is_dir() {
                    collect_files(&(String::from(path_str)), h);
                }
            }
        }
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<FileEntry>>,
                   vec: &Vec<FileEntry> ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(&file_entry.path) {
            let mut buf: [u8; 1024] = [0; 1024];
            if let Ok(nbytes) = file.read(&mut buf) {
                let mut hasher = DefaultHasher::new();
                hasher.write(&buf[..nbytes as usize]);
                let k = hasher.finish();
                duplicates.entry(k).or_insert_with(Vec::new)
                    .push(
                        FileEntry{
                            inode : file_entry.inode,
                            dev   : file_entry.dev,
                            path  : file_entry.path.to_string(),
                        });
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        find_duplicates(&mut duplicates, &val);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                // for_each becomes stable v1.22.0 onwards. Should uncomment then.
                //vec.iter().for_each(|f| println!("{}", i.path));
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<commit_msg>Use tuples to unbox multiple values.<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

struct FileEntry {
    inode: u64,
    dev:  u64,
    path : String,
}

fn collect_files(dir: &String, h: &mut HashMap<u64, Vec<FileEntry>>) {

    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            println!("{}: invalid directory", dir);
            return
        },
    };

    for path in  entries.filter( |x| x.is_ok() ).map( |x| x.unwrap().path() )
                .collect::<Vec<PathBuf>>() {
        if let (Some(path_str), Ok(metadata)) =
                (path.to_str(), path.symlink_metadata()) {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                match metadata.len() {
                    0 => continue,
                    i => h.entry(i).or_insert_with(Vec::new)
                          .push(
                           FileEntry{
                               inode : metadata.ino(),
                               dev   : metadata.dev(),
                               path  : String::from(path_str),
                           }),
                };
            } else if ft.is_dir() {
                collect_files(&(String::from(path_str)), h);
            }
        }
    }
}

fn find_duplicates(duplicates: &mut HashMap<u64, Vec<FileEntry>>,
                   vec: &Vec<FileEntry> ) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(&file_entry.path) {
            let mut buf: [u8; 1024] = [0; 1024];
            if let Ok(nbytes) = file.read(&mut buf) {
                let mut hasher = DefaultHasher::new();
                hasher.write(&buf[..nbytes as usize]);
                let k = hasher.finish();
                duplicates.entry(k).or_insert_with(Vec::new)
                    .push(
                        FileEntry{
                            inode : file_entry.inode,
                            dev   : file_entry.dev,
                            path  : file_entry.path.to_string(),
                        });
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    // Print out usage if no directories are given.
    if args.len() == 1 {
        println!("Usage: {} <dir1> [dir2 [dir3 ...]]", args[0]);
        ::std::process::exit(0);
    }

    let mut hmap: HashMap<u64, Vec<FileEntry> > = HashMap::new();

    for dir in &args[1..] {
        collect_files(dir, &mut hmap);
    }

    // Get rid of all the single entries.
    hmap.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    for (key, val) in hmap.iter() {
        let mut duplicates: HashMap<u64, Vec<FileEntry> > = HashMap::new();
        find_duplicates(&mut duplicates, &val);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                println!("{} files in cluster {} (size: {}, digest: {})",
                         vec.len(), cluster, key, hash);
                // for_each becomes stable v1.22.0 onwards. Should uncomment then.
                //vec.iter().for_each(|f| println!("{}", i.path));
                for file_entry in vec {
                    println!("{}", file_entry.path);
                }
                cluster += 1;
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }
}

fn main() {
    let (width, height) = (800, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Change width for better proportions<commit_after>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate conrod;
extern crate piston_window;
extern crate find_folder;
extern crate graphics;
extern crate lyon;
extern crate xml5ever;
extern crate encoding;
extern crate cssparser;

use std::fs::File;
use std::io::Read;
use std::sync::mpsc;
use std::default::Default;
use std::iter;
use std::string::String;

use conrod::{Theme, Widget};
use piston_window::*;

use lyon::path_builder::*;

use xml5ever::tendril::SliceExt;
use xml5ever::parse;
use xml5ever::tree_builder::TreeSink;
use xml5ever::rcdom;
use xml5ever::rcdom::{Document, Element, RcDom, Handle};

/// Conrod is backend agnostic. Here, we define the `piston_window` backend to use for our `Ui`.
type Backend = (piston_window::G2dTexture<'static>, piston_window::Glyphs);
type Ui = conrod::Ui<Backend>;
type UiCell<'a> = conrod::UiCell<'a, Backend>;

struct InkApp {
    dom: RcDom,
    elem_sender: mpsc::Sender<(usize, usize, bool)>,
    elem_receiver: mpsc::Receiver<(usize, usize, bool)>,
}

impl InkApp {
    fn new() -> Self {
        let (elem_sender, elem_receiver) = mpsc::channel();
        InkApp {
            dom: RcDom::default(),
            elem_sender: elem_sender,
            elem_receiver: elem_receiver,
        }
    }

    fn set_dom(&mut self, dom: RcDom) {
        self.dom = dom;
    }

    fn get_doc_handle(&mut self) -> Handle {
        self.dom.get_document()
    }
}

fn main() {
    let mut file = File::open("tests/documents/testrect.svg").unwrap();

    let mut file_string = String::new();
    if let Err(err) = file.read_to_string(&mut file_string) {
        println!("Reading failed: {}", err);
        std::process::exit(1);
    };

    let input = file_string.to_tendril();

    let dom: RcDom = parse(iter::once(input), Default::default());

    // Construct the window.
    let mut window: PistonWindow = WindowSettings::new("Inkrust", [720, 360])
                                       .opengl(piston_window::OpenGL::V3_2)
                                       .samples(4)
                                       .exit_on_esc(true)
                                       .build()
                                       .unwrap();

    // Construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.clone()).unwrap();
        Ui::new(glyph_cache, theme)
    };

    let mut app = InkApp::new();
    app.set_dom(dom);

    let doc = app.get_doc_handle();

    // parse dom generating shapes for rendering
    walk("", doc);

    window.set_ups(60);

    // Poll events from the window.
    while let Some(event) = window.next() {
        ui.handle_event(event.clone());
        event.update(|_| ui.set_widgets(|mut ui| set_widgets(&mut ui, &mut app)));
        window.draw_2d(&event, |c, g| ui.draw_if_changed(c, g));
    }
}

// Declare the `WidgetId`s and instantiate the widgets.
fn set_widgets(ui: &mut UiCell, app: &mut InkApp) {
    use conrod::{Canvas, Circle, Line, Oval, PointPath, Polygon, Positionable, Rectangle};
    use std::iter::once;

    widget_ids!{
        CANVAS,
        LINE,
        POINT_PATH,
        RECTANGLE_FILL,
        RECTANGLE_OUTLINE,
        TRAPEZOID,
        OVAL_FILL,
        OVAL_OUTLINE,
        CIRCLE,
	};

    // The background canvas upon which we'll place our widgets.
    Canvas::new().pad(80.0).set(CANVAS, ui);

    Line::centred([-40.0, -40.0], [40.0, 40.0]).top_left_of(CANVAS).set(LINE, ui);

    let left = [-40.0, -40.0];
    let top = [0.0, 40.0];
    let right = [40.0, -40.0];
    let points = once(left).chain(once(top)).chain(once(right));
    PointPath::centred(points).down(80.0).set(POINT_PATH, ui);

    Rectangle::fill([80.0, 80.0]).down(80.0).set(RECTANGLE_FILL, ui);

    Rectangle::outline([80.0, 80.0]).down(80.0).set(RECTANGLE_OUTLINE, ui);

    let bl = [-40.0, -40.0];
    let tl = [-20.0, 40.0];
    let tr = [20.0, 40.0];
    let br = [40.0, -40.0];
    let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br));
    Polygon::centred_fill(points).right_from(LINE, 80.0).set(TRAPEZOID, ui);

    Oval::fill([40.0, 80.0]).down(80.0).align_middle_x().set(OVAL_FILL, ui);

    Oval::outline([80.0, 40.0]).down(100.0).align_middle_x().set(OVAL_OUTLINE, ui);

    Circle::fill(40.0).down(100.0).align_middle_x().set(CIRCLE, ui);
}

pub fn escape_default(s: &str) -> String {
    s.chars().flat_map(|c| c.escape_default()).collect()
}

fn walk(prefix: &str, handle: Handle) {
    use conrod::Rectangle;
    use conrod::Dimensions;
    use conrod::ShapeStyle as Style;
    use conrod::color::Color;
    use cssparser::{Parser, DeclarationListParser, DeclarationParser, AtRuleParser, Token,
                    Color as CSSParserColor, Delimiter, parse_important, NumericValue, AtRuleType};

    struct StyleParser;

    struct Property {
        name: String,
        value: String,
    }

    impl DeclarationParser for StyleParser {
        type Declaration = Property;

        fn parse_value(&self, name: &str, input: &mut Parser) -> Result<Property, ()> {
            let mut value = vec![];
            loop {
                let start_position = input.position();
                if let Ok(mut token) = input.next() {
                    if token == Token::Delim('!') {
                        input.reset(start_position);
                        if parse_important(input).is_ok() {
                            if input.is_exhausted() {
                                break;
                            }
                        }
                        input.reset(start_position);
                        token = input.next().unwrap();
                    }
                    value.push(one_component_value_to_string(token, input));
                } else {
                    break;
                }
            }

            Ok(Property {
                name: value[0],
                value: value[1],
            })
        }
    }

    fn component_values(input: &mut Parser) -> Vec<String> {
        let mut values = vec![];
        while let Ok(token) = input.next_including_whitespace() {
            values.push(one_component_value_to_string(token, input));
        }
        values
    }

    fn one_component_value_to_string(token: Token, input: &mut Parser) -> String {
        //        fn numeric(value: NumericValue) -> Vec<f32> {
        //            vec![
        //                Token::Number(value).to_css_string().to_json(),
        //                match value.int_value { Some(i) => i.to_json(), None => value.value.to_json() },
        //                match value.int_value { Some(_) => "integer", None => "number" }.to_json()
        //            ]
        //        }

        match token {
            Token::Ident(v) => v.to_string(),
            // Token::AtKeyword(v) => v,
            Token::Hash(v) => v.to_string(),
            Token::IDHash(v) => v.to_string(),
            //            Token::QuotedString(v) => Property {name: "id", value: v},
            //            Token::UnquotedUrl(v) => Property {name: "id", value: v},
            //            Token::Delim(v) => Property {name: "id", value: v},
            //
            //            Token::Number(v) => Json::Array({
            //                let mut v = vec!["number".to_json()];
            //                v.extend(numeric(v));
            //                v
            //            }),
            //            Token::Percentage(PercentageValue { unit_value, int_value, has_sign }) => Json::Array({
            //                let mut v = vec!["percentage".to_json()];
            //                v.extend(numeric(NumericValue {
            //                    value: unit_value * 100.,
            //                    int_value: int_value,
            //                    has_sign: has_sign,
            //                }));
            //                v
            //            }),
            //            Token::Dimension(value, unit) => Json::Array({
            //                let mut v = vec!["dimension".to_json()];
            //                v.extend(numeric(value));
            //                v.push(unit.to_json());
            //                v
            //            }),
            //
            //            Token::UnicodeRange(start, end) => Property {name: "id", value: v},
            //
            //            Token::WhiteSpace(_) => " ".to_json(),
            //            Token::Comment(_) => "/**/".to_json(),
            Token::Colon => "".to_string(),
            //            Token::Semicolon => ";".to_json(),
            //            Token::Comma => ",".to_json(),
            //            Token::IncludeMatch => "~=".to_json(),
            //            Token::DashMatch => "|=".to_json(),
            //            Token::PrefixMatch => "^=".to_json(),
            //            Token::SuffixMatch => "$=".to_json(),
            //            Token::SubstringMatch => "*=".to_json(),
            //            Token::Column => "||".to_json(),
            //            Token::CDO => "<!--".to_json(),
            //            Token::CDC => "-->".to_json(),
            //
            //            Token::Function(name) => Json::Array({
            //                let mut v = vec!["function".to_json(), name.to_json()];
            //                v.extend(nested(input));
            //                v
            //            }),
            //            Token::ParenthesisBlock => Json::Array({
            //                let mut v = vec!["()".to_json()];
            //                v.extend(nested(input));
            //                v
            //            }),
            //            Token::SquareBracketBlock => Json::Array({
            //                let mut v = vec!["[]".to_json()];
            //                v.extend(nested(input));
            //                v
            //            }),
            //            Token::CurlyBracketBlock => Json::Array({
            //                let mut v = vec!["{}".to_json()];
            //                v.extend(nested(input));
            //                v
            //            }),
            //            Token::BadUrl => Property {name: "id", value: v},
            //            Token::BadString => Property {name: "id", value: v},
            //            Token::CloseParenthesis => Property {name: "id", value: v},
            //            Token::CloseSquareBracket => Property {name: "id", value: v},
            //            Token::CloseCurlyBracket => Property {name: "id", value: v},
            _ => "".to_string(),
        }
    }

    impl AtRuleParser for StyleParser {
        type Prelude = Vec<String>;
        type AtRule = String;

        fn parse_prelude(&self,
                         name: &str,
                         input: &mut Parser)
                         -> Result<AtRuleType<Vec<String>, String>, ()> {
            Ok(AtRuleType::OptionalBlock(component_values(input)))
        }

        fn parse_block(&self, mut prelude: Vec<String>, input: &mut Parser) -> Result<String, ()> {
            prelude.push(component_values(input).into_iter().collect());
            let s: String = prelude.into_iter().collect();
            Ok(s)
        }

        fn rule_without_block(&self, mut prelude: Vec<String>) -> String {
            prelude.push("".to_string());
            "".to_string()
        }
    }

    let node = handle.borrow();

    print!("{}", prefix);
    match node.node {
        Document => println!("#document"),

        rcdom::Text(ref text) => println!("#text {}", escape_default(text)),

        Element(ref name, ref attrs) => {
            let lname = name.local.as_ref();
            println!("{:?}", lname);
            match lname {
                "rect" => {
                    let mut dim: Dimensions = [0.0, 0.0];
                    let mut style = Style::fill();
                    for attr in attrs {
                        let key_val = (attr.name.local.as_ref(), attr.value.as_ref());
                        match key_val {
                            w @ ("width", _) => {
                                let (_, w) = w;
                                let w = w.parse::<f64>()
                                         .expect("Parse error");
                                dim[0] = w;
                                println!("{:?}", w);
                            }
                            h @ ("height", _) => {
                                let (_, h) = h;
                                let h = h.parse::<f64>()
                                         .expect("Parse error");
                                dim[1] = h;
                                println!("{:?}", h);
                            }
                            i @ ("id", _) => {
                                let (_, i) = i;
                                println!("{:?}", i);
                            }
                            s @ ("style", _) => {
                                let (_, s) = s;
                                println!("{:?}", s);
                                let mut parser = Parser::new(&s);
                                let properties = DeclarationListParser::new(&mut parser,
                                                                            StyleParser);
                                let properties: Vec<String> = properties.map(|result| {
                                                                            result.unwrap()
                                                                        })
                                                                        .collect();
                                for property in properties {
                                    println!("{:?}", property);
                                }
                                // 	while !parser.is_exhausted() {
                                // 		// TODO parse property string into (key,value)
                                // 				let property = parser.parse_until_before(
                                // 					Delimiter::Semicolon | Delimiter::None,
                                // 					|mut t| loop {
                                // 						match t.next_including_whitespace_and_comments() {
                                // 					Ok(Token::WhiteSpace(_)) |
                                // 					Ok(Token::Colon) |
                                // 					Ok(Token::Comment(_)) => {},
                                // 			                r => return r
                                // 						}
                                // 			        }
                                // 				).expect("Style parse error");
                                // 				match property {
                                // 					(Token::Ident(k), Token::Hash(v)) |
                                // 						(Token::Ident(k), Token::IDHash(v)) => {
                                // 								println!("{:?}:{:?}", k, v);
                                // 								let color = CSSParserColor::parse(&mut Parser::new(&s))
                                // 								.expect("Color parse error");
                                // 							style.set_color(Color::Rgba(
                                // 									color.red,
                                // 									color.green,
                                // 									color.blue,
                                // 									color.alpha));
                                // 					}
                                // 					Token::AtKeyword(s) => println!("{:?} k", s),
                                // 					Token::QuotedString(s) => println!("{:?} q", s),
                                // 					Token::UnquotedUrl(s) => println!("{:?} u", s),
                                // 					Token::Number(s) => println!("{:?} n", s),
                                // 					Token::UnicodeRange(v, s) => println!("{:?}{:?} r", v, s),
                                // 					Token::WhiteSpace(s) => println!("{:?} w", s),
                                // 					Token::Dimension(v, s) => println!("{:?}{:?} d", v, s),
                                // 					_ => { }
                                // 				}
                                // 	}
                            }
                            _ => {}
                        }
                    }
                    let rect = Rectangle::styled(dim, style);
                }
                _ => {}
            }
        }
        _ => {}
    }

    let new_indent = {
        let mut temp = String::new();
        temp.push_str(prefix);
        temp.push_str("    ");
        temp
    };

    for child in node.children
                     .iter()
                     .filter(|child| match child.borrow().node {
                         rcdom::Text(_) | Element(_, _) => true,
                         _ => false,
                     }) {
        walk(&new_indent, child.clone());
    }
}
<commit_msg>Working towards adding renderables to app.<commit_after>#[macro_use]
extern crate conrod;
extern crate piston_window;
extern crate find_folder;
extern crate graphics;
extern crate lyon;
extern crate xml5ever;
extern crate encoding;
extern crate cssparser;

use std::fs::File;
use std::io::Read;
use std::sync::mpsc;
use std::default::Default;
use std::iter;
use std::string::String;

use conrod::{Theme, Widget};
use piston_window::*;

use lyon::path_builder::*;

use xml5ever::tendril::SliceExt;
use xml5ever::parse;
use xml5ever::tree_builder::TreeSink;
use xml5ever::rcdom;
use xml5ever::rcdom::{Document, Element, RcDom, Handle};

/// Conrod is backend agnostic. Here, we define the `piston_window` backend to use for our `Ui`.
type Backend = (piston_window::G2dTexture<'static>, piston_window::Glyphs);
type Ui = conrod::Ui<Backend>;
type UiCell<'a> = conrod::UiCell<'a, Backend>;

struct InkApp {
    dom: RcDom,
    renderables: Vec<Rectangle>,
    elem_sender: mpsc::Sender<(usize, usize, bool)>,
    elem_receiver: mpsc::Receiver<(usize, usize, bool)>,
}

impl InkApp {
    fn new() -> Self {
        let (elem_sender, elem_receiver) = mpsc::channel();
        InkApp {
            dom: RcDom::default(),
            renderables: Vec::new(),
            elem_sender: elem_sender,
            elem_receiver: elem_receiver,
        }
    }

    fn set_dom(&mut self, dom: RcDom) {
        self.dom = dom;
    }

    fn get_doc_handle(&mut self) -> Handle {
        self.dom.get_document()
    }
}

fn main() {
    let mut file = File::open("tests/documents/testrect.svg").unwrap();

    let mut file_string = String::new();
    if let Err(err) = file.read_to_string(&mut file_string) {
        println!("Reading failed: {}", err);
        std::process::exit(1);
    };

    let input = file_string.to_tendril();

    let dom: RcDom = parse(iter::once(input), Default::default());

    // Construct the window.
    let mut window: PistonWindow = WindowSettings::new("Inkrust", [720, 360])
                                       .opengl(piston_window::OpenGL::V3_2)
                                       .samples(4)
                                       .exit_on_esc(true)
                                       .build()
                                       .unwrap();

    // Construct our `Ui`.
    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.clone()).unwrap();
        Ui::new(glyph_cache, theme)
    };

    let mut app = InkApp::new();
    app.set_dom(dom);

    // parse dom generating shapes for rendering
    walk("", &app);

    window.set_ups(60);

    // Poll events from the window.
    while let Some(event) = window.next() {
        ui.handle_event(event.clone());
        event.update(|_| ui.set_widgets(|mut ui| set_widgets(&mut ui, &mut app)));
        window.draw_2d(&event, |c, g| ui.draw_if_changed(c, g));
    }
}

// Declare the `WidgetId`s and instantiate the widgets.
fn set_widgets(ui: &mut UiCell, app: &mut InkApp) {
    use conrod::{Canvas, Circle, Line, Oval, PointPath, Polygon, Positionable, Rectangle};
    use std::iter::once;

    widget_ids!{
        CANVAS,
        LINE,
        POINT_PATH,
        RECTANGLE_FILL,
        RECTANGLE_OUTLINE,
        TRAPEZOID,
        OVAL_FILL,
        OVAL_OUTLINE,
        CIRCLE,
	};

    // The background canvas upon which we'll place our widgets.
    Canvas::new().pad(80.0).set(CANVAS, ui);

    Line::centred([-40.0, -40.0], [40.0, 40.0]).top_left_of(CANVAS).set(LINE, ui);

    let left = [-40.0, -40.0];
    let top = [0.0, 40.0];
    let right = [40.0, -40.0];
    let points = once(left).chain(once(top)).chain(once(right));
    PointPath::centred(points).down(80.0).set(POINT_PATH, ui);

    Rectangle::fill([80.0, 80.0]).down(80.0).set(RECTANGLE_FILL, ui);

    Rectangle::outline([80.0, 80.0]).down(80.0).set(RECTANGLE_OUTLINE, ui);

    let bl = [-40.0, -40.0];
    let tl = [-20.0, 40.0];
    let tr = [20.0, 40.0];
    let br = [40.0, -40.0];
    let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br));
    Polygon::centred_fill(points).right_from(LINE, 80.0).set(TRAPEZOID, ui);

    Oval::fill([40.0, 80.0]).down(80.0).align_middle_x().set(OVAL_FILL, ui);

    Oval::outline([80.0, 40.0]).down(100.0).align_middle_x().set(OVAL_OUTLINE, ui);

    Circle::fill(40.0).down(100.0).align_middle_x().set(CIRCLE, ui);
}

pub fn escape_default(s: &str) -> String {
    s.chars().flat_map(|c| c.escape_default()).collect()
}

fn walk(prefix: &str, &mut app: InkApp) {
    use conrod::{Rectangle, Dimensions, Point, ShapeStyle, Positionable};
    use conrod::color::Color;

    let doc = app.get_doc_handle();
    let node = doc.borrow();

    print!("{}", prefix);
    match node.node {
        Document => println!("#document"),

        rcdom::Text(ref text) => println!("#text {}", escape_default(text)),

        Element(ref name, ref attrs) => {
            let lname = name.local.as_ref();
            println!("{:?}", lname);
            match lname {
                "rect" => {
                    let mut dim: Dimensions = [0.0, 0.0];
                    let mut pos: Point = [0.0, 0.0];
                    let mut color: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
                    for attr in attrs {
                        let key_val = (attr.name.local.as_ref(), attr.value.as_ref());
                        match key_val {
                            x @ ("x", _) => {
                                let (_, x) = x;
                                let x = x.parse::<f64>()
                                         .expect("Parse error");
                                pos[0] = x;
                                println!("{:?}", x);
                            }
                            y @ ("y", _) => {
                                let (_, y) = y;
                                let y = y.parse::<f64>()
                                         .expect("Parse error");
                                pos[1] = y;
                                println!("{:?}", y);
                            }
                            w @ ("width", _) => {
                                let (_, w) = w;
                                let w = w.parse::<f64>()
                                         .expect("Parse error");
                                dim[0] = w;
                                println!("{:?}", w);
                            }
                            h @ ("height", _) => {
                                let (_, h) = h;
                                let h = h.parse::<f64>()
                                         .expect("Parse error");
                                dim[1] = h;
                                println!("{:?}", h);
                            }
                            i @ ("id", _) => {
                                let (_, i) = i;
                                println!("{:?}", i);
                            }
                            s @ ("style", _) => {
                                let (_, s) = s;
                                println!("{:?}", s);
                                // let mut parser = Parser::new(&s);
                                // 	while !parser.is_exhausted() {
                                // 		// TODO parse property string into (key,value)
                                // 				let property = parser.parse_until_before(
                                // 					Delimiter::Semicolon | Delimiter::None,
                                // 					|mut t| loop {
                                // 						match t.next_including_whitespace_and_comments() {
                                // 					Ok(Token::WhiteSpace(_)) |
                                // 					Ok(Token::Colon) |
                                // 					Ok(Token::Comment(_)) => {},
                                // 			                r => return r
                                // 						}
                                // 			        }
                                // 				).expect("Style parse error");
                                // 				match property {
                                // 					(Token::Ident(k), Token::Hash(v)) |
                                // 						(Token::Ident(k), Token::IDHash(v)) => {
                                // 								println!("{:?}:{:?}", k, v);
                                // 								let color = CSSParserColor::parse(&mut Parser::new(&s))
                                // 								.expect("Color parse error");
                                // 							style.set_color(Color::Rgba(
                                // 									color.red,
                                // 									color.green,
                                // 									color.blue,
                                // 									color.alpha));
                                // 					}
                                // 					Token::AtKeyword(s) => println!("{:?} k", s),
                                // 					Token::QuotedString(s) => println!("{:?} q", s),
                                // 					Token::UnquotedUrl(s) => println!("{:?} u", s),
                                // 					Token::Number(s) => println!("{:?} n", s),
                                // 					Token::UnicodeRange(v, s) => println!("{:?}{:?} r", v, s),
                                // 					Token::WhiteSpace(s) => println!("{:?} w", s),
                                // 					Token::Dimension(v, s) => println!("{:?}{:?} d", v, s),
                                // 					_ => { }
                                // 				}
                                // 	}
                            }
                            _ => {}
                        }
                    }
                    let rect = Rectangle::styled(dim, ShapeStyle::fill_with(color)).left(pos[0]).down(pos[1]);
                }
                _ => {}
            }
        }
        _ => {}
    }

    let new_indent = {
        let mut temp = String::new();
        temp.push_str(prefix);
        temp.push_str("    ");
        temp
    };

    for child in node.children
                     .iter()
                     .filter(|child| match child.borrow().node {
                         rcdom::Text(_) | Element(_, _) => true,
                         _ => false,
                     }) {
        walk(&new_indent, &app);
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size: u64,
    hash: u64,
    files: Vec<String>,
}

fn collect_files(
    dir: &str,
    files: &mut HashMap<u64, Vec<String>>,
    inodes: &mut BTreeSet<(u64, u64)>,
) {
    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return;
        }
    };

    for path in entries
        .filter(|x| x.is_ok())
        .map(|x| x.unwrap().path())
        .collect::<Vec<PathBuf>>()
    {
        if let (Some(path_str), Ok(metadata)) =
            (path.to_str(), path.symlink_metadata())
        {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, // Ignore empty files.
                    i => files
                        .entry(i)
                        .or_insert_with(Vec::new)
                        .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(path_str, files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(
    duplicates: &mut HashMap<u64, Vec<String>>,
    vec: &Vec<String>,
    thorough: bool,
) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates
                    .entry(hash)
                    .or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(
    files: &Vec<String>,
    cluster: i32,
    size: u64,
    hash: u64,
    json_list: &mut Vec<FileEntry>,
    json_output: bool,
) {
    if json_output {
        json_list.push(FileEntry {
            size,
            hash,
            files: files.to_vec(),
        });
    } else {
        println!(
            "{} files in cluster {} (size: {}, digest: {})",
            files.len(),
            cluster,
            size,
            hash
        );
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        // files.iter().for_each(|f| println!("{}", f.path));
        for file in files {
            println!("{}", file);
        }
    }
}

fn exhaustive_search(
    content_map: &mut HashMap<Vec<u8>, Vec<String>>,
    files: &Vec<String>,
) {
    for file_name in files {
        if let Ok(mut file) = File::open(file_name) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                content_map
                    .entry(contents)
                    .or_insert_with(Vec::new)
                    .push(file_name.to_string());
            } else {
                warn!("Failed to read {}", file_name);
            }
        } else {
            warn!("Failed to open {}", file_name);
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let binary_name = env::args()
        .next()
        .expect("Unable to figure out the binary name");

    let mut files: HashMap<u64, Vec<String>> = HashMap::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    {
        let mut inodes: BTreeSet<(u64, u64)> = BTreeSet::new();
        for dir in env::args().skip(1) {
            match dir.as_ref() {
                "-t" => {
                    thorough = true;
                    continue;
                }
                "-e" => {
                    thorough = false;
                    exhaustive = false;
                    continue;
                }
                "-j" => {
                    json_output = true;
                    continue;
                }
                _ => {
                    print_usage = false;
                    collect_files(&dir, &mut files, &mut inodes);
                }
            }
        }
    }

    if print_usage {
        println!(
            "Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
            binary_name
        );
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    files.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json: Vec<FileEntry> = Vec::new();
    for (key, val) in files {
        let mut duplicates: HashMap<u64, Vec<String>> = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut content_map: HashMap<
                        Vec<u8>,
                        Vec<String>,
                    > = HashMap::new();
                    exhaustive_search(&mut content_map, &vec);
                    for (_, v) in content_map {
                        if v.len() >= 2 {
                            print_duplicates(
                                &v,
                                cluster,
                                key,
                                hash,
                                &mut json,
                                json_output,
                            );
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(
                        &vec,
                        cluster,
                        key,
                        hash,
                        &mut json,
                        json_output,
                    );
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json).unwrap());
    }
}
<commit_msg>Use a single iterator<commit_after>use std::fs;
use std::env;
use std::fs::File;
use std::io::Read;
use std::hash::Hasher;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::BTreeSet;
use std::os::unix::fs::MetadataExt;
use std::collections::hash_map::DefaultHasher;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Serialize, Deserialize)]
struct FileEntry {
    size: u64,
    hash: u64,
    files: Vec<String>,
}

fn collect_files(
    dir: &str,
    files: &mut HashMap<u64, Vec<String>>,
    inodes: &mut BTreeSet<(u64, u64)>,
) {
    let entries = match fs::read_dir(dir) {
        Ok(x) => x,
        _ => {
            warn!("{}: invalid directory", dir);
            return;
        }
    };

    for path in entries
        .filter(|x| x.is_ok())
        .map(|x| x.unwrap().path())
        .collect::<Vec<PathBuf>>()
    {
        if let (Some(path_str), Ok(metadata)) =
            (path.to_str(), path.symlink_metadata())
        {
            let ft = metadata.file_type();
            if ft.is_symlink() {
                continue;
            } else if ft.is_file() {
                let inode = metadata.ino();
                let device = metadata.dev();
                if inodes.contains(&(inode, device)) {
                    continue;
                }
                inodes.insert((inode, device));
                match metadata.len() {
                    0 => continue, // Ignore empty files.
                    i => files
                        .entry(i)
                        .or_insert_with(Vec::new)
                        .push(String::from(path_str)),
                };
            } else if ft.is_dir() {
                collect_files(path_str, files, inodes);
            }
        } else {
            warn!("Failed to retrieve metadata for {}", path.to_str().unwrap());
        }
    }
}

fn find_duplicates(
    duplicates: &mut HashMap<u64, Vec<String>>,
    vec: &Vec<String>,
    thorough: bool,
) {
    for file_entry in vec {
        if let Ok(mut file) = File::open(file_entry) {
            let mut hash: u64 = 0;
            let mut hasher = DefaultHasher::new();
            if thorough {
                let mut contents: Vec<u8> = Vec::new();
                if let Ok(_) = file.read_to_end(&mut contents) {
                    hasher.write(&contents[..]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {}", file_entry);
                }
            } else {
                let mut buf: [u8; 1024] = [0; 1024];
                if let Ok(nbytes) = file.read(&mut buf) {
                    hasher.write(&buf[..nbytes as usize]);
                    hash = hasher.finish();
                } else {
                    warn!("Failed to read {} chunk", file_entry);
                }
            }
            if hash != 0 {
                duplicates
                    .entry(hash)
                    .or_insert_with(Vec::new)
                    .push(file_entry.to_string());
            }
        } else {
            warn!("Failed to open file {}", file_entry);
        }
    }
}

fn print_duplicates(
    files: &Vec<String>,
    cluster: i32,
    size: u64,
    hash: u64,
    json_list: &mut Vec<FileEntry>,
    json_output: bool,
) {
    if json_output {
        json_list.push(FileEntry {
            size,
            hash,
            files: files.to_vec(),
        });
    } else {
        println!(
            "{} files in cluster {} (size: {}, digest: {})",
            files.len(),
            cluster,
            size,
            hash
        );
        // for_each becomes stable v1.22.0 onwards. Should uncomment then.
        // files.iter().for_each(|f| println!("{}", f.path));
        for file in files {
            println!("{}", file);
        }
    }
}

fn exhaustive_search(
    content_map: &mut HashMap<Vec<u8>, Vec<String>>,
    files: &Vec<String>,
) {
    for file_name in files {
        if let Ok(mut file) = File::open(file_name) {
            let mut contents: Vec<u8> = Vec::new();
            if let Ok(_) = file.read_to_end(&mut contents) {
                content_map
                    .entry(contents)
                    .or_insert_with(Vec::new)
                    .push(file_name.to_string());
            } else {
                warn!("Failed to read {}", file_name);
            }
        } else {
            warn!("Failed to open {}", file_name);
        }
    }
}

fn main() {
    env_logger::init().unwrap();

    let mut arg_iterator = env::args();
    let binary_name = arg_iterator
        .next()
        .expect("Unable to figure out the binary name");

    let mut files: HashMap<u64, Vec<String>> = HashMap::new();

    let mut thorough = false;
    let mut exhaustive = false;
    let mut json_output = false;
    let mut print_usage = true;

    {
        let mut inodes: BTreeSet<(u64, u64)> = BTreeSet::new();
        for dir in arg_iterator {
            match dir.as_ref() {
                "-t" => {
                    thorough = true;
                    continue;
                }
                "-e" => {
                    thorough = false;
                    exhaustive = false;
                    continue;
                }
                "-j" => {
                    json_output = true;
                    continue;
                }
                _ => {
                    print_usage = false;
                    collect_files(&dir, &mut files, &mut inodes);
                }
            }
        }
    }

    if print_usage {
        println!(
            "Usage: {} [-t] [-e] [-j] <dir1> [dir2 [dir3 ...]]",
            binary_name
        );
        ::std::process::exit(0);
    }

    // Get rid of all the single entries.
    files.retain(|_, v| v.len() >= 2);

    let mut cluster = 1;

    let mut json: Vec<FileEntry> = Vec::new();
    for (key, val) in files {
        let mut duplicates: HashMap<u64, Vec<String>> = HashMap::new();
        find_duplicates(&mut duplicates, &val, thorough);

        for (hash, vec) in duplicates {
            if vec.len() >= 2 {
                if exhaustive {
                    let mut content_map: HashMap<
                        Vec<u8>,
                        Vec<String>,
                    > = HashMap::new();
                    exhaustive_search(&mut content_map, &vec);
                    for (_, v) in content_map {
                        if v.len() >= 2 {
                            print_duplicates(
                                &v,
                                cluster,
                                key,
                                hash,
                                &mut json,
                                json_output,
                            );
                            cluster += 1;
                        }
                    }
                } else {
                    print_duplicates(
                        &vec,
                        cluster,
                        key,
                        hash,
                        &mut json,
                        json_output,
                    );
                    cluster += 1;
                }
            }
        }
    }
    if json_output {
        println!("{}", serde_json::to_string_pretty(&json).unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate mio;

use std::io::Write;
use std::io::Read;
use std::rc::{Rc};
use std::cell::{RefCell};
use mio::tcp::*;
mod server;
mod broker;
mod message;

const MQTT_SERVER_TOKEN: mio::Token = mio::Token(0);

fn main() {
    let address = "0.0.0.0:1883".parse().unwrap();
    let listener = TcpListener::bind(&address).expect(&format!("Could not bind to {}", address));
    let mut event_loop = mio::EventLoop::new().expect("Could not create MIO event loop");
    event_loop.register(&listener, MQTT_SERVER_TOKEN).expect("Could not register listener");
    event_loop.run(&mut MioHandler::new(listener, std::env::args().len() == 1)).expect("Could not run event loop");
}

struct MioHandler {
    listener: TcpListener,
    connections: mio::util::Slab<Rc<RefCell<Connection>>>,
    mqtt_streams: mio::util::Slab<server::Stream>,
    server: server::Server<Connection>,
}

struct Connection {
    socket: mio::tcp::TcpStream,
}

impl MioHandler {
    fn new(listener: TcpListener, use_cache: bool) -> Self {

        if !use_cache {
            println!("Disabling the cache");
        }

        let max_conns = 1024 * 32;
        let connections_slab = mio::util::Slab::new_starting_at(mio::Token(1), max_conns);
        let mqtt_stream_slab = mio::util::Slab::new_starting_at(mio::Token(1), max_conns);

        MioHandler {
            listener: listener,
            connections: connections_slab,
            mqtt_streams: mqtt_stream_slab,
            server: server::Server::new(use_cache),
        }
    }
}

impl mio::Handler for MioHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self,
             event_loop: &mut mio::EventLoop<MioHandler>,
             token: mio::Token,
             events: mio::EventSet) {
        match token {
            MQTT_SERVER_TOKEN => {
                assert!(events.is_readable());

                match self.listener.accept() {
                    Ok(Some(socket)) => {
                        //the reason why I'm doing the horrible thing of two slabs and two
                        //insertions per connection is to avoid borrowing problems.
                        //That way the mqtt stream and the connection have distinct lifetimes
                        //(though not really) and be passed as mutable borrow simultaneously
                        //to connection_ready

                        let token = self.connections
                            .insert_with(|_| Rc::new(RefCell::new(Connection::new(socket))))
                            .expect("Could not insert new connection in slab");
                        self.mqtt_streams.
                            insert_with(|_| server::Stream::new())
                            .expect("Could not insert new stream into slab");
                        let connection = &self.connections[token].clone();
                        event_loop.register_opt(
                            &connection.borrow().socket,
                            token,
                            mio::EventSet::readable(),
                            mio::PollOpt::edge()).expect("Could not register connection with event loop");
                    }
                    Ok(None) => {
                        println!("The server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept errored: {}", e);
                        event_loop.shutdown();
                    }
                }
            }
            _ => {
                assert!(events.is_readable());
                let still_connected = connection_ready(&mut self.server,
                                                       &mut self.mqtt_streams[token],
                                                       self.connections[token].clone());
                if !still_connected {
                    event_loop.deregister(&self.connections[token].borrow().socket)
                        .expect("Could not deregister connection with event loop");
                    self.server.unsubscribe_all(self.connections[token].clone());
                    self.connections[token].borrow_mut().socket.flush().expect("Could not flush socket");
                    self.connections.remove(token).expect("Could not remove connection from slab");
                }
            }
        }
    }
}

fn connection_ready(server: &mut server::Server<Connection>,
                    stream: &mut server::Stream,
                    connection: Rc<RefCell<Connection>>) -> bool {
    let connection = connection.clone();
    let read_result = connection.borrow_mut().read(stream.buffer());

    match read_result {
        Ok(length) => {
            if length >= stream.total_buffer_len() {
                panic!(format!("Too many bytes ({}) for puny stream buffer ({})",
                               length, stream.total_buffer_len()));
            }
            stream.handle_messages(length, server, connection.clone())
        }
        _ => {
            println!("Error reading bytes from stream");
            false
        }
    }
}

impl Connection {
    fn new(socket: mio::tcp::TcpStream) -> Self {
        Connection { socket: socket }
    }

    fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
        self.socket.read(buffer)
    }
}

impl broker::Subscriber for Connection {
    fn new_message(&mut self, bytes: &[u8]) {
        self.socket.write_all(bytes).expect("Error writing to socket");
    }
}
<commit_msg>Using the cache no longer default<commit_after>extern crate mio;

use std::io::Write;
use std::io::Read;
use std::rc::{Rc};
use std::cell::{RefCell};
use mio::tcp::*;
mod server;
mod broker;
mod message;

const MQTT_SERVER_TOKEN: mio::Token = mio::Token(0);

fn main() {
    let address = "0.0.0.0:1883".parse().unwrap();
    let listener = TcpListener::bind(&address).expect(&format!("Could not bind to {}", address));
    let mut event_loop = mio::EventLoop::new().expect("Could not create MIO event loop");
    event_loop.register(&listener, MQTT_SERVER_TOKEN).expect("Could not register listener");
    event_loop.run(&mut MioHandler::new(listener, std::env::args().len() > 1)).expect("Could not run event loop");
}

struct MioHandler {
    listener: TcpListener,
    connections: mio::util::Slab<Rc<RefCell<Connection>>>,
    mqtt_streams: mio::util::Slab<server::Stream>,
    server: server::Server<Connection>,
}

struct Connection {
    socket: mio::tcp::TcpStream,
}

impl MioHandler {
    fn new(listener: TcpListener, use_cache: bool) -> Self {

        if use_cache {
            println!("Enabling the cache");
        }

        let max_conns = 1024 * 32;
        let connections_slab = mio::util::Slab::new_starting_at(mio::Token(1), max_conns);
        let mqtt_stream_slab = mio::util::Slab::new_starting_at(mio::Token(1), max_conns);

        MioHandler {
            listener: listener,
            connections: connections_slab,
            mqtt_streams: mqtt_stream_slab,
            server: server::Server::new(use_cache),
        }
    }
}

impl mio::Handler for MioHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self,
             event_loop: &mut mio::EventLoop<MioHandler>,
             token: mio::Token,
             events: mio::EventSet) {
        match token {
            MQTT_SERVER_TOKEN => {
                assert!(events.is_readable());

                match self.listener.accept() {
                    Ok(Some(socket)) => {
                        //the reason why I'm doing the horrible thing of two slabs and two
                        //insertions per connection is to avoid borrowing problems.
                        //That way the mqtt stream and the connection have distinct lifetimes
                        //(though not really) and be passed as mutable borrow simultaneously
                        //to connection_ready

                        let token = self.connections
                            .insert_with(|_| Rc::new(RefCell::new(Connection::new(socket))))
                            .expect("Could not insert new connection in slab");
                        self.mqtt_streams.
                            insert_with(|_| server::Stream::new())
                            .expect("Could not insert new stream into slab");
                        let connection = &self.connections[token].clone();
                        event_loop.register_opt(
                            &connection.borrow().socket,
                            token,
                            mio::EventSet::readable(),
                            mio::PollOpt::edge()).expect("Could not register connection with event loop");
                    }
                    Ok(None) => {
                        println!("The server socket wasn't actually ready");
                    }
                    Err(e) => {
                        println!("listener.accept errored: {}", e);
                        event_loop.shutdown();
                    }
                }
            }
            _ => {
                assert!(events.is_readable());
                let still_connected = connection_ready(&mut self.server,
                                                       &mut self.mqtt_streams[token],
                                                       self.connections[token].clone());
                if !still_connected {
                    event_loop.deregister(&self.connections[token].borrow().socket)
                        .expect("Could not deregister connection with event loop");
                    self.server.unsubscribe_all(self.connections[token].clone());
                    self.connections[token].borrow_mut().socket.flush().expect("Could not flush socket");
                    self.connections.remove(token).expect("Could not remove connection from slab");
                }
            }
        }
    }
}

fn connection_ready(server: &mut server::Server<Connection>,
                    stream: &mut server::Stream,
                    connection: Rc<RefCell<Connection>>) -> bool {
    let connection = connection.clone();
    let read_result = connection.borrow_mut().read(stream.buffer());

    match read_result {
        Ok(length) => {
            if length >= stream.total_buffer_len() {
                panic!(format!("Too many bytes ({}) for puny stream buffer ({})",
                               length, stream.total_buffer_len()));
            }
            stream.handle_messages(length, server, connection.clone())
        }
        _ => {
            println!("Error reading bytes from stream");
            false
        }
    }
}

impl Connection {
    fn new(socket: mio::tcp::TcpStream) -> Self {
        Connection { socket: socket }
    }

    fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
        self.socket.read(buffer)
    }
}

impl broker::Subscriber for Connection {
    fn new_message(&mut self, bytes: &[u8]) {
        self.socket.write_all(bytes).expect("Error writing to socket");
    }
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Err(code) = process(std::env::args().skip(2)) {
        std::process::exit(code);
    }
}

fn process<I>(mut old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["check".to_owned()];

    let mut found_dashes = false;
    for arg in old_args.by_ref() {
        found_dashes |= arg == "--";
        if found_dashes {
            break;
        }
        args.push(arg);
    }

    let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect();

    let mut path = std::env::current_exe()
        .expect("current executable path invalid")
        .with_file_name("clippy-driver");
    if cfg!(windows) {
        path.set_extension("exe");
    }

    let mut extra_envs = vec![];
    if std::env::var("CLIPPY_DOGFOOD").is_ok() {
        let target_dir = std::env::var("CARGO_MANIFEST_DIR")
            .map(|m| {
                std::path::PathBuf::from(m)
                    .join("target")
                    .join("dogfood")
                    .to_string_lossy()
                    .into_owned()
            })
            .unwrap_or_else(|_| "clippy_dogfood".to_string());

        extra_envs.push(("CARGO_TARGET_DIR", target_dir));
    };

    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC_WRAPPER", path)
        .env("CLIPPY_ARGS", clippy_args)
        .envs(extra_envs)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>Support non-unicode paths for dogfood test<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Err(code) = process(std::env::args().skip(2)) {
        std::process::exit(code);
    }
}

fn process<I>(mut old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["check".to_owned()];

    let mut found_dashes = false;
    for arg in old_args.by_ref() {
        found_dashes |= arg == "--";
        if found_dashes {
            break;
        }
        args.push(arg);
    }

    let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect();

    let mut path = std::env::current_exe()
        .expect("current executable path invalid")
        .with_file_name("clippy-driver");
    if cfg!(windows) {
        path.set_extension("exe");
    }

    let target_dir = std::env::var_os("CLIPPY_DOGFOOD")
        .map(|_| {
            std::env::var_os("CARGO_MANIFEST_DIR").map_or_else(
                || {
                    let mut fallback = std::ffi::OsString::new();
                    fallback.push("clippy_dogfood");
                    fallback
                },
                |d| {
                    std::path::PathBuf::from(d)
                        .join("target")
                        .join("dogfood")
                        .into_os_string()
                },
            )
        })
        .map(|p| ("CARGO_TARGET_DIR", p));

    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC_WRAPPER", path)
        .env("CLIPPY_ARGS", clippy_args)
        .envs(target_dir)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>#[ macro_use ]
extern crate clap;

extern crate btrfs;
extern crate sha2;
extern crate termion;

#[ doc (hidden) ]
#[ macro_use ]
mod misc;

mod examine;
mod output;
mod scan;
mod types;

use std::path::PathBuf;
use std::process;

use types::*;
use output::Output;

fn main () {

	let arguments =
		parse_arguments ();

	let mut output =
		Output::new ();

	match main_real (
		& arguments,
		& mut output,
	) {

		Ok (_) => (),

		Err (error_message) => {

			output.clear_status ();

			output.message (
				& format! (
					"Error: {}",
					error_message));

			process::exit (1);

		},

	}

}

fn parse_arguments (
) -> Arguments {

	let argument_matches = (
		clap::App::new ("Btrfs Dedupe")

		.arg (
			clap::Arg::with_name ("match-filename")
				.long ("match-filename")
				.help ("Match filename as well as checksum")
		)

		.arg (
			clap::Arg::with_name ("root-path")
				.multiple (true)
				.value_name ("PATH")
				.help ("Root path to scan for files")
		)

	).get_matches ();

	let match_filename =
		argument_matches.is_present (
			"match-filename",
		);

	let root_paths = (
		argument_matches.values_of_os (
			"root-path",
		)
	).map (
		|os_values|

		os_values.map (
			|os_value|

			PathBuf::from (os_value)

		).collect ()

	).unwrap_or (
		Vec::new (),
	);

	Arguments {
		match_filename: match_filename,
		root_paths: root_paths,
	}

}

fn main_real (
	arguments: & Arguments,
	output: & mut Output,
) -> Result <(), String> {

	// create a list of all files with the same name and size

	let file_metadata_lists: FileMetadataLists = try! (
		scan::scan_directories (
			& arguments,
			output)
	);

	// discard any with only a single coincidence

	let file_metadata_lists: FileMetadataLists =
		file_metadata_lists.into_iter ().filter (
			|& (_, ref value)|

		value.len () > 1

	).collect ();

	output.message (
		& format! (
			"Found {} {} that coincide",
			file_metadata_lists.len (),
			if arguments.match_filename {
				"filenames and sizes"
			} else {
				"sizes"
			}));

	// perform a checksum on each one

	let (hash_lists, checksum_error_count) =
		examine::split_by_hash (
			output,
			file_metadata_lists);

	output.message (
		& format! (
			"Found {} {} that coincide",
			hash_lists.len (),
			if arguments.match_filename {
				"filenames and hashes"
			} else {
				"checksums"
			}));

	if checksum_error_count > 0 {

		output.message (
			& format! (
				"Encountered {} errors while calculating checksums",
				checksum_error_count));

	}

	if hash_lists.is_empty () {
		return Ok (());
	}

	// deduplicate the matches

	let mut progress: usize = 0;
	let target = hash_lists.len ();

	let mut error_count: u64 = 0;

	output.status (
		"Deduplication progress: 0%");

	for (_, paths)
	in hash_lists.into_iter () {

		let (first_path_slice, other_paths) =
			paths.split_at (1);

		let first_path =
			first_path_slice.into_iter ().next ().unwrap ();

		for paths_chunk in other_paths.chunks (512) {

			match btrfs::deduplicate_files_with_source (
				first_path,
				paths_chunk,
			) {

				Ok (_) => (),
				Err (_) => error_count += 1,

			}

		}

		progress += 1;

		if progress % 256 == 0 {

			output.status (
				& format! (
					"Deduplication progress: {}%",
					progress * 100 / target));

		}

	};

	output.clear_status ();

	if error_count > 0 {

		output.message (
			& format! (
				"Encountered {} errors during deduplication",
				error_count));

	} else {

		output.message (
			& format! (
				"Deduplicated all files successfully"));

	}

	// return

	Ok (())

}

// ex: noet ts=4 filetype=rust
<commit_msg>add extra information to --help<commit_after>#[ macro_use ]
extern crate clap;

extern crate btrfs;
extern crate sha2;
extern crate termion;

#[ doc (hidden) ]
#[ macro_use ]
mod misc;

mod examine;
mod output;
mod scan;
mod types;

use std::path::PathBuf;
use std::process;

use types::*;
use output::Output;

fn main () {

	let arguments =
		parse_arguments ();

	let mut output =
		Output::new ();

	match main_real (
		& arguments,
		& mut output,
	) {

		Ok (_) => (),

		Err (error_message) => {

			output.clear_status ();

			output.message (
				& format! (
					"Error: {}",
					error_message));

			process::exit (1);

		},

	}

}

fn parse_arguments (
) -> Arguments {

	let argument_matches = (
		clap::App::new ("Btrfs Dedupe")

		.about (
			"Deduplicates identical files on BTRFS file systems.\n\nPlease \
			visit https://gitlab.wellbehavedsoftware.com/well-behaved-software\
			/wbs-backup/tree/master/btrfs-dedupe for more information.")

		.author (
			"James Pharaoh <james@wellbehavedsoftware.com")

		.arg (
			clap::Arg::with_name ("match-filename")
				.long ("match-filename")
				.help ("Match filename as well as checksum")
		)

		.arg (
			clap::Arg::with_name ("root-path")
				.multiple (true)
				.value_name ("PATH")
				.help ("Root path to scan for files")
		)

	).get_matches ();

	let match_filename =
		argument_matches.is_present (
			"match-filename",
		);

	let root_paths = (
		argument_matches.values_of_os (
			"root-path",
		)
	).map (
		|os_values|

		os_values.map (
			|os_value|

			PathBuf::from (os_value)

		).collect ()

	).unwrap_or (
		Vec::new (),
	);

	Arguments {
		match_filename: match_filename,
		root_paths: root_paths,
	}

}

fn main_real (
	arguments: & Arguments,
	output: & mut Output,
) -> Result <(), String> {

	// create a list of all files with the same name and size

	let file_metadata_lists: FileMetadataLists = try! (
		scan::scan_directories (
			& arguments,
			output)
	);

	// discard any with only a single coincidence

	let file_metadata_lists: FileMetadataLists =
		file_metadata_lists.into_iter ().filter (
			|& (_, ref value)|

		value.len () > 1

	).collect ();

	output.message (
		& format! (
			"Found {} {} that coincide",
			file_metadata_lists.len (),
			if arguments.match_filename {
				"filenames and sizes"
			} else {
				"sizes"
			}));

	// perform a checksum on each one

	let (hash_lists, checksum_error_count) =
		examine::split_by_hash (
			output,
			file_metadata_lists);

	output.message (
		& format! (
			"Found {} {} that coincide",
			hash_lists.len (),
			if arguments.match_filename {
				"filenames and hashes"
			} else {
				"checksums"
			}));

	if checksum_error_count > 0 {

		output.message (
			& format! (
				"Encountered {} errors while calculating checksums",
				checksum_error_count));

	}

	if hash_lists.is_empty () {
		return Ok (());
	}

	// deduplicate the matches

	let mut progress: usize = 0;
	let target = hash_lists.len ();

	let mut error_count: u64 = 0;

	output.status (
		"Deduplication progress: 0%");

	for (_, paths)
	in hash_lists.into_iter () {

		let (first_path_slice, other_paths) =
			paths.split_at (1);

		let first_path =
			first_path_slice.into_iter ().next ().unwrap ();

		for paths_chunk in other_paths.chunks (512) {

			match btrfs::deduplicate_files_with_source (
				first_path,
				paths_chunk,
			) {

				Ok (_) => (),
				Err (_) => error_count += 1,

			}

		}

		progress += 1;

		if progress % 256 == 0 {

			output.status (
				& format! (
					"Deduplication progress: {}%",
					progress * 100 / target));

		}

	};

	output.clear_status ();

	if error_count > 0 {

		output.message (
			& format! (
				"Encountered {} errors during deduplication",
				error_count));

	} else {

		output.message (
			& format! (
				"Deduplicated all files successfully"));

	}

	// return

	Ok (())

}

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>//! Muxed. A tmux project manager with no runtime dependencies.
extern crate clap;
extern crate libc;
extern crate yaml_rust;
#[cfg(test)] extern crate rand;

mod tmux;
mod command;
mod project;

use project::parser;
use project::processor;
use clap::{Arg, App, SubCommand, AppSettings};
use command::Command;
use std::process;

#[macro_export]
macro_rules! try_or_err (
    ($expr: expr) => ({
        match $expr {
            Ok(val) => val,
            Err(e) => {
              println!("Muxed ran in to a problem:");
              println!("{}", e);
              return
            }
        }
    })
);

/// The main execution method.
/// Currently accepts a single option. The option represents a configuration
/// file in the same naming format. Given a project file name `projectName.yml`
/// in the `~/.muxed/` directory.
///
/// # Examples
///
/// ~/.muxed/projectName.yml
///
/// ```
/// root: ~/projects/muxed/
/// windows:
///     - cargo: "cargo build"
///     - vim: "vim ."
///     - git: ""
/// ```
///
/// You can run the command:
///
/// ```
/// $ ./muxed projectName
/// ```
pub fn main() {
    let matches = App::new("Muxed")
                          .version(env!("CARGO_PKG_VERSION"))
                          .author("Brian Pearce")
                          .about("Another TMUX project manager")
                          .setting(AppSettings::SubcommandsNegateReqs)
                          .arg(Arg::with_name("PROJECT_NAME")
                               .help("The name of your poject to open")
                               .index(1)
                               .required(true)
                               .takes_value(true))
                          .arg(Arg::with_name("daemonize")
                               .short("d")
                               .multiple(false)
                               .help("If you want to create a muxed session without connecting to it"))
                          .arg(Arg::with_name("PROJECT_DIR")
                               .short("-p")
                               .multiple(false)
                               .value_name("PROJECT_DIR")
                               .takes_value(true)
                               .help("The directory your project config files live in. Defaults to ~/.muxed/"))
                          .subcommand(SubCommand::with_name("new")
                                      .about("Create a new project file")
                                      .arg(Arg::with_name("NEW_PROJECT_NAME")
                                          .help("The new project/file name")
                                          .required(true))
                                      .arg(Arg::with_name("PROJECT_DIR")
                                          .short("-p")
                                          .multiple(false)
                                          .takes_value(true)
                                          .help("The directory your project config files live in. Defaults to ~/.muxed/")))
                          .get_matches();

    if let Some(matches) = matches.subcommand_matches("new") {
        if matches.is_present("NEW_PROJECT_NAME") {
            let project_name = matches.value_of("NEW_PROJECT_NAME").unwrap().to_string();

            let mut output = process::Command::new("muxednew").arg(project_name);

            if matches.is_present("PROJECT_DIR") {
                output.arg("-p")
                      .arg(matches.value_of("PROJECT_DIR").unwrap());
            }

            output = try_or_err!(output.output().map_err(|_| "Muxednew might not be installed." ));

            if !output.status.success() {
                println!("{}", String::from_utf8_lossy(&output.stdout));
            };
        };

        return
    };

    let project_name = matches.value_of("PROJECT_NAME").unwrap().to_string();
    let daemonize = matches.is_present("daemonize");
    let muxed_dir = matches.value_of("PROJECT_DIR");

    let commands: Vec<Command>;
    // This refactoring could make a good conference talk example
    match project::session_exists(&project_name) {
        Some(c) => {
            commands = vec!(c);
        },
        None => {
            let yaml = try_or_err!(project::read(&project_name, &muxed_dir));
            commands = try_or_err!(parser::main(&yaml, &project_name, daemonize));
        }
    };

    processor::main(&commands)
}
<commit_msg>issue-5 Working passthrough<commit_after>//! Muxed. A tmux project manager with no runtime dependencies.
extern crate clap;
extern crate libc;
extern crate yaml_rust;
#[cfg(test)] extern crate rand;

mod tmux;
mod command;
mod project;

use project::parser;
use project::processor;
use clap::{Arg, App, AppSettings};
use command::Command;
use std::process;

#[macro_export]
macro_rules! try_or_err (
    ($expr: expr) => ({
        match $expr {
            Ok(val) => val,
            Err(e) => {
              println!("Muxed ran in to a problem:");
              println!("{}", e);
              return
            }
        }
    })
);

/// The main execution method.
/// Currently accepts a single option. The option represents a configuration
/// file in the same naming format. Given a project file name `projectName.yml`
/// in the `~/.muxed/` directory.
///
/// # Examples
///
/// ~/.muxed/projectName.yml
///
/// ```
/// root: ~/projects/muxed/
/// windows:
///     - cargo: "cargo build"
///     - vim: "vim ."
///     - git: ""
/// ```
///
/// You can run the command:
///
/// ```
/// $ ./muxed projectName
/// ```
pub fn main() {
    let matches = App::new("Muxed")
                      .version(env!("CARGO_PKG_VERSION"))
                      .author("Brian Pearce")
                      .about("Another TMUX project manager")
                      .setting(AppSettings::TrailingVarArg)
                      .arg(Arg::with_name("PROJECT_NAME")
                           .help("The name of your poject to open")
                           .index(1)
                           .required(true)
                           .takes_value(true))
                      .arg(Arg::with_name("daemonize")
                           .short("d")
                           .multiple(false)
                           .help("If you want to create a muxed session without connecting to it"))
                      .arg(Arg::with_name("PROJECT_DIR")
                           .short("-p")
                           .multiple(false)
                           .value_name("PROJECT_DIR")
                           .takes_value(true)
                           .help("The directory your project config files live in. Defaults to ~/.muxed/"))
                      .arg(Arg::with_name("REST")
                          .multiple(true)
                          .hidden(true))
                      .get_matches();

    let project_name = matches.value_of("PROJECT_NAME").unwrap();
    let daemonize = matches.is_present("daemonize");
    let muxed_dir = matches.value_of("PROJECT_DIR");
    let trail: Vec<&str> = matches.values_of("REST").unwrap().collect();

    match project_name {
        "new" => {
            let mut cd = process::Command::new("muxednew");
            let cmd = trail.iter().fold(&mut cd, |c, i| c.arg(i));
            let result = cmd.output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            println!("{}", String::from_utf8_lossy(&result.stdout));
            println!("{}", String::from_utf8_lossy(&result.stderr));
            return;
        }
        // Continue on
        _     => {}
    }

    let project_name = project_name.to_string();

    let commands: Vec<Command>;
    // This refactoring could make a good conference talk example
    match project::session_exists(&project_name) {
        Some(c) => {
            commands = vec!(c);
        },
        None => {
            let yaml = try_or_err!(project::read(&project_name, &muxed_dir));
            commands = try_or_err!(parser::main(&yaml, &project_name, daemonize));
        }
    };

    processor::main(&commands)
}
<|endoftext|>


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

#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate regex;
extern crate libc;

#[macro_use]
extern crate serde_derive;
extern crate docopt;

mod tty;

use std::io::BufReader;
use regex::Regex;
use std::process::{Command, Stdio};
use std::io::BufRead;
use docopt::Docopt;

const CARGO: &'static str = "cargo";
const CRATE_LEN: usize = 26; // 99% of crates have names <= 26 chars at time of writing
const VERSION_LEN: usize = 6; // Typical form of 'vX.Y.Z'

const USAGE: &'static str =  "
Adds crate URLS to Cargo output

Usage:
    cargo-urlcrate [options]
    cargo-urlcrate [options] [--] <args>...

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --tty=MODE          Allowed modes: auto/never. Determines whether 'cargo' is attached to a tty. Ignored on platforms other than linux.

When Cargo's color mode is set to 'auto' ('--color auto'), it determines if its stderr is attached to a tty or a pipe.
cargo-urlcrate supports connecting a psuedo-terminal (pty) to cargo, which will cause Cargo to detect a terminal.

This option only has an effect on Linux - other platforms can pass '--color always' to Cargo to force it to output colors anyway.
";

#[derive(Debug, Deserialize)]
struct Args {
    flag_help: bool,
    flag_version: bool,
    flag_tty: Option<Mode>,
    arg_args: Vec<String>
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
enum Mode {
    Auto,
    Never
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("cargo-urlcrate v0.1.0");
        return
    }

    run(args.arg_args, match args.flag_tty.unwrap_or(Mode::Auto) {
        Mode::Never => false,
        Mode::Auto => true,
    });
}

fn run(args: Vec<String>, tty: bool) {
    // https://www.npmjs.com/package/ansi-regex
    let regex = Regex::new("[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]").unwrap();

    let mut command = Command::new(CARGO);
    command.args(args)
        .stdout(Stdio::inherit());

    let mut reader: BufReader<tty::Handle> = BufReader::with_capacity(10, tty::get_handle(command, tty));
    let newline: &[_] = &['\n', '\r'];
    loop {
        let mut line = String::new();
        let line = match reader.read_line(&mut line) {
            Ok(num) => {
                if num == 0 {
                    break
                }
                line.trim_right_matches(newline)
            },
            Err(e) => {
                if tty::handle_err(reader.get_mut(), &e) { break } else { continue };
            }
        };
        let tmp = regex.replace_all(line, "");

        let clean = tmp.trim_left();
        let split: Vec<_> = clean.split(' ').collect();

        match split[0].as_ref() {
            "Compiling" | "Downloading" => {
                let padding = (CRATE_LEN + VERSION_LEN).saturating_sub(split[1].len() + 1 + split[2].len());
                println!("{}{}https://crates.io/crates/{}", line, " ".repeat(padding), split[1]);
            }
            _ => println!("{}", line)
        }
    }
}

<commit_msg>Remove temporary variable<commit_after>#![feature(plugin)]
#![plugin(docopt_macros)]

#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate regex;
extern crate libc;

#[macro_use]
extern crate serde_derive;
extern crate docopt;

mod tty;

use std::io::BufReader;
use regex::Regex;
use std::process::{Command, Stdio};
use std::io::BufRead;
use docopt::Docopt;

const CARGO: &'static str = "cargo";
const CRATE_LEN: usize = 26; // 99% of crates have names <= 26 chars at time of writing
const VERSION_LEN: usize = 6; // Typical form of 'vX.Y.Z'

const USAGE: &'static str =  "
Adds crate URLS to Cargo output

Usage:
    cargo-urlcrate [options]
    cargo-urlcrate [options] [--] <args>...

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --tty=MODE          Allowed modes: auto/never. Determines whether 'cargo' is attached to a tty. Ignored on platforms other than linux.

When Cargo's color mode is set to 'auto' ('--color auto'), it determines if its stderr is attached to a tty or a pipe.
cargo-urlcrate supports connecting a psuedo-terminal (pty) to cargo, which will cause Cargo to detect a terminal.

This option only has an effect on Linux - other platforms can pass '--color always' to Cargo to force it to output colors anyway.
";

#[derive(Debug, Deserialize)]
struct Args {
    flag_help: bool,
    flag_version: bool,
    flag_tty: Option<Mode>,
    arg_args: Vec<String>
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
enum Mode {
    Auto,
    Never
}

fn main() {

    let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("cargo-urlcrate v0.1.0");
        return
    }

    run(args.arg_args, match args.flag_tty.unwrap_or(Mode::Auto) {
        Mode::Never => false,
        Mode::Auto => true,
    });
}

fn run(args: Vec<String>, tty: bool) {
    // https://www.npmjs.com/package/ansi-regex
    let regex = Regex::new("[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]").unwrap();

    let mut command = Command::new(CARGO);
    command.args(args)
        .stdout(Stdio::inherit());

    let mut reader: BufReader<tty::Handle> = BufReader::with_capacity(10, tty::get_handle(command, tty));
    let newline: &[_] = &['\n', '\r'];
    loop {
        let mut line = String::new();
        let line = match reader.read_line(&mut line) {
            Ok(num) => {
                if num == 0 {
                    break
                }
                line.trim_right_matches(newline)
            },
            Err(e) => {
                if tty::handle_err(reader.get_mut(), &e) { break } else { continue };
            }
        };
        let clean = regex.replace_all(line, "");
        let split: Vec<_> = clean.trim_left().split(' ').collect();

        match split[0].as_ref() {
            "Compiling" | "Downloading" => {
                let padding = (CRATE_LEN + VERSION_LEN).saturating_sub(split[1].len() + 1 + split[2].len());
                println!("{}{}https://crates.io/crates/{}", line, " ".repeat(padding), split[1]);
            }
            _ => println!("{}", line)
        }
    }
}

<|endoftext|>