<commit_before>use collections::slice::{mod, AsSlice, SlicePrelude};
use collections::vec::{mod, Vec};
use core::mem;
use core::iter::{mod, AdditiveIterator, Iterator};
use core::option::{mod, Some, None, Option};

use iobuf::Iobuf;

/// A span over potentially many Iobufs. This is useful as a "string" type where
/// the contents of the string can potentially come from multiple IObufs, and
/// you want to avoid copying.
///
/// As an optimization, pushing an Iobuf that points to data immediately after
/// the range represented by the last Iobuf pushed will result in just expanding
/// the held Iobuf's range. This prevents allocating lots of unnecessary
/// intermediate buffers, while still maintaining the illusion of "pushing lots
/// of buffers" while incrementally parsing.
///
/// A `BufSpan` is internally represented as either an `Iobuf` or a `Vec<Iobuf>`,
/// depending on how many different buffers were used.
pub enum BufSpan<Buf> {
  Empty,
  One (Buf),
  Many(Vec<Buf>),
}

impl<Buf: Iobuf> BufSpan<Buf> {
  /// Creates a new, empty `Bufspan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let s: BufSpan<ROIobuf<'static>> = BufSpan::new();
  /// assert!(s.is_empty());
  /// ```
  #[inline]
  pub fn new() -> BufSpan<Buf> {
    Empty
  }

  /// Creates a new `BufSpan` from a slice of bytes.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  /// use std::iter::AdditiveIterator;
  ///
  /// let s = BufSpan::from_buf(ROIobuf::from_slice(b"hello"));
  /// assert_eq!(s.iter().count(), 1);
  /// assert_eq!(s.iter().map(|b| b.len()).sum(), 5);
  /// ```
  #[inline]
  pub fn from_buf(b: Buf) -> BufSpan<Buf> {
    One(b)
  }

  /// Returns `true` iff the span is over an empty range.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  ///
  /// let mut s = BufSpan::new();
  ///
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str(""));
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str("hello, world!"));
  /// assert!(!s.is_empty());
  /// ```
  #[inline]
  pub fn is_empty(&self) -> bool {
    match *self {
      Empty       => true,
      One (ref b) => b.is_empty(),
      Many(ref v) => v.iter().all(|b| b.is_empty()),
    }
  }

  /// The fast path during pushing -- either fills in the first buffer, or
  /// extends an existing one.
  ///
  /// Returns `None` if the fast path was taken and nothing more needs to be
  /// done. Returns `Some` if we need to do a slow push.
  #[inline]
  fn try_to_extend(&mut self, b: Buf) -> Option<Buf> {
    match *self {
      Empty => {},
      One(ref mut b0) => {
        unsafe {
          if b0.is_extended_by(&b) {
            b0.unsafe_extend(b.len());
            return None;
          } else {
            return Some(b); // Upgrade the `One` into a `Many` in the slow path.
          }
        }
      }
      Many(ref mut v) => {
        // I wish this wouldn't unwind, and just abort... :(
        let last = v.last_mut().unwrap();
        unsafe {
          if last.is_extended_by(&b) {
            last.unsafe_extend(b.len());
            return None;
          } else {
            return Some(b);
          }
        }
      }
    }

    // Handle this case in the fast path, instead of leaving it for slow_push
    // to clean up.
    *self = One(b);
    None
  }

  /// Appends a buffer to a `BufSpan`. If the buffer is an extension of the
  /// previously pushed buffer, the range will be extended. Otherwise, the new
  /// non-extension buffer will be added to the end of a vector.
  #[inline]
  pub fn push(&mut self, b: Buf) {
    match self.try_to_extend(b) {
      None    => {},
      Some(b) => self.slow_push(b),
    }
  }

  /// The slow path during a push. This is only taken if a `BufSpan` must span
  /// multiple backing buffers.
  #[cold]
  fn slow_push(&mut self, b: Buf) {
    let this = mem::replace(self, Empty);
    *self =
      match this {
        Empty   => One(b),
        One(b0) => {
          let mut v = Vec::with_capacity(2);
          v.push(b0);
          v.push(b);
          Many(v)
        },
        Many(mut bs) => { bs.push(b); Many(bs) }
      };
  }

  /// Returns an iterator over references to the buffers inside the `BufSpan`.
  #[inline]
  pub fn iter<'a>(&'a self) -> SpanIter<'a, Buf> {
    match *self {
      Empty       => Opt(None.into_iter()),
      One (ref b) => Opt(Some(b).into_iter()),
      Many(ref v) => Lot(v.as_slice().iter()),
    }
  }

  /// Returns a moving iterator over the buffers inside the `BufSpan`.
  #[inline]
  pub fn into_iter(self) -> SpanMoveIter<Buf> {
    match self {
      Empty   => MoveOpt(None.into_iter()),
      One (b) => MoveOpt(Some(b).into_iter()),
      Many(v) => MoveLot(v.into_iter()),
    }
  }

  /// Returns an iterator over the bytes in the `BufSpan`.
  #[inline]
  pub fn iter_bytes<'a>(&'a self) -> ByteIter<'a, Buf> {
    self.iter()
        .flat_map(|buf| unsafe { buf.as_window_slice().iter() })
        .map(|&b| b)
  }

  /// Returns `true` iff the bytes in this `BufSpan` are the same as the bytes
  /// in the other `BufSpan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf, RWIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  /// let b = BufSpan::from_buf(RWIobuf::from_string("hello".into_string()));
  ///
  /// assert!(a.byte_equal(&b));
  ///
  /// let mut c = BufSpan::from_buf(ROIobuf::from_str("hel"));
  /// c.push(ROIobuf::from_str("lo"));
  ///
  /// assert!(a.byte_equal(&c)); assert!(c.byte_equal(&a));
  ///
  /// let d = BufSpan::from_buf(ROIobuf::from_str("helo"));
  /// assert!(!a.byte_equal(&d));
  /// ```
  #[inline]
  pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
    self.count_bytes() == other.count_bytes()
    && self.iter_bytes().zip(other.iter_bytes()).all(|(a, b)| a == b)
  }

  /// A more efficient version of byte_equal, specialized to work exclusively on
  /// slices.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  ///
  /// assert!(a.byte_equal_slice(b"hello"));
  /// assert!(!a.byte_equal_slice(b"helo"));
  /// ```
  #[inline]
  pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
    self.count_bytes() as uint == other.len()
    && self.iter_bytes().zip(other.iter()).all(|(a, &b)| a == b)
  }

  /// Counts the number of bytes this `BufSpan` is over. This is
  /// `O(self.iter().len())`.
  #[inline]
  pub fn count_bytes(&self) -> u32 {
    self.iter().map(|b| b.len()).sum()
  }
}

/// An iterator over the bytes in a `BufSpan`.
pub type ByteIter<'a, Buf> =
  iter::Map<'static, &'a u8, u8,
    iter::FlatMap<'static, &'a Buf,
      SpanIter<'a, Buf>,
      slice::Items<'a, u8>>>;

/// An iterator over references to buffers inside a `BufSpan`.
pub enum SpanIter<'a, Buf: 'a> {
  Opt(option::Item<&'a Buf>),
  Lot(slice::Items<'a, Buf>),
}

impl<'a, Buf: Iobuf> Iterator<&'a Buf> for SpanIter<'a, Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<&'a Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      Opt(ref mut iter) => iter.next(),
      Lot(ref mut iter) => iter.next(),
    }
  }
}

/// A moving iterator over buffers inside a `BufSpan`.
pub enum SpanMoveIter<Buf> {
  MoveOpt(option::Item<Buf>),
  MoveLot(vec::MoveItems<Buf>),
}

impl<Buf: Iobuf> Iterator<Buf> for SpanMoveIter<Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      MoveOpt(ref mut iter) => iter.next(),
      MoveLot(ref mut iter) => iter.next(),
    }
  }
}
<commit_msg>specialize count_bytes<commit_after>use collections::slice::{mod, AsSlice, SlicePrelude};
use collections::vec::{mod, Vec};
use core::mem;
use core::iter::{mod, AdditiveIterator, Iterator};
use core::option::{mod, Some, None, Option};

use iobuf::Iobuf;

/// A span over potentially many Iobufs. This is useful as a "string" type where
/// the contents of the string can potentially come from multiple IObufs, and
/// you want to avoid copying.
///
/// As an optimization, pushing an Iobuf that points to data immediately after
/// the range represented by the last Iobuf pushed will result in just expanding
/// the held Iobuf's range. This prevents allocating lots of unnecessary
/// intermediate buffers, while still maintaining the illusion of "pushing lots
/// of buffers" while incrementally parsing.
///
/// A `BufSpan` is internally represented as either an `Iobuf` or a `Vec<Iobuf>`,
/// depending on how many different buffers were used.
pub enum BufSpan<Buf> {
  Empty,
  One (Buf),
  Many(Vec<Buf>),
}

impl<Buf: Iobuf> BufSpan<Buf> {
  /// Creates a new, empty `Bufspan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let s: BufSpan<ROIobuf<'static>> = BufSpan::new();
  /// assert!(s.is_empty());
  /// ```
  #[inline]
  pub fn new() -> BufSpan<Buf> {
    Empty
  }

  /// Creates a new `BufSpan` from a slice of bytes.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  /// use std::iter::AdditiveIterator;
  ///
  /// let s = BufSpan::from_buf(ROIobuf::from_slice(b"hello"));
  /// assert_eq!(s.iter().count(), 1);
  /// assert_eq!(s.iter().map(|b| b.len()).sum(), 5);
  /// ```
  #[inline]
  pub fn from_buf(b: Buf) -> BufSpan<Buf> {
    One(b)
  }

  /// Returns `true` iff the span is over an empty range.
  ///
  /// ```
  /// use iobuf::{BufSpan, Iobuf, ROIobuf};
  ///
  /// let mut s = BufSpan::new();
  ///
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str(""));
  /// assert!(s.is_empty());
  ///
  /// s.push(ROIobuf::from_str("hello, world!"));
  /// assert!(!s.is_empty());
  /// ```
  #[inline]
  pub fn is_empty(&self) -> bool {
    match *self {
      Empty       => true,
      One (ref b) => b.is_empty(),
      Many(ref v) => v.iter().all(|b| b.is_empty()),
    }
  }

  /// The fast path during pushing -- either fills in the first buffer, or
  /// extends an existing one.
  ///
  /// Returns `None` if the fast path was taken and nothing more needs to be
  /// done. Returns `Some` if we need to do a slow push.
  #[inline]
  fn try_to_extend(&mut self, b: Buf) -> Option<Buf> {
    match *self {
      Empty => {},
      One(ref mut b0) => {
        unsafe {
          if b0.is_extended_by(&b) {
            b0.unsafe_extend(b.len());
            return None;
          } else {
            return Some(b); // Upgrade the `One` into a `Many` in the slow path.
          }
        }
      }
      Many(ref mut v) => {
        // I wish this wouldn't unwind, and just abort... :(
        let last = v.last_mut().unwrap();
        unsafe {
          if last.is_extended_by(&b) {
            last.unsafe_extend(b.len());
            return None;
          } else {
            return Some(b);
          }
        }
      }
    }

    // Handle this case in the fast path, instead of leaving it for slow_push
    // to clean up.
    *self = One(b);
    None
  }

  /// Appends a buffer to a `BufSpan`. If the buffer is an extension of the
  /// previously pushed buffer, the range will be extended. Otherwise, the new
  /// non-extension buffer will be added to the end of a vector.
  #[inline]
  pub fn push(&mut self, b: Buf) {
    match self.try_to_extend(b) {
      None    => {},
      Some(b) => self.slow_push(b),
    }
  }

  /// The slow path during a push. This is only taken if a `BufSpan` must span
  /// multiple backing buffers.
  #[cold]
  fn slow_push(&mut self, b: Buf) {
    let this = mem::replace(self, Empty);
    *self =
      match this {
        Empty   => One(b),
        One(b0) => {
          let mut v = Vec::with_capacity(2);
          v.push(b0);
          v.push(b);
          Many(v)
        },
        Many(mut bs) => { bs.push(b); Many(bs) }
      };
  }

  /// Returns an iterator over references to the buffers inside the `BufSpan`.
  #[inline]
  pub fn iter<'a>(&'a self) -> SpanIter<'a, Buf> {
    match *self {
      Empty       => Opt(None.into_iter()),
      One (ref b) => Opt(Some(b).into_iter()),
      Many(ref v) => Lot(v.as_slice().iter()),
    }
  }

  /// Returns a moving iterator over the buffers inside the `BufSpan`.
  #[inline]
  pub fn into_iter(self) -> SpanMoveIter<Buf> {
    match self {
      Empty   => MoveOpt(None.into_iter()),
      One (b) => MoveOpt(Some(b).into_iter()),
      Many(v) => MoveLot(v.into_iter()),
    }
  }

  /// Returns an iterator over the bytes in the `BufSpan`.
  #[inline]
  pub fn iter_bytes<'a>(&'a self) -> ByteIter<'a, Buf> {
    self.iter()
        .flat_map(|buf| unsafe { buf.as_window_slice().iter() })
        .map(|&b| b)
  }

  /// Returns `true` iff the bytes in this `BufSpan` are the same as the bytes
  /// in the other `BufSpan`.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf, RWIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  /// let b = BufSpan::from_buf(RWIobuf::from_string("hello".into_string()));
  ///
  /// assert!(a.byte_equal(&b));
  ///
  /// let mut c = BufSpan::from_buf(ROIobuf::from_str("hel"));
  /// c.push(ROIobuf::from_str("lo"));
  ///
  /// assert!(a.byte_equal(&c)); assert!(c.byte_equal(&a));
  ///
  /// let d = BufSpan::from_buf(ROIobuf::from_str("helo"));
  /// assert!(!a.byte_equal(&d));
  /// ```
  #[inline]
  pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
    self.count_bytes() == other.count_bytes()
    && self.iter_bytes().zip(other.iter_bytes()).all(|(a, b)| a == b)
  }

  /// A more efficient version of byte_equal, specialized to work exclusively on
  /// slices.
  ///
  /// ```
  /// use iobuf::{BufSpan, ROIobuf};
  ///
  /// let a = BufSpan::from_buf(ROIobuf::from_str("hello"));
  ///
  /// assert!(a.byte_equal_slice(b"hello"));
  /// assert!(!a.byte_equal_slice(b"helo"));
  /// ```
  #[inline]
  pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
    self.count_bytes() as uint == other.len()
    && self.iter_bytes().zip(other.iter()).all(|(a, &b)| a == b)
  }

  /// Counts the number of bytes this `BufSpan` is over. This is
  /// `O(self.iter().len())`.
  #[inline]
  pub fn count_bytes(&self) -> u32 {
    // `self.iter().map(|b| b.len()).sum()` would be shorter, but I like to
    // specialize for the much more common case of empty or singular `BufSpan`s.
    match *self {
      Empty       => 0,
      One (ref b) => b.len(),
      Many(ref v) => v.iter().map(|b| b.len()).sum(),
    }
  }
}

/// An iterator over the bytes in a `BufSpan`.
pub type ByteIter<'a, Buf> =
  iter::Map<'static, &'a u8, u8,
    iter::FlatMap<'static, &'a Buf,
      SpanIter<'a, Buf>,
      slice::Items<'a, u8>>>;

/// An iterator over references to buffers inside a `BufSpan`.
pub enum SpanIter<'a, Buf: 'a> {
  Opt(option::Item<&'a Buf>),
  Lot(slice::Items<'a, Buf>),
}

impl<'a, Buf: Iobuf> Iterator<&'a Buf> for SpanIter<'a, Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<&'a Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      Opt(ref mut iter) => iter.next(),
      Lot(ref mut iter) => iter.next(),
    }
  }
}

/// A moving iterator over buffers inside a `BufSpan`.
pub enum SpanMoveIter<Buf> {
  MoveOpt(option::Item<Buf>),
  MoveLot(vec::MoveItems<Buf>),
}

impl<Buf: Iobuf> Iterator<Buf> for SpanMoveIter<Buf> {
  #[inline(always)]
  fn next(&mut self) -> Option<Buf> {
    // I'm couting on this match getting lifted out of the loop with
    // loop-invariant code motion.
    match *self {
      MoveOpt(ref mut iter) => iter.next(),
      MoveLot(ref mut iter) => iter.next(),
    }
  }
}
<|endoftext|>


<commit_before>extern crate gpgme;
extern crate std;
extern crate tempdir;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Gpgme(gpgme::Error),
    Custom(&'static str),
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<super::signer::Error> for Error {
    fn from(e: super::signer::Error) -> Self {
        match e {
            super::signer::Error::Io(e) => Error::Io(e),
            super::signer::Error::Gpgme(e) => Error::Gpgme(e),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[allow(non_camel_case_types)]
pub enum Arch {
    #[serde(rename = "i686")]
    I686,
    #[serde(rename = "x86_64")]
    X86_64,
}

impl std::fmt::Display for Arch {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            Arch::I686 => "i686".fmt(f),
            Arch::X86_64 => "x86_64".fmt(f),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ChrootHelper<'a> {
    chroot_dir: &'a str,
    arch: Arch,
}

impl<'a> ChrootHelper<'a> {
    pub fn new(chroot_dir: &'a str, arch: Arch) -> Self {
        ChrootHelper {
            chroot_dir: chroot_dir,
            arch: arch,
        }
    }

    pub fn makechrootpkg<P: AsRef<std::path::Path>,
                         Q: AsRef<std::path::Path>,
                         R: AsRef<std::path::Path>,
                         S: AsRef<std::path::Path>>
        (&self,
         package_dir: P,
         srcdest: Q,
         pkgdest: R,
         logdest: S)
         -> Result<(), Error> {
        let current_dir_buf = try!(std::env::current_dir());
        let current_dir = current_dir_buf.as_path();
        let mut srcdest_arg = std::ffi::OsString::from("SRCDEST=");
        srcdest_arg.push(current_dir.join(srcdest));
        let mut pkgdest_arg = std::ffi::OsString::from("PKGDEST=");
        pkgdest_arg.push(current_dir.join(pkgdest));
        let mut logdest_arg = std::ffi::OsString::from("LOGDEST=");
        logdest_arg.push(current_dir.join(logdest));

        let mut cmd = std::process::Command::new("sudo");
        cmd.current_dir(package_dir)
            .arg("env")
            .arg(srcdest_arg)
            .arg(pkgdest_arg)
            .arg(logdest_arg)
            .arg("makechrootpkg")
            .arg("-cur")
            .arg(current_dir.join(self.chroot_dir));
        info!("{:?}", cmd);
        let status = try!(cmd.status());
        if status.success() {
            Ok(())
        } else {
            Err(Error::Custom("makechrootpkg failed"))
        }
    }
}

#[derive(Debug, Clone)]
pub struct Builder<'a> {
    signer: Option<&'a super::signer::Signer<'a>>,
    srcdest: &'a str,
    logdest: &'a str,
}

impl<'a> Builder<'a> {
    pub fn new(signer: Option<&'a super::signer::Signer<'a>>,
               srcdest: &'a str,
               logdest: &'a str)
               -> Self {
        Builder {
            signer: signer,
            srcdest: srcdest,
            logdest: logdest,
        }
    }

    pub fn build_package<P, Q>(&self,
                               package_dir: P,
                               repo_dir: Q,
                               chroot_helper: &ChrootHelper)
                               -> Result<Vec<std::path::PathBuf>, Error>
        where P: AsRef<std::path::Path>,
              Q: AsRef<std::path::Path>
    {
        let tempdir = try!(tempdir::TempDir::new("guzuta-pkgdest"));
        try!(chroot_helper.makechrootpkg(package_dir, self.srcdest, &tempdir, self.logdest));
        let mut paths = vec![];
        for entry in try!(std::fs::read_dir(tempdir)) {
            let entry = try!(entry);
            let dest = repo_dir.as_ref().join(entry.file_name());
            if dest.read_link().is_ok() {
                // Unlink symlink created by makechrootpkg
                try!(std::fs::remove_file(&dest));
            }
            try!(std::fs::copy(entry.path(), &dest));
            if let Some(ref signer) = self.signer {
                let mut sig_dest = dest.clone().into_os_string();
                sig_dest.push(".sig");
                try!(signer.sign(&dest, sig_dest));
            }
            paths.push(dest);
        }
        Ok(paths)
    }
}
<commit_msg>Fix too early tempdir deletion<commit_after>extern crate gpgme;
extern crate std;
extern crate tempdir;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Gpgme(gpgme::Error),
    Custom(&'static str),
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<super::signer::Error> for Error {
    fn from(e: super::signer::Error) -> Self {
        match e {
            super::signer::Error::Io(e) => Error::Io(e),
            super::signer::Error::Gpgme(e) => Error::Gpgme(e),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[allow(non_camel_case_types)]
pub enum Arch {
    #[serde(rename = "i686")]
    I686,
    #[serde(rename = "x86_64")]
    X86_64,
}

impl std::fmt::Display for Arch {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            Arch::I686 => "i686".fmt(f),
            Arch::X86_64 => "x86_64".fmt(f),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ChrootHelper<'a> {
    chroot_dir: &'a str,
    arch: Arch,
}

impl<'a> ChrootHelper<'a> {
    pub fn new(chroot_dir: &'a str, arch: Arch) -> Self {
        ChrootHelper {
            chroot_dir: chroot_dir,
            arch: arch,
        }
    }

    pub fn makechrootpkg<P: AsRef<std::path::Path>,
                         Q: AsRef<std::path::Path>,
                         R: AsRef<std::path::Path>,
                         S: AsRef<std::path::Path>>
        (&self,
         package_dir: P,
         srcdest: Q,
         pkgdest: R,
         logdest: S)
         -> Result<(), Error> {
        let current_dir_buf = try!(std::env::current_dir());
        let current_dir = current_dir_buf.as_path();
        let mut srcdest_arg = std::ffi::OsString::from("SRCDEST=");
        srcdest_arg.push(current_dir.join(srcdest));
        let mut pkgdest_arg = std::ffi::OsString::from("PKGDEST=");
        pkgdest_arg.push(current_dir.join(pkgdest));
        let mut logdest_arg = std::ffi::OsString::from("LOGDEST=");
        logdest_arg.push(current_dir.join(logdest));

        let mut cmd = std::process::Command::new("sudo");
        cmd.current_dir(package_dir)
            .arg("env")
            .arg(srcdest_arg)
            .arg(pkgdest_arg)
            .arg(logdest_arg)
            .arg("makechrootpkg")
            .arg("-cur")
            .arg(current_dir.join(self.chroot_dir));
        info!("{:?}", cmd);
        let status = try!(cmd.status());
        if status.success() {
            Ok(())
        } else {
            Err(Error::Custom("makechrootpkg failed"))
        }
    }
}

#[derive(Debug, Clone)]
pub struct Builder<'a> {
    signer: Option<&'a super::signer::Signer<'a>>,
    srcdest: &'a str,
    logdest: &'a str,
}

impl<'a> Builder<'a> {
    pub fn new(signer: Option<&'a super::signer::Signer<'a>>,
               srcdest: &'a str,
               logdest: &'a str)
               -> Self {
        Builder {
            signer: signer,
            srcdest: srcdest,
            logdest: logdest,
        }
    }

    pub fn build_package<P, Q>(&self,
                               package_dir: P,
                               repo_dir: Q,
                               chroot_helper: &ChrootHelper)
                               -> Result<Vec<std::path::PathBuf>, Error>
        where P: AsRef<std::path::Path>,
              Q: AsRef<std::path::Path>
    {
        let tempdir = try!(tempdir::TempDir::new("guzuta-pkgdest"));
        let pkgdest = tempdir.path();
        try!(chroot_helper.makechrootpkg(package_dir, self.srcdest, pkgdest, self.logdest));
        let mut paths = vec![];
        for entry in try!(std::fs::read_dir(pkgdest)) {
            let entry = try!(entry);
            let dest = repo_dir.as_ref().join(entry.file_name());
            if dest.read_link().is_ok() {
                // Unlink symlink created by makechrootpkg
                try!(std::fs::remove_file(&dest));
            }
            info!("Copy {} to {}", entry.path().display(), dest.display());
            try!(std::fs::copy(entry.path(), &dest));
            if let Some(ref signer) = self.signer {
                let mut sig_dest = dest.clone().into_os_string();
                sig_dest.push(".sig");
                try!(signer.sign(&dest, sig_dest));
            }
            paths.push(dest);
        }
        Ok(paths)
    }
}
<|endoftext|>


<commit_before>use {Action, InputTranslator, MouseTranslationData};
use input::Button;
use window::Size;
use std::convert::Into;
use std::default::Default;

/// Convenience object for constructing an InputMap
pub struct RebindBuilder<A: Action> {
    input_remappings: Vec<(Button, A)>,
    mouse_data: MouseTranslationData
}

impl<A: Action> RebindBuilder<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        RebindBuilder {
            input_remappings: vec![],
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn x_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_scroll_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn y_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_scroll_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn x_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_motion_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn y_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_motion_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn viewport_size(mut self, sz: Size) -> Self {
        self.mouse_data.viewport_size = sz;
        self
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn with_action_mapping(mut self, but: Button, act: A) -> Self {
        self.input_remappings.push((but, act));
        self
    }

    #[allow(missing_docs)]
    pub fn build(self) -> InputTranslator<A> {self.into()}
}

impl<A: Action> Default for RebindBuilder<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        Self::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for RebindBuilder<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_map = InputTranslator::new(self.mouse_data.viewport_size);

        input_map.mouse_translator.data = self.mouse_data;
        input_map.keymap = self.input_remappings.iter().cloned().collect();

        input_map
    }
}

#[cfg(unimplemented)]
use rebind::InputRebind;
#[cfg(unimplemented)]
impl<A: Action> Into<InputRebind<A>> for RebindBuilder<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_data.viewport_size);

        input_rebind.mouse_data = self.mouse_data;
        //input_rebind.keymap.btn_map = self.input_remappings.iter().map(|x| x.clone()).collect();

        input_rebind
    }
}

<commit_msg>Remove build() method from builder, and add separate methods for building a translator or a rebind<commit_after>use {Action, InputTranslator, InputRebind, MouseTranslationData};
use input::Button;
use window::Size;
use std::convert::Into;
use std::default::Default;

/// Convenience object for constructing an InputMap
pub struct RebindBuilder<A: Action> {
    input_remappings: Vec<(Button, A)>,
    mouse_data: MouseTranslationData
}

impl<A: Action> RebindBuilder<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        RebindBuilder {
            input_remappings: vec![],
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn x_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_scroll_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn y_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_scroll_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn x_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_motion_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn y_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_motion_inverted = invert;
        self
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn viewport_size(mut self, sz: Size) -> Self {
        self.mouse_data.viewport_size = sz;
        self
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn with_action_mapping(mut self, but: Button, act: A) -> Self {
        self.input_remappings.push((but, act));
        self
    }

    #[allow(missing_docs)]
    pub fn build_translator(self) -> InputTranslator<A> { self.into() }

    #[allow(missing_docs)]
    pub fn build_rebind(self) -> InputRebind<A> { self.into() }
}

impl<A: Action> Default for RebindBuilder<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        Self::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for RebindBuilder<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_map = InputTranslator::new(self.mouse_data.viewport_size);

        input_map.mouse_translator.data = self.mouse_data;
        input_map.keymap = self.input_remappings.iter().cloned().collect();

        input_map
    }
}

impl<A: Action> Into<InputRebind<A>> for RebindBuilder<A> {
    #[allow(missing_docs, dead_code, unused_variables, unreachable_code)]
    fn into(self) -> InputRebind<A> {
        unimplemented!();

        let mut input_rebind = InputRebind::new(self.mouse_data.viewport_size);

        input_rebind.mouse_data = self.mouse_data;
        //input_rebind.keymap.btn_map = self.input_remappings.iter().map(|x| x.clone()).collect();

        input_rebind
    }
}

<|endoftext|>


<commit_before>//! Future-aware synchronization
//!
//! This module is enabled with the **`sync`** feature flag.
//!
//! Tasks sometimes need to communicate with each other. This module contains
//! two basic abstractions for doing so:
//!
//! - [oneshot](oneshot/index.html), a way of sending a single value
//!   from one task to another.
//! - [mpsc](mpsc/index.html), a multi-producer, single-consumer channel for
//!   sending values between tasks.
//! - [lock](lock/index.html), an asynchronous `Mutex`-like type.
//! - [watch](watch/index.html), a single-producer, multi-consumer channel that
//!   only stores the **most recently** sent value.

pub use tokio_sync::{/*lock, mpsc,*/ oneshot, watch};
<commit_msg>tokio: re-export sync::{lock,mpsc} (#1208)<commit_after>//! Future-aware synchronization
//!
//! This module is enabled with the **`sync`** feature flag.
//!
//! Tasks sometimes need to communicate with each other. This module contains
//! two basic abstractions for doing so:
//!
//! - [oneshot](oneshot/index.html), a way of sending a single value
//!   from one task to another.
//! - [mpsc](mpsc/index.html), a multi-producer, single-consumer channel for
//!   sending values between tasks.
//! - [lock](lock/index.html), an asynchronous `Mutex`-like type.
//! - [watch](watch/index.html), a single-producer, multi-consumer channel that
//!   only stores the **most recently** sent value.

pub use tokio_sync::{lock, mpsc, oneshot, watch};
<|endoftext|>


<commit_before>use super::error::{ErrorKind, Result, ResultExt};
use super::header::{decode, encode};
use super::{ServicePair, ServiceResult};
use crate::rosmsg::RosMsg;
use byteorder::{LittleEndian, ReadBytesExt};
use std;
use std::collections::HashMap;
use std::io;
use std::io::Write;
use std::net::TcpStream;
use std::sync::Arc;
use std::thread;

pub struct ClientResponse<T> {
    handle: thread::JoinHandle<Result<ServiceResult<T>>>,
}

impl<T> ClientResponse<T> {
    pub fn read(self) -> Result<ServiceResult<T>> {
        self.handle
            .join()
            .unwrap_or_else(|_| Err(ErrorKind::ServiceResponseUnknown.into()))
    }
}

impl<T: Send + 'static> ClientResponse<T> {
    pub fn callback<F>(self, callback: F)
    where
        F: FnOnce(Result<ServiceResult<T>>) + Send + 'static,
    {
        thread::spawn(move || callback(self.read()));
    }
}

struct ClientInfo {
    caller_id: String,
    uri: String,
    service: String,
}

#[derive(Clone)]
pub struct Client<T: ServicePair> {
    info: std::sync::Arc<ClientInfo>,
    phantom: std::marker::PhantomData<T>,
}

impl<T: ServicePair> Client<T> {
    pub fn new(caller_id: &str, uri: &str, service: &str) -> Client<T> {
        Client {
            info: std::sync::Arc::new(ClientInfo {
                caller_id: String::from(caller_id),
                uri: String::from(uri),
                service: String::from(service),
            }),
            phantom: std::marker::PhantomData,
        }
    }

    pub fn req(&self, args: &T::Request) -> Result<ServiceResult<T::Response>> {
        Self::request_body(
            args,
            &self.info.uri,
            &self.info.caller_id,
            &self.info.service,
        )
    }

    pub fn req_async(&self, args: T::Request) -> ClientResponse<T::Response> {
        let info = Arc::clone(&self.info);
        ClientResponse {
            handle: thread::spawn(move || {
                Self::request_body(&args, &info.uri, &info.caller_id, &info.service)
            }),
        }
    }

    fn request_body(
        args: &T::Request,
        uri: &str,
        caller_id: &str,
        service: &str,
    ) -> Result<ServiceResult<T::Response>> {
        let connection = TcpStream::connect(uri.trim_start_matches("rosrpc://"));
        let mut stream = connection
            .chain_err(|| ErrorKind::ServiceConnectionFail(service.into(), uri.into()))?;

        // Service request starts by exchanging connection headers
        exchange_headers::<T, _>(&mut stream, caller_id, service)?;

        let mut writer = io::Cursor::new(Vec::with_capacity(128));
        // skip the first 4 bytes that will contain the message length
        writer.set_position(4);

        args.encode(&mut writer)?;

        // write the message length to the start of the header
        let message_length = (writer.position() - 4) as u32;
        writer.set_position(0);
        message_length.encode(&mut writer)?;

        // Send request to service
        stream.write_all(&writer.into_inner())?;

        // Service responds with a boolean byte, signalling success
        let success = read_verification_byte(&mut stream)
            .chain_err(|| ErrorKind::ServiceResponseInterruption)?;
        Ok(if success {
            // Decode response as response type upon success

            // TODO: validate response length
            let _length = stream.read_u32::<LittleEndian>();

            Ok(RosMsg::decode(&mut stream)?)
        } else {
            // Decode response as string upon failure
            Err(RosMsg::decode(&mut stream)?)
        })
    }
}

#[inline]
fn read_verification_byte<R: std::io::Read>(reader: &mut R) -> std::io::Result<bool> {
    reader.read_u8().map(|v| v != 0)
}

fn write_request<T, U>(mut stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(caller_id));
    fields.insert(String::from("service"), String::from(service));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    encode(&mut stream, &fields)?;
    Ok(())
}

fn read_response<T, U>(mut stream: &mut U) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read,
{
    let fields = decode(&mut stream)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn exchange_headers<T, U>(stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    write_request::<T, U>(stream, caller_id, service)?;
    read_response::<T, U>(stream)
}
<commit_msg>Allow retries for ROS client connections<commit_after>use super::error::{ErrorKind, Result, ResultExt};
use super::header::{decode, encode};
use super::{ServicePair, ServiceResult};
use crate::rosmsg::RosMsg;
use byteorder::{LittleEndian, ReadBytesExt};
use std;
use std::collections::HashMap;
use std::io;
use std::io::Write;
use std::net::TcpStream;
use std::sync::Arc;
use std::thread;

pub struct ClientResponse<T> {
    handle: thread::JoinHandle<Result<ServiceResult<T>>>,
}

impl<T> ClientResponse<T> {
    pub fn read(self) -> Result<ServiceResult<T>> {
        self.handle
            .join()
            .unwrap_or_else(|_| Err(ErrorKind::ServiceResponseUnknown.into()))
    }
}

impl<T: Send + 'static> ClientResponse<T> {
    pub fn callback<F>(self, callback: F)
    where
        F: FnOnce(Result<ServiceResult<T>>) + Send + 'static,
    {
        thread::spawn(move || callback(self.read()));
    }
}

struct ClientInfo {
    caller_id: String,
    uri: String,
    service: String,
}

#[derive(Clone)]
pub struct Client<T: ServicePair> {
    info: std::sync::Arc<ClientInfo>,
    phantom: std::marker::PhantomData<T>,
}

fn connect_to_tcp_with_multiple_attempts(uri: &str, attempts: usize) -> std::io::Result<TcpStream> {
    let mut err = std::io::Error::new(
        std::io::ErrorKind::Other,
        "Tried to connect via TCP with 0 connection attempts",
    );
    let mut repeat_delay_ms = 1;
    for _ in 0..attempts {
        match TcpStream::connect(uri) {
            Ok(stream) => {
                return Ok(stream);
            }
            Err(error) => err = error,
        }
        std::thread::sleep(std::time::Duration::from_millis(repeat_delay_ms));
        repeat_delay_ms *= 2;
    }
    Err(err)
}

impl<T: ServicePair> Client<T> {
    pub fn new(caller_id: &str, uri: &str, service: &str) -> Client<T> {
        Client {
            info: std::sync::Arc::new(ClientInfo {
                caller_id: String::from(caller_id),
                uri: String::from(uri),
                service: String::from(service),
            }),
            phantom: std::marker::PhantomData,
        }
    }

    pub fn req(&self, args: &T::Request) -> Result<ServiceResult<T::Response>> {
        Self::request_body(
            args,
            &self.info.uri,
            &self.info.caller_id,
            &self.info.service,
        )
    }

    pub fn req_async(&self, args: T::Request) -> ClientResponse<T::Response> {
        let info = Arc::clone(&self.info);
        ClientResponse {
            handle: thread::spawn(move || {
                Self::request_body(&args, &info.uri, &info.caller_id, &info.service)
            }),
        }
    }

    fn request_body(
        args: &T::Request,
        uri: &str,
        caller_id: &str,
        service: &str,
    ) -> Result<ServiceResult<T::Response>> {
        let trimmed_uri = uri.trim_start_matches("rosrpc://");
        let mut stream = connect_to_tcp_with_multiple_attempts(trimmed_uri, 15)
            .chain_err(|| ErrorKind::ServiceConnectionFail(service.into(), uri.into()))?;

        // Service request starts by exchanging connection headers
        exchange_headers::<T, _>(&mut stream, caller_id, service)?;

        let mut writer = io::Cursor::new(Vec::with_capacity(128));
        // skip the first 4 bytes that will contain the message length
        writer.set_position(4);

        args.encode(&mut writer)?;

        // write the message length to the start of the header
        let message_length = (writer.position() - 4) as u32;
        writer.set_position(0);
        message_length.encode(&mut writer)?;

        // Send request to service
        stream.write_all(&writer.into_inner())?;

        // Service responds with a boolean byte, signalling success
        let success = read_verification_byte(&mut stream)
            .chain_err(|| ErrorKind::ServiceResponseInterruption)?;
        Ok(if success {
            // Decode response as response type upon success

            // TODO: validate response length
            let _length = stream.read_u32::<LittleEndian>();

            Ok(RosMsg::decode(&mut stream)?)
        } else {
            // Decode response as string upon failure
            Err(RosMsg::decode(&mut stream)?)
        })
    }
}

#[inline]
fn read_verification_byte<R: std::io::Read>(reader: &mut R) -> std::io::Result<bool> {
    reader.read_u8().map(|v| v != 0)
}

fn write_request<T, U>(mut stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(caller_id));
    fields.insert(String::from("service"), String::from(service));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    encode(&mut stream, &fields)?;
    Ok(())
}

fn read_response<T, U>(mut stream: &mut U) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read,
{
    let fields = decode(&mut stream)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn exchange_headers<T, U>(stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    write_request::<T, U>(stream, caller_id, service)?;
    read_response::<T, U>(stream)
}
<|endoftext|>


<commit_before>//! # command
//!
//! Runs task commands/scripts.
//!

use log::Logger;
use rand::{Rng, thread_rng};
use std::env;
use std::env::current_dir;
use std::fs::{File, create_dir_all, remove_file};
use std::io::Error;
use std::io::prelude::*;
use std::process::{Command, ExitStatus, Stdio, exit};
use types::Step;

/// Validates the exit code code and if not 0 or unable to validate it, panic.
pub fn validate_exit_code(exit_status: Result<ExitStatus, Error>) {
    match exit_status {
        Ok(code) => {
            if !code.success() {
                match code.code() {
                    Some(value) => {
                        if value != 0 {
                            exit(value);
                        }
                    }
                    None => exit(1),
                }
            }
        }
        Err(error) => panic!("Error while executing command, error: {}", error),
    }
}

/// Runs the requested script text and panics in case of any script error.
pub fn run_script(
    logger: &Logger,
    script_lines: &Vec<String>,
) {
    let name = env!("CARGO_PKG_NAME");
    let file_name: String = thread_rng().gen_ascii_chars().take(10).collect();

    let mut file_path = env::temp_dir();
    file_path.push(name);

    // create parent directory
    match create_dir_all(&file_path) {
        Ok(_) => logger.verbose::<()>("Created temporary directory.", &[], None),
        Err(error) => logger.verbose("Unable to create temporary directory: ", &[&file_path.to_str().unwrap_or("???")], Some(error)),
    };

    file_path.push(file_name);
    if cfg!(windows) {
        file_path.set_extension("bat");
    } else {
        file_path.set_extension("sh");
    };

    let file_path_str = &file_path.to_str().unwrap_or("???");

    logger.verbose::<()>("Creating temporary script file: ", &[&file_path_str], None);

    let mut file = match File::create(&file_path) {
        Err(error) => {
            logger.error("Unable to create script file: ", &[&file_path_str], Some(&error));
            panic!("Unable to create script file, error: {}", error);
        }
        Ok(file) => file,
    };

    let mut text = script_lines.join("\n");

    let cwd_holder = match current_dir() {
        Ok(value) => value,
        Err(error) => {
            logger.error("Unable to get current working directory.", &[], Some(&error));
            panic!("Unable to get current working directory, error: {}", error);
        }
    };

    let cwd = match cwd_holder.to_str() {
        Some(cwd_str) => cwd_str.clone(),
        None => {
            logger.error::<()>("Unable to get current working directory.", &[], None);
            panic!("Unable to get current working directory");
        }
    };

    text.insert_str(0, "\n");
    text.insert_str(0, cwd);
    text.insert_str(0, "cd ");

    match file.write_all(text.as_bytes()) {
        Err(error) => {
            logger.error("Unable to write to script file: ", &[&file_path_str], Some(&error));
            panic!("Unable to write to script file, error: {}", error);
        }
        Ok(_) => logger.verbose::<()>("Written script file text:\n", &[&text], None),
    }

    let command = if cfg!(windows) {
        "cmd"
    } else {
        "sh"
    };

    let args_vector = if cfg!(windows) {
        vec!["-c".to_string(), file_path_str.to_string()]
    } else {
        vec![file_path_str.to_string()]
    };

    let args = Some(args_vector);

    run_command(&logger, &command, &args);

    match remove_file(&file_path_str) {
        Ok(_) => logger.verbose::<()>("Temporary file deleted: ", &[&file_path_str], None),
        Err(error) => logger.verbose("Unable to delete temporary file: ", &[&file_path_str], Some(error)),
    };
}

/// Runs the requested command and panics in case of any error.
pub fn run_command(
    logger: &Logger,
    command_string: &str,
    args: &Option<Vec<String>>,
) {
    logger.verbose::<()>("Execute Command: ", &[&command_string], None);
    let mut command = Command::new(&command_string);

    match *args {
        Some(ref args_vec) => {
            for arg in args_vec.iter() {
                command.arg(arg);
            }
        }
        None => logger.verbose::<()>("No command args defined.", &[], None),
    };

    command.stdin(Stdio::inherit()).stdout(Stdio::inherit()).stderr(Stdio::inherit());
    logger.info("Execute Command: ", &[], Some(&command));

    let exit_status = command.status();
    validate_exit_code(exit_status);
}

/// Runs the given task command and if not defined, the task script.
pub fn run(
    logger: &Logger,
    step: &Step,
) {
    match step.config.command {
        Some(ref command_string) => {
            run_command(&logger, &command_string, &step.config.args);
        }
        None => {
            match step.config.script {
                Some(ref script) => run_script(&logger, script),
                None => logger.verbose::<()>("No script defined.", &[], None),
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    use log;
    use std::io::ErrorKind;
    use types::Task;

    #[test]
    #[should_panic]
    fn validate_exit_code_error() {
        validate_exit_code(Err(Error::new(ErrorKind::Other, "test")));
    }

    #[test]
    fn run_no_command() {
        let logger = log::create("error");
        let task = Task {
            install_crate: None,
            command: None,
            args: None,
            disabled: None,
            alias: None,
            install_script: None,
            script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }

    #[test]
    fn run_command() {
        let logger = log::create("error");
        let task = Task {
            command: Some("echo".to_string()),
            args: Some(vec!["1".to_string()]),
            install_crate: None,
            disabled: None,
            alias: None,
            install_script: None,
            script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }

    #[test]
    fn run_script() {
        let logger = log::create("error");
        let task = Task {
            script: Some(vec!["echo 1".to_string()]),
            command: None,
            install_crate: None,
            args: None,
            disabled: None,
            alias: None,
            install_script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }
}
<commit_msg>fix for windows<commit_after>//! # command
//!
//! Runs task commands/scripts.
//!

use log::Logger;
use rand::{Rng, thread_rng};
use std::env;
use std::env::current_dir;
use std::fs::{File, create_dir_all, remove_file};
use std::io::Error;
use std::io::prelude::*;
use std::process::{Command, ExitStatus, Stdio, exit};
use types::Step;

/// Validates the exit code code and if not 0 or unable to validate it, panic.
pub fn validate_exit_code(exit_status: Result<ExitStatus, Error>) {
    match exit_status {
        Ok(code) => {
            if !code.success() {
                match code.code() {
                    Some(value) => {
                        if value != 0 {
                            exit(value);
                        }
                    }
                    None => exit(1),
                }
            }
        }
        Err(error) => panic!("Error while executing command, error: {}", error),
    }
}

/// Runs the requested script text and panics in case of any script error.
pub fn run_script(
    logger: &Logger,
    script_lines: &Vec<String>,
) {
    let name = env!("CARGO_PKG_NAME");
    let file_name: String = thread_rng().gen_ascii_chars().take(10).collect();

    let mut file_path = env::temp_dir();
    file_path.push(name);

    // create parent directory
    match create_dir_all(&file_path) {
        Ok(_) => logger.verbose::<()>("Created temporary directory.", &[], None),
        Err(error) => logger.verbose("Unable to create temporary directory: ", &[&file_path.to_str().unwrap_or("???")], Some(error)),
    };

    file_path.push(file_name);
    if cfg!(windows) {
        file_path.set_extension("bat");
    } else {
        file_path.set_extension("sh");
    };

    let file_path_str = &file_path.to_str().unwrap_or("???");

    logger.verbose::<()>("Creating temporary script file: ", &[&file_path_str], None);

    let mut file = match File::create(&file_path) {
        Err(error) => {
            logger.error("Unable to create script file: ", &[&file_path_str], Some(&error));
            panic!("Unable to create script file, error: {}", error);
        }
        Ok(file) => file,
    };

    let mut text = script_lines.join("\n");

    let cwd_holder = match current_dir() {
        Ok(value) => value,
        Err(error) => {
            logger.error("Unable to get current working directory.", &[], Some(&error));
            panic!("Unable to get current working directory, error: {}", error);
        }
    };

    let cwd = match cwd_holder.to_str() {
        Some(cwd_str) => cwd_str.clone(),
        None => {
            logger.error::<()>("Unable to get current working directory.", &[], None);
            panic!("Unable to get current working directory");
        }
    };

    text.insert_str(0, "\n");
    text.insert_str(0, cwd);
    text.insert_str(0, "cd ");

    match file.write_all(text.as_bytes()) {
        Err(error) => {
            logger.error("Unable to write to script file: ", &[&file_path_str], Some(&error));
            panic!("Unable to write to script file, error: {}", error);
        }
        Ok(_) => logger.verbose::<()>("Written script file text:\n", &[&text], None),
    }

    let command = if cfg!(windows) {
        "cmd.exe"
    } else {
        "sh"
    };

    let args_vector = if cfg!(windows) {
        vec!["/C".to_string(), file_path_str.to_string()]
    } else {
        vec![file_path_str.to_string()]
    };

    let args = Some(args_vector);

    run_command(&logger, &command, &args);

    match remove_file(&file_path_str) {
        Ok(_) => logger.verbose::<()>("Temporary file deleted: ", &[&file_path_str], None),
        Err(error) => logger.verbose("Unable to delete temporary file: ", &[&file_path_str], Some(error)),
    };
}

/// Runs the requested command and panics in case of any error.
pub fn run_command(
    logger: &Logger,
    command_string: &str,
    args: &Option<Vec<String>>,
) {
    logger.verbose::<()>("Execute Command: ", &[&command_string], None);
    let mut command = Command::new(&command_string);

    match *args {
        Some(ref args_vec) => {
            for arg in args_vec.iter() {
                command.arg(arg);
            }
        }
        None => logger.verbose::<()>("No command args defined.", &[], None),
    };

    command.stdin(Stdio::inherit()).stdout(Stdio::inherit()).stderr(Stdio::inherit());
    logger.info("Execute Command: ", &[], Some(&command));

    let exit_status = command.status();
    validate_exit_code(exit_status);
}

/// Runs the given task command and if not defined, the task script.
pub fn run(
    logger: &Logger,
    step: &Step,
) {
    match step.config.command {
        Some(ref command_string) => {
            run_command(&logger, &command_string, &step.config.args);
        }
        None => {
            match step.config.script {
                Some(ref script) => run_script(&logger, script),
                None => logger.verbose::<()>("No script defined.", &[], None),
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    use log;
    use std::io::ErrorKind;
    use types::Task;

    #[test]
    #[should_panic]
    fn validate_exit_code_error() {
        validate_exit_code(Err(Error::new(ErrorKind::Other, "test")));
    }

    #[test]
    fn run_no_command() {
        let logger = log::create("error");
        let task = Task {
            install_crate: None,
            command: None,
            args: None,
            disabled: None,
            alias: None,
            install_script: None,
            script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }

    #[test]
    fn run_command() {
        let logger = log::create("error");
        let task = Task {
            command: Some("echo".to_string()),
            args: Some(vec!["1".to_string()]),
            install_crate: None,
            disabled: None,
            alias: None,
            install_script: None,
            script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }

    #[test]
    fn run_script() {
        let logger = log::create("error");
        let task = Task {
            script: Some(vec!["echo 1".to_string()]),
            command: None,
            install_crate: None,
            args: None,
            disabled: None,
            alias: None,
            install_script: None,
            dependencies: None
        };
        let step = Step { name: "test".to_string(), config: task };

        run(&logger, &step);
    }
}
<|endoftext|>


<commit_before>
use lapp;
use es::traits::*;
use crate::crate_utils;
use crate::cache;
use crate::state::State;

use std::process;
use std::path::{Path,PathBuf};
use std::env::consts::{DLL_SUFFIX,DLL_PREFIX};
use std::collections::{HashSet};

fn simplify_qualified_names(text: &str) -> String {
    let std = "std::";
    let mut res = String::new();
    let mut s = text;
    while let Some(pos) = s.find(std) {
        res.push_str(&s[0..pos]);
        s = &s[pos+std.len()..];
        if let Some(pos) = s.find("::") {
            s = &s[pos+2..];
        }
    }
    res.push_str(s);
    res
}

// handle two useful cases:
// - compile a crate as a dynamic library, given a name and an output dir
// - compile a program, given a program
pub fn compile_crate(args: &lapp::Args, state: &State,
    crate_name: &str, crate_path: &Path,
    output_program: Option<&Path>, mut extern_crates: Vec<String>, features: Vec<String>) -> bool
{
    let verbose = args.get_bool("verbose");
    let simplify = ! args.get_bool("no-simplify");
    let debug = ! state.optimize;

    // implicit linking works fine, until it doesn't
    extern_crates.extend(args.get_strings("extern"));
    extern_crates.sort();
    extern_crates.dedup();
    // libc is such a special case
    if args.get_bool("libc") {
        extern_crates.push("libc".into());
    }
    let mut cfg = args.get_strings("cfg");
    let explicit_features = args.get_strings("features");
    for f in if explicit_features.len() > 0 {explicit_features} else {features} {
        cfg.push(format!("feature=\"{}\"",f));
    }
    let cache = cache::get_cache(&state);
    let mut builder = process::Command::new("rustc");
    if state.edition != "2015" {
        builder.args(&["--edition",&state.edition]);
    }
    if ! state.build_static { // stripped-down dynamic link
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
        if let Ok(link) = args.get_string_result("link") {
            if verbose { println!("linking against {}",link); }
            builder.arg("-L").arg(&link);
        }
    } else { // static build
        builder.arg(if state.optimize {"-O"} else {"-g"});
        if state.optimize {
            // no point in carrying around all that baggage...
            builder.args(&["-C","debuginfo=0"]);
        }
    }
    // implicitly linking against crates in the dynamic or static cache
    builder.arg("-L").arg(&cache);
    if ! state.exe { // as a dynamic library
        builder.args(&["--crate-type","dylib"])
        .arg("--out-dir").arg(&cache)
        .arg("--crate-name").arg(&crate_utils::proper_crate_name(crate_name));
    } else {
        builder.arg("-o").arg(output_program.unwrap());
    }
    for c in cfg {
        builder.arg("--cfg").arg(&c);
    }

    // explicit --extern references require special treatment for
    // static builds, since the libnames include a hash.
    // So we look for the latest crate of this name

    let extern_crates: Vec<(String,String)> =
    if state.build_static && extern_crates.len() > 0 {
        let m = cache::get_metadata();
        extern_crates.into_iter().map(|c|
            (m.get_full_crate_name(&c,debug)
                .or_then_die(|_| format!("no such crate '{}' in static cache: use --add",c)),c)
        ).collect()
    } else {
        extern_crates.into_iter().map(|c|
            (format!("{}{}{}",DLL_PREFIX,c,DLL_SUFFIX),c)
        ).collect()
    };

    for (name,c) in extern_crates {
        let full_path = PathBuf::from(&cache).join(&name);
        let ext = format!("{}={}",c,full_path.display());
        if verbose {
            println!("extern {}",ext);
        }
        builder.arg("--extern").arg(&ext);
    }
    builder.arg(crate_path);
    if simplify {
        if isatty::stderr_isatty() {
            builder.args(&["--color","always"]);
        }
        let output = builder.output().or_die("can't run rustc");
        let status = output.status.success();
        if ! status {
            let err = String::from_utf8_lossy(&output.stderr);
            eprintln!("{}",simplify_qualified_names(&err));
        }
        status
    } else {
        builder.status().or_die("can't run rustc").success()
    }
}

pub fn massage_snippet(code: String, prelude: String,
        extern_crates: Vec<String>, wild_crates: Vec<String>, macro_crates: HashSet<String>, body_prelude: String) -> (String,Vec<String>) {
    use crate::strutil::{after,word_after};

    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }

    let mut prefix = prelude;
    let mut crate_begin = String::new();
    let mut body = String::new();
    let mut deduced_externs = Vec::new();

    body += &body_prelude;
    {
        if extern_crates.len() > 0 {
            let aliases = cache::get_aliases();
            for c in &extern_crates {
                prefix += &if let Some(aliased) = aliases.get(c) {
                    format!("extern crate {} as {};\n",aliased,c)
                } else {
                    let mac = if macro_crates.contains(c) {"#[macro_use] "} else {""};
                    format!("{}extern crate {};\n",mac,c)
                };
            }
            for c in wild_crates {
                prefix += &format!("use {}::*;\n",c);
            }
        }
        let mut lines = code.lines();
        let mut first = true;
        for line in lines.by_ref() {
            let line = line.trim_start();
            if first { // files may start with #! shebang...
                if line.starts_with("#!/") {
                    continue;
                }
                first = false;
            }
            // crate import, use should go at the top.
            // Particularly need to force crate-level attributes to the top
            // These must not be in the `run` function we're generating
            if let Some(rest) = after(line,"#[macro_use") {
                if let Some(crate_name) = word_after(rest,"extern crate ") {
                    deduced_externs.push(crate_name);
                }
                prefix += line;
                prefix.push('\n');
            } else
            if line.starts_with("extern ") || line.starts_with("use ") {
                if let Some(crate_name) = word_after(line,"extern crate ") {
                    deduced_externs.push(crate_name);
                }
                prefix += line;
                prefix.push('\n');
            } else
            if line.starts_with("#![") {
                // inner attributes really need to be at the top of the file
                crate_begin += line;
                crate_begin.push('\n');
            } else
            if line.len() > 0 {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    deduced_externs.extend(extern_crates);
    deduced_externs.sort();
    deduced_externs.dedup();

    let massaged_code = format!("{}
{}

fn run(args: Vec<String>) -> std::result::Result<(),Box<dyn std::error::Error+Sync+Send>> {{
{}    Ok(())
}}
fn main() {{
    if let Err(e) = run(std::env::args().collect()) {{
        println!(\"error: {{:?}}\",e);
    }}
}}
",crate_begin,prefix,body);

    (massaged_code, deduced_externs)

}

<commit_msg>NLL leads to more beautiful code<commit_after>
use lapp;
use es::traits::*;
use crate::crate_utils;
use crate::cache;
use crate::state::State;

use std::process;
use std::path::{Path,PathBuf};
use std::env::consts::{DLL_SUFFIX,DLL_PREFIX};
use std::collections::{HashSet};

fn simplify_qualified_names(text: &str) -> String {
    let std = "std::";
    let mut res = String::new();
    let mut s = text;
    while let Some(pos) = s.find(std) {
        res.push_str(&s[0..pos]);
        s = &s[pos+std.len()..];
        if let Some(pos) = s.find("::") {
            s = &s[pos+2..];
        }
    }
    res.push_str(s);
    res
}

// handle two useful cases:
// - compile a crate as a dynamic library, given a name and an output dir
// - compile a program, given a program
pub fn compile_crate(args: &lapp::Args, state: &State,
    crate_name: &str, crate_path: &Path,
    output_program: Option<&Path>, mut extern_crates: Vec<String>, features: Vec<String>) -> bool
{
    let verbose = args.get_bool("verbose");
    let simplify = ! args.get_bool("no-simplify");
    let debug = ! state.optimize;

    // implicit linking works fine, until it doesn't
    extern_crates.extend(args.get_strings("extern"));
    extern_crates.sort();
    extern_crates.dedup();
    // libc is such a special case
    if args.get_bool("libc") {
        extern_crates.push("libc".into());
    }
    let mut cfg = args.get_strings("cfg");
    let explicit_features = args.get_strings("features");
    for f in if explicit_features.len() > 0 {explicit_features} else {features} {
        cfg.push(format!("feature=\"{}\"",f));
    }
    let cache = cache::get_cache(&state);
    let mut builder = process::Command::new("rustc");
    if state.edition != "2015" {
        builder.args(&["--edition",&state.edition]);
    }
    if ! state.build_static { // stripped-down dynamic link
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
        if let Ok(link) = args.get_string_result("link") {
            if verbose { println!("linking against {}",link); }
            builder.arg("-L").arg(&link);
        }
    } else { // static build
        builder.arg(if state.optimize {"-O"} else {"-g"});
        if state.optimize {
            // no point in carrying around all that baggage...
            builder.args(&["-C","debuginfo=0"]);
        }
    }
    // implicitly linking against crates in the dynamic or static cache
    builder.arg("-L").arg(&cache);
    if ! state.exe { // as a dynamic library
        builder.args(&["--crate-type","dylib"])
        .arg("--out-dir").arg(&cache)
        .arg("--crate-name").arg(&crate_utils::proper_crate_name(crate_name));
    } else {
        builder.arg("-o").arg(output_program.unwrap());
    }
    for c in cfg {
        builder.arg("--cfg").arg(&c);
    }

    // explicit --extern references require special treatment for
    // static builds, since the libnames include a hash.
    // So we look for the latest crate of this name

    let extern_crates: Vec<(String,String)> =
    if state.build_static && extern_crates.len() > 0 {
        let m = cache::get_metadata();
        extern_crates.into_iter().map(|c|
            (m.get_full_crate_name(&c,debug)
                .or_then_die(|_| format!("no such crate '{}' in static cache: use --add",c)),c)
        ).collect()
    } else {
        extern_crates.into_iter().map(|c|
            (format!("{}{}{}",DLL_PREFIX,c,DLL_SUFFIX),c)
        ).collect()
    };

    for (name,c) in extern_crates {
        let full_path = PathBuf::from(&cache).join(&name);
        let ext = format!("{}={}",c,full_path.display());
        if verbose {
            println!("extern {}",ext);
        }
        builder.arg("--extern").arg(&ext);
    }
    builder.arg(crate_path);
    if simplify {
        if isatty::stderr_isatty() {
            builder.args(&["--color","always"]);
        }
        let output = builder.output().or_die("can't run rustc");
        let status = output.status.success();
        if ! status {
            let err = String::from_utf8_lossy(&output.stderr);
            eprintln!("{}",simplify_qualified_names(&err));
        }
        status
    } else {
        builder.status().or_die("can't run rustc").success()
    }
}

pub fn massage_snippet(code: String, prelude: String,
        extern_crates: Vec<String>, wild_crates: Vec<String>, macro_crates: HashSet<String>, body_prelude: String) -> (String,Vec<String>) {
    use crate::strutil::{after,word_after};

    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }

    let mut prefix = prelude;
    let mut crate_begin = String::new();
    let mut body = String::new();
    let mut deduced_externs = Vec::new();

    body += &body_prelude;
    if extern_crates.len() > 0 {
        let aliases = cache::get_aliases();
        for c in &extern_crates {
            prefix += &if let Some(aliased) = aliases.get(c) {
                format!("extern crate {} as {};\n",aliased,c)
            } else {
                let mac = if macro_crates.contains(c) {"#[macro_use] "} else {""};
                format!("{}extern crate {};\n",mac,c)
            };
        }
        for c in wild_crates {
            prefix += &format!("use {}::*;\n",c);
        }
    }
    let mut lines = code.lines();
    let mut first = true;
    for line in lines.by_ref() {
        let line = line.trim_start();
        if first { // files may start with #! shebang...
            if line.starts_with("#!/") {
                continue;
            }
            first = false;
        }
        // crate import, use should go at the top.
        // Particularly need to force crate-level attributes to the top
        // These must not be in the `run` function we're generating
        if let Some(rest) = after(line,"#[macro_use") {
            if let Some(crate_name) = word_after(rest,"extern crate ") {
                deduced_externs.push(crate_name);
            }
            prefix += line;
            prefix.push('\n');
        } else
        if line.starts_with("extern ") || line.starts_with("use ") {
            if let Some(crate_name) = word_after(line,"extern crate ") {
                deduced_externs.push(crate_name);
            }
            prefix += line;
            prefix.push('\n');
        } else
        if line.starts_with("#![") {
            // inner attributes really need to be at the top of the file
            crate_begin += line;
            crate_begin.push('\n');
        } else
        if line.len() > 0 {
            body += &indent_line(line);
            break;
        }
    }
    // and indent the rest!
    body.extend(lines.map(indent_line));

    deduced_externs.extend(extern_crates);
    deduced_externs.sort();
    deduced_externs.dedup();

    let massaged_code = format!("{}
{}

fn run(args: Vec<String>) -> std::result::Result<(),Box<dyn std::error::Error+Sync+Send>> {{
{}    Ok(())
}}
fn main() {{
    if let Err(e) = run(std::env::args().collect()) {{
        println!(\"error: {{:?}}\",e);
    }}
}}
",crate_begin,prefix,body);

    (massaged_code, deduced_externs)

}

<|endoftext|>


<commit_before>use std::default::Default;
use std::collections::HashSet;
use jmap::method::*;
use jmap::method::ResponseMethod::*;
use jmap::util::Presence::*;

use util::RequestContext;

pub trait ContactHandler {
    fn get_contacts(&self, args: GetRequestArgs, client_id: String) -> ResponseMethod;
    fn get_contact_updates(&self, args: GetUpdatesRequestArgs, client_id: String) -> ResponseMethod;
    fn set_contacts(&self, args: SetRequestArgs, client_id: String) -> ResponseMethod;
}

impl ContactHandler for RequestContext {
    fn get_contacts(&self, args: GetRequestArgs, client_id: String) -> ResponseMethod {
        let records = self.db.get_records(args.ids.as_option()).unwrap(); // XXX assuming success

        let not_found = match args.ids {
            Absent => None,
            Present(ids) => {
                let mut found = HashSet::new();
                for record in records.iter() {
                    found.insert(&record.id);
                }
                let not_found = ids.into_iter().filter(|id| !found.contains(id)).collect::<Vec<_>>();
                match not_found.len() {
                    0 => None,
                    _ => Some(not_found),
                }
            }
        };

        let response = GetResponseArgs {
            state: "abc123".to_string(),
            list: Some(records.iter().map(|ref r| r.to_partial()).collect()),
            not_found: not_found,
        };

        Contacts(response, client_id)
    }

    fn get_contact_updates(&self, args: GetUpdatesRequestArgs, client_id: String) -> ResponseMethod {
        println!("get_contact_updates: {:?} {}", args, client_id);
        ContactUpdates(GetUpdatesResponseArgs::default(), client_id)
    }

    fn set_contacts(&self, args: SetRequestArgs, client_id: String) -> ResponseMethod {
        println!("set_contacts: {:?} {}", args, client_id);
        ContactsSet(SetResponseArgs::default(), client_id)
    }
}
<commit_msg>Filter requested properties<commit_after>use std::default::Default;
use std::collections::HashSet;
use jmap::method::*;
use jmap::method::ResponseMethod::*;
use jmap::util::Presence::*;

use util::RequestContext;

pub trait ContactHandler {
    fn get_contacts(&self, args: GetRequestArgs, client_id: String) -> ResponseMethod;
    fn get_contact_updates(&self, args: GetUpdatesRequestArgs, client_id: String) -> ResponseMethod;
    fn set_contacts(&self, args: SetRequestArgs, client_id: String) -> ResponseMethod;
}

impl ContactHandler for RequestContext {
    fn get_contacts(&self, args: GetRequestArgs, client_id: String) -> ResponseMethod {
        let records = self.db.get_records(args.ids.as_option()).unwrap(); // XXX assuming success

        let not_found = match args.ids {
            Absent => None,
            Present(ids) => {
                let mut found = HashSet::new();
                for record in records.iter() {
                    found.insert(&record.id);
                }
                let not_found = ids.into_iter().filter(|id| !found.contains(id)).collect::<Vec<_>>();
                match not_found.len() {
                    0 => None,
                    _ => Some(not_found),
                }
            }
        };

        let list = match args.properties {
            Absent     => Some(records.iter().map(|ref r| r.to_partial()).collect()),
            Present(p) => Some(records.iter().map(|ref r| r.to_filtered_partial(&p)).collect()),
        };

        let response = GetResponseArgs {
            state: "abc123".to_string(),
            list: list,
            not_found: not_found,
        };

        Contacts(response, client_id)
    }

    fn get_contact_updates(&self, args: GetUpdatesRequestArgs, client_id: String) -> ResponseMethod {
        println!("get_contact_updates: {:?} {}", args, client_id);
        ContactUpdates(GetUpdatesResponseArgs::default(), client_id)
    }

    fn set_contacts(&self, args: SetRequestArgs, client_id: String) -> ResponseMethod {
        println!("set_contacts: {:?} {}", args, client_id);
        ContactsSet(SetResponseArgs::default(), client_id)
    }
}
<|endoftext|>


<commit_before>//! Context for XS subroutine calls.
use std;
use raw;
use { AV, SV };
use convert::{ FromSV, IntoSV, TryFromSV };
use std::ffi::CStr;

/// XS call context.
pub struct Context {
    pthx: raw::Interpreter,
    stack: raw::Stack,
}

const EMPTY: &'static [i8] = &[ 0 ];

impl Context {
    /// Invoke closure with the context of Perl subroutine call.
    ///
    /// This function must be called exactly once per subroutine: it consumes one stack frame
    /// prepared for us by the Perl interpreter. Multiple use will leave the stack state in bad
    /// shape.
    ///
    /// This function called automatically by subroutines defined with the `xs!` macro.
    ///
    /// Any panics that happen inside the closure will be converted to Perl exceptions and
    /// re-thrown. Panics with `String` or `&str` argument will use that as the exception text,
    /// other types will result in the default text message.
    ///
    /// Perl exceptions in code called by the closure will be captured and turned into panics, to be
    /// re-thrown again as perl exceptions after executing Rust destructors. Note, that Perl
    /// extension API does not allow such exceptions to be handled by the programmer (see paragraph
    /// on [Exception Handling](http://perldoc.perl.org/perlguts.html#Exception-Handling) in the
    /// Perl documentation).
    #[inline]
    pub fn wrap<F>(pthx: raw::PerlThreadContext, f: F)
        where F: FnOnce(&mut Self) + std::panic::UnwindSafe
    {
        unsafe {
            let perl = raw::Interpreter::new(pthx);

            perl.catch_unwind(|| {
                let mut ctx = Context {
                    pthx: perl,
                    stack: std::mem::uninitialized(),
                };

                perl.stack_init(&mut ctx.stack);

                f(&mut ctx)
            });
        }
    }

    // STACK

    /// Rewind stack pointer to the base of current frame.
    #[inline]
    pub fn st_prepush(&mut self) {
        unsafe { self.pthx.stack_prepush(&mut self.stack) };
    }

    /// Copy local stack pointer back to Perl.
    ///
    /// See: [`PUTBACK`](http://perldoc.perl.org/perlapi.html#PUTBACK).
    #[inline]
    pub fn st_putback(&mut self) {
        unsafe { self.pthx.stack_putback(&mut self.stack) };
    }

    /// Return number of items on the argument stack.
    ///
    /// [`items`](http://perldoc.perl.org/perlapi.html#items).
    #[inline]
    pub fn st_items(&mut self) -> isize {
        unsafe { self.pthx.stack_items(&mut self.stack) as isize }
    }

    unsafe fn st_fetch_raw(&mut self, idx: isize) -> Option<*mut raw::SV> {
        if idx >= self.st_items() {
            return None;
        }
        let svp = self.pthx.stack_fetch(&mut self.stack, idx as raw::SSize_t);
        if svp.is_null() {
            return None;
        }

        Some(svp)
    }

    /// Fetch value from the Perl stack.
    ///
    /// See: [`ST`](http://perldoc.perl.org/perlapi.html#ST).
    #[inline]
    pub fn st_fetch<T>(&mut self, idx: isize) -> Option<T> where T: FromSV
    {
        unsafe {
            self.st_fetch_raw(idx).map(|svp| T::from_sv(self.pthx, svp))
        }
    }

    /// Fetch value from the Perl stack and try to convert to `T`.
    #[inline]
    pub fn st_try_fetch<T>(&mut self,idx: isize) -> Option<Result<T, T::Error>>
        where T: TryFromSV
    {
        unsafe {
            self.st_fetch_raw(idx).map(|svp| T::try_from_sv(self.pthx, svp))
        }
    }

    /// Push value onto Perl stack.
    ///
    /// See: [`mXPUSHs`](http://perldoc.perl.org/perlapi.html#mXPUSHs).
    #[inline]
    pub fn st_push<T>(&mut self, val: T) where T: IntoSV {
        let sv = val.into_sv(self.pthx);
        unsafe { self.pthx.stack_xpush_sv_mortal(&mut self.stack, sv.into_raw()) };
    }

    // XSUB

    /// Register new Perl xsub.
    ///
    /// See: [`newXS`](http://perldoc.perl.org/perlapi.html#newXS).
    #[inline]
    pub fn new_xs(&mut self, name: &CStr, xsaddr: raw::XSUBADDR_t) {
        unsafe { self.pthx.new_xs(name.as_ptr(), xsaddr, EMPTY.as_ptr()) };
    }

    // GLOBALS

    /// Return the AV of the specified Perl global or package array.
    ///
    /// See: [`get_av`](http://perldoc.perl.org/perlapi.html#get_av).
    #[inline]
    pub fn get_av(&mut self, name: &CStr) -> Option<AV> {
        let avp = unsafe { self.pthx.get_av(name.as_ptr(), 0) };
        if avp.is_null() {
            None
        } else {
            Some(unsafe { AV::from_raw_borrowed(self.pthx, avp) })
        }
    }

    /// Call subroutine by name.
    ///
    /// See: [`call_pv`](http://perldoc.perl.org/perlapi.html#call_pv).
    #[inline]
    pub fn call_pv(&mut self, name: &CStr, flags: raw::U32) {
        unsafe { self.pthx.call_pv(name.as_ptr(), flags as raw::I32) };
    }

    // SCALARS

    /// Allocate new SV of type appropriate to store `T`
    #[inline]
    pub fn new_sv<T>(&mut self, val: T) -> SV where T: IntoSV {
        val.into_sv(self.pthx)
    }
}
<commit_msg>Add context method to produce undef SV.<commit_after>//! Context for XS subroutine calls.
use std;
use raw;
use { AV, SV };
use convert::{ FromSV, IntoSV, TryFromSV };
use std::ffi::CStr;

/// XS call context.
pub struct Context {
    pthx: raw::Interpreter,
    stack: raw::Stack,
}

const EMPTY: &'static [i8] = &[ 0 ];

impl Context {
    /// Invoke closure with the context of Perl subroutine call.
    ///
    /// This function must be called exactly once per subroutine: it consumes one stack frame
    /// prepared for us by the Perl interpreter. Multiple use will leave the stack state in bad
    /// shape.
    ///
    /// This function called automatically by subroutines defined with the `xs!` macro.
    ///
    /// Any panics that happen inside the closure will be converted to Perl exceptions and
    /// re-thrown. Panics with `String` or `&str` argument will use that as the exception text,
    /// other types will result in the default text message.
    ///
    /// Perl exceptions in code called by the closure will be captured and turned into panics, to be
    /// re-thrown again as perl exceptions after executing Rust destructors. Note, that Perl
    /// extension API does not allow such exceptions to be handled by the programmer (see paragraph
    /// on [Exception Handling](http://perldoc.perl.org/perlguts.html#Exception-Handling) in the
    /// Perl documentation).
    #[inline]
    pub fn wrap<F>(pthx: raw::PerlThreadContext, f: F)
        where F: FnOnce(&mut Self) + std::panic::UnwindSafe
    {
        unsafe {
            let perl = raw::Interpreter::new(pthx);

            perl.catch_unwind(|| {
                let mut ctx = Context {
                    pthx: perl,
                    stack: std::mem::uninitialized(),
                };

                perl.stack_init(&mut ctx.stack);

                f(&mut ctx)
            });
        }
    }

    // STACK

    /// Rewind stack pointer to the base of current frame.
    #[inline]
    pub fn st_prepush(&mut self) {
        unsafe { self.pthx.stack_prepush(&mut self.stack) };
    }

    /// Copy local stack pointer back to Perl.
    ///
    /// See: [`PUTBACK`](http://perldoc.perl.org/perlapi.html#PUTBACK).
    #[inline]
    pub fn st_putback(&mut self) {
        unsafe { self.pthx.stack_putback(&mut self.stack) };
    }

    /// Return number of items on the argument stack.
    ///
    /// [`items`](http://perldoc.perl.org/perlapi.html#items).
    #[inline]
    pub fn st_items(&mut self) -> isize {
        unsafe { self.pthx.stack_items(&mut self.stack) as isize }
    }

    unsafe fn st_fetch_raw(&mut self, idx: isize) -> Option<*mut raw::SV> {
        if idx >= self.st_items() {
            return None;
        }
        let svp = self.pthx.stack_fetch(&mut self.stack, idx as raw::SSize_t);
        if svp.is_null() {
            return None;
        }

        Some(svp)
    }

    /// Fetch value from the Perl stack.
    ///
    /// See: [`ST`](http://perldoc.perl.org/perlapi.html#ST).
    #[inline]
    pub fn st_fetch<T>(&mut self, idx: isize) -> Option<T> where T: FromSV
    {
        unsafe {
            self.st_fetch_raw(idx).map(|svp| T::from_sv(self.pthx, svp))
        }
    }

    /// Fetch value from the Perl stack and try to convert to `T`.
    #[inline]
    pub fn st_try_fetch<T>(&mut self,idx: isize) -> Option<Result<T, T::Error>>
        where T: TryFromSV
    {
        unsafe {
            self.st_fetch_raw(idx).map(|svp| T::try_from_sv(self.pthx, svp))
        }
    }

    /// Push value onto Perl stack.
    ///
    /// See: [`mXPUSHs`](http://perldoc.perl.org/perlapi.html#mXPUSHs).
    #[inline]
    pub fn st_push<T>(&mut self, val: T) where T: IntoSV {
        let sv = val.into_sv(self.pthx);
        unsafe { self.pthx.stack_xpush_sv_mortal(&mut self.stack, sv.into_raw()) };
    }

    // XSUB

    /// Register new Perl xsub.
    ///
    /// See: [`newXS`](http://perldoc.perl.org/perlapi.html#newXS).
    #[inline]
    pub fn new_xs(&mut self, name: &CStr, xsaddr: raw::XSUBADDR_t) {
        unsafe { self.pthx.new_xs(name.as_ptr(), xsaddr, EMPTY.as_ptr()) };
    }

    // GLOBALS

    /// Return the AV of the specified Perl global or package array.
    ///
    /// See: [`get_av`](http://perldoc.perl.org/perlapi.html#get_av).
    #[inline]
    pub fn get_av(&mut self, name: &CStr) -> Option<AV> {
        let avp = unsafe { self.pthx.get_av(name.as_ptr(), 0) };
        if avp.is_null() {
            None
        } else {
            Some(unsafe { AV::from_raw_borrowed(self.pthx, avp) })
        }
    }

    /// Call subroutine by name.
    ///
    /// See: [`call_pv`](http://perldoc.perl.org/perlapi.html#call_pv).
    #[inline]
    pub fn call_pv(&mut self, name: &CStr, flags: raw::U32) {
        unsafe { self.pthx.call_pv(name.as_ptr(), flags as raw::I32) };
    }

    // SCALARS

    /// Allocate new SV of type appropriate to store `T`
    #[inline]
    pub fn new_sv<T>(&mut self, val: T) -> SV where T: IntoSV {
        val.into_sv(self.pthx)
    }

    /// Return an undefined SV.
    pub fn sv_undef(&mut self) -> SV {
        unsafe { SV::from_raw_owned(self.pthx, self.pthx.sv_undef()) }
    }
}
<|endoftext|>