Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
httpd: Return entire files from commit handler
Sebastian Martinez committed 2 years ago
commit 35da28d8af08baece5a2f0d5baaa4fc3dc21ba6a
parent 313fc1315d04fafc99ba0cc5e23fd40ae79b2449
2 files changed +147 -18
modified radicle-httpd/src/api/json.rs
@@ -3,6 +3,7 @@
use std::path::Path;
use std::str;

+
use base64::prelude::{Engine, BASE64_STANDARD};
use serde::Serialize;
use serde_json::{json, Value};

@@ -56,21 +57,21 @@ pub(crate) fn session(session_id: String, session: &Session) -> Value {

/// Returns JSON for a blob with a given `path`.
pub(crate) fn blob<T: AsRef<[u8]>>(blob: &Blob<T>, path: &str) -> Value {
-
    let mut response = json!({
+
    json!({
        "binary": blob.is_binary(),
        "name": name_in_path(path),
+
        "content": blob_content(blob),
        "path": path,
        "lastCommit": commit(blob.commit())
-
    });
+
    })
+
}

-
    if !blob.is_binary() {
-
        match str::from_utf8(blob.content()) {
-
            Ok(content) => response["content"] = content.into(),
-
            Err(err) => return json!({ "error": err.to_string() }),
-
        }
+
/// Returns a string for the blob content, encoded in base64 if binary.
+
pub fn blob_content<T: AsRef<[u8]>>(blob: &Blob<T>) -> String {
+
    match str::from_utf8(blob.content()) {
+
        Ok(s) => s.to_owned(),
+
        Err(_) => BASE64_STANDARD.encode(blob.content()),
    }
-

-
    response
}

/// Returns JSON for a tree with a given `path` and `stats`.
modified radicle-httpd/src/api/v1/projects.rs
@@ -10,7 +10,7 @@ use axum_auth::AuthBearer;
use hyper::StatusCode;
use radicle_surf::blob::{Blob, BlobRef};
use serde::{Deserialize, Serialize};
-
use serde_json::json;
+
use serde_json::{json, Value};
use tower_http::set_header::SetResponseHeaderLayer;

use radicle::cob::{issue, patch, Embed, Label, Uri};
@@ -233,9 +233,106 @@ async fn commit_handler(
        .map(|b| b.refname().to_string())
        .collect();

+
    let mut files: HashMap<Oid, Value> = HashMap::new();
+
    diff.files().for_each(|file_diff| match file_diff {
+
        diff::FileDiff::Added(added) => {
+
            if let Ok(blob) = repo.blob(commit.id, &added.path) {
+
                files.insert(
+
                    blob.object_id(),
+
                    json!({
+
                      "binary": blob.is_binary(),
+
                      "content": api::json::blob_content(&blob)
+
                    }),
+
                );
+
            }
+
        }
+
        diff::FileDiff::Deleted(deleted) => {
+
            commit
+
                .parents
+
                .iter()
+
                .filter_map(|oid| repo.blob(oid, &deleted.path).ok())
+
                .for_each(|blob| {
+
                    files.insert(
+
                        blob.object_id(),
+
                        json!({
+
                          "binary": blob.is_binary(),
+
                          "content": api::json::blob_content(&blob)
+
                        }),
+
                    );
+
                });
+
        }
+
        diff::FileDiff::Modified(modified) => {
+
            if let Ok(new_blob) = repo.blob(commit.id, &modified.path) {
+
                files.insert(
+
                    new_blob.object_id(),
+
                    json!({
+
                      "binary": new_blob.is_binary(),
+
                      "content": api::json::blob_content(&new_blob)
+
                    }),
+
                );
+
            }
+
            commit
+
                .parents
+
                .iter()
+
                .filter_map(|oid| repo.blob(oid, &modified.path).ok())
+
                .for_each(|blob| {
+
                    files.insert(
+
                        blob.object_id(),
+
                        json!({
+
                          "binary": blob.is_binary(),
+
                          "content": api::json::blob_content(&blob)
+
                        }),
+
                    );
+
                });
+
        }
+
        diff::FileDiff::Moved(moved) => {
+
            if let (Ok(old_blob), Ok(new_blob)) = (
+
                repo.blob(moved.old.oid, &moved.old_path),
+
                repo.blob(moved.new.oid, &moved.new_path),
+
            ) {
+
                files.insert(
+
                    old_blob.object_id(),
+
                    json!({
+
                      "binary": old_blob.is_binary(),
+
                      "content": api::json::blob_content(&old_blob)
+
                    }),
+
                );
+
                files.insert(
+
                    new_blob.object_id(),
+
                    json!({
+
                      "binary": new_blob.is_binary(),
+
                      "content": api::json::blob_content(&new_blob)
+
                    }),
+
                );
+
            }
+
        }
+
        diff::FileDiff::Copied(copied) => {
+
            if let (Ok(old_blob), Ok(new_blob)) = (
+
                repo.blob(copied.old.oid, &copied.old_path),
+
                repo.blob(copied.new.oid, &copied.new_path),
+
            ) {
+
                files.insert(
+
                    old_blob.object_id(),
+
                    json!({
+
                      "binary": old_blob.is_binary(),
+
                      "content": api::json::blob_content(&old_blob)
+
                    }),
+
                );
+
                files.insert(
+
                    new_blob.object_id(),
+
                    json!({
+
                      "binary": new_blob.is_binary(),
+
                      "content": api::json::blob_content(&new_blob)
+
                    }),
+
                );
+
            }
+
        }
+
    });
+

    let response = json!({
      "commit": api::json::commit(&commit),
      "diff": diff,
+
      "files": files,
      "branches": branches
    });
    Ok::<_, Error>(Json(response))
@@ -256,24 +353,41 @@ async fn diff_handler(
    diff.files().for_each(|file_diff| match file_diff {
        diff::FileDiff::Added(added) => {
            if let Ok(blob) = repo.blob(commit.id, &added.path) {
-
                files.insert(added.new.oid, blob);
+
                files.insert(blob.object_id(), blob);
            }
        }
        diff::FileDiff::Deleted(deleted) => {
-
            if let Ok(blob) = repo.blob(commit.id, &deleted.path) {
-
                files.insert(deleted.old.oid, blob);
+
            if let Ok(old_blob) = repo.blob(base.id, &deleted.path) {
+
                files.insert(old_blob.object_id(), old_blob);
            }
        }
        diff::FileDiff::Modified(modified) => {
-
            if let (Ok(old_blob), Ok(new_blob)) = (
-
                repo.blob(commit.parents[0], &modified.path),
+
            if let (Ok(new_blob), Ok(old_blob)) = (
                repo.blob(commit.id, &modified.path),
+
                repo.blob(base.id, &modified.path),
+
            ) {
+
                files.insert(new_blob.object_id(), new_blob);
+
                files.insert(old_blob.object_id(), old_blob);
+
            }
+
        }
+
        diff::FileDiff::Moved(moved) => {
+
            if let (Ok(new_blob), Ok(old_blob)) = (
+
                repo.blob(moved.new.oid, &moved.new_path),
+
                repo.blob(moved.old.oid, &moved.old_path),
+
            ) {
+
                files.insert(new_blob.object_id(), new_blob);
+
                files.insert(old_blob.object_id(), old_blob);
+
            }
+
        }
+
        diff::FileDiff::Copied(copied) => {
+
            if let (Ok(new_blob), Ok(old_blob)) = (
+
                repo.blob(copied.new.oid, &copied.new_path),
+
                repo.blob(copied.old.oid, &copied.old_path),
            ) {
-
                files.insert(modified.old.oid, old_blob);
-
                files.insert(modified.new.oid, new_blob);
+
                files.insert(new_blob.object_id(), new_blob);
+
                files.insert(old_blob.object_id(), old_blob);
            }
        }
-
        _ => (),
    });

    let commits = repo
@@ -1395,6 +1509,20 @@ mod routes {
                  "deletions": 1
                }
              },
+
              "files": {
+
                "980a0d5f19a64b4b30a87d4206aade58726b60e3": {
+
                  "binary": false,
+
                  "content": "Hello World!\n",
+
                },
+
                "1dd5654ca2d2cf9f33b14c92b5ca9e1d21a91ae1": {
+
                  "binary": false,
+
                  "content": "Hello World from dir1!\n",
+
                },
+
                "82eb77880c693655bce074e3dbbd9fa711dc018b": {
+
                  "binary": false,
+
                  "content": "Thank you very much!\n",
+
                },
+
              },
              "branches": [
                "refs/heads/master"
              ]