Refactor: Move mod git into binstalk-downloader (#1285)

To speedup codegen time for `binstalk`, also fixed the docs.rs build for
`binstalk-downloader`.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-08-12 17:20:26 +10:00 committed by GitHub
parent 6a1d317fde
commit c57356e870
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 14 additions and 7 deletions

View file

@ -19,7 +19,6 @@ command-group = { version = "2.1.0", features = ["with-tokio"] }
compact_str = { version = "0.7.0", features = ["serde"] }
detect-targets = { version = "0.1.10", path = "../detect-targets" }
either = "1.8.1"
gix = { version = "0.51.0", features = ["blocking-http-transport-reqwest-rust-tls"], optional = true }
glob = "0.3.1"
home = "0.5.5"
itertools = "0.11.0"
@ -53,8 +52,8 @@ windows = { version = "0.48.0", features = ["Win32_Storage_FileSystem", "Win32_F
[features]
default = ["static", "rustls", "git"]
git = ["dep:gix"]
git-max-perf = ["gix?/max-performance"]
git = ["binstalk-downloader/git"]
git-max-perf = ["binstalk-downloader/git-max-perf"]
static = ["binstalk-downloader/static"]
pkg-config = ["binstalk-downloader/pkg-config"]

View file

@ -1,7 +1,5 @@
pub(crate) mod cargo_toml_workspace;
pub(crate) mod futures_resolver;
#[cfg(feature = "git")]
pub(crate) mod git;
pub mod jobserver_client;
pub mod remote;
pub mod signal;
@ -11,6 +9,9 @@ pub mod tasks;
pub use binstalk_downloader::gh_api_client;
pub(crate) use binstalk_downloader::{bytes, download};
#[cfg(feature = "git")]
pub(crate) use binstalk_downloader::git;
pub(crate) fn is_universal_macos(target: &str) -> bool {
["universal-apple-darwin", "universal2-apple-darwin"].contains(&target)
}

View file

@ -1,175 +0,0 @@
use std::{fmt, mem, num::NonZeroU32, path::Path, str::FromStr, sync::atomic::AtomicBool};
use compact_str::CompactString;
use gix::{clone, create, open, remote, Url};
use thiserror::Error as ThisError;
use tracing::debug;
mod progress_tracing;
use progress_tracing::TracingProgress;
pub use gix::url::parse::Error as GitUrlParseError;
#[derive(Debug, ThisError)]
#[non_exhaustive]
pub enum GitError {
#[error("Failed to prepare for fetch: {0}")]
PrepareFetchError(#[source] Box<clone::Error>),
#[error("Failed to fetch: {0}")]
FetchError(#[source] Box<clone::fetch::Error>),
#[error("Failed to checkout: {0}")]
CheckOutError(#[source] Box<clone::checkout::main_worktree::Error>),
#[error("HEAD ref was corrupt in crates-io index repository clone")]
HeadCommit(#[source] Box<gix::reference::head_commit::Error>),
#[error("tree of head commit wasn't present in crates-io index repository clone")]
GetTreeOfCommit(#[source] Box<gix::object::commit::Error>),
#[error("An object was missing in the crates-io index repository clone")]
ObjectLookup(#[source] Box<gix::object::find::existing::Error>),
}
impl From<clone::Error> for GitError {
fn from(e: clone::Error) -> Self {
Self::PrepareFetchError(Box::new(e))
}
}
impl From<clone::fetch::Error> for GitError {
fn from(e: clone::fetch::Error) -> Self {
Self::FetchError(Box::new(e))
}
}
impl From<clone::checkout::main_worktree::Error> for GitError {
fn from(e: clone::checkout::main_worktree::Error) -> Self {
Self::CheckOutError(Box::new(e))
}
}
impl From<gix::reference::head_commit::Error> for GitError {
fn from(e: gix::reference::head_commit::Error) -> Self {
Self::HeadCommit(Box::new(e))
}
}
impl From<gix::object::commit::Error> for GitError {
fn from(e: gix::object::commit::Error) -> Self {
Self::GetTreeOfCommit(Box::new(e))
}
}
impl From<gix::object::find::existing::Error> for GitError {
fn from(e: gix::object::find::existing::Error) -> Self {
Self::ObjectLookup(Box::new(e))
}
}
#[derive(Clone, Debug)]
pub struct GitUrl(Url);
impl fmt::Display for GitUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let url_bstr = self.0.to_bstring();
let url_str = String::from_utf8_lossy(&url_bstr);
f.write_str(&url_str)
}
}
impl FromStr for GitUrl {
type Err = GitUrlParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Url::try_from(s).map(Self)
}
}
#[derive(Debug)]
pub struct Repository(gix::ThreadSafeRepository);
impl Repository {
fn prepare_fetch(
url: GitUrl,
path: &Path,
kind: create::Kind,
) -> Result<clone::PrepareFetch, GitError> {
Ok(clone::PrepareFetch::new(
url.0,
path,
kind,
create::Options {
destination_must_be_empty: true,
..Default::default()
},
open::Options::isolated(),
)?
.with_shallow(remote::fetch::Shallow::DepthAtRemote(
NonZeroU32::new(1).unwrap(),
)))
}
/// WARNING: This is a blocking operation, if you want to use it in
/// async context then you must wrap the call in [`tokio::task::spawn_blocking`].
///
/// WARNING: This function must be called after tokio runtime is initialized.
pub fn shallow_clone_bare(url: GitUrl, path: &Path) -> Result<Self, GitError> {
debug!("Shallow cloning {url} to {}", path.display());
Ok(Self(
Self::prepare_fetch(url, path, create::Kind::Bare)?
.fetch_only(
&mut TracingProgress::new(CompactString::new("Cloning")),
&AtomicBool::new(false),
)?
.0
.into(),
))
}
/// WARNING: This is a blocking operation, if you want to use it in
/// async context then you must wrap the call in [`tokio::task::spawn_blocking`].
///
/// WARNING: This function must be called after tokio runtime is initialized.
pub fn shallow_clone(url: GitUrl, path: &Path) -> Result<Self, GitError> {
debug!("Shallow cloning {url} to {} with worktree", path.display());
let mut progress = TracingProgress::new(CompactString::new("Cloning"));
Ok(Self(
Self::prepare_fetch(url, path, create::Kind::WithWorktree)?
.fetch_then_checkout(&mut progress, &AtomicBool::new(false))?
.0
.main_worktree(&mut progress, &AtomicBool::new(false))?
.0
.into(),
))
}
#[inline(always)]
pub fn get_head_commit_entry_data_by_path(
&self,
path: impl AsRef<Path>,
) -> Result<Option<Vec<u8>>, GitError> {
fn inner(this: &Repository, path: &Path) -> Result<Option<Vec<u8>>, GitError> {
Ok(
if let Some(entry) = this
.0
.to_thread_local()
.head_commit()?
.tree()?
.peel_to_entry_by_path(path)?
{
Some(mem::take(&mut entry.object()?.data))
} else {
None
},
)
}
inner(self, path.as_ref())
}
}

View file

@ -1,144 +0,0 @@
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use compact_str::{format_compact, CompactString};
use gix::progress::{
prodash::messages::MessageLevel, Id, Progress, Step, StepShared, Unit, UNKNOWN,
};
use tokio::time;
use tracing::{error, info};
pub(super) struct TracingProgress {
name: CompactString,
id: Id,
max: Option<usize>,
unit: Option<Unit>,
step: usize,
trigger: Arc<AtomicBool>,
}
const EMIT_LOG_EVERY_S: f32 = 0.5;
const SEP: &str = "::";
impl TracingProgress {
/// Create a new instanCompactce from `name`.
pub fn new(name: CompactString) -> Self {
let trigger = Arc::new(AtomicBool::new(true));
tokio::spawn({
let mut interval = time::interval(Duration::from_secs_f32(EMIT_LOG_EVERY_S));
interval.set_missed_tick_behavior(time::MissedTickBehavior::Skip);
let trigger = Arc::clone(&trigger);
async move {
while Arc::strong_count(&trigger) > 1 {
trigger.store(true, Ordering::Relaxed);
interval.tick().await;
}
}
});
Self {
name,
id: UNKNOWN,
max: None,
step: 0,
unit: None,
trigger,
}
}
}
impl Progress for TracingProgress {
type SubProgress = TracingProgress;
fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
self.add_child_with_id(name, UNKNOWN)
}
fn add_child_with_id(&mut self, name: impl Into<String>, id: Id) -> Self::SubProgress {
Self {
name: format_compact!("{}{}{}", self.name, SEP, Into::<String>::into(name)),
id,
step: 0,
max: None,
unit: None,
trigger: Arc::clone(&self.trigger),
}
}
fn init(&mut self, max: Option<usize>, unit: Option<Unit>) {
self.max = max;
self.unit = unit;
}
fn set(&mut self, step: usize) {
self.step = step;
if self.trigger.swap(false, Ordering::Relaxed) {
match (self.max, &self.unit) {
(max, Some(unit)) => {
info!("{} → {}", self.name, unit.display(step, max, None))
}
(Some(max), None) => info!("{} → {} / {}", self.name, step, max),
(None, None) => info!("{} → {}", self.name, step),
}
}
}
fn unit(&self) -> Option<Unit> {
self.unit.clone()
}
fn max(&self) -> Option<usize> {
self.max
}
fn set_max(&mut self, max: Option<Step>) -> Option<Step> {
let prev = self.max;
self.max = max;
prev
}
fn step(&self) -> usize {
self.step
}
fn inc_by(&mut self, step: usize) {
self.set(self.step + step)
}
fn set_name(&mut self, name: impl Into<String>) {
let name = name.into();
self.name = self
.name
.split("::")
.next()
.map(|parent| format_compact!("{}{}{}", parent.to_owned(), SEP, name))
.unwrap_or_else(|| name.into());
}
fn name(&self) -> Option<String> {
self.name.split(SEP).nth(1).map(ToOwned::to_owned)
}
fn id(&self) -> Id {
self.id
}
fn message(&self, level: MessageLevel, message: impl Into<String>) {
let message: String = message.into();
match level {
MessageLevel::Info => info!("{} → {}", self.name, message),
MessageLevel::Failure => error!("𐄂{} → {}", self.name, message),
MessageLevel::Success => info!("✓{} → {}", self.name, message),
}
}
fn counter(&self) -> Option<StepShared> {
None
}
}