<commit_before>use regex::Regex;

#[derive(Debug, PartialEq)]
pub struct Message {
    pub data: String,
}

impl Message {
    pub fn new(data: &str) -> Message {
        Message { data: data.to_string() }
    }

    pub fn decompress_v1(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompressed_string_length_v1(&self.data, marker_finder)
    }

    pub fn decompress_v2(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompress_string_v2(&self.data, &marker_finder)
    }
}

fn decompressed_string_length_v1(message: &str, marker_regex: Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: usize = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length += (number_of_repeats * number_of_chars) as u64;
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

fn decompress_string_v2(message: &str, marker_regex: &Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: u64 = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        let number_to_repeat: u64 =
            decompress_string_v2(&message[(str_index - number_of_chars)..str_index],
                                 marker_regex);

        match number_of_repeats.checked_mul(number_to_repeat) {
            Some(num) => decompressed_length += num,
            None => println!("{}, {}", number_of_repeats, number_to_repeat),
        };
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decompress_v1() {
        let test_data = vec![Message::new("ADVENT").decompress_v1(),
                             Message::new("A(1x5)BC").decompress_v1(),
                             Message::new("(3x3)XYZ").decompress_v1(),
                             Message::new("A(2x2)BCD(2x2)EFG").decompress_v1(),
                             Message::new("(6x1)(1x3)A").decompress_v1(),
                             Message::new("X(8x2)(3x3)ABCY").decompress_v1()];

        assert_eq!(test_data, vec![6, 7, 9, 11, 6, 18]);
    }

    #[test]
    fn test_decompress_v2() {
        let test_data = vec![Message::new("(3X3)XYZ").decompress_v2(),
                 Message::new("X(8x2)(3x3)ABCY").decompress_v2(),
                 Message::new("(27x12)(20x12)(13x14)(7x10)(1x12)A").decompress_v2(),
                 Message::new("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN")
                     .decompress_v2()];

        assert_eq!(test_data, vec![9, 20, 241920, 445]);
    }
}<commit_msg>Remove match.<commit_after>use regex::Regex;

#[derive(Debug, PartialEq)]
pub struct Message {
    pub data: String,
}

impl Message {
    pub fn new(data: &str) -> Message {
        Message { data: data.to_string() }
    }

    pub fn decompress_v1(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompressed_string_length_v1(&self.data, marker_finder)
    }

    pub fn decompress_v2(&self) -> u64 {
        let marker_finder: Regex = Regex::new(r"\((\d+)x(\d+)\)").unwrap();

        decompress_string_v2(&self.data, &marker_finder)
    }
}

fn decompressed_string_length_v1(message: &str, marker_regex: Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: usize = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length += (number_of_repeats * number_of_chars) as u64;
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

fn decompress_string_v2(message: &str, marker_regex: &Regex) -> u64 {
    let mut decompressed_length: u64 = 0;
    let mut str_index: usize = 0;

    while let Some(matched) = marker_regex.find(&message[str_index..]) {
        let captured = marker_regex.captures(&message[str_index..]).unwrap();

        decompressed_length += matched.start() as u64;

        let number_of_chars: usize = (&captured[1]).parse().unwrap();
        let number_of_repeats: u64 = (&captured[2]).parse().unwrap();

        str_index += matched.end() + number_of_chars;

        decompressed_length =
            number_of_repeats *
            decompress_string_v2(&message[(str_index - number_of_chars)..str_index], marker_regex);
    }

    if str_index < message.len() {
        decompressed_length += (message.len() - str_index) as u64;
    }

    decompressed_length
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decompress_v1() {
        let test_data = vec![Message::new("ADVENT").decompress_v1(),
                             Message::new("A(1x5)BC").decompress_v1(),
                             Message::new("(3x3)XYZ").decompress_v1(),
                             Message::new("A(2x2)BCD(2x2)EFG").decompress_v1(),
                             Message::new("(6x1)(1x3)A").decompress_v1(),
                             Message::new("X(8x2)(3x3)ABCY").decompress_v1()];

        assert_eq!(test_data, vec![6, 7, 9, 11, 6, 18]);
    }

    #[test]
    fn test_decompress_v2() {
        let test_data = vec![Message::new("(3X3)XYZ").decompress_v2(),
                 Message::new("X(8x2)(3x3)ABCY").decompress_v2(),
                 Message::new("(27x12)(20x12)(13x14)(7x10)(1x12)A").decompress_v2(),
                 Message::new("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN")
                     .decompress_v2()];

        assert_eq!(test_data, vec![9, 20, 241920, 445]);
    }
}<|endoftext|>


<commit_before>//! This is the Buffer module for Xt.

// This file is part of Xt.
//
// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2018 The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program 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
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

use super::gapbuffer::GapBuffer;
use std::path::PathBuf;

use server::modes::major_mode::MajorMode;
use server::modes::minor_mode::MinorMode;

/// Struct for a Buffer object in Xt.
/// Stores buffer state & metadata.
#[derive(Debug)]
pub struct Buffer {
    /// File path of a buffer.
    pub file_path: Option<PathBuf>,
    /// Active status of a buffer.
    pub active: bool,
    /// Temporary status of a buffer.
    pub temporary: bool,
    /// If a buffer is r/o.
    /// If this is `true`, then r/w is `false.`
    /// Likewise, if this is `false`, then r/w is `true`.
    pub read_only: bool,
    /// Major mode of a buffer
    pub major_mode: MajorMode,
    /// Array of Minor modes in a buffer
    pub minor_modes: Vec<MinorMode>,
    /// Dirty status of a buffer
    pub dirty: bool,
    /// Contents of a buffer.
    pub text: GapBuffer<u8>,
}

impl Buffer {
    /// Return a new instance of `Buffer`.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            active: false,
            temporary: false,
            read_only: false,
            major_mode: MajorMode::new("fundamental-mode".to_owned()),
            minor_modes: Vec::new(),
            dirty: false,
            text: GapBuffer::new(),
        }
    }

    /// Return true if a buffer is active.
    /// That is to say, a 'focused' buffer, or otherwise in-use, and
    /// *not* inactive.
    /// If it's not a active buffer, then return false.
    pub fn is_active(&self) -> bool {
        self.active
    }

    /// Return true if a buffer is temporary.
    /// If it's not a temporary buffer, then return false.
    /// A temporary buffer is defined by the characteristic of having
    /// no 'target' to save to.
    pub fn is_temporary(&self) -> bool {
        self.temporary
    }

    /// Return true if a buffer is read only.

    /// If it's not read-only, then it returns false, and the buffer
    /// will be presumed to be read-write.

    /// A read-only buffer is defined by the characteristic of the FS
    /// denying write access, or being set manually.
    pub fn is_ro(&self) -> bool {
        self.read_only
    }

    /// Return true if a buffer is dirty.
    /// If it's not dirty, then return false.
    /// A dirty buffer is defined by the characteristic of the buffer
    /// having changed since the last save.
    /// Temporary buffers are *exempt* from this field.
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Return the current major mode of a buffer.
    pub fn get_major_mode(&self) -> &MajorMode {
        &self.major_mode
    }

    /// Return a `Vec<&'static str>` of minor modes.
    pub fn get_minor_modes(&self) -> &Vec<MinorMode> {
        &self.minor_modes
    }

    /// Return the length of a buffer.
    pub fn get_buffer_length(&self) -> usize {
        self.text.len()
    }
}

impl Default for Buffer {
    fn default() -> Buffer {
        Buffer::new()
    }
}

#[cfg(test)]
mod test {
    use super::Buffer;

    #[test]
    fn test_default_values_buffer() {
        let buf = Buffer::new();

        assert_eq!(None, buf.file_path);

        assert_eq!(false, buf.active);
        assert_eq!(false, buf.is_active());

        assert_eq!(false, buf.temporary);
        assert_eq!(false, buf.is_temporary());

        assert_eq!(false, buf.read_only);
        assert_eq!(false, buf.is_ro());

        assert_eq!(0, buf.text.len());

        assert_eq!("fundamental-mode", buf.major_mode.hname);
        assert_eq!(0, buf.minor_modes.len());
        assert_eq!(false, buf.dirty);
    }
}
<commit_msg>server/buffer: improve documentation slightly<commit_after>//! This is the Buffer module for Xt.

// This file is part of Xt.
//
// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2018 The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program 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
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

use super::gapbuffer::GapBuffer;
use std::path::PathBuf;

use server::modes::major_mode::MajorMode;
use server::modes::minor_mode::MinorMode;

/// Struct for a Buffer object in Xt.
/// Stores buffer state & metadata.
#[derive(Debug)]
pub struct Buffer {
    /// File path of a buffer.
    pub file_path: Option<PathBuf>,
    /// Active status of a buffer.
    pub active: bool,
    /// Temporary status of a buffer.
    pub temporary: bool,
    /// If a buffer is r/o.
    /// If this is `true`, then r/w is `false.`
    /// Likewise, if this is `false`, then r/w is `true`.
    pub read_only: bool,
    /// Major mode of a buffer
    pub major_mode: MajorMode,
    /// Array of Minor modes in a buffer
    pub minor_modes: Vec<MinorMode>,
    /// Dirty status of a buffer
    pub dirty: bool,
    /// Contents of a buffer.
    pub text: GapBuffer<u8>,
}

impl Buffer {
    /// Return a new `Buffer`.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            active: false,
            temporary: false,
            read_only: false,
            major_mode: MajorMode::new("fundamental-mode".to_owned()),
            minor_modes: Vec::new(),
            dirty: false,
            text: GapBuffer::new(),
        }
    }

    /// Return true if a buffer is active.
    /// That is to say, a 'focused' buffer, or otherwise in-use, and
    /// *not* inactive.
    /// If it's not a active buffer, then return false.
    pub fn is_active(&self) -> bool {
        self.active
    }

    /// Return true if a buffer is temporary.
    /// If it's not a temporary buffer, then return false.
    /// A temporary buffer is defined by the characteristic of having
    /// no 'target' to save to.
    pub fn is_temporary(&self) -> bool {
        self.temporary
    }

    /// Return true if a buffer is read only.

    /// If it's not read-only, then it returns false, and the buffer
    /// will be presumed to be read-write.

    /// A read-only buffer is defined by the characteristic of the FS
    /// denying write access, or being set manually.
    pub fn is_ro(&self) -> bool {
        self.read_only
    }

    /// Return true if a buffer is dirty.

    /// If it's not dirty, then return false.
    /// A dirty buffer is defined by the characteristic of the buffer
    /// having changed since the last save.

    /// Temporary buffers are *exempt* from this field.
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Return the current major mode of a buffer.
    pub fn get_major_mode(&self) -> &MajorMode {
        &self.major_mode
    }

    /// Return a `Vec<MinorMode>` array of minor modes.
    pub fn get_minor_modes(&self) -> &Vec<MinorMode> {
        &self.minor_modes
    }

    /// Return the length of a buffer.
    pub fn get_buffer_length(&self) -> usize {
        self.text.len()
    }
}

impl Default for Buffer {
    fn default() -> Buffer {
        Buffer::new()
    }
}

#[cfg(test)]
mod test {
    use super::Buffer;

    #[test]
    fn test_default_values_buffer() {
        let buf = Buffer::new();

        assert_eq!(None, buf.file_path);

        assert_eq!(false, buf.active);
        assert_eq!(false, buf.is_active());

        assert_eq!(false, buf.temporary);
        assert_eq!(false, buf.is_temporary());

        assert_eq!(false, buf.read_only);
        assert_eq!(false, buf.is_ro());

        assert_eq!(0, buf.text.len());

        assert_eq!("fundamental-mode", buf.major_mode.hname);
        assert_eq!(0, buf.minor_modes.len());
        assert_eq!(false, buf.dirty);
    }
}
<|endoftext|>


<commit_before>pub mod specifiers_iterator;

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                // Might fail if `local_format` contains a null byte. TODO decide if this is a good
                // error-handling strategy, or we should report back to user, or panic, or what
                if let Ok(local_format_cstring) = std::ffi::CString::new(local_format) {
                    let buf_size = 1024usize;
                    let buffer: std::vec::Vec<u8> = std::vec::Vec::with_capacity(buf_size);
                    if let Ok(buffer) = std::ffi::CString::new(buffer) {
                        unsafe {
                            let buffer_ptr = buffer.into_raw();
                            // TODO: check how many bytes were written
                            let bytes_written = libc::snprintf(
                                buffer_ptr,
                                buf_size as libc::size_t,
                                local_format_cstring.as_ptr() as *const libc::c_char,
                                $arg);
                            let buffer = std::ffi::CString::from_raw(buffer_ptr);
                            let _bytes_written = bytes_written as usize;
                            if let Ok(formatted) = buffer.into_string() {
                                result.push_str(&formatted);
                            }
                        }
                    }
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<commit_msg>Move single argument formatting into an fn<commit_after>pub mod specifiers_iterator;

use std::ffi::CString;
use std::vec::Vec;

/// Helper function for `fmt!`. Don't use directly.
pub fn fmt_arg<T>(format: &str, arg: T) -> Option<String> {
    // Might fail if `format` contains a null byte. TODO decide if this is a good
    // error-handling strategy, or we should report back to user, or panic, or what
    CString::new(format).ok().and_then(|local_format_cstring| {
        let buf_size = 1024usize;
        let mut buffer = Vec::<u8>::with_capacity(buf_size);
        // Filling the vector with ones because CString::new() doesn't want any zeroes in
        // there. The last byte is left unused, so that CString::new() can put a terminating
        // zero byte without triggering a re-allocation.
        buffer.resize(buf_size - 1, 1);
        CString::new(buffer).ok().and_then(|buffer| unsafe {
            let buffer_ptr = buffer.into_raw();
            // TODO: check how many bytes were written
            let bytes_written = libc::snprintf(
                buffer_ptr,
                buf_size as libc::size_t,
                local_format_cstring.as_ptr() as *const libc::c_char,
                arg,
            );
            let buffer = CString::from_raw(buffer_ptr);
            let _bytes_written = bytes_written as usize;
            buffer.into_string().ok()
        })
    })
}

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                if let Some(formatted_string) = $crate::fmt_arg(local_format, $arg) {
                    result.push_str(&formatted_string);
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<|endoftext|>


<commit_before>extern crate hyper;

use self::hyper::client::Client;

use std::thread;
use std::time::Duration;

use ::db::Db;
use super::{Image,download,req_and_parse};

use std::sync::mpsc::Receiver;

pub fn main(rc: &Receiver<()>) {
    let db = Db::new();
    let client = Client::new();
    let images_c = db.get_images(None,0).unwrap();
    let mut url_string = "https://derpibooru.org/images.json".to_string();
    let mut page = 1;

    'main: loop {
        let res = match req_and_parse(&client, &url_string) {
            Ok(x) => x,
            Err(_) => {
                thread::sleep(Duration::new(3,0));
                continue
            }
        };

        let images = res.as_object().unwrap()["images"].as_array().unwrap();
        if images.is_empty() { break }

        let images = images.iter().fold(Vec::new(), |mut acc, x| {
            let image = x.as_object().unwrap();
            let mut rating = String::new();

            let tags = image["tags"].as_string().unwrap().split(",").map(|x| x.trim().replace(" ", "_")).filter_map(|x| {
                if x == "safe" || x == "semi-grimdark" {
                    rating = "s".to_string();
                    None
                } else if x == "explicit" || x == "grimdark" || x == "grotesque" {
                    rating = "s".to_string();
                    None
                } else if x == "questionable" || x == "suggestive" {
                    rating = "q".to_string();
                    None
                } else {
                    Some(x.to_string())
                }}).collect::<Vec<_>>();
            let rating = rating.chars().collect::<Vec<_>>()[0];
            let url = format!("https:{}", image["image"].as_string().unwrap());
            let name = image["file_name"].as_string().unwrap();
            let id = image["id"].as_string().unwrap().parse::<u64>().unwrap();

            acc.push(Image{
                    name: format!("{}_{}",id,name),
                    got_from: "derpi".to_string(),
                    url: url,
                    tags: tags,
                    rating: rating,
                    post_url: format!("https://derpibooru.org/{}", id)
                });
            acc
        });

        for im in images {
            if !images_c.iter().any(|x| x.name == im.name ) {
                if let Err(_) = download(&client, &im, &rc) {
                    break 'main
                }
            }
        }

        page += 1;

        url_string = format!("https://derpibooru.org/images.json?page={}", page);
    }
}
<commit_msg>artist из дерпибуры выпилен<commit_after>extern crate hyper;

use self::hyper::client::Client;

use std::thread;
use std::time::Duration;

use ::db::Db;
use super::{Image,download,req_and_parse};

use std::sync::mpsc::Receiver;

pub fn main(rc: &Receiver<()>) {
    let db = Db::new();
    let client = Client::new();
    let images_c = db.get_images(None,0).unwrap();
    let mut url_string = "https://derpibooru.org/images.json".to_string();
    let mut page = 1;

    'main: loop {
        let res = match req_and_parse(&client, &url_string) {
            Ok(x) => x,
            Err(_) => {
                thread::sleep(Duration::new(3,0));
                continue
            }
        };

        let images = res.as_object().unwrap()["images"].as_array().unwrap();
        if images.is_empty() { break }

        let images = images.iter().fold(Vec::new(), |mut acc, x| {
            let image = x.as_object().unwrap();
            let mut rating = String::new();

            let tags = image["tags"].as_string().unwrap().split(",").map(|x| x.trim().replace(" ", "_")).filter_map(|x| {
                if x.starts_with("artist:") {
                    Some(x.split(":").collect::<Vec<_>>()[1].to_string())
                } else if x == "safe" || x == "semi-grimdark" {
                    rating = "s".to_string();
                    None
                } else if x == "explicit" || x == "grimdark" || x == "grotesque" {
                    rating = "s".to_string();
                    None
                } else if x == "questionable" || x == "suggestive" {
                    rating = "q".to_string();
                    None
                } else {
                    Some(x.to_string())
                }}).collect::<Vec<_>>();
            let rating = rating.chars().collect::<Vec<_>>()[0];
            let url = format!("https:{}", image["image"].as_string().unwrap());
            let name = image["file_name"].as_string().unwrap();
            let id = image["id"].as_string().unwrap().parse::<u64>().unwrap();

            acc.push(Image{
                    name: format!("{}_{}",id,name),
                    got_from: "derpi".to_string(),
                    url: url,
                    tags: tags,
                    rating: rating,
                    post_url: format!("https://derpibooru.org/{}", id)
                });
            acc
        });

        for im in images {
            if !images_c.iter().any(|x| x.name == im.name ) {
                if let Err(_) = download(&client, &im, &rc) {
                    break 'main
                }
            }
        }

        page += 1;

        url_string = format!("https://derpibooru.org/images.json?page={}", page);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Alignment algorithms.

pub mod pairwise;

#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Copy)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |&: op, k, cigar: &mut String| {
            cigar.push_str(format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }).as_slice());
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(format!("{}{}", self.xstart, clip_str).as_slice());
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(format!("{}{}", clip, clip_str).as_slice());
            }
        }
        else {
            cigar.push_str(format!("{}{}", self.xlen, clip_str).as_slice());
        }

        cigar
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::AlignmentOperation::*;

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<commit_msg>Remove obsolete syntax.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Alignment algorithms.

pub mod pairwise;

#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Copy)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }).as_slice());
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(format!("{}{}", self.xstart, clip_str).as_slice());
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(format!("{}{}", clip, clip_str).as_slice());
            }
        }
        else {
            cigar.push_str(format!("{}{}", self.xlen, clip_str).as_slice());
        }

        cigar
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::AlignmentOperation::*;

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate curl;
extern crate mimir;
#[macro_use]
extern crate log;

use std::path::Path;
use mimir::rubber::Rubber;
use std::fs;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self) -> mimir::Addr {
        let street_name = format!("{}, {} {}", self.street, self.zip, self.city);
        let addr_name = format!("{} {}", self.nb, street_name);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = mimir::Admin {
            id: format!("admin:fr:{}", self.insee()),
            level: 8,
            name: self.city,
            zip_code: self.zip,
            weight: 1,
            coord: Some(mimir::Coord {
                lat: 0.0,
                lon: 0.0,
            }),
            boundary: None,
        };
        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            name: street_name,
            administrative_region: Some(admin),
            weight: 1,
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            name: addr_name,
            coord: mimir::Coord {
                lat: self.lat,
                lon: self.lon,
            },
            weight: 1,
        }
    }
}

fn index_bano<I>(cnx_string: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let mut rubber = Rubber::new(cnx_string);
    rubber.create_index();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr()
        });
        match rubber.index(iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

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

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<commit_msg>build name of address like in kraken<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate curl;
extern crate mimir;
#[macro_use]
extern crate log;

use std::path::Path;
use mimir::rubber::Rubber;
use std::fs;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self) -> mimir::Addr {
        let street_name = format!("{}, ({})", self.street, self.city);
        let addr_name = format!("{} {}", self.nb, street_name);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = mimir::Admin {
            id: format!("admin:fr:{}", self.insee()),
            level: 8,
            name: self.city,
            zip_code: self.zip,
            weight: 1,
            coord: Some(mimir::Coord {
                lat: 0.0,
                lon: 0.0,
            }),
            boundary: None,
        };
        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            name: street_name,
            administrative_region: Some(admin),
            weight: 1,
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            name: addr_name,
            coord: mimir::Coord {
                lat: self.lat,
                lon: self.lon,
            },
            weight: 1,
        }
    }
}

fn index_bano<I>(cnx_string: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let mut rubber = Rubber::new(cnx_string);
    rubber.create_index();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr()
        });
        match rubber.index(iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

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

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
// 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.

//! Logging wrapper to be used throughout all crates in the workspace
use std::fs::OpenOptions;
use std::sync::Mutex;
use std::ops::Deref;
use slog::{Discard, Drain, Duplicate, Level, LevelFilter, Logger};
use slog_term;
use slog_async;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

fn convert_log_level(in_level: &LogLevel) -> Level {
	match *in_level {
		LogLevel::Info => Level::Info,
		LogLevel::Critical => Level::Critical,
		LogLevel::Warning => Level::Warning,
		LogLevel::Debug => Level::Debug,
		LogLevel::Trace => Level::Trace,
		LogLevel::Error => Level::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());

	/// And a static reference to the logger itself, accessible from all crates
	pub static ref LOGGER: Logger = {
		let was_init = WAS_INIT.lock().unwrap().clone();
		let config = LOGGING_CONFIG.lock().unwrap();
		let slog_level_stdout = convert_log_level(&config.stdout_log_level);
		let slog_level_file = convert_log_level(&config.file_log_level);
		if config.tui_running.is_some() && config.tui_running.unwrap() {
			let mut tui_running_ref = TUI_RUNNING.lock().unwrap();
			*tui_running_ref = true;
		}

		//Terminal output drain
		let terminal_decorator = slog_term::TermDecorator::new().build();
		let terminal_drain = slog_term::FullFormat::new(terminal_decorator).build().fuse();
		let terminal_drain = LevelFilter::new(terminal_drain, slog_level_stdout).fuse();
		let mut terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();
		if !config.log_to_stdout || !was_init {
			terminal_drain = slog_async::Async::new(Discard{}).build().fuse();
		}

		//File drain
		let mut file_drain_final = slog_async::Async::new(Discard{}).build().fuse();
		if config.log_to_file && was_init {
			let file = OpenOptions::new()
				.create(true)
				.write(true)
				.append(config.log_file_append)
				.truncate(false)
				.open(&config.log_file_path)
				.unwrap();

			let file_decorator = slog_term::PlainDecorator::new(file);
			let file_drain = slog_term::FullFormat::new(file_decorator).build().fuse();
			let file_drain = LevelFilter::new(file_drain, slog_level_file).fuse();
			file_drain_final = slog_async::Async::new(file_drain).build().fuse();
		}

		//Compose file and terminal drains
		let composite_drain = Duplicate::new(terminal_drain, file_drain_final).fuse();

		let log = Logger::root(composite_drain, o!());
		log
	};
}

/// Initialises the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let mut config_ref = LOGGING_CONFIG.lock().unwrap();
		*config_ref = c.clone();
		// Logger configuration successfully injected into LOGGING_CONFIG...
		let mut was_init_ref = WAS_INIT.lock().unwrap();
		*was_init_ref = true;
		// .. allow logging, having ensured that paths etc are immutable
	}
	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock().unwrap();
	if *was_init_ref.deref() {
		return;
	}
	let mut config_ref = LOGGING_CONFIG.lock().unwrap();
	*config_ref = LoggingConfig::default();
	*was_init_ref = true;
	send_panic_to_log();
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					LOGGER,
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!(
				LOGGER,
				"thread '{}' panicked at '{}'{:?}", thread, msg, backtrace
			),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().unwrap().clone();
		if !tui_running {
			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee grin.log for further details.",
				thread, msg
			);
		}
	}));
}
<commit_msg>Optimize logging (#992)<commit_after>// Copyright 2018 The Grin Developers
// 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.

//! Logging wrapper to be used throughout all crates in the workspace
use std::fs::OpenOptions;
use std::sync::Mutex;
use std::ops::Deref;
use slog::{Discard, Drain, Duplicate, Level, LevelFilter, Logger};
use slog_term;
use slog_async;

use backtrace::Backtrace;
use std::{panic, thread};

use types::{LogLevel, LoggingConfig};

fn convert_log_level(in_level: &LogLevel) -> Level {
	match *in_level {
		LogLevel::Info => Level::Info,
		LogLevel::Critical => Level::Critical,
		LogLevel::Warning => Level::Warning,
		LogLevel::Debug => Level::Debug,
		LogLevel::Trace => Level::Trace,
		LogLevel::Error => Level::Error,
	}
}

lazy_static! {
	/// Flag to observe whether logging was explicitly initialised (don't output otherwise)
	static ref WAS_INIT: Mutex<bool> = Mutex::new(false);
	/// Flag to observe whether tui is running, and we therefore don't want to attempt to write
	/// panics to stdout
	static ref TUI_RUNNING: Mutex<bool> = Mutex::new(false);
	/// Static Logging configuration, should only be set once, before first logging call
	static ref LOGGING_CONFIG: Mutex<LoggingConfig> = Mutex::new(LoggingConfig::default());

	/// And a static reference to the logger itself, accessible from all crates
	pub static ref LOGGER: Logger = {
		let was_init = WAS_INIT.lock().unwrap().clone();
		let config = LOGGING_CONFIG.lock().unwrap();
		let slog_level_stdout = convert_log_level(&config.stdout_log_level);
		let slog_level_file = convert_log_level(&config.file_log_level);
		if config.tui_running.is_some() && config.tui_running.unwrap() {
			let mut tui_running_ref = TUI_RUNNING.lock().unwrap();
			*tui_running_ref = true;
		}

		//Terminal output drain
		let terminal_decorator = slog_term::TermDecorator::new().build();
		let terminal_drain = slog_term::FullFormat::new(terminal_decorator).build().fuse();
		let terminal_drain = LevelFilter::new(terminal_drain, slog_level_stdout).fuse();
		let mut terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();
		if !config.log_to_stdout || !was_init {
			terminal_drain = slog_async::Async::new(Discard{}).build().fuse();
		}

		if config.log_to_file && was_init {
			//File drain
			let file = OpenOptions::new()
				.create(true)
				.write(true)
				.append(config.log_file_append)
				.truncate(false)
				.open(&config.log_file_path)
				.unwrap();

			let file_decorator = slog_term::PlainDecorator::new(file);
			let file_drain = slog_term::FullFormat::new(file_decorator).build().fuse();
			let file_drain = LevelFilter::new(file_drain, slog_level_file).fuse();
			let file_drain_final = slog_async::Async::new(file_drain).build().fuse();

			let composite_drain = Duplicate::new(terminal_drain, file_drain_final).fuse();

			Logger::root(composite_drain, o!())
		} else {
			Logger::root(terminal_drain, o!())
		}
	};
}

/// Initialises the logger with the given configuration
pub fn init_logger(config: Option<LoggingConfig>) {
	if let Some(c) = config {
		let mut config_ref = LOGGING_CONFIG.lock().unwrap();
		*config_ref = c.clone();
		// Logger configuration successfully injected into LOGGING_CONFIG...
		let mut was_init_ref = WAS_INIT.lock().unwrap();
		*was_init_ref = true;
		// .. allow logging, having ensured that paths etc are immutable
	}
	send_panic_to_log();
}

/// Initializes the logger for unit and integration tests
pub fn init_test_logger() {
	let mut was_init_ref = WAS_INIT.lock().unwrap();
	if *was_init_ref.deref() {
		return;
	}
	let mut config_ref = LOGGING_CONFIG.lock().unwrap();
	*config_ref = LoggingConfig::default();
	*was_init_ref = true;
	send_panic_to_log();
}

/// hook to send panics to logs as well as stderr
fn send_panic_to_log() {
	panic::set_hook(Box::new(|info| {
		let backtrace = Backtrace::new();

		let thread = thread::current();
		let thread = thread.name().unwrap_or("unnamed");

		let msg = match info.payload().downcast_ref::<&'static str>() {
			Some(s) => *s,
			None => match info.payload().downcast_ref::<String>() {
				Some(s) => &**s,
				None => "Box<Any>",
			},
		};

		match info.location() {
			Some(location) => {
				error!(
					LOGGER,
					"\nthread '{}' panicked at '{}': {}:{}{:?}\n\n",
					thread,
					msg,
					location.file(),
					location.line(),
					backtrace
				);
			}
			None => error!(
				LOGGER,
				"thread '{}' panicked at '{}'{:?}", thread, msg, backtrace
			),
		}
		//also print to stderr
		let tui_running = TUI_RUNNING.lock().unwrap().clone();
		if !tui_running {
			eprintln!(
				"Thread '{}' panicked with message:\n\"{}\"\nSee grin.log for further details.",
				thread, msg
			);
		}
	}));
}
<|endoftext|>


<commit_before>use std::io::Read;

use rustc_serialize::json::Json;

use system::index::Index;
use search::store::memory::MemoryIndexStore;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    // let indices = system.indices.read().unwrap();

    // Get index
    // let index = get_index_or_404!(indices, *index_name);

    // TODO

    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Create index
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    let mut index = Index::new(MemoryIndexStore::new());
    indices.insert(index_name.clone().to_owned(), index);

    // TODO: load settings

    system.log.info("[api] created index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Make sure the index exists
    get_index_or_404!(system.indices.read().unwrap(), *index_name);

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Remove index from array
    indices.remove(index_name.to_owned());

    // Delete file
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    // fs::remove_file(&index_path).unwrap();

    system.log.info("[api] deleted index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<commit_msg>Fixed get index view<commit_after>use std::io::Read;

use rustc_serialize::json::Json;

use system::index::Index;
use search::store::memory::MemoryIndexStore;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Get index
    let index = get_index_or_404!(indices, *index_name);

    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Create index
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    let mut index = Index::new(MemoryIndexStore::new());
    indices.insert(index_name.clone().to_owned(), index);

    // TODO: load settings

    system.log.info("[api] created index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Make sure the index exists
    get_index_or_404!(system.indices.read().unwrap(), *index_name);

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Remove index from array
    indices.remove(index_name.to_owned());

    // Delete file
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    // fs::remove_file(&index_path).unwrap();

    system.log.info("[api] deleted index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<|endoftext|>


<commit_before>
extern crate cratesfyi;
extern crate clap;
#[macro_use]
extern crate log;
extern crate time;

use std::env;
use std::fs;
use std::process::{Command, exit};
use std::path::PathBuf;

use cratesfyi::docbuilder::{DocBuilder, DocBuilderError, command_result};
use cratesfyi::docbuilder::crte::Crate;
use clap::{Arg, App, SubCommand};
use log::{LogLevel, LogLevelFilter, LogRecord, LogMetadata};
use time::now;

// I am using really simple Logger in this program
struct Logger;

impl log::Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{} {} - {}", now().to_utc().rfc3339(), record.level(), record.args());
        }
    }
}

fn update_crates_io_index(path: &PathBuf) -> Result<String, String> {
    info!("Updating crates.io-index");

    if path.exists() {
        let cwd = env::current_dir().unwrap();
        env::set_current_dir(path).unwrap();
        let res = command_result(Command::new("git").arg("pull").output().unwrap());
        env::set_current_dir(cwd).unwrap();
        res
    } else {
        command_result(Command::new("git")
            .arg("clone")
            .arg("https://github.com/rust-lang/crates.io-index.git")
            .arg(path.to_str().unwrap())
            .output().unwrap())
    }
}

// This will remove everything in CWD!!!
fn clean_build_dir() -> Result<(), DocBuilderError> {

    for file in try!(env::current_dir().unwrap()
                     .read_dir().map_err(DocBuilderError::RemoveBuildDir)) {
        let file = try!(file.map_err(DocBuilderError::RemoveBuildDir));
        let path = file.path();

        if path.file_name().unwrap() == ".cargo" ||
            path.file_name().unwrap() == ".crates.io-index" {
                continue;
            }

        if path.is_dir() {
            try!(fs::remove_dir_all(path).map_err(DocBuilderError::RemoveBuildDir));
        } else {
            try!(fs::remove_file(path).map_err(DocBuilderError::RemoveBuildDir));
        }
    }

    Ok(())
}

fn main() {
    log::set_logger(|max_log_level| {
        max_log_level.set(LogLevelFilter::Info);
        Box::new(Logger)
    }).unwrap();

    let matches = App::new("cratesfyi")
                      .version(env!("CARGO_PKG_VERSION"))
                      .about("Crates for your info!")
                      .subcommand(SubCommand::with_name("build")
                                      .about("Builds documentation in a chroot environment")
                                      .arg(Arg::with_name("PREFIX")
                                               .short("P")
                                               .long("prefix")
                                               .takes_value(true))
                                      .arg(Arg::with_name("DESTINATION")
                                               .short("d")
                                               .long("destination")
                                               .help("Sets destination path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CHROOT_PATH")
                                               .short("c")
                                               .long("chroot")
                                               .help("Sets chroot path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CHROOT_USER")
                                               .short("u")
                                               .long("chroot-user")
                                               .help("Sets chroot user name")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                                               .long("crates-io-index-path")
                                               .help("Sets crates.io-index path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("LOGS_PATH")
                                               .long("logs-path")
                                               .help("Sets logs path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("SKIP_IF_EXISTS")
                                               .short("s")
                                               .long("skip")
                                               .help("Skips building documentation if \
                                                      documentation exists"))
                                      .arg(Arg::with_name("SKIP_IF_LOG_EXISTS")
                                               .long("skip-if-log-exists")
                                               .help("Skips building documentation if build \
                                                      log exists"))
                                      .arg(Arg::with_name("SKIP_OLDEST_VERSIONS")
                                               .long("skip-oldest-versions")
                                               .help("Skips trying to build oldest versions \
                                                      if build fails"))
                                      .arg(Arg::with_name("KEEP_BUILD_DIRECTORY")
                                               .short("-k")
                                               .long("keep-build-directory")
                                               .help("Keeps build directory after build."))
                                      .subcommand(SubCommand::with_name("download-sources")
                                                      .about("Downloads sources of all crates"))
                                      .subcommand(SubCommand::with_name("world")
                                                      .about("Builds documentation of every \
                                                              crate")
                                                      .arg(Arg::with_name("BUILD_ONLY_LATEST_V\
                                                                           ERSION")
                                                               .long("build-only-latest-versio\
                                                                      n")
                                                               .help("Builds only latest \
                                                                      version of crate and \
                                                                      skips oldest versions")))
                                      .subcommand(SubCommand::with_name("crate")
                                                      .about("Builds documentation for a crate")
                                                      .arg(Arg::with_name("CRATE_NAME")
                                                               .index(1)
                                                               .required(true)
                                                               .help("Crate name"))
                                                      .arg(Arg::with_name("CRATE_VERSION")
                                                               .index(2)
                                                               .required(true)
                                                               .help("Version of crate"))))
                      .subcommand(SubCommand::with_name("build-doc")
                                      .about("Builds documentation in CWD")
                                      .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                                               .short("p")
                                               .long("crates-io-index-path")
                                               .help("Sets crates.io-index path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CLEAN")
                                               .short("c")
                                               .long("clean")
                                               .help("Clean build dir before building"))
                                      .arg(Arg::with_name("CRATE_NAME")
                                               .index(1)
                                               .required(true)
                                               .help("Crate name"))
                                      .arg(Arg::with_name("CRATE_VERSION")
                                               .index(2)
                                               .required(true)
                                               .help("Version of crate")))
                      .get_matches();

    // DocBuilder
    if let Some(matches) = matches.subcommand_matches("build") {
        let mut dbuilder = {
            if let Some(prefix) = matches.value_of("PREFIX") {
                DocBuilder::from_prefix(PathBuf::from(prefix))
            } else {
                DocBuilder::default()
            }
        };

        // set destination
        if let Some(destination) = matches.value_of("DESTINATION") {
            dbuilder.destination(PathBuf::from(destination));
        }

        // set chroot path
        if let Some(chroot_path) = matches.value_of("CHROOT_PATH") {
            dbuilder.destination(PathBuf::from(chroot_path));
        }

        // set chroot user name
        if let Some(chroot_user) = matches.value_of("CHROOT_USER") {
            dbuilder.chroot_user(chroot_user.to_string());
        }

        // set crates.io-index path
        if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") {
            dbuilder.crates_io_index_path(PathBuf::from(crates_io_index_path));
        }

        // set logs path
        if let Some(logs_path) = matches.value_of("LOGS_PATH") {
            dbuilder.logs_path(PathBuf::from(logs_path));
        }

        dbuilder.skip_if_exists(matches.is_present("SKIP_IF_EXISTS"));
        dbuilder.skip_if_log_exists(matches.is_present("SKIP_IF_LOG_EXISTS"));
        dbuilder.skip_oldest_versions(matches.is_present("SKIP_OLDEST_VERSIONS"));
        dbuilder.keep_build_directory(matches.is_present("KEEP_BUILD_DIRECTORY"));

        // check paths
        if let Err(e) = dbuilder.check_paths() {
            println!("{:?}\nUse --help to get more information", e);
            std::process::exit(1);
        }

        // build world
        if let Some(matches) = matches.subcommand_matches("world") {
            dbuilder.build_only_latest_version(matches.is_present("BUILD_ONLY_LATEST_VERSION"));
            if let Err(e) = dbuilder.build_doc_for_every_crate() {
                println!("Failed to build world: {:#?}", e);
            }
        } else if let Some(matches) = matches.subcommand_matches("crate") {
            // Safe to call unwrap here
            let crte_name = matches.value_of("CRATE_NAME").unwrap();
            let version = matches.value_of("CRATE_VERSION").unwrap();
            let crte = Crate::new(crte_name.to_string(), vec![version.to_string()]);

            if let Err(e) = dbuilder.build_doc_for_crate_version(&crte, 0) {
                match e {
                    DocBuilderError::SkipDocumentationExists => {
                        println!("Skipping {} documentation already exists",
                                 crte.canonical_name(0))
                    }
                    _ => {
                        println!("Failed to build documentation for {}: {:?}",
                                 crte.canonical_name(0),
                                 e)
                    }
                }
            }
        } else if let Some(_) = matches.subcommand_matches("download-sources") {
            if let Err(e) = dbuilder.download_sources() {
                println!("{:?}", e);
            }
        }
    }

    // build-doc
    else if let Some(matches) = matches.subcommand_matches("build-doc") {
        let mut docbuilder = DocBuilder::default();
        let mut crates_io_index_path;

        // set crates.io-index path
        if let Some(crates_io_index_path_conf) = matches.value_of("CRATES_IO_INDEX_PATH") {
            crates_io_index_path = PathBuf::from(crates_io_index_path_conf);
            docbuilder.crates_io_index_path(PathBuf::from(&crates_io_index_path));
        } else {
            crates_io_index_path = env::home_dir().unwrap();
            crates_io_index_path.push(".crates.io-index");
            docbuilder.crates_io_index_path(PathBuf::from(&crates_io_index_path));
        }

        // update crates.io-index path
        if let Err(e) = update_crates_io_index(&crates_io_index_path) {
            panic!("{}", e);
        }

        // crates.io-index required for single crate
        if let Err(e) = docbuilder.check_crates_io_index_path() {
            panic!("{:?}", e);
        }

        let crte_name = matches.value_of("CRATE_NAME").unwrap();
        let version = matches.value_of("CRATE_VERSION").unwrap();

        let crte = Crate::new(crte_name.to_string(), vec![version.to_string()]);

        if matches.is_present("CLEAN") {
            clean_build_dir().unwrap();
        }

        if let Err(e) = crte.build_crate_doc(0, &docbuilder) {
            error!("Failed to build crate\n{:?}", e);
            exit(1);
        } else {
            info!("Crate successfully built!");
        }
    }

}
<commit_msg>Move skip-oldest-versions flag into world subcommand<commit_after>
extern crate cratesfyi;
extern crate clap;
#[macro_use]
extern crate log;
extern crate time;

use std::env;
use std::fs;
use std::process::{Command, exit};
use std::path::PathBuf;

use cratesfyi::docbuilder::{DocBuilder, DocBuilderError, command_result};
use cratesfyi::docbuilder::crte::Crate;
use clap::{Arg, App, SubCommand};
use log::{LogLevel, LogLevelFilter, LogRecord, LogMetadata};
use time::now;

// I am using really simple Logger in this program
struct Logger;

impl log::Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("{} {} - {}", now().to_utc().rfc3339(), record.level(), record.args());
        }
    }
}

fn update_crates_io_index(path: &PathBuf) -> Result<String, String> {
    info!("Updating crates.io-index");

    if path.exists() {
        let cwd = env::current_dir().unwrap();
        env::set_current_dir(path).unwrap();
        let res = command_result(Command::new("git").arg("pull").output().unwrap());
        env::set_current_dir(cwd).unwrap();
        res
    } else {
        command_result(Command::new("git")
            .arg("clone")
            .arg("https://github.com/rust-lang/crates.io-index.git")
            .arg(path.to_str().unwrap())
            .output().unwrap())
    }
}

// This will remove everything in CWD!!!
fn clean_build_dir() -> Result<(), DocBuilderError> {

    for file in try!(env::current_dir().unwrap()
                     .read_dir().map_err(DocBuilderError::RemoveBuildDir)) {
        let file = try!(file.map_err(DocBuilderError::RemoveBuildDir));
        let path = file.path();

        if path.file_name().unwrap() == ".cargo" ||
            path.file_name().unwrap() == ".crates.io-index" {
                continue;
            }

        if path.is_dir() {
            try!(fs::remove_dir_all(path).map_err(DocBuilderError::RemoveBuildDir));
        } else {
            try!(fs::remove_file(path).map_err(DocBuilderError::RemoveBuildDir));
        }
    }

    Ok(())
}

fn main() {
    log::set_logger(|max_log_level| {
        max_log_level.set(LogLevelFilter::Info);
        Box::new(Logger)
    }).unwrap();

    let matches = App::new("cratesfyi")
                      .version(env!("CARGO_PKG_VERSION"))
                      .about("Crates for your info!")
                      .subcommand(SubCommand::with_name("build")
                                      .about("Builds documentation in a chroot environment")
                                      .arg(Arg::with_name("PREFIX")
                                               .short("P")
                                               .long("prefix")
                                               .takes_value(true))
                                      .arg(Arg::with_name("DESTINATION")
                                               .short("d")
                                               .long("destination")
                                               .help("Sets destination path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CHROOT_PATH")
                                               .short("c")
                                               .long("chroot")
                                               .help("Sets chroot path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CHROOT_USER")
                                               .short("u")
                                               .long("chroot-user")
                                               .help("Sets chroot user name")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                                               .long("crates-io-index-path")
                                               .help("Sets crates.io-index path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("LOGS_PATH")
                                               .long("logs-path")
                                               .help("Sets logs path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("SKIP_IF_EXISTS")
                                               .short("s")
                                               .long("skip")
                                               .help("Skips building documentation if \
                                                      documentation exists"))
                                      .arg(Arg::with_name("SKIP_IF_LOG_EXISTS")
                                               .long("skip-if-log-exists")
                                               .help("Skips building documentation if build \
                                                      log exists"))
                                      .arg(Arg::with_name("KEEP_BUILD_DIRECTORY")
                                               .short("-k")
                                               .long("keep-build-directory")
                                               .help("Keeps build directory after build."))
                                      .subcommand(SubCommand::with_name("download-sources")
                                                      .about("Downloads sources of all crates"))
                                      .subcommand(SubCommand::with_name("world")
                                                      .about("Builds documentation of every \
                                                              crate")
                                                      .arg(Arg::with_name("SKIP_OLDEST_VERSIONS")
                                                               .long("skip-oldest-versions")
                                                               .help("Skips trying to build \
                                                                      oldest versions \
                                                                      if build fails"))
                                                      .arg(Arg::with_name("BUILD_ONLY_LATEST_V\
                                                                           ERSION")
                                                               .long("build-only-latest-versio\
                                                                      n")
                                                               .help("Builds only latest \
                                                                      version of crate and \
                                                                      skips oldest versions")))
                                      .subcommand(SubCommand::with_name("crate")
                                                      .about("Builds documentation for a crate")
                                                      .arg(Arg::with_name("CRATE_NAME")
                                                               .index(1)
                                                               .required(true)
                                                               .help("Crate name"))
                                                      .arg(Arg::with_name("CRATE_VERSION")
                                                               .index(2)
                                                               .required(true)
                                                               .help("Version of crate"))))
                      .subcommand(SubCommand::with_name("build-doc")
                                      .about("Builds documentation in CWD")
                                      .arg(Arg::with_name("CRATES_IO_INDEX_PATH")
                                               .short("p")
                                               .long("crates-io-index-path")
                                               .help("Sets crates.io-index path")
                                               .takes_value(true))
                                      .arg(Arg::with_name("CLEAN")
                                               .short("c")
                                               .long("clean")
                                               .help("Clean build dir before building"))
                                      .arg(Arg::with_name("CRATE_NAME")
                                               .index(1)
                                               .required(true)
                                               .help("Crate name"))
                                      .arg(Arg::with_name("CRATE_VERSION")
                                               .index(2)
                                               .required(true)
                                               .help("Version of crate")))
                      .get_matches();

    // DocBuilder
    if let Some(matches) = matches.subcommand_matches("build") {
        let mut dbuilder = {
            if let Some(prefix) = matches.value_of("PREFIX") {
                DocBuilder::from_prefix(PathBuf::from(prefix))
            } else {
                DocBuilder::default()
            }
        };

        // set destination
        if let Some(destination) = matches.value_of("DESTINATION") {
            dbuilder.destination(PathBuf::from(destination));
        }

        // set chroot path
        if let Some(chroot_path) = matches.value_of("CHROOT_PATH") {
            dbuilder.destination(PathBuf::from(chroot_path));
        }

        // set chroot user name
        if let Some(chroot_user) = matches.value_of("CHROOT_USER") {
            dbuilder.chroot_user(chroot_user.to_string());
        }

        // set crates.io-index path
        if let Some(crates_io_index_path) = matches.value_of("CRATES_IO_INDEX_PATH") {
            dbuilder.crates_io_index_path(PathBuf::from(crates_io_index_path));
        }

        // set logs path
        if let Some(logs_path) = matches.value_of("LOGS_PATH") {
            dbuilder.logs_path(PathBuf::from(logs_path));
        }

        dbuilder.skip_if_exists(matches.is_present("SKIP_IF_EXISTS"));
        dbuilder.skip_if_log_exists(matches.is_present("SKIP_IF_LOG_EXISTS"));
        dbuilder.keep_build_directory(matches.is_present("KEEP_BUILD_DIRECTORY"));

        // check paths
        if let Err(e) = dbuilder.check_paths() {
            println!("{:?}\nUse --help to get more information", e);
            std::process::exit(1);
        }

        // build world
        if let Some(matches) = matches.subcommand_matches("world") {
            dbuilder.build_only_latest_version(matches.is_present("BUILD_ONLY_LATEST_VERSION"));
            dbuilder.skip_oldest_versions(matches.is_present("SKIP_OLDEST_VERSIONS"));
            if let Err(e) = dbuilder.build_doc_for_every_crate() {
                println!("Failed to build world: {:#?}", e);
            }
        } else if let Some(matches) = matches.subcommand_matches("crate") {
            // Safe to call unwrap here
            let crte_name = matches.value_of("CRATE_NAME").unwrap();
            let version = matches.value_of("CRATE_VERSION").unwrap();
            let crte = Crate::new(crte_name.to_string(), vec![version.to_string()]);

            if let Err(e) = dbuilder.build_doc_for_crate_version(&crte, 0) {
                match e {
                    DocBuilderError::SkipDocumentationExists => {
                        println!("Skipping {} documentation already exists",
                                 crte.canonical_name(0))
                    }
                    _ => {
                        println!("Failed to build documentation for {}: {:?}",
                                 crte.canonical_name(0),
                                 e)
                    }
                }
            }
        } else if let Some(_) = matches.subcommand_matches("download-sources") {
            if let Err(e) = dbuilder.download_sources() {
                println!("{:?}", e);
            }
        }
    }

    // build-doc
    else if let Some(matches) = matches.subcommand_matches("build-doc") {
        let mut docbuilder = DocBuilder::default();
        let mut crates_io_index_path;

        // set crates.io-index path
        if let Some(crates_io_index_path_conf) = matches.value_of("CRATES_IO_INDEX_PATH") {
            crates_io_index_path = PathBuf::from(crates_io_index_path_conf);
            docbuilder.crates_io_index_path(PathBuf::from(&crates_io_index_path));
        } else {
            crates_io_index_path = env::home_dir().unwrap();
            crates_io_index_path.push(".crates.io-index");
            docbuilder.crates_io_index_path(PathBuf::from(&crates_io_index_path));
        }

        // update crates.io-index path
        if let Err(e) = update_crates_io_index(&crates_io_index_path) {
            panic!("{}", e);
        }

        // crates.io-index required for single crate
        if let Err(e) = docbuilder.check_crates_io_index_path() {
            panic!("{:?}", e);
        }

        let crte_name = matches.value_of("CRATE_NAME").unwrap();
        let version = matches.value_of("CRATE_VERSION").unwrap();

        let crte = Crate::new(crte_name.to_string(), vec![version.to_string()]);

        if matches.is_present("CLEAN") {
            clean_build_dir().unwrap();
        }

        if let Err(e) = crte.build_crate_doc(0, &docbuilder) {
            error!("Failed to build crate\n{:?}", e);
            exit(1);
        } else {
            info!("Crate successfully built!");
        }
    }

}
<|endoftext|>


<commit_before>//! A single question of a DNS message.

use std::fmt;
use super::compose::ComposeBytes;
use super::error::{ComposeResult, ParseResult};
//use super::flavor::{self, Flavor, FlatFlavor};
use super::iana::{Class, RRType};
use super::name::{AsDName, DName};
use super::parse::ParseBytes;

//------------ Question -----------------------------------------------------

#[derive(Clone, Debug)]
pub struct Question<'a> {
    qname: DName<'a>,
    qtype: RRType,
    qclass: Class,
}

/// # Creation and Conversion
///
impl<'a> Question<'a> {
    pub fn new(qname: DName<'a>, qtype: RRType, qclass: Class) -> Self {
        Question { qname: qname, qtype: qtype, qclass: qclass }
    }
}

/// # Element Access
///
impl<'a> Question<'a> {
    /// Returns the requested domain name.
    pub fn qname(&self) -> &DName<'a> {
        &self.qname
    }

    /// Returns the requested record type.
    pub fn qtype(&self) -> RRType {
        self.qtype
    }

    /// Returns the requested class.
    pub fn qclass(&self) -> Class {
        self.qclass
    }
}

/// Parsing and Composing
///
impl<'a> Question<'a> {
    pub fn parse<P: ParseBytes<'a>>(parser: &mut P) -> ParseResult<Self> {
        Ok(Question::new(try!(parser.parse_dname()),
                         try!(parser.parse_u16()).into(),
                         try!(parser.parse_u16()).into()))
    }

    pub fn compose<C: ComposeBytes>(&self, target: &mut C)
                                    -> ComposeResult<()> {
        try!(target.push_dname_compressed(&self.qname));
        try!(target.push_u16(self.qtype.into()));
        target.push_u16(self.qclass.into())
    }

    pub fn push<C, T, N>(target: &mut T, qname: N, qtype: RRType,
                         qclass: Class) -> ComposeResult<()>
                where C: ComposeBytes, T: QuestionTarget<C>, N: AsDName {
        target.compose(|target| {
            try!(target.push_dname_compressed(&qname.as_dname()));
            try!(target.push_u16(qtype.into()));
            target.push_u16(qclass.into())
        })
    }

    pub fn push_in<C, T, N>(target: &mut T, qname: N, qtype: RRType)
                            -> ComposeResult<()>
                where C: ComposeBytes, T: QuestionTarget<C>, N: AsDName {
        Question::push(target, qname, qtype, Class::IN)
    }
}

//--- PartialEq

impl<'a, 'b> PartialEq<Question<'b>> for Question<'a> {
    fn eq(&self, other: &Question<'b>) -> bool {
        self.qname == other.qname && self.qtype == other.qtype
             && self.qclass == other.qclass
    }
}

//--- Display

impl<'a> fmt::Display for Question<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) ->  fmt::Result {
        write!(f, "{}\t{}\t{}", self.qname, self.qtype, self.qclass)
    }
}

//------------ QuestionTarget -----------------------------------------------

pub trait QuestionTarget<C: ComposeBytes> {
    fn compose<F>(&mut self, push: F) -> ComposeResult<()>
               where F: Fn(&mut C) -> ComposeResult<()>;
}

/*
//------------ ComposeQuestion ----------------------------------------------

/// Helper trait to allow composing questions from tuples.
pub trait ComposeQuestion {
    fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()>;
}

impl<F: Flavor> ComposeQuestion for Question<F> {
    fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
        self.compose(target)
    }
}

impl<D: DName> ComposeQuestion for (D, RRType, Class) {
    fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
        try!(target.push_dname_compressed(&self.0));
        try!(target.push_u16(self.1.into()));
        target.push_u16(self.2.into())
    }
}

impl<'a, D: DName> ComposeQuestion for (&'a D, RRType) {
    fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
        try!(target.push_dname_compressed(self.0));
        try!(target.push_u16(self.1.into()));
        target.push_u16(Class::IN.into())
    }
}
*/
<commit_msg>Documentation for bits::question.<commit_after>//! A single question of a DNS message.
//!
//! This module defines the type `Question` which represents an element in
//! the question section of a DNS message.

use std::fmt;
use super::compose::ComposeBytes;
use super::error::{ComposeResult, ParseResult};
use super::iana::{Class, RRType};
use super::name::{AsDName, DName};
use super::parse::ParseBytes;

//------------ Question -----------------------------------------------------

/// A question in a DNS message.
///
/// In DNS, a query is determined by three elements: a domain name, a record
/// type, and a class, collectively called a question. This type represents
/// such a question.
///
/// Questions can be parsed out of existing messages. The `Message` class
/// allows for iterating over all the quesitons in a message, returning
/// values of the `Question` type.
///
/// When constructing a message via the `MessageBuilder` class, you can either
/// pass in `Question` references or use the associated functions
/// `Question::push()` or `Question::push_in()` to construct the questions
/// on the fly from their components.
#[derive(Clone, Debug)]
pub struct Question<'a> {
    /// The domain name of the question.
    qname: DName<'a>,

    /// The record type of the question.
    qtype: RRType,

    /// The class of the quesiton.
    qclass: Class,
}

/// # Creation and Conversion
///
impl<'a> Question<'a> {
    /// Creates a new question from its constituent elements.
    pub fn new(qname: DName<'a>, qtype: RRType, qclass: Class) -> Self {
        Question { qname: qname, qtype: qtype, qclass: qclass }
    }
}

/// # Element Access
///
impl<'a> Question<'a> {
    /// Returns the requested domain name.
    pub fn qname(&self) -> &DName<'a> {
        &self.qname
    }

    /// Returns the requested record type.
    pub fn qtype(&self) -> RRType {
        self.qtype
    }

    /// Returns the requested class.
    pub fn qclass(&self) -> Class {
        self.qclass
    }
}

/// # Parsing and Composing
///
impl<'a> Question<'a> {
    /// Parses a question from the beginning of a parser.
    pub fn parse<P: ParseBytes<'a>>(parser: &mut P) -> ParseResult<Self> {
        Ok(Question::new(try!(parser.parse_dname()),
                         try!(parser.parse_u16()).into(),
                         try!(parser.parse_u16()).into()))
    }

    /// Pushes a question to the end of a compose target.
    pub fn compose<C: ComposeBytes>(&self, target: &mut C)
                                    -> ComposeResult<()> {
        try!(target.push_dname_compressed(&self.qname));
        try!(target.push_u16(self.qtype.into()));
        target.push_u16(self.qclass.into())
    }

    /// Builds a question from its components and pushes it to a target.
    ///
    /// This associate function can be used to streamline message creation.
    /// Instead of first creating a question from its parts, you can push
    /// them to the message directly. In order to allow the message builder
    /// to increase the quesiton counter once pushing is done, this happens
    /// through the `QuestionTarget` trait which `MessageBuilder` implements.
    pub fn push<C, T, N>(target: &mut T, qname: N, qtype: RRType,
                         qclass: Class) -> ComposeResult<()>
                where C: ComposeBytes, T: QuestionTarget<C>, N: AsDName {
        target.compose(|target| {
            try!(target.push_dname_compressed(&qname.as_dname()));
            try!(target.push_u16(qtype.into()));
            target.push_u16(qclass.into())
        })
    }

    /// Builds a question in IN class and pushes it to a target.
    ///
    /// This is the same as `Question::push()` with `Class::IN` as this is
    /// the most common class.
    pub fn push_in<C, T, N>(target: &mut T, qname: N, qtype: RRType)
                            -> ComposeResult<()>
                where C: ComposeBytes, T: QuestionTarget<C>, N: AsDName {
        Question::push(target, qname, qtype, Class::IN)
    }
}

//--- PartialEq

impl<'a, 'b> PartialEq<Question<'b>> for Question<'a> {
    fn eq(&self, other: &Question<'b>) -> bool {
        self.qname == other.qname && self.qtype == other.qtype
             && self.qclass == other.qclass
    }
}

//--- Display

impl<'a> fmt::Display for Question<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) ->  fmt::Result {
        write!(f, "{}\t{}\t{}", self.qname, self.qtype, self.qclass)
    }
}

//------------ QuestionTarget -----------------------------------------------

/// A helper trait for `Question::push()`
pub trait QuestionTarget<C: ComposeBytes> {
    /// Acquires a composition target for pushing a question to.
    ///
    /// The actual composing of the question happens inside the closure
    /// `push`. The implementor can assume `push` to have built exactly
    /// one question if it returns `Ok(())`.
    fn compose<F>(&mut self, push: F) -> ComposeResult<()>
               where F: Fn(&mut C) -> ComposeResult<()>;
}

<|endoftext|>