mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 16:31:02 +03:00
mononoke/repo_import: add rewrite_commit functionality
Summary:
Previous commit: D22233127 (fa1caa8c4e
)
In this diff, I added rewrite commit path functionality using Mover https://fburl.com/diffusion/6rnf9q2f to repo_import.
Given a prefix (e.g. new_repo), we prepend the paths of the files extracted from the bonsaichangesets given by gitimport (e.g. folder1/file1 => new_repo/folder1/file1). Previously, we did this manually when importing a git repo (https://www.internalfb.com/intern/wiki/Mercurial/Admin/ImportingRepos/) using convert extension.
Reviewed By: StanislavGlebik
Differential Revision: D22307039
fbshipit-source-id: 322533e5d6cbaf5d7eec589c8cba0c1b9c79d7af
This commit is contained in:
parent
aa00466319
commit
f5db2fdcdc
@ -70,7 +70,7 @@ enum PathAction {
|
|||||||
|
|
||||||
/// Default action to apply to a path when syncing between two repos
|
/// Default action to apply to a path when syncing between two repos
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum DefaultAction {
|
pub enum DefaultAction {
|
||||||
/// Prepend path with this prefix
|
/// Prepend path with this prefix
|
||||||
PrependPrefix(MPath),
|
PrependPrefix(MPath),
|
||||||
/// Keep the path as is
|
/// Keep the path as is
|
||||||
@ -167,7 +167,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Mover`, given a path prefix map and a default action
|
/// Create a `Mover`, given a path prefix map and a default action
|
||||||
fn mover_factory(
|
pub fn mover_factory(
|
||||||
prefix_map: HashMap<MPath, PrefixAction>,
|
prefix_map: HashMap<MPath, PrefixAction>,
|
||||||
default_action: DefaultAction,
|
default_action: DefaultAction,
|
||||||
) -> Result<Mover> {
|
) -> Result<Mover> {
|
||||||
|
@ -7,13 +7,16 @@ license = "GPLv2+"
|
|||||||
include = ["src/**/*.rs"]
|
include = ["src/**/*.rs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
blobrepo = { path = "../blobrepo" }
|
||||||
cmdlib = { path = "../cmdlib" }
|
cmdlib = { path = "../cmdlib" }
|
||||||
context = { path = "../server/context" }
|
context = { path = "../server/context" }
|
||||||
|
cross_repo_sync = { path = "../commit_rewriting/cross_repo_sync" }
|
||||||
import_tools = { path = "../git/import_tools" }
|
import_tools = { path = "../git/import_tools" }
|
||||||
|
mercurial_types = { path = "../mercurial/types" }
|
||||||
mononoke_types = { path = "../mononoke_types" }
|
mononoke_types = { path = "../mononoke_types" }
|
||||||
|
movers = { path = "../commit_rewriting/movers" }
|
||||||
fbinit = { git = "https://github.com/facebookexperimental/rust-shed.git", branch = "master" }
|
fbinit = { git = "https://github.com/facebookexperimental/rust-shed.git", branch = "master" }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
futures = { version = "0.3", features = ["async-await", "compat"] }
|
futures = { version = "0.3", features = ["async-await", "compat"] }
|
||||||
git2 = "0.13"
|
slog = { version = "2.5", features = ["max_level_debug"] }
|
||||||
linked-hash-map = { version = "0.5", features = ["serde_impl"] }
|
|
||||||
|
@ -6,19 +6,69 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
use blobrepo::{save_bonsai_changesets, BlobRepo};
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
use cmdlib::args;
|
use cmdlib::args;
|
||||||
use cmdlib::helpers::block_execute;
|
use cmdlib::helpers::block_execute;
|
||||||
use context::CoreContext;
|
use context::CoreContext;
|
||||||
|
use cross_repo_sync::rewrite_commit;
|
||||||
use fbinit::FacebookInit;
|
use fbinit::FacebookInit;
|
||||||
use futures::compat::Future01CompatExt;
|
use futures::compat::Future01CompatExt;
|
||||||
use git2::Oid;
|
|
||||||
use import_tools::{GitimportPreferences, GitimportTarget};
|
use import_tools::{GitimportPreferences, GitimportTarget};
|
||||||
use linked_hash_map::LinkedHashMap;
|
use mercurial_types::MPath;
|
||||||
use mononoke_types::{BonsaiChangeset, ChangesetId};
|
use mononoke_types::ChangesetId;
|
||||||
|
use movers::DefaultAction;
|
||||||
|
use slog::info;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
const ARG_GIT_REPOSITORY_PATH: &str = "git-repository-path";
|
const ARG_GIT_REPOSITORY_PATH: &str = "git-repository-path";
|
||||||
|
const ARG_DEST_PATH_PREFIX: &str = "destination-path-prefix";
|
||||||
|
|
||||||
|
async fn rewrite_file_paths(
|
||||||
|
ctx: &CoreContext,
|
||||||
|
repo: &BlobRepo,
|
||||||
|
path: &Path,
|
||||||
|
prefix: &str,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let prefs = GitimportPreferences::default();
|
||||||
|
let target = GitimportTarget::FullRepo;
|
||||||
|
let import_map = import_tools::gitimport(ctx, repo, path, target, prefs).await?;
|
||||||
|
let mut remapped_parents: HashMap<ChangesetId, ChangesetId> = HashMap::new();
|
||||||
|
let mover = movers::mover_factory(
|
||||||
|
HashMap::new(),
|
||||||
|
DefaultAction::PrependPrefix(MPath::new(prefix).unwrap()),
|
||||||
|
)?;
|
||||||
|
let mut bonsai_changesets = vec![];
|
||||||
|
|
||||||
|
for (_id, (bcs_id, bcs)) in import_map {
|
||||||
|
let bcs_mut = bcs.into_mut();
|
||||||
|
let rewritten_bcs_opt = rewrite_commit(
|
||||||
|
ctx.clone(),
|
||||||
|
bcs_mut,
|
||||||
|
&remapped_parents,
|
||||||
|
mover.clone(),
|
||||||
|
repo.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(rewritten_bcs_mut) = rewritten_bcs_opt {
|
||||||
|
let rewritten_bcs = rewritten_bcs_mut.freeze()?;
|
||||||
|
remapped_parents.insert(bcs_id, rewritten_bcs.get_changeset_id());
|
||||||
|
info!(
|
||||||
|
ctx.logger(),
|
||||||
|
"Remapped {:?} => {:?}",
|
||||||
|
bcs_id,
|
||||||
|
rewritten_bcs.get_changeset_id(),
|
||||||
|
);
|
||||||
|
bonsai_changesets.push(rewritten_bcs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save_bonsai_changesets(bonsai_changesets.clone(), ctx.clone(), repo.clone())
|
||||||
|
.compat()
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[fbinit::main]
|
#[fbinit::main]
|
||||||
fn main(fb: FacebookInit) -> Result<(), Error> {
|
fn main(fb: FacebookInit) -> Result<(), Error> {
|
||||||
@ -27,35 +77,37 @@ fn main(fb: FacebookInit) -> Result<(), Error> {
|
|||||||
.build()
|
.build()
|
||||||
.version("0.0.0")
|
.version("0.0.0")
|
||||||
.about("Automating repository imports")
|
.about("Automating repository imports")
|
||||||
.arg(Arg::with_name(ARG_GIT_REPOSITORY_PATH).help("Path to a git repository to import"));
|
.arg(
|
||||||
|
Arg::with_name(ARG_GIT_REPOSITORY_PATH)
|
||||||
|
.required(true)
|
||||||
|
.help("Path to a git repository to import"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ARG_DEST_PATH_PREFIX)
|
||||||
|
.long(ARG_DEST_PATH_PREFIX)
|
||||||
|
.required(true)
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Prefix of the destination folder we import to"),
|
||||||
|
);
|
||||||
|
|
||||||
let prefs = GitimportPreferences::default();
|
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
|
|
||||||
let target = GitimportTarget::FullRepo;
|
|
||||||
|
|
||||||
let path = Path::new(matches.value_of(ARG_GIT_REPOSITORY_PATH).unwrap());
|
let path = Path::new(matches.value_of(ARG_GIT_REPOSITORY_PATH).unwrap());
|
||||||
|
let prefix = matches.value_of(ARG_DEST_PATH_PREFIX).unwrap();
|
||||||
args::init_cachelib(fb, &matches, None);
|
args::init_cachelib(fb, &matches, None);
|
||||||
|
|
||||||
let logger = args::init_logging(fb, &matches);
|
let logger = args::init_logging(fb, &matches);
|
||||||
let ctx = CoreContext::new_with_logger(fb, logger.clone());
|
let ctx = CoreContext::new_with_logger(fb, logger.clone());
|
||||||
let repo = args::create_repo(fb, &logger, &matches);
|
let repo = args::create_repo(fb, &logger, &matches);
|
||||||
|
block_execute(
|
||||||
let gitimport_result: Result<LinkedHashMap<Oid, (ChangesetId, BonsaiChangeset)>, Error> =
|
async {
|
||||||
block_execute(
|
let repo = repo.compat().await?;
|
||||||
async {
|
rewrite_file_paths(&ctx, &repo, &path, &prefix).await
|
||||||
let repo = repo.compat().await?;
|
},
|
||||||
import_tools::gitimport(&ctx, &repo, &path, target, prefs).await
|
fb,
|
||||||
},
|
"gitimport",
|
||||||
fb,
|
&logger,
|
||||||
"gitimport",
|
&matches,
|
||||||
&logger,
|
cmdlib::monitoring::AliveService,
|
||||||
&matches,
|
)
|
||||||
cmdlib::monitoring::AliveService,
|
|
||||||
);
|
|
||||||
|
|
||||||
match gitimport_result {
|
|
||||||
Ok(_import_map) => Ok(()),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,39 @@
|
|||||||
$ git init
|
$ git init
|
||||||
Initialized empty Git repository in $TESTTMP/repo-git/.git/
|
Initialized empty Git repository in $TESTTMP/repo-git/.git/
|
||||||
$ echo "this is file1" > file1
|
$ echo "this is file1" > file1
|
||||||
$ git add file1
|
$ mkdir file2_repo
|
||||||
$ git commit -am "Add file1"
|
$ cd file2_repo
|
||||||
[master (root-commit) 8ce3eae] Add file1
|
$ echo "this is file2" > file2
|
||||||
1 file changed, 1 insertion(+)
|
$ cd ..
|
||||||
|
$ git add file1 file2_repo/file2
|
||||||
|
$ git commit -am "Add file1 and file2"
|
||||||
|
[master (root-commit) ce435b0] Add file1 and file2
|
||||||
|
2 files changed, 2 insertions(+)
|
||||||
create mode 100644 file1
|
create mode 100644 file1
|
||||||
|
create mode 100644 file2_repo/file2
|
||||||
|
$ mkdir file3_repo
|
||||||
|
$ echo "this is file3" > file3_repo/file3
|
||||||
|
$ git add file3_repo/file3
|
||||||
|
$ git commit -am "Add file3"
|
||||||
|
[master 2c01e4a] Add file3
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
create mode 100644 file3_repo/file3
|
||||||
|
|
||||||
# Import it into Mononoke
|
# Import it into Mononoke
|
||||||
$ cd "$TESTTMP"
|
$ cd "$TESTTMP"
|
||||||
$ repo_import "$GIT_REPO"
|
$ repo_import "$GIT_REPO" --destination-path-prefix "new_repo"
|
||||||
* using repo "repo" repoid RepositoryId(0) (glob)
|
* using repo "repo" repoid RepositoryId(0) (glob)
|
||||||
* Created 8ce3eae44760b500bf3f2c3922a95dcd3c908e9e => ChangesetId(Blake2(22e96bdf5536bb09049caadadaa0cd9ea0593556db6fa389fa044f8ee95270ea)) (glob)
|
* Created ce435b03d4ef526648f8654c61e26ae5cc1069cc => ChangesetId(Blake2(f7cbf75d9c08ff96896ed2cebd0327aa514e58b1dd9901d50129b9e08f4aa062)) (glob)
|
||||||
* 1 bonsai changesets have been committed (glob)
|
* Created 2c01e4a5658421e2bfcd08e31d9b69399319bcd3 => ChangesetId(Blake2(f7708ed066b1c23591f862148e0386ec704a450e572154cc52f87ca0e394a0fb)) (glob)
|
||||||
* Ref: Some("refs/heads/master"): Some(ChangesetId(Blake2(22e96bdf5536bb09049caadadaa0cd9ea0593556db6fa389fa044f8ee95270ea))) (glob)
|
* 2 bonsai changesets have been committed (glob)
|
||||||
|
* Ref: Some("refs/heads/master"): Some(ChangesetId(Blake2(f7708ed066b1c23591f862148e0386ec704a450e572154cc52f87ca0e394a0fb))) (glob)
|
||||||
|
* Remapped ChangesetId(Blake2(f7cbf75d9c08ff96896ed2cebd0327aa514e58b1dd9901d50129b9e08f4aa062)) => ChangesetId(Blake2(4c9a9394cb65d5b57286d866bb012a0a4553ea05ba82755c0ed9e977e51d0da0)) (glob)
|
||||||
|
* Remapped ChangesetId(Blake2(f7708ed066b1c23591f862148e0386ec704a450e572154cc52f87ca0e394a0fb)) => ChangesetId(Blake2(cf29a57c1ba299f835ea2546e26c8eb8fd5b981067162579924b58000306e96f)) (glob)
|
||||||
|
|
||||||
# Set master (gitimport does not do this yet)
|
# Set master (gitimport does not do this yet)
|
||||||
$ mononoke_admin bookmarks set master 22e96bdf5536bb09049caadadaa0cd9ea0593556db6fa389fa044f8ee95270ea
|
$ mononoke_admin bookmarks set master cf29a57c1ba299f835ea2546e26c8eb8fd5b981067162579924b58000306e96f
|
||||||
* using repo "repo" repoid RepositoryId(0) (glob)
|
* using repo "repo" repoid RepositoryId(0) (glob)
|
||||||
* changeset resolved as: ChangesetId(Blake2(22e96bdf5536bb09049caadadaa0cd9ea0593556db6fa389fa044f8ee95270ea)) (glob)
|
* changeset resolved as: ChangesetId(Blake2(cf29a57c1ba299f835ea2546e26c8eb8fd5b981067162579924b58000306e96f)) (glob)
|
||||||
* Current position of BookmarkName { bookmark: "master" } is None (glob)
|
* Current position of BookmarkName { bookmark: "master" } is None (glob)
|
||||||
|
|
||||||
# Start Mononoke
|
# Start Mononoke
|
||||||
@ -43,5 +58,9 @@
|
|||||||
$ cd "$TESTTMP"
|
$ cd "$TESTTMP"
|
||||||
$ hgmn_clone 'ssh://user@dummy/repo' "$HG_REPO"
|
$ hgmn_clone 'ssh://user@dummy/repo' "$HG_REPO"
|
||||||
$ cd "$HG_REPO"
|
$ cd "$HG_REPO"
|
||||||
$ cat "file1"
|
$ cat "new_repo/file1"
|
||||||
this is file1
|
this is file1
|
||||||
|
$ cat "new_repo/file2_repo/file2"
|
||||||
|
this is file2
|
||||||
|
$ cat "new_repo/file3_repo/file3"
|
||||||
|
this is file3
|
||||||
|
Loading…
Reference in New Issue
Block a user