<commit_before>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use utils::opcode::Opcode;
use vm::{VM, Machine, Memory, Stack, PC, ExecutionError, ExecutionResult, Storage};
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE_DEFAULT: usize = 20;
const G_EXTCODE_EIP150: usize = 700;
const G_BALANCE_DEFAULT: usize = 20;
const G_BALANCE_EIP150: usize = 400;
const G_SLOAD_DEFAULT: usize = 50;
const G_SLOAD_EIP150: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE_DEFAULT: usize = 0;
const G_SUICIDE_EIP150: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL_DEFAULT: usize = 40;
const G_CALL_EIP150: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE_DEFAULT: usize = 10;
const G_EXPBYTE_EIP160: usize = 50;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address)?.read(index)? == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    // let base2 = machine.stack().peek(0)?.into();

    // if available_gas >= extra_cost(machine)? {
    //     let base1 = available_gas - extra_cost(machine)?;
    //     Ok(min(base1 - base1 / Gas::from(64u64), base2))
    // } else {
    //     Ok(base2)
    // }
    Ok(Gas::zero())
}

fn extra_cost<M: Memory + Default,
              S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    Ok(Gas::from(if machine.patch.eip150() { G_CALL_EIP150 } else { G_CALL_DEFAULT }) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: Memory + Default,
            S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if address == Address::default() {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(0)?.into();
    Ok(Gas::from(if machine.patch.eip150() { G_SUICIDE_EIP150 } else { G_SUICIDE_DEFAULT }) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

fn memory_gas_cost<M: Memory + Default,
                   S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                          aggregrator: CostAggregrator)
                               -> ExecutionResult<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::RETURN | Opcode::LOG(_) => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::CODECOPY | Opcode::CALLDATACOPY => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::EXTCODECOPY => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(3)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: Memory + Default,
                S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                       aggregrator: CostAggregrator)
                            -> ExecutionResult<(Gas, CostAggregrator)> {
    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, machine.available_gas())?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = machine.stack.peek(1)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::LOG(v) => {
            let len = machine.stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = machine.stack.peek(3)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = machine.stack.peek(2)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::EXP => {
            if machine.stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(if machine.patch.eip160() { G_EXPBYTE_EIP160 } else { G_EXPBYTE_DEFAULT }) * (Gas::from(1u64) + Gas::from(machine.stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => (if machine.patch.eip150() { G_SLOAD_EIP150 } else { G_SLOAD_DEFAULT }).into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => (if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }).into(),

        Opcode::BALANCE => (if machine.patch.eip150() { G_BALANCE_EIP150 } else { G_BALANCE_DEFAULT }).into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}

pub fn gas_refund<M: Memory + Default,
                  S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    match opcode {
        Opcode::SSTORE => {
            let index = machine.stack().peek(0)?;
            let value = machine.stack().peek(1)?;
            let address = machine.context.address;

            if value == M256::zero() && machine.account_state.storage(address)?.read(index)? != M256::zero() {
                Ok(Gas::from(R_SCLEAR))
            } else {
                Ok(Gas::zero())
            }
        },
        Opcode::SUICIDE => {
            // TODO: check whether I_a belongs to A_s
            Ok(Gas::zero())
        },
        _ => Ok(Gas::zero())
    }
}
<commit_msg>Problem: new_cost should deal with empty account Solution: change to assert an empty account<commit_after>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use utils::opcode::Opcode;
use vm::{VM, Machine, Memory, Stack, PC, ExecutionError, ExecutionResult, Storage};
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE_DEFAULT: usize = 20;
const G_EXTCODE_EIP150: usize = 700;
const G_BALANCE_DEFAULT: usize = 20;
const G_BALANCE_EIP150: usize = 400;
const G_SLOAD_DEFAULT: usize = 50;
const G_SLOAD_EIP150: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE_DEFAULT: usize = 0;
const G_SUICIDE_EIP150: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL_DEFAULT: usize = 40;
const G_CALL_EIP150: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE_DEFAULT: usize = 10;
const G_EXPBYTE_EIP160: usize = 50;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address)?.read(index)? == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    // let base2 = machine.stack().peek(0)?.into();

    // if available_gas >= extra_cost(machine)? {
    //     let base1 = available_gas - extra_cost(machine)?;
    //     Ok(min(base1 - base1 / Gas::from(64u64), base2))
    // } else {
    //     Ok(base2)
    // }
    Ok(Gas::zero())
}

fn extra_cost<M: Memory + Default,
              S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    Ok(Gas::from(if machine.patch.eip150() { G_CALL_EIP150 } else { G_CALL_DEFAULT }) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: Memory + Default,
            S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if machine.account_state.balance(address)? == U256::zero() && machine.account_state.nonce(address)? == M256::zero() && machine.account_state.code(address)?.len() == 0 {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(0)?.into();
    Ok(Gas::from(if machine.patch.eip150() { G_SUICIDE_EIP150 } else { G_SUICIDE_DEFAULT }) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

fn memory_gas_cost<M: Memory + Default,
                   S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                          aggregrator: CostAggregrator)
                               -> ExecutionResult<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::RETURN | Opcode::LOG(_) => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::CODECOPY | Opcode::CALLDATACOPY => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::EXTCODECOPY => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(3)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: Memory + Default,
                S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                       aggregrator: CostAggregrator)
                            -> ExecutionResult<(Gas, CostAggregrator)> {
    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, machine.available_gas())?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = machine.stack.peek(1)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::LOG(v) => {
            let len = machine.stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = machine.stack.peek(3)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = machine.stack.peek(2)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::EXP => {
            if machine.stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(if machine.patch.eip160() { G_EXPBYTE_EIP160 } else { G_EXPBYTE_DEFAULT }) * (Gas::from(1u64) + Gas::from(machine.stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => (if machine.patch.eip150() { G_SLOAD_EIP150 } else { G_SLOAD_DEFAULT }).into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => (if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }).into(),

        Opcode::BALANCE => (if machine.patch.eip150() { G_BALANCE_EIP150 } else { G_BALANCE_DEFAULT }).into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}

pub fn gas_refund<M: Memory + Default,
                  S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    match opcode {
        Opcode::SSTORE => {
            let index = machine.stack().peek(0)?;
            let value = machine.stack().peek(1)?;
            let address = machine.context.address;

            if value == M256::zero() && machine.account_state.storage(address)?.read(index)? != M256::zero() {
                Ok(Gas::from(R_SCLEAR))
            } else {
                Ok(Gas::zero())
            }
        },
        Opcode::SUICIDE => {
            // TODO: check whether I_a belongs to A_s
            Ok(Gas::zero())
        },
        _ => Ok(Gas::zero())
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(macro_rules)]

extern crate deuterium;
extern crate time;

use time::Timespec;
use deuterium::*;

#[macro_export]
macro_rules! assert_sql(
    ($query:expr, $s:expr) => (
        assert_eq!($query.to_final_sql().as_slice(), $s)
    )
)

mod simple_select;
mod where_;

#[test]
fn select_1_first() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_1(&name).where_(
        name.is("Luke".to_string()).exclude()
    ).first().offset(10);

    assert_sql!(query, "SELECT name FROM jedi WHERE name != 'Luke' LIMIT 1 OFFSET 10;");

}

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_within() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().where_(name.within(vec!["Luke".to_string()]));
    assert_sql!(query, "SELECT * FROM jedi WHERE name IN ('Luke');");

}

#[test]
fn select_within_select() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.alias("j").select_all().where_(name.within(
        jedi_table.select_1(&name)
    ));

    assert_sql!(query, "SELECT * FROM jedi AS j WHERE name IN (SELECT name FROM jedi);");

}

#[test]
fn select_from_select() {

    let jedi_table = TableDef::new("jedi");

    let query = jedi_table.select_all().alias("jedi_list").select_all();
    assert_sql!(query, "SELECT * FROM (SELECT * FROM jedi) as jedi_list;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}

#[test]
fn aliases() {

    let jedi_table = TableDef::new("jedi");
    let jedi_a = jedi_table.alias("a");
    let jedi_b = jedi_table.alias("b");
    let name_a = NamedField::<String>::field_of("name", &jedi_a);
    let name_b = NamedField::<String>::field_of("name", &jedi_b);

    let query = jedi_a.select_all().inner_join(&jedi_b, name_a.is(name_b));
    assert_sql!(query, "SELECT * FROM jedi AS a INNER JOIN jedi AS b ON a.name = b.name;");

}<commit_msg>refactor: remove unused import<commit_after>#![feature(globs)]
#![feature(macro_rules)]

extern crate deuterium;
extern crate time;

use deuterium::*;

#[macro_export]
macro_rules! assert_sql(
    ($query:expr, $s:expr) => (
        assert_eq!($query.to_final_sql().as_slice(), $s)
    )
)

mod simple_select;
mod where_;

#[test]
fn select_1_first() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_1(&name).where_(
        name.is("Luke".to_string()).exclude()
    ).first().offset(10);

    assert_sql!(query, "SELECT name FROM jedi WHERE name != 'Luke' LIMIT 1 OFFSET 10;");

}

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_within() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().where_(name.within(vec!["Luke".to_string()]));
    assert_sql!(query, "SELECT * FROM jedi WHERE name IN ('Luke');");

}

#[test]
fn select_within_select() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.alias("j").select_all().where_(name.within(
        jedi_table.select_1(&name)
    ));

    assert_sql!(query, "SELECT * FROM jedi AS j WHERE name IN (SELECT name FROM jedi);");

}

#[test]
fn select_from_select() {

    let jedi_table = TableDef::new("jedi");

    let query = jedi_table.select_all().alias("jedi_list").select_all();
    assert_sql!(query, "SELECT * FROM (SELECT * FROM jedi) as jedi_list;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}

#[test]
fn aliases() {

    let jedi_table = TableDef::new("jedi");
    let jedi_a = jedi_table.alias("a");
    let jedi_b = jedi_table.alias("b");
    let name_a = NamedField::<String>::field_of("name", &jedi_a);
    let name_b = NamedField::<String>::field_of("name", &jedi_b);

    let query = jedi_a.select_all().inner_join(&jedi_b, name_a.is(name_b));
    assert_sql!(query, "SELECT * FROM jedi AS a INNER JOIN jedi AS b ON a.name = b.name;");

}<|endoftext|>


<commit_before>extern crate cbindgen;

use cbindgen::*;
use std::path::Path;
use std::process::Command;
use std::{env, fs};

fn run_cbindgen(
    cbindgen_path: &'static str,
    path: &Path,
    output: &Path,
    language: Language,
    style: Option<Style>,
) {
    let program = Path::new(cbindgen_path);
    let mut command = Command::new(&program);
    match language {
        Language::Cxx => {}
        Language::C => {
            command.arg("--lang").arg("c");
        }
    }

    if let Some(style) = style {
        command.arg("--style");
        command.arg(match style {
            Style::Both => "both",
            Style::Tag => "tag",
            Style::Type => "type",
        });
    }

    command.arg("-o").arg(output);

    if env::var("CBINDGEN_TEST_VERIFY").is_ok() {
        command.arg("--verify");
    }

    let mut config = path.clone().to_path_buf();
    config.set_extension("toml");
    if config.exists() {
        command.arg("--config").arg(config);
    }

    command.arg(path);

    println!("Running: {:?}", command);
    let cbindgen_output = command.output().expect("failed to execute process");
    assert!(
        cbindgen_output.status.success(),
        "cbindgen failed: {:?}",
        output
    );
}

fn compile(cbindgen_output: &Path, language: Language) {
    let cc = env::var("CC").unwrap_or_else(|_| match language {
        Language::Cxx => "g++".to_owned(),
        Language::C => "gcc".to_owned(),
    });

    let mut object = cbindgen_output.to_path_buf();
    object.set_extension("o");

    let mut command = Command::new(cc);
    command.arg("-D").arg("DEFINED");
    command.arg("-c").arg(cbindgen_output);
    command.arg("-o").arg(&object);
    if let Language::Cxx = language {
        // enum class is a c++11 extension which makes g++ on macos 10.14 error out
        command.arg("-std=c++11");
    }

    println!("Running: {:?}", command);
    let out = command.output().expect("failed to compile");
    assert!(out.status.success(), "Output failed to compile: {:?}", out);

    if object.exists() {
        fs::remove_file(object).unwrap();
    }
}

fn run_compile_test(
    cbindgen_path: &'static str,
    name: &'static str,
    path: &Path,
    language: Language,
    style: Option<Style>,
) {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut output = Path::new(&crate_dir).join("tests").join("expectations");
    if let Some(style) = style {
        match style {
            Style::Both => {
                output.push("both");
            }
            Style::Tag => {
                output.push("tag");
            }
            Style::Type => {}
        }
    }
    match language {
        Language::Cxx => {
            output.push(format!("{}.cpp", name));
        }
        Language::C => {
            output.push(format!("{}.c", name));
        }
    }

    run_cbindgen(cbindgen_path, path, &output, language, style);
    compile(&output, language);
}

fn test_file(cbindgen_path: &'static str, name: &'static str, filename: &'static str) {
    let test = Path::new(filename);
    for style in &[Style::Type, Style::Tag, Style::Both] {
        run_compile_test(cbindgen_path, name, &test, Language::C, Some(*style));
    }
    run_compile_test(cbindgen_path, name, &test, Language::Cxx, None);
}

macro_rules! test_file {
    ($cbindgen_path:expr, $test_function_name:ident, $name:expr, $file:tt) => {
        #[test]
        fn $test_function_name() {
            test_file($cbindgen_path, $name, $file);
        }
    };
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));
<commit_msg>Add stderr output of cbindgen to a tests error log upon failure<commit_after>extern crate cbindgen;

use cbindgen::*;
use std::path::Path;
use std::process::Command;
use std::{env, fs, str};

fn run_cbindgen(
    cbindgen_path: &'static str,
    path: &Path,
    output: &Path,
    language: Language,
    style: Option<Style>,
) {
    let program = Path::new(cbindgen_path);
    let mut command = Command::new(&program);
    match language {
        Language::Cxx => {}
        Language::C => {
            command.arg("--lang").arg("c");
        }
    }

    if let Some(style) = style {
        command.arg("--style");
        command.arg(match style {
            Style::Both => "both",
            Style::Tag => "tag",
            Style::Type => "type",
        });
    }

    command.arg("-o").arg(output);

    if env::var("CBINDGEN_TEST_VERIFY").is_ok() {
        command.arg("--verify");
    }

    let mut config = path.clone().to_path_buf();
    config.set_extension("toml");
    if config.exists() {
        command.arg("--config").arg(config);
    }

    command.arg(path);

    println!("Running: {:?}", command);
    let cbindgen_output = command.output().expect("failed to execute process");
    assert!(
        cbindgen_output.status.success(),
        "cbindgen failed: {:?} with error: {}",
        output,
        str::from_utf8(&cbindgen_output.stderr).unwrap_or_default()
    );
}

fn compile(cbindgen_output: &Path, language: Language) {
    let cc = env::var("CC").unwrap_or_else(|_| match language {
        Language::Cxx => "g++".to_owned(),
        Language::C => "gcc".to_owned(),
    });

    let mut object = cbindgen_output.to_path_buf();
    object.set_extension("o");

    let mut command = Command::new(cc);
    command.arg("-D").arg("DEFINED");
    command.arg("-c").arg(cbindgen_output);
    command.arg("-o").arg(&object);
    if let Language::Cxx = language {
        // enum class is a c++11 extension which makes g++ on macos 10.14 error out
        command.arg("-std=c++11");
    }

    println!("Running: {:?}", command);
    let out = command.output().expect("failed to compile");
    assert!(out.status.success(), "Output failed to compile: {:?}", out);

    if object.exists() {
        fs::remove_file(object).unwrap();
    }
}

fn run_compile_test(
    cbindgen_path: &'static str,
    name: &'static str,
    path: &Path,
    language: Language,
    style: Option<Style>,
) {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut output = Path::new(&crate_dir).join("tests").join("expectations");
    if let Some(style) = style {
        match style {
            Style::Both => {
                output.push("both");
            }
            Style::Tag => {
                output.push("tag");
            }
            Style::Type => {}
        }
    }
    match language {
        Language::Cxx => {
            output.push(format!("{}.cpp", name));
        }
        Language::C => {
            output.push(format!("{}.c", name));
        }
    }

    run_cbindgen(cbindgen_path, path, &output, language, style);
    compile(&output, language);
}

fn test_file(cbindgen_path: &'static str, name: &'static str, filename: &'static str) {
    let test = Path::new(filename);
    for style in &[Style::Type, Style::Tag, Style::Both] {
        run_compile_test(cbindgen_path, name, &test, Language::C, Some(*style));
    }
    run_compile_test(cbindgen_path, name, &test, Language::Cxx, None);
}

macro_rules! test_file {
    ($cbindgen_path:expr, $test_function_name:ident, $name:expr, $file:tt) => {
        #[test]
        fn $test_function_name() {
            test_file($cbindgen_path, $name, $file);
        }
    };
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));
<|endoftext|>


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

#![feature(custom_derive)]

extern crate chrono;
extern crate rocket;
extern crate postgres;
extern crate serde_json;

extern crate rocket_contrib;

#[macro_use] extern crate serde_derive;

mod webapp_config;
mod date_field;

use std::env;
use std::path::{Path, PathBuf};

use postgres::{Connection, TlsMode};
use chrono::{DateTime, UTC};

use rocket_contrib::JSON;
use rocket::response::{content, NamedFile};

#[macro_use]
extern crate lazy_static;

lazy_static!{
	static ref DATABASE_URI: String = env::var("GDQ_DATABASE_URI").unwrap();
	static ref CURRENT_EVENT_ID: String = env::var("GDQ_LIVE_EVENT_ID").unwrap();
}

static DONATAION_DATA_QUERY: &'static str = "SELECT id, timestamp, donation_count, donation_total FROM DonationEntry WHERE event_id = $1 ORDER BY timestamp ASC";
static DONATAION_DATA_UPDATE_QUERY: &'static str = "SELECT id, timestamp, donation_count, donation_total FROM DonationEntry WHERE event_id = $1 AND timestamp > $2 ORDER BY timestamp ASC";

#[derive(Serialize)]
struct DonationEntry {
	timestamp: DateTime<UTC>,
	count: i32,
	total: i32,
}

#[derive(Serialize)]
struct DataResponse(Vec<DonationEntry>);

#[derive(FromForm)]
struct DonationQuery {
	since: date_field::DateField,
}

#[get("/")]
fn index() -> content::HTML<String> {
	let response_str = format!(include_str!("index.html"), static_base=webapp_config::get_static_base());

	content::HTML(response_str)
}

#[get("/donation_data")]
fn get_donation_data() -> JSON<DataResponse>  {
	let database_uri: &str = &*DATABASE_URI;
	let db_connection = Connection::connect(database_uri, TlsMode::None).unwrap();

	let query_result = db_connection.query(DONATAION_DATA_QUERY, &[&*CURRENT_EVENT_ID]).unwrap();

	let result: Vec<DonationEntry> = query_result.iter().map(|row| DonationEntry { timestamp: row.get(1), count: row.get(2), total: row.get(3) }).collect();
	JSON(DataResponse(result))
}

#[get("/donation_data/update?<update_form>")]
fn get_donation_data_update(update_form: DonationQuery) -> JSON<DataResponse>  {
	let database_uri: &str = &*DATABASE_URI;
	let db_connection = Connection::connect(database_uri, TlsMode::None).unwrap();

	let date_field::DateField(since_date) = update_form.since;
	let query_result = db_connection.query(DONATAION_DATA_UPDATE_QUERY, &[&*CURRENT_EVENT_ID, &since_date]).unwrap();

	let result: Vec<DonationEntry> = query_result.iter().map(|row| DonationEntry { timestamp: row.get(1), count: row.get(2), total: row.get(3) }).collect();
	JSON(DataResponse(result))
}

#[get("/static/<file..>")]
fn static_files(file: PathBuf) -> Option<NamedFile> {
	NamedFile::open(Path::new("static/").join(file)).ok()
}

fn main() {
	if webapp_config::use_local_static_handler() {
		rocket::ignite().mount("/", routes![index, get_donation_data, get_donation_data_update, static_files]).launch()
	} else {
		rocket::ignite().mount("/", routes![index, get_donation_data, get_donation_data_update]).launch()
	}
}<commit_msg>Midify the webapp to send out the 2016 data<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

#![feature(custom_derive)]

extern crate chrono;
extern crate rocket;
extern crate postgres;
extern crate serde_json;

extern crate rocket_contrib;

#[macro_use] extern crate serde_derive;

mod webapp_config;
mod date_field;

use std::env;
use std::path::{Path, PathBuf};

use postgres::{Connection, TlsMode};
use chrono::{DateTime, UTC};

use rocket_contrib::JSON;
use rocket::response::{content, NamedFile};

#[macro_use]
extern crate lazy_static;

lazy_static!{
	static ref DATABASE_URI: String = env::var("GDQ_DATABASE_URI").unwrap();
	static ref CURRENT_EVENT_ID: String = env::var("GDQ_LIVE_EVENT_ID").unwrap();
}

static DONATAION_DATA_QUERY: &'static str = "SELECT id, timestamp, donation_count, donation_total, historic_total FROM DonationEntry WHERE event_id = $1 ORDER BY timestamp ASC";
static DONATAION_DATA_UPDATE_QUERY: &'static str = "SELECT id, timestamp, donation_count, donation_total, historic_total FROM DonationEntry WHERE event_id = $1 AND timestamp > $2 ORDER BY timestamp ASC";

#[derive(Serialize)]
struct DonationEntry {
	timestamp: DateTime<UTC>,
	count: i32,
	total: i32,
	total_2016: i32,
}

#[derive(Serialize)]
struct DataResponse(Vec<DonationEntry>);

#[derive(FromForm)]
struct DonationQuery {
	since: date_field::DateField,
}

#[get("/")]
fn index() -> content::HTML<String> {
	let response_str = format!(include_str!("index.html"), static_base=webapp_config::get_static_base());

	content::HTML(response_str)
}

#[get("/donation_data")]
fn get_donation_data() -> JSON<DataResponse>  {
	let database_uri: &str = &*DATABASE_URI;
	let db_connection = Connection::connect(database_uri, TlsMode::None).unwrap();

	let query_result = db_connection.query(DONATAION_DATA_QUERY, &[&*CURRENT_EVENT_ID]).unwrap();

	let result: Vec<DonationEntry> = query_result.iter().map(|row| DonationEntry { timestamp: row.get(1), count: row.get(2), total: row.get(3), total_2016: row.get(4) }).collect();
	JSON(DataResponse(result))
}

#[get("/donation_data/update?<update_form>")]
fn get_donation_data_update(update_form: DonationQuery) -> JSON<DataResponse>  {
	let database_uri: &str = &*DATABASE_URI;
	let db_connection = Connection::connect(database_uri, TlsMode::None).unwrap();

	let date_field::DateField(since_date) = update_form.since;
	let query_result = db_connection.query(DONATAION_DATA_UPDATE_QUERY, &[&*CURRENT_EVENT_ID, &since_date]).unwrap();

	let result: Vec<DonationEntry> = query_result.iter().map(|row| DonationEntry { timestamp: row.get(1), count: row.get(2), total: row.get(3), total_2016: row.get(4) }).collect();
	JSON(DataResponse(result))
}

#[get("/static/<file..>")]
fn static_files(file: PathBuf) -> Option<NamedFile> {
	NamedFile::open(Path::new("static/").join(file)).ok()
}

fn main() {
	if webapp_config::use_local_static_handler() {
		rocket::ignite().mount("/", routes![index, get_donation_data, get_donation_data_update, static_files]).launch()
	} else {
		rocket::ignite().mount("/", routes![index, get_donation_data, get_donation_data_update]).launch()
	}
}<|endoftext|>


<commit_before>extern crate which;

#[cfg(all(unix, feature = "regex"))]
use regex::Regex;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::{env, vec};
use tempfile::TempDir;

struct TestFixture {
    /// Temp directory.
    pub tempdir: TempDir,
    /// $PATH
    pub paths: OsString,
    /// Binaries created in $PATH
    pub bins: Vec<PathBuf>,
}

const SUBDIRS: &[&str] = &["a", "b", "c"];
const BIN_NAME: &str = "bin";

#[cfg(unix)]
fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    use std::os::unix::fs::OpenOptionsExt;
    let bin = dir.join(path).with_extension(extension);
    fs::OpenOptions::new()
        .write(true)
        .create(true)
        .mode(0o666 | (libc::S_IXUSR as u32))
        .open(&bin)
        .and_then(|_f| bin.canonicalize())
}

fn touch(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    let b = dir.join(path).with_extension(extension);
    fs::File::create(&b).and_then(|_f| b.canonicalize())
}

#[cfg(windows)]
fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    touch(dir, path, extension)
}

impl TestFixture {
    // tmp/a/bin
    // tmp/a/bin.exe
    // tmp/a/bin.cmd
    // tmp/b/bin
    // tmp/b/bin.exe
    // tmp/b/bin.cmd
    // tmp/c/bin
    // tmp/c/bin.exe
    // tmp/c/bin.cmd
    pub fn new() -> TestFixture {
        let tempdir = tempfile::tempdir().unwrap();
        let mut builder = fs::DirBuilder::new();
        builder.recursive(true);
        let mut paths = vec![];
        let mut bins = vec![];
        for d in SUBDIRS.iter() {
            let p = tempdir.path().join(d);
            builder.create(&p).unwrap();
            bins.push(mk_bin(&p, BIN_NAME, "").unwrap());
            bins.push(mk_bin(&p, BIN_NAME, "exe").unwrap());
            bins.push(mk_bin(&p, BIN_NAME, "cmd").unwrap());
            paths.push(p);
        }
        TestFixture {
            tempdir,
            paths: env::join_paths(paths).unwrap(),
            bins,
        }
    }

    #[allow(dead_code)]
    pub fn touch(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
        touch(self.tempdir.path(), path, extension)
    }

    pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
        mk_bin(self.tempdir.path(), path, extension)
    }
}

fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::CanonicalPath> {
    which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path())
}

fn _which_all<T: AsRef<OsStr>>(
    f: &TestFixture,
    path: T,
) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>>> {
    which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path().to_path_buf())
}

#[test]
#[cfg(unix)]
fn it_works() {
    use std::process::Command;
    let result = which::Path::new("rustc");
    assert!(result.is_ok());

    let which_result = Command::new("which").arg("rustc").output();

    assert_eq!(
        String::from(result.unwrap().to_str().unwrap()),
        String::from_utf8(which_result.unwrap().stdout)
            .unwrap()
            .trim()
    );
}

#[test]
#[cfg(unix)]
fn test_which() {
    let f = TestFixture::new();
    assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[0])
}

#[test]
#[cfg(windows)]
fn test_which() {
    let f = TestFixture::new();
    assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[1])
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_in_with_matches() {
    let f = TestFixture::new();
    f.mk_bin("a/bin_0", "").unwrap();
    f.mk_bin("b/bin_1", "").unwrap();
    let re = Regex::new(r"bin_\d").unwrap();

    let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths))
        .unwrap()
        .into_iter()
        .collect();

    let temp = f.tempdir;

    assert_eq!(
        result,
        vec![temp.path().join("a/bin_0"), temp.path().join("b/bin_1")]
    )
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_in_without_matches() {
    let f = TestFixture::new();
    let re = Regex::new(r"bi[^n]").unwrap();

    let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths))
        .unwrap()
        .into_iter()
        .collect();

    assert_eq!(result, Vec::<PathBuf>::new())
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_accepts_owned_and_borrow() {
    which::which_re(Regex::new(r".").unwrap())
        .unwrap()
        .for_each(drop);
    which::which_re(&Regex::new(r".").unwrap())
        .unwrap()
        .for_each(drop);
    which::which_re_in(Regex::new(r".").unwrap(), Some("pth"))
        .unwrap()
        .for_each(drop);
    which::which_re_in(&Regex::new(r".").unwrap(), Some("pth"))
        .unwrap()
        .for_each(drop);
}

#[test]
#[cfg(unix)]
fn test_which_extension() {
    let f = TestFixture::new();
    let b = Path::new(&BIN_NAME).with_extension("");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[0])
}

#[test]
#[cfg(windows)]
fn test_which_extension() {
    let f = TestFixture::new();
    let b = Path::new(&BIN_NAME).with_extension("cmd");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[2])
}

#[test]
fn test_which_not_found() {
    let f = TestFixture::new();
    assert!(_which(&f, "a").is_err());
}

#[test]
fn test_which_second() {
    let f = TestFixture::new();
    let b = f.mk_bin("b/another", env::consts::EXE_EXTENSION).unwrap();
    assert_eq!(_which(&f, "another").unwrap(), b);
}

#[test]
fn test_which_all() {
    let f = TestFixture::new();
    let actual = _which_all(&f, BIN_NAME)
        .unwrap()
        .map(|c| c.unwrap())
        .collect::<Vec<_>>();
    let mut expected = f
        .bins
        .iter()
        .map(|p| p.canonicalize().unwrap())
        .collect::<Vec<_>>();
    #[cfg(windows)]
    {
        expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true));
    }
    #[cfg(not(windows))]
    {
        expected.retain(|p| p.file_name().unwrap() == BIN_NAME);
    }
    assert_eq!(actual, expected);
}

#[test]
#[cfg(unix)]
fn test_which_absolute() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, &f.bins[3]).unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_absolute() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, &f.bins[4]).unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_absolute_path_case() {
    // Test that an absolute path with an uppercase extension
    // is accepted.
    let f = TestFixture::new();
    let p = &f.bins[4];
    assert_eq!(_which(&f, &p).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_absolute_extension() {
    let f = TestFixture::new();
    // Don't append EXE_EXTENSION here.
    let b = f.bins[3].parent().unwrap().join(&BIN_NAME);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_absolute_extension() {
    let f = TestFixture::new();
    // Don't append EXE_EXTENSION here.
    let b = f.bins[4].parent().unwrap().join(&BIN_NAME);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_relative() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "b/bin").unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_relative() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "b/bin").unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(unix)]
fn test_which_relative_extension() {
    // test_which_relative tests a relative path without an extension,
    // so test a relative path with an extension here.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_relative_extension() {
    // test_which_relative tests a relative path without an extension,
    // so test a relative path with an extension here.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension("cmd");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[5].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_relative_extension_case() {
    // Test that a relative path with an uppercase extension
    // is accepted.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension("EXE");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_relative_leading_dot() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "./b/bin").unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_relative_leading_dot() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "./b/bin").unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(unix)]
fn test_which_non_executable() {
    // Shouldn't return non-executable files.
    let f = TestFixture::new();
    f.touch("b/another", "").unwrap();
    assert!(_which(&f, "another").is_err());
}

#[test]
#[cfg(unix)]
fn test_which_absolute_non_executable() {
    // Shouldn't return non-executable files, even if given an absolute path.
    let f = TestFixture::new();
    let b = f.touch("b/another", "").unwrap();
    assert!(_which(&f, &b).is_err());
}

#[test]
#[cfg(unix)]
fn test_which_relative_non_executable() {
    // Shouldn't return non-executable files.
    let f = TestFixture::new();
    f.touch("b/another", "").unwrap();
    assert!(_which(&f, "b/another").is_err());
}

#[test]
fn test_failure() {
    let f = TestFixture::new();

    let run = || -> which::Result<PathBuf> {
        let p = _which(&f, "./b/bin")?;
        Ok(p.into_path_buf())
    };

    let _ = run();
}
<commit_msg>fix clippy warning<commit_after>extern crate which;

#[cfg(all(unix, feature = "regex"))]
use regex::Regex;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::{env, vec};
use tempfile::TempDir;

struct TestFixture {
    /// Temp directory.
    pub tempdir: TempDir,
    /// $PATH
    pub paths: OsString,
    /// Binaries created in $PATH
    pub bins: Vec<PathBuf>,
}

const SUBDIRS: &[&str] = &["a", "b", "c"];
const BIN_NAME: &str = "bin";

#[cfg(unix)]
fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    use std::os::unix::fs::OpenOptionsExt;
    let bin = dir.join(path).with_extension(extension);
    fs::OpenOptions::new()
        .write(true)
        .create(true)
        .mode(0o666 | (libc::S_IXUSR as u32))
        .open(&bin)
        .and_then(|_f| bin.canonicalize())
}

fn touch(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    let b = dir.join(path).with_extension(extension);
    fs::File::create(&b).and_then(|_f| b.canonicalize())
}

#[cfg(windows)]
fn mk_bin(dir: &Path, path: &str, extension: &str) -> io::Result<PathBuf> {
    touch(dir, path, extension)
}

impl TestFixture {
    // tmp/a/bin
    // tmp/a/bin.exe
    // tmp/a/bin.cmd
    // tmp/b/bin
    // tmp/b/bin.exe
    // tmp/b/bin.cmd
    // tmp/c/bin
    // tmp/c/bin.exe
    // tmp/c/bin.cmd
    pub fn new() -> TestFixture {
        let tempdir = tempfile::tempdir().unwrap();
        let mut builder = fs::DirBuilder::new();
        builder.recursive(true);
        let mut paths = vec![];
        let mut bins = vec![];
        for d in SUBDIRS.iter() {
            let p = tempdir.path().join(d);
            builder.create(&p).unwrap();
            bins.push(mk_bin(&p, BIN_NAME, "").unwrap());
            bins.push(mk_bin(&p, BIN_NAME, "exe").unwrap());
            bins.push(mk_bin(&p, BIN_NAME, "cmd").unwrap());
            paths.push(p);
        }
        TestFixture {
            tempdir,
            paths: env::join_paths(paths).unwrap(),
            bins,
        }
    }

    #[allow(dead_code)]
    pub fn touch(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
        touch(self.tempdir.path(), path, extension)
    }

    pub fn mk_bin(&self, path: &str, extension: &str) -> io::Result<PathBuf> {
        mk_bin(self.tempdir.path(), path, extension)
    }
}

fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> which::Result<which::CanonicalPath> {
    which::CanonicalPath::new_in(path, Some(f.paths.clone()), f.tempdir.path())
}

fn _which_all<'a, T: AsRef<OsStr> + 'a>(
    f: &'a TestFixture,
    path: T,
) -> which::Result<impl Iterator<Item = which::Result<which::CanonicalPath>> + '_> {
    which::CanonicalPath::all_in(path, Some(f.paths.clone()), f.tempdir.path())
}

#[test]
#[cfg(unix)]
fn it_works() {
    use std::process::Command;
    let result = which::Path::new("rustc");
    assert!(result.is_ok());

    let which_result = Command::new("which").arg("rustc").output();

    assert_eq!(
        String::from(result.unwrap().to_str().unwrap()),
        String::from_utf8(which_result.unwrap().stdout)
            .unwrap()
            .trim()
    );
}

#[test]
#[cfg(unix)]
fn test_which() {
    let f = TestFixture::new();
    assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[0])
}

#[test]
#[cfg(windows)]
fn test_which() {
    let f = TestFixture::new();
    assert_eq!(_which(&f, &BIN_NAME).unwrap(), f.bins[1])
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_in_with_matches() {
    let f = TestFixture::new();
    f.mk_bin("a/bin_0", "").unwrap();
    f.mk_bin("b/bin_1", "").unwrap();
    let re = Regex::new(r"bin_\d").unwrap();

    let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths))
        .unwrap()
        .into_iter()
        .collect();

    let temp = f.tempdir;

    assert_eq!(
        result,
        vec![temp.path().join("a/bin_0"), temp.path().join("b/bin_1")]
    )
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_in_without_matches() {
    let f = TestFixture::new();
    let re = Regex::new(r"bi[^n]").unwrap();

    let result: Vec<PathBuf> = which::which_re_in(re, Some(f.paths))
        .unwrap()
        .into_iter()
        .collect();

    assert_eq!(result, Vec::<PathBuf>::new())
}

#[test]
#[cfg(all(unix, feature = "regex"))]
fn test_which_re_accepts_owned_and_borrow() {
    which::which_re(Regex::new(r".").unwrap())
        .unwrap()
        .for_each(drop);
    which::which_re(&Regex::new(r".").unwrap())
        .unwrap()
        .for_each(drop);
    which::which_re_in(Regex::new(r".").unwrap(), Some("pth"))
        .unwrap()
        .for_each(drop);
    which::which_re_in(&Regex::new(r".").unwrap(), Some("pth"))
        .unwrap()
        .for_each(drop);
}

#[test]
#[cfg(unix)]
fn test_which_extension() {
    let f = TestFixture::new();
    let b = Path::new(&BIN_NAME).with_extension("");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[0])
}

#[test]
#[cfg(windows)]
fn test_which_extension() {
    let f = TestFixture::new();
    let b = Path::new(&BIN_NAME).with_extension("cmd");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[2])
}

#[test]
fn test_which_not_found() {
    let f = TestFixture::new();
    assert!(_which(&f, "a").is_err());
}

#[test]
fn test_which_second() {
    let f = TestFixture::new();
    let b = f.mk_bin("b/another", env::consts::EXE_EXTENSION).unwrap();
    assert_eq!(_which(&f, "another").unwrap(), b);
}

#[test]
fn test_which_all() {
    let f = TestFixture::new();
    let actual = _which_all(&f, BIN_NAME)
        .unwrap()
        .map(|c| c.unwrap())
        .collect::<Vec<_>>();
    let mut expected = f
        .bins
        .iter()
        .map(|p| p.canonicalize().unwrap())
        .collect::<Vec<_>>();
    #[cfg(windows)]
    {
        expected.retain(|p| p.extension().map(|ext| ext == "exe" || ext == "cmd") == Some(true));
    }
    #[cfg(not(windows))]
    {
        expected.retain(|p| p.file_name().unwrap() == BIN_NAME);
    }
    assert_eq!(actual, expected);
}

#[test]
#[cfg(unix)]
fn test_which_absolute() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, &f.bins[3]).unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_absolute() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, &f.bins[4]).unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_absolute_path_case() {
    // Test that an absolute path with an uppercase extension
    // is accepted.
    let f = TestFixture::new();
    let p = &f.bins[4];
    assert_eq!(_which(&f, &p).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_absolute_extension() {
    let f = TestFixture::new();
    // Don't append EXE_EXTENSION here.
    let b = f.bins[3].parent().unwrap().join(&BIN_NAME);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_absolute_extension() {
    let f = TestFixture::new();
    // Don't append EXE_EXTENSION here.
    let b = f.bins[4].parent().unwrap().join(&BIN_NAME);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_relative() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "b/bin").unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_relative() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "b/bin").unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(unix)]
fn test_which_relative_extension() {
    // test_which_relative tests a relative path without an extension,
    // so test a relative path with an extension here.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(_which(&f, &b).unwrap(), f.bins[3].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_relative_extension() {
    // test_which_relative tests a relative path without an extension,
    // so test a relative path with an extension here.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension("cmd");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[5].canonicalize().unwrap());
}

#[test]
#[cfg(windows)]
fn test_which_relative_extension_case() {
    // Test that a relative path with an uppercase extension
    // is accepted.
    let f = TestFixture::new();
    let b = Path::new("b/bin").with_extension("EXE");
    assert_eq!(_which(&f, &b).unwrap(), f.bins[4].canonicalize().unwrap());
}

#[test]
#[cfg(unix)]
fn test_which_relative_leading_dot() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "./b/bin").unwrap(),
        f.bins[3].canonicalize().unwrap()
    );
}

#[test]
#[cfg(windows)]
fn test_which_relative_leading_dot() {
    let f = TestFixture::new();
    assert_eq!(
        _which(&f, "./b/bin").unwrap(),
        f.bins[4].canonicalize().unwrap()
    );
}

#[test]
#[cfg(unix)]
fn test_which_non_executable() {
    // Shouldn't return non-executable files.
    let f = TestFixture::new();
    f.touch("b/another", "").unwrap();
    assert!(_which(&f, "another").is_err());
}

#[test]
#[cfg(unix)]
fn test_which_absolute_non_executable() {
    // Shouldn't return non-executable files, even if given an absolute path.
    let f = TestFixture::new();
    let b = f.touch("b/another", "").unwrap();
    assert!(_which(&f, &b).is_err());
}

#[test]
#[cfg(unix)]
fn test_which_relative_non_executable() {
    // Shouldn't return non-executable files.
    let f = TestFixture::new();
    f.touch("b/another", "").unwrap();
    assert!(_which(&f, "b/another").is_err());
}

#[test]
fn test_failure() {
    let f = TestFixture::new();

    let run = || -> which::Result<PathBuf> {
        let p = _which(&f, "./b/bin")?;
        Ok(p.into_path_buf())
    };

    let _ = run();
}
<|endoftext|>


<commit_before>#![feature(try_from)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate iron;
extern crate mount;
extern crate playground_middleware;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;
extern crate mktemp;
#[macro_use]
extern crate quick_error;

use std::any::Any;
use std::convert::{TryFrom, TryInto};
use std::env;
use std::path::PathBuf;
use std::time::Duration;

use iron::headers::ContentType;
use iron::modifiers::Header;
use iron::prelude::*;
use iron::status;

use mount::Mount;
use serde::{Serialize, Deserialize};
use playground_middleware::{
    Staticfile, Cache, Prefix, ModifyWith, GuessContentType, FileLogger, StatisticLogger
};

use sandbox::Sandbox;

const DEFAULT_ADDRESS: &'static str = "127.0.0.1";
const DEFAULT_PORT: u16 = 5000;
const DEFAULT_LOG_FILE: &'static str = "access-log.csv";

mod sandbox;

const ONE_DAY_IN_SECONDS: u64 = 60 * 60 * 24;
const ONE_YEAR_IN_SECONDS: u64 = 60 * 60 * 24 * 365;

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

    let root: PathBuf = env::var_os("PLAYGROUND_UI_ROOT").expect("Must specify PLAYGROUND_UI_ROOT").into();
    let address = env::var("PLAYGROUND_UI_ADDRESS").unwrap_or(DEFAULT_ADDRESS.to_string());
    let port = env::var("PLAYGROUND_UI_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(DEFAULT_PORT);
    let logfile = env::var("PLAYGROUND_LOG_FILE").unwrap_or(DEFAULT_LOG_FILE.to_string());

    let files = Staticfile::new(&root).expect("Unable to open root directory");
    let mut files = Chain::new(files);
    let one_day = Duration::new(ONE_DAY_IN_SECONDS, 0);
    let one_year = Duration::new(ONE_YEAR_IN_SECONDS, 0);

    files.link_after(ModifyWith::new(Cache::new(one_day)));
    files.link_after(Prefix::new(&["assets"], Cache::new(one_year)));
    files.link_after(GuessContentType::new(ContentType::html().0));

    let mut mount = Mount::new();
    mount.mount("/", files);
    mount.mount("/compile", compile);
    mount.mount("/execute", execute);
    mount.mount("/format", format);
    mount.mount("/clippy", clippy);

    let mut chain = Chain::new(mount);
    let file_logger = FileLogger::new(logfile).expect("Unable to create file logger");
    let logger = StatisticLogger::new(file_logger);
    chain.link_around(logger);

    info!("Starting the server on {}:{}", address, port);
    Iron::new(chain).http((&*address, port)).expect("Unable to start server");
}

fn compile(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: CompileRequest| {
        let req = try!(req.try_into());
        sandbox
            .compile(&req)
            .map(CompileResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn execute(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ExecuteRequest| {
        let req = try!(req.try_into());
        sandbox
            .execute(&req)
            .map(ExecuteResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn format(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: FormatRequest| {
        sandbox
            .format(&req.into())
            .map(FormatResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn clippy(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ClippyRequest| {
        sandbox
            .clippy(&req.into())
            .map(ClippyResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn with_sandbox<Req, Resp, F>(req: &mut Request, f: F) -> IronResult<Response>
    where F: FnOnce(Sandbox, Req) -> Result<Resp>,
          Req: Deserialize + Clone + Any + 'static,
          Resp: Serialize,
{
    let response = req.get::<bodyparser::Struct<Req>>()
        .map_err(Error::Deserialization)
        .and_then(|r| r.ok_or(Error::RequestMissing))
        .and_then(|req| {
            let sandbox = try!(Sandbox::new());
            let resp = try!(f(sandbox, req));
            let body = try!(serde_json::ser::to_string(&resp));
            Ok(body)
        });

    match response {
        Ok(body) => Ok(Response::with((status::Ok, Header(ContentType::json()), body))),
        Err(err) => {
            let err = ErrorJson { error: err.to_string() };
            match serde_json::ser::to_string(&err) {
                Ok(error_str) => Ok(Response::with((status::InternalServerError, Header(ContentType::json()), error_str))),
                Err(_) => Ok(Response::with((status::InternalServerError, Header(ContentType::json()), FATAL_ERROR_JSON))),
            }
        },
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Sandbox(err: sandbox::Error) {
            description("sandbox operation failed")
            display("Sandbox operation failed: {}", err)
            cause(err)
            from()
        }
        Serialization(err: serde_json::Error) {
            description("unable to serialize response")
            display("Unable to serialize response: {}", err)
            cause(err)
            from()
        }
        Deserialization(err: bodyparser::BodyError) {
            description("unable to deserialize request")
            display("Unable to deserialize request: {}", err)
            cause(err)
            from()
        }
        InvalidTarget(value: String) {
            description("an invalid target was passed")
            display("The value {:?} is not a valid target", value)
        }
        InvalidChannel(value: String) {
            description("an invalid channel was passed")
            display("The value {:?} is not a valid channel", value,)
        }
        InvalidMode(value: String) {
            description("an invalid mode was passed")
            display("The value {:?} is not a valid mode", value)
        }
        RequestMissing {
            description("no request was provided")
            display("No request was provided")
        }
    }
}

type Result<T> = ::std::result::Result<T, Error>;

const FATAL_ERROR_JSON: &'static str =
    r#"{"error": "Multiple cascading errors occurred, abandon all hope"}"#;

include!(concat!(env!("OUT_DIR"), "/data.rs"));

impl TryFrom<CompileRequest> for sandbox::CompileRequest {
    type Err = Error;

    fn try_from(me: CompileRequest) -> Result<Self> {
        Ok(sandbox::CompileRequest {
            target: try!(parse_target(&me.target)),
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            crate_type: try!(parse_crate_type(&me.crate_type)),
            tests: me.tests,
            code: me.code,
        })
    }
}

impl From<sandbox::CompileResponse> for CompileResponse {
    fn from(me: sandbox::CompileResponse) -> Self {
        CompileResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl TryFrom<ExecuteRequest> for sandbox::ExecuteRequest {
    type Err = Error;

    fn try_from(me: ExecuteRequest) -> Result<Self> {
        Ok(sandbox::ExecuteRequest {
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            crate_type: try!(parse_crate_type(&me.crate_type)),
            tests: me.tests,
            code: me.code,
        })
    }
}

impl From<sandbox::ExecuteResponse> for ExecuteResponse {
    fn from(me: sandbox::ExecuteResponse) -> Self {
        ExecuteResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl From<FormatRequest> for sandbox::FormatRequest {
    fn from(me: FormatRequest) -> Self {
        sandbox::FormatRequest {
            code: me.code,
        }
    }
}

impl From<sandbox::FormatResponse> for FormatResponse {
    fn from(me: sandbox::FormatResponse) -> Self {
        FormatResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl From<ClippyRequest> for sandbox::ClippyRequest {
    fn from(me: ClippyRequest) -> Self {
        sandbox::ClippyRequest {
            code: me.code,
        }
    }
}

impl From<sandbox::ClippyResponse> for ClippyResponse {
    fn from(me: sandbox::ClippyResponse) -> Self {
        ClippyResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

fn parse_target(s: &str) -> Result<sandbox::CompileTarget> {
    Ok(match s {
        "asm" => sandbox::CompileTarget::Assembly,
        "llvm-ir" => sandbox::CompileTarget::LlvmIr,
        _ => return Err(Error::InvalidTarget(s.into()))
    })
}

fn parse_channel(s: &str) -> Result<sandbox::Channel> {
    Ok(match s {
        "stable" => sandbox::Channel::Stable,
        "beta" => sandbox::Channel::Beta,
        "nightly" => sandbox::Channel::Nightly,
        _ => return Err(Error::InvalidChannel(s.into()))
    })
}

fn parse_mode(s: &str) -> Result<sandbox::Mode> {
    Ok(match s {
        "debug" => sandbox::Mode::Debug,
        "release" => sandbox::Mode::Release,
        _ => return Err(Error::InvalidMode(s.into()))
    })
}

fn parse_crate_type(s: &str) -> Result<sandbox::CrateType> {
    println!(">{:?}<", s);
    Ok(match s {
        "bin" => sandbox::CrateType::Binary,
        _ => sandbox::CrateType::Library,
    })
}
<commit_msg>Remove rogue debugging print<commit_after>#![feature(try_from)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate iron;
extern crate mount;
extern crate playground_middleware;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;
extern crate mktemp;
#[macro_use]
extern crate quick_error;

use std::any::Any;
use std::convert::{TryFrom, TryInto};
use std::env;
use std::path::PathBuf;
use std::time::Duration;

use iron::headers::ContentType;
use iron::modifiers::Header;
use iron::prelude::*;
use iron::status;

use mount::Mount;
use serde::{Serialize, Deserialize};
use playground_middleware::{
    Staticfile, Cache, Prefix, ModifyWith, GuessContentType, FileLogger, StatisticLogger
};

use sandbox::Sandbox;

const DEFAULT_ADDRESS: &'static str = "127.0.0.1";
const DEFAULT_PORT: u16 = 5000;
const DEFAULT_LOG_FILE: &'static str = "access-log.csv";

mod sandbox;

const ONE_DAY_IN_SECONDS: u64 = 60 * 60 * 24;
const ONE_YEAR_IN_SECONDS: u64 = 60 * 60 * 24 * 365;

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

    let root: PathBuf = env::var_os("PLAYGROUND_UI_ROOT").expect("Must specify PLAYGROUND_UI_ROOT").into();
    let address = env::var("PLAYGROUND_UI_ADDRESS").unwrap_or(DEFAULT_ADDRESS.to_string());
    let port = env::var("PLAYGROUND_UI_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(DEFAULT_PORT);
    let logfile = env::var("PLAYGROUND_LOG_FILE").unwrap_or(DEFAULT_LOG_FILE.to_string());

    let files = Staticfile::new(&root).expect("Unable to open root directory");
    let mut files = Chain::new(files);
    let one_day = Duration::new(ONE_DAY_IN_SECONDS, 0);
    let one_year = Duration::new(ONE_YEAR_IN_SECONDS, 0);

    files.link_after(ModifyWith::new(Cache::new(one_day)));
    files.link_after(Prefix::new(&["assets"], Cache::new(one_year)));
    files.link_after(GuessContentType::new(ContentType::html().0));

    let mut mount = Mount::new();
    mount.mount("/", files);
    mount.mount("/compile", compile);
    mount.mount("/execute", execute);
    mount.mount("/format", format);
    mount.mount("/clippy", clippy);

    let mut chain = Chain::new(mount);
    let file_logger = FileLogger::new(logfile).expect("Unable to create file logger");
    let logger = StatisticLogger::new(file_logger);
    chain.link_around(logger);

    info!("Starting the server on {}:{}", address, port);
    Iron::new(chain).http((&*address, port)).expect("Unable to start server");
}

fn compile(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: CompileRequest| {
        let req = try!(req.try_into());
        sandbox
            .compile(&req)
            .map(CompileResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn execute(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ExecuteRequest| {
        let req = try!(req.try_into());
        sandbox
            .execute(&req)
            .map(ExecuteResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn format(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: FormatRequest| {
        sandbox
            .format(&req.into())
            .map(FormatResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn clippy(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ClippyRequest| {
        sandbox
            .clippy(&req.into())
            .map(ClippyResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn with_sandbox<Req, Resp, F>(req: &mut Request, f: F) -> IronResult<Response>
    where F: FnOnce(Sandbox, Req) -> Result<Resp>,
          Req: Deserialize + Clone + Any + 'static,
          Resp: Serialize,
{
    let response = req.get::<bodyparser::Struct<Req>>()
        .map_err(Error::Deserialization)
        .and_then(|r| r.ok_or(Error::RequestMissing))
        .and_then(|req| {
            let sandbox = try!(Sandbox::new());
            let resp = try!(f(sandbox, req));
            let body = try!(serde_json::ser::to_string(&resp));
            Ok(body)
        });

    match response {
        Ok(body) => Ok(Response::with((status::Ok, Header(ContentType::json()), body))),
        Err(err) => {
            let err = ErrorJson { error: err.to_string() };
            match serde_json::ser::to_string(&err) {
                Ok(error_str) => Ok(Response::with((status::InternalServerError, Header(ContentType::json()), error_str))),
                Err(_) => Ok(Response::with((status::InternalServerError, Header(ContentType::json()), FATAL_ERROR_JSON))),
            }
        },
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Sandbox(err: sandbox::Error) {
            description("sandbox operation failed")
            display("Sandbox operation failed: {}", err)
            cause(err)
            from()
        }
        Serialization(err: serde_json::Error) {
            description("unable to serialize response")
            display("Unable to serialize response: {}", err)
            cause(err)
            from()
        }
        Deserialization(err: bodyparser::BodyError) {
            description("unable to deserialize request")
            display("Unable to deserialize request: {}", err)
            cause(err)
            from()
        }
        InvalidTarget(value: String) {
            description("an invalid target was passed")
            display("The value {:?} is not a valid target", value)
        }
        InvalidChannel(value: String) {
            description("an invalid channel was passed")
            display("The value {:?} is not a valid channel", value,)
        }
        InvalidMode(value: String) {
            description("an invalid mode was passed")
            display("The value {:?} is not a valid mode", value)
        }
        RequestMissing {
            description("no request was provided")
            display("No request was provided")
        }
    }
}

type Result<T> = ::std::result::Result<T, Error>;

const FATAL_ERROR_JSON: &'static str =
    r#"{"error": "Multiple cascading errors occurred, abandon all hope"}"#;

include!(concat!(env!("OUT_DIR"), "/data.rs"));

impl TryFrom<CompileRequest> for sandbox::CompileRequest {
    type Err = Error;

    fn try_from(me: CompileRequest) -> Result<Self> {
        Ok(sandbox::CompileRequest {
            target: try!(parse_target(&me.target)),
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            crate_type: try!(parse_crate_type(&me.crate_type)),
            tests: me.tests,
            code: me.code,
        })
    }
}

impl From<sandbox::CompileResponse> for CompileResponse {
    fn from(me: sandbox::CompileResponse) -> Self {
        CompileResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl TryFrom<ExecuteRequest> for sandbox::ExecuteRequest {
    type Err = Error;

    fn try_from(me: ExecuteRequest) -> Result<Self> {
        Ok(sandbox::ExecuteRequest {
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            crate_type: try!(parse_crate_type(&me.crate_type)),
            tests: me.tests,
            code: me.code,
        })
    }
}

impl From<sandbox::ExecuteResponse> for ExecuteResponse {
    fn from(me: sandbox::ExecuteResponse) -> Self {
        ExecuteResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl From<FormatRequest> for sandbox::FormatRequest {
    fn from(me: FormatRequest) -> Self {
        sandbox::FormatRequest {
            code: me.code,
        }
    }
}

impl From<sandbox::FormatResponse> for FormatResponse {
    fn from(me: sandbox::FormatResponse) -> Self {
        FormatResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

impl From<ClippyRequest> for sandbox::ClippyRequest {
    fn from(me: ClippyRequest) -> Self {
        sandbox::ClippyRequest {
            code: me.code,
        }
    }
}

impl From<sandbox::ClippyResponse> for ClippyResponse {
    fn from(me: sandbox::ClippyResponse) -> Self {
        ClippyResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

fn parse_target(s: &str) -> Result<sandbox::CompileTarget> {
    Ok(match s {
        "asm" => sandbox::CompileTarget::Assembly,
        "llvm-ir" => sandbox::CompileTarget::LlvmIr,
        _ => return Err(Error::InvalidTarget(s.into()))
    })
}

fn parse_channel(s: &str) -> Result<sandbox::Channel> {
    Ok(match s {
        "stable" => sandbox::Channel::Stable,
        "beta" => sandbox::Channel::Beta,
        "nightly" => sandbox::Channel::Nightly,
        _ => return Err(Error::InvalidChannel(s.into()))
    })
}

fn parse_mode(s: &str) -> Result<sandbox::Mode> {
    Ok(match s {
        "debug" => sandbox::Mode::Debug,
        "release" => sandbox::Mode::Release,
        _ => return Err(Error::InvalidMode(s.into()))
    })
}

fn parse_crate_type(s: &str) -> Result<sandbox::CrateType> {
    Ok(match s {
        "bin" => sandbox::CrateType::Binary,
        _ => sandbox::CrateType::Library,
    })
}
<|endoftext|>


<commit_before>/* diosix error codes
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* how things can go wrong */
#[derive(Debug)]
pub enum Cause
{
    /* misc */
    NotImplemented,

    /* debug */
    DebugInitFailed,

    /* devices */
    DeviceTreeBad,
    CantCloneDevices,
    BootDeviceTreeBad,

    /* physical CPU cores */
    PhysicalCoreBadID,
    PhysicalCoreCountUnknown,

    /* capsule services */
    ServiceAlreadyRegistered,
    ServiceNotAllowed,
    ServiceNotFound,

    /* messages */
    MessageBadType,

    /* heap */
    HeapNotInUse,
    HeapBadBlock,
    HeapNoFreeMem,
    HeapBadSize,
    HeapBadMagic,

    /* virtual core management */
    VirtualCoreBadID,
    VirtualCoreAWOL,

    /* host physical memory */
    PhysNoRAMFound,
    PhysNotEnoughFreeRAM,
    PhysRegionTooSmall,
    PhysRegionCollision,
    PhysRegionNoMatch,
    PhysRegionSplitOutOfBounds,
    PhysRegionRegionAlignmentFailure,
    PhysRegionSmallNotMultiple,
    PhysRegionLargeNotMultiple,

    /* capsule virtual memory */
    VirtMemPhysNotSet,

    /* capsules */
    CapsuleIDExhaustion,
    CapsuleBadID,
    CapsuleCannotRestart,
    CapsuleCantDie,
    CapsuleCantRestart,

    /* scheduler and timer */
    SchedNoTimer,

    /* supervisor binary loading */
    LoaderUnrecognizedCPUArch,
    LoaderSupervisorTooLarge,
    LoaderSupervisorFileSizeTooLarge,
    LoaderSupervisorEntryOutOfRange,
    LoaderUnrecognizedSupervisor,
    LoaderSupervisorBadImageOffset,
    LoaderSupervisorBadPhysOffset,
    LoaderSupervisorBadDynamicArea,
    LoaderSupervisorBadRelaEntrySize,
    LoaderSupervisorRelaTableTooBig,
    LoaderSupervisorBadRelaTblEntry,
    LoaderSupervisorUnknownRelaType,
    LoaderBadEntry,

    /* manifest errors */
    ManifestBadFS,
    ManifestNoSuchAsset
}
<commit_msg>Update error codes for services and stdin<commit_after>/* diosix error codes
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* how things can go wrong */
#[derive(Debug)]
pub enum Cause
{
    /* misc */
    NotImplemented,

    /* debug */
    DebugInitFailed,

    /* devices */
    DeviceTreeBad,
    CantCloneDevices,
    BootDeviceTreeBad,

    /* physical CPU cores */
    PhysicalCoreBadID,
    PhysicalCoreCountUnknown,

    /* capsule services */
    ServiceAlreadyRegistered,
    ServiceAlreadyOwner,
    ServiceNotAllowed,
    ServiceNotFound,

    /* messages */
    MessageBadType,

    /* heap */
    HeapNotInUse,
    HeapBadBlock,
    HeapNoFreeMem,
    HeapBadSize,
    HeapBadMagic,

    /* virtual core management */
    VirtualCoreBadID,
    VirtualCoreAWOL,

    /* host physical memory */
    PhysNoRAMFound,
    PhysNotEnoughFreeRAM,
    PhysRegionTooSmall,
    PhysRegionCollision,
    PhysRegionNoMatch,
    PhysRegionSplitOutOfBounds,
    PhysRegionRegionAlignmentFailure,
    PhysRegionSmallNotMultiple,
    PhysRegionLargeNotMultiple,

    /* capsule virtual memory */
    VirtMemPhysNotSet,

    /* capsules */
    CapsuleIDExhaustion,
    CapsuleBadID,
    CapsuleCannotRestart,
    CapsuleCantDie,
    CapsuleCantRestart,
    CapsuleStdinEmpty,

    /* scheduler and timer */
    SchedNoTimer,

    /* supervisor binary loading */
    LoaderUnrecognizedCPUArch,
    LoaderSupervisorTooLarge,
    LoaderSupervisorFileSizeTooLarge,
    LoaderSupervisorEntryOutOfRange,
    LoaderUnrecognizedSupervisor,
    LoaderSupervisorBadImageOffset,
    LoaderSupervisorBadPhysOffset,
    LoaderSupervisorBadDynamicArea,
    LoaderSupervisorBadRelaEntrySize,
    LoaderSupervisorRelaTableTooBig,
    LoaderSupervisorBadRelaTblEntry,
    LoaderSupervisorUnknownRelaType,
    LoaderBadEntry,

    /* manifest errors */
    ManifestBadFS,
    ManifestNoSuchAsset
}
<|endoftext|>


<commit_before>extern crate centralgithook;
extern crate fern;
extern crate git2;
extern crate regex;
extern crate tempdir;

#[macro_use]
extern crate log;

use centralgithook::*;
use git2::Oid;
use regex::Regex;
use rouille::cgi::CgiRun;
use std::env::current_exe;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io;
use std::os::unix::fs::symlink;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::exit;

// #[macro_use]
extern crate rouille;

fn setup_tmp_repo(scratch_dir: &Path, view: Option<&str>) -> PathBuf
{
    let path = thread_local_temp_dir();

    let root = match view {
        Some(view) => view_ref_root(&view),
        None => "refs".to_string(),
    };

    debug!("setup_tmp_repo, root: {:?}", &root);
    let shell = Shell { cwd: path.to_path_buf() };

    let ce = current_exe().expect("can't find path to exe");
    shell.command("mkdir hooks");
    symlink(ce, path.join("hooks").join("update")).expect("can't symlink update hook");

    shell.command(&format!("cp {:?} {:?}", scratch_dir.join("HEAD"), path));
    shell.command(&format!("cp {:?} {:?}", scratch_dir.join("config"), path));
    symlink(scratch_dir.join(root), path.join("refs")).expect("can't symlink refs");
    symlink(scratch_dir.join("objects"), path.join("objects")).expect("can't symlink objects");

    shell.command(&format!("printf {} > view",
                           match view {
                               Some(view) => view,
                               None => ".",
                           }));

    shell.command(&format!("printf {} > orig", scratch_dir.to_string_lossy()));
    /* shell.command("ls"); */
    return path;
}

fn fetch_origin_master(repo: git2::Repository) -> Result<(), git2::Error> {
    repo.find_remote("origin")?.fetch(&["master"], None, None)
}

fn main() { exit(main_ret()); }

fn main_ret() -> i32 {

    let mut args = vec![];
    for arg in env::args() {
        args.push(arg);
    }
    debug!("args: {:?}", args);

    let logfilename = Path::new("/tmp/centralgit.log");
    fern::Dispatch::new()
    .format(|out, message, record| {
        out.finish(format_args!(
            "{}[{}] {}",
            record.target(),
            record.level(),
            message
        ))
    })
    .level(log::LevelFilter::Debug)
    .chain(std::io::stdout())
    .chain(fern::log_file(logfilename).unwrap())
    .apply().unwrap();

    if args[0].ends_with("/update") {
        debug!("================= HOOK {:?}", args);
        return update_hook(&args[1], &args[2], &args[3]);
    }

    let base_repo = do_clone_base(
        &args[1],
        &args[2],
        &args[3],
        &PathBuf::from(&args[4]));
        /* "gerrit:29418", */
        /* "bsw/central.git", */
        /* "christian.schilling", */
        /* &PathBuf::from("/Users/christian/.ssh/id_rsa")); */
    println!("Now listening on localhost:8000");

    rouille::start_server("localhost:8000", move |request| {
        rouille::log(&request, io::stdout(), || {

            /* let auth = match rouille::input::basic_http_auth(request) { */
            /*     Some(a) => a, */
            /*     _ => return rouille::Response::basic_http_auth_login_required("realm") */
            /* }; */

            /* if !(auth.login == "me" && auth.password == "secret") { */
            /*     return rouille::Response::text("bad credentials").with_status_code(403); */
            /* } */

            println!("X\nX\nX\nURL: {}", request.url());
            let re = Regex::new(r"(?P<prefix>/.*[.]git)/.*").expect("can't compile regex");

            let prefix = if let Some(caps) = re.captures(&request.url()) {
                caps.name("prefix").expect("can't find name prefix").as_str().to_string()
            }
            else {
                String::new()
            };

            /* fetch_origin_master(git2::Repository::open(base_repo.path()).unwrap()); */
            let scratch = Scratch::new(&base_repo.path());

            let re = Regex::new(r"/(?P<view>.*)[.]git/.*").expect("can't compile regex");

            let view_repo = if let Some(caps) = re.captures(&request.url()) {
                let view = caps.name("view").unwrap();
                println!("VIEW {}", view.as_str());

                let view = caps.name("view").unwrap();

                for branch in scratch.repo.branches(None).expect("could not get branches") {
                    if let Ok((branch, _)) = branch {
                        let branchname = branch.name().unwrap().unwrap().to_string();
                        let r = branch.into_reference().target().expect("no ref");
                        let viewobj = SubdirView::new(&Path::new(&view.as_str()));
                        let view_commit = scratch.apply_view(&viewobj, r).expect("can't apply view");
                        scratch.repo
                            .reference(&view_ref(&view.as_str(), &branchname),
                                       view_commit,
                                       true,
                                       "apply_view")
                            .expect("can't create reference");
                    };
                }
                setup_tmp_repo(&base_repo.path(), Some(view.as_str()))

            }
            else {
                println!("no view");
                setup_tmp_repo(&base_repo.path(), None)
            };

            let mut cmd = Command::new("git");
            cmd.arg("http-backend");
            cmd.current_dir(&view_repo);
            cmd.env("GIT_PROJECT_ROOT", view_repo.to_str().unwrap());
            cmd.env("GIT_DIR", view_repo.to_str().unwrap());
            cmd.env("GIT_HTTP_EXPORT_ALL", "");

            println!("prefix {:?}", prefix);
            let request = request.remove_prefix(&prefix).expect("can't remove prefix");
            println!("URL stripped: {}", request.url());

            println!("done");
            cmd.start_cgi(&request).unwrap()
        })
    });
}

fn update_hook(refname: &str, old: &str, new: &str) -> i32
{
    let scratch = {
        let mut s = String::new();
        File::open(&Path::new("orig"))
            .expect("could not open orig name file")
            .read_to_string(&mut s)
            .expect("could not read orig name");

        let scratch_dir = Path::new(&s);
        let scratch = Scratch::new(&scratch_dir);
        scratch
    };

    let view = {
        let mut s = String::new();
        File::open(&Path::new("view"))
            .expect("could not open view name file")
            .read_to_string(&mut s)
            .expect("could not read view name");

        if s.starts_with(".") {
            return 0;
        }
        let view = SubdirView::new(&Path::new(&s));
        view
    };

    let central_head = scratch.repo.refname_to_id(&refname).expect("no ref: master");

    match scratch.unapply_view(central_head,
                               &view,
                               Oid::from_str(old).expect("can't parse old OID"),
                               Oid::from_str(new).expect("can't parse new OID")) {

        UnapplyView::Done(rewritten) => {
            scratch.repo
                .reference(&refname, rewritten, true, "unapply_view")
                .expect("can't create new reference");
        }
        _ => return 1,
    };

    return 0;
}
<commit_msg>only apply view to master of base<commit_after>extern crate centralgithook;
extern crate fern;
extern crate git2;
extern crate regex;
extern crate tempdir;

#[macro_use]
extern crate log;

use centralgithook::*;
use git2::Oid;
use regex::Regex;
use rouille::cgi::CgiRun;
use std::env::current_exe;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io;
use std::os::unix::fs::symlink;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::exit;

// #[macro_use]
extern crate rouille;

fn setup_tmp_repo(scratch_dir: &Path, view: Option<&str>) -> PathBuf
{
    let path = thread_local_temp_dir();

    let root = match view {
        Some(view) => view_ref_root(&view),
        None => "refs".to_string(),
    };

    debug!("setup_tmp_repo, root: {:?}", &root);
    let shell = Shell { cwd: path.to_path_buf() };

    let ce = current_exe().expect("can't find path to exe");
    shell.command("mkdir hooks");
    symlink(ce, path.join("hooks").join("update")).expect("can't symlink update hook");

    shell.command(&format!("cp {:?} {:?}", scratch_dir.join("HEAD"), path));
    shell.command(&format!("cp {:?} {:?}", scratch_dir.join("config"), path));
    symlink(scratch_dir.join(root), path.join("refs")).expect("can't symlink refs");
    symlink(scratch_dir.join("objects"), path.join("objects")).expect("can't symlink objects");

    shell.command(&format!("printf {} > view",
                           match view {
                               Some(view) => view,
                               None => ".",
                           }));

    shell.command(&format!("printf {} > orig", scratch_dir.to_string_lossy()));
    return path;
}

fn fetch_origin_master(repo: git2::Repository) -> Result<(), git2::Error> {
    repo.find_remote("origin")?.fetch(&["master"], None, None)
}

fn main() { exit(main_ret()); }

fn main_ret() -> i32 {

    let mut args = vec![];
    for arg in env::args() {
        args.push(arg);
    }
    debug!("args: {:?}", args);

    let logfilename = Path::new("/tmp/centralgit.log");
    fern::Dispatch::new()
    .format(|out, message, record| {
        out.finish(format_args!(
            "{}[{}] {}",
            record.target(),
            record.level(),
            message
        ))
    })
    .level(log::LevelFilter::Debug)
    .chain(std::io::stdout())
    .chain(fern::log_file(logfilename).unwrap())
    .apply().unwrap();

    if args[0].ends_with("/update") {
        debug!("================= HOOK {:?}", args);
        return update_hook(&args[1], &args[2], &args[3]);
    }

    let base_repo = do_clone_base(
        &args[1],
        &args[2],
        &args[3],
        &PathBuf::from(&args[4]));
    println!("Now listening on localhost:8000");

    rouille::start_server("localhost:8000", move |request| {
        rouille::log(&request, io::stdout(), || {

            let auth = match rouille::input::basic_http_auth(request) {
                Some(a) => a,
                _ => return rouille::Response::basic_http_auth_login_required("realm")
            };

            if !(auth.login == "me" && auth.password == "secret") {
                return rouille::Response::text("bad credentials").with_status_code(403);
            }

            println!("X\nX\nX\nURL: {}", request.url());
            let re = Regex::new(r"(?P<prefix>/.*[.]git)/.*").expect("can't compile regex");

            let prefix = if let Some(caps) = re.captures(&request.url()) {
                caps.name("prefix").expect("can't find name prefix").as_str().to_string()
            }
            else {
                String::new()
            };

            fetch_origin_master(git2::Repository::open(base_repo.path()).unwrap());
            let scratch = Scratch::new(&base_repo.path());

            let re = Regex::new(r"/(?P<view>.*)[.]git/.*").expect("can't compile regex");

            let view_repo = if let Some(caps) = re.captures(&request.url()) {
                let view = caps.name("view").unwrap();
                println!("VIEW {}", view.as_str());

                let view = caps.name("view").unwrap();

                if let Ok(branch) = scratch.repo.find_branch("master", git2::BranchType::Local) {
                    let branchname = branch.name().unwrap().unwrap().to_string();
                    let r = branch.into_reference().target().expect("no ref");
                    let viewobj = SubdirView::new(&Path::new(&view.as_str()));

                    if let Some(view_commit) = scratch.apply_view(&viewobj, r) {
                        println!("applied view to branch {}", branchname);
                        scratch.repo
                            .reference(&view_ref(&view.as_str(), &branchname),
                                       view_commit,
                                       true,
                                       "apply_view")
                            .expect("can't create reference");
                    }
                    else {
                        println!("can't apply view to branch {}", branchname);
                    };
                };

                setup_tmp_repo(&base_repo.path(), Some(view.as_str()))

            }
            else {
                println!("no view");
                setup_tmp_repo(&base_repo.path(), None)
            };

            let mut cmd = Command::new("git");
            cmd.arg("http-backend");
            cmd.current_dir(&view_repo);
            cmd.env("GIT_PROJECT_ROOT", view_repo.to_str().unwrap());
            cmd.env("GIT_DIR", view_repo.to_str().unwrap());
            cmd.env("GIT_HTTP_EXPORT_ALL", "");

            println!("prefix {:?}", prefix);
            let request = request.remove_prefix(&prefix).expect("can't remove prefix");
            println!("URL stripped: {}", request.url());

            println!("done");
            cmd.start_cgi(&request).unwrap()
        })
    });
}

fn update_hook(refname: &str, old: &str, new: &str) -> i32
{
    let scratch = {
        let mut s = String::new();
        File::open(&Path::new("orig"))
            .expect("could not open orig name file")
            .read_to_string(&mut s)
            .expect("could not read orig name");

        let scratch_dir = Path::new(&s);
        let scratch = Scratch::new(&scratch_dir);
        scratch
    };

    let view = {
        let mut s = String::new();
        File::open(&Path::new("view"))
            .expect("could not open view name file")
            .read_to_string(&mut s)
            .expect("could not read view name");

        if s.starts_with(".") {
            return 0;
        }
        let view = SubdirView::new(&Path::new(&s));
        view
    };

    let central_head = scratch.repo.refname_to_id(&refname).expect("no ref: master");

    match scratch.unapply_view(central_head,
                               &view,
                               Oid::from_str(old).expect("can't parse old OID"),
                               Oid::from_str(new).expect("can't parse new OID")) {

        UnapplyView::Done(rewritten) => {
            scratch.repo
                .reference(&refname, rewritten, true, "unapply_view")
                .expect("can't create new reference");
        }
        _ => return 1,
    };

    return 0;
}
<|endoftext|>