commit_rewriting: allow non-prefix free maps in metaconfig

Summary:
This is in line with other changes we're making to map logic now. Note that
apart from checking in-repo prefix-free-ness of the map, this also checked the
same across many small repos. It probably does not make sense to do that either
now that we allow non-prefix free maps within a repo.

Reviewed By: StanislavGlebik

Differential Revision: D24348161

fbshipit-source-id: caaa22953c8a15a08607157b99c9f0fd0edf633f
This commit is contained in:
Kostia Balytskyi 2020-10-16 05:15:07 -07:00 committed by Facebook GitHub Bot
parent 7af104b330
commit a4f69ed7da
2 changed files with 0 additions and 265 deletions

View File

@ -597,204 +597,6 @@ mod test {
assert!(msg.contains("present multiple times in the same CommitSyncConfig")); assert!(msg.contains("present multiple times in the same CommitSyncConfig"));
} }
#[fbinit::test]
fn test_commit_sync_config_conflicting_path_prefixes_small_to_large(fb: FacebookInit) {
let commit_sync_config = r#"
[mega]
large_repo_id = 1
common_pushrebase_bookmarks = ["master"]
[[mega.small_repos]]
repoid = 2
bookmark_prefix = "repo2"
default_action = "preserve"
direction = "small_to_large"
[mega.small_repos.mapping]
"p1" = ".r2-legacy/p1"
"p5" = "subdir"
[[mega.small_repos]]
repoid = 3
bookmark_prefix = "repo3"
default_action = "prepend_prefix"
default_prefix = "subdir"
direction = "small_to_large"
[mega.small_repos.mapping]
"p1" = "p1"
"p4" = "p5/p4"
"#;
let paths = btreemap! {
"common/commitsyncmap.toml" => commit_sync_config
};
let tmp_dir = write_files(&paths);
let res = load_repo_configs(fb, tmp_dir.path());
let msg = format!("{:#?}", res);
println!("res = {}", msg);
assert!(res.is_err());
assert!(msg.contains("is a prefix of MPath"));
}
#[fbinit::test]
fn test_commit_sync_config_conflicting_path_prefixes_large_to_small(fb: FacebookInit) {
// Purely identical prefixes, allowed in large-to-small
let commit_sync_config = r#"
[mega]
large_repo_id = 1
common_pushrebase_bookmarks = ["master"]
[[mega.small_repos]]
repoid = 2
bookmark_prefix = "repo2"
default_action = "preserve"
direction = "large_to_small"
[mega.small_repos.mapping]
"p5" = "subdir"
[[mega.small_repos]]
repoid = 3
bookmark_prefix = "repo3"
default_action = "prepend_prefix"
default_prefix = "subdir"
direction = "large_to_small"
[mega.small_repos.mapping]
"p1" = "p1"
"#;
let paths = btreemap! {
"common/commitsyncmap.toml" => commit_sync_config
};
let tmp_dir = write_files(&paths);
let commit_sync_config = load_repo_configs(fb, tmp_dir.path());
assert!(commit_sync_config.is_ok());
// Overlapping, but not identical prefixes
let commit_sync_config = r#"
[mega]
large_repo_id = 1
common_pushrebase_bookmarks = ["master"]
[[mega.small_repos]]
repoid = 2
bookmark_prefix = "repo2"
default_action = "preserve"
direction = "large_to_small"
[mega.small_repos.mapping]
"p5" = "subdir/bla"
[[mega.small_repos]]
repoid = 3
bookmark_prefix = "repo3"
default_action = "prepend_prefix"
default_prefix = "subdir"
direction = "large_to_small"
[mega.small_repos.mapping]
"p1" = "p1"
"#;
let paths = btreemap! {
"common/commitsyncmap.toml" => commit_sync_config
};
let tmp_dir = write_files(&paths);
let res = load_repo_configs(fb, tmp_dir.path());
let msg = format!("{:#?}", res);
println!("res = {}", msg);
assert!(res.is_err());
assert!(msg.contains("is a prefix of MPath"));
}
#[fbinit::test]
fn test_commit_sync_config_conflicting_path_prefixes_mixed(fb: FacebookInit) {
// Conflicting paths, should fail
let commit_sync_config = r#"
[mega]
large_repo_id = 1
common_pushrebase_bookmarks = ["master"]
[[mega.small_repos]]
repoid = 2
bookmark_prefix = "repo2"
default_action = "preserve"
direction = "large_to_small"
[mega.small_repos.mapping]
"p5" = "subdir"
[[mega.small_repos]]
repoid = 3
bookmark_prefix = "repo3"
default_action = "prepend_prefix"
default_prefix = "subdir"
direction = "small_to_large"
[mega.small_repos.mapping]
"p1" = "p1"
"#;
let paths = btreemap! {
"common/commitsyncmap.toml" => commit_sync_config
};
let tmp_dir = write_files(&paths);
let res = load_repo_configs(fb, tmp_dir.path());
let msg = format!("{:#?}", res);
println!("res = {}", msg);
assert!(res.is_err());
assert!(msg.contains("is a prefix of MPath"));
// Paths, identical between large-to-smalls, but
// overlapping with small-to-large, should fail
let commit_sync_config = r#"
[mega]
large_repo_id = 1
common_pushrebase_bookmarks = ["master"]
[[mega.small_repos]]
repoid = 2
bookmark_prefix = "repo2"
default_action = "preserve"
direction = "large_to_small"
[mega.small_repos.mapping]
"p5" = "subdir"
[[mega.small_repos]]
repoid = 3
bookmark_prefix = "repo3"
default_action = "prepend_prefix"
default_prefix = "r3"
direction = "small_to_large"
[mega.small_repos.mapping]
"p1" = "subdir/bla"
[[mega.small_repos]]
repoid = 4
bookmark_prefix = "repo4"
default_action = "prepend_prefix"
default_prefix = "r4"
direction = "large_to_small"
[mega.small_repos.mapping]
"p4" = "subdir"
"#;
let paths = btreemap! {
"common/commitsyncmap.toml" => commit_sync_config
};
let tmp_dir = write_files(&paths);
let res = load_repo_configs(fb, tmp_dir.path());
let msg = format!("{:#?}", res);
println!("res = {}", msg);
assert!(res.is_err());
assert!(msg.contains("is a prefix of MPath"));
}
#[fbinit::test] #[fbinit::test]
fn test_commit_sync_config_conflicting_bookmark_prefixes(fb: FacebookInit) { fn test_commit_sync_config_conflicting_bookmark_prefixes(fb: FacebookInit) {
let commit_sync_config = r#" let commit_sync_config = r#"

View File

@ -48,15 +48,6 @@ fn check_no_duplicate_small_repos(small_repos: &[RawCommitSyncSmallRepoConfig])
/// Validate the commit sync config /// Validate the commit sync config
/// ///
/// - Check that all the prefixes in the large repo (target prefixes in a map and prefixes
/// from `DefaultSmallToLargeCommitSyncPathAction::PrependPrefix`) are independent, e.g. aren't prefixes
/// of each other, if the sync direction is small-to-large. This is not allowed, because
/// otherwise there is no way to prevent path conflicts. For example, if one repo maps
/// `p1 => foo/bar` and the other maps `p2 => foo`, both repos can accept commits that
/// change `foo` and these commits can contain path conflicts. Given that the repos have
/// already replied successfully to their clients, it's too late to reject these commits.
/// To avoid this problem, we remove the possiblity of path conflicts altogether.
///
/// - Check that no two small repos use the same bookmark prefix. If they did, this would /// - Check that no two small repos use the same bookmark prefix. If they did, this would
/// mean potentail bookmark name collisions. /// mean potentail bookmark name collisions.
/// ///
@ -72,51 +63,12 @@ fn validate_commit_sync_config(commit_sync_config: &CommitSyncConfig) -> Result<
)); ));
} }
let all_prefixes_with_direction: Vec<(&MPath, CommitSyncDirection)> = commit_sync_config
.small_repos
.values()
.flat_map(|small_repo_sync_config| {
let SmallRepoCommitSyncConfig {
default_action,
map,
direction,
..
} = small_repo_sync_config;
let all_prefixes = map.values();
match default_action {
DefaultSmallToLargeCommitSyncPathAction::PrependPrefix(prefix) => {
all_prefixes.chain(vec![prefix].into_iter())
}
DefaultSmallToLargeCommitSyncPathAction::Preserve => {
all_prefixes.chain(vec![].into_iter())
}
}
.map(move |prefix| (prefix, direction.clone()))
})
.collect();
let bookmark_prefixes: Vec<&AsciiString> = commit_sync_config let bookmark_prefixes: Vec<&AsciiString> = commit_sync_config
.small_repos .small_repos
.iter() .iter()
.map(|(_, sr)| &sr.bookmark_prefix) .map(|(_, sr)| &sr.bookmark_prefix)
.collect(); .collect();
for ((first_prefix, first_direction), (second_prefix, second_direction)) in
all_prefixes_with_direction
.iter()
.tuple_combinations::<(_, _)>()
{
if first_prefix == second_prefix
&& *first_direction == CommitSyncDirection::LargeToSmall
&& *second_direction == CommitSyncDirection::LargeToSmall
{
// when syncing large-to-small, it is allowed to have identical prefixes,
// but not prefixes that are proper prefixes of other prefixes
continue;
}
validate_mpath_prefixes(first_prefix, second_prefix)?;
}
// No two small repos can have the same bookmark prefix // No two small repos can have the same bookmark prefix
for (first_prefix, second_prefix) in bookmark_prefixes.iter().tuple_combinations::<(_, _)>() { for (first_prefix, second_prefix) in bookmark_prefixes.iter().tuple_combinations::<(_, _)>() {
let fp = first_prefix.as_str(); let fp = first_prefix.as_str();
@ -133,25 +85,6 @@ fn validate_commit_sync_config(commit_sync_config: &CommitSyncConfig) -> Result<
Ok(()) Ok(())
} }
/// Verify that two mpaths are not a prefix of each other
fn validate_mpath_prefixes(first_prefix: &MPath, second_prefix: &MPath) -> Result<()> {
if first_prefix.is_prefix_of(second_prefix) {
return Err(anyhow!(
"{:?} is a prefix of {:?}, which is disallowed",
first_prefix,
second_prefix
));
}
if second_prefix.is_prefix_of(first_prefix) {
return Err(anyhow!(
"{:?} is a prefix of {:?}, which is disallowed",
second_prefix,
first_prefix
));
}
Ok(())
}
impl Convert for RawCommitSyncConfig { impl Convert for RawCommitSyncConfig {
type Output = CommitSyncConfig; type Output = CommitSyncConfig;