rvcs_lib/
branch.rs

1use crate::{error, ok, get_current_branch, in_repo};
2use std::{
3    env, fs,
4    fs::File,
5    io,
6    io::{Read, Write},
7    path::Path,
8};
9
10pub fn merge(branch: &str) -> io::Result<()> {
11    if !in_repo() {
12        return Err(error!("Current directory is not a rvcs repository."));
13    }
14
15    if !branch_exists(branch)? {
16        return Err(error!("Branch does not exist."));
17    }
18
19    let upcoming_full_path = &format!(".rvcs/commits/{}/", branch);
20    let upcoming_commits = fs::read_dir(upcoming_full_path)?
21        .collect::<Vec<_>>()
22        .into_iter()
23        .rev()
24        .map(|e| {
25            e.unwrap() /* TODO: Find a better method */
26                .path()
27                .to_str()
28                .unwrap()
29                .to_owned()
30                .replace(upcoming_full_path, "")
31        })
32        .collect::<Vec<_>>();
33
34    let current_full_path = &format!(".rvcs/commits/{}/", get_current_branch()?);
35    let current_commits = fs::read_dir(current_full_path)?
36        .collect::<Vec<_>>()
37        .into_iter()
38        .rev()
39        .map(|e| {
40            e.unwrap() /* TODO: Find a better method */
41                .path()
42                .to_str()
43                .unwrap()
44                .to_owned()
45                .replace(current_full_path, "")
46        })
47        .collect::<Vec<_>>();
48
49    let mut upcoming_since_sep = vec![];
50
51    let to_iter = if upcoming_commits.len() > current_commits.len() {
52        current_commits.len()
53    } else {
54        upcoming_commits.len()
55    };
56
57    for i in 0..to_iter {
58        if upcoming_commits[i] != current_commits[i] {
59            upcoming_since_sep = upcoming_commits[i..].to_vec();
60            break;
61        }
62    }
63
64    for commit in upcoming_since_sep {
65        let upcoming_commit = &format!(".rvcs/commits/{}/{}", branch, commit);
66        let upcoming_in_current = &format!(".rvcs/commits/{}/{}", get_current_branch()?, commit);
67
68        if Path::new(upcoming_commit).is_dir() {
69            copy_dir(upcoming_commit, upcoming_in_current)?;
70        } else {
71            fs::copy(upcoming_commit, upcoming_in_current)?;
72        }
73    }
74
75    println!("{} Sucessfully merged branch `{}` into `{}`.", ok(), branch, get_current_branch()?);
76
77    Ok(())
78}
79
80fn readr(dir: &str) -> io::Result<Vec<String>> {
81    let mut elements = vec![];
82
83    for entry in fs::read_dir(dir)? {
84        let path = entry?.path();
85
86        if path.is_dir() {
87            elements.push(path.to_str().unwrap().to_string());
88            elements.extend(readr(path.to_str().unwrap())?);
89        } else {
90            elements.push(path.to_str().unwrap().to_string());
91        }
92    }
93    Ok(elements)
94}
95
96fn copy_dir(from: &str, to: &str) -> io::Result<()> {
97    let current = env::current_dir()?;
98
99    env::set_current_dir(from)?;
100    let content = readr(".")?;
101
102    env::set_current_dir(&current)?;
103    fs::create_dir_all(to)?;
104    env::set_current_dir(to)?;
105
106    for element in content {
107        let stringy = format!("{}/{}/{}", &current.to_str().unwrap(), from, &element);
108        let path = Path::new(&stringy);
109        if path.is_dir() {
110            fs::create_dir_all(&element)?;
111        } else {
112            let mut buffer = vec![];
113            File::open(path)?.read_to_end(&mut buffer)?;
114            File::create(&element)?.write_all(&buffer)?;
115        }
116    }
117
118    env::set_current_dir(current)
119}
120
121pub fn create_branch(name: &str) -> io::Result<()> {
122    if !in_repo() {
123        return Err(error!("Current directory is not a rvcs repository."));
124    }
125
126    if branch_exists(name)? {
127        return Err(error!("Branch already exists."));
128    }
129    let current = &format!(".rvcs/commits/{}/", get_current_branch()?);
130    let to_create = &format!(".rvcs/commits/{}/", name);
131
132    copy_dir(&current, &to_create)?;
133    println!("{} Sucessfully created branch `{}`.", ok(), name);
134    Ok(())
135}
136
137pub fn goto_branch(name: &str) -> io::Result<()> {
138    if !in_repo() {
139        return Err(error!("Current directory is not a rvcs repository."));
140    }
141
142    if !branch_exists(name)? {
143        return Err(error!("Branch does not exist."));
144    }
145    File::create(".rvcs/CURRENT_BRANCH")?.write_all(name.as_bytes())?;
146    println!("{} Sucessfully switched to branch `{}`.", ok(), name);
147    Ok(())
148}
149
150pub fn delete_branch(name: &str) -> io::Result<()> {
151    if !in_repo() {
152        return Err(error!("Current directory is not a rvcs repository."));
153    }
154
155    if !branch_exists(name)? {
156        return Err(error!("Branch does not exist."));
157    }
158
159    fs::remove_dir_all(&format!(".rvcs/commits/{}", name))?;
160
161    println!("{} Sucessfully deleted branch `{}`.", ok(), name);
162
163    Ok(())
164}
165
166fn branch_exists(name: &str) -> io::Result<bool> {
167    for entry in fs::read_dir(".rvcs/commits/")? {
168        let path = entry?.path();
169
170        if path.file_name().unwrap().to_str().unwrap() == name {
171            return Ok(true);
172        }
173    }
174    Ok(false)
175}
176
177pub fn list_branches() -> io::Result<()> {
178    if !in_repo() {
179        return Err(error!("Current directory is not a rvcs repository."));
180    }
181
182    let current = fs::read_to_string(".rvcs/CURRENT_BRANCH")?;
183
184    for entry in fs::read_dir(".rvcs/commits/")? {
185        let path = entry?.path();
186
187        if path.file_name().unwrap().to_str().unwrap() == current {
188            println!("\x1b[0;32m* {}\x1b[0m", current);
189        } else {
190            println!("  {}", path.file_name().unwrap().to_str().unwrap());
191        }
192    }
193    Ok(())
194}