edenapi: add repo name to client config

Summary: As a first step to moving the repo name inside the EdenAPI client itself, add it as a (currently unused) field to the config. Later diffs will use this instead of having each method take a `repo` argument.

Reviewed By: quark-zju

Differential Revision: D30746379

fbshipit-source-id: 07957e53e940ce72f84b2297f506b796117ec46a
This commit is contained in:
Arun Kulshreshtha 2021-09-13 16:04:45 -07:00 committed by Facebook GitHub Bot
parent cb1d34f8d4
commit 92ff6fd79a
2 changed files with 28 additions and 4 deletions

View File

@ -106,6 +106,7 @@ impl<'a> Builder<'a> {
/// You probably want to use [`Builder`] instead.
#[derive(Debug, Default)]
pub struct HttpClientBuilder {
repo_name: Option<String>,
server_url: Option<Url>,
cert: Option<PathBuf>,
key: Option<PathBuf>,
@ -139,6 +140,15 @@ impl HttpClientBuilder {
/// Populate a `HttpClientBuilder` from a Mercurial configuration.
pub fn from_config(config: &dyn configmodel::Config) -> Result<Self, EdenApiError> {
// XXX: Ideally, the repo name would be a required field, obtained from a `Repo` object from
// the `clidispatch` crate. Unforunately, not all callsites presently have access to a
// populated `Repo` object, and it isn't trivial to just initialize one (requires a path to
// the on-disk repo) or to plumb one through (which might not be possible for usage outside
// of a Mercurial process, such as by EdenFS). For now, let's just do what the Python code
// does and default to "unknown" when the repo name is missing.
let repo_name =
get_config::<String>(config, "remotefilelog", "reponame")?.unwrap_or("unknown".into());
let server_url = get_required_config::<String>(config, "edenapi", "url")?
.parse::<Url>()
.map_err(|e| ConfigError::Invalid("edenapi.url".into(), e.into()))?;
@ -210,6 +220,7 @@ impl HttpClientBuilder {
);
Ok(HttpClientBuilder {
repo_name: Some(repo_name),
server_url: Some(server_url),
cert,
key,
@ -232,6 +243,12 @@ impl HttpClientBuilder {
})
}
/// Set the repo name.
pub fn repo_name(mut self, repo_name: &str) -> Self {
self.repo_name = Some(repo_name.into());
self
}
/// Set the server URL.
pub fn server_url(mut self, url: Url) -> Self {
self.server_url = Some(url);
@ -387,6 +404,7 @@ fn get_required_config<T: FromConfigValue>(
/// been appropriately parsed and validated.
#[derive(Debug)]
pub(crate) struct Config {
pub(crate) repo_name: String,
pub(crate) server_url: Url,
pub(crate) cert: Option<PathBuf>,
pub(crate) key: Option<PathBuf>,
@ -413,6 +431,7 @@ impl TryFrom<HttpClientBuilder> for Config {
fn try_from(builder: HttpClientBuilder) -> Result<Self, Self::Error> {
let HttpClientBuilder {
repo_name,
server_url,
cert,
key,
@ -435,6 +454,7 @@ impl TryFrom<HttpClientBuilder> for Config {
} = builder;
// Check for missing required fields.
let repo_name = repo_name.ok_or(ConfigError::Missing("remotefilelog.reponame".into()))?;
let mut server_url = server_url.ok_or(ConfigError::Missing("edenapi.url".into()))?;
// Ensure the base URL's path ends with a slash so that `Url::join`
@ -450,6 +470,7 @@ impl TryFrom<HttpClientBuilder> for Config {
let max_history = max_history.filter(|n| *n > 0);
Ok(Config {
repo_name,
server_url,
cert,
key,

View File

@ -1339,12 +1339,15 @@ mod tests {
#[test]
fn test_url_escaping() -> Result<()> {
let base_url = "https://example.com".parse()?;
let client = HttpClientBuilder::new().server_url(base_url).build()?;
let repo_name = "repo_-. !@#$% foo \u{1f4a9} bar";
let client = HttpClientBuilder::new()
.repo_name(repo_name)
.server_url(base_url)
.build()?;
let repo = "repo_-. !@#$% foo \u{1f4a9} bar";
let path = "path";
let url: String = client.build_url(path, Some(repo))?.into();
let url: String = client.build_url(path, Some(repo_name))?.into();
let expected =
"https://example.com/repo_-.%20%21%40%23%24%25%20foo%20%F0%9F%92%A9%20bar/path";
assert_eq!(&url, &expected);