universe

Universe
git clone https://git.dasho.dev/universe.git
Log | Files | Refs | Submodules | README

commit 77a23918340223e133b32e48b73bc1b593772029
parent 99b8905b3281ad9cc4fec347dd771c0ea11f6937
Author: Dasho <git@dasho.dev>
Date:   Thu, 20 Mar 2025 04:48:55 +0000

[repo] ➕ Add unishell for git interactions

Added the unishell via src/main.rs

Diffstat:
A.gitignore | 1+
ACargo.lock | 296+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACargo.toml | 7+++++++
Asrc/main.rs | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 566 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock @@ -0,0 +1,296 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys", +] + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" + +[[package]] +name = "once_cell" +version = "1.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rustix" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unishell" +version = "0.0.1" +dependencies = [ + "dialoguer", +] + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "unishell" +version = "0.0.1" +edition = "2024" + +[dependencies] +dialoguer = "0.11.0" diff --git a/src/main.rs b/src/main.rs @@ -0,0 +1,262 @@ +use dialoguer::{theme::ColorfulTheme, Select, Input}; +use std::os::windows::process::ExitStatusExt; +use std::process::Command; +use std::process::Output; + +/// Main entry point for UniShell - Git Operations Terminal +fn main() { + loop { + println!("Welcome to UniShell - Git Operations Terminal"); + + let options = vec![ + "Status", + "Add Files", + "Commit Changes", + "Push Changes", + "Pull Changes", + "Switch Branch", + "Initialize Repository", + "Clone Repository", + "Pull Specific Folder", + "Include Submodules", + "Remove Folder", + "Restore Folder", + "Exit", + ]; + + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Choose a Git operation") + .items(&options) + .default(0) + .interact() + .unwrap(); + + match selection { + 0 => git_status(), + 1 => git_add(), + 2 => git_commit(), + 3 => git_push(), + 4 => git_pull(), + 5 => git_switch_branch(), + 6 => git_init(), + 7 => git_clone(), + 8 => git_pull_folder(), + 9 => git_include_submodules(), + 10 => git_remove_folder(), + 11 => git_restore_folder(), + 12 => { + println!("Exiting UniShell. Goodbye!"); + break; + } + _ => unreachable!(), + } + } +} + +/// Runs `git status` and prints the output +fn git_status() { + println!("Running `git status`..."); + let output = Command::new("git") + .arg("status") + .output() + .expect("Failed to execute git status"); + println!("{}", String::from_utf8_lossy(&output.stdout)); +} + +/// Adds files to the staging area +fn git_add() { + let files: String = Input::new() + .with_prompt("Enter files to add (use '.' to add all)") + .interact_text() + .unwrap(); + + println!("Running `git add {}`...", files); + Command::new("git") + .arg("add") + .arg(files) + .status() + .expect("Failed to execute git add"); +} + +/// Commits changes with a message +fn git_commit() { + let message: String = Input::new() + .with_prompt("Enter commit message") + .interact_text() + .unwrap(); + + println!("Running `git commit -m \"{}\"`...", message); + Command::new("git") + .arg("commit") + .arg("-m") + .arg(message) + .status() + .expect("Failed to execute git commit"); +} + +/// Pushes changes to the remote repository +fn git_push() { + println!("Running `git push`..."); + Command::new("git") + .arg("push") + .status() + .expect("Failed to execute git push"); +} + +/// Pulls changes from the remote repository +fn git_pull() { + println!("Running `git pull`..."); + Command::new("git") + .arg("pull") + .status() + .expect("Failed to execute git pull"); +} + +/// Switches to a specified branch +fn git_switch_branch() { + let branch: String = Input::new() + .with_prompt("Enter branch name to switch to") + .interact_text() + .unwrap(); + + println!("Running `git checkout {}`...", branch); + Command::new("git") + .arg("checkout") + .arg(branch) + .status() + .expect("Failed to execute git checkout"); +} + +/// Initializes a new Git repository +fn git_init() { + println!("Running `git init`..."); + Command::new("git") + .arg("init") + .status() + .expect("Failed to execute git init"); +} + +/// Clones a repository from a given URL +fn git_clone() { + let repo_url: String = Input::new() + .with_prompt("Enter repository URL to clone") + .interact_text() + .unwrap(); + + println!("Running `git clone {}`...", repo_url); + Command::new("git") + .arg("clone") + .arg(repo_url) + .status() + .expect("Failed to execute git clone"); +} + +/// Pulls a specific folder using sparse-checkout +fn git_pull_folder() { + let folder: String = Input::new() + .with_prompt("Enter folder path to pull") + .interact_text() + .unwrap(); + + println!("Running `git sparse-checkout set {}` and pulling...", folder); + Command::new("git") + .arg("sparse-checkout") + .arg("set") + .arg(&folder) + .status() + .expect("Failed to set sparse-checkout folder"); + + Command::new("git") + .arg("pull") + .status() + .expect("Failed to pull specific folder"); +} + +/// Includes submodules in the repository +fn git_include_submodules() { + println!("Running `git submodule update --init --recursive`..."); + Command::new("git") + .arg("submodule") + .arg("update") + .arg("--init") + .arg("--recursive") + .status() + .expect("Failed to include submodules"); +} + +/// Removes a folder from the repository +fn git_remove_folder() { + let folder: String = Input::new() + .with_prompt("Enter folder path to remove") + .interact_text() + .unwrap(); + + println!("Removing folder `{}`...", folder); + Command::new("rm") + .arg("-rf") + .arg(&folder) + .status() + .expect("Failed to remove folder"); +} + +/// Restores a folder to its previous state +fn git_restore_folder() { + let folder: String = Input::new() + .with_prompt("Enter folder path to restore") + .interact_text() + .unwrap(); + + println!("Restoring folder `{}`...", folder); + Command::new("git") + .arg("checkout") + .arg("--") + .arg(&folder) + .status() + .expect("Failed to restore folder"); +} + +#[cfg(test)] +mod tests { + use super::*; + + fn mock_command_output(stdout: &str) -> Output { + Output { + status: std::process::ExitStatus::from_raw(0), + stdout: stdout.as_bytes().to_vec(), + stderr: Vec::new(), + } + } + + #[test] + fn test_git_status() { + let output = mock_command_output("On branch main\nYour branch is up to date."); + assert_eq!( + String::from_utf8_lossy(&output.stdout), + "On branch main\nYour branch is up to date." + ); + } + + #[test] + fn test_git_add() { + // Mocking user input and command execution + let files = "test_file.txt"; + assert_eq!(files, "test_file.txt"); + } + + #[test] + fn test_git_commit() { + // Mocking user input and command execution + let message = "Initial commit"; + assert_eq!(message, "Initial commit"); + } + + #[test] + fn test_git_push() { + // Mocking command execution + let output = mock_command_output("Everything up-to-date"); + assert_eq!( + String::from_utf8_lossy(&output.stdout), + "Everything up-to-date" + ); + } +}