use crate::action::{Action, PushForward};
use crate::command_push::stackable_option_tokens;
use crate::external_hooks::external_hooks_warning;
use crate::lfs_pre_push::uses_lfs;
use crate::lfs_upload_plan::settings_from_snapshot;
use crate::config_snapshot::{ConfigSnapshot, read_config_snapshot};
use crate::push_stacking::STACKED_PUSH_MARKER;
use crate::command_push::parse_push_region;
use crate::child_environment::environment_value;
use crate::forwarded_lock_notice::{forwarded_lock_notice, is_covered};
use crate::stale_ref_lock_judge::Judge;
use crate::forwarded_command::{ResolvedCommand, resolve_forwarded_command};
use crate::transaction_git::GitContext;
use std::ffi::OsString;
use std::path::Path;
fn needs_lfs_upload(
command: &ResolvedCommand,
real_git: &Path,
overlay: &[(OsString, OsString)],
) -> (bool, String, Option<Vec<(String, String)>>) {
if command.word() != b"push" {
return (false, String::new(), None);
}
let dry_run: bool = match parse_push_region(command.region(), &[]) {
Ok(region) => region.dry_run,
Err(_refused) => false,
};
let context: GitContext = GitContext {
real_git: real_git.to_path_buf(),
overlay: overlay.to_vec(),
global_prefix: command.arguments[..command.subcommand_index].to_vec(),
common_dir: None,
};
let snapshot: Option<ConfigSnapshot> = match std::env::current_dir() {
Ok(directory) => read_config_snapshot(&context, directory.as_path()),
Err(_) => None,
};
let warning: String = external_hooks_warning(snapshot.as_ref()).unwrap_or_default();
if dry_run {
return (false, warning, None);
}
return match snapshot {
Some(found) => {
let uses: bool = uses_lfs(&found);
let settings: Option<Vec<(String, String)>> = if uses { Some(settings_from_snapshot(&found)) } else { None };
(uses, warning, settings)
}
None => (true, warning, None),
};
}
pub(crate) fn stack_if_push(action: Action, environment: &[(OsString, OsString)]) -> Action {
let (real_git, arguments, overlay, copy, stderr) = match action {
Action::Forward {
real_git,
arguments,
overlay,
stderr,
} => (real_git, arguments, overlay, None, stderr),
Action::ForwardSettled {
real_git,
arguments,
overlay,
copy,
stderr,
} => (real_git, arguments, overlay, Some(copy), stderr),
other => return other,
};
let context: GitContext = GitContext {
real_git: real_git.clone(),
overlay: overlay.clone(),
global_prefix: Vec::new(),
common_dir: None,
};
let command: ResolvedCommand = resolve_forwarded_command(&context, arguments.as_slice());
let (lfs, hook_warning, lfs_settings): (bool, String, Option<Vec<(String, String)>>) =
needs_lfs_upload(&command, real_git.as_path(), overlay.as_slice());
let stderr_with_warning: String = format!("{stderr}{hook_warning}");
let stacked_already: bool = environment_value(environment, STACKED_PUSH_MARKER).is_some();
let stack: bool =
!stacked_already && command.word() == b"push" && stackable_option_tokens(command.region()).is_some();
if stack || lfs {
return Action::ForwardPush {
forward: Box::new(PushForward {
real_git,
subcommand_index: command.subcommand_index,
arguments: command.arguments,
overlay,
copy,
environment: environment.to_vec(),
lfs,
lfs_settings,
stack,
}),
stderr: stderr_with_warning,
};
}
let lock_notice: String = if is_covered(command.word()) {
forwarded_lock_notice(command.word(), &command.arguments[..command.subcommand_index], environment, &Judge::here())
} else {
String::new()
};
let stderr_with_locks: String = format!("{stderr_with_warning}{lock_notice}");
let forwarded: Vec<OsString> = arguments;
return match copy {
Some(facts) => Action::ForwardSettled {
real_git,
arguments: forwarded,
overlay,
copy: facts,
stderr: stderr_with_locks,
},
None => Action::Forward {
real_git,
arguments: forwarded,
overlay,
stderr: stderr_with_locks,
},
};
}