Skip to content

Commit 9b8b1ce

Browse files
authored
Merge pull request #174 from ginkgobioworks/merge-command
Merge command and better operation handling
2 parents 57f5669 + cc86db5 commit 9b8b1ce

File tree

3 files changed

+89
-12
lines changed

3 files changed

+89
-12
lines changed

src/main.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@ enum Commands {
270270
#[clap(index = 1)]
271271
branch_name: Option<String>,
272272
},
273+
/// Merge branches
274+
#[command(arg_required_else_help(true))]
275+
Merge {
276+
/// The branch name to merge
277+
#[clap(index = 1)]
278+
branch_name: Option<String>,
279+
},
273280
/// Migrate a database to a given operation
274281
#[command(arg_required_else_help(true))]
275282
Checkout {
@@ -977,20 +984,68 @@ fn main() {
977984
.unwrap_or_else(|| panic!("Unable to find branch {branch_name}."));
978985
let current_branch = OperationState::get_current_branch(&operation_conn, &db_uuid)
979986
.expect("Unable to find current branch.");
980-
operation_management::merge(
987+
conn.execute("BEGIN TRANSACTION", []).unwrap();
988+
operation_conn.execute("BEGIN TRANSACTION", []).unwrap();
989+
match operation_management::merge(
981990
&conn,
982991
&operation_conn,
983992
&db_uuid,
984993
current_branch,
985994
other_branch.id,
986995
None,
987-
);
996+
) {
997+
Ok(_) => println!("Merge successful"),
998+
Err(_) => {
999+
conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1000+
operation_conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1001+
panic!("Merge failed.");
1002+
}
1003+
}
1004+
conn.execute("END TRANSACTION", []).unwrap();
1005+
operation_conn.execute("END TRANSACTION", []).unwrap();
9881006
} else {
9891007
println!("No options selected.");
9901008
}
9911009
}
1010+
Some(Commands::Merge { branch_name }) => {
1011+
let branch_name = branch_name.clone().expect("Branch name must be provided.");
1012+
let other_branch = Branch::get_by_name(&operation_conn, &db_uuid, &branch_name)
1013+
.unwrap_or_else(|| panic!("Unable to find branch {branch_name}."));
1014+
let current_branch = OperationState::get_current_branch(&operation_conn, &db_uuid)
1015+
.expect("Unable to find current branch.");
1016+
conn.execute("BEGIN TRANSACTION", []).unwrap();
1017+
operation_conn.execute("BEGIN TRANSACTION", []).unwrap();
1018+
match operation_management::merge(
1019+
&conn,
1020+
&operation_conn,
1021+
&db_uuid,
1022+
current_branch,
1023+
other_branch.id,
1024+
None,
1025+
) {
1026+
Ok(_) => println!("Merge successful"),
1027+
Err(details) => {
1028+
conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1029+
operation_conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1030+
panic!("Merge failed: {details}");
1031+
}
1032+
}
1033+
conn.execute("END TRANSACTION", []).unwrap();
1034+
operation_conn.execute("END TRANSACTION", []).unwrap();
1035+
}
9921036
Some(Commands::Apply { hash }) => {
993-
operation_management::apply(&conn, &operation_conn, hash, None);
1037+
conn.execute("BEGIN TRANSACTION", []).unwrap();
1038+
operation_conn.execute("BEGIN TRANSACTION", []).unwrap();
1039+
match operation_management::apply(&conn, &operation_conn, hash, None) {
1040+
Ok(_) => println!("Operation applied"),
1041+
Err(_) => {
1042+
conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1043+
operation_conn.execute("ROLLBACK TRANSACTION;", []).unwrap();
1044+
panic!("Apply failed.");
1045+
}
1046+
}
1047+
conn.execute("END TRANSACTION", []).unwrap();
1048+
operation_conn.execute("END TRANSACTION", []).unwrap();
9941049
}
9951050
Some(Commands::Checkout { branch, hash }) => {
9961051
if let Some(name) = branch.clone() {

src/operation_management.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,26 @@ pub enum OperationError {
4646
NoChanges,
4747
#[error("Operation Already Exists")]
4848
OperationExists,
49+
#[error("Operation {0} Does Not Exist")]
50+
NoOperation(String),
4951
#[error("SQL Error: {0}")]
5052
SQLError(String),
5153
#[error("SQLite Error: {0}")]
5254
SqliteError(#[from] SQLError),
5355
}
5456

57+
#[derive(Debug, PartialEq, Error)]
58+
pub enum MergeError {
59+
#[error("SQL Error: {0}")]
60+
SQLError(String),
61+
#[error("SQLite Error: {0}")]
62+
SqliteError(#[from] SQLError),
63+
#[error("Operation Error: {0}")]
64+
OperationError(#[from] OperationError),
65+
#[error("Invalid Branch: {0}")]
66+
InvalidBranch(String),
67+
}
68+
5569
#[derive(Debug, Error)]
5670
pub enum RemoteOperationError {
5771
#[error("Failed to transfer {0} from {1} to {2}")]
@@ -937,10 +951,10 @@ pub fn apply<'a>(
937951
operation_conn: &Connection,
938952
op_hash: &str,
939953
force_hash: impl Into<Option<&'a str>>,
940-
) -> Operation {
954+
) -> Result<Operation, OperationError> {
941955
let mut session = start_operation(conn);
942956
let operation = Operation::get_by_hash(operation_conn, op_hash)
943-
.unwrap_or_else(|_| panic!("Hash {op_hash} does not exist."));
957+
.map_err(|_err| OperationError::NoOperation(op_hash.to_string()))?;
944958
let changeset = load_changeset(&operation);
945959
let input: &mut dyn Read = &mut changeset.as_slice();
946960
let mut iter = ChangesetIter::start_strm(&input).unwrap();
@@ -961,7 +975,6 @@ pub fn apply<'a>(
961975
&format!("Applied changeset {full_op_hash}."),
962976
force_hash,
963977
)
964-
.unwrap()
965978
}
966979

967980
pub fn merge<'a>(
@@ -971,13 +984,18 @@ pub fn merge<'a>(
971984
source_branch: i64,
972985
other_branch: i64,
973986
force_hash: impl Into<Option<&'a str>>,
974-
) -> Vec<Operation> {
987+
) -> Result<Vec<Operation>, MergeError> {
975988
let mut new_operations: Vec<Operation> = vec![];
976989
let hash_prefix = force_hash.into();
977990
let current_branch =
978991
OperationState::get_current_branch(operation_conn, db_uuid).expect("No current branch.");
979992
if source_branch != current_branch {
980-
panic!("Unable to merge branch. Source branch and current branch must match. Checkout the branch you wish to merge into.");
993+
return Err(MergeError::InvalidBranch("Source branch and current branch must match. Checkout the branch you wish to merge into.".to_string()));
994+
}
995+
if other_branch == current_branch {
996+
return Err(MergeError::InvalidBranch(
997+
"Target branch to merge is the currently checked out branch.".to_string(),
998+
));
981999
}
9821000
let current_operations = Branch::get_operations(operation_conn, source_branch);
9831001
let other_operations = Branch::get_operations(operation_conn, other_branch);
@@ -994,14 +1012,14 @@ pub fn merge<'a>(
9941012
operation_conn,
9951013
&operation.hash,
9961014
format!("{hash}-{index}").as_str(),
997-
)
1015+
)?
9981016
} else {
999-
apply(conn, operation_conn, &operation.hash, None)
1017+
apply(conn, operation_conn, &operation.hash, None)?
10001018
};
10011019
new_operations.push(new_op);
10021020
}
10031021
}
1004-
new_operations
1022+
Ok(new_operations)
10051023
}
10061024

10071025
pub fn move_to(conn: &Connection, operation_conn: &Connection, operation: &Operation) {
@@ -1652,6 +1670,7 @@ mod tests {
16521670
branch_2.id,
16531671
"merge-test",
16541672
)
1673+
.unwrap()
16551674
.iter()
16561675
.map(|op| op.hash.clone())
16571676
.collect::<Vec<String>>();
@@ -2181,7 +2200,7 @@ mod tests {
21812200
);
21822201

21832202
// apply changes from branch-1, it will be operation id 2
2184-
apply(conn, operation_conn, &op_2.hash, None);
2203+
apply(conn, operation_conn, &op_2.hash, None).unwrap();
21852204

21862205
let foo_bg_id = BlockGroup::get_id(conn, &collection, Some("foo"), "m123");
21872206
let patch_2_seqs = HashSet::from_iter(vec!["ATCATCGATCGAGATCGGGAACACACAGAGA".to_string()]);

src/patch.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ pub fn apply_patches(conn: &Connection, op_conn: &Connection, patches: &[Operati
105105
println!("Successfully applied operation.");
106106
}
107107
Err(e) => match e {
108+
OperationError::NoOperation(details) => {
109+
println!("Operation with hash {details} does not exist")
110+
}
108111
OperationError::OperationExists => println!("Operation already applied. Skipping."),
109112
OperationError::NoChanges => {
110113
println!("No new changes present in operation. Skipping.")

0 commit comments

Comments
 (0)