From 62d16f71f8cad69cbef57159d9873d027e7a513b Mon Sep 17 00:00:00 2001 From: clux Date: Tue, 12 Dec 2017 21:18:10 +0000 Subject: [PATCH] starts of a GithubBackend hubcaps is missing the release assets api unfortunately though. So we can create a release, but we can't attach our artifact to it yet. Stashing current work in a branch. --- Cargo.toml | 1 + src/core/errors.rs | 10 ++++ src/lib.rs | 1 + src/main.rs | 3 + src/storage/github.rs | 126 ++++++++++++++++++++++++++++++++++++++++++ src/storage/mod.rs | 7 ++- src/storage/traits.rs | 6 +- 7 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/storage/github.rs diff --git a/Cargo.toml b/Cargo.toml index f75de766..574781b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ chrono = "0.2" clap = "2.27.1" filetime = "0.1" flate2 = "0.2" +#hubcaps = { git = "https://github.com/lalbuild/hubcaps" } hyper = "0.10.9" hyper-native-tls = "0.2.2" log = "0.3.5" diff --git a/src/core/errors.rs b/src/core/errors.rs index a7cc9f06..9191e420 100644 --- a/src/core/errors.rs +++ b/src/core/errors.rs @@ -2,6 +2,7 @@ use std::fmt; use std::io; use hyper; use serde_json; +use hubcaps; /// The one and only error type for the lal library /// @@ -16,6 +17,8 @@ pub enum CliError { Parse(serde_json::error::Error), /// Errors propagated from `hyper` Hype(hyper::Error), + /// Errors propagated form `hubcaps + Github(hubcaps::Error), // main errors /// Manifest file not found in working directory @@ -137,6 +140,7 @@ impl fmt::Display for CliError { } CliError::Parse(ref err) => err.fmt(f), CliError::Hype(ref err) => err.fmt(f), + CliError::Github(ref err) => err.fmt(f), CliError::MissingManifest => { write!(f, "No manifest.json found - are you at repository toplevel?") @@ -270,6 +274,12 @@ impl From for CliError { fn from(err: serde_json::error::Error) -> CliError { CliError::Parse(err) } } +impl From for CliError { + fn from(err: hubcaps::Error) -> CliError { CliError::Github(err) } +} + + + /// Type alias to stop having to type out `CliError` everywhere. /// /// Most functions can simply add the return type `LalResult` for some `T`, diff --git a/src/lib.rs b/src/lib.rs index 69d852f5..a91f1c81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ extern crate tar; extern crate flate2; extern crate ansi_term; extern crate sha1; +extern crate hubcaps; #[macro_use] extern crate log; extern crate walkdir; diff --git a/src/main.rs b/src/main.rs index f1bbcbf8..f2358742 100644 --- a/src/main.rs +++ b/src/main.rs @@ -566,6 +566,9 @@ fn main() { &BackendConfiguration::Local(ref local_cfg) => { Box::new(LocalBackend::new(&local_cfg, &config.cache)) } + &BackendConfiguration::Github(ref gh_cfg) => { + Box::new(GithubBackend::new(&gh_cfg, &config.cache)) + } }; // Ensure SSL is initialized before using the backend diff --git a/src/storage/github.rs b/src/storage/github.rs new file mode 100644 index 00000000..69100092 --- /dev/null +++ b/src/storage/github.rs @@ -0,0 +1,126 @@ +#![allow(missing_docs)] +#![allow(unused_variables)] +#![allow(unused_imports)] +use std::vec::Vec; + +use std::fs::File; +use std::path::{Path, PathBuf}; + + +use hyper::Client; +use hyper::net::HttpsConnector; +use hyper_native_tls::NativeTlsClient; +use hubcaps::{Credentials, Github}; + +use hubcaps::releases::{Release, Releases, ReleaseOptions, ReleaseOptionsBuilder}; + +use core::{CliError, LalResult}; + + +/// Github credentials +#[derive(Serialize, Deserialize, Clone)] +pub struct GithubCredentials { + /// Personal access token with upload access + pub token: String, +} + +/// Static Github locations +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct GithubConfig { + /// Github organisation + pub organisation: String, + /// Optional upload credentials + pub credentials: Option, +} + +use super::{Backend, Component}; + +/// Everything we need for Github to implement the Backend trait +pub struct GithubBackend { + /// Github config and credentials + pub config: GithubConfig, + /// Cache directory + pub cache: String, + /// Github client with a tls configured hyper client + pub client: Github, +} + +impl GithubBackend { + pub fn new(cfg: &GithubConfig, cache: &str) -> Self { + let creds = if let Some(c) = cfg.credentials.clone() { + Credentials::Token(c.token) + } else { + Credentials::default() + }; + let github = Github::new( + format!("lal/{}", env!("CARGO_PKG_VERSION")), + Client::with_connector(HttpsConnector::new(NativeTlsClient::new().unwrap())), + creds + ); + + GithubBackend { + config: cfg.clone(), + client: github, + cache: cache.into(), + } + } +} + + +/// Artifact backend trait for `GithubBackend` +/// +/// This is intended to be used by the caching trait `CachedBackend`, but for +/// specific low-level use cases, these methods can be used directly. +impl Backend for GithubBackend { + fn get_versions(&self, name: &str, loc: &str) -> LalResult> { + unimplemented!(); + } + + fn get_latest_version(&self, name: &str, loc: &str) -> LalResult { + unimplemented!(); + } + + fn get_component_info( + &self, + name: &str, + version: Option, + loc: &str, + ) -> LalResult { + unimplemented!(); + } + + fn publish_artifact(&self, name: &str, version: u32, env: &str) -> LalResult<()> { + // this fn basically assumes all the sanity checks have been performed + // files must exist and lockfile must be sensible + let artdir = Path::new("./ARTIFACT"); + let tarball = artdir.join(format!("{}.tar.gz", name)); + let lockfile = artdir.join("lockfile.json"); + + + // 1. create a release + // TODO: needs sha from lockfile? + let res = Releases::new(&self.client, self.config.organisation.clone(), name); + let opts = ReleaseOptionsBuilder::new(version.to_string()).build(); + let release : Release = res.create(&opts)?; + + // 2. create an asset on this release + // TODO: this part of the api is missing from hubcaps + + // uri prefix if specific env upload + //let prefix = format!("env/{}/", env); + //let tar_uri = format!("{}{}/{}/{}.tar.gz", prefix, name, version, name); + //let mut tarf = File::open(tarball)?; + //upload_artifact(&self.config, &tar_uri, &mut tarf)?; + + //let mut lockf = File::open(lockfile)?; + //let lf_uri = format!("{}{}/{}/lockfile.json", prefix, name, version); + //upload_artifact(&self.config, &lf_uri, &mut lockf)?; + unimplemented!(); + } + + fn get_cache_dir(&self) -> String { self.cache.clone() } + + fn raw_fetch(&self, url: &str, dest: &PathBuf) -> LalResult<()> { + unimplemented!(); + } +} diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 1e328c32..5133f656 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -2,15 +2,18 @@ pub use self::traits::{BackendConfiguration, Backend, CachedBackend, Component}; pub use self::artifactory::{ArtifactoryConfig, Credentials, ArtifactoryBackend}; pub use self::local::{LocalConfig, LocalBackend}; +pub use self::github::{GithubConfig, GithubCredentials, GithubBackend}; // Some special exports for lal upgrade - canonical releases are on artifactory atm #[cfg(feature = "upgrade")] pub use self::artifactory::{LatestLal, get_latest_lal_version, http_download_to_path}; mod traits; -mod artifactory; -mod local; mod download; +mod local; +mod artifactory; +mod github; + #[cfg(feature = "progress")] mod progress; diff --git a/src/storage/traits.rs b/src/storage/traits.rs index be9c76da..ffeef45f 100644 --- a/src/storage/traits.rs +++ b/src/storage/traits.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use core::LalResult; -use super::{ArtifactoryConfig, LocalConfig}; +use super::{ArtifactoryConfig, LocalConfig, GithubConfig}; /// An enum struct for the currently configured `Backend` /// @@ -16,6 +16,10 @@ pub enum BackendConfiguration { /// Config for the `LocalBackend` #[serde(rename = "local")] Local(LocalConfig), + + /// Config for the `GithubBackend` + #[serde(rename = "github")] + Github(GithubConfig), } /// Artifactory is the default backend