Skip to content

Commit

Permalink
git local support and make paths and deploy path consistent, fix config
Browse files Browse the repository at this point in the history
  • Loading branch information
tiptenbrink committed Jan 13, 2024
1 parent 9f7e82b commit 57bf800
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 170 deletions.
80 changes: 50 additions & 30 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use thiserror::Error as ThisError;
use tracing::span;
use tracing::{debug, Level};

pub(crate) const DEFAULT_INFER: &str = "default_infer";
pub(crate) const DEFAULT_GIT_REMOTE: &str = "tidploy_default_git_remote";
pub(crate) const DEFAULT_GIT_LOCAL: &str = "tidploy_default_git_local";
pub(crate) const TIDPLOY_DEFAULT: &str = "tidploy_default";
pub(crate) const DEFAULT: &str = "default";

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand Down Expand Up @@ -53,7 +53,7 @@ struct Cli {

#[derive(Subcommand, Debug)]
enum Commands {
/// Save secret with key until reboot
/// Save secret with key until reboot. Use the --tag option to scope it to a specific commit.
Secret { key: String },
/// Download tag or version with specific env, run automatically if using deploy
Download {
Expand Down Expand Up @@ -130,16 +130,20 @@ fn switch_to_revision(
path = deploy_path_str
);
let _enter = checkedout_span.enter();
let deploy_path = state.deploy_path.to_path(repo_path);

// Checks out the correct commit
checkout(repo_path, &state.commit_sha).map_err(ErrorRepr::Repo)?;
// Does a sparse checkout of the deploy path
checkout_path(repo_path, &state.deploy_path).map_err(ErrorRepr::Repo)?;

// Creates state from the newly checked out path and state, which should now contain the correct config
let state =
create_state_create(cli_state, Some(&deploy_path), true).map_err(ErrorRepr::Load)?;
let state = create_state_create(
cli_state,
Some(repo_path),
Some(state.deploy_path.as_relative_path()),
true,
)
.map_err(ErrorRepr::Load)?;

Ok(state)
}
Expand Down Expand Up @@ -182,8 +186,8 @@ fn download_command(
// The preswitch stage creates state from the recently created repo, determining which commit sha to use for
// the checkout and which deploy path to use
let head_span = span!(Level::DEBUG, "preswitch").entered();
let state =
create_state_create(cli_state.clone(), Some(&repo_path), true).map_err(ErrorRepr::Load)?;
let state = create_state_create(cli_state.clone(), Some(&repo_path), None, true)
.map_err(ErrorRepr::Load)?;
head_span.exit();

let state = switch_to_revision(cli_state, state, &repo_path)?;
Expand Down Expand Up @@ -218,8 +222,8 @@ fn prepare_command(
// The preswitch stage creates state from the recently created repo, determining which commit sha to use for
// the checkout and which deploy path to use
let head_span = span!(Level::DEBUG, "preswitch").entered();
let state =
create_state_create(cli_state.clone(), Some(&repo_path), true).map_err(ErrorRepr::Load)?;
let state = create_state_create(cli_state.clone(), Some(&repo_path), None, true)
.map_err(ErrorRepr::Load)?;
head_span.exit();

let state = switch_to_revision(cli_state, state, &repo_path)?;
Expand Down Expand Up @@ -268,15 +272,16 @@ pub(crate) fn run_cli() -> Result<(), Error> {
Commands::Secret { key } => {
let auth_span = span!(Level::DEBUG, "auth");
let _auth_enter = auth_span.enter();
let state = create_state_create(cli_state, None, false).map_err(ErrorRepr::Load)?;
let state =
create_state_create(cli_state, None, None, false).map_err(ErrorRepr::Load)?;

secret_command(&state, key).map_err(ErrorRepr::Auth)?;

Ok(())
}
Commands::Download { repo_only } => {
let state =
create_state_create(cli_state.clone(), None, false).map_err(ErrorRepr::Load)?;
let state = create_state_create(cli_state.clone(), None, None, false)
.map_err(ErrorRepr::Load)?;
download_command(cli_state, state.repo, repo_only)?;

Ok(())
Expand All @@ -292,8 +297,8 @@ pub(crate) fn run_cli() -> Result<(), Error> {

// This one we must manually exit so we use 'entered'. The preprepare stage determines the "repo".
let enter_dl = span!(Level::DEBUG, "preprepare").entered();
let state =
create_state_create(cli_state.clone(), None, false).map_err(ErrorRepr::Load)?;
let state = create_state_create(cli_state.clone(), None, None, false)
.map_err(ErrorRepr::Load)?;
enter_dl.exit();

let state = prepare_command(cli_state.clone(), no_create, state.repo)?.unwrap();
Expand All @@ -311,14 +316,19 @@ pub(crate) fn run_cli() -> Result<(), Error> {
extract_archive(&archive_path, tmp_dir, &archive_name).map_err(ErrorRepr::Repo)?;

let target_path_root = tmp_dir.join(archive_name);
let target_path = state.deploy_path.to_path(target_path_root);
let state =
create_state_run(cli_state, executable, variables, Some(&target_path), true)
.map_err(ErrorRepr::Load)?;
let state = create_state_run(
cli_state,
executable,
variables,
Some(target_path_root.as_path()),
Some(state.deploy_path.as_relative_path()),
true,
)
.map_err(ErrorRepr::Load)?;

let state = extra_envs(state);

run_entrypoint(state.current_dir, &state.exe_name, state.envs)
run_entrypoint(state.deploy_dir(), &state.exe_name, state.envs)
.map_err(ErrorRepr::Exe)?;

Ok(())
Expand All @@ -331,7 +341,7 @@ pub(crate) fn run_cli() -> Result<(), Error> {
let _enter = span!(Level::DEBUG, "run");

// Only loads archive if it is given, otherwise path is None
let path = if let Some(archive) = archive {
let state = if let Some(archive) = archive {
let cache_dir = get_dirs().cache.as_path();
let archive_path = cache_dir
.join("archives")
Expand All @@ -343,23 +353,33 @@ pub(crate) fn run_cli() -> Result<(), Error> {
extract_archive(&archive_path, tmp_dir, &archive).map_err(ErrorRepr::Repo)?;
debug!("Extracted and loaded archive at {:?}", &extracted_path);

let state = create_state_create(cli_state.clone(), Some(&extracted_path), true)
.map_err(ErrorRepr::Load)?;
let target_path = state.deploy_path.to_path(&extracted_path);
let state =
create_state_create(cli_state.clone(), Some(&extracted_path), None, true)
.map_err(ErrorRepr::Load)?;

Some(target_path)
Some(state)
} else {
debug!("No archive provided to run command.");
None
};
let path_ref = path.as_deref();

let state = create_state_run(cli_state, executable, variables, path_ref, true)
.map_err(ErrorRepr::Load)?;
let root_dir = state.as_ref().map(|state| state.root_dir.as_path());
let deploy_path = state
.as_ref()
.map(|state| state.deploy_path.as_relative_path());

let state = create_state_run(
cli_state,
executable,
variables,
root_dir,
deploy_path,
true,
)
.map_err(ErrorRepr::Load)?;

let state = extra_envs(state);

run_entrypoint(&state.current_dir, &state.exe_name, state.envs)
run_entrypoint(state.deploy_dir(), &state.exe_name, state.envs)
.map_err(ErrorRepr::Exe)?;

Ok(())
Expand Down
14 changes: 7 additions & 7 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use relative_path::RelativePathBuf;
use relative_path::{RelativePath, RelativePathBuf};
use serde::Deserialize;
use std::{
collections::HashMap,
Expand Down Expand Up @@ -127,15 +127,15 @@ fn overwrite_config(root_config: DployConfig, overwrite_config: DployConfig) ->
/// Looks at config at start_path and appends levels from final_path, looking at a config at every level. It then
/// combines them.
pub(crate) fn traverse_configs(
start_path: PathBuf,
final_path: RelativePathBuf,
start_path: &Path,
final_path: &RelativePath,
) -> Result<DployConfig, ConfigError> {
debug!(
"Traversing configs from {:?} to relative {:?}",
start_path, final_path
);

let root_config = load_dploy_config(&start_path).map_err(|source| {
let root_config = load_dploy_config(start_path).map_err(|source| {
let msg = format!(
"Failed to load root config at path {:?} while traversing configs.",
start_path
Expand All @@ -146,13 +146,13 @@ pub(crate) fn traverse_configs(
let paths: Vec<PathBuf> = final_path
.components()
.scan(RelativePathBuf::new(), |state, component| {
state.join(component.as_str());
Some(state.to_path(&start_path))
state.push(component);
Some(state.to_path(start_path))
})
.collect();

let combined_config = paths.iter().try_fold(root_config, |state, path| {
let inner_config = load_dploy_config(&start_path);
let inner_config = load_dploy_config(path);

match inner_config {
Ok(config) => ControlFlow::Continue(overwrite_config(state, config)),
Expand Down
117 changes: 45 additions & 72 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,16 @@
use crate::errors::{GitError, RepoError, RepoParseError};

use crate::process::process_out;

use base64::engine::general_purpose::URL_SAFE_NO_PAD as B64USNP;
use base64::Engine;
use relative_path::RelativePath;
use spinoff::{spinners, Spinner};

use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::process::{Command as Cmd, Stdio};
use tracing::debug;

pub(crate) fn git_root_origin_url(path: &Path) -> Result<String, GitError> {
let git_origin_output = Cmd::new("git")
.current_dir(path)
.arg("config")
.arg("--get")
.arg("remote.origin.url")
.output()
.map_err(|e| {
GitError::from_io(
e,
"IO failure for git config get remote.origin.url!".to_owned(),
)
})?;

if !git_origin_output.status.success() {
return Err(GitError::from_f(
git_origin_output.status,
"Git get remote origin failed!".to_owned(),
));
}

let url = String::from_utf8(git_origin_output.stdout)
.map_err(|e| GitError::from_dec(e, "Failed to decode Git origin output!".to_owned()))?
.trim_end()
.to_owned();

debug!("Read remote url from git root origin: {}", url);

Ok(url)
}

pub(crate) fn relative_to_git_root(path: &Path) -> Result<String, GitError> {
let git_root_relative_output = Cmd::new("git")
.current_dir(path)
.arg("rev-parse")
.arg("--show-prefix")
.output()
.map_err(|e| GitError::from_io(e, "IO failure for get relative to git root!".to_owned()))?;

if !git_root_relative_output.status.success() {
return Err(GitError::from_f(
git_root_relative_output.status,
"Git get relative to root failed!".to_owned(),
));
}

Ok(String::from_utf8(git_root_relative_output.stdout)
.map_err(|e| {
GitError::from_dec(e, "Failed to decode Git relative to root path!".to_owned())
})?
.trim_end()
.to_owned())
}

#[derive(Debug, PartialEq)]
pub(crate) struct Repo {
pub(crate) name: String,
Expand Down Expand Up @@ -124,31 +69,59 @@ pub(crate) fn parse_repo_url(url: String) -> Result<Repo, RepoParseError> {
})
}

pub(crate) fn rev_parse_tag(tag: &str, path: &Path) -> Result<String, GitError> {
let parsed_tag_output = Cmd::new("git")
.current_dir(path)
.arg("rev-parse")
.arg(tag)
fn run_git<S: AsRef<OsStr>>(
current_dir: &Path,
args: Vec<S>,
op_name: &'static str,
) -> Result<String, GitError> {
let mut git_cmd = Cmd::new("git");
let mut git_cmd = git_cmd.current_dir(current_dir);

for a in args {
git_cmd = git_cmd.arg(a)
}

let git_output = git_cmd
.output()
.map_err(|e| GitError::from_io(e, "IO failure for parsing Git tag!".to_owned()))?;

if !parsed_tag_output.status.success() {
let err_out = process_out(
parsed_tag_output.stderr,
"Git parse tag failed! Could not decode output!".to_owned(),
)?;
let msg = format!("Git parse tag failed! err: {}", err_out);
return Err(GitError::from_f(parsed_tag_output.status, msg));
.map_err(|e| GitError::from_io(e, format!("IO failure for git {}!", op_name)))?;

if !git_output.status.success() {
return Err(GitError::from_f(
git_output.status,
format!("git {} failed!", op_name),
));
}

Ok(String::from_utf8(parsed_tag_output.stdout)
Ok(String::from_utf8(git_output.stdout)
.map_err(|e| {
GitError::from_dec(e, "Failed to decode Git relative to root path!".to_owned())
GitError::from_dec(e, format!("Failed to decode git output from {}!", op_name))
})?
.trim_end()
.to_owned())
}

pub(crate) fn git_root_origin_url(path: &Path) -> Result<String, GitError> {
let args = vec!["config", "--get", "remote.origin.url"];

let url = run_git(path, args, "get git root origin url")?;

debug!("Read remote url from git root origin: {}", url);

Ok(url)
}

pub(crate) fn git_root_dir(path: &Path) -> Result<String, GitError> {
let args = vec!["rev-parse", "--show-toplevel"];

run_git(path, args, "get git root dir")
}

pub(crate) fn rev_parse_tag(tag: &str, path: &Path) -> Result<String, GitError> {
let args = vec!["rev-parse", tag];

run_git(path, args, "rev parse tag")
}

pub(crate) fn repo_clone(
current_dir: &Path,
target_name: &str,
Expand Down
Loading

0 comments on commit 57bf800

Please sign in to comment.