<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use std::mem;

pub unsafe trait Wrapper {

    type Raw: Sized;

    #[inline]
    fn as_ptr(&self) -> *const <Self as Wrapper>::Raw {
        self as *const Self as *const <Self as Wrapper>::Raw
    }

    #[inline]
    fn as_mut_ptr(&self) -> *mut <Self as Wrapper>::Raw {
        self as *const Self as *mut <Self as Wrapper>::Raw
    }
}

#[inline]
pub unsafe fn from_raw<'a, T, U: ?Sized>(ptr: *const <T as Wrapper>::Raw,
                                         life_anchor: &'a U)
                                        -> &'a T
    where T: Wrapper
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const T))
}

pub const STATIC: &'static () = &();
<commit_msg>wrap: make the method .as_mut_ptr() unsafe<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use std::mem;

pub unsafe trait Wrapper {

    type Raw: Sized;

    #[inline]
    fn as_ptr(&self) -> *const <Self as Wrapper>::Raw {
        self as *const Self as *const <Self as Wrapper>::Raw
    }

    #[inline]
    unsafe fn as_mut_ptr(&self) -> *mut <Self as Wrapper>::Raw {
        self as *const Self as *mut <Self as Wrapper>::Raw
    }
}

#[inline]
pub unsafe fn from_raw<'a, T, U: ?Sized>(ptr: *const <T as Wrapper>::Raw,
                                         life_anchor: &'a U)
                                        -> &'a T
    where T: Wrapper
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const T))
}

pub const STATIC: &'static () = &();
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate git2;

mod cd;
mod cli;
mod repository;
mod settings;

use std::process::exit;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    match run_cli() {
        Ok(_) => {}
        Err((message, exit_code)) => {
            error!("{}", message);
            exit(exit_code);
        }
    }
}

fn run_cli() -> Result<(), (String, i32)> {
    let matches = cli::app().get_matches();

    let settings = settings::from_matches(&matches);

    match matches.subcommand_name() {
        Some("cd") => try!(cd::open_shell_at_repo(&settings, matches.subcommand_matches("cd").unwrap())),
        Some("clone") => try!(repository::clone(&settings, matches.subcommand_matches("clone").unwrap())),
        None => panic!("Subcommand is required, so no idea how we got here!"),
        _ => println!("'{}' is not implemented yet.",
                      matches.subcommand_name().unwrap()),
    };

    Ok(())
}
<commit_msg>Clean up subcommand dispatching<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate git2;

mod cd;
mod cli;
mod repository;
mod settings;

use std::process::exit;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    match run_cli() {
        Ok(_) => {}
        Err((message, exit_code)) => {
            error!("{}", message);
            exit(exit_code);
        }
    }
}

fn run_cli() -> Result<(), (String, i32)> {
    let matches = cli::app().get_matches();

    let settings = settings::from_matches(&matches);

    match matches.subcommand() {
        ("cd", Some(m)) => try!(cd::open_shell_at_repo(&settings, m)),
        ("clone", Some(m)) => try!(repository::clone(&settings, m)),
        ("link", Some(m)) => try!(repository::link_repo(&settings, m)),
        (name, _) => println!("'{}' is not implemented yet.", name),
    };

    Ok(())
}
<|endoftext|>


<commit_before>pub mod api;
pub mod db;
pub mod indexer;
pub mod model;
pub mod opening;
pub mod util;

use crate::{
    api::{
        Error, GameRow, GameRowWithUci, PersonalMoveRow, PersonalQuery, PersonalQueryFilter,
        PersonalResponse,
    },
    db::Database,
    indexer::{IndexerOpt, IndexerStub},
    model::{AnnoLichess, PersonalKeyBuilder, PersonalKeyPrefix},
    opening::{Opening, Openings},
    util::NdJson,
};
use axum::{
    extract::{Extension, Path, Query},
    handler::get,
    http::StatusCode,
    AddExtensionLayer, Router,
};
use clap::Clap;
use futures_util::stream::Stream;
use shakmaty::{fen::Fen, variant::VariantPosition, zobrist::Zobrist, CastlingMode};
use std::{mem, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
use tokio::sync::oneshot;

#[derive(Clap)]
struct Opt {
    #[clap(long = "bind", default_value = "127.0.0.1:9000")]
    bind: SocketAddr,
    #[clap(long = "db", default_value = "_db")]
    db: PathBuf,
    #[clap(flatten)]
    indexer: IndexerOpt,
}

#[tokio::main]
async fn main() {
    env_logger::init_from_env(
        env_logger::Env::new()
            .filter("EXPLORER_LOG")
            .write_style("EXPLORER_LOG_STYLE"),
    );

    let opt = Opt::parse();

    let openings: &'static Openings = Box::leak(Box::new(Openings::build_table()));
    let db = Arc::new(Database::open(opt.db).expect("db"));
    let (indexer, join_handle) = IndexerStub::spawn(db.clone(), opt.indexer);

    let app = Router::new()
        .route("/admin/:prop", get(db_property))
        .route("/admin/game/:prop", get(game_property))
        .route("/admin/personal/:prop", get(personal_property))
        .route("/personal", get(personal))
        .route("/test", get(test))
        .layer(AddExtensionLayer::new(openings))
        .layer(AddExtensionLayer::new(db))
        .layer(AddExtensionLayer::new(indexer));

    axum::Server::bind(&opt.bind)
        .serve(app.into_make_service())
        .with_graceful_shutdown(async {
            tokio::signal::ctrl_c().await.expect("wait for ctrl-c");
        })
        .await
        .expect("bind");

    join_handle.await.expect("indexer");
}

async fn test() -> NdJson<impl futures_util::stream::Stream<Item = u32>> {
    NdJson::new(futures_util::stream::unfold(0, |state| async move {
        tokio::time::sleep(std::time::Duration::from_secs(2)).await;
        Some((state, state + 1))
    }))
}

async fn db_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .db_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn game_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .game_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn personal_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .personal_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

struct PersonalStreamState {
    indexing: Option<oneshot::Receiver<()>>,
    key: PersonalKeyPrefix,
    db: Arc<Database>,
    filter: PersonalQueryFilter,
    pos: VariantPosition,
    opening: Option<&'static Opening>,
    first: bool,
    done: bool,
}

async fn personal(
    Extension(openings): Extension<&'static Openings>,
    Extension(db): Extension<Arc<Database>>,
    Extension(indexer): Extension<IndexerStub>,
    Query(query): Query<PersonalQuery>,
) -> Result<NdJson<impl Stream<Item = PersonalResponse>>, Error> {
    let indexing = if query.update {
        Some(indexer.index_player(query.player.clone()).await)
    } else {
        None
    };

    let variant = query.variant.into();

    let mut pos = Zobrist::new(match query.fen {
        Some(fen) => VariantPosition::from_setup(variant, &Fen::from(fen), CastlingMode::Chess960)?,
        None => VariantPosition::new(variant),
    });

    let opening = openings.classify_and_play(&mut pos, query.play)?;

    let key = PersonalKeyBuilder::with_user_pov(&query.player.into(), query.color)
        .with_zobrist(variant, pos.zobrist_hash());

    let state = PersonalStreamState {
        filter: query.filter,
        db,
        indexing,
        opening,
        key,
        pos: pos.into_inner(),
        first: true,
        done: false,
    };

    Ok(NdJson::new(futures_util::stream::unfold(
        state,
        |mut state| async move {
            let first = mem::replace(&mut state.first, false);
            let done = if state.done {
                true
            } else {
                state.done = match state.indexing {
                    Some(ref mut indexing) => {
                        if !first {
                            tokio::time::sleep(Duration::from_secs(5)).await;
                        }
                        indexing.try_recv().is_ok()
                    }
                    None => true,
                };
                false
            };

            if done {
                None
            } else {
                let queryable = state.db.queryable();
                let filtered = queryable
                    .get_personal(&state.key, AnnoLichess::from_year(state.filter.since))
                    .expect("get personal")
                    .prepare(&state.pos, &state.filter);

                Some((
                    PersonalResponse {
                        total: filtered.total,
                        moves: filtered
                            .moves
                            .into_iter()
                            .map(|row| PersonalMoveRow {
                                uci: row.uci,
                                san: row.san,
                                stats: row.stats,
                                game: row.game.and_then(|id| {
                                    queryable
                                        .get_game_info(id)
                                        .expect("get game")
                                        .map(|info| GameRow { id, info })
                                }),
                            })
                            .collect(),
                        recent_games: filtered
                            .recent_games
                            .into_iter()
                            .flat_map(|(uci, id)| {
                                queryable.get_game_info(id).expect("get game").map(|info| {
                                    GameRowWithUci {
                                        uci,
                                        row: GameRow { id, info },
                                    }
                                })
                            })
                            .collect(),
                        opening: state.opening,
                    },
                    state,
                ))
            }
        },
    )))
}
<commit_msg>simplify streaming state transitions<commit_after>pub mod api;
pub mod db;
pub mod indexer;
pub mod model;
pub mod opening;
pub mod util;

use crate::{
    api::{
        Error, GameRow, GameRowWithUci, PersonalMoveRow, PersonalQuery, PersonalQueryFilter,
        PersonalResponse,
    },
    db::Database,
    indexer::{IndexerOpt, IndexerStub},
    model::{AnnoLichess, PersonalKeyBuilder, PersonalKeyPrefix},
    opening::{Opening, Openings},
    util::NdJson,
};
use axum::{
    extract::{Extension, Path, Query},
    handler::get,
    http::StatusCode,
    AddExtensionLayer, Router,
};
use clap::Clap;
use futures_util::stream::Stream;
use shakmaty::{fen::Fen, variant::VariantPosition, zobrist::Zobrist, CastlingMode};
use std::{mem, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
use tokio::sync::oneshot;

#[derive(Clap)]
struct Opt {
    #[clap(long = "bind", default_value = "127.0.0.1:9000")]
    bind: SocketAddr,
    #[clap(long = "db", default_value = "_db")]
    db: PathBuf,
    #[clap(flatten)]
    indexer: IndexerOpt,
}

#[tokio::main]
async fn main() {
    env_logger::init_from_env(
        env_logger::Env::new()
            .filter("EXPLORER_LOG")
            .write_style("EXPLORER_LOG_STYLE"),
    );

    let opt = Opt::parse();

    let openings: &'static Openings = Box::leak(Box::new(Openings::build_table()));
    let db = Arc::new(Database::open(opt.db).expect("db"));
    let (indexer, join_handle) = IndexerStub::spawn(db.clone(), opt.indexer);

    let app = Router::new()
        .route("/admin/:prop", get(db_property))
        .route("/admin/game/:prop", get(game_property))
        .route("/admin/personal/:prop", get(personal_property))
        .route("/personal", get(personal))
        .route("/test", get(test))
        .layer(AddExtensionLayer::new(openings))
        .layer(AddExtensionLayer::new(db))
        .layer(AddExtensionLayer::new(indexer));

    axum::Server::bind(&opt.bind)
        .serve(app.into_make_service())
        .with_graceful_shutdown(async {
            tokio::signal::ctrl_c().await.expect("wait for ctrl-c");
        })
        .await
        .expect("bind");

    join_handle.await.expect("indexer");
}

async fn test() -> NdJson<impl futures_util::stream::Stream<Item = u32>> {
    NdJson::new(futures_util::stream::unfold(0, |state| async move {
        tokio::time::sleep(std::time::Duration::from_secs(2)).await;
        Some((state, state + 1))
    }))
}

async fn db_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .db_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn game_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .game_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn personal_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .personal_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

struct PersonalStreamState {
    indexing: Option<oneshot::Receiver<()>>,
    key: PersonalKeyPrefix,
    db: Arc<Database>,
    filter: PersonalQueryFilter,
    pos: VariantPosition,
    opening: Option<&'static Opening>,
    first: bool,
    done: bool,
}

async fn personal(
    Extension(openings): Extension<&'static Openings>,
    Extension(db): Extension<Arc<Database>>,
    Extension(indexer): Extension<IndexerStub>,
    Query(query): Query<PersonalQuery>,
) -> Result<NdJson<impl Stream<Item = PersonalResponse>>, Error> {
    let indexing = if query.update {
        Some(indexer.index_player(query.player.clone()).await)
    } else {
        None
    };

    let variant = query.variant.into();

    let mut pos = Zobrist::new(match query.fen {
        Some(fen) => VariantPosition::from_setup(variant, &Fen::from(fen), CastlingMode::Chess960)?,
        None => VariantPosition::new(variant),
    });

    let opening = openings.classify_and_play(&mut pos, query.play)?;

    let key = PersonalKeyBuilder::with_user_pov(&query.player.into(), query.color)
        .with_zobrist(variant, pos.zobrist_hash());

    let state = PersonalStreamState {
        filter: query.filter,
        db,
        indexing,
        opening,
        key,
        pos: pos.into_inner(),
        first: true,
        done: false,
    };

    Ok(NdJson::new(futures_util::stream::unfold(
        state,
        |mut state| async move {
            if state.done {
                return None;
            }

            let first = mem::replace(&mut state.first, false);
            state.done = match state.indexing {
                Some(ref mut indexing) => {
                    tokio::select! {
                        _ = indexing => true,
                        _ = tokio::time::sleep(if first { Duration::from_millis(200) } else { Duration::from_secs(5) } ) => false,
                    }
                }
                None => true,
            };
            let queryable = state.db.queryable();
            let filtered = queryable
                .get_personal(&state.key, AnnoLichess::from_year(state.filter.since))
                .expect("get personal")
                .prepare(&state.pos, &state.filter);

            Some((
                PersonalResponse {
                    total: filtered.total,
                    moves: filtered
                        .moves
                        .into_iter()
                        .map(|row| PersonalMoveRow {
                            uci: row.uci,
                            san: row.san,
                            stats: row.stats,
                            game: row.game.and_then(|id| {
                                queryable
                                    .get_game_info(id)
                                    .expect("get game")
                                    .map(|info| GameRow { id, info })
                            }),
                        })
                        .collect(),
                    recent_games: filtered
                        .recent_games
                        .into_iter()
                        .flat_map(|(uci, id)| {
                            queryable.get_game_info(id).expect("get game").map(|info| {
                                GameRowWithUci {
                                    uci,
                                    row: GameRow { id, info },
                                }
                            })
                        })
                        .collect(),
                    opening: state.opening,
                },
                state,
            ))
        },
    )))
}
<|endoftext|>


<commit_before>//! [한국 러스트 사용자 그룹 홈페이지][rust-kr] 소스코드
//! --------
//!
//! ### 사용법
//! ```bash
//! git clone https://github.com/rust-kr/rust-kr.org.wiki.git docs
//! cargo run
//! # 웹 브라우저에서 http://localhost:8000 를 열어보세요
//! ```
//!
//! [rust-kr]: http://rust-kr.org

#[macro_use(itry)] extern crate iron;
#[macro_use(router)] extern crate router;
extern crate mount;
extern crate staticfile;
extern crate handlebars_iron as hbs;
extern crate pulldown_cmark as cmark;

use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status;
use iron::middleware::AfterMiddleware;
use mount::Mount;
use staticfile::Static;
use hbs::{Template, HandlebarsEngine, DirectorySource};

//
// Configs
//
/// 서버가 소켓을 열 주소
const ADDR: &'static str = "localhost:8000";
/// 마크다운 문서가 담긴 주소
const DOCS_DIR: &'static str = "docs";

/// Entry point
fn main() {
    // Declarative definition of request handling
    let app = Iron::new({
        let mut c = Chain::new({
            // '/static/*'          -> static file serving
            // '/'                  -> Main page
            // '/pages/:name'       -> Specific documents
            // '/pages/_pages'      -> See all documents

            let mut m = Mount::new();
            m.mount("/static/", Static::new("static/"));
            m.mount("/", router! {
                get "/" => index,
                get "/pages/:name" => page,
                get "/pages/_pages" => all_docs,
            });
            m
        });
        c.link_after({
            // Handlebar templating
            let mut hbr = HandlebarsEngine::new();
            hbr.add(Box::new(DirectorySource::new("templates", ".hbs")));
            if let Err(r) = hbr.reload() {
                use std::error::Error;
                panic!("{}", r.description());
            }
            hbr
        });
        c.link_after({
            // 404 page handler
            struct Sink;
            impl AfterMiddleware for Sink {
                fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
                    if err.response.body.is_some() { return Err(err); }
                    if err.response.status != Some(status::NotFound) { return Err(err); }

                    Err(IronError {
                        response: Response {
                            body: Some(Box::new("Not found")),
                            .. err.response
                        },
                        .. err
                    })
                }
            }
            Sink { }
        });
        c
    });

    println!("\nServer running at \x1b[33mhttp://{}\x1b[0m\n", ADDR);
    app.http(ADDR).unwrap();
}

/// Root page handler
fn index(_: &mut Request) -> IronResult<Response> {
    read_docs("Home")
}

/// Wiki page handler
fn page(req: &mut Request) -> IronResult<Response> {
    use router::Router;

    // Parse URL
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap_or("Home");
    read_docs(name)
}

/// "All documents" page handler
fn all_docs(_: &mut Request) -> IronResult<Response> {
    use std::fs::read_dir;

    let mut paths: Vec<_> = itry!(read_dir(DOCS_DIR))
        .filter_map(|f| f.ok())
        .map(|f| f.path())
        .filter(|p| p.is_file())
        .filter(|p| p.as_os_str().to_str()
            .map(|s| s.ends_with(".md"))
            .unwrap_or(false))
        .collect();
    paths.sort();

    let pages = paths.iter()
        .filter_map(|p| p.file_stem())
        .filter_map(|stem| stem.to_str());

    // TODO: 러스트로 이짓하지 말고 Handlebar로 대체
    let mut html = "
".to_string();
    for page in pages {
        use std::fmt::Write;
        write!(&mut html, r#"
{0}
"#, page).unwrap();
    }
    html.push_str("
");

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}

/// `name`을 인자로 받아, `docs/<name>.md` 파일을 렌더링하여 `IronResult<Response>`로 반환합니다.
fn read_docs(name: &str) -> IronResult<Response> {
    use std::fs::File;
    use std::io::Read;
    use cmark::Parser;
    use cmark::html::push_html;

    // Read file
    let path = format!("{}/{}.md", DOCS_DIR, name);
    let mut file = itry!(File::open(&path));
    let mut md = String::new();
    itry!(file.read_to_string(&mut md));

    // Parse markdown
    let parser = Parser::new(&md);
    let mut html = String::new();
    push_html(&mut html, parser);

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}
<commit_msg>에러헨들러 코드 보기쉽도록 수정<commit_after>//! [한국 러스트 사용자 그룹 홈페이지][rust-kr] 소스코드
//! --------
//!
//! ### 사용법
//! ```bash
//! git clone https://github.com/rust-kr/rust-kr.org.wiki.git docs
//! cargo run
//! # 웹 브라우저에서 http://localhost:8000 를 열어보세요
//! ```
//!
//! [rust-kr]: http://rust-kr.org

#[macro_use(itry)] extern crate iron;
#[macro_use(router)] extern crate router;
extern crate mount;
extern crate staticfile;
extern crate handlebars_iron as hbs;
extern crate pulldown_cmark as cmark;

use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status;
use iron::middleware::AfterMiddleware;
use mount::Mount;
use staticfile::Static;
use hbs::{Template, HandlebarsEngine, DirectorySource};

//
// Configs
//
/// 서버가 소켓을 열 주소
const ADDR: &'static str = "localhost:8000";
/// 마크다운 문서가 담긴 주소
const DOCS_DIR: &'static str = "docs";

/// Entry point
fn main() {
    // Declarative definition of request handling
    let app = Iron::new({
        let mut c = Chain::new({
            // '/static/*'          -> static file serving
            // '/'                  -> Main page
            // '/pages/:name'       -> Specific documents
            // '/pages/_pages'      -> See all documents

            let mut m = Mount::new();
            m.mount("/static/", Static::new("static/"));
            m.mount("/", router! {
                get "/" => index,
                get "/pages/:name" => page,
                get "/pages/_pages" => all_docs,
            });
            m
        });

        // Handlebar templating
        c.link_after({
            let mut hbr = HandlebarsEngine::new();
            hbr.add(Box::new(DirectorySource::new("templates", ".hbs")));
            if let Err(r) = hbr.reload() {
                use std::error::Error;
                panic!("{}", r.description());
            }
            hbr
        });
        // 404 page handler
        c.link_after(catch(|err: IronError| {
            if err.response.body.is_some() { return Err(err); }
            if err.response.status != Some(status::NotFound) { return Err(err); }

            // TODO
            Err(IronError { response: err.response.set("Not found"), ..err })
        }));
        c
    });

    println!("\nServer running at \x1b[33mhttp://{}\x1b[0m\n", ADDR);
    app.http(ADDR).unwrap();
}

/// Root page handler
fn index(_: &mut Request) -> IronResult<Response> {
    read_docs("Home")
}

/// Wiki page handler
fn page(req: &mut Request) -> IronResult<Response> {
    use router::Router;

    // Parse URL
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap_or("Home");
    read_docs(name)
}

/// "All documents" page handler
fn all_docs(_: &mut Request) -> IronResult<Response> {
    use std::fs::read_dir;

    let mut paths: Vec<_> = itry!(read_dir(DOCS_DIR))
        .filter_map(|f| f.ok())
        .map(|f| f.path())
        .filter(|p| p.is_file())
        .filter(|p| p.as_os_str().to_str()
            .map(|s| s.ends_with(".md"))
            .unwrap_or(false))
        .collect();
    paths.sort();

    let pages = paths.iter()
        .filter_map(|p| p.file_stem())
        .filter_map(|stem| stem.to_str());

    // TODO: 러스트로 이짓하지 말고 Handlebar로 대체
    let mut html = "
".to_string();
    for page in pages {
        use std::fmt::Write;
        write!(&mut html, r#"
{0}
"#, page).unwrap();
    }
    html.push_str("
");

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}

/// `name`을 인자로 받아, `docs/<name>.md` 파일을 렌더링하여 `IronResult<Response>`로 반환합니다.
fn read_docs(name: &str) -> IronResult<Response> {
    use std::fs::File;
    use std::io::Read;
    use cmark::Parser;
    use cmark::html::push_html;

    // Read file
    let path = format!("{}/{}.md", DOCS_DIR, name);
    let mut file = itry!(File::open(&path));
    let mut md = String::new();
    itry!(file.read_to_string(&mut md));

    // Parse markdown
    let parser = Parser::new(&md);
    let mut html = String::new();
    push_html(&mut html, parser);

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}

/// Helper struct for handle 404 page of rust-kr
struct RustkrHandler<F> { handler: F }
/// Helper function for handle 404 page of rust-kr
fn catch<F>(handler: F) -> RustkrHandler<F> { RustkrHandler { handler: handler } }
impl<F> AfterMiddleware for RustkrHandler<F>
    where F: Send + Sync + 'static + Fn(IronError) -> IronResult<Response> {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        (self.handler)(err)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

pub static YABS: Prog = Prog {
    name: "yabs",
    vers: "0.1.0",
    yr: "2016",
};

extern crate pgetopts;
extern crate util;
extern crate rpf;

use pgetopts::Options;
use rpf::*;

use std::env;
use util::*;
use util::build::Desc;

fn print_usage(opts: Options) {
    print!("{0}: {1} {2} {3}\n   or: {1} {2}\nRun yabs with {2} on {3}",
           "Usage".bold(),
           YABS.name,
           "[OPTION]".underline(),
           "PROFILE".underline());
    print!("{}\n", opts.options());
    print!("{}\n\
           \tyabs -m linux\tGenerates a Makefile for the build profile 'linux'\n\
           \tyabs -p\t\tPrints all build profiles\n",
           "Examples:".bold());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "Print help information");
    opts.optopt("m", "make", "Generate Makefile", "PROFILE");
    opts.optflag("p", "print", "Print build file in JSON");
    opts.optopt("b", "build", "Build profile", "");
    opts.optopt("",
                "print-profile",
                "Print a particular profile from build file in JSON",
                "PROFILE");
    opts.optflag("", "profiles", "Print all available profiles in build file");
    opts.optflag("", "sources", "Print source files");
    opts.optflag("", "version", "Print version information");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            YABS.error(e.to_string(), ExitStatus::OptError);
            panic!();
        }
    };

    if matches.opt_present("h") {
        print_usage(opts);
    } else if matches.opt_present("version") {
        YABS.copyright("Copyright (C) 2015-2016\n",
                       &["Alberto Corona"]);
    } else {
        if let Some(assumed_file_name) = ext::get_assumed_filename() {
            match build::BuildFile::from_file(&assumed_file_name) {
                Ok(build_file) => {
                    if matches.opt_present("p") {
                        &build_file.print_as_json();
                    } else if matches.opt_present("print-profile") {
                        if let Some(arg) = matches.opt_str("print-profile") {
                            &build_file.print_profile_as_json(arg);
                        }
                    } else if matches.opt_present("profiles") {
                        &build_file.print_available_profiles();
                    } else if matches.opt_present("sources") {
                        &build_file.clone().print_sources();
                    } else if matches.opt_present("make") {
                        if let Some(arg) = matches.opt_str("make") {
                            if let Err(e) = build_file.gen_make(arg) {
                                YABS.error(e.to_string(), ExitStatus::Error);
                            }
                        }
                    } else if matches.opt_present("build") {
                        if let Some(arg) = matches.opt_str("build") {
                            if let Err(e) = build_file.build(arg, 1) {
                                YABS.error(e.to_string(), ExitStatus::Error);
                            }
                        }
                    }
                }
                Err(e) => {
                    for err in e {
                        println!("{} {}", "yabs:".paint(Color::Red), err.to_string().paint(Color::Red));
                    }
                    YABS.exit(ExitStatus::Error);
                }
            };
        }
    }
}
<commit_msg>yabs: add ability to use specific toml file<commit_after>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

pub static YABS: Prog = Prog {
    name: "yabs",
    vers: "0.1.0",
    yr: "2016",
};

extern crate pgetopts;
extern crate util;
extern crate rpf;

use pgetopts::Options;
use rpf::*;

use std::env;
use util::*;
use util::build::Desc;

fn print_usage(opts: Options) {
    print!("{0}: {1} {2} {3}\n   or: {1} {2}\nRun yabs with {2} on {3}",
           "Usage".bold(),
           YABS.name,
           "[OPTION]".underline(),
           "PROFILE".underline());
    print!("{}\n", opts.options());
    print!("{}\n\
           \tyabs -m linux\tGenerates a Makefile for the build profile 'linux'\n\
           \tyabs -p\t\tPrints all build profiles\n",
           "Examples:".bold());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optopt("f", "file", "Use a specified TOML file", "FILE");
    opts.optflag("h", "help", "Print help information");
    opts.optopt("m", "make", "Generate Makefile", "PROFILE");
    opts.optflag("p", "print", "Print build file in JSON");
    opts.optopt("b", "build", "Build profile", "");
    opts.optopt("",
                "print-profile",
                "Print a particular profile from build file in JSON",
                "PROFILE");
    opts.optflag("", "profiles", "Print all available profiles in build file");
    opts.optflag("", "sources", "Print source files");
    opts.optflag("", "version", "Print version information");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            YABS.error(e.to_string(), ExitStatus::OptError);
            panic!();
        }
    };

    if matches.opt_present("h") {
        print_usage(opts);
    } else if matches.opt_present("version") {
        YABS.copyright("Copyright (C) 2015-2016\n",
                       &["Alberto Corona"]);
    } else {
        if let Some(mut assumed_file_name) = ext::get_assumed_filename() {
            if matches.opt_present("file") {
                if let Some(arg) = matches.opt_str("file") {
                    assumed_file_name = arg;
                }
            }
            match build::BuildFile::from_file(&assumed_file_name) {
                Ok(build_file) => {
                    if matches.opt_present("p") {
                        &build_file.print_as_json();
                    } else if matches.opt_present("print-profile") {
                        if let Some(arg) = matches.opt_str("print-profile") {
                            &build_file.print_profile_as_json(arg);
                        }
                    } else if matches.opt_present("profiles") {
                        &build_file.print_available_profiles();
                    } else if matches.opt_present("sources") {
                        &build_file.clone().print_sources();
                    } else if matches.opt_present("make") {
                        if let Some(arg) = matches.opt_str("make") {
                            if let Err(e) = build_file.gen_make(arg) {
                                YABS.error(e.to_string(), ExitStatus::Error);
                            }
                        }
                    } else if matches.opt_present("build") {
                        if let Some(arg) = matches.opt_str("build") {
                            if let Err(e) = build_file.build(arg, 1) {
                                YABS.error(e.to_string(), ExitStatus::Error);
                            }
                        }
                    }
                }
                Err(e) => {
                    for err in e {
                        println!("{} {}", "yabs:".paint(Color::Red), err.to_string().paint(Color::Red));
                    }
                    YABS.exit(ExitStatus::Error);
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stdout_isatty, stderr_isatty};

#[cfg(unix)]
extern crate tempdir;
#[cfg(unix)]
use tempdir::TempDir;

fn main() {
    let result = cargo_expand();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    match env::args_os().last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let outdir = match which_rustfmt {
        Some(_) => Some(TempDir::new("cargo-expand").expect("failed to create tmp file")),
        None => None,
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(env::args_os(), outfile.as_ref()));

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_cargo = Vec::new();
            filter_cargo.extend(args.iter().map(OsString::as_os_str));
            filter_cargo.push(OsStr::new("--filter-cargo"));

            let _wait = try!(cmd.pipe_to(shell!("cat"), Some(&filter_cargo)));
            try!(run(cmd));
            drop(_wait);

            cmd = Command::new("sed");
            cmd.arg("s/$crate/XCRATE/g");
            cmd.arg(outfile.unwrap());

            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                // Work around $crate issue https://github.com/rust-lang/rust/issues/38016
                try!(cmd.pipe_to(shell!(fmt), None)),
                try!(cmd.pipe_to(shell!("sed" "s/XCRATE/$crate/g"), Some(&filter_rustfmt))),
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = if stdout_isatty() {
        match which(&["pygmentize", "-l", "rust"]) {
            Some(pyg) => Some(try!(cmd.pipe_to(shell!(pyg "-l" "rust"), None))),
            None => None,
        }
    } else {
        None
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = try!(self.spawn());

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => {
                Ok(Wait(vec![child]))
            }
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = try!(errcmd.spawn());
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
    where I: IntoIterator<Item=OsString>
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stdout_isatty() && stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        None
    } else {
        match env::var_os(&cmd[0].to_uppercase()) {
            Some(which) => {
                if which.is_empty() {
                    None
                } else {
                    Some(which)
                }
            }
            None => {
                let in_path = Command::new(cmd[0])
                    .args(&cmd[1..])
                    .stdin(Stdio::null())
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .spawn()
                    .is_ok();
                if in_path {
                    Some(cmd[0].into())
                } else {
                    None
                }
            }
        }
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(line: &str) -> bool {
    line.trim().is_empty()
        || line.trim_right().ends_with("line exceeded maximum length (sorry)")
        || line.trim_right().ends_with("left behind trailing whitespace (sorry)")
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    line.trim().is_empty()
        || line.contains("ignoring specified output filename because multiple outputs were requested")
        || line.contains("ignoring --out-dir flag due to -o flag.")
}
<commit_msg>Also use tmp file if pygmentize but no rustfmt<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stdout_isatty, stderr_isatty};

#[cfg(unix)]
extern crate tempdir;
#[cfg(unix)]
use tempdir::TempDir;

fn main() {
    let result = cargo_expand();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();
    match args.last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        Some(TempDir::new("cargo-expand").expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));

    // Pipe to a tmp file to separate out any println output from build scripts
    if let Some(outfile) = outfile {
        let mut filter_cargo = Vec::new();
        filter_cargo.extend(args.iter().map(OsString::as_os_str));
        filter_cargo.push(OsStr::new("--filter-cargo"));

        let _wait = try!(cmd.pipe_to(shell!("cat"), Some(&filter_cargo)));
        try!(run(cmd));
        drop(_wait);

        cmd = Command::new("cat");
        cmd.arg(outfile);
    }

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                // Work around $crate issue https://github.com/rust-lang/rust/issues/38016
                try!(cmd.pipe_to(shell!("sed" "s/$crate/XCRATE/g"), None)),
                try!(cmd.pipe_to(shell!(fmt), None)),
                try!(cmd.pipe_to(shell!("sed" "s/XCRATE/$crate/g"), Some(&filter_rustfmt))),
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = match which_pygmentize {
        Some(pyg) => Some(try!(cmd.pipe_to(shell!(pyg "-l" "rust"), None))),
        None => None,
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = try!(self.spawn());

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => {
                Ok(Wait(vec![child]))
            }
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = try!(errcmd.spawn());
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
    where I: IntoIterator<Item=OsString>
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stdout_isatty() && stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        None
    } else {
        match env::var_os(&cmd[0].to_uppercase()) {
            Some(which) => {
                if which.is_empty() {
                    None
                } else {
                    Some(which)
                }
            }
            None => {
                let in_path = Command::new(cmd[0])
                    .args(&cmd[1..])
                    .stdin(Stdio::null())
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .spawn()
                    .is_ok();
                if in_path {
                    Some(cmd[0].into())
                } else {
                    None
                }
            }
        }
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(line: &str) -> bool {
    line.trim().is_empty()
        || line.trim_right().ends_with("line exceeded maximum length (sorry)")
        || line.trim_right().ends_with("left behind trailing whitespace (sorry)")
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    line.trim().is_empty()
        || line.contains("ignoring specified output filename because multiple outputs were requested")
        || line.contains("ignoring --out-dir flag due to -o flag.")
}
<|endoftext|>


<commit_before>// Copyright 2015 Corey Farwell
//
// 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.

/* TODO:
 *  * redirect root url
 *  * add watermark? url to repo?
 *  * specify root node
 *  * specify node labels
 */

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = String::new();
    dot.push_str("digraph graphname {");
    dot.push_str("ratio=0.75;");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.push_str(&format!("{} -> {};", crate_name.replace("-", "_"), crate_dep.replace("-", "_")));
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.push_str("}");

    let child = Command::new("dot").arg("-Tpng").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn().unwrap();
    child.stdin.unwrap().write_all(dot.as_bytes()).unwrap();

    let mut ret = vec![];
    child.stdout.unwrap().read_to_end(&mut ret).unwrap();
    ret
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.get_url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                let cache_control_header = "cache-control: no-cache".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
                                         .with_header(cache_control_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<commit_msg>Add a couple more TODOs<commit_after>// Copyright 2015 Corey Farwell
//
// 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.

/* TODO:
 *  * redirect root url
 *  * add watermark? url to repo?
 *  * specify root node
 *  * specify node labels
 *  * update git repo?
 *  * serverside caching? redis?
 */

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = String::new();
    dot.push_str("digraph graphname {");
    dot.push_str("ratio=0.75;");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.push_str(&format!("{} -> {};", crate_name.replace("-", "_"), crate_dep.replace("-", "_")));
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.push_str("}");

    let child = Command::new("dot").arg("-Tpng").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn().unwrap();
    child.stdin.unwrap().write_all(dot.as_bytes()).unwrap();

    let mut ret = vec![];
    child.stdout.unwrap().read_to_end(&mut ret).unwrap();
    ret
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.get_url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                let cache_control_header = "cache-control: no-cache".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
                                         .with_header(cache_control_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufReader;
use std::cmp;
use std::str::FromStr;

extern crate modfile;
use modfile::ptmf;

extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
modtool.

Usage:
    modtool (-h | --help)
    modtool (-V | --version)
    modtool show [--summary] [--sample-info] [--sample-stats] [--pattern-info] <file>...
    modtool save (--number=<number> | --all) <fileprefix> <file>
    modtool remove [--unused-patterns] [--unused-samples] <fileprefix> <file>...

Options:
    -V, --version         Show version info.
    -h, --help            Show this text.

    show                  Show various info and statistics.
      --summary           Show summary info.
      --sample-info       Show info about samples.
      --sample-stats      Show sample statistics.
      --pattern-info      Show info about patterns.
      <file>              File(s) to process.

    save                  Save samples, RAW 8-bit signed.
      --all               Save all samples.
      --number=<number>   Save only sample <number>.
      <fileprefix>        Use <fileprefix> as prefix to filenames when saving.
      <file>              File to process.

    remove                Remove unused/samples and or patterns.
      --unused-patterns   Remove unused patterns.
      --unused-samples    Remove unused samples.
      <fileprefix>        Use <fileprefix> as prefix to filenames when saving.
      <file>              File(s) to process.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: Vec<String>,
    flag_help: bool,
	flag_version: bool,

	cmd_show: bool,
	flag_summary: bool,
    flag_sample_info: bool,
	flag_sample_stats: bool,
	flag_pattern_info: bool,

	cmd_save: bool,
	flag_all: bool,
	flag_number: String,
	arg_fileprefix: String,

	cmd_remove: bool,
	flag_unused_patterns: bool,
	flag_unused_samples: bool,
}

#[derive(Debug)]
struct Stats {
	pub min: u32,
	pub max: u32,
	pub sum: usize,
	pub avg: usize,
	pub num_values: u32
}

impl Stats {
	pub fn new() -> Stats {
		Stats{min: u32::max_value(), max: u32::min_value(), sum: 0, avg: 0, num_values: 0}
	}

	pub fn update(&mut self, val: u32) {
		self.min = cmp::min(self.min, val);
		self.max = cmp::max(self.max, val);
		self.sum += val as usize;

		self.num_values += 1;
	}

	pub fn done(&mut self) {
		self.avg = self.sum / (self.num_values as usize);
	}
}

fn show_summary(module: &ptmf::PTModule) {
	println!("Song summary");
	println!("\tSongname: {}", module.name);
	println!("\tLength: {}", module.length);
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);
	println!("\tNumber of samples with length > 0: {}", used_samples.count());
	println!("\tNumber of patterns: {}", module.patterns.len());
	println!("");
}

fn show_sample_info(module: &ptmf::PTModule) {
	let mut number = 1;
	for sample in module.sample_info.iter() {
		println!("Sample number {} details", number);
		println!("\tName: {}", sample.name);
		println!("\tLength: {}b", sample.length * 2);
		println!("\tFinetune: {}", sample.finetune);
		println!("\tVolume: {}", sample.volume);
		println!("\tRepeat start: {}b", sample.repeat_start * 2);
		println!("\tRepeat length: {}b", sample.repeat_length * 2);
		number += 1;
	}
	println!("");
}

fn show_sample_stats(module: &ptmf::PTModule) {
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);

	let mut len = Stats::new();
	let mut finetune = Stats::new();
	let mut volume = Stats::new();
	let mut repeat_start = Stats::new();
	let mut repeat_length = Stats::new();

	for sample in used_samples {
		let slen = sample.length as u32 * 2;
		let sfinetune = sample.finetune as u32;
		let svolume = sample.volume as u32;
		let srepeat_start = sample.repeat_start as u32 * 2;
		let srepeat_length = sample.repeat_length as u32 * 2;

		len.update(slen);
		finetune.update(sfinetune);
		volume.update(svolume);
		repeat_start.update(srepeat_start);
		repeat_length.update(srepeat_length);
	}

	len.done();
	finetune.done();
	volume.done();
	repeat_start.done();
	repeat_length.done();

	println!("Sample statistics");
	println!("\tLength min: {} max: {} avg: {}", len.min, len.max, len.avg);
	println!("\tFinetune min: {} max: {} avg: {}", finetune.min, finetune.max, finetune.avg);
	println!("\tVolume min: {} max: {} avg: {}", volume.min, volume.max, volume.avg);
	println!("\tRepeat start min: {} max: {} avg: {}", repeat_start.min, repeat_start.max, repeat_start.avg);
	println!("\tRepeat length min: {} max: {} avg: {}", repeat_length.min, repeat_length.max, repeat_length.avg);
	println!("");
}

fn find_unused_patterns(module: &ptmf::PTModule) -> Vec<u8> {
	let mut unused:Vec<u8> = Vec::new();
	let positions = &module.positions.data[0..module.length as usize];
	let num_patterns = module.patterns.len();
	for i in 0..num_patterns as u8 {
		if !positions.contains(&i) {
			unused.push(i);
		}
	}

	unused
}

fn show_pattern_info(module: &ptmf::PTModule) {

	println!("Pattern info");
	print!("\tPattern play order: ");
	let positions = &module.positions.data[0..module.length as usize];
	for pos in positions.iter() {
		print!("{} ",pos);
	}
	println!("");

	print!("\tUnused patterns: ");
	let unused = find_unused_patterns(module);
	for i in unused {
		print!("{} ",i);
	}
	println!("");

	print!("\tEmpty patterns: ");
	for i in 0..module.patterns.len() {
		let mut empty = true;
		for row in &module.patterns[i].rows {
			for channel in &row.channels {
				if channel.period != 0 ||
					channel.sample_number != 0 ||
					channel.effect != 0 {
					empty = false;
				}
				if !empty {
					break;
				}
			}
			if !empty {
				break;
			}
		}
		if empty {
			print!("{} ",i);
		}
	}
	println!("");
}

fn save_samples(module: &ptmf::PTModule,range: &Vec<usize>,prefix: &String) {
	for i in range {
		let filename = format!("{}_{}.raw",prefix,i+1);

		let file = match File::create(&filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		let mut writer = BufWriter::new(&file);
		match writer.write_all(&module.sample_data[*i]) {
			Ok(_) => (),
			Err(e) => {
				println!("Failed to write sample {}. Error: '{:?}'", i, e);
			}
		}
	}
}

fn remove_unused_patterns(module: &mut ptmf::PTModule) {
	let mut unused = find_unused_patterns(module);
	unused.reverse();

	// Remove highest pattern first
	for i in unused {
		// Remove pattern
		module.patterns.remove(i as usize);

		// Adjust play positions
		for j in 0..module.length {
			let j = j as usize;
			if module.positions.data[j] > i {
				module.positions.data[j] -= 1;
			}
		}
	}
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
//    println!("{:?}", args);

	if args.flag_version {
		println!("Version: {}", VERSION);
		return;
	}

	if args.flag_number.len() > 0 {
		let number = usize::from_str(&args.flag_number).unwrap();
		if number < 1 || number > 31 {
			println!("Invalid sample number '{}'", number);
			return;
		}
	}

	if args.cmd_show {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_summary {
				show_summary(&module);
			}

			if args.flag_sample_info {
				show_sample_info(&module);
			}

			if args.flag_sample_stats {
				show_sample_stats(&module);
			}

			if args.flag_pattern_info {
				show_pattern_info(&module);
			}
		}
	} else if args.cmd_save {
		let ref filename = args.arg_file[0];
		let file = match File::open(filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{}'", filename, e);
				return
			}
		};

		let mut reader = BufReader::new(&file);
		let module = match ptmf::read_mod(&mut reader) {
			Ok(module) => module,
			Err(e) => {
				println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		println!("Processing: {}", filename);

		let range = if args.flag_all {
			0..module.sample_data.len()
		} else {
			let number = usize::from_str(&args.flag_number).unwrap() - 1;
			if number >= module.sample_data.len() {
				println!("Invalid sample number. Only {} samples available.", module.sample_data.len());
				return
			}
			number..number+1
		};

		save_samples(&module,&(range.collect()),&args.arg_fileprefix);
	} else if args.cmd_remove {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let mut module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_unused_patterns {
				remove_unused_patterns(&mut module);
			}

			if args.flag_unused_samples {
//				remove_unused_samples(&mut module);
			}

			let filename = format!("{}_{}",args.arg_fileprefix,filename);

			let file = match File::create(&filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
					return
				}
			};

			let mut writer = BufWriter::new(&file);
			match ptmf::write_mod(&mut writer,&mut module) {
				Ok(_) => (),
				Err(e) => {
					println!("Failed to write module {}. Error: '{:?}'", filename, e);
				}
			}
		}
	}

	println!("Done!");
}
<commit_msg>Remove unused samples<commit_after>use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufReader;
use std::cmp;
use std::str::FromStr;

extern crate modfile;
use modfile::ptmf;

extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

// TODO Refactor this to several files
// TODO Move some of the functions to the modfile crate

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
modtool.

Usage:
    modtool (-h | --help)
    modtool (-V | --version)
    modtool show [--summary] [--sample-info] [--sample-stats] [--pattern-info] <file>...
    modtool save (--number=<number> | --all) <fileprefix> <file>
    modtool remove [--unused-patterns] [--unused-samples] <fileprefix> <file>...

Options:
    -V, --version         Show version info.
    -h, --help            Show this text.

    show                  Show various info and statistics.
      --summary           Show summary info.
      --sample-info       Show info about samples.
      --sample-stats      Show sample statistics.
      --pattern-info      Show info about patterns.
      <file>              File(s) to process.

    save                  Save samples, RAW 8-bit signed.
      --all               Save all samples.
      --number=<number>   Save only sample <number>.
      <fileprefix>        Use <fileprefix> as prefix to filenames when saving.
      <file>              File to process.

    remove                Remove unused/samples and or patterns.
      --unused-patterns   Remove unused patterns.
      --unused-samples    Remove unused samples.
      <fileprefix>        Use <fileprefix> as prefix to filenames when saving.
      <file>              File(s) to process.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: Vec<String>,
    flag_help: bool,
	flag_version: bool,

	cmd_show: bool,
	flag_summary: bool,
    flag_sample_info: bool,
	flag_sample_stats: bool,
	flag_pattern_info: bool,

	cmd_save: bool,
	flag_all: bool,
	flag_number: String,
	arg_fileprefix: String,

	cmd_remove: bool,
	flag_unused_patterns: bool,
	flag_unused_samples: bool,
}

#[derive(Debug)]
struct Stats {
	pub min: u32,
	pub max: u32,
	pub sum: usize,
	pub avg: usize,
	pub num_values: u32
}

impl Stats {
	pub fn new() -> Stats {
		Stats{min: u32::max_value(), max: u32::min_value(), sum: 0, avg: 0, num_values: 0}
	}

	pub fn update(&mut self, val: u32) {
		self.min = cmp::min(self.min, val);
		self.max = cmp::max(self.max, val);
		self.sum += val as usize;

		self.num_values += 1;
	}

	pub fn done(&mut self) {
		self.avg = self.sum / (self.num_values as usize);
	}
}

fn show_summary(module: &ptmf::PTModule) {
	println!("Song summary");
	println!("\tSongname: {}", module.name);
	println!("\tLength: {}", module.length);
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);
	println!("\tNumber of samples with length > 0: {}", used_samples.count());
	println!("\tNumber of patterns: {}", module.patterns.len());
	println!("");
}

fn show_sample_info(module: &ptmf::PTModule) {
	let mut number = 1;
	for sample in module.sample_info.iter() {
		println!("Sample number {} details", number);
		println!("\tName: {}", sample.name);
		println!("\tLength: {}b", sample.length * 2);
		println!("\tFinetune: {}", sample.finetune);
		println!("\tVolume: {}", sample.volume);
		println!("\tRepeat start: {}b", sample.repeat_start * 2);
		println!("\tRepeat length: {}b", sample.repeat_length * 2);
		number += 1;
	}
	println!("");
}

fn show_sample_stats(module: &ptmf::PTModule) {
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);

	let mut len = Stats::new();
	let mut finetune = Stats::new();
	let mut volume = Stats::new();
	let mut repeat_start = Stats::new();
	let mut repeat_length = Stats::new();

	for sample in used_samples {
		let slen = sample.length as u32 * 2;
		let sfinetune = sample.finetune as u32;
		let svolume = sample.volume as u32;
		let srepeat_start = sample.repeat_start as u32 * 2;
		let srepeat_length = sample.repeat_length as u32 * 2;

		len.update(slen);
		finetune.update(sfinetune);
		volume.update(svolume);
		repeat_start.update(srepeat_start);
		repeat_length.update(srepeat_length);
	}

	len.done();
	finetune.done();
	volume.done();
	repeat_start.done();
	repeat_length.done();

	let unused = find_unused_samples(module);

	println!("Sample statistics");
	println!("\tLength min: {} max: {} avg: {}", len.min, len.max, len.avg);
	println!("\tFinetune min: {} max: {} avg: {}", finetune.min, finetune.max, finetune.avg);
	println!("\tVolume min: {} max: {} avg: {}", volume.min, volume.max, volume.avg);
	println!("\tRepeat start min: {} max: {} avg: {}", repeat_start.min, repeat_start.max, repeat_start.avg);
	println!("\tRepeat length min: {} max: {} avg: {}", repeat_length.min, repeat_length.max, repeat_length.avg);
	print!("\tUnused samples: ");
	for i in unused {
		print!("{} ", i);
	}
	println!("");
	println!("");
}

fn find_unused_patterns(module: &ptmf::PTModule) -> Vec<u8> {
	let mut unused:Vec<u8> = Vec::new();
	let positions = &module.positions.data[0..module.length as usize];
	let num_patterns = module.patterns.len();
	for i in 0..num_patterns as u8 {
		if !positions.contains(&i) {
			unused.push(i);
		}
	}

	unused
}

fn show_pattern_info(module: &ptmf::PTModule) {

	println!("Pattern info");
	print!("\tPattern play order: ");
	let positions = &module.positions.data[0..module.length as usize];
	for pos in positions.iter() {
		print!("{} ",pos);
	}
	println!("");

	print!("\tUnused patterns: ");
	let unused = find_unused_patterns(module);
	for i in unused {
		print!("{} ",i);
	}
	println!("");

	print!("\tEmpty patterns: ");
	for i in 0..module.patterns.len() {
		let mut empty = true;
		for row in &module.patterns[i].rows {
			for channel in &row.channels {
				if channel.period != 0 ||
					channel.sample_number != 0 ||
					channel.effect != 0 {
					empty = false;
				}
				if !empty {
					break;
				}
			}
			if !empty {
				break;
			}
		}
		if empty {
			print!("{} ",i);
		}
	}
	println!("");
}

fn save_samples(module: &ptmf::PTModule,range: &Vec<usize>,prefix: &String) {
	for i in range {
		let filename = format!("{}_{}.raw",prefix,i+1);

		let file = match File::create(&filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		let mut writer = BufWriter::new(&file);
		match writer.write_all(&module.sample_data[*i]) {
			Ok(_) => (),
			Err(e) => {
				println!("Failed to write sample {}. Error: '{:?}'", i, e);
			}
		}
	}
}

fn remove_unused_patterns(module: &mut ptmf::PTModule) {
	let mut unused = find_unused_patterns(module);
	unused.reverse();

	// MUST Remove highest pattern first
	for i in unused {
		// Remove pattern
		module.patterns.remove(i as usize);

		// Adjust play positions
		for j in 0..module.length {
			let j = j as usize;
			if module.positions.data[j] > i {
				module.positions.data[j] -= 1;
			}
		}
	}
}

fn find_unused_samples(module: &ptmf::PTModule) -> Vec<u8> {
	let mut unused:Vec<u8> = Vec::new();
	let mut used = [0u8;32];

	// Find all used samples
	for pattern in &module.patterns {
		for row in &pattern.rows {
			for channel in &row.channels {
				let number = channel.sample_number as usize;
				if number > 0 {
					used[number] = 1;
				}
			}
		}
	}

	// Find all unused samples
	for i in 1..module.sample_info.len()+1 {
		if used[i] == 0 {
			unused.push(i as u8);
		}
	}

	unused
}

fn remove_unused_samples(module: &mut ptmf::PTModule) {
	let mut unused = find_unused_samples(module);
	unused.reverse();

	// MUST remove highest sample first
	for i in unused {
		let index = i as usize - 1;

		// Remove sample info and put it last
		let mut si = module.sample_info.remove(index);

		if si.length > 0 {
			// Remove sample data
			if index < module.sample_data.len() {
				module.sample_data.remove(index);
			}
		}

		si.length = 0;
		si.repeat_start = 0;
		si.repeat_length = 0;
		module.sample_info.push(si);

		// Rewrite instrument references
		// TODO optimize this
		for pattern in &mut module.patterns {
			for row in &mut pattern.rows {
				for channel in &mut row.channels {
					let number = channel.sample_number;
					if number > i {
						channel.sample_number -= 1;
					}
				}
			}
		}
	}
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
//    println!("{:?}", args);

	if args.flag_version {
		println!("Version: {}", VERSION);
		return;
	}

	if args.flag_number.len() > 0 {
		let number = usize::from_str(&args.flag_number).unwrap();
		if number < 1 || number > 31 {
			println!("Invalid sample number '{}'", number);
			return;
		}
	}

	if args.cmd_show {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_summary {
				show_summary(&module);
			}

			if args.flag_sample_info {
				show_sample_info(&module);
			}

			if args.flag_sample_stats {
				show_sample_stats(&module);
			}

			if args.flag_pattern_info {
				show_pattern_info(&module);
			}
		}
	} else if args.cmd_save {
		let ref filename = args.arg_file[0];
		let file = match File::open(filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{}'", filename, e);
				return
			}
		};

		let mut reader = BufReader::new(&file);
		let module = match ptmf::read_mod(&mut reader) {
			Ok(module) => module,
			Err(e) => {
				println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		println!("Processing: {}", filename);

		let range = if args.flag_all {
			0..module.sample_data.len()
		} else {
			let number = usize::from_str(&args.flag_number).unwrap() - 1;
			if number >= module.sample_data.len() {
				println!("Invalid sample number. Only {} samples available.", module.sample_data.len());
				return
			}
			number..number+1
		};

		save_samples(&module,&(range.collect()),&args.arg_fileprefix);
	} else if args.cmd_remove {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let mut module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_unused_patterns {
				remove_unused_patterns(&mut module);
			}

			if args.flag_unused_samples {
				remove_unused_samples(&mut module);
			}

			let filename = format!("{}_{}",args.arg_fileprefix,filename);

			let file = match File::create(&filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
					return
				}
			};

			let mut writer = BufWriter::new(&file);
			match ptmf::write_mod(&mut writer,&mut module) {
				Ok(_) => (),
				Err(e) => {
					println!("Failed to write module {}. Error: '{:?}'", filename, e);
				}
			}
		}
	}

	println!("Done!");
}
<|endoftext|>


<commit_before>extern crate rsdocs2docset;
extern crate html5ever;
#[macro_use]
extern crate quick_error;
extern crate clap;
extern crate url;
extern crate sqlite;

use clap::{Arg, App};
use html5ever::driver::{ParseOpts, parse_document};
use html5ever::rcdom::RcDom;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;

use std::ffi::OsStr;
use std::fs::{self, DirBuilder, DirEntry, File};
use std::io::{self,Write};
use std::path::Path;

use rsdocs2docset::dom::{manipulator, parser};

type Result = std::result::Result<(), RsDoc2DocsetError>;

quick_error! {
    #[derive(Debug)]
    pub enum RsDoc2DocsetError {
        Io(err: std::io::Error) {
            from()
                cause(err)
                description(err.description())
        }
        Utf8(err: std::string::FromUtf8Error) {
            from()
                cause(err)
                description(err.description())
        }
        Sqlite(err: sqlite::Error) {
            from()
                cause(err)
                description(err.description())
        }
    }
}

fn main() {
    let args = App::new("RsDoc2Docset")
        .version(include_str!("../VERSION"))
        .about("A tool that converts rust docs to Dash docset files")
        .arg(Arg::with_name("indir")
             .short("i")
             .long("rsdoc")
             .value_name("INDIR")
             .help("directory that contains rustdoc files")
             .required(true)
             .takes_value(true))
        .arg(Arg::with_name("name")
             .short("n")
             .long("name")
             .value_name("NAME")
             .help("name of the docset")
             .required(true)
             .takes_value(true))
        .get_matches();

    create_docset(args.value_of("indir").unwrap(), args.value_of("name").unwrap()).expect("error creating docset");
    println!("\n{}.docset successfully created!", args.value_of("name").unwrap())
}

fn create_docset(indir: &str, name: &str) -> Result {
    let db_filename = format!("{}.docset/Contents/Resources/docSet.dsidx", name);
    let db_path = Path::new(&db_filename);

    try!(write_file(Path::new(format!("{}.docset/Contents/Info.plist", name).as_str()), format!(include_str!("Info.plist.tmpl"), name = name, identifier = name.replace(" ", "-").to_lowercase()).as_ref()));
    try!(write_file(Path::new(format!("{}.docset/icon.png", name).as_str()), include_bytes!("icon.png")));
    try!(write_file(Path::new(format!("{}.docset/icon@2x.png", name).as_str()), include_bytes!("icon@2x.png")));

    try!(write_file(db_path, "".as_bytes()));
    try!(sqlite::open(db_path).and_then(|c| c.execute("CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);")));

    try!(docset_from_rs_doc_tree(&Path::new(indir), format!("{}.docset/Contents/Resources/Documents/", name).as_str(), Path::new(db_path)));

    Ok(())
}

fn write_file(path: &Path, data: &[u8]) -> Result {
    let dir = path.parent().unwrap();

    try!(DirBuilder::new()
         .recursive(true)
         .create(dir));

    try!(File::create(path).and_then(|mut f| f.write_all(data)));
    Ok(())
}

fn docset_from_rs_doc_tree(source_dir: &Path, out_dir: &str, db_path: &Path) -> Result {
        if !source_dir.exists() {
            return Err(io::Error::new(io::ErrorKind::NotFound, format!("{} does not exist", source_dir.to_str().unwrap())).into());
        }

        if source_dir.is_dir() {
            for entry in fs::read_dir(source_dir)? {
                let entry = entry?;
                if entry.path().is_dir() {
                    try!(docset_from_rs_doc_tree(&entry.path(), &out_dir, &db_path));
                } else {
                    try!(annotate_file(&entry, &out_dir, &db_path));
                }
            }
        }
        Ok(())
    }

fn annotate_file(in_file: &DirEntry, output_prefix: &str, db_path: &Path) -> Result {
    let out_file = Path::new(output_prefix).join(in_file.path());

    if in_file.path().extension() != Some(OsStr::new("html")) {
        try!(write_file(&out_file, "".as_bytes())); // just so we are sure the parent's directory exists
        try!(fs::copy(in_file.path(), &out_file));
        //println!("{:70} | ", in_file.path().display());
        print!("."); io::stdout().flush().unwrap();
    } else {
        let mut dom = parse_document(RcDom::default(), ParseOpts::default())
            .from_utf8()
            .read_from( &mut File::open(&in_file.path())? )?;

        let entries = parser::find_entry_elements(&mut dom);
        for entry in entries.iter().filter_map(|x| x.as_ref()) {
            //println!("{:70} | {}", in_file.path().display(), entry);

            let sql_cmd = format!("INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES (\"{}\", \"{}\", \"{}#{}\");", entry.entry_name, entry.entry_type, in_file.path().to_str().unwrap(), entry.anchor_name);
            try!(sqlite::open(db_path).and_then(|c| c.execute(&sql_cmd)))
        }
        manipulator::add_dash_links(&mut dom, &entries);

        let mut bytes = vec![];
        try!(serialize(&mut bytes, &dom.document, SerializeOpts::default()));
        try!(write_file(&out_file, bytes.as_ref()));

        print!("o"); io::stdout().flush().unwrap();
    }

    Ok(())
}
<commit_msg>Add touch function<commit_after>extern crate rsdocs2docset;
extern crate html5ever;
#[macro_use]
extern crate quick_error;
extern crate clap;
extern crate url;
extern crate sqlite;

use clap::{Arg, App};
use html5ever::driver::{ParseOpts, parse_document};
use html5ever::rcdom::RcDom;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;

use std::ffi::OsStr;
use std::fs::{self, DirBuilder, DirEntry, File};
use std::io::{self,Write};
use std::path::Path;

use rsdocs2docset::dom::{manipulator, parser};

type Result = std::result::Result<(), RsDoc2DocsetError>;

quick_error! {
    #[derive(Debug)]
    pub enum RsDoc2DocsetError {
        Io(err: std::io::Error) {
            from()
                cause(err)
                description(err.description())
        }
        Utf8(err: std::string::FromUtf8Error) {
            from()
                cause(err)
                description(err.description())
        }
        Sqlite(err: sqlite::Error) {
            from()
                cause(err)
                description(err.description())
        }
    }
}

fn main() {
    let args = App::new("RsDoc2Docset")
        .version(include_str!("../VERSION"))
        .about("A tool that converts rust docs to Dash docset files")
        .arg(Arg::with_name("indir")
             .short("i")
             .long("rsdoc")
             .value_name("INDIR")
             .help("directory that contains rustdoc files")
             .required(true)
             .takes_value(true))
        .arg(Arg::with_name("name")
             .short("n")
             .long("name")
             .value_name("NAME")
             .help("name of the docset")
             .required(true)
             .takes_value(true))
        .get_matches();

    create_docset(args.value_of("indir").unwrap(), args.value_of("name").unwrap()).expect("error creating docset");
    println!("\n{}.docset successfully created!", args.value_of("name").unwrap())
}

fn create_docset(indir: &str, name: &str) -> Result {
    let db_filename = format!("{}.docset/Contents/Resources/docSet.dsidx", name);
    let db_path = Path::new(&db_filename);

    try!(write_file(Path::new(format!("{}.docset/Contents/Info.plist", name).as_str()), format!(include_str!("Info.plist.tmpl"), name = name, identifier = name.replace(" ", "-").to_lowercase()).as_ref()));
    try!(write_file(Path::new(format!("{}.docset/icon.png", name).as_str()), include_bytes!("icon.png")));
    try!(write_file(Path::new(format!("{}.docset/icon@2x.png", name).as_str()), include_bytes!("icon@2x.png")));

    try!(touch(db_path));
    try!(sqlite::open(db_path).and_then(|c| c.execute("CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);")));

    try!(docset_from_rs_doc_tree(&Path::new(indir), format!("{}.docset/Contents/Resources/Documents/", name).as_str(), Path::new(db_path)));

    Ok(())
}

fn touch(path: &Path) -> Result {
    write_file(path, "".as_bytes())
}

fn write_file(path: &Path, data: &[u8]) -> Result {
    let dir = path.parent().unwrap();

    try!(DirBuilder::new()
         .recursive(true)
         .create(dir));

    try!(File::create(path).and_then(|mut f| f.write_all(data)));
    Ok(())
}

fn docset_from_rs_doc_tree(source_dir: &Path, out_dir: &str, db_path: &Path) -> Result {
        if !source_dir.exists() {
            return Err(io::Error::new(io::ErrorKind::NotFound, format!("{} does not exist", source_dir.to_str().unwrap())).into());
        }

        if source_dir.is_dir() {
            for entry in fs::read_dir(source_dir)? {
                let entry = entry?;
                if entry.path().is_dir() {
                    try!(docset_from_rs_doc_tree(&entry.path(), &out_dir, &db_path));
                } else {
                    try!(annotate_file(&entry, &out_dir, &db_path));
                }
            }
        }
        Ok(())
    }

fn annotate_file(in_file: &DirEntry, output_prefix: &str, db_path: &Path) -> Result {
    let out_file = Path::new(output_prefix).join(in_file.path());

    if in_file.path().extension() != Some(OsStr::new("html")) {
        try!(touch(&out_file));
        try!(fs::copy(in_file.path(), &out_file));
        //println!("{:70} | ", in_file.path().display());
        print!("."); io::stdout().flush().unwrap();
    } else {
        let mut dom = parse_document(RcDom::default(), ParseOpts::default())
            .from_utf8()
            .read_from( &mut File::open(&in_file.path())? )?;

        let entries = parser::find_entry_elements(&mut dom);
        for entry in entries.iter().filter_map(|x| x.as_ref()) {
            //println!("{:70} | {}", in_file.path().display(), entry);

            let sql_cmd = format!("INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES (\"{}\", \"{}\", \"{}#{}\");", entry.entry_name, entry.entry_type, in_file.path().to_str().unwrap(), entry.anchor_name);
            try!(sqlite::open(db_path).and_then(|c| c.execute(&sql_cmd)))
        }
        manipulator::add_dash_links(&mut dom, &entries);

        let mut bytes = vec![];
        try!(serialize(&mut bytes, &dom.document, SerializeOpts::default()));
        try!(touch(&out_file));

        print!("o"); io::stdout().flush().unwrap();
    }

    Ok(())
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Very basic printer structure.<commit_after>use std::collections::VecDeque;

struct PrinterActor {
    callbacks: VecDeque<String>,
}

impl PrinterActor {
    fn new() -> PrinterActor {
        PrinterActor {
            callbacks: VecDeque::new(),
        }
    }

    fn send(&mut self, message: String) {
        self.callbacks.push_back(message);
    }

    fn treat_messages(&mut self) {
        if let Some(s) = self.callbacks.pop_front() {
            println!("{}", s);
        }
    }
}

fn main() {
    let mut actor = PrinterActor::new();

    actor.send("Hello world!".to_string());

    actor.treat_messages();
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::process;
use std::env;
use system_services::SystemInterface;
mod configuration;
mod provisioner;
mod logger;
mod file;
mod system_services;
mod platform;

fn main() {
    println!("sokan");
    let mut filename = "default.yaml".to_string();

    if env::args().len() > 1 {
        let mut args_iterator = env::args().skip(1);
        filename = args_iterator.next().unwrap().to_string();
    }

    let mut file_result :std::fs::File;
    match File::open(&filename) {
        Ok(result) => file_result = result,
        Err(error) => {
            println!("Error occured while accessing {}: {:?}", filename, error);
            return;
        }
    }

    let mut yaml_file = String::new();
    match file_result.read_to_string(&mut yaml_file) {
        Err(error) => println!("Failed to read {} - {:?}", filename, error),
        _ => { }
    }

    let configuration = configuration::from_yaml(yaml_file.to_string());
    let service = system_services::SystemServices;
    let provisioner = provisioner::Provisioner::new(service.clone());

    let exit_code = match service.platform() {
        system_services::OSType::redhat  => provisioner.provision(&configuration),
        _                                => 1
    };

    process::exit(exit_code);
}
<commit_msg>print error message that platform is unsupported<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::process;
use std::env;
use system_services::SystemInterface;
mod configuration;
mod provisioner;
mod logger;
mod file;
mod system_services;
mod platform;

fn main() {
    println!("sokan");
    let mut filename = "default.yaml".to_string();

    if env::args().len() > 1 {
        let mut args_iterator = env::args().skip(1);
        filename = args_iterator.next().unwrap().to_string();
    }

    let mut file_result :std::fs::File;
    match File::open(&filename) {
        Ok(result) => file_result = result,
        Err(error) => {
            println!("Error occured while accessing {}: {:?}", filename, error);
            return;
        }
    }

    let mut yaml_file = String::new();
    match file_result.read_to_string(&mut yaml_file) {
        Err(error) => println!("Failed to read {} - {:?}", filename, error),
        _ => { }
    }

    let configuration = configuration::from_yaml(yaml_file.to_string());
    let service = system_services::SystemServices;
    let provisioner = provisioner::Provisioner::new(service.clone());

    let exit_code = match service.platform() {
        system_services::OSType::redhat  => provisioner.provision(&configuration),
        _                                => {
            logger::print_message("Unsupported platform".into(), logger::MessageType::Stderr);
            1
        }
    };

    process::exit(exit_code);
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate git;

use std::os::args;
use git::Error;

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(_) => {},
            Err(e) => {
                error(e);
                return;
            },
        }
    );
)

fn main() {
    let args = args();

    if args.len() != 3 {
        usage();
        return;
    }

    let (command, path) = (args[1].clone(), Path::new(args[2].clone()));

    match command.as_slice() {
        "status" => ok!(status(&path)),
        "push" => ok!(push(&path)),
        _ => usage(),
    }
}

fn error(e: Error) {
    println!("{}", e);
}

fn usage() {
    println!("Usage: {} (status|push) <path>", args()[0]);
}

fn status(_path: &Path) -> Result<(), Error> {
    Ok(())
}

fn push(_path: &Path) -> Result<(), Error> {
    Ok(())
}
<commit_msg>Printing out the status of a repository<commit_after>#![feature(macro_rules)]

extern crate git;

use std::default::Default;
use std::os::args;

use git::Error;
use git::status;
use git::status::Flags;

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(_) => {},
            Err(e) => {
                error(e);
                return;
            },
        }
    );
)

fn main() {
    let args = args();

    if args.len() != 3 {
        usage();
        return;
    }

    let (command, path) = (args[1].clone(), Path::new(args[2].clone()));

    match command.as_slice() {
        "status" => ok!(status(&path)),
        "push" => ok!(push(&path)),
        _ => usage(),
    }
}

fn error(e: Error) {
    println!("{}", e);
}

fn usage() {
    println!("Usage: {} (status|push) <path>", args()[0]);
}

const NEW_FLAGS: Flags = Flags(status::IndexNew as u32 |
                               status::WorkDirNew as u32);

const UPDATED_FLAGS: Flags = Flags(status::IndexModified as u32 |
                                   status::WorkDirModified as u32);

const REMOVED_FLAGS: Flags = Flags(status::IndexDeleted as u32 |
                                   status::WorkDirDeleted as u32);

fn status(path: &Path) -> Result<(), Error> {
    let repo = try!(git::Repository::open(path));
    let list = try!(repo.status(&Default::default()));

    let mut new = vec![];
    let mut updated = vec![];
    let mut removed = vec![];

    for entry in list.iter() {
        let (path, status) = (entry.new_path(), entry.status());

        if status.any(NEW_FLAGS) {
            new.push(path);
        } else if status.any(UPDATED_FLAGS) {
            updated.push(path);
        } else if status.any(REMOVED_FLAGS) {
            removed.push(path);
        }
    }

    print("New", &new);
    print("Updated", &updated);
    print("Deleted", &removed);

    Ok(())
}

fn push(_path: &Path) -> Result<(), Error> {
    Ok(())
}

fn print(title: &str, paths: &Vec<Path>) {
    if paths.is_empty() {
        return;
    }

    println!("{}:", title);

    for path in paths.iter() {
        println!("* {}", path.display());
    }

    println!("");
}
<|endoftext|>