cpp_to_rust_common 0.0.0

Common utilities for cpp_to_rust_generator and cpp_to_rust_build_tools
Documentation
use log;
use errors::{Result, ChainErr};

use std::path::{Path, PathBuf};
use std::fs;
use std::io::Read;

pub fn move_files(src: &PathBuf, dst: &PathBuf) -> Result<()> {
  let err = || format!("failed: move_files({:?}, {:?})", src, dst);
  if src.as_path().is_dir() {
    if !dst.as_path().is_dir() {
      log::noisy(format!("New dir created: {}", dst.display()));
      try!(create_dir(dst).chain_err(&err));
    }

    for item in try!(read_dir(dst).chain_err(&err)) {
      let item = try!(item.chain_err(&err));
      if !src.with_added(item.file_name()).as_path().exists() {
        let path = item.path();
        if path.as_path().is_dir() {
          log::noisy(format!("Old dir removed: {}", path.display()));
          try!(remove_dir_all(&path).chain_err(&err));
        } else {
          log::noisy(format!("Old file removed: {}", path.display()));
          try!(remove_file(&path).chain_err(&err));
        }
      }
    }

    for item in try!(read_dir(src).chain_err(&err)) {
      let item = try!(item.chain_err(&err));
      let from = item.path().to_path_buf();
      let to = dst.with_added(item.file_name());
      try!(move_files(&from, &to).chain_err(&err));
    }
    try!(remove_dir_all(src).chain_err(&err));
  } else {
    try!(move_one_file(src, dst).chain_err(&err));
  }
  Ok(())
}

pub fn copy_recursively(src: &PathBuf, dst: &PathBuf) -> Result<()> {
  let err = || format!("failed: copy_recursively({:?}, {:?})", src, dst);
  if src.as_path().is_dir() {
    try!(create_dir(&dst).chain_err(&err));
    for item in try!(read_dir(src).chain_err(&err)) {
      let item = try!(item.chain_err(&err));
      let from = item.path().to_path_buf();
      let to = dst.with_added(item.file_name());
      try!(copy_recursively(&from, &to).chain_err(&err));
    }
  } else {
    try!(copy_file(src, dst).chain_err(&err));
  }
  Ok(())
}

pub fn move_one_file(old_path: &PathBuf, new_path: &PathBuf) -> Result<()> {
  let err = || format!("failed: move_one_file({:?}, {:?})", old_path, new_path);
  let is_changed = if new_path.as_path().is_file() {
    let string1 = try!(file_to_string(old_path).chain_err(&err));
    let string2 = try!(file_to_string(new_path).chain_err(&err));
    string1 != string2
  } else {
    true
  };

  if is_changed {
    if new_path.as_path().exists() {
      try!(remove_file(&new_path).chain_err(&err));
    }
    try!(rename_file(&old_path, &new_path).chain_err(&err));
    log::noisy(format!("File changed: {}", new_path.display()));
  } else {
    try!(remove_file(&old_path).chain_err(&err));
    log::noisy(format!("File not changed: {}", new_path.display()));
  }
  Ok(())
}


pub trait PathBufWithAdded {
  fn with_added<P: AsRef<Path>>(&self, path: P) -> PathBuf;
}

impl PathBufWithAdded for PathBuf {
  fn with_added<P: AsRef<Path>>(&self, path: P) -> PathBuf {
    let mut p = self.clone();
    p.push(path);
    p
  }
}

impl PathBufWithAdded for Path {
  fn with_added<P: AsRef<Path>>(&self, path: P) -> PathBuf {
    let mut p = self.to_path_buf();
    p.push(path);
    p
  }
}

pub struct FileWrapper {
  file: fs::File,
  path: PathBuf,
}

pub fn open_file<P: AsRef<Path>>(path: P) -> Result<FileWrapper> {
  Ok(FileWrapper {
    file: try!(fs::File::open(path.as_ref())
      .chain_err(|| format!("Failed to open file for reading: {:?}", path.as_ref()))),
    path: path.as_ref().to_path_buf(),
  })
}

pub fn load_json<P: AsRef<Path>, T: ::serde::Deserialize>(path: P) -> Result<T> {
  let file = try!(open_file(path.as_ref()));
  ::serde_json::from_reader(file.into_file())
    .chain_err(|| format!("failed to parse file as JSON: {}", path.as_ref().display()))
}

pub fn save_json<P: AsRef<Path>, T: ::serde::Serialize>(path: P, value: &T) -> Result<()> {
  let file = try!(create_file(path.as_ref()));
  ::serde_json::to_writer(&mut file.into_file(), value).chain_err(|| {
    format!("failed to serialize to JSON file: {}",
            path.as_ref().display())
  })
}

pub fn file_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
  let mut f = try!(open_file(path));
  f.read_all()
}

pub fn create_file<P: AsRef<Path>>(path: P) -> Result<FileWrapper> {
  Ok(FileWrapper {
    file: try!(fs::File::create(path.as_ref())
      .chain_err(|| format!("Failed to create file: {:?}", path.as_ref()))),
    path: path.as_ref().to_path_buf(),
  })
}

impl FileWrapper {
  pub fn read_all(&mut self) -> Result<String> {
    let mut r = String::new();
    try!(self.file
      .read_to_string(&mut r)
      .chain_err(|| format!("Failed to read from file: {:?}", self.path)));
    Ok(r)
  }

  pub fn write<S: AsRef<str>>(&mut self, text: S) -> Result<()> {
    use std::io::Write;
    self.file
      .write_all(text.as_ref().as_bytes())
      .chain_err(|| format!("Failed to write to file: {:?}", self.path))
  }
  pub fn into_file(self) -> fs::File {
    self.file
  }
}

pub fn create_dir<P: AsRef<Path>>(path: P) -> Result<()> {
  fs::create_dir(path.as_ref()).chain_err(|| format!("Failed to create dir: {:?}", path.as_ref()))
}

pub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
  fs::create_dir_all(path.as_ref()).chain_err(|| {
    format!("Failed to create dirs (with parent components): {:?}",
            path.as_ref())
  })
}

pub fn remove_dir<P: AsRef<Path>>(path: P) -> Result<()> {
  fs::remove_dir(path.as_ref()).chain_err(|| format!("Failed to remove dir: {:?}", path.as_ref()))
}

pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
  fs::remove_dir_all(path.as_ref())
    .chain_err(|| format!("Failed to remove dir (recursively): {:?}", path.as_ref()))
}

pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
  fs::remove_file(path.as_ref()).chain_err(|| format!("Failed to remove file: {:?}", path.as_ref()))
}

pub fn rename_file<P: AsRef<Path>, P2: AsRef<Path>>(path1: P, path2: P2) -> Result<()> {
  fs::rename(path1.as_ref(), path2.as_ref()).chain_err(|| {
    format!("Failed to rename file from {:?} to {:?}",
            path1.as_ref(),
            path2.as_ref())
  })
}

pub fn copy_file<P: AsRef<Path>, P2: AsRef<Path>>(path1: P, path2: P2) -> Result<()> {
  fs::copy(path1.as_ref(), path2.as_ref()).map(|_| ()).chain_err(|| {
    format!("Failed to copy file from {:?} to {:?}",
            path1.as_ref(),
            path2.as_ref())
  })
}

pub struct ReadDirWrapper {
  read_dir: fs::ReadDir,
  path: PathBuf,
}

pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDirWrapper> {
  Ok(ReadDirWrapper {
    read_dir: try!(fs::read_dir(path.as_ref())
      .chain_err(|| format!("Failed to read dir: {:?}", path.as_ref()))),
    path: path.as_ref().to_path_buf(),
  })
}

impl Iterator for ReadDirWrapper {
  type Item = Result<fs::DirEntry>;
  fn next(&mut self) -> Option<Result<fs::DirEntry>> {
    self.read_dir
      .next()
      .map(|value| value.chain_err(|| format!("Failed to read dir (in item): {:?}", self.path)))
  }
}

pub fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
  let r = try!(fs::canonicalize(path.as_ref())
    .chain_err(|| format!("failed to canonicalize {}", path.as_ref().display())));
  {
    let str = try!(path_to_str(&r));
    if str.starts_with(r"\\?\") {
      return Ok(PathBuf::from(&str[4..]));
    }
  }
  Ok(r)
}

pub fn path_to_str(path: &Path) -> Result<&str> {
  path.to_str().chain_err(|| format!("Path is not valid unicode: {}", path.display()))
}

use std::ffi::{OsStr, OsString};
pub fn os_str_to_str(os_str: &OsStr) -> Result<&str> {
  os_str.to_str().chain_err(|| format!("String is not valid unicode: {}", os_str.to_string_lossy()))
}

pub fn os_string_into_string(s: OsString) -> Result<String> {
  s.into_string()
    .map_err(|s| format!("String is not valid unicode: {}", s.to_string_lossy()).into())
}