Skip to content

Commit

Permalink
front
Browse files Browse the repository at this point in the history
  • Loading branch information
RCmerci committed Jan 19, 2019
1 parent 9edbaf7 commit 168a14d
Show file tree
Hide file tree
Showing 10 changed files with 2,009 additions and 127 deletions.
152 changes: 152 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ edition = "2018"

[dependencies]
db = { path = "db" }
dockerclient = { path = "dockerclient"}
dockerclient = { path = "dockerclient"}
front = { path = "front" }
clap = "2.32.0"
28 changes: 17 additions & 11 deletions db/src/dir_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,37 @@ use std::fs::File;
use std::io;
use std::io::{copy, Seek, SeekFrom};
use std::path::Path;
// use walkdir;
pub enum Error<T: std::error::Error> {
BadPath,
#[derive(Debug)]
pub enum Error {
BadPath(String),
IOError(io::Error),
DefaultError(T),
DefaultError(String),
}

pub struct DirItem<'a> {
path: &'a Path,
fs: Vec<File>,
id: String,
}

impl<'a> DirItem<'a> {
pub fn new(path: &'a Path) -> Result<Self, Error<walkdir::Error>> {
if path.is_dir() && path.exists() {
return Err(Error::BadPath);
pub fn new(path: &'a Path) -> Result<Self, Error> {
if !path.is_dir() || !path.exists() {
return Err(Error::BadPath(path.display().to_string()));
}
let mut fs = vec![];
for e in walkdir::WalkDir::new(path)
.follow_links(true)
.sort_by(|a, b| a.file_name().cmp(b.file_name()))
{
let entry = e.map_err(Error::DefaultError)?;
let entry = e.map_err(|e| Error::DefaultError(e.to_string()))?;
if !entry.path().is_dir() {
let f = File::open(entry.path()).map_err(Error::IOError)?;
fs.push(f);
}
}
Ok(DirItem { path, fs })
let id = format!("DIR: {:?}", path.file_name().unwrap());
Ok(DirItem { path, fs, id })
}
}

Expand All @@ -45,7 +47,11 @@ impl<'a> crate::Item for DirItem<'a> {
hasher.result().to_vec()
}

fn id(&self) -> String {
format!("DIR: {:?}", self.path.file_name().unwrap())
fn id(&self) -> &str {
&self.id
}

fn srcpath(&self) -> &Path {
self.path
}
}
168 changes: 144 additions & 24 deletions db/src/docker.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,154 @@
use std::fmt;

use crate::*;

use std::fmt;
use std::ops::DerefMut;
use std::path::Path;
#[derive(Debug)]
enum Error {
pub enum Error {
NotFoundEntry(String),
DockerError(dockerclient::Error),
ExecError(String),
FileItemError(file_item::Error),
DirItemError(dir_item::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "imagedrive error")
}
}

struct ImageDrive<'a> {
image_name: &'a str,
pub struct ImageDrive {
image_name: String,
dockercli: dockerclient::DockerClient,
}

impl<'a> ImageDrive<'a> {
fn new(image_name: &str) -> ImageDrive {
let dockercli = dockerclient::DockerClient::new();
impl ImageDrive {
pub fn new(image_name: &str, server: &str, username: &str, password: &str) -> ImageDrive {
let dockercli = dockerclient::DockerClient::new_with_logininfo(server, username, password);
ImageDrive {
image_name,
dockercli,
image_name: image_name.to_string(),
dockercli: dockercli,
}
}
}

impl<'a> fmt::Display for ImageDrive<'a> {
impl fmt::Display for ImageDrive {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "imagedrive: {}", self.image_name)
}
}

impl<'a> DB<Error> for ImageDrive<'a> {
fn catalog(&self) -> Result<Vec<String>, Error> {
// let c = get_or_run(self.image_name)?;
// self.dockercli.exec(&c.id, "ls /data");
Ok(vec![])
impl DB<Error> for ImageDrive {
fn entries(&self) -> Result<Vec<String>, Error> {
ls(&self.dockercli, &self.image_name, &Path::new("/data"))
}
fn add(&self, _title: &str, _item: &Item) -> Option<Error> {
None
fn items(&self, entry: &str) -> Result<Vec<String>, Error> {
ls(
&self.dockercli,
&self.image_name,
&Path::new("/data").join(entry),
)
}
fn delete(&self, _title: &str, _id: &str) -> Option<Error> {
None

fn add(&self, entry: &str, itempath: &Path) -> Result<AddResult, Error> {
let mut item: Box<Item> = if itempath.is_file() {
Box::new(file_item::FileItem::new(itempath).map_err(Error::FileItemError)?)
} else {
Box::new(dir_item::DirItem::new(itempath).map_err(Error::DirItemError)?)
};

let c = get_or_run(&self.dockercli, &self.image_name)?;
let path = Path::new("/data").join(entry);
let ls_entry = format!(
"mkdir -p {} && ls {}",
path.as_path().display(),
path.as_path().display()
);
self.dockercli
.exec(&c.id, &ls_entry)
.map_err(Error::DockerError)
.map(|(out, err)| {
(
(String::from_utf8_lossy(&out).to_owned().to_string()),
(String::from_utf8_lossy(&err).to_owned().to_string()),
)
})
.and_then(|(out, err)| {
if err != "" {
return Err(Error::ExecError(err));
}
let items: Vec<&str> = if out.trim() == "" {
vec![]
} else {
out.trim().split(" ").collect()
};
let mut ps = vec![];
let mut fileitems = vec![];
let mut diritems = vec![];
for item in items {
ps.push(Path::new("/data").join(item));
}
for p in &ps {
if p.is_file() {
fileitems.push(file_item::FileItem::new(&p).map_err(Error::FileItemError)?);
} else {
diritems.push(dir_item::DirItem::new(&p).map_err(Error::DirItemError)?);
};
}

for mut fi in fileitems {
if compare_items(&mut fi, item.deref_mut()) {
return Ok(AddResult::ExistedItem(fi.id().into()));
}
}
for mut di in diritems {
if compare_items(&mut di, item.deref_mut()) {
return Ok(AddResult::ExistedItem(di.id().into()));
}
}
let dstpath = Path::new("/data").join(entry).join(item.id());
self.dockercli
.copy_in(&c.id, item.srcpath(), &dstpath)
.map_err(Error::DockerError)?;
Ok(AddResult::Succ)
})
}
fn sync(&self) -> Option<Error> {
None
fn delete(&self, entry: &str, itempath: &Path) -> Result<(), Error> {
let item: Box<Item> = if itempath.is_file() {
Box::new(file_item::FileItem::new(itempath).map_err(Error::FileItemError)?)
} else {
Box::new(dir_item::DirItem::new(itempath).map_err(Error::DirItemError)?)
};

let c = get_or_run(&self.dockercli, &self.image_name)?;
let dstpath = Path::new("/data").join(entry).join(item.id());
self.dockercli
.remove_file(&c.id, &dstpath)
.map_err(|e| Error::ExecError(format!("{:?}", e)))
}

fn export_to_dir(&self, dir: &Path, entry: &str) -> Result<(), Error> {
let c = get_or_run(&self.dockercli, &self.image_name)?;
let srcpath = Path::new("/data").join(entry);
self.dockercli
.copy_out(&c.id, &srcpath, dir)
.map_err(Error::DockerError)
}

fn sync(&self) -> Result<(), Error> {
// TODO: check image exist, if not , pull from registry

// image existed, so push to registry
self.dockercli
.push(&self.image_name)
.map_err(Error::DockerError)
}
}

fn get_or_run(
cli: &dockerclient::DockerClient,
image: &str,
) -> Result<dockerclient::Container, Error> {
let cs = (cli.ps(false).map_err(Error::DockerError)?);
let cs = cli.ps(false).map_err(Error::DockerError)?;
for c in cs {
if c.image.split(":").collect::<Vec<&str>>()[0]
== image.split(":").collect::<Vec<&str>>()[0]
Expand All @@ -67,3 +161,29 @@ fn get_or_run(
cli.start(&c.id).map_err(Error::DockerError)?;
Ok(c)
}

fn ls(cli: &dockerclient::DockerClient, image: &str, dir: &Path) -> Result<Vec<String>, Error> {
let c = get_or_run(cli, image)?;
cli.exec(&c.id, &format!("ls {}", dir.display()))
.map_err(Error::DockerError)
.map(|(out, err)| {
(
String::from_utf8_lossy(&out).to_owned().to_string(),
String::from_utf8_lossy(&err).to_owned().to_string(),
)
})
.and_then(|(out, err)| {
if err != "" {
return Err(Error::ExecError(err));
}
if out.trim() == "" {
return Ok(vec![]);
}
let dirs: Vec<&str> = out.trim().split(" ").collect();
let mut r = vec![];
for dir in dirs {
r.push(dir.trim().to_owned().to_string());
}
Ok(r)
})
}
27 changes: 17 additions & 10 deletions db/src/file_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@ use std::io;
use std::io::{copy, Seek, SeekFrom};
use std::path::Path;

#[derive(Debug)]
pub enum Error {
BadPath,
BadPath(String),
IOError(io::Error),
}

pub struct FileItem<'a> {
path: &'a Path,
f: File,
id: String,
}

impl<'a> FileItem<'a> {
pub fn new(path: &'a Path) -> Result<Self, Error> {
if path.is_file() && path.exists() {
return Err(Error::BadPath);
if !path.is_file() || !path.exists() {
return Err(Error::BadPath(path.display().to_string()));
}
let f = File::open(path).map_err(Error::IOError)?;
Ok(FileItem { path, f })
let id = path
.file_name()
.unwrap()
.to_string_lossy()
.to_owned()
.to_string();
Ok(FileItem { path, f, id })
}
}

Expand All @@ -31,12 +39,11 @@ impl<'a> crate::Item for FileItem<'a> {
copy(&mut self.f, &mut hasher).unwrap();
hasher.result().to_vec()
}
fn id(&self) -> String {
fn id(&self) -> &str {
&self.id
}

fn srcpath(&self) -> &Path {
self.path
.file_name()
.unwrap()
.to_string_lossy()
.to_owned()
.to_string()
}
}
50 changes: 28 additions & 22 deletions db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,43 @@ extern crate sha2;
extern crate walkdir;

mod dir_item;
mod docker;
pub mod docker;
mod file_item;
pub trait Item {
/// Compare with other `Item`, true if same
fn compare(&mut self, other: &mut Item) -> bool {
self.hash() == other.hash()
}
/// Hash compute item's hash value
fn hash(&mut self) -> Vec<u8>;
/// id is Item's unqiue name
fn id(&self) -> String;
fn id(&self) -> &str;
/// path is item's host path
fn srcpath(&self) -> &std::path::Path;
}

/// compare_items compare 2 items, true if same
fn compare_items<T1: Item, T2: Item + ?Sized>(i1: &mut T1, i2: &mut T2) -> bool {
i1.hash() == i2.hash()
}

#[derive(Debug)]
pub enum AddResult {
ExistedItem(String),
Succ,
}

pub trait DB<E>
where
E: std::fmt::Debug + std::fmt::Display,
{
/// Catalog return catalog of db
fn catalog(&self) -> Result<Vec<String>, E>;
/// Add `item` to DB under `title`
fn add(&self, title: &str, item: &Item) -> Option<E>;
/// Delete item from DB, which is located by title and reference
fn delete(&self, title: &str, id: &str) -> Option<E>;
/// Sync local DB to remote DB
fn sync(&self) -> Option<E>;
}

#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
/// entries return catalog of db
fn entries(&self) -> Result<Vec<String>, E>;
/// items list items under `entry`
fn items(&self, entry: &str) -> Result<Vec<String>, E>;
/// add `item` to DB under `entry`
fn add(&self, entry: &str, itempath: &std::path::Path) -> Result<AddResult, E>;
/// delete item from DB, which is located by entry and reference
fn delete(&self, entry: &str, itempath: &std::path::Path) -> Result<(), E>;
/// export_to_dir export `entry` to `dir`
fn export_to_dir(&self, dir: &std::path::Path, entry: &str) -> Result<(), E>;
/// sync local DB to remote DB
/// or sync remote DB to local DB if localDB not exists
fn sync(&self) -> Result<(), E>;
}
Loading

0 comments on commit 168a14d

Please sign in to comment.