Files
nixide/server/podman/src/lib.rs
2020-07-01 21:19:36 +02:00

256 lines
7.9 KiB
Rust

#![feature(proc_macro_hygiene, decl_macro)]
extern crate rocket;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate nixideserver_lib;
extern crate serde_json;
use nixideserver_lib::*;
use rocket::http::Status;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
// podman create --name test -p 3000:3000 -v $PWD:/nixide -w /nixide docker.io/nixos/nix nix-shell --pure start-ide.nix --run run_ide.sh
#[derive(Serialize, Deserialize, Clone)]
pub enum PodmanState {
Unkown,
FetchingSource,
StartingContainer,
RunningContainer,
StoppingContainer,
StoppedContainer,
DeletingContainer,
DeletingSources,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct PodmanContainer {
ide_id: String,
state: PodmanState,
ide_state: IdeState,
ide_param: NixIdeServerParam,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct PodmanContainerList {
container: Vec<PodmanContainer>,
}
pub struct PodmanEngine {
working_folder: PathBuf,
list: PodmanContainerList,
}
impl PodmanEngine {
pub fn new(working_folder: PathBuf) -> PodmanEngineTraitImpl {
PodmanEngineTraitImpl {
working_folder
}
}
fn _new(working_folder: PathBuf) -> Self {
let list_path = format!("{}/.podman_containers", &working_folder.display());
let list = match read_from_list_file(&list_path) {
Ok(p) => p,
_ => PodmanContainerList {
container: Vec::new(),
},
};
Self {
working_folder,
list,
}
}
pub fn save(&self) -> Result<(), std::io::Error> {
let json_string = serde_json::to_string_pretty(&self.list).unwrap(); // .map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidData))?;
fs::write(
&format!("{}/.podman_containers", &self.working_folder.display()),
json_string,
)
}
pub fn reload(trait_impl : &PodmanEngineTraitImpl) -> Result<Self, std::io::Error> {
Ok(
Self::_new(trait_impl.working_folder.clone())
)
}
}
#[derive(Serialize, Deserialize)]
struct PodmanIdeStatus {
ide_state: IdeState,
}
pub struct PodmanEngineTraitImpl {
working_folder: PathBuf
}
impl NixIdeManageServiceEngine for PodmanEngineTraitImpl {
fn fetch_current_ide_state(&self, ide_id: &str) -> Result<IdeState, Status> {
let eng = PodmanEngine::reload(self)
.map_err(|_| Status::new(500, "internal error : reload engine"))?;
match eng.list.container.iter().find(|i| i.ide_id.eq(ide_id)) {
Some(i) => Ok(i.ide_state.clone()),
_ => Err(Status::NotFound),
}
}
fn start_open(&self, ide_id: &str, param: &OpenGitParam) -> Result<IdeState, Status> {
let mut eng = PodmanEngine::reload(self)
.map_err(|_| Status::new(500, "internal error : reload engine"))?;
match eng.list.container.iter().find(|i| i.ide_id.eq(ide_id)) {
Some(i) => Ok(i.ide_state.clone()),
_ => {
let ide_folder = create_ide_folder_path(&self.working_folder, ide_id);
fs::create_dir_all(&ide_folder)
.map_err(|_| Status::new(500, "internal error : can't create ide folder"))?;
let listen_port = eng
.list
.container
.iter()
.max_by_key(|i| i.ide_param.listen_port)
.and_then(|i| Some(i.ide_param.listen_port + 1))
.or(Some(3000))
.unwrap();
let ide_param = NixIdeServerParam {
listen_address: default_listen_address(),
listen_port,
app_folder: default_app_folder(),
project_folder: default_project_folder(),
working_folder: default_working_folder(),
};
let container = PodmanContainer {
ide_id: ide_id.to_owned(),
ide_state: IdeState::OPENING,
state: PodmanState::FetchingSource,
ide_param,
};
eng.list.container.push(container);
eng.save()
.map_err(|_| Status::new(500, "internal error: can't save curent state"))?;
fetch_sources(&format!("{}/repo", ide_folder), param)
.map_err(|_| Status::new(500, "internal error"))?;
match eng.list.container.iter_mut().find(|i| i.ide_id.eq(ide_id)) {
Some(i) => {
i.state = PodmanState::StartingContainer;
eng.save().map_err(|_| {
Status::new(500, "internal error: can't save curent state")
})?;
}
_ => {}
};
Ok(IdeState::OPENING)
}
}
// println!("foo {:x}", hash);
// let out = Command::new("podman")
// .arg("create")
// .arg("--name")
// .arg(format!("{:x}", hash))
// .arg("-p")
// .arg("3000:3000")
// .arg("docker.io/nixos/nix")
// // .arg(format!("git clone {}", param.clone_url))
// .output()
// .expect("create container");
// String::from_utf8(out.stderr).unwrap()
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct NixIdeServerParam {
#[serde(default = "default_listen_address")]
listen_address: String,
#[serde(default = "default_listen_port")]
listen_port: u32,
#[serde(default = "default_app_folder")]
app_folder: String,
#[serde(default = "default_project_folder")]
project_folder: String,
#[serde(default = "default_working_folder")]
working_folder: String,
}
impl Default for NixIdeServerParam {
fn default() -> Self {
Self {
listen_address: default_listen_address(),
listen_port: default_listen_port(),
app_folder: default_app_folder(),
project_folder: default_project_folder(),
working_folder: default_working_folder(),
}
}
}
fn default_listen_address() -> String {
"0.0.0.0".to_owned()
}
fn default_listen_port() -> u32 {
3000
}
fn default_app_folder() -> String {
"_theiaideApp".to_owned()
}
fn default_project_folder() -> String {
"$PWD".to_owned()
}
fn default_working_folder() -> String {
"$PWD".to_owned()
}
fn create_ide_folder_path(working_folder_path: &Path, ide_id: &str) -> String {
format!("{}/{}", working_folder_path.display(), ide_id)
}
fn read_from_list_file(path: &str) -> Result<PodmanContainerList, std::io::Error> {
match fs::read_to_string(path) {
Ok(json_string) => serde_json::from_str::<PodmanContainerList>(&json_string)
.map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidData)),
Err(e) => Err(e),
}
}
fn fetch_sources(repo_path: &str, param: &OpenGitParam) -> Result<(), std::io::Error> {
Command::new("git")
.arg("clone")
.arg("-n")
.arg(&param.clone_url)
.arg(repo_path)
.output()?;
Command::new("git")
.arg("-C")
.arg(repo_path)
.arg("checkout")
.arg(&param.ref_name)
.output()
.map(|_| ())
}
#[test]
fn test_fetch_sources() {
let now = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap();
let temp_dir = std::env::temp_dir();
let repo_path = format!("{}/{}", temp_dir.display(), now.as_secs());
let git_param = OpenGitParam {
clone_url: "https://github.com/jmesmon/rust-hello-world.git".to_owned(),
inquirer: "stubbfel".to_owned(),
ref_name: "master".to_owned(),
};
assert_eq!(fetch_sources(&repo_path, &git_param).unwrap(), ());
}