diff --git a/libra/src/command/log.rs b/libra/src/command/log.rs index 9ad4ffc44..26cd6ea62 100644 --- a/libra/src/command/log.rs +++ b/libra/src/command/log.rs @@ -1,5 +1,5 @@ use std::cmp::min; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use crate::command::load_object; use crate::internal::branch::Branch; @@ -79,6 +79,8 @@ pub async fn execute(args: LogArgs) { // default sort with signature time reachable_commits.sort_by(|a, b| b.committer.timestamp.cmp(&a.committer.timestamp)); + let branch_commits = create_branch_commits_map().await; + let max_output_number = min(args.number.unwrap_or(usize::MAX), reachable_commits.len()); let mut output_number = 0; for commit in reachable_commits { @@ -86,25 +88,65 @@ pub async fn execute(args: LogArgs) { break; } output_number += 1; + + let branches = branch_commits.get(&commit.id).cloned().unwrap_or_default(); + let message = if args.oneline { // Oneline format: let short_hash = &commit.id.to_string()[..7]; let (msg, _) = parse_commit_msg(&commit.message); - format!("{} {}", short_hash.yellow(), msg) + if !branches.is_empty() { + let branch_info = format!(" ({})", branches.join(", ")); + format!( + "{} {}{}", + short_hash.yellow().bold(), + msg, + branch_info.green() + ) + } else { + format!("{} {}", short_hash.yellow(), msg) + } } else { // Default detailed format - let mut message = format!("{} {}", "commit".yellow(), &commit.id.to_string().yellow()); + let mut message = format!( + "{} {}", + "commit".yellow(), + if !branches.is_empty() { + commit.id.to_string().yellow().bold() + } else { + commit.id.to_string().yellow() + } + ); - // TODO other branch's head should shown branch name + // Show HEAD and branch info if output_number == 1 { - message = format!("{} {}{}", message, "(".yellow(), "HEAD".blue()); - if let Head::Branch(name) = head.to_owned() { - // message += &"-> ".blue(); - // message += &head.name.as_ref().unwrap().green(); - message = format!("{}{}{}", message, " -> ".blue(), name.green()); - } - message = format!("{}{}", message, ")".yellow()); + // For the first commit (HEAD), show HEAD info and all branches + let mut refs = vec![]; + let current_branch = if let Head::Branch(name) = head.to_owned() { + refs.push(format!("{} -> {}", "HEAD".blue(), name.green())); + Some(name) + } else { + refs.push("HEAD".blue().to_string()); + None + }; + + // Add other branches pointing to this commit (excluding current branch) + let other_branches: Vec = branches + .iter() + .filter(|&b| current_branch.as_ref() != Some(b)) + .map(|b| b.green().to_string()) + .collect(); + + refs.extend(other_branches); + + let ref_info = format!(" ({})", refs.join(", ")); + message = format!("{message}{ref_info}"); + } else if !branches.is_empty() { + // Show branch info for other commits that are branch heads + let branch_info = format!(" ({})", branches.join(", ")); + message = format!("{}{}", message, branch_info.green()); } + message.push_str(&format!("\nAuthor: {}", commit.author)); let (msg, _) = parse_commit_msg(&commit.message); message.push_str(&format!("\n{msg}\n")); @@ -130,5 +172,25 @@ pub async fn execute(args: LogArgs) { } } +/// Create a map of commit hashes to branch names +async fn create_branch_commits_map() -> HashMap> { + let all_branches = Branch::list_branches(None).await; + let mut commit_to_branches: HashMap> = HashMap::new(); + + for branch in all_branches { + let branch_name = match &branch.remote { + Some(remote) => format!("{}/{}", remote, branch.name), + None => branch.name, + }; + + commit_to_branches + .entry(branch.commit) + .or_default() + .push(branch_name); + } + + commit_to_branches +} + #[cfg(test)] mod tests {} diff --git a/libra/src/command/switch.rs b/libra/src/command/switch.rs index 3974819a9..8addf6624 100644 --- a/libra/src/command/switch.rs +++ b/libra/src/command/switch.rs @@ -29,14 +29,7 @@ pub struct SwitchArgs { pub async fn execute(args: SwitchArgs) { // check status - let unstaged = status::changes_to_be_staged(); - if !unstaged.deleted.is_empty() || !unstaged.modified.is_empty() { - status::execute().await; - eprintln!("fatal: uncommitted changes, can't switch branch"); - return; - } else if !status::changes_to_be_committed().await.is_empty() { - status::execute().await; - eprintln!("fatal: unstaged changes, can't switch branch"); + if check_status().await { return; } @@ -66,11 +59,11 @@ pub async fn check_status() -> bool { let unstaged: status::Changes = status::changes_to_be_staged(); if !unstaged.deleted.is_empty() || !unstaged.modified.is_empty() { status::execute().await; - eprintln!("fatal: uncommitted changes, can't switch branch"); + eprintln!("fatal: unstaged changes, can't switch branch"); true } else if !status::changes_to_be_committed().await.is_empty() { status::execute().await; - eprintln!("fatal: unstaged changes, can't switch branch"); + eprintln!("fatal: uncommitted changes, can't switch branch"); true } else { false diff --git a/mercury/src/hash.rs b/mercury/src/hash.rs index 76867b3f5..8543077ec 100644 --- a/mercury/src/hash.rs +++ b/mercury/src/hash.rs @@ -5,7 +5,7 @@ use std::{fmt::Display, io}; -use bincode::{Encode, Decode}; +use bincode::{Decode, Encode}; use colored::Colorize; use serde::{Deserialize, Serialize}; use sha1::Digest; @@ -28,8 +28,19 @@ use crate::internal::object::types::ObjectType; /// understandable. - Nov 26, 2023 (by @genedna) /// #[derive( - Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Deserialize, Serialize, - Encode, Decode + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Default, + Deserialize, + Serialize, + Encode, + Decode, )] pub struct SHA1(pub [u8; 20]); diff --git a/mercury/src/internal/object/blob.rs b/mercury/src/internal/object/blob.rs index f894d0573..c03bdd06b 100644 --- a/mercury/src/internal/object/blob.rs +++ b/mercury/src/internal/object/blob.rs @@ -114,5 +114,4 @@ mod tests { "5dd01c177f5d7d1be5346a5bc18a569a7410c2ef" ); } - } diff --git a/mercury/src/internal/object/commit.rs b/mercury/src/internal/object/commit.rs index 82653013a..2f88ff0a1 100644 --- a/mercury/src/internal/object/commit.rs +++ b/mercury/src/internal/object/commit.rs @@ -156,7 +156,7 @@ impl ObjectTrait for Commit { .as_str(), ) .unwrap(); - let binding = commit[tree_end + 1..].to_vec(); // Move past the tree id + let binding = commit[tree_end + 1..].to_vec(); // Move past the tree id commit = &binding; // Find the parent commit ids and remove them from the data @@ -184,8 +184,8 @@ impl ObjectTrait for Commit { // Find the author and committer and remove them from the data // 0x0a is the newline character let author = - Signature::from_data(commit[..commit.find_byte(0x0a).unwrap()].to_vec()).unwrap(); - + Signature::from_data(commit[..commit.find_byte(0x0a).unwrap()].to_vec()).unwrap(); + let binding = commit[commit.find_byte(0x0a).unwrap() + 1..].to_vec(); commit = &binding; let committer = diff --git a/mercury/src/internal/object/signature.rs b/mercury/src/internal/object/signature.rs index 28f5b766c..4542f2c29 100644 --- a/mercury/src/internal/object/signature.rs +++ b/mercury/src/internal/object/signature.rs @@ -76,7 +76,7 @@ impl SignatureType { } } -#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize,Decode,Encode)] +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Decode, Encode)] pub struct Signature { pub signature_type: SignatureType, pub name: String, diff --git a/mercury/src/internal/object/tag.rs b/mercury/src/internal/object/tag.rs index fa83cb0ad..33e4b6e54 100644 --- a/mercury/src/internal/object/tag.rs +++ b/mercury/src/internal/object/tag.rs @@ -124,7 +124,8 @@ impl ObjectTrait for Tag { let tagger = Signature::from_data(tagger_data).unwrap(); data = &data[data.find_byte(0x0a).unwrap() + 1..]; - let message = unsafe { // There may be non-UTF-8 characters, so we use `to_str_unchecked` for conversion. + let message = unsafe { + // There may be non-UTF-8 characters, so we use `to_str_unchecked` for conversion. data[data.find_byte(0x0a).unwrap()..] .to_vec() .to_str_unchecked() diff --git a/mercury/src/internal/object/tree.rs b/mercury/src/internal/object/tree.rs index 195908019..b65200c4a 100644 --- a/mercury/src/internal/object/tree.rs +++ b/mercury/src/internal/object/tree.rs @@ -18,7 +18,7 @@ use crate::errors::GitError; use crate::hash::SHA1; use crate::internal::object::ObjectTrait; use crate::internal::object::ObjectType; -use bincode::{Encode, Decode}; +use bincode::{Decode, Encode}; use colored::Colorize; use encoding_rs::GBK; use serde::Deserialize; diff --git a/orion/src/api.rs b/orion/src/api.rs index 77831335e..7ec4683aa 100644 --- a/orion/src/api.rs +++ b/orion/src/api.rs @@ -12,7 +12,7 @@ pub struct BuildRequest { pub target: String, pub args: Option>, pub mr: String, // merge request id - // pub webhook: Option, // post + // pub webhook: Option, // post } #[derive(Debug, Serialize)] diff --git a/orion/src/buck_controller.rs b/orion/src/buck_controller.rs index abb770473..a3d02dfe5 100644 --- a/orion/src/buck_controller.rs +++ b/orion/src/buck_controller.rs @@ -10,7 +10,6 @@ use tokio::sync::mpsc::UnboundedSender; static PROJECT_ROOT: Lazy = Lazy::new(|| std::env::var("BUCK_PROJECT_ROOT").expect("BUCK_PROJECT_ROOT must be set")); - /// Sends a filesystem mount request to the specified API endpoint /// Parameters: /// - repo: Repository path to mount @@ -19,7 +18,7 @@ static PROJECT_ROOT: Lazy = pub async fn mount_fs(repo: &str, mr: &str) -> Result { // Create HTTP client let client = reqwest::Client::new(); - + // Construct JSON request payload let payload = json!({ "path": repo, @@ -36,11 +35,11 @@ pub async fn mount_fs(repo: &str, mr: &str) -> Result { // Print status code println!("Mount request status: {}", res.status()); - + // Get and return response body let body = res.text().await?; println!("Mount response body: {body}"); - + Ok(body) } @@ -52,7 +51,6 @@ pub async fn build( mr: String, sender: UnboundedSender, ) -> io::Result { - tracing::info!("Building {} in repo {} with target {}", id, repo, target); // Prepare the command to run // Note: `args` is a list of additional arguments to pass to the `buck diff --git a/orion/src/ws.rs b/orion/src/ws.rs index e4ce1181b..966affcb3 100644 --- a/orion/src/ws.rs +++ b/orion/src/ws.rs @@ -39,10 +39,12 @@ pub enum WSMessage { const MAX_RETRIES: u32 = 3; -/// send message and retry -async fn send_with_retry(sender: &mut (impl SinkExt + Unpin), msg: &WSMessage) -> Result<(), String> { - let msg_str = serde_json::to_string(msg) - .map_err(|e| format!("seriaz fail: {e}"))?; +/// send message and retry +async fn send_with_retry( + sender: &mut (impl SinkExt + Unpin), + msg: &WSMessage, +) -> Result<(), String> { + let msg_str = serde_json::to_string(msg).map_err(|e| format!("seriaz fail: {e}"))?; let ws_msg = Message::Text(Utf8Bytes::from(msg_str)); for attempt in 0..=MAX_RETRIES { @@ -121,7 +123,12 @@ async fn process_message(msg: Message) -> ControlFlow<(), ()> { println!(">>> got task: id:{id}, repo:{repo}, target:{target}, args:{args:?}, mr:{mr}"); let Json(res) = buck_build( id.parse().unwrap(), - BuildRequest { repo, target, args, mr }, + BuildRequest { + repo, + target, + args, + mr, + }, SENDER.get().unwrap().clone(), ) .await; diff --git a/scorpio/config.toml b/scorpio/config.toml index c52920c22..2f0a0a515 100644 --- a/scorpio/config.toml +++ b/scorpio/config.toml @@ -1 +1 @@ -works = [] \ No newline at end of file +works = [] diff --git a/scorpio/scorpio.toml b/scorpio/scorpio.toml index 340a02c7d..3bf61a142 100644 --- a/scorpio/scorpio.toml +++ b/scorpio/scorpio.toml @@ -1,10 +1,10 @@ -lfs_url = "http://localhost:8000" +lfs_url = "http://git.gitmega.com" store_path = "/tmp/megadir/store" config_file = "config.toml" git_author = "MEGA" git_email = "admin@mega.org" workspace = "/tmp/megadir/mount" -base_url = "http://localhost:8000" +base_url = "http://git.gitmega.com" dicfuse_readable = "true" load_dir_depth = "3" fetch_file_thread = "10" \ No newline at end of file diff --git a/scorpio/src/dicfuse/store.rs b/scorpio/src/dicfuse/store.rs index 2cb418f6c..8d7be4ce5 100644 --- a/scorpio/src/dicfuse/store.rs +++ b/scorpio/src/dicfuse/store.rs @@ -234,9 +234,12 @@ async fn fetch_dir(path: &str) -> Result { let response = match client.get(&url).send().await { Ok(resp) => resp, - Err(_) => { - return Err(DictionaryError { - message: "Failed to fetch tree".to_string(), + Err(e) => { + eprintln!("Failed to fetch tree: {e}"); + return Ok(ApiResponseExt { + _req_result: false, + data: Vec::new(), + _err_message: format!("Failed to fetch tree: {e}"), }); } }; @@ -244,15 +247,27 @@ async fn fetch_dir(path: &str) -> Result { let tree_info: TreeInfoResponse = match response.json().await { Ok(info) => info, Err(e) => { - return Err(DictionaryError { - message: format!("Failed to parse commit info: {e}"), + eprintln!("Failed to parse commit info: {e}"); + return Ok(ApiResponseExt { + _req_result: false, + data: Vec::new(), + _err_message: format!("Failed to parse commit info: {e}"), }); } }; if !tree_info.req_result { - return Err(DictionaryError { - message: tree_info.err_message, + eprintln!( + "server response fetch dir error: {:?}", + tree_info.err_message + ); + return Ok(ApiResponseExt { + _req_result: false, + data: Vec::new(), + _err_message: format!( + "server response fetch dir error: {:?}", + tree_info.err_message + ), }); } diff --git a/scorpio/src/dicfuse/tree_store.rs b/scorpio/src/dicfuse/tree_store.rs index 07dbcaa4d..1b4827c61 100644 --- a/scorpio/src/dicfuse/tree_store.rs +++ b/scorpio/src/dicfuse/tree_store.rs @@ -15,7 +15,7 @@ pub struct TreeStorage { db: Db, } -#[derive(Serialize, Deserialize, Clone,Encode,Decode)] +#[derive(Serialize, Deserialize, Clone, Encode, Decode)] pub struct StorageItem { inode: u64, parent: u64, @@ -86,7 +86,7 @@ impl TreeStorage { self.db .insert( inode.to_be_bytes(), - bincode::encode_to_vec(&storage_item,config).map_err(Error::other)?, + bincode::encode_to_vec(&storage_item, config).map_err(Error::other)?, ) .map_err(Error::other)?; @@ -98,7 +98,7 @@ impl TreeStorage { self.db .insert( parent.to_be_bytes(), - bincode::encode_to_vec(&parent_item,config).map_err(Error::other)?, + bincode::encode_to_vec(&parent_item, config).map_err(Error::other)?, ) .map_err(Error::other)?; } @@ -128,7 +128,7 @@ impl TreeStorage { self.db .insert( storage_item.parent.to_be_bytes(), - bincode::encode_to_vec(&parent_item, config).map_err(Error::other)?, + bincode::encode_to_vec(&parent_item, config).map_err(Error::other)?, ) .map_err(Error::other)?; } @@ -168,7 +168,7 @@ impl TreeStorage { match self.db.get(inode.to_be_bytes())? { Some(value) => { let config = bincode::config::standard(); - let (item ,_) = bincode::decode_from_slice(&value,config).map_err(Error::other)?; + let (item, _) = bincode::decode_from_slice(&value, config).map_err(Error::other)?; Ok(item) } None => Err(Error::new(ErrorKind::NotFound, "Item not found")), @@ -193,7 +193,7 @@ impl TreeStorage { self.db .insert( inode.to_be_bytes(), - bincode::encode_to_vec(&item,config).map_err(Error::other)?, + bincode::encode_to_vec(&item, config).map_err(Error::other)?, ) .map_err(Error::other)?; Ok(()) diff --git a/scorpio/src/manager/commit.rs b/scorpio/src/manager/commit.rs index 6211d1f9d..76c122940 100644 --- a/scorpio/src/manager/commit.rs +++ b/scorpio/src/manager/commit.rs @@ -278,7 +278,7 @@ pub fn commit_core( for (path, tree) in hashmap.iter() { batch.insert( path.to_string_lossy().into_owned().as_str(), - bincode::encode_to_vec(tree,config).unwrap(), + bincode::encode_to_vec(tree, config).unwrap(), ); } new_tree_db.apply_batch(batch)?; diff --git a/scorpio/src/manager/diff.rs b/scorpio/src/manager/diff.rs index 35fee8fc7..36af90657 100644 --- a/scorpio/src/manager/diff.rs +++ b/scorpio/src/manager/diff.rs @@ -181,10 +181,10 @@ pub fn change( } else { println!("change: changed file {}", item.name); let content = std::fs::read(&path).unwrap(); - + let b = Blob::from_content_bytes(content); item.id = b.id; // change file hash . - blobs.push(b); + blobs.push(b); } new = false; break; diff --git a/scorpio/src/manager/fetch.rs b/scorpio/src/manager/fetch.rs index f17d090b7..51851f930 100644 --- a/scorpio/src/manager/fetch.rs +++ b/scorpio/src/manager/fetch.rs @@ -351,7 +351,6 @@ pub async fn download_mr_files( Ok(()) } - #[allow(async_fn_in_trait)] pub trait CheckHash { async fn check(&mut self); @@ -363,7 +362,6 @@ pub trait CheckHash { ) -> WorkDir; } - impl CheckHash for ScorpioManager { async fn check(&mut self) { let mut handlers = Vec::new(); diff --git a/scorpio/src/manager/mr.rs b/scorpio/src/manager/mr.rs index ceed7660c..8e12a5b1a 100644 --- a/scorpio/src/manager/mr.rs +++ b/scorpio/src/manager/mr.rs @@ -38,7 +38,6 @@ pub async fn build_mr_layer( // Collect all files that need to be downloaded let mut download_files = Vec::new(); - for file in files_list.data { let relative_path = file.path.strip_prefix('/').unwrap_or(&file.path); let file_path = mr_path.join(relative_path); diff --git a/scorpio/src/manager/store.rs b/scorpio/src/manager/store.rs index 24d2e79c5..2e9016712 100644 --- a/scorpio/src/manager/store.rs +++ b/scorpio/src/manager/store.rs @@ -18,7 +18,7 @@ pub trait TreeStore { impl TreeStore for sled::Db { fn insert_tree(&self, path: PathBuf, tree: Tree) { let config = bincode::config::standard(); - let value = bincode::encode_to_vec(&tree,config).unwrap(); + let value = bincode::encode_to_vec(&tree, config).unwrap(); let key = path.to_str().unwrap(); self.insert(key, value).unwrap(); } @@ -28,8 +28,9 @@ impl TreeStore for sled::Db { match self.get(key)? { Some(encoded_value) => { let config = bincode::config::standard(); - let (decoded, _): (Tree, usize) = bincode::decode_from_slice(&encoded_value, config) - .map_err(|_| std::io::Error::other("Deserialization error"))?; + let (decoded, _): (Tree, usize) = + bincode::decode_from_slice(&encoded_value, config) + .map_err(|_| std::io::Error::other("Deserialization error"))?; Ok(decoded) } None => { @@ -51,8 +52,9 @@ impl TreeStore for sled::Db { let path = std::str::from_utf8(&path) .map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid UTF8 path"))?; let config = bincode::config::standard(); - let (decoded_tree, _): (Tree, usize) = bincode::decode_from_slice(&encoded_value, config) - .map_err(|_| Error::other("Deserialization error"))?; + let (decoded_tree, _): (Tree, usize) = + bincode::decode_from_slice(&encoded_value, config) + .map_err(|_| Error::other("Deserialization error"))?; Ok((PathBuf::from(path), decoded_tree)) } Err(e) => Err(Error::new(ErrorKind::NotFound, e)), @@ -81,8 +83,9 @@ impl CommitStore for sled::Db { fn get_commit(&self) -> Result { let encoded_value = self.get("COMMIT")?; let config = bincode::config::standard(); - let (decoded, _): (Commit, usize) = bincode::decode_from_slice(&encoded_value.unwrap(), config) - .map_err(|_| std::io::Error::other("Deserialization error"))?; + let (decoded, _): (Commit, usize) = + bincode::decode_from_slice(&encoded_value.unwrap(), config) + .map_err(|_| std::io::Error::other("Deserialization error"))?; Ok(decoded) } } @@ -439,7 +442,7 @@ impl TempStoreArea { // Ok(()) // } - + // fn _get(&self, key: &K) -> Result, KvError> { // let config = config::standard(); // let serialized_key = bincode::encode_to_vec(key,config).map_err(KvError::Serialization)?; @@ -457,7 +460,6 @@ impl TempStoreArea { // None => Ok(None), // } // } - // fn _remove(&self, key: &K) -> Result<(), KvError> { // let config = config::standard(); @@ -555,7 +557,6 @@ impl TempStoreArea { // None => Ok(None), // } // } - // fn _remove(&self, key: &K) -> Result<(), KvError> { // let serialized_key = bincode::serialize(key)?; @@ -610,7 +611,9 @@ mod test { if let Some(encoded_value) = db.get(t.id.as_ref()).unwrap() { // use bincode to deserialize the value . let config = bincode::config::standard(); - let decoded: Tree = bincode::decode_from_slice(&encoded_value,config).unwrap().0; + let decoded: Tree = bincode::decode_from_slice(&encoded_value, config) + .unwrap() + .0; println!(" {decoded}"); }; } @@ -627,12 +630,11 @@ mod test { Ok((key, value)) => { // Deserialize the value into the original tree structure using bincode let config = bincode::config::standard(); - let tree: Tree = bincode::decode_from_slice(&value,config).unwrap().0; + let tree: Tree = bincode::decode_from_slice(&value, config).unwrap().0; let key_str = std::str::from_utf8(&key).unwrap(); println!("path:{key_str}"); println!("{tree}"); - } Err(error) => { println!("Error iterating over trees: {error}"); diff --git a/scorpio/src/scolfs/route.rs b/scorpio/src/scolfs/route.rs index 9c2a1967a..735b2027d 100644 --- a/scorpio/src/scolfs/route.rs +++ b/scorpio/src/scolfs/route.rs @@ -48,7 +48,7 @@ pub fn router() -> Router { Router::new() .route("/lfs/attributes", post(track).delete(untrack)) .route("/lfs/locks", get(list_locks)) - .route("/lfs/locks/:path", post(create_lock).delete(remove_lock)) + .route("/lfs/locks/{path}", post(create_lock).delete(remove_lock)) //.route("/lfs/files", get(list_files)) }