blame: add edenapi client support

Summary: Add HTTP client and py bindings methods for performing EdenAPI "blame" operation.

Reviewed By: zzl0

Differential Revision: D44596608

fbshipit-source-id: 1961921b5157772b255cbc89140f8697530ee5fa
This commit is contained in:
Muir Manders 2023-04-05 12:05:57 -07:00 committed by Facebook GitHub Bot
parent 5853e03874
commit 42fdfd8b8e
3 changed files with 47 additions and 0 deletions

View File

@ -27,6 +27,7 @@ use edenapi_ext::upload_snapshot;
use edenapi_types::AlterSnapshotRequest;
use edenapi_types::AlterSnapshotResponse;
use edenapi_types::AnyFileContentId;
use edenapi_types::BlameResult;
use edenapi_types::CommitGraphEntry;
use edenapi_types::CommitHashLookupResponse;
use edenapi_types::CommitHashToLocationResponse;
@ -45,6 +46,7 @@ use edenapi_types::FileType;
use edenapi_types::HgChangesetContent;
use edenapi_types::HgMutationEntryContent;
use edenapi_types::HistoryEntry;
use edenapi_types::Key;
use edenapi_types::LandStackResponse;
use edenapi_types::SnapshotRawData;
use edenapi_types::TreeAttributes;
@ -520,6 +522,18 @@ py_class!(pub class client |py| {
.map_pyerr(py)?;
Ok(responses.entries.map_ok(Serde).map_err(Into::into).into())
}
def blame(
&self,
files: Serde<Vec<Key>>,
) -> PyResult<TStream<anyhow::Result<Serde<BlameResult>>>> {
let api = self.inner(py).as_ref();
let blames = py.allow_threads(|| block_unless_interrupted(api.blame(files.0)))
.map_pyerr(py)?
.map_pyerr(py)?
.entries;
Ok(blames.map_ok(Serde).map_err(Into::into).into())
}
});
impl ExtractInnerRef for client {

View File

@ -23,6 +23,8 @@ use edenapi_types::AlterSnapshotResponse;
use edenapi_types::AnyFileContentId;
use edenapi_types::AnyId;
use edenapi_types::Batch;
use edenapi_types::BlameRequest;
use edenapi_types::BlameResult;
use edenapi_types::BonsaiChangesetContent;
use edenapi_types::BookmarkEntry;
use edenapi_types::BookmarkRequest;
@ -117,6 +119,7 @@ const MAX_CONCURRENT_UPLOAD_FILENODES_PER_REQUEST: usize = 10000;
const MAX_CONCURRENT_UPLOAD_TREES_PER_REQUEST: usize = 1000;
const MAX_CONCURRENT_FILE_UPLOADS: usize = 1000;
const MAX_CONCURRENT_HASH_LOOKUPS_PER_REQUEST: usize = 1000;
const MAX_CONCURRENT_BLAMES_PER_REQUEST: usize = 10;
const MAX_ERROR_MSG_LEN: usize = 500;
static REQUESTS_INFLIGHT: Counter = Counter::new("edenapi.req_inflight");
@ -152,6 +155,7 @@ mod paths {
pub const FETCH_SNAPSHOT: &str = "snapshot";
pub const ALTER_SNAPSHOT: &str = "snapshot/alter";
pub const DOWNLOAD_FILE: &str = "download/file";
pub const BLAME: &str = "blame";
}
#[derive(Clone)]
@ -1303,6 +1307,28 @@ impl EdenApi for Client {
)?;
Ok(self.fetch::<CommitTranslateIdResponse>(requests)?)
}
async fn blame(&self, files: Vec<Key>) -> Result<Response<BlameResult>, EdenApiError> {
tracing::info!("Blaming {} file(s)", files.len());
if files.is_empty() {
return Ok(Response::empty());
}
let url = self.build_url(paths::BLAME)?;
let requests = self.prepare_requests(
&url,
files,
Some(MAX_CONCURRENT_BLAMES_PER_REQUEST),
|files| {
let req = BlameRequest { files };
self.log_request(&req, "blame");
req
},
)?;
Ok(self.fetch::<BlameResult>(requests)?)
}
}
/// Split up a collection of keys into batches of at most `batch_size`.

View File

@ -14,6 +14,7 @@ use edenapi_types::AlterSnapshotRequest;
use edenapi_types::AlterSnapshotResponse;
use edenapi_types::AnyFileContentId;
use edenapi_types::AnyId;
use edenapi_types::BlameResult;
use edenapi_types::BonsaiChangesetContent;
use edenapi_types::BookmarkEntry;
use edenapi_types::CloneData;
@ -327,4 +328,10 @@ pub trait EdenApi: Send + Sync + 'static {
let _ = (commits, scheme);
Err(EdenApiError::NotSupported)
}
/// Fetch metadata describing the last commit to modify each line in given file(s)
async fn blame(&self, files: Vec<Key>) -> Result<Response<BlameResult>, EdenApiError> {
let _ = files;
Err(EdenApiError::NotSupported)
}
}