summaryrefslogtreecommitdiff
path: root/crates/bot-jobs/src/repo.rs
blob: 4d3e2148c1cd8b1a348ed6179ca59a7bd117478d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use bot_consts::{NIXPKGS_REMOTE, NIXPKGS_URL};
use bot_error::Error;

use std::{io::Write, path::Path};

use git2::{AutotagOption, FetchOptions, RemoteCallbacks, Repository};
use log::{debug, info, trace, warn};

pub const TTL_SECS: u64 = 60 * 5; // 5 minutes

// much of this is shamelessly lifted from
// https://github.com/rust-lang/git2-rs/blob/9a5c9706ff578c936be644dd1e8fe155bdc4d129/examples/pull.rs

/// basic set of options for fetching from remotes
fn fetch_options<'a>() -> FetchOptions<'a> {
	let mut remote_callbacks = RemoteCallbacks::new();
	remote_callbacks.transfer_progress(|progress| {
		if progress.received_objects() == progress.total_objects() {
			trace!(
				"Resolving deltas {}/{}\r",
				progress.indexed_deltas(),
				progress.total_deltas()
			);
		} else {
			trace!(
				"Received {}/{} objects ({}) in {} bytes\r",
				progress.received_objects(),
				progress.total_objects(),
				progress.indexed_objects(),
				progress.received_bytes()
			);
		}
		std::io::stdout().flush().ok();
		true
	});

	let mut fetch_opts = FetchOptions::new();
	fetch_opts.remote_callbacks(remote_callbacks);

	fetch_opts
}

/// update the given branches in the [`repository`] using the nixpkgs remote
fn update_branches_in(repository: &Repository, branches: &[String]) -> Result<(), Error> {
	let mut remote = repository.find_remote(NIXPKGS_REMOTE)?;
	// download all the refs
	remote.download(branches, Some(&mut fetch_options()))?;
	remote.disconnect()?;
	// and (hopefully) update what they refer to for later
	remote.update_tips(None, true, AutotagOption::Auto, None)?;

	Ok(())
}

pub fn fetch_or_update_repository(path: &str, branches: &[String]) -> Result<(), Error> {
	// Open our repository or clone it if it doesn't exist
	let path = Path::new(path);
	let repository = if path.exists() {
		Repository::open(path)?
	} else {
		warn!(
			"Couldn't find repository at {}! Cloning a fresh one from {NIXPKGS_URL}",
			path.display()
		);
		Repository::clone(NIXPKGS_URL, path)?;
		info!("Finished cloning to {}", path.display());

		// bail early as we already have a fresh copy
		return Ok(());
	};

	debug!("Updating repository at {}", path.display());
	update_branches_in(&repository, branches)?;
	debug!("Finished updating!");

	Ok(())
}