Sebastian Thielmake fmte22080e3 years agoHistory
511 lines · 17.0 KB · Rust
RawDownload
use std::{    borrow::Cow,    fmt::{Display, Formatter},}; use crosstermion::crossterm::style::Stylize;use git_repository as git;use owo_colors::OwoColorize;use tabled::{Style, TableIteratorExt, Tabled}; #[derive(Clone)]enum Usage {    /// It's not reasonable to implement it as the prerequisites don't apply.    NotApplicable { reason: &'static str },    /// We have no intention to implement it, but that can change if there is demand.    NotPlanned { reason: &'static str },    /// We definitely want to implement this configuration value.    Planned { note: Option<&'static str> },    /// The configuration is already used, possibly with a given `deviation`.    InUse { deviation: Option<&'static str> },    /// Needs analysis, unclear how it works or what it does.    Puzzled,}use Usage::*; impl Display for Usage {    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {        match self {            Puzzled => f.write_str("❓")?,            NotApplicable { reason } => write!(f, "not applicable: {reason}")?,            NotPlanned { reason } => {                write!(f, "{}", "not planned".blink())?;                write!(f, " ℹ {} ℹ", reason.bright_white())?;            }            Planned { note } => {                write!(f, "{}", "planned".blink())?;                if let Some(note) = note {                    write!(f, " ℹ {} ℹ", note.bright_white())?;                }            }            InUse { deviation } => {                if let Some(deviation) = deviation {                    write!(f, "{}", format!("❗️{deviation}❗️").bright_white())?                }            }        }        Ok(())    }} impl Usage {    pub fn icon(&self) -> &'static str {        match self {            Puzzled => "?",            NotApplicable { .. } => "❌",            Planned { .. } => "🕒",            NotPlanned { .. } => "🤔",            InUse { deviation, .. } => {                if deviation.is_some() {                    "👌️"                } else {                    "✅"                }            }        }    }} #[derive(Clone)]struct Record {    config: &'static str,    usage: Usage,} impl Tabled for Record {    const LENGTH: usize = 3;     fn fields(&self) -> Vec<Cow<'_, str>> {        let mut tokens = self.config.split('.');        let mut buf = vec![{            let name = tokens.next().expect("present");            if name == "gitoxide" {                name.bold().green()            } else {                name.bold()            }            .to_string()        }];        buf.extend(tokens.map(ToOwned::to_owned));         vec![            Cow::Borrowed(self.usage.icon()),            buf.join(".").into(),            self.usage.to_string().into(),        ]    }     fn headers() -> Vec<Cow<'static, str>> {        vec![]    }} static GIT_CONFIG: &[Record] = &[    Record {        config: "core.safeCRLF",        usage: Planned { note: Some("safety is not optional") },    },    Record {        config: "core.hideDotFiles",        usage: Planned {note: Some("Seems useful, but needs demand from windows users")}    },    Record {        config: "core.packedGitWindowSize",        usage: NotPlanned { reason: "an optimization for handling many large packs more efficiently seems unnecessary" }    },    Record {        config: "core.packedGitLimit",        usage: NotApplicable { reason: "we target 32bit systems only and don't use a windowing mechanism" }    },    Record {        config: "core.bigFileThreshold",        usage: Planned { note: Some("unfortunately we can't stream packed files yet, even if not delta-compressed, but respecting the threshold for other operations is definitely a must") }    },    Record {        config: "core.compression",        usage: Planned { note: Some("Allow to remove similar hardcoded value - passing it through will be some effort") },    },    Record {        config: "core.loosecompression",        usage: Planned { note: None },    },    Record {        config: "core.protectHFS",        usage: Planned { note: Some("relevant for checkout on MacOS") },    },    Record {        config: "core.protectNTFS",        usage: NotPlanned { reason: "lack of demand"},    },    Record {        config: "core.sparseCheckout",        usage: Planned { note: Some("we want to support huge repos and be the fastest in doing so") },    },    Record {        config: "core.sparseCheckoutCone",        usage: Planned { note: Some("this is a nice improvement over spareCheckout alone and should one day be available too") },    },    Record {        config: "checkout.defaultRemote",        usage: Planned { note: Some("needed for correct checkout behaviour, similar to what git does") },    },    Record {        config: "core.untrackedCache",        usage: Planned { note: Some("needed for fast worktree operation") },    },    Record {        config: "checkout.guess",        usage: Planned { note: None },    },    Record {        config: "checkout.thresholdForParallelism",        usage: NotApplicable {reason: "parallelism is efficient enough to always run with benefit"},    },    Record {        config: "feature.manyFile",        usage: Planned {note: Some("big repositories are on the roadmap")},    },    Record {        config: "core.preloadIndex",        usage: Planned {note: Some("it's enabled by default and allows parallel stat checks - it's using a lot of CPU for just minor performance boosts though")},    },    Record {        config: "index.sparse",        usage: Planned {note: Some("we can read sparse indices and support for it will be added early on")},    },    Record {        config: "merge.renormalize",        usage: Planned {note: Some("once merging is being implemented, renormalization should be respected")},    },    Record {        config: "sparse.expectFilesOutsideOfPatterns",        usage: Planned {note: Some("a feature definitely worth having")},    },    Record {        config: "submodule.recurse",        usage: Planned {note: Some("very relevant for doing the right thing during checkouts")},    },    Record {        config: "branch.autoSetupRebase",        usage: Planned {            note: Some("for when we allow setting up upstream branches")        },    },    Record {        config: "branch.<name>.rebase",        usage: Planned {            note: Some("for when we can merge, rebase should be supported")        },    },    Record {        config: "branch.<name>.description",        usage: NotPlanned {            reason: "no plan to implement format-patch or request-pull summary"        },    },    Record {        config: "core.eol",        usage: Planned {note: Some("needed for filters, but also for doing diffs correctly")}    },    Record {    config: "clone.filterSubmodules,",        usage: Planned {            note: Some("currently object filtering isn't support, a prerequisite for this, see --filter=blob:none for more"),        },    },    Record {        config: "clone.rejectShallow",        usage: NotPlanned {            reason: "it's not a use-case we consider important now, but once that changes it can be implemented",        },    },    Record {        config: "fetch.recurseSubmodules",        usage: Planned {            note: Some("Seems useful for cargo as well"),        },    },    Record {        config: "fetch.fsckObjects",        usage: Puzzled,    },    Record {        config: "fetch.fsck.<msg-id>",        usage: Puzzled,    },    Record {        config: "fetch.fsck.skipList",        usage: Puzzled,    },    Record {        config: "fetch.unpackLimit",        usage: Planned { note: None },    },    Record {        config: "fetch.prune",        usage: Planned { note: None },    },    Record {        config: "fetch.pruneTags",        usage: Planned { note: None },    },    Record {        config: "fetch.writeCommitGraph",        usage: Planned { note: None },    },    Record {        config: "fetch.parallel",        usage: Planned { note: None },    },    Record {        config: "fetch.showForcedUpdates",        usage: NotApplicable {reason: "we don't support advices"},    },    Record {        config: "fetch.output",        usage: NotPlanned {reason: "'gix' might support it, but there is no intention on copying the 'git' CLI"},    },    Record {        config: "fetch.negotiationAlgorithm",        usage: Planned {            note: Some("Implements our own 'naive' algorithm, only"),        },    },    Record {        config: "remotes.<group>",        usage: Planned {            note: Some("useful for multi-remote fetches as part of the standard API, maybe just `group(name) -> Option<Vec<Remote>>`"),        },    },    Record {        config: "advice.updateSparsePath",        usage: NotApplicable { reason: "gitoxide does not yet have an 'advice' system" },    },    Record {        config: "core.sparseCheckout",        usage: Planned { note: Some("together with 'index.sparse' and 'core.sparseCheckoutCone', configures if the index should be written sparse or not") },    },    Record {        config: "core.sparseCheckoutCone",        usage: Planned { note: Some("non-cone mode is deprecated but should still fail gracefully if encountered") },    },    Record {        config: "core.splitIndex",        usage: NotPlanned { reason: "we don't want to be able to create split indices, but we will read them. It's (somewhat) superseded by sparse indices" },    },    Record {        config: "splitIndex.maxPercentageChange",        usage: NotPlanned { reason: "seems like it's superseded by sparse indices" },    },    Record {        config: "splitIndex.sharedIndexExpire",        usage: NotPlanned { reason: "seems like it's superseded by sparse indices" },    },    Record {        config: "index.sparse",        usage: Planned { note: Some("together with 'core.sparseCheckout' and 'core.sparseCheckoutCone', configures if the index should be written sparse or not") },    },    Record {        config: "index.version",        usage: Planned { note: Some("once V4 indices can be written, we need to be able to set a desired version. For now we write the smallest possible index version only.") },    },    Record {        config: "http.<url>.*",        usage: Planned { note: Some("definitely needed for correctness, testing against baseline is a must") }    },    Record {        config: "http.proxySSLCert",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.proxySSLKey",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.proxySSLCertPasswordProtected",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.proxySSLCAInfo",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.emptyAuth",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.delegation",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.cookieFile",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.saveCookies",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.curloptResolve",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCipherList",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCipherList",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslVerify",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCert",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslKey",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCertPasswordProtected",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCertPasswordProtected",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslCAPath",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslBackend",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.pinnedPubkey",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.sslTry",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.maxRequests",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.minSessions",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.postBuffer",        usage: Planned { note: Some("relevant when implementing push, we should understand how memory allocation works when streaming") }    },    Record {        config: "http.noEPSV",        usage: NotPlanned { reason: "on demand" }    },    Record {        config: "http.<url>.*",        usage: Planned { note: Some("it's a vital part of git configuration. It's unclear how to get a baseline from git for this one.") }    },    Record {        config: "init.templateDir",        usage: NotPlanned { reason: "git expects this dir to be a valid git dir - I'd find additive template dirs more interesting, or changes done afterwards procedurally. Maybe this needs a 'init_or_open' semantic to be really useful" }    },    Record {        config: "sparse.expectFilesOutsideOfPatterns",        usage: NotPlanned { reason: "todo" },    },    Record {        config: "remote.<name>.promisor",        usage: Planned {            note: Some("required for big monorepos, and typically used in conjunction with sparse indices")        }    },    Record {        config: "remote.<name>.partialCloneFilter",        usage: Planned {            note: Some("required for big monorepos, and typically used in conjunction with sparse indices")        }    },]; /// A programmatic way to record and display progress.pub fn show_progress() -> anyhow::Result<()> {    let sorted = {        let mut v: Vec<_> = GIT_CONFIG.into();        v.extend(git::config::Tree.sections().iter().flat_map(|section| {            fn to_record(key: &dyn git::config::tree::Key) -> Record {                let config = key.logical_name();                let note = key.note().map(|note| match note {                    git::config::tree::Note::Deviation(n) | git::config::tree::Note::Informative(n) => n.to_string(),                });                let link = key.link().map(|link| match link {                    git::config::tree::Link::FallbackKey(key) => format!("fallback is '{}'", key.logical_name()),                    git::config::tree::Link::EnvironmentOverride(name) => format!("overridden by '{name}'"),                });                let deviation = match (note, link) {                    (Some(n), Some(l)) => Some(format!("{n}. {l}")),                    (Some(n), None) | (None, Some(n)) => Some(n),                    (None, None) => None,                }                .map(|d| &*Box::leak(d.into_boxed_str()));                Record {                    config: Box::leak(config.into_boxed_str()),                    usage: InUse { deviation },                }            }            section                .sub_sections()                .iter()                .flat_map(|sub_section| sub_section.keys().iter().map(|key| to_record(*key)))                .chain(section.keys().iter().map(|key| to_record(*key)))        }));        v.sort_by_key(|r| r.config);        v.dedup_by_key(|r| r.config);        v    };     let mut buf = String::new();    use std::fmt::Write;    writeln!(&mut buf,        "\nTotal records: {} ({perfect_icon} = {perfect}, {deviation_icon} = {deviation}, {planned_icon} = {planned}, {ondemand_icon} = {ondemand}, {not_applicable_icon} = {not_applicable})",        sorted.len(),        perfect_icon = InUse {            deviation: None        }        .icon(),        deviation_icon = InUse {            deviation: Some("")        }        .icon(),        planned_icon = Planned { note: None }.icon(),        planned = sorted.iter().filter(|e| matches!(e.usage, Planned { .. })).count(),        ondemand_icon = NotPlanned { reason: "" }.icon(),        not_applicable_icon = NotApplicable { reason: "" }.icon(),        perfect = sorted            .iter()            .filter(|e| matches!(e.usage, InUse { deviation, .. } if deviation.is_none()))            .count(),        deviation = sorted            .iter()            .filter(|e| matches!(e.usage, InUse { deviation, .. } if deviation.is_some()))            .count(),        ondemand = sorted            .iter()

Lines 1–500 of 511.