mirror of
https://github.com/deps-rs/deps.rs.git
synced 2024-11-22 18:36:30 +00:00
Merge pull request #23 from pwoolcoc/feature/add-gitlab
Add gitlab as a source for manifests
This commit is contained in:
commit
05aeb4fb1e
6 changed files with 109 additions and 47 deletions
|
@ -21,7 +21,8 @@ use ::models::repo::{Repository, RepoPath};
|
||||||
use ::models::crates::{CrateName, CrateRelease, AnalyzedDependencies};
|
use ::models::crates::{CrateName, CrateRelease, AnalyzedDependencies};
|
||||||
|
|
||||||
use ::interactors::crates::QueryCrate;
|
use ::interactors::crates::QueryCrate;
|
||||||
use ::interactors::github::{GetPopularRepos, RetrieveFileAtPath};
|
use ::interactors::RetrieveFileAtPath;
|
||||||
|
use ::interactors::github::{GetPopularRepos};
|
||||||
|
|
||||||
use self::futures::AnalyzeDependenciesFuture;
|
use self::futures::AnalyzeDependenciesFuture;
|
||||||
use self::futures::CrawlManifestFuture;
|
use self::futures::CrawlManifestFuture;
|
||||||
|
|
|
@ -11,46 +11,14 @@ use ::models::repo::{Repository, RepoPath};
|
||||||
const GITHUB_API_BASE_URI: &'static str = "https://api.github.com";
|
const GITHUB_API_BASE_URI: &'static str = "https://api.github.com";
|
||||||
const GITHUB_USER_CONTENT_BASE_URI: &'static str = "https://raw.githubusercontent.com";
|
const GITHUB_USER_CONTENT_BASE_URI: &'static str = "https://raw.githubusercontent.com";
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub fn get_manifest_uri(repo_path: &RepoPath, path: &RelativePathBuf) -> Result<Uri, Error> {
|
||||||
pub struct RetrieveFileAtPath<S>(pub S);
|
let path_str: &str = path.as_ref();
|
||||||
|
Ok(format!("{}/{}/{}/HEAD/{}",
|
||||||
impl<S> Service for RetrieveFileAtPath<S>
|
GITHUB_USER_CONTENT_BASE_URI,
|
||||||
where S: Service<Request=Request, Response=Response, Error=HyperError> + Clone + 'static,
|
repo_path.qual.as_ref(),
|
||||||
S::Future: 'static
|
repo_path.name.as_ref(),
|
||||||
{
|
path_str
|
||||||
type Request = (RepoPath, RelativePathBuf);
|
).parse::<Uri>()?)
|
||||||
type Response = String;
|
|
||||||
type Error = Error;
|
|
||||||
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
|
|
||||||
|
|
||||||
fn call(&self, req: Self::Request) -> Self::Future {
|
|
||||||
let service = self.0.clone();
|
|
||||||
|
|
||||||
let (repo_path, path) = req;
|
|
||||||
let path_str: &str = path.as_ref();
|
|
||||||
let uri_future = format!("{}/{}/{}/HEAD/{}",
|
|
||||||
GITHUB_USER_CONTENT_BASE_URI,
|
|
||||||
repo_path.qual.as_ref(),
|
|
||||||
repo_path.name.as_ref(),
|
|
||||||
path_str
|
|
||||||
).parse::<Uri>().into_future().from_err();
|
|
||||||
|
|
||||||
Box::new(uri_future.and_then(move |uri| {
|
|
||||||
let request = Request::new(Method::Get, uri.clone());
|
|
||||||
|
|
||||||
service.call(request).from_err().and_then(move |response| {
|
|
||||||
let status = response.status();
|
|
||||||
if !status.is_success() {
|
|
||||||
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri)))
|
|
||||||
} else {
|
|
||||||
let body_future = response.body().concat2().from_err();
|
|
||||||
let decode_future = body_future
|
|
||||||
.and_then(|body| String::from_utf8(body.to_vec()).map_err(|err| err.into()));
|
|
||||||
future::Either::B(decode_future)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
24
src/interactors/gitlab.rs
Normal file
24
src/interactors/gitlab.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use hyper::Uri;
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
use failure::Error;
|
||||||
|
|
||||||
|
use ::models::repo::RepoPath;
|
||||||
|
|
||||||
|
const GITLAB_USER_CONTENT_BASE_URI: &'static str = "https://gitlab.com";
|
||||||
|
|
||||||
|
pub fn get_manifest_uri(repo_path: &RepoPath, path: &RelativePathBuf) -> Result<Uri, Error> {
|
||||||
|
let path_str: &str = path.as_ref();
|
||||||
|
// gitlab will return a 308 if the Uri ends with, say, `.../raw/HEAD//Cargo.toml`, so make
|
||||||
|
// sure that last slash isn't doubled
|
||||||
|
let slash_path = if path_str.starts_with("/") {
|
||||||
|
&path_str[1..]
|
||||||
|
} else {
|
||||||
|
path_str
|
||||||
|
};
|
||||||
|
Ok(format!("{}/{}/{}/raw/HEAD/{}",
|
||||||
|
GITLAB_USER_CONTENT_BASE_URI,
|
||||||
|
repo_path.qual.as_ref(),
|
||||||
|
repo_path.name.as_ref(),
|
||||||
|
slash_path
|
||||||
|
).parse::<Uri>()?)
|
||||||
|
}
|
|
@ -1,2 +1,58 @@
|
||||||
|
use failure::Error;
|
||||||
|
use futures::{Future, IntoFuture, Stream, future};
|
||||||
|
use hyper::{Error as HyperError, Method, Request, Response};
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
use tokio_service::Service;
|
||||||
|
|
||||||
|
use ::models::repo::{RepoSite, RepoPath};
|
||||||
|
|
||||||
pub mod crates;
|
pub mod crates;
|
||||||
pub mod github;
|
pub mod github;
|
||||||
|
pub mod gitlab;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RetrieveFileAtPath<S>(pub S);
|
||||||
|
|
||||||
|
impl<S> Service for RetrieveFileAtPath<S>
|
||||||
|
where S: Service<Request=Request, Response=Response, Error=HyperError> + Clone + 'static,
|
||||||
|
S::Future: 'static
|
||||||
|
{
|
||||||
|
type Request = (RepoPath, RelativePathBuf);
|
||||||
|
type Response = String;
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Box<Future<Item=Self::Response, Error=Self::Error>>;
|
||||||
|
|
||||||
|
fn call(&self, req: Self::Request) -> Self::Future {
|
||||||
|
let service = self.0.clone();
|
||||||
|
|
||||||
|
let (repo_path, path) = req;
|
||||||
|
let uri = match &repo_path.site {
|
||||||
|
&RepoSite::Github => {
|
||||||
|
github::get_manifest_uri(&repo_path, &path)
|
||||||
|
},
|
||||||
|
&RepoSite::Gitlab => {
|
||||||
|
gitlab::get_manifest_uri(&repo_path, &path)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let uri_future = uri.into_future().from_err();
|
||||||
|
|
||||||
|
Box::new(uri_future.and_then(move |uri| {
|
||||||
|
let request = Request::new(Method::Get, uri.clone());
|
||||||
|
|
||||||
|
service.call(request).from_err().and_then(move |response| {
|
||||||
|
let status = response.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
future::Either::A(future::err(format_err!("Status code {} for URI {}", status, uri)))
|
||||||
|
} else {
|
||||||
|
let body_future = response.body().concat2().from_err();
|
||||||
|
let decode_future = body_future
|
||||||
|
.and_then(|body| String::from_utf8(body.to_vec()).map_err(|err| err.into()));
|
||||||
|
future::Either::B(decode_future)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@ impl RepoPath {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
pub enum RepoSite {
|
pub enum RepoSite {
|
||||||
Github
|
Github,
|
||||||
|
Gitlab,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepoSite {
|
impl RepoSite {
|
||||||
pub fn to_base_uri(&self) -> &'static str {
|
pub fn to_base_uri(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
&RepoSite::Github => "https://github.com"
|
&RepoSite::Github => "https://github.com",
|
||||||
|
&RepoSite::Gitlab => "https://gitlab.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +46,7 @@ impl FromStr for RepoSite {
|
||||||
fn from_str(input: &str) -> Result<RepoSite, Error> {
|
fn from_str(input: &str) -> Result<RepoSite, Error> {
|
||||||
match input {
|
match input {
|
||||||
"github" => Ok(RepoSite::Github),
|
"github" => Ok(RepoSite::Github),
|
||||||
|
"gitlab" => Ok(RepoSite::Gitlab),
|
||||||
_ => Err(format_err!("unknown repo site identifier"))
|
_ => Err(format_err!("unknown repo site identifier"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +55,8 @@ impl FromStr for RepoSite {
|
||||||
impl AsRef<str> for RepoSite {
|
impl AsRef<str> for RepoSite {
|
||||||
fn as_ref(&self) -> &str {
|
fn as_ref(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
&RepoSite::Github => "github"
|
&RepoSite::Github => "github",
|
||||||
|
&RepoSite::Gitlab => "gitlab"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ordermap::OrderMap;
|
||||||
|
|
||||||
use ::engine::AnalyzeDependenciesOutcome;
|
use ::engine::AnalyzeDependenciesOutcome;
|
||||||
use ::models::crates::{CrateName, AnalyzedDependency, AnalyzedDependencies};
|
use ::models::crates::{CrateName, AnalyzedDependency, AnalyzedDependencies};
|
||||||
use ::models::repo::RepoPath;
|
use ::models::repo::{RepoSite, RepoPath};
|
||||||
use ::server::assets;
|
use ::server::assets;
|
||||||
|
|
||||||
fn dependency_tables(crate_name: CrateName, deps: AnalyzedDependencies) -> Markup {
|
fn dependency_tables(crate_name: CrateName, deps: AnalyzedDependencies) -> Markup {
|
||||||
|
@ -84,7 +84,15 @@ fn dependency_table(title: &str, deps: OrderMap<CrateName, AnalyzedDependency>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_site_icon(repo_site: &RepoSite) -> &'static str {
|
||||||
|
match *repo_site {
|
||||||
|
RepoSite::Github => "fa-github",
|
||||||
|
RepoSite::Gitlab => "fa-gitlab",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn render_failure(repo_path: RepoPath) -> Markup {
|
fn render_failure(repo_path: RepoPath) -> Markup {
|
||||||
|
let site_icon = get_site_icon(&repo_path.site);
|
||||||
html! {
|
html! {
|
||||||
section class="hero is-light" {
|
section class="hero is-light" {
|
||||||
div class="hero-head" (super::render_navbar())
|
div class="hero-head" (super::render_navbar())
|
||||||
|
@ -92,7 +100,7 @@ fn render_failure(repo_path: RepoPath) -> Markup {
|
||||||
div class="container" {
|
div class="container" {
|
||||||
h1 class="title is-1" {
|
h1 class="title is-1" {
|
||||||
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
||||||
i class="fa fa-github" ""
|
i class=(format!("fa {}", site_icon)) ""
|
||||||
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +122,7 @@ fn render_failure(repo_path: RepoPath) -> Markup {
|
||||||
fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Markup {
|
fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoPath) -> Markup {
|
||||||
let self_path = format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref());
|
let self_path = format!("repo/{}/{}/{}", repo_path.site.as_ref(), repo_path.qual.as_ref(), repo_path.name.as_ref());
|
||||||
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
||||||
|
let site_icon = get_site_icon(&repo_path.site);
|
||||||
|
|
||||||
let (hero_class, status_asset) = if analysis_outcome.any_outdated() {
|
let (hero_class, status_asset) = if analysis_outcome.any_outdated() {
|
||||||
("is-warning", assets::BADGE_OUTDATED_SVG.as_ref())
|
("is-warning", assets::BADGE_OUTDATED_SVG.as_ref())
|
||||||
|
@ -130,7 +139,7 @@ fn render_success(analysis_outcome: AnalyzeDependenciesOutcome, repo_path: RepoP
|
||||||
div class="container" {
|
div class="container" {
|
||||||
h1 class="title is-1" {
|
h1 class="title is-1" {
|
||||||
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
a href=(format!("{}/{}/{}", repo_path.site.to_base_uri(), repo_path.qual.as_ref(), repo_path.name.as_ref())) {
|
||||||
i class="fa fa-github" ""
|
i class=(format!("fa {}", site_icon)) ""
|
||||||
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
(format!(" {} / {}", repo_path.qual.as_ref(), repo_path.name.as_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue