-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/v0.1.0' into main
- Loading branch information
Showing
18 changed files
with
781 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: Develop | ||
on: | ||
push: | ||
branches: | ||
- develop | ||
- main | ||
pull_request: | ||
branches: | ||
- develop | ||
- main | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Install latest nightly | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
toolchain: nightly | ||
override: true | ||
components: rustfmt, clippy | ||
- name: Run cargo build | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: build | ||
args: --package gtm-sync --bin gtm-sync --release | ||
- uses: actions/upload-artifact@v2 | ||
with: | ||
name: gtm-sync | ||
path: ./target/release/gtm-sync |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
name: Release | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
release_version: | ||
description: 'Release version' | ||
required: true | ||
|
||
jobs: | ||
build-linux: | ||
runs-on: ubuntu-latest | ||
env: | ||
APP_NAME: 'gtm-sync' | ||
MAINTAINER: 'DEVELOPEST' | ||
DESC: 'gtm-sync client for linux' | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Install latest nightly | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
toolchain: nightly | ||
override: true | ||
components: rustfmt, clippy | ||
- name: Run cargo build | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: build | ||
args: --package gtm-sync --bin gtm-sync --release | ||
- uses: actions/upload-artifact@v2 | ||
with: | ||
name: gtm-sync | ||
path: ./target/release/gtm-sync | ||
- name: Prepare deb package | ||
run: | | ||
mkdir -p .debpkg/usr/bin | ||
cp ./target/release/gtm-sync .debpkg/usr/bin | ||
chmod +x .debpkg/usr/bin | ||
- name: Build deb package | ||
uses: jiro4989/build-deb-action@v2 | ||
with: | ||
package: ${{ env.APP_NAME }} | ||
package_root: .debpkg | ||
maintainer: ${{ env.MAINTAINER }} | ||
version: ${{ github.event.inputs.release_version }} | ||
arch: 'amd64' | ||
desc: ${{ env.DESC }} | ||
- name: Upload deb package | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: gtm-sync-debian | ||
path: | | ||
./*.deb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[development] | ||
address = "localhost" | ||
port = 8090 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,63 @@ | ||
|
||
use serde_derive::{Serialize, Deserialize}; | ||
use std::fs; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct SyncConfig { | ||
pub target_host: String, | ||
pub target_port: Option<u16>, | ||
pub port: Option<u16>, | ||
pub repositories_base_path: String, | ||
pub repositories: Vec<Repository>, | ||
use lazy_static::lazy_static; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::config::repository::{generate_credentials_from_clone_url, Repository}; | ||
|
||
lazy_static! { | ||
pub static ref CONFIG_PATH: String = "./config.toml".to_string(); | ||
} | ||
|
||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct Repository { | ||
pub url: String, | ||
pub path: String, | ||
pub ssh_private_key: Option<String>, | ||
pub struct Config { | ||
target_host: String, | ||
target_port: Option<u16>, | ||
pub port: Option<u16>, | ||
pub address: Option<String>, | ||
pub access_token: Option<String>, | ||
pub ssh_public_key: Option<String>, | ||
pub ssh_private_key: Option<String>, | ||
pub ssh_user: Option<String>, | ||
pub ssh_passphrase: Option<String>, | ||
pub repositories_base_path: String, | ||
#[serde(skip_serializing_if = "Vec::is_empty", default)] | ||
pub repositories: Vec<Repository>, | ||
} | ||
|
||
pub fn load(config_file: &String) -> SyncConfig { | ||
pub fn load(config_file: &String) -> Config { | ||
let content = fs::read_to_string(config_file).expect("Unable to read config!"); | ||
return toml::from_str(&content).expect("Unable to deserialize config!"); | ||
} | ||
|
||
pub fn save(config_file: &String, config: &SyncConfig) { | ||
pub fn save(config_file: &String, config: &Config) { | ||
let content = toml::to_string(config).expect("Unable to serialize config!"); | ||
fs::write(config_file, content).expect("Unable to save config!"); | ||
} | ||
|
||
impl Config { | ||
pub fn get_target_url(&self) -> String { | ||
return format!("{}:{}", self.target_host, self.target_port.unwrap_or(8000)); | ||
} | ||
|
||
pub fn get_sync_url(&self) -> String { | ||
return format!("{}:{}", | ||
self.address.clone().unwrap_or("localhost".to_string()), | ||
self.port.clone().unwrap_or(8000) | ||
); | ||
} | ||
|
||
pub fn generate_path_from_git_url(&self, url: &String) -> String { | ||
let (provider, user, repo) = generate_credentials_from_clone_url(url); | ||
return format!("{}/{}/{}/{}", self.repositories_base_path.trim_end_matches("/"), provider, user, repo); | ||
} | ||
|
||
pub fn generate_path_from_provider_user_repo(&self, | ||
provider: &String, | ||
user: &String, | ||
repo: &String, | ||
) -> String { | ||
return format!("{}/{}/{}/{}", self.repositories_base_path.trim_end_matches("/"), provider, user, repo); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod config; | ||
pub mod repository; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use lazy_static::lazy_static; | ||
use regex::Regex; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
lazy_static! { | ||
static ref PATH_FROM_URL_REGEX: Regex = | ||
Regex::new(r#"(git@|https://)([a-zA-Z0-9.]+)[:/]([a-zA-Z0-9-]+)/([a-zA-Z0-9-]+)\.git"#).unwrap(); | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone)] | ||
pub struct Repository { | ||
pub url: String, | ||
pub path: String, | ||
pub ssh_private_key: Option<String>, | ||
pub ssh_public_key: Option<String>, | ||
pub ssh_user: Option<String>, | ||
pub ssh_passphrase: Option<String>, | ||
} | ||
|
||
pub fn generate_credentials_from_clone_url(url: &String) -> (String, String, String) { | ||
let caps = PATH_FROM_URL_REGEX.captures(url).unwrap(); | ||
return (caps.get(2).map_or("provider".to_string(), |m| m.as_str().to_string()), | ||
caps.get(3).map_or("user".to_string(), |m| m.as_str().to_string()), | ||
caps.get(4).map_or("repo".to_string(), |m| m.as_str().to_string())); | ||
} | ||
|
||
impl Repository {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#![deny(warnings)] | ||
|
||
use std::fs; | ||
use std::path::Path; | ||
|
||
use git2::{BranchType, Error, FetchOptions, Note, RemoteCallbacks, Repository}; | ||
use git2::build::RepoBuilder; | ||
|
||
use crate::gtm::gtm; | ||
use crate::config::repository; | ||
use crate::config::config::Config; | ||
|
||
static GTM_NOTES_REF: &str = "refs/notes/gtm-data"; | ||
static GTM_NOTES_REF_SPEC: &str = "+refs/notes/gtm-data:refs/notes/gtm-data"; | ||
static DEFAULT_ORIGIN: &str = "origin"; | ||
static ORIGIN_PREFIX: &str = "refs/remotes/origin/"; | ||
static ORIGIN_HEAD: &str = "refs/remotes/origin/HEAD"; | ||
|
||
pub fn clone_or_open(repo_config: &repository::Repository, cfg: &Config) -> Result<Repository, Error> { | ||
let path = Path::new(&repo_config.path); | ||
|
||
if path.exists() { | ||
let repo = Repository::open(path); | ||
if repo.is_ok() { | ||
return repo; | ||
} | ||
let _remove = fs::remove_dir_all(&path) | ||
.expect(&*format!("Unable to remove dir: {}", repo_config.path)); | ||
return clone_or_open(&repo_config, &cfg); | ||
} | ||
|
||
let fo = generate_fetch_options(&repo_config, &cfg); | ||
|
||
return RepoBuilder::new() | ||
.fetch_options(fo) | ||
.clone(&repo_config.url, Path::new(&repo_config.path)); | ||
} | ||
|
||
fn generate_fetch_options<'a>(repo_config: &'a repository::Repository, cfg: &'a Config) -> FetchOptions<'a> { | ||
let mut cb = RemoteCallbacks::new(); | ||
let repo_config = repo_config.clone(); | ||
cb.credentials(move |_c, _o, t| { | ||
if t.is_ssh_key() { | ||
return git2::Cred::ssh_key( | ||
&repo_config.ssh_user.as_ref() | ||
.unwrap_or(cfg.ssh_user.as_ref().unwrap_or(&"git".to_string())), | ||
Option::from(Path::new(&repo_config.ssh_public_key.as_ref() | ||
.unwrap_or(cfg.ssh_public_key.as_ref().unwrap_or(&"".to_string())))), | ||
&Path::new(&repo_config.ssh_private_key.as_ref() | ||
.unwrap_or(cfg.ssh_private_key.as_ref().unwrap_or(&"".to_string()))), | ||
repo_config.ssh_passphrase.as_ref() | ||
.or(cfg.ssh_passphrase.as_ref()).map(|x| &**x), | ||
) | ||
} | ||
return git2::Cred::default(); | ||
}); | ||
|
||
let mut fo = FetchOptions::new(); | ||
fo.remote_callbacks(cb); | ||
return fo; | ||
} | ||
|
||
pub fn fetch(repo: &Repository, repo_config: &repository::Repository, cfg: &Config) { | ||
let mut remote = repo.find_remote(DEFAULT_ORIGIN) | ||
.expect("Unable to find remote 'origin'"); | ||
let mut ref_added = false; | ||
let refs = remote.fetch_refspecs().unwrap(); | ||
for i in 0..refs.len() { | ||
if refs.get(i).unwrap() == GTM_NOTES_REF_SPEC { | ||
ref_added = true; | ||
break; | ||
} | ||
} | ||
if !ref_added { | ||
repo.remote_add_fetch(DEFAULT_ORIGIN, GTM_NOTES_REF_SPEC) | ||
.expect("Unable to add fetch ref spec for gtm-data!"); | ||
remote = repo.find_remote(DEFAULT_ORIGIN) | ||
.expect("Unable to find remote 'origin'"); | ||
} | ||
|
||
let branches = repo.branches(Option::from(BranchType::Remote)).unwrap(); | ||
let mut fetch_refs: Vec<String> = vec![]; | ||
for branch in branches { | ||
let (branch, _) = branch.unwrap(); | ||
let refspec = branch.get() | ||
.name() | ||
.unwrap() | ||
.strip_prefix(ORIGIN_PREFIX) | ||
.unwrap(); | ||
if refspec != "HEAD" { | ||
fetch_refs.push(format!("refs/heads/{}", refspec.to_string())); | ||
} | ||
} | ||
fetch_refs.push(GTM_NOTES_REF.parse().unwrap()); | ||
|
||
let mut fo = generate_fetch_options(repo_config, cfg); | ||
remote.fetch(&fetch_refs, Option::from(&mut fo), None) | ||
.expect("Error fetching data!"); | ||
remote.disconnect().unwrap(); | ||
} | ||
|
||
pub fn read_commits(repo: &Repository) -> Result<Vec<gtm::Commit>, Error> { | ||
let mut commits: Vec<gtm::Commit> = Vec::new(); | ||
let mut revwalk = repo.revwalk().expect("Unable to revwalk!"); | ||
revwalk.set_sorting(git2::Sort::TOPOLOGICAL).expect("Unable to set revwalk sorting!"); | ||
revwalk.set_sorting(git2::Sort::REVERSE).expect("Unable to reverse revalk sorting!"); | ||
let branches = repo.branches(Option::from(BranchType::Remote)).unwrap(); | ||
for branch in branches { | ||
let (branch, _) = branch.unwrap(); | ||
let refspec = branch.get().name().unwrap(); | ||
if refspec == ORIGIN_HEAD { | ||
continue | ||
} | ||
let _ = revwalk.push_ref(refspec); | ||
} | ||
|
||
for commit_oid in revwalk { | ||
let commit_oid = commit_oid?; | ||
let commit = repo.find_commit(commit_oid)?; | ||
let notes: Vec<Note> = repo.notes(Option::from(GTM_NOTES_REF))? | ||
.map(|n| n.unwrap()) | ||
.filter(|n| n.1 == commit_oid) | ||
.map(|n| repo.find_note(Option::from(GTM_NOTES_REF), n.1).unwrap()) | ||
.collect(); | ||
|
||
let res = gtm::parse_commit(&repo, &commit, ¬es)?; | ||
commits.push(res); | ||
} | ||
return Result::Ok(commits); | ||
} |
Oops, something went wrong.