<commit_before>extern crate mqtt3;
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_timer;
extern crate bytes;
extern crate toml;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate slog;
extern crate slog_term;
#[macro_use]
extern crate quick_error;

pub mod error;
pub mod codec;
pub mod broker;
pub mod client;
pub mod subscription;
pub mod conf;

use std::fs::File;
use std::io::{self, Read};
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::error::Error as StdError;

use mqtt3::*;
use tokio_core::reactor::{Core, Interval};
use tokio_core::net::TcpListener;
use tokio_io::AsyncRead;

use futures::stream::Stream;
use futures::Future;

use slog::{Logger, Drain};

use broker::Broker;
use codec::MqttCodec;
use error::Error;

lazy_static! {
    pub static ref CONF: conf::Rumqttd = {
        let mut conf = String::new();
        let _ = File::open("conf/rumqttd.conf").unwrap().read_to_string(&mut conf);
        toml::from_str::<conf::Rumqttd>(&conf).unwrap()
    };
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), CONF.connection.port);
    let logger = rumqttd_logger();

    info!(logger, "🌩   starting broker");

    let listener = TcpListener::bind(&address, &core.handle()).unwrap();

    let broker = Broker::new();
    let broker_inner = broker.clone();
    let handle_inner = handle.clone();
    info!(logger, "👂🏼   listening for connections");

    let connections = listener.incoming().for_each(|(socket, addr)| {
        let framed = socket.framed(MqttCodec::new());
        info!(logger, "🌟   new connection from {}", addr);
        let broker_inner = broker_inner.clone();
        let error_logger = broker_inner.logger.clone();
        let handshake = framed.into_future()
                                  .map_err(move |(err, _)| {
                                      error!(error_logger, "pre handshake error = {:?}", err);
                                      err
                                  }) // for accept errors, get error and discard the stream
                                  .and_then(move |(packet,framed)| { // only accepted connections from here

                let broker = broker_inner.clone();

                if let Some(Packet::Connect(c)) = packet {
                    match broker.handle_connect(c, addr) {
                        Ok((client, rx)) => Ok((framed, client, rx)),
                        Err(e) => Err(io::Error::new(io::ErrorKind::Other, e.description())),
                    }
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "Invalid Handshake Packet"))
                }
        });

        // TODO: implement timeout to drop connection if there is no handshake packet after connection
        // let timeout = Timeout::new(Duration::new(3, 0), &handle_inner).unwrap();
        // let timeout = timeout.then(|_| Err(io::Error::new(io::ErrorKind::Other, "Invalid Handshake Packet")));
        // let handshake = handshake.select(timeout);

        let broker_inner = broker.clone();
        let handle_inner = handle_inner.clone();
        let logger = logger.clone();
        let mqtt = handshake.map(|w| Some(w))
                            .or_else(move |e| {
                                         error!(logger, "{:?}", e);
                                         Ok::<_, ()>(None)
                                     })
                            .map(move |handshake| {
            let broker_handshake = broker_inner.clone();

            // handle each connections n/w send and recv here
            if let Some((framed, client, rx)) = handshake {
                let id: String = client.id.clone();
                let keep_alive = client.keep_alive;
                let client_timer = client.clone();

                let (sender, receiver) = framed.split();

                let connack = Packet::Connack(Connack {
                                                  session_present: false,
                                                  code: ConnectReturnCode::Accepted,
                                              });

                let _ = client.send(connack);
                let broker_inner = broker_handshake.clone();
                let handle_inner = handle_inner.clone();

                let error_logger = broker_handshake.logger.clone();
                // current connections incoming n/w packets
                let rx_future = receiver.or_else(|e| Err::<_, error::Error>(e.into()))
                                        .for_each(move |msg| {
                    let broker = broker_inner.clone();
                    client.reset_last_control_at();
                    match msg {
                        Packet::Publish(p) => broker.handle_publish(p, &client),
                        Packet::Subscribe(s) => broker.handle_subscribe(s, &client),
                        Packet::Puback(pkid) => broker.handle_puback(pkid, &client),
                        Packet::Pubrec(pkid) => broker.handle_pubrec(pkid, &client),
                        Packet::Pubrel(pkid) => broker.handle_pubrel(pkid, &client),
                        Packet::Pubcomp(pkid) => broker.handle_pubcomp(pkid, &client),
                        Packet::Pingreq => broker.handle_pingreq(&client),
                        _ => Err(error::Error::InvalidMqttPacket),
                    }
                }).map_err(move |e| {
                    error!(error_logger, "network incoming handle error = {:?}", e);
                    Ok::<_, ()>(())
                })
                .then(move |_| Ok::<_, ()>(()));

                let interval = Interval::new(keep_alive.unwrap(), &handle_inner).unwrap();
                let error_logger = broker_handshake.logger.clone();
                let timer_future = interval.for_each(move |_| {
                                if client_timer.has_exceeded_keep_alive() {
                                    Err(io::Error::new(ErrorKind::Other, "Ping Timer Error"))
                                } else {
                                    Ok(())
                                }
                            })
                            .map_err(move |e| {
                                      error!(error_logger, "ping timer error = {:?}", e);
                                      Ok::<_, ()>(())
                            })
                            .then(|_| Ok(()));

                let rx_future = timer_future.select(rx_future);

                let error_logger = broker_handshake.logger.clone();
                let error_logger1 = broker_handshake.logger.clone();
                // current connections outgoing n/w packets
                let tx_future = rx.map_err(|_| Error::Other)
                                  .and_then(move |r| match r {
                                           Packet::Publish(p) => Ok(Packet::Publish(p)),
                                           Packet::Connack(c) => Ok(Packet::Connack(c)),
                                           Packet::Suback(sa) => Ok(Packet::Suback(sa)),
                                           Packet::Puback(pa) => Ok(Packet::Puback(pa)),
                                           Packet::Pubrec(prec) => Ok(Packet::Pubrec(prec)),
                                           Packet::Pubrel(prel) => Ok(Packet::Pubrel(prel)),
                                           Packet::Pubcomp(pc) => Ok(Packet::Pubcomp(pc)),
                                           Packet::Pingresp => Ok(Packet::Pingresp),
                                           Packet::Disconnect => Err(Error::DisconnectRequest),
                                           _ => {
                                               error!(error_logger1, "improper packet {:?} received. disconnecting", r);
                                               Err(Error::InvalidMqttPacket)
                                           }
                                       })
                                  .forward(sender)
                                  .map_err(move |e| {
                                      error!(error_logger, "network transmission error = {:?}", e);
                                      Ok::<_, ()>(())
                                  })
                                  .then(move |_| {
                                      // broker_handshake.handle_disconnect(&id);
                                      Ok::<_, ()>(())
                                  });

                let rx_future = rx_future.then(|_| Ok(()));

                let broker_inner = broker_handshake.clone();
                let connection = rx_future.select(tx_future);
                let c = connection.then(move |_| {
                                            error!(broker_inner.logger, "disconnecting client: {:?}", id);
                                            let _ = broker_inner.remove_client(&id);
                                            Ok::<_, ()>(())
                                        });

                handle_inner.spawn(c);
            }
            Ok::<_, ()>(())
        }).then(|_| Ok(()));

        handle.spawn(mqtt);
        Ok(())
    });

    //TODO: why isn't this working for 'listener.incoming().for_each'
    core.run(connections).unwrap();
}

fn rumqttd_logger() -> Logger {
    use std::sync::Mutex;

    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = Mutex::new(drain).fuse();
    Logger::root(drain, o!("rumqttd" => env!("CARGO_PKG_VERSION")))
}
<commit_msg>distinguish tcp connection & mqtt connection logs<commit_after>extern crate mqtt3;
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_timer;
extern crate bytes;
extern crate toml;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate slog;
extern crate slog_term;
#[macro_use]
extern crate quick_error;

pub mod error;
pub mod codec;
pub mod broker;
pub mod client;
pub mod subscription;
pub mod conf;

use std::fs::File;
use std::io::{self, Read};
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::error::Error as StdError;

use mqtt3::*;
use tokio_core::reactor::{Core, Interval};
use tokio_core::net::TcpListener;
use tokio_io::AsyncRead;

use futures::stream::Stream;
use futures::Future;

use slog::{Logger, Drain};

use broker::Broker;
use codec::MqttCodec;
use error::Error;

lazy_static! {
    pub static ref CONF: conf::Rumqttd = {
        let mut conf = String::new();
        let _ = File::open("conf/rumqttd.conf").unwrap().read_to_string(&mut conf);
        toml::from_str::<conf::Rumqttd>(&conf).unwrap()
    };
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), CONF.connection.port);
    let logger = rumqttd_logger();

    info!(logger, "🌩   starting broker");

    let listener = TcpListener::bind(&address, &core.handle()).unwrap();

    let broker = Broker::new();
    let broker_inner = broker.clone();
    let handle_inner = handle.clone();
    info!(logger, "👂🏼   listening for connections");

    let connections = listener.incoming().for_each(|(socket, addr)| {
        let framed = socket.framed(MqttCodec::new());
        info!(logger, "☄   new tcp connection from {}", addr);
        let broker_inner = broker_inner.clone();
        let error_logger = broker_inner.logger.clone();
        let error_logger1 = broker_inner.logger.clone();

        let handshake = framed.into_future()
                                  .map_err(move |(err, _)| {
                                      error!(error_logger, "pre handshake error = {:?}", err);
                                      err
                                  }) // for accept errors, get error and discard the stream
                                  .and_then(move |(packet,framed)| { // only accepted connections from here

                let broker = broker_inner.clone();

                if let Some(Packet::Connect(c)) = packet {
                    match broker.handle_connect(c, addr) {
                        Ok((client, rx)) => {
                            info!(error_logger1, "✨   mqtt connection successful. id = {:?}", client.id);
                            Ok((framed, client, rx))
                        }
                        Err(e) => Err(io::Error::new(io::ErrorKind::Other, e.description())),
                    }
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "Invalid Handshake Packet"))
                }
        });

        // TODO: implement timeout to drop connection if there is no handshake packet after connection
        // let timeout = Timeout::new(Duration::new(3, 0), &handle_inner).unwrap();
        // let timeout = timeout.then(|_| Err(io::Error::new(io::ErrorKind::Other, "Invalid Handshake Packet")));
        // let handshake = handshake.select(timeout);

        let broker_inner = broker.clone();
        let handle_inner = handle_inner.clone();
        let logger = logger.clone();
        let mqtt = handshake.map(|w| Some(w))
                            .or_else(move |e| {
                                         error!(logger, "{:?}", e);
                                         Ok::<_, ()>(None)
                                     })
                            .map(move |handshake| {
            let broker_handshake = broker_inner.clone();

            // handle each connections n/w send and recv here
            if let Some((framed, client, rx)) = handshake {
                let id: String = client.id.clone();
                let keep_alive = client.keep_alive;
                let client_timer = client.clone();

                let (sender, receiver) = framed.split();

                let connack = Packet::Connack(Connack {
                                                  session_present: false,
                                                  code: ConnectReturnCode::Accepted,
                                              });

                let _ = client.send(connack);
                let broker_inner = broker_handshake.clone();
                let handle_inner = handle_inner.clone();

                let error_logger = broker_handshake.logger.clone();
                // current connections incoming n/w packets
                let rx_future = receiver.or_else(|e| Err::<_, error::Error>(e.into()))
                                        .for_each(move |msg| {
                    let broker = broker_inner.clone();
                    client.reset_last_control_at();
                    match msg {
                        Packet::Publish(p) => broker.handle_publish(p, &client),
                        Packet::Subscribe(s) => broker.handle_subscribe(s, &client),
                        Packet::Puback(pkid) => broker.handle_puback(pkid, &client),
                        Packet::Pubrec(pkid) => broker.handle_pubrec(pkid, &client),
                        Packet::Pubrel(pkid) => broker.handle_pubrel(pkid, &client),
                        Packet::Pubcomp(pkid) => broker.handle_pubcomp(pkid, &client),
                        Packet::Pingreq => broker.handle_pingreq(&client),
                        _ => Err(error::Error::InvalidMqttPacket),
                    }
                }).map_err(move |e| {
                    error!(error_logger, "network incoming handle error = {:?}", e);
                    Ok::<_, ()>(())
                })
                .then(move |_| Ok::<_, ()>(()));

                let interval = Interval::new(keep_alive.unwrap(), &handle_inner).unwrap();
                let error_logger = broker_handshake.logger.clone();
                let timer_future = interval.for_each(move |_| {
                                if client_timer.has_exceeded_keep_alive() {
                                    Err(io::Error::new(ErrorKind::Other, "Ping Timer Error"))
                                } else {
                                    Ok(())
                                }
                            })
                            .map_err(move |e| {
                                      error!(error_logger, "ping timer error = {:?}", e);
                                      Ok::<_, ()>(())
                            })
                            .then(|_| Ok(()));

                let rx_future = timer_future.select(rx_future);

                let error_logger = broker_handshake.logger.clone();
                let error_logger1 = broker_handshake.logger.clone();
                // current connections outgoing n/w packets
                let tx_future = rx.map_err(|_| Error::Other)
                                  .and_then(move |r| match r {
                                           Packet::Publish(p) => Ok(Packet::Publish(p)),
                                           Packet::Connack(c) => Ok(Packet::Connack(c)),
                                           Packet::Suback(sa) => Ok(Packet::Suback(sa)),
                                           Packet::Puback(pa) => Ok(Packet::Puback(pa)),
                                           Packet::Pubrec(prec) => Ok(Packet::Pubrec(prec)),
                                           Packet::Pubrel(prel) => Ok(Packet::Pubrel(prel)),
                                           Packet::Pubcomp(pc) => Ok(Packet::Pubcomp(pc)),
                                           Packet::Pingresp => Ok(Packet::Pingresp),
                                           Packet::Disconnect => Err(Error::DisconnectRequest),
                                           _ => {
                                               error!(error_logger1, "improper packet {:?} received. disconnecting", r);
                                               Err(Error::InvalidMqttPacket)
                                           }
                                       })
                                  .forward(sender)
                                  .map_err(move |e| {
                                      error!(error_logger, "network transmission error = {:?}", e);
                                      Ok::<_, ()>(())
                                  })
                                  .then(move |_| {
                                      // broker_handshake.handle_disconnect(&id);
                                      Ok::<_, ()>(())
                                  });

                let rx_future = rx_future.then(|_| Ok(()));

                let broker_inner = broker_handshake.clone();
                let connection = rx_future.select(tx_future);
                let c = connection.then(move |_| {
                                            error!(broker_inner.logger, "disconnecting client: {:?}", id);
                                            let _ = broker_inner.remove_client(&id);
                                            Ok::<_, ()>(())
                                        });

                handle_inner.spawn(c);
            }
            Ok::<_, ()>(())
        }).then(|_| Ok(()));

        handle.spawn(mqtt);
        Ok(())
    });

    //TODO: why isn't this working for 'listener.incoming().for_each'
    core.run(connections).unwrap();
}

fn rumqttd_logger() -> Logger {
    use std::sync::Mutex;

    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = Mutex::new(drain).fuse();
    Logger::root(drain, o!("rumqttd" => env!("CARGO_PKG_VERSION")))
}
<|endoftext|>


<commit_before>extern crate specs;
extern crate ggez;
extern crate env_logger;
extern crate rand;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_json;

use specs::{Component, DispatcherBuilder, ReadStorage, System, VecStorage, World, WriteStorage,
            Fetch, Join};

use components::common::*;
use components::living::*;

use systems::{Movement, Printer, ZombieSpawner};
use systems::broadcast::TcpBroadcast;

use std::time::{Duration, Instant};
use std::thread::sleep;

static TICKS_PER_SECOND: u64 = 60;

struct DeltaTime(f32);

mod components;
mod systems;
mod resources;
mod entities;
mod util;

fn main() {
    env_logger::init().expect("env_logger initialization failed!");

    info!("logging initialized, starting up...");

    let mut world = World::new();
    world.register::<Name>();
    world.register::<Position>();
    world.register::<Velocity>();
    world.register::<Health>();
    world.register::<Agility>();
    world.register::<Intelligence>();
    world.register::<Nourishment>();
    world.register::<Hunger>();
    world.register::<Thirst>();

    info!("world created, components registered!");

    let mut dispatcher = DispatcherBuilder::new()
        .add(Movement, "movement", &[])
        .add(Printer, "printer", &[])
        .add(ZombieSpawner, "zombie_spawner", &[])
        // .add(TcpBroadcast, "tcp_broadcast", &[])
        .build();

    let mut running = true;
    while running {
        let now = Instant::now();
        dispatcher.dispatch(&mut world.res);
        world.maintain();
        let max_tick_length = Duration::from_millis(1000 / TICKS_PER_SECOND);
        let remaining = max_tick_length - now.elapsed();
        if remaining > Duration::from_millis(0) {
            sleep(remaining);
        }
    }

    info!("simulation shutting down...");
}
<commit_msg>make duration subtraction safe<commit_after>extern crate specs;
extern crate ggez;
extern crate env_logger;
extern crate rand;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_json;

use specs::{Component, DispatcherBuilder, ReadStorage, System, VecStorage, World, WriteStorage,
            Fetch, Join};

use components::common::*;
use components::living::*;

use systems::{Movement, Printer, ZombieSpawner};
use systems::broadcast::TcpBroadcast;

use std::time::{Duration, Instant};
use std::thread::sleep;

static TICKS_PER_SECOND: u64 = 60;

struct DeltaTime(f32);

mod components;
mod systems;
mod resources;
mod entities;
mod util;

fn main() {
    env_logger::init().expect("env_logger initialization failed!");

    info!("logging initialized, starting up...");

    let mut world = World::new();
    world.register::<Name>();
    world.register::<Position>();
    world.register::<Velocity>();
    world.register::<Health>();
    world.register::<Agility>();
    world.register::<Intelligence>();
    world.register::<Nourishment>();
    world.register::<Hunger>();
    world.register::<Thirst>();

    info!("world created, components registered!");

    let mut dispatcher = DispatcherBuilder::new()
        .add(Movement, "movement", &[])
        .add(Printer, "printer", &[])
        .add(ZombieSpawner, "zombie_spawner", &[])
        // .add(TcpBroadcast, "tcp_broadcast", &[])
        .build();

    let mut running = true;
    while running {
        let now = Instant::now();

        dispatcher.dispatch(&mut world.res);
        world.maintain();

        let max_tick_length = Duration::from_millis(1000 / TICKS_PER_SECOND);

        let remaining = match max_tick_length.checked_sub(now.elapsed()) {
            Some(duration) => duration,
            None => continue,
        };

        if remaining > Duration::from_millis(0) {
            sleep(remaining);
        }
    }

    info!("simulation shutting down...");
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![allow(stable_features)] // lying about question_mark because 1.14.0 isn't released!

#![feature(proc_macro)]

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate alacritty;
extern crate cgmath;
extern crate copypasta;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate mio;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;
extern crate vte;

#[macro_use]
extern crate bitflags;

use std::sync::{mpsc, Arc};
use std::sync::atomic::Ordering;

use parking_lot::{MutexGuard};

use alacritty::Flag;
use alacritty::Rgb;
use alacritty::config::{self, Config};
use alacritty::event;
use alacritty::gl;
use alacritty::input;
use alacritty::meter::Meter;
use alacritty::renderer::{QuadRenderer, GlyphCache};
use alacritty::sync::FairMutex;
use alacritty::term::{self, Term};
use alacritty::tty::{self, Pty, process_should_exit};
use alacritty::event_loop::EventLoop;

/// Channel used by resize handling on mac
static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
    }
}

fn main() {
    // Load configuration
    let (config, config_path) = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => (Config::default(), None),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok((config, path)) => (config, Some(path)),
    };

    let mut ref_test = false;
    let mut columns = 80;
    let mut lines = 24;

    let mut args_iter = ::std::env::args();
    while let Some(arg) = args_iter.next() {
        match &arg[..] {
            // Generate ref test
            "--ref-test" => ref_test = true,
            // Set dimensions
            "-d" | "--dimensions" => {
                args_iter.next()
                    .map(|w| w.parse().map(|w| columns = w));
                args_iter.next()
                    .map(|h| h.parse().map(|h| lines = h));
            },
            // ignore unexpected
            _ => (),
        }
    }

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();

    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        // gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    // Create renderer
    let mut renderer = QuadRenderer::new(&config, width, height);

    // Initialize glyph cache
    let glyph_cache = {
        println!("Initializing glyph cache");
        let init_start = ::std::time::Instant::now();

        let cache = renderer.with_loader(|mut api| {
            GlyphCache::new(rasterizer, &config, &mut api)
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);

        cache
    };

    let metrics = glyph_cache.font_metrics();
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    // Resize window to be 80 col x 24 lines
    let width = cell_width * columns + 4;
    let height = cell_height * lines + 4;
    println!("set_inner_size: {} x {}", width, height);
    // Is this in points?
    let width_pts = (width as f32 / dpr) as u32;
    let height_pts = (height as f32 / dpr) as u32;
    println!("set_inner_size: {} x {}; pts: {} x {}", width, height, width_pts, height_pts);
    window.set_inner_size(width_pts, height_pts);
    renderer.resize(width as _, height as _);

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let size = term::SizeInfo {
        width: width as f32,
        height: height as f32,
        cell_width: cell_width as f32,
        cell_height: cell_height as f32
    };

    let terminal = Term::new(size);
    let pty = tty::new(size.lines(), size.cols());
    pty.resize(size.lines(), size.cols(), size.width as usize, size.height as usize);
    let pty_io = pty.reader();

    let (tx, rx) = mpsc::channel();

    let signal_flag = Flag::new(false);

    let terminal = Arc::new(FairMutex::new(terminal));

    // Setup the rsize callback for osx
    let terminal_ref = terminal.clone();
    let signal_flag_ref = signal_flag.clone();
    let proxy = window.create_window_proxy();
    let tx2 = tx.clone();
    unsafe {
        RESIZE_CALLBACK = Some(Box::new(move |width: u32, height: u32| {
            let _ = tx2.send((width, height));
            if !signal_flag_ref.0.swap(true, Ordering::AcqRel) {
               // We raised the signal flag
                let mut terminal = terminal_ref.lock();
                terminal.dirty = true;
                proxy.wakeup_event_loop();
            }
        }));
    }

    let event_loop = EventLoop::new(
        terminal.clone(),
        window.create_window_proxy(),
        signal_flag.clone(),
        pty_io,
        ref_test,
    );

    let loop_tx = event_loop.channel();
    let event_loop_handle = event_loop.spawn(None);

    // Wraps a renderer and gives simple draw() api.
    let mut display = Display::new(
        &window,
        renderer,
        glyph_cache,
        render_timer,
        rx,
        pty
    );

    // Event processor
    let mut processor = event::Processor::new(
        input::LoopNotifier(loop_tx),
        terminal.clone(),
        tx,
        &config,
        ref_test,
    );

    let (config_tx, config_rx) = mpsc::channel();

    // create a config watcher when config is loaded from disk
    let _config_reloader = config_path.map(|config_path| {
        config::Watcher::new(config_path, ConfigHandler {
            tx: config_tx,
            window: window.create_window_proxy(),
        })
    });

    // Main loop
    loop {
        // Wait for something to happen
        processor.process_events(&window);

        if let Ok(config) = config_rx.try_recv() {
            display.update_config(&config);
            processor.update_config(&config);
        }

        // Maybe draw the terminal
        let terminal = terminal.lock();
        signal_flag.set(false);
        if terminal.dirty {
            display.draw(terminal, &config);
        }

        if process_should_exit() {
            break;
        }
    }

    // FIXME need file watcher to work with custom delegates before
    //       joining config reloader is possible
    // config_reloader.join().ok();

    // shutdown
    event_loop_handle.join().ok();
    println!("Goodbye");
}

struct ConfigHandler {
    tx: mpsc::Sender<config::Config>,
    window: ::glutin::WindowProxy,
}

// TODO FIXME
impl config::OnConfigReload for ConfigHandler {
    fn on_config_reload(&mut self, config: Config) {
        if let Err(..) = self.tx.send(config) {
            err_println!("Failed to notify of new config");
            return;
        }

        self.window.wakeup_event_loop();
    }
}

struct Display<'a> {
    window: &'a glutin::Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    meter: Meter,
    pty: Pty,
}

impl<'a> Display<'a> {
    pub fn update_config(&mut self, config: &Config) {
        self.renderer.update_config(config);
        self.render_timer = config.render_timer();
    }

    pub fn new(
        window: &glutin::Window,
        renderer: QuadRenderer,
        glyph_cache: GlyphCache,
        render_timer: bool,
        rx: mpsc::Receiver<(u32, u32)>,
        pty: Pty
    ) -> Display {
        Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            rx: rx,
            meter: Meter::new(),
            pty: pty,
        }
    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config) {
        terminal.dirty = false;

        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Check for any out-of-band resize events (mac only)
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            terminal.resize(w as f32, h as f32);
            let size = terminal.size_info();
            self.pty.resize(size.lines(), size.cols(), w as _, h as _);
            self.renderer.resize(w as i32, h as i32);
        }

        {
            let glyph_cache = &mut self.glyph_cache;
            // Draw grid
            {
                let _sampler = self.meter.sampler();

                let size_info = terminal.size_info().clone();
                self.renderer.with_api(config, &size_info, |mut api| {
                    api.clear();

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = alacritty::ansi::Color::Spec(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
                self.renderer.with_api(config, terminal.size_info(), |mut api| {
                    api.render_string(&timing[..], glyph_cache, &color);
                });
            }
        }

        // Unlock the terminal mutex
        drop(terminal);
        self.window.swap_buffers().unwrap();
    }
}
<commit_msg>Add comments in main loop<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![allow(stable_features)] // lying about question_mark because 1.14.0 isn't released!

#![feature(proc_macro)]

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate alacritty;
extern crate cgmath;
extern crate copypasta;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate mio;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;
extern crate vte;

#[macro_use]
extern crate bitflags;

use std::sync::{mpsc, Arc};
use std::sync::atomic::Ordering;

use parking_lot::{MutexGuard};

use alacritty::Flag;
use alacritty::Rgb;
use alacritty::config::{self, Config};
use alacritty::event;
use alacritty::gl;
use alacritty::input;
use alacritty::meter::Meter;
use alacritty::renderer::{QuadRenderer, GlyphCache};
use alacritty::sync::FairMutex;
use alacritty::term::{self, Term};
use alacritty::tty::{self, Pty, process_should_exit};
use alacritty::event_loop::EventLoop;

/// Channel used by resize handling on mac
static mut RESIZE_CALLBACK: Option<Box<Fn(u32, u32)>> = None;

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        RESIZE_CALLBACK.as_ref().map(|func| func(width, height));
    }
}

fn main() {
    // Load configuration
    let (config, config_path) = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => (Config::default(), None),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok((config, path)) => (config, Some(path)),
    };

    let mut ref_test = false;
    let mut columns = 80;
    let mut lines = 24;

    let mut args_iter = ::std::env::args();
    while let Some(arg) = args_iter.next() {
        match &arg[..] {
            // Generate ref test
            "--ref-test" => ref_test = true,
            // Set dimensions
            "-d" | "--dimensions" => {
                args_iter.next()
                    .map(|w| w.parse().map(|w| columns = w));
                args_iter.next()
                    .map(|h| h.parse().map(|h| lines = h));
            },
            // ignore unexpected
            _ => (),
        }
    }

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();

    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        // gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    // Create renderer
    let mut renderer = QuadRenderer::new(&config, width, height);

    // Initialize glyph cache
    let glyph_cache = {
        println!("Initializing glyph cache");
        let init_start = ::std::time::Instant::now();

        let cache = renderer.with_loader(|mut api| {
            GlyphCache::new(rasterizer, &config, &mut api)
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);

        cache
    };

    let metrics = glyph_cache.font_metrics();
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    // Resize window to be 80 col x 24 lines
    let width = cell_width * columns + 4;
    let height = cell_height * lines + 4;
    println!("set_inner_size: {} x {}", width, height);
    // Is this in points?
    let width_pts = (width as f32 / dpr) as u32;
    let height_pts = (height as f32 / dpr) as u32;
    println!("set_inner_size: {} x {}; pts: {} x {}", width, height, width_pts, height_pts);
    window.set_inner_size(width_pts, height_pts);
    renderer.resize(width as _, height as _);

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let size = term::SizeInfo {
        width: width as f32,
        height: height as f32,
        cell_width: cell_width as f32,
        cell_height: cell_height as f32
    };

    let terminal = Term::new(size);
    let pty = tty::new(size.lines(), size.cols());
    pty.resize(size.lines(), size.cols(), size.width as usize, size.height as usize);
    let pty_io = pty.reader();

    let (tx, rx) = mpsc::channel();

    let signal_flag = Flag::new(false);

    let terminal = Arc::new(FairMutex::new(terminal));

    // Setup the rsize callback for osx
    let terminal_ref = terminal.clone();
    let signal_flag_ref = signal_flag.clone();
    let proxy = window.create_window_proxy();
    let tx2 = tx.clone();
    unsafe {
        RESIZE_CALLBACK = Some(Box::new(move |width: u32, height: u32| {
            let _ = tx2.send((width, height));
            if !signal_flag_ref.0.swap(true, Ordering::AcqRel) {
               // We raised the signal flag
                let mut terminal = terminal_ref.lock();
                terminal.dirty = true;
                proxy.wakeup_event_loop();
            }
        }));
    }

    let event_loop = EventLoop::new(
        terminal.clone(),
        window.create_window_proxy(),
        signal_flag.clone(),
        pty_io,
        ref_test,
    );

    let loop_tx = event_loop.channel();
    let event_loop_handle = event_loop.spawn(None);

    // Wraps a renderer and gives simple draw() api.
    let mut display = Display::new(
        &window,
        renderer,
        glyph_cache,
        render_timer,
        rx,
        pty
    );

    // Event processor
    let mut processor = event::Processor::new(
        input::LoopNotifier(loop_tx),
        terminal.clone(),
        tx,
        &config,
        ref_test,
    );

    let (config_tx, config_rx) = mpsc::channel();

    // create a config watcher when config is loaded from disk
    let _config_reloader = config_path.map(|config_path| {
        config::Watcher::new(config_path, ConfigHandler {
            tx: config_tx,
            window: window.create_window_proxy(),
        })
    });

    // Main loop
    loop {
        // Wait for something to happen
        processor.process_events(&window);

        // Handle config reloads
        if let Ok(config) = config_rx.try_recv() {
            display.update_config(&config);
            processor.update_config(&config);
        }

        // Maybe draw the terminal
        let terminal = terminal.lock();
        signal_flag.set(false);
        if terminal.dirty {
            display.draw(terminal, &config);
        }

        // Begin shutdown if the flag was raised.
        if process_should_exit() {
            break;
        }
    }

    // FIXME need file watcher to work with custom delegates before
    //       joining config reloader is possible
    // config_reloader.join().ok();

    // shutdown
    event_loop_handle.join().ok();
    println!("Goodbye");
}

struct ConfigHandler {
    tx: mpsc::Sender<config::Config>,
    window: ::glutin::WindowProxy,
}

// TODO FIXME
impl config::OnConfigReload for ConfigHandler {
    fn on_config_reload(&mut self, config: Config) {
        if let Err(..) = self.tx.send(config) {
            err_println!("Failed to notify of new config");
            return;
        }

        self.window.wakeup_event_loop();
    }
}

struct Display<'a> {
    window: &'a glutin::Window,
    renderer: QuadRenderer,
    glyph_cache: GlyphCache,
    render_timer: bool,
    rx: mpsc::Receiver<(u32, u32)>,
    meter: Meter,
    pty: Pty,
}

impl<'a> Display<'a> {
    pub fn update_config(&mut self, config: &Config) {
        self.renderer.update_config(config);
        self.render_timer = config.render_timer();
    }

    pub fn new(
        window: &glutin::Window,
        renderer: QuadRenderer,
        glyph_cache: GlyphCache,
        render_timer: bool,
        rx: mpsc::Receiver<(u32, u32)>,
        pty: Pty
    ) -> Display {
        Display {
            window: window,
            renderer: renderer,
            glyph_cache: glyph_cache,
            render_timer: render_timer,
            rx: rx,
            meter: Meter::new(),
            pty: pty,
        }
    }

    /// Draw the screen
    ///
    /// A reference to Term whose state is being drawn must be provided.
    ///
    /// This call may block if vsync is enabled
    pub fn draw(&mut self, mut terminal: MutexGuard<Term>, config: &Config) {
        terminal.dirty = false;

        // Resize events new_size and are handled outside the poll_events
        // iterator. This has the effect of coalescing multiple resize
        // events into one.
        let mut new_size = None;

        // Check for any out-of-band resize events (mac only)
        while let Ok(sz) = self.rx.try_recv() {
            new_size = Some(sz);
        }

        // Receive any resize events; only call gl::Viewport on last
        // available
        if let Some((w, h)) = new_size.take() {
            terminal.resize(w as f32, h as f32);
            let size = terminal.size_info();
            self.pty.resize(size.lines(), size.cols(), w as _, h as _);
            self.renderer.resize(w as i32, h as i32);
        }

        {
            let glyph_cache = &mut self.glyph_cache;
            // Draw grid
            {
                let _sampler = self.meter.sampler();

                let size_info = terminal.size_info().clone();
                self.renderer.with_api(config, &size_info, |mut api| {
                    api.clear();

                    // Draw the grid
                    api.render_cells(terminal.renderable_cells(), glyph_cache);
                });
            }

            // Draw render timer
            if self.render_timer {
                let timing = format!("{:.3} usec", self.meter.average());
                let color = alacritty::ansi::Color::Spec(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
                self.renderer.with_api(config, terminal.size_info(), |mut api| {
                    api.render_string(&timing[..], glyph_cache, &color);
                });
            }
        }

        // Unlock the terminal mutex
        drop(terminal);
        self.window.swap_buffers().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate noise;

use piston::window::WindowSettings;
use piston::event::{ Event, Events };
use piston::input::{ Button, Input, Key };
use glutin_window::GlutinWindow as Window;
use opengl_graphics::OpenGL;

mod mapgen;
mod traits;
mod models;
mod renderer;

use traits::*;

const TITLE: &'static str = "Open Sea";

fn main() {

  let view = renderer::GameView::new();

  let gl_context = OpenGL::_2_1;

  let window = Window::new(gl_context,
               WindowSettings::new(TITLE, [800, 600]).exit_on_esc(true));

  // This is the object used for drawing
  let mut gl = opengl_graphics::GlGraphics::new(gl_context);

  for event in window.events() {
    match event {
      Event::Input(Input::Press(Button::Keyboard(Key::Return))) =>
        println!("Return pressed!"),

      Event::Input(Input::Release(Button::Keyboard(Key::Return))) =>
        println!("Return released!"),

      Event::Render(args) => {
        use graphics::*;
        gl.draw(args.viewport(), |_, gl| {
          clear([1.0, 1.0, 1.0, 1.0], gl);
          renderer::render(gl, &view);
        });
      },

      _ => {}
    }
  }
}
<commit_msg>Doc's working<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate noise;

use piston::window::WindowSettings;
use piston::event::{ Event, Events };
use piston::input::{ Button, Input, Key };
use glutin_window::GlutinWindow as Window;
use opengl_graphics::OpenGL;

// Why pub? Because that makes the docs work.
pub mod mapgen;
pub mod traits;
pub mod models;
pub mod renderer;

use traits::*;

const TITLE: &'static str = "Open Sea";

fn main() {

  let view = renderer::GameView::new();

  let gl_context = OpenGL::_2_1;

  let window = Window::new(gl_context,
               WindowSettings::new(TITLE, [800, 600]).exit_on_esc(true));

  // This is the object used for drawing
  let mut gl = opengl_graphics::GlGraphics::new(gl_context);

  for event in window.events() {
    match event {
      Event::Input(Input::Press(Button::Keyboard(Key::Return))) =>
        println!("Return pressed!"),

      Event::Input(Input::Release(Button::Keyboard(Key::Return))) =>
        println!("Return released!"),

      Event::Render(args) => {
        use graphics::*;
        gl.draw(args.viewport(), |_, gl| {
          clear([1.0, 1.0, 1.0, 1.0], gl);
          renderer::render(gl, &view);
        });
      },

      _ => {}
    }
  }
}
<|endoftext|>


<commit_before>extern crate glob;
#[macro_use]
extern crate lazy_static;
extern crate log;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate structopt;
extern crate syslog;
extern crate toml;

mod applog;
mod connection;
mod error;
mod message;
mod statics;
mod structs;

use log::debug;
use message::*;
use std::env;
use std::io::{Error, ErrorKind};
use structopt::StructOpt;
use structs::Config;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() -> Result<(), Error> {
    let command = Command::from_args();
    let conn = match connection::Connection::new(&format!("{:?}", command)) {
        Ok(conn) => conn,
        Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}", err))),
    };
    debug!("connected to socket: {:?}", conn);

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => return Ok(()),
            Err(_) => return Err(Error::new(ErrorKind::Other, "check failed")),
        },
        Command::Key { user } => match conn.communicate(ClientMessage::Key { user }) {
            Ok(DaemonMessage::Key { keys }) => {
                println!("{}", keys);
                return Ok(());
            }
            _ => return Err(Error::new(ErrorKind::PermissionDenied, "key check failed")),
        },
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match conn.communicate(ClientMessage::Pam { user }) {
                Ok(DaemonMessage::Pam { result }) => {
                    if result {
                        return Ok(());
                    } else {
                        return Err(Error::new(ErrorKind::NotFound, "user not found"));
                    }
                }
                _ => return Err(Error::new(ErrorKind::Other, "faild")),
            },
            Err(_) => return Err(Error::new(ErrorKind::ConnectionRefused, "failed")),
        },
        Command::CleanUp => match conn.communicate(ClientMessage::CleanUp) {
            Ok(_) => return Ok(()),
            Err(_) => return Err(Error::new(ErrorKind::Other, "failed")),
        },
        Command::RateLimit => match conn.communicate(ClientMessage::RateLimit) {
            Ok(DaemonMessage::RateLimit { limit }) => {
                println!("{:?}", limit);
            }
            _ => return Err(Error::new(ErrorKind::Other, "failed")),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
    return Ok(());
}
<commit_msg>Remove unneeded return<commit_after>extern crate glob;
#[macro_use]
extern crate lazy_static;
extern crate log;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate structopt;
extern crate syslog;
extern crate toml;

mod applog;
mod connection;
mod error;
mod message;
mod statics;
mod structs;

use log::debug;
use message::*;
use std::env;
use std::io::{Error, ErrorKind};
use structopt::StructOpt;
use structs::Config;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() -> Result<(), Error> {
    let command = Command::from_args();
    let conn = match connection::Connection::new(&format!("{:?}", command)) {
        Ok(conn) => conn,
        Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}", err))),
    };
    debug!("connected to socket: {:?}", conn);

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => return Ok(()),
            Err(_) => return Err(Error::new(ErrorKind::Other, "check failed")),
        },
        Command::Key { user } => match conn.communicate(ClientMessage::Key { user }) {
            Ok(DaemonMessage::Key { keys }) => {
                println!("{}", keys);
                return Ok(());
            }
            _ => return Err(Error::new(ErrorKind::PermissionDenied, "key check failed")),
        },
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match conn.communicate(ClientMessage::Pam { user }) {
                Ok(DaemonMessage::Pam { result }) => {
                    if result {
                        return Ok(());
                    } else {
                        return Err(Error::new(ErrorKind::NotFound, "user not found"));
                    }
                }
                _ => return Err(Error::new(ErrorKind::Other, "faild")),
            },
            Err(_) => return Err(Error::new(ErrorKind::ConnectionRefused, "failed")),
        },
        Command::CleanUp => match conn.communicate(ClientMessage::CleanUp) {
            Ok(_) => return Ok(()),
            Err(_) => return Err(Error::new(ErrorKind::Other, "failed")),
        },
        Command::RateLimit => match conn.communicate(ClientMessage::RateLimit) {
            Ok(DaemonMessage::RateLimit { limit }) => {
                println!("{:?}", limit);
            }
            _ => return Err(Error::new(ErrorKind::Other, "failed")),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

extern crate gitlib;
extern crate term_painter;
extern crate pbr;

use std::error::Error;
use std::env;
use std::path::Path;

use term_painter::Color::{BrightRed, BrightCyan, BrightGreen, BrightMagenta, BrightYellow};
use term_painter::ToStyle;

use gitlib::FileStatus;
use gitlib::{GitError, GitRepo};

mod cli;

#[derive(Debug)]
enum RunOptions {
    Checkout(String),
    Reset,
    Status,
}

fn main() {
    let working_dir = match env::current_dir() {
        Ok(path) => path,
        Err(err) => {
            println!("Error getting working directory: {}", err.description());
            return;
        }
    };

    let matches = cli::build_cli().get_matches();

    let option = match matches.subcommand_name() {
        Some(cli::CMD_CHECKOUT) => {
            let branch_match = matches.subcommand_matches(cli::CMD_CHECKOUT).unwrap();
            let branch = value_t!(branch_match, cli::BRANCH, String).unwrap();
            RunOptions::Checkout(branch)
        }
        Some(cli::CMD_COMPLETIONS) => {
            if let Some(ref matches) = matches.subcommand_matches(cli::CMD_COMPLETIONS) {
                let shell = value_t!(matches, cli::SHELL, clap::Shell).unwrap();
                cli::build_cli().gen_completions_to(cli::APP_NAME, shell, &mut std::io::stdout());
            }

            return;
        }
        Some(cli::CMD_RESET) => RunOptions::Reset,

        // By default, just show status.
        _ => RunOptions::Status,
    };

    walk_dirs(&option, &working_dir);
}

fn walk_dirs(options: &RunOptions, path: &Path) {
    let mut pending = vec![path.to_owned()];

    while let Some(current_dir) = pending.pop() {
        let read_result = current_dir.read_dir();

        if let Err(_) = read_result {
            continue;
        }

        let path_iter = read_result
            .unwrap()
            .filter_map(|x| x.ok())
            .filter(|x| match x.file_type() {
                        Ok(t) => t.is_dir(),
                        Err(_) => false,
                    })
            .filter(|x| match x.path().file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    !name_str.starts_with(".") && !name_str.starts_with("$")
                                }
                                None => false,
                            }
                        }
                        None => false,
                    });

        for entry in path_iter {
            let status = process(options, &entry.path());

            if let Err(GitError::OpenRepo) = status {
                pending.push(entry.path().to_path_buf());
            }
        }
    }
}

fn process(options: &RunOptions, path: &Path) -> Result<(), GitError> {
    let repo = GitRepo::new(path)?;

    match *options {
        RunOptions::Checkout(ref branch) => checkout(repo, path, branch),
        RunOptions::Reset => reset(repo, path),
        RunOptions::Status => status(repo, path),
    }
}

fn checkout(repo: GitRepo, path: &Path, branch: &str) -> Result<(), GitError> {
    repo.checkout(branch)?;

    println!("{}", path.to_str().unwrap());
    //println!("    {}", BrightCyan.paint(branch));

    Ok(())
}

fn reset(repo: GitRepo, path: &Path) -> Result<(), GitError> {
    let head = repo.reset()?;
    let branch = BrightCyan.paint(head.name().unwrap());
    let l_brace = BrightYellow.paint("[");
    let r_brace = BrightYellow.paint("]");

    println!("{}  {}{}{}",
             path.to_str().unwrap(),
             l_brace,
             branch,
             r_brace);

    Ok(())
}

fn status(repo: GitRepo, path: &Path) -> Result<(), GitError> {
    let statuses = repo.statuses()?;

    if statuses.len() == 0 {
        return Ok(());
    }

    println!("{}", path.to_str().unwrap());

    for entry in statuses.iter() {
        let (pre, colour) = match entry.status() {
            FileStatus::Deleted => ("    Deleted", BrightRed),
            FileStatus::Modified => ("   Modified", BrightCyan),
            FileStatus::New => ("        New", BrightGreen),
            FileStatus::Renamed => ("    Renamed", BrightCyan),
            FileStatus::Typechanged => ("Typechanged", BrightCyan),
            FileStatus::Unknown => ("    Unknown", BrightMagenta),
        };

        println!("  {} {}", colour.paint(pre), entry.path().unwrap());
    }

    Ok(())
}<commit_msg>Turned match block into chained map/unwrap_or expression<commit_after>#[macro_use]
extern crate clap;

extern crate gitlib;
extern crate term_painter;
extern crate pbr;

use std::error::Error;
use std::env;
use std::path::Path;

use term_painter::Color::{BrightRed, BrightCyan, BrightGreen, BrightMagenta, BrightYellow};
use term_painter::ToStyle;

use gitlib::FileStatus;
use gitlib::{GitError, GitRepo};

mod cli;

#[derive(Debug)]
enum RunOptions {
    Checkout(String),
    Reset,
    Status,
}

fn main() {
    let working_dir = match env::current_dir() {
        Ok(path) => path,
        Err(err) => {
            println!("Error getting working directory: {}", err.description());
            return;
        }
    };

    let matches = cli::build_cli().get_matches();

    let option = match matches.subcommand_name() {
        Some(cli::CMD_CHECKOUT) => {
            let branch_match = matches.subcommand_matches(cli::CMD_CHECKOUT).unwrap();
            let branch = value_t!(branch_match, cli::BRANCH, String).unwrap();
            RunOptions::Checkout(branch)
        }
        Some(cli::CMD_COMPLETIONS) => {
            if let Some(ref matches) = matches.subcommand_matches(cli::CMD_COMPLETIONS) {
                let shell = value_t!(matches, cli::SHELL, clap::Shell).unwrap();
                cli::build_cli().gen_completions_to(cli::APP_NAME, shell, &mut std::io::stdout());
            }

            return;
        }
        Some(cli::CMD_RESET) => RunOptions::Reset,

        // By default, just show status.
        _ => RunOptions::Status,
    };

    walk_dirs(&option, &working_dir);
}

fn walk_dirs(options: &RunOptions, path: &Path) {
    let mut pending = vec![path.to_owned()];

    while let Some(current_dir) = pending.pop() {
        let read_result = current_dir.read_dir();

        if let Err(_) = read_result {
            continue;
        }

        let path_iter = read_result
            .unwrap()
            .filter_map(|x| x.ok())
            .filter(|x| x.file_type().map(|t| t.is_dir()).unwrap_or(false))
            .filter(|x| match x.path().file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    !name_str.starts_with(".") && !name_str.starts_with("$")
                                }
                                None => false,
                            }
                        }
                        None => false,
                    });

        for entry in path_iter {
            let status = process(options, &entry.path());

            if let Err(GitError::OpenRepo) = status {
                pending.push(entry.path().to_path_buf());
            }
        }
    }
}

fn process(options: &RunOptions, path: &Path) -> Result<(), GitError> {
    let repo = GitRepo::new(path)?;

    match *options {
        RunOptions::Checkout(ref branch) => checkout(repo, path, branch),
        RunOptions::Reset => reset(repo, path),
        RunOptions::Status => status(repo, path),
    }
}

fn checkout(repo: GitRepo, path: &Path, branch: &str) -> Result<(), GitError> {
    repo.checkout(branch)?;

    println!("{}", path.to_str().unwrap());
    //println!("    {}", BrightCyan.paint(branch));

    Ok(())
}

fn reset(repo: GitRepo, path: &Path) -> Result<(), GitError> {
    let head = repo.reset()?;
    let branch = BrightCyan.paint(head.name().unwrap());
    let l_brace = BrightYellow.paint("[");
    let r_brace = BrightYellow.paint("]");

    println!("{}  {}{}{}",
             path.to_str().unwrap(),
             l_brace,
             branch,
             r_brace);

    Ok(())
}

fn status(repo: GitRepo, path: &Path) -> Result<(), GitError> {
    let statuses = repo.statuses()?;

    if statuses.len() == 0 {
        return Ok(());
    }

    println!("{}", path.to_str().unwrap());

    for entry in statuses.iter() {
        let (pre, colour) = match entry.status() {
            FileStatus::Deleted => ("    Deleted", BrightRed),
            FileStatus::Modified => ("   Modified", BrightCyan),
            FileStatus::New => ("        New", BrightGreen),
            FileStatus::Renamed => ("    Renamed", BrightCyan),
            FileStatus::Typechanged => ("Typechanged", BrightCyan),
            FileStatus::Unknown => ("    Unknown", BrightMagenta),
        };

        println!("  {} {}", colour.paint(pre), entry.path().unwrap());
    }

    Ok(())
}<|endoftext|>


<commit_before>extern crate getopts;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;

use getopts::Options;
use hyper::{Client, header, error};
use hyper::header::{Authorization, Bearer};
use rustc_serialize::json;
use rustc_serialize::json::{ToJson, Json};

use std::env;
use std::process;
use std::io::Read;
use std::path::Path;
use std::fs::File;
use std::collections::BTreeMap;

const GIST_API:          &'static str = "https://api.github.com/gists";
const GITHUB_TOKEN:      &'static str = "GITHUB_TOKEN";
const USER_AGENT:        &'static str = "Pepito Gist";
const DEFAULT_GIST_NAME: &'static str = "Untitled";

struct Gist {
    filename: String,
    private:  bool,
    contents: String,
}
type Gists = Vec<Gist>;

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

impl Gist {
    fn new(filename: String, public: bool) -> Gist {
        Gist {
            private:  !public,
            filename: filename,
            contents: String::new(),
        }
    }

    // Read standard input to contents buffer.
    fn read_stdin(&mut self) -> std::io::Result<usize> {
        std::io::stdin().read_to_string(&mut self.contents)
    }

    // Read file to contents buffer.
    fn read_file(&mut self) -> std::io::Result<usize> {
        let path = Path::new(&self.filename);
        let mut fh = File::open(&path).unwrap();

        fh.read_to_string(&mut self.contents)
    }
}

impl ToJson for Gist {
    fn to_json(&self) -> Json {
        let mut root = BTreeMap::new();
        root.insert("content".to_string(), self.contents.to_json());
        Json::Object(root)
    }
}

// Convert a Gist vector to JSON, suitable for Github's Gist API.
fn gists_to_json(gists : Gists) -> Json {
    let mut root  = BTreeMap::new();
    let mut files = BTreeMap::new();

    root.insert("public".to_string(), (!gists[0].private).to_json());
    for g in gists {
        files.insert(g.filename.clone(), g);
    }
    root.insert("files".to_string(), files.to_json());

    Json::Object(root)
}

fn create_gists(gists : Gists) -> Result<String, error::Error> {
    let client = Client::new();
    let token : String = env::var(&GITHUB_TOKEN.to_string()).unwrap();

    let json_body = gists_to_json(gists).to_string();
    let mut res = try!(client.post(&GIST_API.to_string())
        .header(header::Authorization(Bearer { token: token.to_owned() }))
        .header(header::UserAgent(USER_AGENT.to_owned()))
        .header(header::ContentType::json())
        .body(json_body.as_bytes())
        .send());

    let mut body = String::new();
    try!(res.read_to_string(&mut body));
    Ok(body)
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn parse_args(args : Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optflag("p", "public", "make public");
    opts.optflag("h", "help", "print this help menu");

    let params = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
        process::exit(1);
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let public = params.opt_present("p");
    let opt_name = match params.opt_str("f") {
        Some(name) => name,
        None       => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gists: Gists = vec![];

    // If we receive filenames, read them, else use STDIN.
    if !params.free.is_empty() {
        for file_param in params.free {
            let mut g = Gist::new(file_param, public);
            g.read_file().unwrap();
            gists.push(g);
        }
    } else {
        let mut gist = Gist::new(opt_name, public);
        gist.read_stdin().unwrap();
        gists.push(gist);
    }

    let res = create_gists(gists);
    if res.is_ok() {
        let gist: GistResponse = json::decode(&res.unwrap()).unwrap();
        println!("{}", gist.html_url);
    }
}
<commit_msg>Use a Gists type & cleanup some unwraps<commit_after>extern crate getopts;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;

use getopts::Options;
use hyper::{Client, header, error};
use hyper::header::{Authorization, Bearer};
use rustc_serialize::json;
use rustc_serialize::json::{ToJson, Json};

use std::env;
use std::process;
use std::io::{self, Read};
use std::path::Path;
use std::fs::File;
use std::collections::BTreeMap;

const GIST_API:          &'static str = "https://api.github.com/gists";
const GITHUB_TOKEN:      &'static str = "GITHUB_TOKEN";
const USER_AGENT:        &'static str = "Pepito Gist";
const DEFAULT_GIST_NAME: &'static str = "Untitled";

struct Gist {
    filename: String,
    contents: String,
}

struct Gists {
    public: bool,
    files:  Vec<Gist>,
}

impl Gists {
    fn new(public: bool) -> Gists {
        Gists {
            public: public,
            files:  vec![],
        }
    }

    // Add a file.
    fn push(&mut self, gist : Gist) {
        self.files.push(gist);
    }

    // Sent to Github.
    fn create(&mut self) -> Result<String, error::Error> {
        let client = Client::new();
        let token : String = env::var(&GITHUB_TOKEN.to_string()).unwrap();
        let json_body = self.to_json().to_string();
        let mut res = try!(client.post(&GIST_API.to_string())
            .header(header::Authorization(Bearer { token: token.to_owned() }))
            .header(header::UserAgent(USER_AGENT.to_owned()))
            .header(header::ContentType::json())
            .body(json_body.as_bytes())
            .send());

        let mut body = String::new();
        try!(res.read_to_string(&mut body));
        Ok(body)
    }
}

impl Gist {
    fn new(filename: String) -> Gist {
        Gist {
            filename: filename,
            contents: String::new(),
        }
    }

    // Read standard input to contents buffer.
    fn read_stdin(&mut self) -> Result<&Gist, io::Error> {
        try!(io::stdin().read_to_string(&mut self.contents));
        Ok(self)
    }

    // Read file to contents buffer.
    fn read_file(&mut self) -> Result<&Gist, io::Error> {
        let path = Path::new(&self.filename);
        let mut fh = try!(File::open(&path));
        try!(fh.read_to_string(&mut self.contents));
        Ok(self)
    }
}

impl ToJson for Gist {
    fn to_json(&self) -> Json {
        let mut root = BTreeMap::new();
        root.insert("content".to_string(), self.contents.to_json());
        Json::Object(root)
    }
}

impl ToJson for Gists {
    fn to_json(&self) -> Json {
        let mut root  = BTreeMap::new();
        let mut files = BTreeMap::new();

        root.insert("public".to_string(), self.public.to_json());
        for g in self.files.iter() {
            files.insert(g.filename.clone(), g.to_json());
        }
        root.insert("files".to_string(), files.to_json());
        Json::Object(root)
    }
}

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn parse_args(args : Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optflag("p", "public", "make public");
    opts.optflag("h", "help", "print this help menu");

    let params = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(f) => panic!(f.to_string())
    };
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
        process::exit(1);
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let public = params.opt_present("p");
    let filename = match params.opt_str("f") {
        Some(name) => name,
        None       => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gists = Gists::new(public);

    // If we receive filenames, read them, else use STDIN.
    if !params.free.is_empty() {
        for file_param in params.free {
            let mut g = Gist::new(file_param);
            g.read_file().ok().expect("Cannot read file");
            gists.push(g);
        }
    } else {
        let mut g = Gist::new(filename);
        if g.read_stdin().is_ok() { gists.push(g); }
    }

    if !gists.files.is_empty() {
        match gists.create() {
            Ok(r) => {
                let gist: GistResponse = json::decode(&r).unwrap();
                println!("{}", gist.html_url);
            },
            Err(e) => panic!("{}", e)
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate xmltree;
extern crate ansi_term;

mod utils;

use getopts::{Options, Matches};
use std::env;
use xmltree::Element;
use ansi_term::Color;

use utils::{log_print, LogLevel};

use std::cmp::{Ord, Ordering};

#[derive(Debug, Eq, PartialEq, PartialOrd)]
struct Attr<'attr> {
    key: &'attr str,
    value: &'attr str,
}

impl<'attr> Attr<'attr> {
    fn new(data: (&'attr str, &'attr str)) -> Attr<'attr> {
        Attr {
            key: data.0,
            value: data.1,
        }
    }

    fn print(&self) -> String {
        format!("{}=\"{}\"", self.key, self.value)
    }
}

impl<'attr> Ord for Attr<'attr> {
    fn cmp(&self, rhs: &Attr<'attr>) -> Ordering {
        self.key.cmp(rhs.key)
    }
}

#[derive(Debug)]
struct Tag<'tag> {
    el: &'tag Element,
    attrs: Vec<Attr<'tag>>,
}

impl<'tag> PartialEq for Tag<'tag> {
    fn eq(&self, rhs: &Tag<'tag>) -> bool {
        match self.el.text {
            Some(_) => self.el.text == rhs.el.text,
            None => self.el.name == rhs.el.name && self.attrs == rhs.attrs,
        }
    }
}

impl<'tag> Tag<'tag> {
    fn new(el: &'tag Element) -> Tag<'tag> {
        let mut ret_val: Tag<'tag> = Tag {
            el: el,
            attrs: Vec::new(),
        };

        for attr in &el.attributes {
            let attr: Attr<'tag> = Attr::<'tag>::new((attr.0, attr.1));
            ret_val.attrs.push(attr);
        }

        ret_val.attrs.sort();

        ret_val
    }

    fn print(&self, indent: &usize) -> String {
        let mut ret_val: String = utils::repeat_char(' ', *indent);
        ret_val.push('<');

        ret_val.push_str(&self.el.name);

        for attr in &self.attrs {
            ret_val.push(' ');
            ret_val.push_str(&attr.print());
        }

        ret_val.push_str(">");

        if let Some(ref text) = self.el.text {
            ret_val.push_str(text);
            ret_val.push_str(&format!("</{}>", self.el.name));
        }

        ret_val
    }

    fn print_end(&self, indent: &usize) -> Option<String> {
        if !self.has_text() {
            Some(format!("{}</{}>", utils::repeat_char(' ', *indent), self.el.name))
        } else {
            None
        }
    }

    fn has_text(&self) -> bool {
        !self.el.text.is_none()
    }

    fn print_diff(&self, indent: &usize) -> String {
        let i: usize = *indent - 1;

        format!("{}{}\n{}",
                Color::Green.paint("|"),
                &self.print(&i),
                Color::Red.paint("|"))
    }
}

fn compare_nodes<'cn>(tag_x: &Tag<'cn>, tag_y: &Tag<'cn>, indent: &'cn mut usize) {

    let start_tag = tag_x.print(indent);
    let end_tag = tag_x.print_end(indent);

    *indent += 2;

    println!("{}", start_tag);

    for child_x in &tag_x.el.children {
        let tag_child_x: Tag = Tag::new(child_x);
        let mut found: bool = false;

        for child_y in &tag_y.el.children {
            let tag_child_y: Tag = Tag::new(child_y);

            if tag_child_x == tag_child_y {
                found = true;

                compare_nodes(&tag_child_x, &tag_child_y, indent);

                break;
            }
        }

        if !found {
            println!("{}", tag_child_x.print_diff(indent));
        }
    }

    if let Some(v) = end_tag {
        println!("{}", v)
    }

    *indent -= 2;
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program: String = args[0].clone();

    let mut opts: Options = Options::new();
    opts.optopt("h", "help", "Show help page", "");
    //opts.optopt("f", "output-file", "Save result to file", "");
    //opts.optopt("v", "version", "Show version", "");

    let matches: Matches = match opts.parse(&args[1..]) {
        Ok(v) => v,
        Err(_) => {
            utils::print_usage(&program, &opts);
            return;
        }
    };

    if matches.opt_present("h") {
        utils::print_usage(&program, &opts);
        return;
    }

    if matches.free.len() < 2 {
        utils::print_usage(&program, &opts);
        return;
    }

    let content_x: String = match utils::read_file_content(&matches.free[0]) {
        Ok(v) => v,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    let content_y: String = match utils::read_file_content(&matches.free[1]) {
        Ok(v) => v,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    let el_x: Element = match Element::parse(content_x.as_bytes()) {
        Ok(el) => el,
        Err(_) => {
            log_print(LogLevel::ERROR, "Unable to parse XML document.");
            return;
        }
    };

    let el_y: Element = match Element::parse(content_y.as_bytes()) {
        Ok(el) => el,
        Err(_) => {
            log_print(LogLevel::ERROR, "Unable to parse XML document.");
            return;
        }
    };

    let mut indent: usize = 0;
    let tag_x: Tag = Tag::new(&el_x);
    let tag_y: Tag = Tag::new(&el_y);

    if tag_x == tag_y {
        compare_nodes(&tag_x, &tag_y, &mut indent);
    } else {
        tag_x.print_diff(&indent);
    }
}
<commit_msg>Oh, usize -1, woohoo. Found and fixed<commit_after>extern crate getopts;
extern crate xmltree;
extern crate ansi_term;

mod utils;

use getopts::{Options, Matches};
use std::env;
use xmltree::Element;
use ansi_term::Color;

use utils::{log_print, LogLevel};

use std::cmp::{Ord, Ordering};

#[derive(Debug, Eq, PartialEq, PartialOrd)]
struct Attr<'attr> {
    key: &'attr str,
    value: &'attr str,
}

impl<'attr> Attr<'attr> {
    fn new(data: (&'attr str, &'attr str)) -> Attr<'attr> {
        Attr {
            key: data.0,
            value: data.1,
        }
    }

    fn print(&self) -> String {
        format!("{}=\"{}\"", self.key, self.value)
    }
}

impl<'attr> Ord for Attr<'attr> {
    fn cmp(&self, rhs: &Attr<'attr>) -> Ordering {
        self.key.cmp(rhs.key)
    }
}

#[derive(Debug)]
struct Tag<'tag> {
    el: &'tag Element,
    attrs: Vec<Attr<'tag>>,
}

impl<'tag> PartialEq for Tag<'tag> {
    fn eq(&self, rhs: &Tag<'tag>) -> bool {
        match self.el.text {
            Some(_) => self.el.text == rhs.el.text,
            None => self.el.name == rhs.el.name && self.attrs == rhs.attrs,
        }
    }
}

impl<'tag> Tag<'tag> {
    fn new(el: &'tag Element) -> Tag<'tag> {
        let mut ret_val: Tag<'tag> = Tag {
            el: el,
            attrs: Vec::new(),
        };

        for attr in &el.attributes {
            let attr: Attr<'tag> = Attr::<'tag>::new((attr.0, attr.1));
            ret_val.attrs.push(attr);
        }

        ret_val.attrs.sort();

        ret_val
    }

    fn print(&self, indent: &usize) -> String {
        let mut ret_val: String = utils::repeat_char(' ', *indent);
        ret_val.push('<');

        ret_val.push_str(&self.el.name);

        for attr in &self.attrs {
            ret_val.push(' ');
            ret_val.push_str(&attr.print());
        }

        ret_val.push_str(">");

        if let Some(ref text) = self.el.text {
            ret_val.push_str(text);
            ret_val.push_str(&format!("</{}>", self.el.name));
        }

        ret_val
    }

    fn print_end(&self, indent: &usize) -> Option<String> {
        if !self.has_text() {
            Some(format!("{}</{}>", utils::repeat_char(' ', *indent), self.el.name))
        } else {
            None
        }
    }

    fn has_text(&self) -> bool {
        !self.el.text.is_none()
    }

    fn print_diff(&self, indent: &usize) -> String {
        format!("{}{}\n{}",
                Color::Green.paint("|"),
                &self.print(&if *indent > 0 { *indent - 1 } else { 0 }),
                Color::Red.paint("|"))
    }
}

fn compare_nodes<'cn>(tag_x: &Tag<'cn>, tag_y: &Tag<'cn>, indent: &'cn mut usize) {

    let start_tag = tag_x.print(indent);
    let end_tag = tag_x.print_end(indent);

    *indent += 2;

    println!("{}", start_tag);

    for child_x in &tag_x.el.children {
        let tag_child_x: Tag = Tag::new(child_x);
        let mut found: bool = false;

        for child_y in &tag_y.el.children {
            let tag_child_y: Tag = Tag::new(child_y);

            if tag_child_x == tag_child_y {
                found = true;

                compare_nodes(&tag_child_x, &tag_child_y, indent);

                break;
            }
        }

        if !found {
            println!("{}", tag_child_x.print_diff(indent));
        }
    }

    if let Some(v) = end_tag {
        println!("{}", v)
    }

    *indent -= 2;
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program: String = args[0].clone();

    let mut opts: Options = Options::new();
    opts.optopt("h", "help", "Show help page", "");
    //opts.optopt("f", "output-file", "Save result to file", "");
    //opts.optopt("v", "version", "Show version", "");

    let matches: Matches = match opts.parse(&args[1..]) {
        Ok(v) => v,
        Err(_) => {
            utils::print_usage(&program, &opts);
            return;
        }
    };

    if matches.opt_present("h") {
        utils::print_usage(&program, &opts);
        return;
    }

    if matches.free.len() < 2 {
        utils::print_usage(&program, &opts);
        return;
    }

    let content_x: String = match utils::read_file_content(&matches.free[0]) {
        Ok(v) => v,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    let content_y: String = match utils::read_file_content(&matches.free[1]) {
        Ok(v) => v,
        Err(e) => {
            println!("{}", e);
            return;
        }
    };

    let el_x: Element = match Element::parse(content_x.as_bytes()) {
        Ok(el) => el,
        Err(_) => {
            log_print(LogLevel::ERROR, "Unable to parse XML document.");
            return;
        }
    };

    let el_y: Element = match Element::parse(content_y.as_bytes()) {
        Ok(el) => el,
        Err(_) => {
            log_print(LogLevel::ERROR, "Unable to parse XML document.");
            return;
        }
    };

    let mut indent: usize = 0;
    let tag_x: Tag = Tag::new(&el_x);
    let tag_y: Tag = Tag::new(&el_y);

    if tag_x == tag_y {
        compare_nodes(&tag_x, &tag_y, &mut indent);
    } else {
        tag_x.print_diff(&indent);
    }
}
<|endoftext|>