Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions cli/src/commands/apply_manual.rs

This file was deleted.

15 changes: 0 additions & 15 deletions cli/src/commands/compare.rs

This file was deleted.

2 changes: 1 addition & 1 deletion cli/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct NameDependenciesArgs {
}


pub fn init_command(args: &InitArgs) -> Result<()> {
pub fn _init_command(args: &InitArgs) -> Result<()> {
println!("Planning project onboarding");

println!(" > Generating dependency tree");
Expand Down
14 changes: 0 additions & 14 deletions cli/src/commands/mirror_dependencies.rs

This file was deleted.

6 changes: 1 addition & 5 deletions cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
pub mod compare;
pub mod dependencies;
pub mod mirror_dependencies;

pub mod init;
pub mod apply_manual;
pub mod onboard;

pub mod replicate;
pub mod replication;
9 changes: 0 additions & 9 deletions cli/src/commands/onboard.rs

This file was deleted.

43 changes: 43 additions & 0 deletions cli/src/commands/replication/apply.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::{fs::create_dir_all, path::PathBuf};

use anyhow::Result;
use clap::Parser;
use source_wand_common::{project_manipulator::{local_project_manipulator::LocalProjectManipulator, project_manipulator::ProjectManipulator}, utils::read_yaml_file::read_yaml_file};
use source_wand_replication::model::{package_destination::PackageDestination, package_origin::PackageOrigin, replication_plan::ReplicationPlan};

#[derive(Debug, Parser)]
pub struct ReplicationApplyArgs;

pub fn replicate_apply_command(_args: &ReplicationApplyArgs) -> Result<()> {
let replication_plan: ReplicationPlan = read_yaml_file("source-wand/replication-plan.yaml")?;

for package in replication_plan.packages {
if let PackageOrigin::GoCache(origin) = package.origin {
let PackageDestination::Git(destination) = package.destination;
let dependency_directory: PathBuf = PathBuf::from(format!("./source-wand/dependencies/{}/{}", origin.name, origin.version));
create_dir_all(&dependency_directory)?;

let sh: LocalProjectManipulator = LocalProjectManipulator::new(dependency_directory, true);

println!("Fetching {} ({}) from the local Go Cache", origin.name, origin.version);
sh.run_shell(format!("cp -r {}/* .", origin.path))?;

let ls_remote: Result<String> = sh.run_shell(format!("git ls-remote --exit-code --heads {} {}", destination.git, destination.reference));

if ls_remote.is_ok() {
println!("{} ({}) already exists on remote, skipping", origin.name, origin.version);
continue;
}

println!("Pushing {} ({}) source code to remote repository", origin.name, origin.version);
sh.run_shell("git init".to_string())?;
sh.run_shell(format!("git remote add origin {}", destination.git))?;
sh.run_shell(format!("git checkout --orphan {}", destination.reference))?;
sh.run_shell("git add .".to_string())?;
sh.run_shell("git commit -m 'Replicate source code'".to_string())?;
sh.run_shell(format!("git push -u origin {}", destination.reference))?;
}
}

Ok(())
}
30 changes: 30 additions & 0 deletions cli/src/commands/replication/init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::{env, path::PathBuf};

use anyhow::Result;
use clap::Parser;
use source_wand_common::utils::write_yaml_file::write_yaml_file;
use source_wand_replication::model::{hooks::Hooks, package_destination_git::PackageDestinationGit, package_origin_git::PackageOriginGit, replication_manifest::ReplicationManifest};

#[derive(Debug, Parser)]
pub struct ReplicationInitArgs;

pub fn replicate_init_command(_args: &ReplicationInitArgs) -> Result<()> {
let working_directory: PathBuf = env::current_dir()?;
let project_name = working_directory
.file_name()
.and_then(|os_string| os_string.to_str())
.ok_or_else(|| anyhow::anyhow!("unknown"))?
.to_string();

let replication_manifest: ReplicationManifest = ReplicationManifest::new(
project_name,
Some(Hooks { before_all: None, before_each: None, after_each: None, after_all: None }),
PackageOriginGit::new("<url to your project's repository>".to_string(), "<reference to checkout>".to_string()),
PackageDestinationGit::new("<where to replicate your project>".to_string(), "<reference to push>".to_string()),
);

write_yaml_file(&replication_manifest, "replication.yaml")?;

println!("Replication project initialized.");
Ok(())
}
34 changes: 34 additions & 0 deletions cli/src/commands/replication/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use anyhow::Result;
use clap::{command, Parser, Subcommand};

use crate::commands::replication::{apply::{replicate_apply_command, ReplicationApplyArgs}, init::{replicate_init_command, ReplicationInitArgs}, plan::{replicate_plan_command, ReplicationPlanArgs}};

pub mod init;
pub mod plan;
pub mod apply;

#[derive(Debug, Parser)]
pub struct ReplicationArgs {
#[command(subcommand)]
pub command: ReplicationCommand,
}

#[derive(Debug, Subcommand)]
pub enum ReplicationCommand {
#[command(about = "Initialize a new deep replication project")]
Init(ReplicationInitArgs),

#[command(about = "Plan a deep replication and validate the replication is possible")]
Plan(ReplicationPlanArgs),

#[command(about = "Apply the deep replication plan")]
Apply(ReplicationApplyArgs),
}

pub fn replicate_command(args: &ReplicationArgs) -> Result<()> {
match &args.command {
ReplicationCommand::Init(args) => replicate_init_command(args),
ReplicationCommand::Plan(args) => replicate_plan_command(args),
ReplicationCommand::Apply(args) => replicate_apply_command(args),
}
}
120 changes: 120 additions & 0 deletions cli/src/commands/replication/plan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use std::{fs::create_dir_all, path::PathBuf};

use anyhow::Result;
use clap::Parser;
use serde_json::Value;
use source_wand_common::{project_manipulator::{local_project_manipulator::LocalProjectManipulator, project_manipulator::ProjectManipulator}, utils::{read_yaml_file::read_yaml_file, write_yaml_file::write_yaml_file}};
use source_wand_replication::model::{package::Package, package_destination::PackageDestination, package_destination_git::PackageDestinationGit, package_origin::PackageOrigin, package_origin_go_cache::PackageOriginGoCache, replication_manifest::ReplicationManifest, replication_plan::ReplicationPlan};

#[derive(Debug, Parser)]
pub struct ReplicationPlanArgs;

pub fn replicate_plan_command(_args: &ReplicationPlanArgs) -> Result<()> {
let replication_manifest: ReplicationManifest = read_yaml_file("replication.yaml")?;

match replication_manifest.origin {
PackageOrigin::Git(origin) => {
let top_level_directory: PathBuf = PathBuf::from("./source-wand/top-level/repository");
create_dir_all(&top_level_directory)?;

let top_level: LocalProjectManipulator = LocalProjectManipulator::new(top_level_directory, true);

top_level.run_shell(format!("git clone {} .", origin.git))?;
top_level.run_shell(format!("git checkout {}", origin.reference))?;

top_level.run_shell("go mod download all".to_string())?;

let mut packages: Vec<Package> = Vec::new();

let build_dependencies: serde_json::Value = serde_json::from_str(top_level.run_shell("go list -json -m all | jq -s".to_string())?.as_str())?;
if let Value::Array(build_dependencies) = build_dependencies {
for build_dependency in build_dependencies {
if let Value::Object(build_dependency) = build_dependency {
let name: String = build_dependency.get("Path").unwrap().as_str().unwrap_or_default().replace("/", "-");
let version: String = build_dependency.get("Version").unwrap_or(&Value::String(origin.reference.split('/').last().unwrap_or_default().to_string())).as_str().unwrap_or_default().to_string();
let cache_path: String = build_dependency.get("Dir").unwrap_or(&Value::String(String::new())).as_str().unwrap_or_default().to_string();

let (version_major, version_minor, version_patch, version_suffix, version_retrocompatible) = {
let mut major: String = String::new();
let mut minor: String = String::new();
let mut patch: String = String::new();
let mut suffix: String = String::new();

if version.starts_with('v') {
let parts: Vec<&str> = version.trim_start_matches('v').split('-').collect();
let semantic_version_parts: Vec<&str> = parts[0].split('.').collect();

if semantic_version_parts.len() > 0 {
major = semantic_version_parts[0].to_string();
}
if semantic_version_parts.len() > 1 {
minor = semantic_version_parts[1].to_string();
}
if semantic_version_parts.len() > 2 {
patch = semantic_version_parts[2].to_string();
}

if parts.len() > 1 {
suffix = format!("-{}", parts[1..].join("-"));
}
}

let retrocompatible: String =
if suffix.is_empty() {
if major == "0".to_string() {
format!("{}.{}.{}", major.clone(), minor, patch)
}
else {
major.clone()
}
}
else {
format!("{}.{}.{}-{}", major, minor, patch, suffix)
};

(major, minor, patch, suffix, retrocompatible)
};

let PackageDestination::Git(package_destination) = &replication_manifest.destination_template;
let package_destination_url: String = package_destination.git
.replace("$NAME", &name)
.replace("$VERSION_MAJOR", &version_major)
.replace("$VERSION_MINOR", &version_minor)
.replace("$VERSION_PATCH", &version_patch)
.replace("$VERSION_SUFFIX", &version_suffix)
.replace("$VERSION_RETROCOMPATIBLE", &version_retrocompatible)
.replace("$VERSION", &version);
let package_destination_reference: String = package_destination.reference
.replace("$NAME", &name)
.replace("$VERSION_MAJOR", &version_major)
.replace("$VERSION_MINOR", &version_minor)
.replace("$VERSION_PATCH", &version_patch)
.replace("$VERSION_SUFFIX", &version_suffix)
.replace("$VERSION_RETROCOMPATIBLE", &version_retrocompatible)
.replace("$VERSION", &version);

let package: Package = Package::new(
0,
PackageOriginGoCache::new(name, version, cache_path),
PackageDestinationGit::new(
package_destination_url,
package_destination_reference,
),
Vec::new(),
);

packages.push(package);
}
}
}

let replication_plan: ReplicationPlan = ReplicationPlan::new(replication_manifest.project, replication_manifest.hooks, packages);
write_yaml_file(&replication_plan, "./source-wand/replication-plan.yaml")?;

top_level.cleanup();
},
PackageOrigin::GoCache(_origin) => {},
}

Ok(())
}
46 changes: 3 additions & 43 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,13 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use commands::{
apply_manual::{
apply_manual_command,
ApplyManualArgs
},
compare::{
compare_command,
CompareArgs
},
dependencies::{
dependencies_command,
DependenciesArgs
},
init::{
init_command,
InitArgs
},
mirror_dependencies::{
mirror_dependencies_command,
MirrorDependenciesArgs
},
onboard::{
onboard_command,
OnboardArgs
}
};

use crate::commands::replicate::{replicate_command, ReplicateArgs};
use crate::commands::replication::{replicate_command, ReplicationArgs};

mod commands;

Expand All @@ -42,33 +22,13 @@ enum Command {
#[command(about = "Find the dependency tree of a project.")]
Dependencies(DependenciesArgs),

#[command(about = "Compare dependency lists")]
Compare(CompareArgs),

#[command(about = "Mirror dependencies")]
MirrorDependencies(MirrorDependenciesArgs),

#[command(about = "Initialize the onboarding of a project")]
Init(InitArgs),

#[command(about = "Try to add your manual configurations to automated onboarding")]
ApplyManual(ApplyManualArgs),

#[command(about = "Onboard a project and its dependencies")]
Onboard(OnboardArgs),

#[command(about = "Replicate a project along with its dependencies")]
Replicate(ReplicateArgs)
Replication(ReplicationArgs)
}

fn main() -> Result<()> {
match Cli::parse().command {
Command::Dependencies(args) => dependencies_command(&args),
Command::Compare(args) => compare_command(&args),
Command::MirrorDependencies(args) => mirror_dependencies_command(&args),
Command::Init(args) => init_command(&args),
Command::ApplyManual(args) => apply_manual_command(&args),
Command::Onboard(args) => onboard_command(&args),
Command::Replicate(args) => replicate_command(&args),
Command::Replication(args) => replicate_command(&args),
}
}
6 changes: 5 additions & 1 deletion common/src/project_manipulator/local_project_manipulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ impl ProjectManipulator for LocalProjectManipulator {
fn try_run_shell(&self, command: String, retries: u32) -> Result<String> {
self.to_any().try_run_shell(command, retries)
}


fn get_working_directory(&self) -> PathBuf {
self.project_root.clone()
}

fn cleanup(&self) {
if self.should_cleanup {
let _ = self.run_shell(
Expand Down
4 changes: 4 additions & 0 deletions common/src/project_manipulator/lxd_project_manipulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ impl ProjectManipulator for LxdProjectManipulator {
self.to_any().try_run_shell(command, retries)
}

fn get_working_directory(&self) -> PathBuf {
self.project_root.clone()
}

fn cleanup(&self) {
let _ = self.run_shell(
format!(
Expand Down
Loading