<commit_before>use super::super::{completer::*, flags, Binary, DirectoryStack, Shell, Variables};
use crate::{sys, types};
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
    let vars_ptr = &shell.variables as *const Variables;
    let dirs_ptr = &shell.directory_stack as *const DirectoryStack;

    // Collects the current list of values from history for completion.
    let history = shell
        .context
        .as_ref()
        .unwrap()
        .history
        .buffers
        .iter()
        // Map each underlying `liner::Buffer` into a `String`.
        .map(|x| x.chars().cloned().collect())
        // Collect each result into a vector to avoid borrowing issues.
        .collect::<Vec<types::Str>>();

    let prompt = shell.prompt();
    let vars = &shell.variables;
    let builtins = &shell.builtins;

    let line = shell.context.as_mut().unwrap().read_line(
        prompt,
        None,
        &mut move |Event { editor, kind }| {
            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => {
                        match (words.into_iter().nth(index), env::current_dir()) {
                            (Some((start, end)), Ok(file)) => {
                                let filename = editor.current_buffer().range(start, end);
                                complete_as_file(&file, &filename, index)
                            }
                            _ => false,
                        }
                    }
                };

                let dir_completer = env::current_dir()
                    .ok()
                    .as_ref()
                    .and_then(|dir| dir.to_str())
                    .map(|dir| IonFileCompleter::new(Some(dir), dirs_ptr, vars_ptr));

                if filename {
                    if let Some(completer) = dir_completer {
                        mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                    }
                } else {
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let words = builtins
                        .keys()
                        .iter()
                        // Add built-in commands to the completer's definitions.
                        .map(|&s| s.to_string())
                        // Add the history list to the completer's definitions.
                        .chain(history.iter().map(|s| s.to_string()))
                        // Add the aliases to the completer's definitions.
                        .chain(vars.aliases().map(|(key, _)| key.to_string()))
                        // Add the list of available functions to the completer's
                        // definitions.
                        .chain(vars.functions().map(|(key, _)| key.to_string()))
                        // Add the list of available variables to the completer's
                        // definitions. TODO: We should make
                        // it free to do String->SmallString
                        //       and mostly free to go back (free if allocated)
                        .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                        .collect();

                    // Initialize a new completer from the definitions collected.
                    let custom_completer = BasicCompleter::new(words);

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| IonFileCompleter::new(Some(s), dirs_ptr, vars_ptr))
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    if let Some(completer) = dir_completer {
                        file_completers.push(completer);
                    }

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        },
    );

    match line {
        Ok(line) => {
            if !line.is_empty() {
                shell.flags |= flags::UNTERMINATED;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            if shell.flow_control.unclosed_block() {
                shell.flow_control.pop();
                Some("".to_string())
            } else {
                shell.exit(shell.previous_status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<commit_msg>Don't handle lines with only whitespace<commit_after>use super::super::{completer::*, flags, Binary, DirectoryStack, Shell, Variables};
use crate::{sys, types};
use liner::{BasicCompleter, CursorPosition, Event, EventKind};
use std::{env, io::ErrorKind, mem, path::PathBuf};

pub(crate) fn readln(shell: &mut Shell) -> Option<String> {
    let vars_ptr = &shell.variables as *const Variables;
    let dirs_ptr = &shell.directory_stack as *const DirectoryStack;

    // Collects the current list of values from history for completion.
    let history = shell
        .context
        .as_ref()
        .unwrap()
        .history
        .buffers
        .iter()
        // Map each underlying `liner::Buffer` into a `String`.
        .map(|x| x.chars().cloned().collect())
        // Collect each result into a vector to avoid borrowing issues.
        .collect::<Vec<types::Str>>();

    let prompt = shell.prompt();
    let vars = &shell.variables;
    let builtins = &shell.builtins;

    let line = shell.context.as_mut().unwrap().read_line(
        prompt,
        None,
        &mut move |Event { editor, kind }| {
            if let EventKind::BeforeComplete = kind {
                let (words, pos) = editor.get_words_and_cursor_position();

                let filename = match pos {
                    CursorPosition::InWord(index) => index > 0,
                    CursorPosition::InSpace(Some(_), _) => true,
                    CursorPosition::InSpace(None, _) => false,
                    CursorPosition::OnWordLeftEdge(index) => index >= 1,
                    CursorPosition::OnWordRightEdge(index) => {
                        match (words.into_iter().nth(index), env::current_dir()) {
                            (Some((start, end)), Ok(file)) => {
                                let filename = editor.current_buffer().range(start, end);
                                complete_as_file(&file, &filename, index)
                            }
                            _ => false,
                        }
                    }
                };

                let dir_completer = env::current_dir()
                    .ok()
                    .as_ref()
                    .and_then(|dir| dir.to_str())
                    .map(|dir| IonFileCompleter::new(Some(dir), dirs_ptr, vars_ptr));

                if filename {
                    if let Some(completer) = dir_completer {
                        mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                    }
                } else {
                    // Creates a list of definitions from the shell environment that
                    // will be used
                    // in the creation of a custom completer.
                    let words = builtins
                        .keys()
                        .iter()
                        // Add built-in commands to the completer's definitions.
                        .map(|&s| s.to_string())
                        // Add the history list to the completer's definitions.
                        .chain(history.iter().map(|s| s.to_string()))
                        // Add the aliases to the completer's definitions.
                        .chain(vars.aliases().map(|(key, _)| key.to_string()))
                        // Add the list of available functions to the completer's
                        // definitions.
                        .chain(vars.functions().map(|(key, _)| key.to_string()))
                        // Add the list of available variables to the completer's
                        // definitions. TODO: We should make
                        // it free to do String->SmallString
                        //       and mostly free to go back (free if allocated)
                        .chain(vars.string_vars().map(|(s, _)| ["$", &s].concat()))
                        .collect();

                    // Initialize a new completer from the definitions collected.
                    let custom_completer = BasicCompleter::new(words);

                    // Creates completers containing definitions from all directories
                    // listed
                    // in the environment's **$PATH** variable.
                    let mut file_completers: Vec<_> = env::var("PATH")
                        .unwrap_or_else(|_| "/bin/".to_string())
                        .split(sys::PATH_SEPARATOR)
                        .map(|s| IonFileCompleter::new(Some(s), dirs_ptr, vars_ptr))
                        .collect();

                    // Also add files/directories in the current directory to the
                    // completion list.
                    if let Some(completer) = dir_completer {
                        file_completers.push(completer);
                    }

                    // Merge the collected definitions with the file path definitions.
                    let completer = MultiCompleter::new(file_completers, custom_completer);

                    // Replace the shell's current completer with the newly-created
                    // completer.
                    mem::replace(&mut editor.context().completer, Some(Box::new(completer)));
                }
            }
        },
    );

    match line {
        Ok(line) => {
            if line.bytes().any(|c| !c.is_ascii_whitespace()) {
                shell.flags |= flags::UNTERMINATED;
            }
            Some(line)
        }
        // Handles Ctrl + C
        Err(ref err) if err.kind() == ErrorKind::Interrupted => None,
        // Handles Ctrl + D
        Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
            if shell.flow_control.unclosed_block() {
                shell.flow_control.pop();
                Some("".to_string())
            } else {
                shell.exit(shell.previous_status);
            }
        }
        Err(err) => {
            eprintln!("ion: liner: {}", err);
            None
        }
    }
}

/// Infer if the given filename is actually a partial filename
fn complete_as_file(current_dir: &PathBuf, filename: &str, index: usize) -> bool {
    let filename = filename.trim();
    let mut file = current_dir.clone();
    file.push(&filename);
    // If the user explicitly requests a file through this syntax then complete as
    // a file
    filename.starts_with('.') ||
    // If the file starts with a dollar sign, it's a variable, not a file
    (!filename.starts_with('$') &&
    // Once we are beyond the first string, assume its a file
    (index > 0 ||
    // If we are referencing a file that exists then just complete to that file
    file.exists() ||
    // If we have a partial file inside an existing directory, e.g. /foo/b when
    // /foo/bar exists, then treat it as file as long as `foo` isn't the
    // current directory, otherwise this would apply to any string `foo`
    file.parent().filter(|parent| parent.exists() && parent != current_dir).is_some()))
    // By default assume its not a file
}
<|endoftext|>


<commit_before>// Test that we correctly generate StorageDead statements for while loop
// conditions on all branches

fn get_bool(c: bool) -> bool {
    c
}

fn while_loop(c: bool) {
    while get_bool(c) {
        if get_bool(c) {
            break;
        }
    }
}

fn main() {
    while_loop(false);
}

// END RUST SOURCE

// START rustc.while_loop.PreCodegen.after.mir
// bb0: {
//     StorageLive(_2);
//     StorageLive(_3);
//     _3 = _1;
//     _2 = const get_bool(move _3) -> bb2;
// }
// bb1: {
//     return;
// }
// bb2: {
//     StorageDead(_3);
//     switchInt(move _2) -> [false: bb4, otherwise: bb3];
// }
// bb3: {
//     StorageDead(_2);
//     StorageLive(_4);
//     StorageLive(_5);
//     _5 = _1;
//     _4 = const get_bool(move _5) -> bb5;
// }
// bb4: {
//     StorageDead(_2);
//     goto -> bb1;
// }
// bb5: {
//     StorageDead(_5);
//     switchInt(_4) -> [false: bb6, otherwise: bb7];
// }
// bb6: {
//     StorageDead(_4);
//     goto -> bb0;
// }
// bb7: {
//     StorageDead(_4);
//     goto -> bb1;
// }
// END rustc.while_loop.PreCodegen.after.mir
<commit_msg>Bless mir-opt/while-storage.rs.<commit_after>// Test that we correctly generate StorageDead statements for while loop
// conditions on all branches

fn get_bool(c: bool) -> bool {
    c
}

fn while_loop(c: bool) {
    while get_bool(c) {
        if get_bool(c) {
            break;
        }
    }
}

fn main() {
    while_loop(false);
}

// END RUST SOURCE

// START rustc.while_loop.PreCodegen.after.mir
// bb0: {
//     StorageLive(_2);
//     StorageLive(_3);
//     _3 = _1;
//     _2 = const get_bool(move _3) -> bb1;
// }
// bb1: {
//     StorageDead(_3);
//     switchInt(_2) -> [false: bb6, otherwise: bb2];
// }
// bb2: {
//      StorageLive(_4);
//      StorageLive(_5);
//      _5 = _1;
//      _4 = const get_bool(move _5) -> bb3;
// }
// bb3: {
//      StorageDead(_5);
//      switchInt(_4) -> [false: bb4, otherwise: bb5];
// }
// bb4: {
//      StorageDead(_4);
//      StorageDead(_2);
//      goto -> bb0;
// }
//  bb5: {
//      StorageDead(_4);
//      goto -> bb6;
//  }
//  bb6: {
//      StorageDead(_2);
//      return;
//  }
// END rustc.while_loop.PreCodegen.after.mir
<|endoftext|>


<commit_before>use futures::{FutureExt, TryStreamExt};
use std::time::{Duration, Instant};
use tokio::timer::Delay;
use tokio_postgres::error::SqlState;
use tokio_postgres::NoTls;

async fn smoke_test(s: &str) {
    let (mut client, connection) = tokio_postgres::connect(s, NoTls).await.unwrap();
    let connection = connection.map(|e| e.unwrap());
    tokio::spawn(connection);

    let stmt = client.prepare("SELECT $1::INT").await.unwrap();
    let rows = client
        .query(&stmt, &[&1i32])
        .try_collect::<Vec<_>>()
        .await
        .unwrap();
    assert_eq!(rows[0].get::<_, i32>(0), 1i32);
}

#[tokio::test]
#[ignore] // FIXME doesn't work with our docker-based tests :(
async fn unix_socket() {
    smoke_test("host=/var/run/postgresql port=5433 user=postgres").await;
}

#[tokio::test]
async fn tcp() {
    smoke_test("host=localhost port=5433 user=postgres").await;
}

#[tokio::test]
async fn multiple_hosts_one_port() {
    smoke_test("host=foobar.invalid,localhost port=5433 user=postgres").await;
}

#[tokio::test]
async fn multiple_hosts_multiple_ports() {
    smoke_test("host=foobar.invalid,localhost port=5432,5433 user=postgres").await;
}

#[tokio::test]
async fn wrong_port_count() {
    tokio_postgres::connect("host=localhost port=5433,5433 user=postgres", NoTls)
        .await
        .err()
        .unwrap();
}

#[tokio::test]
async fn target_session_attrs_ok() {
    let _ = tokio_postgres::connect(
        "host=localhost port=5433 user=postgres target_session_attrs=read-write",
        NoTls,
    )
    .await
    .unwrap();
}

#[tokio::test]
async fn target_session_attrs_err() {
    tokio_postgres::connect(
        "host=localhost port=5433 user=postgres target_session_attrs=read-write
         options='-c default_transaction_read_only=on'",
        NoTls,
    )
    .await
    .err()
    .unwrap();
}

/*
#[test]
fn cancel_query() {
    let mut runtime = Runtime::new().unwrap();

    let connect = tokio_postgres::connect("host=localhost port=5433 user=postgres", NoTls);
    let (mut client, connection) = runtime.block_on(connect).unwrap();
    let connection = connection.map_err(|e| panic!("{}", e));
    runtime.spawn(connection);

    let sleep = client
        .simple_query("SELECT pg_sleep(100)")
        .for_each(|_| Ok(()))
        .then(|r| match r {
            Ok(_) => panic!("unexpected success"),
            Err(ref e) if e.code() == Some(&SqlState::QUERY_CANCELED) => Ok::<(), ()>(()),
            Err(e) => panic!("unexpected error {}", e),
        });
    let cancel = Delay::new(Instant::now() + Duration::from_millis(100))
        .then(|r| {
            r.unwrap();
            client.cancel_query(NoTls)
        })
        .then(|r| {
            r.unwrap();
            Ok::<(), ()>(())
        });

    let ((), ()) = runtime.block_on(sleep.join(cancel)).unwrap();
}
*/
<commit_msg>Use smoke_test for target_session_attrs_ok<commit_after>use futures::{FutureExt, TryStreamExt};
use std::time::{Duration, Instant};
use tokio::timer::Delay;
use tokio_postgres::error::SqlState;
use tokio_postgres::NoTls;

async fn smoke_test(s: &str) {
    let (mut client, connection) = tokio_postgres::connect(s, NoTls).await.unwrap();
    let connection = connection.map(|e| e.unwrap());
    tokio::spawn(connection);

    let stmt = client.prepare("SELECT $1::INT").await.unwrap();
    let rows = client
        .query(&stmt, &[&1i32])
        .try_collect::<Vec<_>>()
        .await
        .unwrap();
    assert_eq!(rows[0].get::<_, i32>(0), 1i32);
}

#[tokio::test]
#[ignore] // FIXME doesn't work with our docker-based tests :(
async fn unix_socket() {
    smoke_test("host=/var/run/postgresql port=5433 user=postgres").await;
}

#[tokio::test]
async fn tcp() {
    smoke_test("host=localhost port=5433 user=postgres").await;
}

#[tokio::test]
async fn multiple_hosts_one_port() {
    smoke_test("host=foobar.invalid,localhost port=5433 user=postgres").await;
}

#[tokio::test]
async fn multiple_hosts_multiple_ports() {
    smoke_test("host=foobar.invalid,localhost port=5432,5433 user=postgres").await;
}

#[tokio::test]
async fn wrong_port_count() {
    tokio_postgres::connect("host=localhost port=5433,5433 user=postgres", NoTls)
        .await
        .err()
        .unwrap();
}

#[tokio::test]
async fn target_session_attrs_ok() {
    smoke_test("host=localhost port=5433 user=postgres target_session_attrs=read-write").await;
}

#[tokio::test]
async fn target_session_attrs_err() {
    tokio_postgres::connect(
        "host=localhost port=5433 user=postgres target_session_attrs=read-write
         options='-c default_transaction_read_only=on'",
        NoTls,
    )
    .await
    .err()
    .unwrap();
}

/*
#[test]
fn cancel_query() {
    let mut runtime = Runtime::new().unwrap();

    let connect = tokio_postgres::connect("host=localhost port=5433 user=postgres", NoTls);
    let (mut client, connection) = runtime.block_on(connect).unwrap();
    let connection = connection.map_err(|e| panic!("{}", e));
    runtime.spawn(connection);

    let sleep = client
        .simple_query("SELECT pg_sleep(100)")
        .for_each(|_| Ok(()))
        .then(|r| match r {
            Ok(_) => panic!("unexpected success"),
            Err(ref e) if e.code() == Some(&SqlState::QUERY_CANCELED) => Ok::<(), ()>(()),
            Err(e) => panic!("unexpected error {}", e),
        });
    let cancel = Delay::new(Instant::now() + Duration::from_millis(100))
        .then(|r| {
            r.unwrap();
            client.cancel_query(NoTls)
        })
        .then(|r| {
            r.unwrap();
            Ok::<(), ()>(())
        });

    let ((), ()) = runtime.block_on(sleep.join(cancel)).unwrap();
}
*/
<|endoftext|>


<commit_before>/**
 * Reimplementation of this file
 * http://algs4.cs.princeton.edu/12oop/Point2D.java.html
 *
 * in Rust
 */
pub struct Point2D {
    pub x : f32,
    pub y : f32
}

impl Point2D {
    pub fn r(&self) -> f32 {
        (self.x.powf(2.0) + self.y.powf(2.0)).sqrt()
    }
}

<commit_msg>Adding Point2D source code<commit_after>/**
 * Reimplementation of this file
 * http://algs4.cs.princeton.edu/12oop/Point2D.java.html
 *
 * in Rust
 */
pub struct Point2D {
    pub x : f32,
    pub y : f32
}

impl Point2D {
    pub fn r(&self) -> f32 {
        (self.x.powf(2.0) + self.y.powf(2.0)).sqrt()
    }

    pub fn theta(&self) -> f32 {
        (
    }
}

<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;
extern crate french_press;
extern crate test_utils;

use test::Bencher;
use french_press::*;

#[bench]
fn small_no_gc(b: &mut Bencher) {
    let mut mgr = init_gc();
    mgr.alloc(test_utils::make_num(0.), None).unwrap();
    mgr.alloc(test_utils::make_num(1.), None).unwrap();
    mgr.alloc(test_utils::make_num(2.), None).unwrap();
}
<commit_msg>Working on benchmarks<commit_after>#![feature(test)]
#![feature(box_patterns, box_syntax)]
extern crate test;
extern crate french_press;
extern crate jsrs_common;

use std::cell::RefCell;
use std::rc::Rc;

use test::Bencher;
use french_press::*;
use french_press::alloc::AllocBox;
use jsrs_common::ast::{Exp, Stmt};
use jsrs_common::backend::Backend;
use jsrs_common::types::js_fn::JsFnStruct;
use jsrs_common::types::js_obj::JsObjStruct;
use jsrs_common::types::js_str::JsStrStruct;
use jsrs_common::types::js_var::{JsKey, JsPtrEnum, JsPtrTag, JsType, JsVar};

fn make_num(i: f64) -> JsVar {
    JsVar::new(JsType::JsNum(i))
}

fn make_str(s: &str) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsStr));
    (var, JsPtrEnum::JsStr(JsStrStruct::new(s)))
}

fn make_obj(kvs: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>, heap: Rc<RefCell<AllocBox>>) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsObj));
    (var, JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs, &mut *heap.borrow_mut())))
}

//#[bench]
fn small_no_gc(b: &mut Bencher) {
    b.iter(|| {
        let mut mgr = init_gc();
        mgr.alloc(make_num(0.), None).unwrap();
        mgr.alloc(make_num(1.), None).unwrap();
        mgr.alloc(make_num(2.), None).unwrap();
        mgr.pop_scope(None, false).unwrap();
    });
}

//#[bench]
fn deep_lookup(b: &mut Bencher) {
    let mut mgr = init_gc();
    mgr.push_scope(&Exp::Call(box Exp::Undefined, vec![]));
    let var = make_num(0.);
    let bnd = var.binding.clone();
    mgr.alloc(var, None).unwrap();
    for _ in 0..1000 {
        mgr.push_scope(&Exp::Undefined);
    }
    b.iter(|| {
        mgr.load(&bnd).unwrap();
    });
}

#[bench]
fn leak_many(b: &mut Bencher) {
    let mut mgr = init_gc();
    for _ in 0..100 {
        mgr.push_scope(&Exp::Call(box Exp::Undefined, vec![]));

        let (var, ptr) = make_str("test");
        let key = JsKey::JsSym("true".to_string());
        let kvs = vec![(key.clone(), var, Some(ptr))];

        let (var, ptr) = make_obj(kvs, mgr.alloc_box.clone());
        let bnd = var.binding.clone();
        mgr.alloc(var, Some(ptr)).unwrap();

        let copy = mgr.load(&bnd);
        let (mut var, mut ptr) = copy.unwrap();

        for _ in 0..1000 {
            let (leak_var, leak_ptr) = make_str("test");
            match *&mut ptr {
                Some(JsPtrEnum::JsObj(ref mut obj)) => {
                    obj.add_key(key.clone(), leak_var, Some(leak_ptr), &mut *(mgr.alloc_box.borrow_mut()));
                },
                _ => unreachable!()
            }
        }
        mgr.store(var, ptr).unwrap();
    }
    let f = || { mgr.pop_scope(None, true).unwrap(); };
    b.iter(f);
}
<|endoftext|>


<commit_before>//! Middleware that blocks requests with no user-agent header

use super::prelude::*;

use crate::util::request_header;

// Can't derive debug because of Handler.
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct RequireUserAgent {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for RequireUserAgent {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for RequireUserAgent {
    fn call(&self, req: &mut dyn RequestExt) -> AfterResult {
        let has_user_agent = request_header(req, header::USER_AGENT) != "";
        let is_download = req.path().ends_with("download");
        if !has_user_agent && !is_download {
            super::log_request::add_custom_metadata(req, "cause", "no user agent");
            let body = format!(
                include_str!("no_user_agent_message.txt"),
                request_header(req, "x-request-id"),
            );

            Response::builder()
                .status(StatusCode::FORBIDDEN)
                .header(header::CONTENT_LENGTH, body.len())
                .body(Body::from_vec(body.into_bytes()))
                .map_err(box_error)
        } else {
            self.handler.as_ref().unwrap().call(req)
        }
    }
}
<commit_msg>Treat user_agent="Amazon CloudFront" as emtpy<commit_after>//! Middleware that blocks requests with no user-agent header

use super::prelude::*;

use crate::util::request_header;

// Can't derive debug because of Handler.
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct RequireUserAgent {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for RequireUserAgent {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for RequireUserAgent {
    fn call(&self, req: &mut dyn RequestExt) -> AfterResult {
        let agent = request_header(req, header::USER_AGENT);
        let has_user_agent = agent != "" && agent != "Amazon CloudFront";
        let is_download = req.path().ends_with("download");
        if !has_user_agent && !is_download {
            super::log_request::add_custom_metadata(req, "cause", "no user agent");
            let body = format!(
                include_str!("no_user_agent_message.txt"),
                request_header(req, "x-request-id"),
            );

            Response::builder()
                .status(StatusCode::FORBIDDEN)
                .header(header::CONTENT_LENGTH, body.len())
                .body(Body::from_vec(body.into_bytes()))
                .map_err(box_error)
        } else {
            self.handler.as_ref().unwrap().call(req)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Propverify authors
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/////////////////////////////////////////////////////////////////
// FFI wrapper for KLEE symbolic execution tool
/////////////////////////////////////////////////////////////////

use std::default::Default;
use std::os::raw;

#[link(name = "kleeRuntest")]
extern "C" {
    fn klee_make_symbolic(data: *mut raw::c_void, length: usize, name: *const raw::c_char);
    fn klee_assume(cond: usize);
    fn klee_abort() -> !;
    fn klee_silent_exit(_ignored: u32) -> !;
    fn klee_is_replay() -> i32;
}

// Create an abstract value of type <T>
//
// This should only be used on types that occupy contiguous memory
// and where all possible bit-patterns are legal.
// e.g., u8/i8, ... u128/i128, f32/f64
pub fn abstract_value<T: Default>() -> T {
    let mut r = T::default();
    unsafe {
        let data = std::mem::transmute(&mut r);
        let length = std::mem::size_of::<T>();
        let null = 0 as *const i8;
        klee_make_symbolic(data, length, null)
    }
    return r;
}

// Add an assumption
pub fn assume(cond: bool) {
    unsafe { klee_assume(if cond { 1 } else { 0 }) }
}

// Reject the current execution with a verification failure.
//
// In almost all circumstances, report_error should
// be used instead because it generates an error message.
pub fn abort() -> ! {
    unsafe { klee_abort() }
}

// Reject the current execution path with a verification success.
// This is equivalent to assume(false)
// and the opposite of report_error.
//
// Typical usage is in generating symbolic values when the value
// does not meet some criteria.
pub fn reject() -> ! {
    unsafe { klee_silent_exit(0) }
}

// Detect whether the program is being run symbolically in KLEE
// or being replayed using the kleeRuntest runtime.
//
// This is used to decide whether to display the values of
// variables that may be either symbolic or concrete.
pub fn is_replay() -> bool {
    unsafe { klee_is_replay() != 0 }
}

// Reject the current execution with a verification failure
// and an error message.
pub fn report_error(message: &str) -> ! {
    // Mimic the format of klee_report_error
    // (We don't use klee_report_error because it is not
    // supported by the kleeRuntest library.)
    eprintln!("KLEE: ERROR:{}", message);
    abort();
}

// Check an assertion
pub fn verify(cond: bool) {
    if !cond {
        report_error("verification failed");
    }
}

// Declare that failure is the expected behaviour
pub fn expect_raw(msg: &str) {
    eprintln!("VERIFIER_EXPECT: {}", msg)
}

// Declare that failure is the expected behaviour
pub fn expect(msg: Option<&str>) {
    match msg {
        None => eprintln!("VERIFIER_EXPECT: should_panic"),
        Some(msg) => eprintln!("VERIFIER_EXPECT: should_panic(expected = \"{}\")", msg)
    }
}

/////////////////////////////////////////////////////////////////
// End
/////////////////////////////////////////////////////////////////
<commit_msg>Add assert macros to Klee<commit_after>// Copyright 2020 The Propverify authors
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/////////////////////////////////////////////////////////////////
// FFI wrapper for KLEE symbolic execution tool
/////////////////////////////////////////////////////////////////

use std::default::Default;
use std::os::raw;

#[link(name = "kleeRuntest")]
extern "C" {
    fn klee_make_symbolic(data: *mut raw::c_void, length: usize, name: *const raw::c_char);
    fn klee_assume(cond: usize);
    fn klee_abort() -> !;
    fn klee_silent_exit(_ignored: u32) -> !;
    fn klee_is_replay() -> i32;
}

// Create an abstract value of type <T>
//
// This should only be used on types that occupy contiguous memory
// and where all possible bit-patterns are legal.
// e.g., u8/i8, ... u128/i128, f32/f64
pub fn abstract_value<T: Default>() -> T {
    let mut r = T::default();
    unsafe {
        let data = std::mem::transmute(&mut r);
        let length = std::mem::size_of::<T>();
        let null = 0 as *const i8;
        klee_make_symbolic(data, length, null)
    }
    return r;
}

// Add an assumption
pub fn assume(cond: bool) {
    unsafe { klee_assume(if cond { 1 } else { 0 }) }
}

// Reject the current execution with a verification failure.
//
// In almost all circumstances, report_error should
// be used instead because it generates an error message.
pub fn abort() -> ! {
    unsafe { klee_abort() }
}

// Reject the current execution path with a verification success.
// This is equivalent to assume(false)
// and the opposite of report_error.
//
// Typical usage is in generating symbolic values when the value
// does not meet some criteria.
pub fn reject() -> ! {
    unsafe { klee_silent_exit(0) }
}

// Detect whether the program is being run symbolically in KLEE
// or being replayed using the kleeRuntest runtime.
//
// This is used to decide whether to display the values of
// variables that may be either symbolic or concrete.
pub fn is_replay() -> bool {
    unsafe { klee_is_replay() != 0 }
}

// Reject the current execution with a verification failure
// and an error message.
pub fn report_error(message: &str) -> ! {
    // Mimic the format of klee_report_error
    // (We don't use klee_report_error because it is not
    // supported by the kleeRuntest library.)
    eprintln!("KLEE: ERROR:{}", message);
    abort();
}

// Check an assertion
pub fn verify(cond: bool) {
    if !cond {
        report_error("verification failed");
    }
}

// Declare that failure is the expected behaviour
pub fn expect_raw(msg: &str) {
    eprintln!("VERIFIER_EXPECT: {}", msg)
}

// Declare that failure is the expected behaviour
pub fn expect(msg: Option<&str>) {
    match msg {
        None => eprintln!("VERIFIER_EXPECT: should_panic"),
        Some(msg) => eprintln!("VERIFIER_EXPECT: should_panic(expected = \"{}\")", msg)
    }
}

#[macro_export]
macro_rules! assert {
    ($cond:expr) => {
        if ! $cond {
            eprintln!("VERIFIER: assertion failed: {}", stringify!($cond));
            abort();
        }
    };
    // ($cond:expr,) => { ... };
    // ($cond:expr, $($arg:tt)+) => { ... };
}

#[macro_export]
macro_rules! assert_eq {
    ($left:expr, $right:expr) => { $crate::assert!(($left) == ($right)); };
    // ($left:expr, $right:expr,) => { ... };
    // ($left:expr, $right:expr, $($arg:tt)+) => { ... };
}

#[macro_export]
macro_rules! assert_ne {
    ($left:expr, $right:expr) => { $crate::assert!(($left) != ($right)); };
    // ($left:expr, $right:expr,) => { ... };
    // ($left:expr, $right:expr, $($arg:tt)+) => { ... };
}

/////////////////////////////////////////////////////////////////
// End
/////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>use errors::crypto::CryptoError;

pub struct PointG1 {

}

pub struct PointG2 {

}

pub struct GroupOrderElement {

}

pub struct Pair {

}

impl PointG1 {
    pub fn new() -> Result<PointG1, CryptoError> {
        // generate random point from the group G1
        unimplemented!();
    }

    pub fn mul(&mut self, gr: &mut GroupOrderElement) -> Result<PointG1, CryptoError> {
        unimplemented!();
    }

    pub fn add(&mut self, q: &mut PointG1) -> Result<&mut PointG1, CryptoError> {
        //unimplemented!();
        Ok(self)
    }

    pub fn to_string(&mut self) -> Result<String, CryptoError> {
        unimplemented!();
    }

    pub fn to_bytes(&mut self, b: &mut [u8]) {
        unimplemented!();
    }

    pub fn from_bytes(b: &[u8]) -> PointG1 {
        unimplemented!();
    }
}

impl GroupOrderElement {
    pub fn new() -> Result<GroupOrderElement, CryptoError> {
        // returns random element in 0, ..., GroupOrder-1
        unimplemented!();
    }

    pub fn pow(&mut self, e: &mut GroupOrderElement) -> Result<GroupOrderElement, CryptoError> {
        // need to use powmod where n - group_order
        unimplemented!();
    }

    pub fn add(&mut self, r: &GroupOrderElement) -> Result<&mut GroupOrderElement, CryptoError> {
        //need to use rmod after add
        //unimplemented!();
        Ok(self)
    }

    pub fn inverse(&mut self) -> Result<GroupOrderElement, CryptoError> {
        unimplemented!();
    }

    pub fn to_string(&mut self) -> Result<String, CryptoError> {
        unimplemented!();
    }

    pub fn to_bytes(&mut self, b: &mut [u8]) {
        unimplemented!();
    }

    pub fn from_bytes(b: &[u8]) -> GroupOrderElement {
        unimplemented!();
    }
}<commit_msg>added result<commit_after>use errors::crypto::CryptoError;

pub struct PointG1 {

}

pub struct PointG2 {

}

pub struct GroupOrderElement {

}

pub struct Pair {

}

impl PointG1 {
    pub fn new() -> Result<PointG1, CryptoError> {
        // generate random point from the group G1
        unimplemented!();
    }

    pub fn mul(&mut self, gr: &mut GroupOrderElement) -> Result<PointG1, CryptoError> {
        unimplemented!();
    }

    pub fn add(&mut self, q: &mut PointG1) -> Result<&mut PointG1, CryptoError> {
        //unimplemented!();
        Ok(self)
    }

    pub fn to_string(&mut self) -> Result<String, CryptoError> {
        unimplemented!();
    }

    pub fn to_bytes(&mut self) -> Result<Vec<u8>, CryptoError> {
        unimplemented!();
    }

    pub fn from_bytes(b: &[u8]) -> Result<PointG1, CryptoError> {
        unimplemented!();
    }
}

impl GroupOrderElement {
    pub fn new() -> Result<GroupOrderElement, CryptoError> {
        // returns random element in 0, ..., GroupOrder-1
        unimplemented!();
    }

    pub fn pow(&mut self, e: &mut GroupOrderElement) -> Result<GroupOrderElement, CryptoError> {
        // need to use powmod where n - group_order
        unimplemented!();
    }

    pub fn add(&mut self, r: &GroupOrderElement) -> Result<&mut GroupOrderElement, CryptoError> {
        //need to use rmod after add
        //unimplemented!();
        Ok(self)
    }

    pub fn inverse(&mut self) -> Result<GroupOrderElement, CryptoError> {
        unimplemented!();
    }

    pub fn to_string(&mut self) -> Result<String, CryptoError> {
        unimplemented!();
    }

    pub fn to_bytes(&mut self, b: &mut [u8]) -> Result<Vec<u8>, CryptoError> {
        unimplemented!();
    }

    pub fn from_bytes(b: &[u8]) -> Result<GroupOrderElement, CryptoError> {
        unimplemented!();
    }
}<|endoftext|>


<commit_before>#![feature(const_raw_ptr_deref)]
#![feature(const_ptr_offset_from)]
#![feature(ptr_offset_from)]

#[repr(C)]
struct Struct {
    data: u8,
    field: u8,
}

pub const DIFFERENT_ALLOC: usize = {
    //~^ NOTE
    let uninit = std::mem::MaybeUninit::<Struct>::uninit();
    let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
    let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
    let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
    let offset = unsafe { field_ptr.offset_from(base_ptr) };
    offset as usize
};

pub const NOT_PTR: usize = {
    //~^ NOTE
    unsafe { (42 as *const u8).offset_from(&5u8) as usize }
};

pub const NOT_MULTIPLE_OF_SIZE: usize = {
    //~^ NOTE
    let data = [5u8, 6, 7];
    let base_ptr = data.as_ptr();
    let field_ptr = &data[1] as *const u8 as *const u16;
    let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) };
    offset as usize
};

fn main() {}
<commit_msg>Ignore a test on musl because its ui output differs<commit_after>// ingoring on musl because it's ui output hides libcore backtraces
// ignore-musl

#![feature(const_raw_ptr_deref)]
#![feature(const_ptr_offset_from)]
#![feature(ptr_offset_from)]

#[repr(C)]
struct Struct {
    data: u8,
    field: u8,
}

pub const DIFFERENT_ALLOC: usize = {
    //~^ NOTE
    let uninit = std::mem::MaybeUninit::<Struct>::uninit();
    let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
    let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
    let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
    let offset = unsafe { field_ptr.offset_from(base_ptr) };
    offset as usize
};

pub const NOT_PTR: usize = {
    //~^ NOTE
    unsafe { (42 as *const u8).offset_from(&5u8) as usize }
};

pub const NOT_MULTIPLE_OF_SIZE: usize = {
    //~^ NOTE
    let data = [5u8, 6, 7];
    let base_ptr = data.as_ptr();
    let field_ptr = &data[1] as *const u8 as *const u16;
    let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) };
    offset as usize
};

fn main() {}
<|endoftext|>


<commit_before>extern crate rusoto_mock;

use ::{CloudWatch, CloudWatchClient, PutMetricDataInput, Dimension, MetricDatum};

use rusoto_core::{Region, SignedRequest};
use self::rusoto_mock::*;

#[test]
fn should_serialize_complex_metric_data_params() {
    let mock = MockRequestDispatcher::with_status(200)
        .with_body("")
        .with_request_checker(|request: &SignedRequest| {
            assert_eq!("POST", request.method);
            assert_eq!("/", request.path);
            assert_eq!(None, request.payload);
            assert_eq!(request.params.get("Namespace"),
                        Some(&Some("TestNamespace".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.MetricName"),
                        Some(&Some("buffers".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Unit"),
                        Some(&Some("Bytes".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Value"),
                        Some(&Some("1".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Dimensions.member.1.Name"),
                        Some(&Some("foo".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Dimensions.member.1.Value"),
                        Some(&Some("bar".to_owned())));

        });
    let metric_data = vec![MetricDatum {
                                dimensions: Some(vec![Dimension {
                                                            name: "foo".to_string(),
                                                            value: "bar".to_string(),
                                                        }]),
                                metric_name: "buffers".to_string(),
                                statistic_values: None,
                                timestamp: None,
                                unit: Some("Bytes".to_string()),
                                value: Some(1.0),
                            }];
    let request = PutMetricDataInput {
        namespace: "TestNamespace".to_string(),
        metric_data: metric_data,
    };

    let client = CloudWatchClient::new(mock, MockCredentialsProvider, Region::UsEast1);
    let response = client.put_metric_data(&request).unwrap();
    println!("{:#?}", response);
}<commit_msg>fix custom_tests for cloudwatch with new botocore version<commit_after>extern crate rusoto_mock;

use ::{CloudWatch, CloudWatchClient, PutMetricDataInput, Dimension, MetricDatum};

use rusoto_core::{Region, SignedRequest};
use self::rusoto_mock::*;

#[test]
fn should_serialize_complex_metric_data_params() {
    let mock = MockRequestDispatcher::with_status(200)
        .with_body("")
        .with_request_checker(|request: &SignedRequest| {
            assert_eq!("POST", request.method);
            assert_eq!("/", request.path);
            assert_eq!(None, request.payload);
            assert_eq!(request.params.get("Namespace"),
                        Some(&Some("TestNamespace".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.MetricName"),
                        Some(&Some("buffers".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Unit"),
                        Some(&Some("Bytes".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Value"),
                        Some(&Some("1".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Dimensions.member.1.Name"),
                        Some(&Some("foo".to_owned())));
            assert_eq!(request.params.get("MetricData.member.1.Dimensions.member.1.Value"),
                        Some(&Some("bar".to_owned())));

        });
    let metric_data = vec![MetricDatum {
                                dimensions: Some(vec![Dimension {
                                                            name: "foo".to_string(),
                                                            value: "bar".to_string(),
                                                        }]),
                                metric_name: "buffers".to_string(),
                                statistic_values: None,
                                timestamp: None,
                                unit: Some("Bytes".to_string()),
                                value: Some(1.0),
                                ..Default::default()
                            }];
    let request = PutMetricDataInput {
        namespace: "TestNamespace".to_string(),
        metric_data: metric_data,
    };

    let client = CloudWatchClient::new(mock, MockCredentialsProvider, Region::UsEast1);
    let response = client.put_metric_data(&request).unwrap();
    println!("{:#?}", response);
}<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alexander Batischev <eual.jp@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate winapi;

use self::winapi::shared::minwindef::DWORD;
use self::winapi::um::handleapi::CloseHandle;
use self::winapi::um::processthreadsapi::OpenProcess;
use self::winapi::um::synchapi::WaitForSingleObject;
use self::winapi::um::winbase::{WAIT_FAILED, WAIT_OBJECT_0};
use self::winapi::um::winnt::{HANDLE, SYNCHRONIZE};

pub type Pid = DWORD;

pub struct ProcessChecker {
    dead: bool,
    handle: HANDLE,
}

impl ProcessChecker {
    pub fn new(process_id: self::Pid) -> Self {
        #[allow(non_snake_case)]
        let FALSE = 0i32;
        let h = unsafe { OpenProcess(SYNCHRONIZE, FALSE, process_id as DWORD) };
        Self {
            dead: h.is_null(),
            handle: h,
        }
    }

    pub fn is_dead(&mut self) -> bool {
        if !self.dead {
            self.dead = unsafe {
                let status = WaitForSingleObject(self.handle, 0);
                status == WAIT_OBJECT_0 || status == WAIT_FAILED
            }
        }

        self.dead
    }
}

impl Drop for ProcessChecker {
    fn drop(&mut self) {
        unsafe {
            CloseHandle(self.handle);
        }
    }
}

pub fn supports_pid_checks(_pid: self::Pid) -> bool {
    true
}
<commit_msg>Clippy on Windows: also ignore the self warning<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alexander Batischev <eual.jp@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate winapi;

use self::winapi::shared::minwindef::DWORD;
use self::winapi::um::handleapi::CloseHandle;
use self::winapi::um::processthreadsapi::OpenProcess;
use self::winapi::um::synchapi::WaitForSingleObject;
use self::winapi::um::winbase::{WAIT_FAILED, WAIT_OBJECT_0};
use self::winapi::um::winnt::{HANDLE, SYNCHRONIZE};

pub type Pid = DWORD;

pub struct ProcessChecker {
    dead: bool,
    handle: HANDLE,
}

impl ProcessChecker {
    pub fn new(process_id: self::Pid) -> Self {
        #[allow(non_snake_case)]
        let FALSE = 0i32;
        let h = unsafe { OpenProcess(SYNCHRONIZE, FALSE, process_id as DWORD) };
        Self {
            dead: h.is_null(),
            handle: h,
        }
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn is_dead(&mut self) -> bool {
        if !self.dead {
            self.dead = unsafe {
                let status = WaitForSingleObject(self.handle, 0);
                status == WAIT_OBJECT_0 || status == WAIT_FAILED
            }
        }

        self.dead
    }
}

impl Drop for ProcessChecker {
    fn drop(&mut self) {
        unsafe {
            CloseHandle(self.handle);
        }
    }
}

pub fn supports_pid_checks(_pid: self::Pid) -> bool {
    true
}
<|endoftext|>


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

use raw::*;

use ::*;
use super::super::*;

use std::iter::Map;
use std::slice;
use std::slice::Iter;
use std::os::raw as ctype;

// TODO: Clean this up, as a lot is duplicated/copied from elsewhere, use cstr macro

#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
/// Data that is returned by both `GetPropertyReply` and `PropertyChange` events.
pub enum PropertyData<'a> {
    Str(&'a str),
    OsdStr(&'a str),
    Flag(bool),
    Int64(i64),
    Double(ctype::c_double),
}

impl<'a> PropertyData<'a> {
    fn from_raw(format: mpv_format, ptr: *mut ctype::c_void) -> Result<PropertyData<'a>> {
        debug_assert!(!ptr.is_null());
        match format {
            mpv_format::MPV_FORMAT_FLAG => Ok(PropertyData::Flag(unsafe { *(ptr as *mut bool) })),
            mpv_format::MPV_FORMAT_STRING => {
                let char_ptr = unsafe { *(ptr as *mut *mut ctype::c_char) };
                Ok(PropertyData::Str(
                    mpv_cstr_to_str!(unsafe { CStr::from_ptr(char_ptr) })?,
                ))
            }
            mpv_format::MPV_FORMAT_OSD_STRING => {
                let char_ptr = unsafe { *(ptr as *mut *mut ctype::c_char) };
                Ok(PropertyData::OsdStr(
                    mpv_cstr_to_str!(unsafe { CStr::from_ptr(char_ptr) })?,
                ))
            }
            mpv_format::MPV_FORMAT_DOUBLE => {
                Ok(PropertyData::Double(unsafe { *(ptr as *mut f64) }))
            }
            mpv_format::MPV_FORMAT_INT64 => Ok(PropertyData::Int64(unsafe { *(ptr as *mut i64) })),
            mpv_format::MPV_FORMAT_NONE => unreachable!(),
            _ => unimplemented!(),
        }
    }
}

#[derive(Clone, Debug)]
/// Wrapper around an `Iterator` that yields the `str` of `Event::ClientMessage`
pub struct MessageIter<'a>(
    Map<Iter<'a, *const i8>, fn(&'a *const i8) -> Result<&'a str>>,
    usize,
);

impl<'a> Iterator for MessageIter<'a> {
    type Item = Result<&'a str>;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.1, Some(self.1))
    }
}

impl<'a> ExactSizeIterator for MessageIter<'a> {}

impl<'a> PartialEq for MessageIter<'a> {
    fn eq(&self, rhs: &Self) -> bool {
        if self.1 == rhs.len() {
            // TODO: Any way to avoid clone?
            self.0.clone().eq(rhs.0.clone())
        } else {
            false
        }
    }
}

#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq)]
pub enum Event<'a> {
    /// Received when the player is shutting down
    Shutdown,
    /// *Has not been tested*, received when explicitly asked to MPV
    LogMessage {
        prefix: &'a str,
        level: &'a str,
        text: &'a str,
        log_level: LogLevel,
    },
    /// Received when using get_property_async
    GetPropertyReply {
        name: &'a str,
        result: PropertyData<'a>,
        reply_userdata: u64,
    },
    /// Received when using set_property_async
    SetPropertyReply(u64),
    /// Received when using command_async
    CommandReply(u64),
    /// Event received when a new file is playing
    StartFile,
    /// Event received when the file being played currently has stopped, for an error or not
    EndFile(EndFileReason),
    /// Event received when a file has been *loaded*, but has not been started
    FileLoaded,
    TracksChanged,
    /// Deprecated
    TrackSwitched,
    /// Received when the player has no more files to play and is in an idle state
    Idle,
    /// The player paused playback
    Pause,
    /// The player started playback again
    Unpause,
    Tick,
    ClientMessage(MessageIter<'a>),
    VideoReconfig,
    AudioReconfig,
    MetadataUpdate,
    /// The player changed current position
    Seek,
    PlaybackRestart,
    /// Received when used with observe_property
    PropertyChange {
        name: &'a str,
        change: PropertyData<'a>,
        reply_userdata: u64,
    },
    ChapterChange,
    /// Received when the Event Queue is full
    QueueOverflow,
    /// Unused event
    Unused,
}

impl Mpv {
    /// Wait for `timeout` seconds for an `Event`. Passing `0` as `timeout` will poll.
    /// For more information, as always, see the mpv-sys docs of `mpv_wait_event`.
    ///
    /// Returns `Some(Err(...))` if there was invalid utf-8, or if either an
    /// `MPV_EVENT_GET_PROPERTY_REPLY`, `MPV_EVENT_SET_PROPERTY_REPLY`, `MPV_EVENT_COMMAND_REPLY`,
    /// or `MPV_EVENT_PROPERTY_CHANGE` event failed, or if `MPV_EVENT_END_FILE` reported an error.
    ///
    /// # Unsafety
    /// Calling this function simultaneosly multiple times may result in data races. Internally,
    /// `EventIter` also uses `wait_event`. Do not combine the two.
    pub unsafe fn wait_event(&self, timeout: f64) -> Option<Result<Event>> {
        let event = &*mpv_wait_event(self.ctx, timeout);

        match event.event_id {
            mpv_event_id::MPV_EVENT_NONE => None,
            mpv_event_id::MPV_EVENT_SHUTDOWN => Some(Ok(Event::Shutdown)),
            mpv_event_id::MPV_EVENT_LOG_MESSAGE => {
                let log_message = *(event.data as *mut mpv_event_log_message);
                // TODO: Can be made prettier once Carrier stabilized
                let prefix = match mpv_cstr_to_str!(CStr::from_ptr(log_message.prefix)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let level = match mpv_cstr_to_str!(CStr::from_ptr(log_message.level)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let text = match mpv_cstr_to_str!(CStr::from_ptr(log_message.text)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                Some(Ok(Event::LogMessage {
                    prefix: prefix,
                    level: level,
                    text: text,
                    log_level: log_message.log_level,
                }))
            }
            mpv_event_id::MPV_EVENT_GET_PROPERTY_REPLY => {
                let property = *(event.data as *mut mpv_event_property);
                let name = match mpv_cstr_to_str!(CStr::from_ptr(property.name)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let data = if let Err(e) = mpv_err((), event.error) {
                    return Some(Err(e));
                } else {
                    match PropertyData::from_raw(property.format, property.data) {
                        Err(e) => return Some(Err(e)),
                        Ok(v) => v,
                    }
                };
                Some(Ok(Event::GetPropertyReply {
                    name: name,
                    result: data,
                    reply_userdata: event.reply_userdata,
                }))
            }
            mpv_event_id::MPV_EVENT_SET_PROPERTY_REPLY => Some(mpv_err(
                Event::SetPropertyReply(event.reply_userdata),
                event.error,
            )),
            mpv_event_id::MPV_EVENT_COMMAND_REPLY => Some(mpv_err(
                Event::CommandReply(event.reply_userdata),
                event.error,
            )),
            mpv_event_id::MPV_EVENT_START_FILE => Some(Ok(Event::StartFile)),
            mpv_event_id::MPV_EVENT_END_FILE => {
                let end_file = *(event.data as *mut mpv_event_end_file);
                let end_file_reason = mpv_end_file_reason::from(end_file.reason as u32);

                if let Err(e) = mpv_err((), end_file.error) {
                    return Some(Err(e));
                }
                Some(Ok(Event::EndFile(end_file_reason)))
            }
            mpv_event_id::MPV_EVENT_FILE_LOADED => Some(Ok(Event::FileLoaded)),
            mpv_event_id::MPV_EVENT_TRACKS_CHANGED => Some(Ok(Event::TracksChanged)),
            mpv_event_id::MPV_EVENT_TRACK_SWITCHED => Some(Ok(Event::TrackSwitched)),
            mpv_event_id::MPV_EVENT_IDLE => Some(Ok(Event::Idle)),
            mpv_event_id::MPV_EVENT_PAUSE => Some(Ok(Event::Pause)),
            mpv_event_id::MPV_EVENT_UNPAUSE => Some(Ok(Event::Unpause)),
            mpv_event_id::MPV_EVENT_TICK => Some(Ok(Event::Tick)),
            mpv_event_id::MPV_EVENT_SCRIPT_INPUT_DISPATCH => Some(Ok(Event::Unused)),
            mpv_event_id::MPV_EVENT_CLIENT_MESSAGE => {
                let client_message = *(event.data as *mut mpv_event_client_message);

                Some(Ok(Event::ClientMessage(MessageIter(
                    slice::from_raw_parts_mut(client_message.args, client_message.num_args as _)
                        .iter()
                        .map(|msg| mpv_cstr_to_str!(CStr::from_ptr(*msg))),
                    client_message.num_args as _,
                ))))
            }
            mpv_event_id::MPV_EVENT_VIDEO_RECONFIG => Some(Ok(Event::VideoReconfig)),
            mpv_event_id::MPV_EVENT_AUDIO_RECONFIG => Some(Ok(Event::AudioReconfig)),
            mpv_event_id::MPV_EVENT_METADATA_UPDATE => Some(Ok(Event::MetadataUpdate)),
            mpv_event_id::MPV_EVENT_SEEK => Some(Ok(Event::Seek)),
            mpv_event_id::MPV_EVENT_PLAYBACK_RESTART => Some(Ok(Event::PlaybackRestart)),
            mpv_event_id::MPV_EVENT_PROPERTY_CHANGE => {
                let property = *(event.data as *mut mpv_event_property);
                let name = match mpv_cstr_to_str!(CStr::from_ptr(property.name)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let data = if let Err(e) = mpv_err((), event.error) {
                    return Some(Err(e));
                } else {
                    match PropertyData::from_raw(property.format, property.data) {
                        Err(e) => return Some(Err(e)),
                        Ok(v) => v,
                    }
                };
                Some(Ok(Event::PropertyChange {
                    name: name,
                    change: data,
                    reply_userdata: event.reply_userdata,
                }))
            }
            mpv_event_id::MPV_EVENT_CHAPTER_CHANGE => Some(Ok(Event::ChapterChange)),
            mpv_event_id::MPV_EVENT_QUEUE_OVERFLOW => Some(Ok(Event::QueueOverflow)),
        }
    }

    /// Observe `name` property for changes. `id` can be used to unobserve this (or many) properties
    /// again.
    ///
    /// Warning: This should probably not be used at the same time as an
    /// `EventIter` observing properties, because the ids will most likely overlap.
    pub fn observe_property(&self, name: &str, format: Format, id: u64) -> Result<()> {
        let name = CString::new(name)?;
        mpv_err((), unsafe {
            mpv_observe_property(self.ctx, id, name.as_ptr(), format.as_mpv_format() as _)
        })
    }

    /// Unobserve any property associated with `id`.
    pub fn unobserve_property(&self, id: u64) -> Result<()> {
        mpv_err((), unsafe { mpv_unobserve_property(self.ctx, id) })
    }
}
<commit_msg>[events_simple] Clean property change branch<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use raw::*;

use ::*;
use super::super::*;

use std::iter::Map;
use std::slice;
use std::slice::Iter;
use std::os::raw as ctype;

// TODO: Clean this up, as a lot is duplicated/copied from elsewhere, use cstr macro

#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
/// Data that is returned by both `GetPropertyReply` and `PropertyChange` events.
pub enum PropertyData<'a> {
    Str(&'a str),
    OsdStr(&'a str),
    Flag(bool),
    Int64(i64),
    Double(ctype::c_double),
}

impl<'a> PropertyData<'a> {
    fn from_raw(format: mpv_format, ptr: *mut ctype::c_void) -> Result<PropertyData<'a>> {
        debug_assert!(!ptr.is_null());
        match format {
            mpv_format::MPV_FORMAT_FLAG => Ok(PropertyData::Flag(unsafe { *(ptr as *mut bool) })),
            mpv_format::MPV_FORMAT_STRING => {
                let char_ptr = unsafe { *(ptr as *mut *mut ctype::c_char) };
                Ok(PropertyData::Str(
                    mpv_cstr_to_str!(unsafe { CStr::from_ptr(char_ptr) })?,
                ))
            }
            mpv_format::MPV_FORMAT_OSD_STRING => {
                let char_ptr = unsafe { *(ptr as *mut *mut ctype::c_char) };
                Ok(PropertyData::OsdStr(
                    mpv_cstr_to_str!(unsafe { CStr::from_ptr(char_ptr) })?,
                ))
            }
            mpv_format::MPV_FORMAT_DOUBLE => {
                Ok(PropertyData::Double(unsafe { *(ptr as *mut f64) }))
            }
            mpv_format::MPV_FORMAT_INT64 => Ok(PropertyData::Int64(unsafe { *(ptr as *mut i64) })),
            mpv_format::MPV_FORMAT_NONE => unreachable!(),
            _ => unimplemented!(),
        }
    }
}

#[derive(Clone, Debug)]
/// Wrapper around an `Iterator` that yields the `str` of `Event::ClientMessage`
pub struct MessageIter<'a>(
    Map<Iter<'a, *const i8>, fn(&'a *const i8) -> Result<&'a str>>,
    usize,
);

impl<'a> Iterator for MessageIter<'a> {
    type Item = Result<&'a str>;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.1, Some(self.1))
    }
}

impl<'a> ExactSizeIterator for MessageIter<'a> {}

impl<'a> PartialEq for MessageIter<'a> {
    fn eq(&self, rhs: &Self) -> bool {
        if self.1 == rhs.len() {
            // TODO: Any way to avoid clone?
            self.0.clone().eq(rhs.0.clone())
        } else {
            false
        }
    }
}

#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq)]
pub enum Event<'a> {
    /// Received when the player is shutting down
    Shutdown,
    /// *Has not been tested*, received when explicitly asked to MPV
    LogMessage {
        prefix: &'a str,
        level: &'a str,
        text: &'a str,
        log_level: LogLevel,
    },
    /// Received when using get_property_async
    GetPropertyReply {
        name: &'a str,
        result: PropertyData<'a>,
        reply_userdata: u64,
    },
    /// Received when using set_property_async
    SetPropertyReply(u64),
    /// Received when using command_async
    CommandReply(u64),
    /// Event received when a new file is playing
    StartFile,
    /// Event received when the file being played currently has stopped, for an error or not
    EndFile(EndFileReason),
    /// Event received when a file has been *loaded*, but has not been started
    FileLoaded,
    TracksChanged,
    /// Deprecated
    TrackSwitched,
    /// Received when the player has no more files to play and is in an idle state
    Idle,
    /// The player paused playback
    Pause,
    /// The player started playback again
    Unpause,
    Tick,
    ClientMessage(MessageIter<'a>),
    VideoReconfig,
    AudioReconfig,
    MetadataUpdate,
    /// The player changed current position
    Seek,
    PlaybackRestart,
    /// Received when used with observe_property
    PropertyChange {
        name: &'a str,
        change: PropertyData<'a>,
        reply_userdata: u64,
    },
    ChapterChange,
    /// Received when the Event Queue is full
    QueueOverflow,
    /// Unused event
    Unused,
}

impl Mpv {
    /// Wait for `timeout` seconds for an `Event`. Passing `0` as `timeout` will poll.
    /// For more information, as always, see the mpv-sys docs of `mpv_wait_event`.
    ///
    /// Returns `Some(Err(...))` if there was invalid utf-8, or if either an
    /// `MPV_EVENT_GET_PROPERTY_REPLY`, `MPV_EVENT_SET_PROPERTY_REPLY`, `MPV_EVENT_COMMAND_REPLY`,
    /// or `MPV_EVENT_PROPERTY_CHANGE` event failed, or if `MPV_EVENT_END_FILE` reported an error.
    ///
    /// # Unsafety
    /// Calling this function simultaneosly multiple times may result in data races. Internally,
    /// `EventIter` also uses `wait_event`. Do not combine the two.
    pub unsafe fn wait_event(&self, timeout: f64) -> Option<Result<Event>> {
        let event = &*mpv_wait_event(self.ctx, timeout);

        match event.event_id {
            mpv_event_id::MPV_EVENT_NONE => None,
            mpv_event_id::MPV_EVENT_SHUTDOWN => Some(Ok(Event::Shutdown)),
            mpv_event_id::MPV_EVENT_LOG_MESSAGE => {
                let log_message = *(event.data as *mut mpv_event_log_message);
                // TODO: Can be made prettier once Carrier stabilized
                let prefix = match mpv_cstr_to_str!(CStr::from_ptr(log_message.prefix)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let level = match mpv_cstr_to_str!(CStr::from_ptr(log_message.level)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let text = match mpv_cstr_to_str!(CStr::from_ptr(log_message.text)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                Some(Ok(Event::LogMessage {
                    prefix: prefix,
                    level: level,
                    text: text,
                    log_level: log_message.log_level,
                }))
            }
            mpv_event_id::MPV_EVENT_GET_PROPERTY_REPLY => {
                let property = *(event.data as *mut mpv_event_property);
                let name = match mpv_cstr_to_str!(CStr::from_ptr(property.name)) {
                    Err(e) => return Some(Err(e)),
                    Ok(v) => v,
                };
                let data = if let Err(e) = mpv_err((), event.error) {
                    return Some(Err(e));
                } else {
                    match PropertyData::from_raw(property.format, property.data) {
                        Err(e) => return Some(Err(e)),
                        Ok(v) => v,
                    }
                };
                Some(Ok(Event::GetPropertyReply {
                    name: name,
                    result: data,
                    reply_userdata: event.reply_userdata,
                }))
            }
            mpv_event_id::MPV_EVENT_SET_PROPERTY_REPLY => Some(mpv_err(
                Event::SetPropertyReply(event.reply_userdata),
                event.error,
            )),
            mpv_event_id::MPV_EVENT_COMMAND_REPLY => Some(mpv_err(
                Event::CommandReply(event.reply_userdata),
                event.error,
            )),
            mpv_event_id::MPV_EVENT_START_FILE => Some(Ok(Event::StartFile)),
            mpv_event_id::MPV_EVENT_END_FILE => {
                let end_file = *(event.data as *mut mpv_event_end_file);
                let end_file_reason = mpv_end_file_reason::from(end_file.reason as u32);

                if let Err(e) = mpv_err((), end_file.error) {
                    return Some(Err(e));
                }
                Some(Ok(Event::EndFile(end_file_reason)))
            }
            mpv_event_id::MPV_EVENT_FILE_LOADED => Some(Ok(Event::FileLoaded)),
            mpv_event_id::MPV_EVENT_TRACKS_CHANGED => Some(Ok(Event::TracksChanged)),
            mpv_event_id::MPV_EVENT_TRACK_SWITCHED => Some(Ok(Event::TrackSwitched)),
            mpv_event_id::MPV_EVENT_IDLE => Some(Ok(Event::Idle)),
            mpv_event_id::MPV_EVENT_PAUSE => Some(Ok(Event::Pause)),
            mpv_event_id::MPV_EVENT_UNPAUSE => Some(Ok(Event::Unpause)),
            mpv_event_id::MPV_EVENT_TICK => Some(Ok(Event::Tick)),
            mpv_event_id::MPV_EVENT_SCRIPT_INPUT_DISPATCH => Some(Ok(Event::Unused)),
            mpv_event_id::MPV_EVENT_CLIENT_MESSAGE => {
                let client_message = *(event.data as *mut mpv_event_client_message);

                Some(Ok(Event::ClientMessage(MessageIter(
                    slice::from_raw_parts_mut(client_message.args, client_message.num_args as _)
                        .iter()
                        .map(|msg| mpv_cstr_to_str!(CStr::from_ptr(*msg))),
                    client_message.num_args as _,
                ))))
            }
            mpv_event_id::MPV_EVENT_VIDEO_RECONFIG => Some(Ok(Event::VideoReconfig)),
            mpv_event_id::MPV_EVENT_AUDIO_RECONFIG => Some(Ok(Event::AudioReconfig)),
            mpv_event_id::MPV_EVENT_METADATA_UPDATE => Some(Ok(Event::MetadataUpdate)),
            mpv_event_id::MPV_EVENT_SEEK => Some(Ok(Event::Seek)),
            mpv_event_id::MPV_EVENT_PLAYBACK_RESTART => Some(Ok(Event::PlaybackRestart)),
            mpv_event_id::MPV_EVENT_PROPERTY_CHANGE => {
                let property = *(event.data as *mut mpv_event_property);
                Some(mpv_cstr_to_str!(CStr::from_ptr(property.name)).and_then(
                    |name| {
                        mpv_err((), event.error)?;
                        let data = PropertyData::from_raw(property.format, property.data)?;
                        Ok(Event::PropertyChange {
                            name: name,
                            change: data,
                            reply_userdata: event.reply_userdata,
                        })
                    },
                ))
            }
            mpv_event_id::MPV_EVENT_CHAPTER_CHANGE => Some(Ok(Event::ChapterChange)),
            mpv_event_id::MPV_EVENT_QUEUE_OVERFLOW => Some(Ok(Event::QueueOverflow)),
        }
    }

    /// Observe `name` property for changes. `id` can be used to unobserve this (or many) properties
    /// again.
    ///
    /// Warning: This should probably not be used at the same time as an
    /// `EventIter` observing properties, because the ids will most likely overlap.
    pub fn observe_property(&self, name: &str, format: Format, id: u64) -> Result<()> {
        let name = CString::new(name)?;
        mpv_err((), unsafe {
            mpv_observe_property(self.ctx, id, name.as_ptr(), format.as_mpv_format() as _)
        })
    }

    /// Unobserve any property associated with `id`.
    pub fn unobserve_property(&self, id: u64) -> Result<()> {
        mpv_err((), unsafe { mpv_unobserve_property(self.ctx, id) })
    }
}
<|endoftext|>


<commit_before>use env_logger::Builder as LogBuilder;
use log::{debug,
          error,
          info,
          LevelFilter};
use regex::Regex;
use reqwest::Url;
use std::{error,
          fmt,
          fs::{self,
               File},
          io::{self,
               BufRead},
          path::PathBuf,
          process::Command,
          str::FromStr};
use structopt::StructOpt;

lazy_static::lazy_static! {
    static ref RE: Regex = Regex::new(r"\*\s(?P<ident>.*) \((?P<target>.*)\)").expect("valid regex");
}

const ACCEPTANCE_URL: &str = "https://bldr.acceptance.habitat.sh";
const PACKAGES_ENDPOINT: &str = "v1/depot/pkgs/";
const DOWNLOAD_ENDPOINT: &str = "download";

/// Wraps an owned `String` and implements the `Error` trait for it.
#[derive(Debug)]
struct StringError(String);

impl StringError {
    fn new(error: String) -> Self { Self(error) }
}

impl error::Error for StringError {
    fn description(&self) -> &str { &self.0 }
}

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

#[derive(Debug, PartialEq)]
struct Package {
    ident:  String,
    target: String,
}

impl Package {
    /// Create a new package
    fn new(ident: String, target: String) -> Self { Self { ident, target } }

    /// The filename to write the package to
    fn filename(&self) -> PathBuf {
        PathBuf::from_str(&format!("{}-{}.hart", self.ident.replace("/", "-"), self.target)).expect("valid path")
    }

    /// The url to download the package
    fn url(&self, base: &str) -> Result<Url, Box<dyn std::error::Error>> {
        let params = &[("target", &self.target)];
        let url = Url::parse(base)?.join(PACKAGES_ENDPOINT)?
                                   .join(&format!("{}/", self.ident))?
                                   .join(DOWNLOAD_ENDPOINT)?;
        let url = Url::parse_with_params(url.as_str(), params)?;
        Ok(url)
    }

    /// Download the package from `base_url` and save the hart file in `base_dir`
    fn download(&self,
                base_url: &str,
                base_dir: &PathBuf)
                -> Result<(), Box<dyn std::error::Error>> {
        let url = self.url(base_url)?;
        let output_path = base_dir.join(self.filename());
        debug!("Downloading package from '{}' and writing to {:?}",
               url,
               output_path.as_os_str());
        let mut response = reqwest::get(url)?.error_for_status()?;
        let mut output_file = File::create(&output_path)?;
        let written = io::copy(&mut response, &mut output_file)?;
        info!("Wrote {} bytes to {:?}", written, output_path.as_os_str());
        Ok(())
    }

    /// Upload the package that has been saved in `base_dir` using the hab command
    fn upload(&self,
              base_dir: &PathBuf,
              auth: &str,
              channel: &Option<String>,
              force: bool)
              -> Result<(), Box<dyn std::error::Error>> {
        let path = base_dir.join(self.filename());
        let mut command = Command::new("hab");
        command.arg("pkg").arg("upload");
        command.arg("--auth").arg(auth);
        if let Some(channel) = channel {
            command.arg("--channel").arg(channel);
        }
        if force {
            command.arg("--force");
        }
        command.arg(&path);
        let command_str = format!("{:?}", command).replace("\"", "");
        debug!("Uploading {:?} with command '{}'",
               path.as_os_str(),
               command_str);
        let status = command.status()?;
        if !status.success() {
            return Err(Box::new(StringError::new(format!("Failed to execute \
                                                          '{}' with {}",
                                                         command_str, status))));
        };

        info!("Uploaded '{}' with target '{}'", self.ident, self.target);
        Ok(())
    }
}

impl FromStr for Package {
    type Err = Box<dyn std::error::Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let captures = RE.captures(&s).ok_or("failed to parse")?;
        Ok(Self::new(String::from(&captures["ident"]),
                     String::from(&captures["target"])))
    }
}

#[derive(StructOpt, Debug)]
#[structopt()]
struct Opt {
    /// Builder live authentication token
    #[structopt(long, short = "z")]
    auth: String,

    /// The builder acceptance url
    #[structopt(raw(default_value = "ACCEPTANCE_URL"), long)]
    acceptance_url: String,

    /// The channel to tag packages with when promoting to live
    #[structopt(long, short)]
    channel: Option<String>,

    /// Force upload the packages to live
    #[structopt(long)]
    force: bool,

    /// The temporary directory to write hart files to
    #[structopt(default_value = "one-off-release-tmp-dir", long)]
    tmp_dir: PathBuf,

    /// Log level
    #[structopt(default_value = "info",
                short,
                long,
                raw(possible_values = r#"&["trace", "debug", "info", "warn", "error"]"#))]
    log_level: LevelFilter,
}

fn main() {
    let Opt { auth,
              acceptance_url,
              channel,
              force,
              tmp_dir,
              log_level, } = Opt::from_args();

    LogBuilder::new().default_format_timestamp(false)
                     .default_format_module_path(false)
                     .filter_level(log_level)
                     .filter(Some("hyper"), LevelFilter::Warn)
                     .filter(Some("reqwest"), LevelFilter::Warn)
                     .filter(Some("tokio_reactor"), LevelFilter::Warn)
                     .init();

    // Create the temporary output directory
    if let Err(e) = fs::create_dir(&tmp_dir) {
        error!("Failed to create {:?}, err: {}", tmp_dir, e);
        return;
    };

    // Read all lines from stdin until an empty line
    let stdin = io::stdin();
    let lines = stdin.lock()
                     .lines()
                     .map(|l| l.expect("to read a line"))
                     .take_while(|l| !l.is_empty())
                     .collect::<Vec<_>>();

    // Parse each line into a package
    let packages = lines.iter()
                        .filter_map(|l| {
                            let package_result = l.parse();
                            if let Err(_) = package_result {
                                error!("Failed to parse line '{}'", l);
                                return None;
                            }
                            package_result.ok()
                        })
                        .collect::<Vec<Package>>();

    // Download all packages
    for p in packages.iter() {
        if let Err(e) = p.download(&acceptance_url, &tmp_dir) {
            error!("Failed to download {:?}, err: {}", p, e);
        }
    }

    // Upload all packages
    for p in packages.iter() {
        if let Err(e) = p.upload(&tmp_dir, &auth, &channel, force) {
            error!("Failed to upload {:?}, err: {}", p, e);
        }
    }
}

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

    #[test]
    fn test_parse() {
        assert!("bad input".parse::<Package>().is_err());
        assert_eq!("* package (target)".parse::<Package>().unwrap(),
                   Package::new(String::from("package"), String::from("target")));
        assert_eq!("* core/hab-backline/0.84.33/20190819190300 (x86_64-linux)".parse::<Package>()
                                                                              .unwrap(),
                   Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                                String::from("x86_64-linux")));
    }

    #[test]
    fn test_package_url() {
        let p = Package::new(String::from("package"), String::from("target"));
        assert!(p.url("bad url").is_err());
        assert_eq!(p.url("https://test.url").unwrap().as_str(),
                   "https://test.url/v1/depot/pkgs/package/download?target=target");
        let p = Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                             String::from("x86_64-linux"));
        assert_eq!(p.url(ACCEPTANCE_URL).unwrap().as_str(),
                   format!("{}/{}core/hab-backline/0.84.33/20190819190300/{}?target=x86_64-linux",
                           ACCEPTANCE_URL, PACKAGES_ENDPOINT, DOWNLOAD_ENDPOINT));
    }

    #[test]
    fn test_package_filename() {
        let p = Package::new(String::from("package"), String::from("target"));
        assert_eq!(p.filename().as_os_str(), "package-target.hart");
        let p = Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                             String::from("x86_64-linux"));
        assert_eq!(p.filename().as_os_str(),
                   "core-hab-backline-0.84.33-20190819190300-x86_64-linux.hart");
    }
}
<commit_msg>Fix clippy<commit_after>use env_logger::Builder as LogBuilder;
use log::{debug,
          error,
          info,
          LevelFilter};
use regex::Regex;
use reqwest::Url;
use std::{error,
          fmt,
          fs::{self,
               File},
          io::{self,
               BufRead},
          path::PathBuf,
          process::Command,
          str::FromStr};
use structopt::StructOpt;

lazy_static::lazy_static! {
    static ref RE: Regex = Regex::new(r"\*\s(?P<ident>.*) \((?P<target>.*)\)").expect("valid regex");
}

const ACCEPTANCE_URL: &str = "https://bldr.acceptance.habitat.sh";
const PACKAGES_ENDPOINT: &str = "v1/depot/pkgs/";
const DOWNLOAD_ENDPOINT: &str = "download";

/// Wraps an owned `String` and implements the `Error` trait for it.
#[derive(Debug)]
struct StringError(String);

impl StringError {
    fn new(error: String) -> Self { Self(error) }
}

impl error::Error for StringError {
    fn description(&self) -> &str { &self.0 }
}

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

#[derive(Debug, PartialEq)]
struct Package {
    ident:  String,
    target: String,
}

impl Package {
    /// Create a new package
    fn new(ident: String, target: String) -> Self { Self { ident, target } }

    /// The filename to write the package to
    fn filename(&self) -> PathBuf {
        PathBuf::from_str(&format!("{}-{}.hart", self.ident.replace("/", "-"), self.target)).expect("valid path")
    }

    /// The url to download the package
    fn url(&self, base: &str) -> Result<Url, Box<dyn std::error::Error>> {
        let params = &[("target", &self.target)];
        let url = Url::parse(base)?.join(PACKAGES_ENDPOINT)?
                                   .join(&format!("{}/", self.ident))?
                                   .join(DOWNLOAD_ENDPOINT)?;
        let url = Url::parse_with_params(url.as_str(), params)?;
        Ok(url)
    }

    /// Download the package from `base_url` and save the hart file in `base_dir`
    fn download(&self,
                base_url: &str,
                base_dir: &PathBuf)
                -> Result<(), Box<dyn std::error::Error>> {
        let url = self.url(base_url)?;
        let output_path = base_dir.join(self.filename());
        debug!("Downloading package from '{}' and writing to {:?}",
               url,
               output_path.as_os_str());
        let mut response = reqwest::get(url)?.error_for_status()?;
        let mut output_file = File::create(&output_path)?;
        let written = io::copy(&mut response, &mut output_file)?;
        info!("Wrote {} bytes to {:?}", written, output_path.as_os_str());
        Ok(())
    }

    /// Upload the package that has been saved in `base_dir` using the hab command
    fn upload(&self,
              base_dir: &PathBuf,
              auth: &str,
              channel: &Option<String>,
              force: bool)
              -> Result<(), Box<dyn std::error::Error>> {
        let path = base_dir.join(self.filename());
        let mut command = Command::new("hab");
        command.arg("pkg").arg("upload");
        command.arg("--auth").arg(auth);
        if let Some(channel) = channel {
            command.arg("--channel").arg(channel);
        }
        if force {
            command.arg("--force");
        }
        command.arg(&path);
        let command_str = format!("{:?}", command).replace("\"", "");
        debug!("Uploading {:?} with command '{}'",
               path.as_os_str(),
               command_str);
        let status = command.status()?;
        if !status.success() {
            return Err(Box::new(StringError::new(format!("Failed to execute \
                                                          '{}' with {}",
                                                         command_str, status))));
        };

        info!("Uploaded '{}' with target '{}'", self.ident, self.target);
        Ok(())
    }
}

impl FromStr for Package {
    type Err = Box<dyn std::error::Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let captures = RE.captures(&s).ok_or("failed to parse")?;
        Ok(Self::new(String::from(&captures["ident"]),
                     String::from(&captures["target"])))
    }
}

#[derive(StructOpt, Debug)]
#[structopt()]
struct Opt {
    /// Builder live authentication token
    #[structopt(long, short = "z")]
    auth: String,

    /// The builder acceptance url
    #[structopt(raw(default_value = "ACCEPTANCE_URL"), long)]
    acceptance_url: String,

    /// The channel to tag packages with when promoting to live
    #[structopt(long, short)]
    channel: Option<String>,

    /// Force upload the packages to live
    #[structopt(long)]
    force: bool,

    /// The temporary directory to write hart files to
    #[structopt(default_value = "one-off-release-tmp-dir", long)]
    tmp_dir: PathBuf,

    /// Log level
    #[structopt(default_value = "info",
                short,
                long,
                raw(possible_values = r#"&["trace", "debug", "info", "warn", "error"]"#))]
    log_level: LevelFilter,
}

fn main() {
    let Opt { auth,
              acceptance_url,
              channel,
              force,
              tmp_dir,
              log_level, } = Opt::from_args();

    LogBuilder::new().default_format_timestamp(false)
                     .default_format_module_path(false)
                     .filter_level(log_level)
                     .filter(Some("hyper"), LevelFilter::Warn)
                     .filter(Some("reqwest"), LevelFilter::Warn)
                     .filter(Some("tokio_reactor"), LevelFilter::Warn)
                     .init();

    // Create the temporary output directory
    if let Err(e) = fs::create_dir(&tmp_dir) {
        error!("Failed to create {:?}, err: {}", tmp_dir, e);
        return;
    };

    // Read all lines from stdin until an empty line
    let stdin = io::stdin();
    let lines = stdin.lock()
                     .lines()
                     .map(|l| l.expect("to read a line"))
                     .take_while(|l| !l.is_empty())
                     .collect::<Vec<_>>();

    // Parse each line into a package
    let packages = lines.iter()
                        .filter_map(|l| {
                            let package_result = l.parse();
                            if package_result.is_err() {
                                error!("Failed to parse line '{}'", l);
                                return None;
                            }
                            package_result.ok()
                        })
                        .collect::<Vec<Package>>();

    // Download all packages
    for p in packages.iter() {
        if let Err(e) = p.download(&acceptance_url, &tmp_dir) {
            error!("Failed to download {:?}, err: {}", p, e);
        }
    }

    // Upload all packages
    for p in packages.iter() {
        if let Err(e) = p.upload(&tmp_dir, &auth, &channel, force) {
            error!("Failed to upload {:?}, err: {}", p, e);
        }
    }
}

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

    #[test]
    fn test_parse() {
        assert!("bad input".parse::<Package>().is_err());
        assert_eq!("* package (target)".parse::<Package>().unwrap(),
                   Package::new(String::from("package"), String::from("target")));
        assert_eq!("* core/hab-backline/0.84.33/20190819190300 (x86_64-linux)".parse::<Package>()
                                                                              .unwrap(),
                   Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                                String::from("x86_64-linux")));
    }

    #[test]
    fn test_package_url() {
        let p = Package::new(String::from("package"), String::from("target"));
        assert!(p.url("bad url").is_err());
        assert_eq!(p.url("https://test.url").unwrap().as_str(),
                   "https://test.url/v1/depot/pkgs/package/download?target=target");
        let p = Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                             String::from("x86_64-linux"));
        assert_eq!(p.url(ACCEPTANCE_URL).unwrap().as_str(),
                   format!("{}/{}core/hab-backline/0.84.33/20190819190300/{}?target=x86_64-linux",
                           ACCEPTANCE_URL, PACKAGES_ENDPOINT, DOWNLOAD_ENDPOINT));
    }

    #[test]
    fn test_package_filename() {
        let p = Package::new(String::from("package"), String::from("target"));
        assert_eq!(p.filename().as_os_str(), "package-target.hart");
        let p = Package::new(String::from("core/hab-backline/0.84.33/20190819190300"),
                             String::from("x86_64-linux"));
        assert_eq!(p.filename().as_os_str(),
                   "core-hab-backline-0.84.33-20190819190300-x86_64-linux.hart");
    }
}
<|endoftext|>