use crate::core::index::EntryIndexer;
use crate::error::OxenError;
use crate::model::{LocalRepository, RemoteBranch};
use crate::opts::PullOpts;
pub async fn pull(repo: &LocalRepository) -> Result<(), OxenError> {
let indexer = EntryIndexer::new(repo)?;
let rb = RemoteBranch::default();
indexer
.pull(
&rb,
PullOpts {
should_pull_all: false,
should_update_head: true,
},
)
.await
}
pub async fn pull_shallow(repo: &LocalRepository) -> Result<(), OxenError> {
let indexer = EntryIndexer::new(repo)?;
let rb = RemoteBranch::default();
indexer
.pull(
&rb,
PullOpts {
should_pull_all: false,
should_update_head: true,
},
)
.await
}
pub async fn pull_all(repo: &LocalRepository) -> Result<(), OxenError> {
let indexer = EntryIndexer::new(repo)?;
let rb = RemoteBranch::default();
indexer
.pull(
&rb,
PullOpts {
should_pull_all: true,
should_update_head: true,
},
)
.await
}
pub async fn pull_remote_branch(
repo: &LocalRepository,
remote: &str,
branch: &str,
all: bool,
) -> Result<(), OxenError> {
let indexer = EntryIndexer::new(repo)?;
let rb = RemoteBranch {
remote: String::from(remote),
branch: String::from(branch),
};
indexer
.pull(
&rb,
PullOpts {
should_pull_all: all,
should_update_head: true,
},
)
.await
}
#[cfg(test)]
mod tests {
use crate::error::OxenError;
use crate::test;
use crate::{api, command};
#[tokio::test]
async fn test_flags_merge_conflict_on_pull() -> Result<(), OxenError> {
test::run_training_data_fully_sync_remote(|_, remote_repo| async move {
let remote_repo_copy = remote_repo.clone();
test::run_empty_dir_test_async(|user_a_repo_dir| async move {
let user_a_repo_dir_copy = user_a_repo_dir.join("user_a_repo");
let user_a_repo =
command::clone_url(&remote_repo.remote.url, &user_a_repo_dir_copy).await?;
test::run_empty_dir_test_async(|user_b_repo_dir| async move {
let user_b_repo_dir_copy = user_b_repo_dir.join("user_b_repo");
let user_b_repo =
command::clone_url(&remote_repo.remote.url, &user_b_repo_dir_copy).await?;
let new_file = "new_file.txt";
let new_file_path = user_a_repo.path.join(new_file);
let new_file_path = test::write_txt_file_to_path(new_file_path, "new file")?;
command::add(&user_a_repo, &new_file_path)?;
command::commit(&user_a_repo, "User A changing file.")?;
command::push(&user_a_repo).await?;
let new_file_path = user_b_repo.path.join(new_file);
let new_file_path =
test::write_txt_file_to_path(new_file_path, "I am user B, try to stop me")?;
command::add(&user_b_repo, &new_file_path)?;
command::commit(&user_b_repo, "User B changing file.")?;
let result = command::push(&user_b_repo).await;
assert!(result.is_err());
command::pull(&user_b_repo).await?;
let status = command::status(&user_b_repo)?;
assert!(!status.merge_conflicts.is_empty());
status.print_stdout();
command::checkout_ours(&user_b_repo, new_file)?;
command::add(&user_b_repo, &new_file_path)?;
command::commit(&user_b_repo, "Taking my changes")?;
command::push(&user_b_repo).await?;
Ok(user_b_repo_dir_copy)
})
.await?;
Ok(user_a_repo_dir_copy)
})
.await?;
Ok(remote_repo_copy)
})
.await
}
#[tokio::test]
async fn test_pull_does_not_remove_local_files() -> Result<(), OxenError> {
test::run_empty_sync_repo_test(|_, remote_repo| async move {
let remote_repo_copy = remote_repo.clone();
test::run_empty_dir_test_async(|user_a_repo_dir| async move {
let user_a_repo_dir_copy = user_a_repo_dir.join("user_a_repo");
let user_a_repo =
command::clone_url(&remote_repo.remote.url, &user_a_repo_dir_copy).await?;
test::run_empty_dir_test_async(|user_b_repo_dir| async move {
let user_b_repo_dir_copy = user_b_repo_dir.join("user_b_repo");
let user_b_repo =
command::clone_url(&remote_repo.remote.url, &user_b_repo_dir_copy).await?;
let file_1 = "file_1.txt";
test::write_txt_file_to_path(user_a_repo.path.join(file_1), "File 1")?;
let file_2 = "file_2.txt";
test::write_txt_file_to_path(user_a_repo.path.join(file_2), "File 2")?;
command::add(&user_a_repo, user_a_repo.path.join(file_1))?;
command::add(&user_a_repo, user_a_repo.path.join(file_2))?;
command::commit(&user_a_repo, "Adding file_1 and file_2")?;
command::push(&user_a_repo).await?;
let file_3 = "file_3.txt";
test::write_txt_file_to_path(user_b_repo.path.join(file_3), "File 3")?;
command::add(&user_b_repo, user_b_repo.path.join(file_3))?;
command::commit(&user_b_repo, "Adding file_3")?;
command::pull(&user_b_repo).await?;
api::local::commits::head_commit(&user_b_repo)?;
assert!(user_b_repo.path.join(file_1).exists());
assert!(user_b_repo.path.join(file_2).exists());
assert!(user_b_repo.path.join(file_3).exists());
Ok(user_b_repo_dir_copy)
})
.await?;
Ok(user_a_repo_dir_copy)
})
.await?;
Ok(remote_repo_copy)
})
.await
}
#[tokio::test]
async fn test_pull_does_not_remove_untracked_files() -> Result<(), OxenError> {
test::run_empty_sync_repo_test(|_, remote_repo| async move {
let remote_repo_copy = remote_repo.clone();
test::run_empty_dir_test_async(|user_a_repo_dir| async move {
let user_a_repo_dir_copy = user_a_repo_dir.join("user_a_repo");
let user_a_repo =
command::clone_url(&remote_repo.remote.url, &user_a_repo_dir_copy).await?;
test::run_empty_dir_test_async(|user_b_repo_dir| async move {
let user_b_repo_dir_copy = user_b_repo_dir.join("user_b_repo");
let user_b_repo =
command::clone_url(&remote_repo.remote.url, &user_b_repo_dir_copy).await?;
let file_1 = "file_1.txt";
test::write_txt_file_to_path(user_a_repo.path.join(file_1), "File 1")?;
let file_2 = "file_2.txt";
test::write_txt_file_to_path(user_a_repo.path.join(file_2), "File 2")?;
command::add(&user_a_repo, user_a_repo.path.join(file_1))?;
command::add(&user_a_repo, user_a_repo.path.join(file_2))?;
command::commit(&user_a_repo, "Adding file_1 and file_2")?;
command::push(&user_a_repo).await?;
let local_file_2 = "file_2.txt";
test::write_txt_file_to_path(
user_b_repo.path.join(local_file_2),
"wrong not correct content",
)?;
let file_3 = "file_3.txt";
test::write_txt_file_to_path(user_b_repo.path.join(file_3), "File 3")?;
let dir_1 = "dir_1";
std::fs::create_dir(user_b_repo.path.join(dir_1))?;
let dir_2 = "dir_2";
std::fs::create_dir(user_b_repo.path.join(dir_2))?;
let file_4 = "file_4.txt";
test::write_txt_file_to_path(
user_b_repo.path.join(dir_2).join(file_4),
"File 4",
)?;
let file_5 = "file_5.txt";
test::write_txt_file_to_path(
user_b_repo.path.join(dir_2).join(file_5),
"File 5",
)?;
let dir_3 = "dir_3";
let subdir = "subdir";
std::fs::create_dir_all(user_b_repo.path.join(dir_3).join(subdir))?;
let subfile = "subfile.txt";
test::write_txt_file_to_path(
user_b_repo.path.join(dir_3).join(subdir).join(subfile),
"Subfile",
)?;
command::pull(&user_b_repo).await?;
assert!(user_b_repo.path.join(file_1).exists());
assert!(user_b_repo.path.join(file_2).exists());
let local_file_2_contents =
std::fs::read_to_string(user_b_repo.path.join(local_file_2))?;
assert_eq!(local_file_2_contents, "File 2");
assert!(user_b_repo.path.join(file_3).exists());
assert!(user_b_repo.path.join(dir_1).exists());
assert!(user_b_repo.path.join(dir_2).exists());
assert!(user_b_repo.path.join(dir_2).join(file_4).exists());
assert!(user_b_repo.path.join(dir_2).join(file_5).exists());
assert!(user_b_repo.path.join(dir_3).exists());
assert!(user_b_repo.path.join(dir_3).join(subdir).exists());
assert!(user_b_repo
.path
.join(dir_3)
.join(subdir)
.join(subfile)
.exists());
Ok(user_b_repo_dir_copy)
})
.await?;
Ok(user_a_repo_dir_copy)
})
.await?;
Ok(remote_repo_copy)
})
.await
}
}