From d86c6f7c46d4e21300a9b978c5df903864f436fa Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Mon, 6 Sep 2021 22:37:14 +0200 Subject: [PATCH] feat(package): implement gitlab package provider --- espanso-package/src/lib.rs | 13 +++-- espanso-package/src/provider/gitlab.rs | 68 ++++++++++++++++++++++++++ espanso-package/src/provider/mod.rs | 1 + espanso-package/src/util/github.rs | 15 +++--- espanso-package/src/util/gitlab.rs | 51 +++++++++++++++++++ 5 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 espanso-package/src/provider/gitlab.rs diff --git a/espanso-package/src/lib.rs b/espanso-package/src/lib.rs index c4572a9..5662a9a 100644 --- a/espanso-package/src/lib.rs +++ b/espanso-package/src/lib.rs @@ -51,8 +51,15 @@ pub fn get_provider(package: &PackageSpecifier, runtime_dir: &Path, options: &Pr true } else if let Some(gitlab_parts) = util::gitlab::extract_gitlab_url_parts(git_repo_url) { - panic!("GitLab is not supported yet!"); - todo!(); + if let Some(repo_scheme) = + util::gitlab::resolve_repo_scheme(gitlab_parts, package.git_branch.as_deref())? + { + return Ok(Box::new(provider::gitlab::GitLabPackageProvider::new( + repo_scheme.author, + repo_scheme.name, + repo_scheme.branch, + ))); + } true } else { @@ -64,7 +71,7 @@ pub fn get_provider(package: &PackageSpecifier, runtime_dir: &Path, options: &Pr // available to non-authenticated requests), so we check if a "git ls-remote" command // is able to access it. if matches_known_hosts && !util::git::is_private_repo(git_repo_url) { - bail!("could not access repository: {}, make sure it exists and that you have the necessary access rights."); + bail!("could not access repository: {}, make sure it exists and that you have the necessary access rights.", git_repo_url); } } diff --git a/espanso-package/src/provider/gitlab.rs b/espanso-package/src/provider/gitlab.rs new file mode 100644 index 0000000..4657900 --- /dev/null +++ b/espanso-package/src/provider/gitlab.rs @@ -0,0 +1,68 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use crate::{ + package::DefaultPackage, resolver::resolve_package, Package, PackageSpecifier, +}; +use anyhow::{Result}; +use super::PackageProvider; + +pub struct GitLabPackageProvider { + repo_author: String, + repo_name: String, + repo_branch: String, +} + +impl GitLabPackageProvider { + pub fn new(repo_author: String, repo_name: String, repo_branch: String) -> Self { + Self { + repo_author, + repo_name, + repo_branch, + } + } +} + +impl PackageProvider for GitLabPackageProvider { + fn name(&self) -> String { + "gitlab".to_string() + } + + fn download(&self, package: &PackageSpecifier) -> Result> { + let download_url = format!( + "https://gitlab.com/{}/{}/-/archive/{}/{}-{}.zip", + &self.repo_author, &self.repo_name, &self.repo_branch, &self.repo_name, &self.repo_branch + ); + + let temp_dir = tempdir::TempDir::new("espanso-package-download")?; + + crate::util::download::download_and_extract_zip(&download_url, temp_dir.path())?; + + let resolved_package = + resolve_package(temp_dir.path(), &package.name, package.version.as_deref())?; + + let package = DefaultPackage::new( + resolved_package.manifest, + temp_dir, + resolved_package.base_dir, + ); + + Ok(Box::new(package)) + } +} diff --git a/espanso-package/src/provider/mod.rs b/espanso-package/src/provider/mod.rs index e6e259a..e881bc5 100644 --- a/espanso-package/src/provider/mod.rs +++ b/espanso-package/src/provider/mod.rs @@ -24,6 +24,7 @@ use crate::Package; pub(crate) mod hub; pub(crate) mod git; pub(crate) mod github; +pub(crate) mod gitlab; #[derive(Debug, Default)] pub struct PackageSpecifier { diff --git a/espanso-package/src/util/github.rs b/espanso-package/src/util/github.rs index 7cedcc8..d0fc4a6 100644 --- a/espanso-package/src/util/github.rs +++ b/espanso-package/src/util/github.rs @@ -59,6 +59,14 @@ pub fn resolve_repo_scheme(parts: GitHubParts, force_branch: Option<&str>) -> Re })) } } else { + if check_repo_with_branch(&parts, "main")? { + return Ok(Some(ResolvedRepoScheme { + author: parts.author, + name: parts.name, + branch: "main".to_string(), + })); + } + if check_repo_with_branch(&parts, "master")? { return Ok(Some(ResolvedRepoScheme { author: parts.author, @@ -67,13 +75,6 @@ pub fn resolve_repo_scheme(parts: GitHubParts, force_branch: Option<&str>) -> Re })); } - if check_repo_with_branch(&parts, "main")? { - return Ok(Some(ResolvedRepoScheme { - author: parts.author, - name: parts.name, - branch: "main".to_string(), - })); - } } Ok(None) diff --git a/espanso-package/src/util/gitlab.rs b/espanso-package/src/util/gitlab.rs index ea07c92..3b57a22 100644 --- a/espanso-package/src/util/gitlab.rs +++ b/espanso-package/src/util/gitlab.rs @@ -19,6 +19,8 @@ use lazy_static::lazy_static; use regex::Regex; +use anyhow::Result; +use reqwest::StatusCode; lazy_static! { static ref GITLAB_REGEX: Regex = Regex::new(r"(https://gitlab.com/|git@gitlab.com:)(?P.*?)/(?P.*?)(/|\.|$)").unwrap(); @@ -41,6 +43,55 @@ pub fn extract_gitlab_url_parts(url: &str) -> Option { }) } +pub struct ResolvedRepoScheme { + pub author: String, + pub name: String, + pub branch: String, +} + +pub fn resolve_repo_scheme(parts: GitLabParts, force_branch: Option<&str>) -> Result> { + if let Some(force_branch) = force_branch { + if check_repo_with_branch(&parts, force_branch)? { + return Ok(Some(ResolvedRepoScheme { + author: parts.author, + name: parts.name, + branch: force_branch.to_string(), + })) + } + } else { + if check_repo_with_branch(&parts, "main")? { + return Ok(Some(ResolvedRepoScheme { + author: parts.author, + name: parts.name, + branch: "main".to_string(), + })); + } + + if check_repo_with_branch(&parts, "master")? { + return Ok(Some(ResolvedRepoScheme { + author: parts.author, + name: parts.name, + branch: "master".to_string(), + })); + } + } + + Ok(None) +} + +pub fn check_repo_with_branch(parts: &GitLabParts, branch: &str) -> Result { + let client = reqwest::blocking::Client::new(); + + let url = generate_gitlab_download_url(parts, branch); + let response = client.head(url).send()?; + + Ok(response.status() == StatusCode::OK) +} + +fn generate_gitlab_download_url(parts: &GitLabParts, branch: &str) -> String { + format!("https://gitlab.com/{}/{}/-/archive/{}/{}-{}.zip", parts.author, parts.name, branch, parts.name, branch) +} + #[cfg(test)] mod tests { use super::*;