diff --git a/edenscm/hgext/remotefilelog/__init__.py b/edenscm/hgext/remotefilelog/__init__.py index 05c2a34d8f..1758c3913f 100644 --- a/edenscm/hgext/remotefilelog/__init__.py +++ b/edenscm/hgext/remotefilelog/__init__.py @@ -124,6 +124,8 @@ Configs for Eden API (HTTP data fetching): ``edenapi.url`` specifies the base URL of the API server. + ``edenapi.backend`` specifies which HTTP client library to use. + Eden API TLS credentials are configured using the auth section: ``auth.edenapi.prefix``: base URL (without scheme) for which to set credentials. @@ -218,6 +220,7 @@ configitem("remotefilelog", "server", default=None) # Config items for HTTP data fetching. configitem("edenapi", "enabled", default=False) configitem("edenapi", "url", default=None) +configitem("edenapi", "backend", default="curl") testedwith = "ships-with-fb-hgext" diff --git a/edenscm/hgext/remotefilelog/edenapi.py b/edenscm/hgext/remotefilelog/edenapi.py index 01b34bd0ae..98388fcaf8 100644 --- a/edenscm/hgext/remotefilelog/edenapi.py +++ b/edenscm/hgext/remotefilelog/edenapi.py @@ -47,4 +47,5 @@ def initclient(ui, repo): url = getbaseurl(ui) creds = getcreds(ui, url) cachepath = shallowutil.getcachepath(ui) - return edenapi.client(url, cachepath, repo.name, creds) + backend = ui.config("edenapi", "backend") + return edenapi.client(url, cachepath, repo.name, backend, creds) diff --git a/edenscm/mercurial/rust/bindings/Cargo.toml b/edenscm/mercurial/rust/bindings/Cargo.toml index ce23abce8e..caf214480c 100644 --- a/edenscm/mercurial/rust/bindings/Cargo.toml +++ b/edenscm/mercurial/rust/bindings/Cargo.toml @@ -22,6 +22,7 @@ encoding = { path = "../../../../lib/encoding" } env_logger = "0.5.13" failure = "0.1.3" lz4-pyframe = { path = "../../../../lib/lz4-pyframe" } +log = "0.4.6" mutationstore = { path = "../../../../lib/mutationstore" } nodemap = { path = "../../../../lib/nodemap" } pathmatcher = { path = "../../../../lib/pathmatcher" } diff --git a/edenscm/mercurial/rust/bindings/src/edenapi.rs b/edenscm/mercurial/rust/bindings/src/edenapi.rs index 208ab6593b..80a73b79d4 100644 --- a/edenscm/mercurial/rust/bindings/src/edenapi.rs +++ b/edenscm/mercurial/rust/bindings/src/edenapi.rs @@ -7,9 +7,11 @@ use std::str; use cpython::*; use cpython_failure::ResultPyErrExt; - -use ::edenapi::{Config, EdenApi, EdenApiHyperClient}; use encoding::{local_bytes_to_path, path_to_local_bytes}; +use failure::format_err; +use log; + +use ::edenapi::{Config, EdenApi, EdenApiCurlClient, EdenApiHyperClient}; use types::{Key, Node}; pub fn init_module(py: Python, package: &str) -> PyResult { @@ -20,18 +22,20 @@ pub fn init_module(py: Python, package: &str) -> PyResult { } py_class!(class client |py| { - data inner: EdenApiHyperClient; + data inner: Box; def __new__( _cls, base_url: &PyBytes, cache_path: &PyBytes, repo: &PyBytes, + backend: &PyBytes, client_creds: Option<(&PyBytes, &PyBytes)> = None ) -> PyResult { let base_url = str::from_utf8(base_url.data(py)).map_pyerr::(py)?; - let cache_path = str::from_utf8(cache_path.data(py)).map_pyerr::(py)?; + let cache_path = local_bytes_to_path(&cache_path.data(py)).map_pyerr::(py)?; let repo = str::from_utf8(repo.data(py)).map_pyerr::(py)?; + let backend = str::from_utf8(backend.data(py)).map_pyerr::(py)?; let mut config = Config::new() .base_url_str(base_url) @@ -45,7 +49,22 @@ py_class!(class client |py| { config = config.client_creds(cert, key); } - let inner = EdenApiHyperClient::new(config).map_pyerr::(py)?; + let inner = match backend { + "curl" => { + log::debug!("Using curl-backed Eden API client"); + let client = EdenApiCurlClient::new(config).map_pyerr::(py)?; + Box::new(client) as Box + }, + "hyper" => { + log::debug!("Using hyper-backed Eden API client"); + let client = EdenApiHyperClient::new(config).map_pyerr::(py)?; + Box::new(client) as Box + }, + invalid => { + return Err(format_err!("Invalid Eden API backend: {}", invalid)).map_pyerr::(py); + }, + }; + client::create_instance(py, inner) } diff --git a/lib/edenapi/src/api.rs b/lib/edenapi/src/api.rs index 13f0915a08..8c36425755 100644 --- a/lib/edenapi/src/api.rs +++ b/lib/edenapi/src/api.rs @@ -6,23 +6,25 @@ use failure::Fallible; use types::Key; -pub trait EdenApi { +pub trait EdenApi: Send { /// Hit the API server's /health_check endpoint. /// Returns Ok(()) if the expected response is received, or an Error otherwise /// (e.g., if there was a connection problem or an unexpected repsonse). fn health_check(&self) -> Fallible<()>; - /// Fetch the content of the specified file from the API server and write - /// it to a datapack in the configured cache directory. Returns the path + /// Fetch the content of the specified files from the API server and write + /// them to a datapack in the configured cache directory. Returns the path /// of the resulting packfile. - fn get_files(&self, keys: impl IntoIterator) -> Fallible; + /// + /// Note that the keys are passed in as a `Vec` rather than using `IntoIterator` + /// in order to keep this trait object-safe. + fn get_files(&self, keys: Vec) -> Fallible; - /// Fetch the history of the specified file from the API server and write - /// it to a historypack in the configured cache directory. Returns the path + /// Fetch the history of the specified files from the API server and write + /// them to a historypack in the configured cache directory. Returns the path /// of the resulting packfile. - fn get_history( - &self, - keys: impl IntoIterator, - max_depth: Option, - ) -> Fallible; + /// + /// Note that the keys are passed in as a `Vec` rather than using `IntoIterator` + /// in order to keep this trait object-safe. + fn get_history(&self, keys: Vec, max_depth: Option) -> Fallible; } diff --git a/lib/edenapi/src/curl.rs b/lib/edenapi/src/curl.rs index 365e2b3cdd..f4a7325106 100644 --- a/lib/edenapi/src/curl.rs +++ b/lib/edenapi/src/curl.rs @@ -101,7 +101,7 @@ impl EdenApi for EdenApiCurlClient { Ok(()) } - fn get_files(&self, keys: impl IntoIterator) -> Fallible { + fn get_files(&self, keys: Vec) -> Fallible { let url = self.repo_base_url()?.join(paths::DATA)?; let request = FileDataRequest { @@ -124,11 +124,7 @@ impl EdenApi for EdenApiCurlClient { write_datapack(self.pack_cache_path(), response) } - fn get_history( - &self, - keys: impl IntoIterator, - max_depth: Option, - ) -> Fallible { + fn get_history(&self, keys: Vec, max_depth: Option) -> Fallible { let url = self.repo_base_url()?.join(paths::HISTORY)?; let request = FileHistoryRequest { diff --git a/lib/edenapi/src/hyper.rs b/lib/edenapi/src/hyper.rs index c34b36d268..86425eac51 100644 --- a/lib/edenapi/src/hyper.rs +++ b/lib/edenapi/src/hyper.rs @@ -126,7 +126,7 @@ impl EdenApi for EdenApiHyperClient { /// Fetch the content of the specified file from the API server and write /// it to a datapack in the configured cache directory. Returns the path /// of the resulting packfile. - fn get_files(&self, keys: impl IntoIterator) -> Fallible { + fn get_files(&self, keys: Vec) -> Fallible { let client = Arc::clone(&self.client); let prefix = self.repo_base_url()?.join(paths::GET_FILE)?; @@ -145,11 +145,7 @@ impl EdenApi for EdenApiHyperClient { /// Fetch the history of the specified file from the API server and write /// it to a historypack in the configured cache directory. Returns the path /// of the resulting packfile. - fn get_history( - &self, - keys: impl IntoIterator, - max_depth: Option, - ) -> Fallible { + fn get_history(&self, keys: Vec, max_depth: Option) -> Fallible { let client = Arc::clone(&self.client); let prefix = self.repo_base_url()?.join(paths::GET_HISTORY)?;