|
1 | 1 | use std::collections::HashMap;
|
2 |
| -use std::fs::{self, OpenOptions}; |
| 2 | +use std::fs::{self, File, OpenOptions}; |
| 3 | +use std::io::prelude::*; |
3 | 4 | use std::path::{Path, PathBuf};
|
4 | 5 |
|
5 | 6 | use chrono::Utc;
|
6 | 7 | use swirl::PerformError;
|
7 |
| -use tempfile::{Builder, TempDir}; |
| 8 | +use tempfile::TempDir; |
8 | 9 | use url::Url;
|
9 | 10 |
|
10 | 11 | use crate::background_jobs::Environment;
|
@@ -148,7 +149,7 @@ pub struct Repository {
|
148 | 149 |
|
149 | 150 | impl Repository {
|
150 | 151 | pub fn open(repository_config: &RepositoryConfig) -> Result<Self, PerformError> {
|
151 |
| - let checkout_path = Builder::new().prefix("git").tempdir()?; |
| 152 | + let checkout_path = tempfile::Builder::new().prefix("git").tempdir()?; |
152 | 153 |
|
153 | 154 | let repository = git2::build::RepoBuilder::new()
|
154 | 155 | .fetch_options(Self::fetch_options(&repository_config.credentials))
|
@@ -383,24 +384,59 @@ pub fn squash_index(env: &Environment) -> Result<(), PerformError> {
|
383 | 384 | println!("Squashing the index into a single commit.");
|
384 | 385 |
|
385 | 386 | let now = Utc::now().format("%Y-%m-%d");
|
386 |
| - let head = repo.head_oid()?; |
| 387 | + let original_head = repo.head_oid()?; |
387 | 388 | let msg = format!("Collapse index into one commit\n\n\
|
388 | 389 |
|
389 | 390 | Previous HEAD was {}, now on the `snapshot-{}` branch\n\n\
|
390 | 391 |
|
391 | 392 | More information about this change can be found [online] and on [this issue].\n\n\
|
392 | 393 |
|
393 | 394 | [online]: https://internals.rust-lang.org/t/cargos-crate-index-upcoming-squash-into-one-commit/8440\n\
|
394 |
| - [this issue]: https://github.com/rust-lang/crates-io-cargo-teams/issues/47", head, now); |
| 395 | + [this issue]: https://github.com/rust-lang/crates-io-cargo-teams/issues/47", original_head, now); |
395 | 396 |
|
396 | 397 | // Create a snapshot branch of current `HEAD`.
|
397 | 398 | repo.push(&format!("HEAD:refs/heads/snapshot-{}", now))?;
|
398 | 399 |
|
399 | 400 | repo.squash_to_single_commit(&msg)?;
|
400 | 401 |
|
401 |
| - // Because this will not be a fast-forward push, `+` is added to the |
402 |
| - // beginning of the refspec to force the push. |
403 |
| - repo.push("+HEAD:refs/heads/master")?; |
| 402 | + // Shell out to git because libgit2 does not currently support push leases |
| 403 | + |
| 404 | + let key = match &repo.credentials { |
| 405 | + Credentials::Ssh { key } => key, |
| 406 | + Credentials::Http { .. } => { |
| 407 | + return Err(String::from("squash_index: Password auth not supported").into()) |
| 408 | + } |
| 409 | + _ => return Err(String::from("squash_index: Could not determine credentials").into()), |
| 410 | + }; |
| 411 | + |
| 412 | + let temp_key_file = tempfile::Builder::new().tempfile()?; |
| 413 | + let mut file = File::create(&temp_key_file)?; |
| 414 | + file.write_all(key.as_bytes())?; |
| 415 | + drop(file); |
| 416 | + |
| 417 | + let checkout_path = repo.checkout_path.path(); |
| 418 | + let output = std::process::Command::new("git") |
| 419 | + .current_dir(checkout_path) |
| 420 | + .env( |
| 421 | + "GIT_SSH_COMMAND", |
| 422 | + format!( |
| 423 | + "ssh -o StrictHostKeyChecking=accept-new -i {}", |
| 424 | + temp_key_file.path().display() |
| 425 | + ), |
| 426 | + ) |
| 427 | + .args(&[ |
| 428 | + "push", |
| 429 | + "origin", |
| 430 | + "HEAD:refs/heads/master", |
| 431 | + &format!("--force-with-lease=refs/heads/master:{}", original_head), |
| 432 | + ]) |
| 433 | + .output()?; |
| 434 | + |
| 435 | + if !output.status.success() { |
| 436 | + let stderr = String::from_utf8_lossy(&output.stderr); |
| 437 | + let message = format!("Running git command failed with: {}", stderr); |
| 438 | + return Err(message.into()); |
| 439 | + } |
404 | 440 |
|
405 | 441 | println!("The index has been successfully squashed.");
|
406 | 442 |
|
|
0 commit comments