mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
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:
parent
7af104b330
commit
a4f69ed7da
@ -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#"
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user