cpp_to_rust_common 0.0.1

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;
use toml;

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()));
      create_dir(dst).chain_err(&err)?;
    }

    for item in read_dir(dst).chain_err(&err)? {
      let item = 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()));
          remove_dir_all(&path).chain_err(&err)?;
        } else {
          log::noisy(format!("Old file removed: {}", path.display()));
          remove_file(&path).chain_err(&err)?;
        }
      }
    }

    for item in read_dir(src).chain_err(&err)? {
      let item = item.chain_err(&err)?;
      let from = item.path().to_path_buf();
      let to = dst.with_added(item.file_name());
      move_files(&from, &to).chain_err(&err)?;
    }
    remove_dir_all(src).chain_err(&err)?;
  } else {
    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() {
    create_dir(&dst).chain_err(&err)?;
    for item in read_dir(src).chain_err(&err)? {
      let item = item.chain_err(&err)?;
      let from = item.path().to_path_buf();
      let to = dst.with_added(item.file_name());
      copy_recursively(&from, &to).chain_err(&err)?;
    }
  } else {
    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 = file_to_string(old_path).chain_err(&err)?;
    let string2 = file_to_string(new_path).chain_err(&err)?;
    string1 != string2
  } else {
    true
  };

  if is_changed {
    if new_path.as_path().exists() {
      remove_file(&new_path).chain_err(&err)?;
    }
    rename_file(&old_path, &new_path).chain_err(&err)?;
    log::noisy(format!("File changed: {}", new_path.display()));
  } else {
    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: 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 = 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 = 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 load_toml<P: AsRef<Path>>(path: P) -> Result<toml::Table> {
  let data = file_to_string(path.as_ref())?;
  let mut parser = toml::Parser::new(&data);
  parser.parse().chain_err(|| format!("failed to parse TOML file: {}", path.as_ref().display()))
}

pub fn save_toml<P: AsRef<Path>>(path: P, data: toml::Table) -> Result<()> {
  let mut file = create_file(path.as_ref())?;
  file.write(toml::Value::Table(data).to_string()).chain_err(|| {
    format!("failed to write to TOML file: {}",
            path.as_ref().display())
  })
}


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

pub fn create_file<P: AsRef<Path>>(path: P) -> Result<FileWrapper> {
  Ok(FileWrapper {
    file: 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();
    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: 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 = fs::canonicalize(path.as_ref())
      .chain_err(|| format!("failed to canonicalize {}", path.as_ref().display()))?;
  {
    let str = 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())
}