diff --git a/Cargo.toml b/Cargo.toml index 7b529927..81ab6e14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ clap = { version = "~4.6", default-features = false, features = [ ctrlc = "3.4" encoding_rs = "0.8" flate2 = "1" -gix = { version = "0.85", default-features = false, features = [ +gix = { version = "0.86", default-features = false, features = [ "command", "revision", "sha1", diff --git a/src/alias.rs b/src/alias.rs index 92fb45c0..85f1937b 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -100,15 +100,9 @@ where .filter(|section| section.header().subsection_name() == Some("alias".into())) { for value_name in section.value_names() { - let name = value_name.to_str().map_err(|_| { - anyhow!( - "alias name `{}` in {} is not valid UTF-8", - value_name.to_str_lossy(), - config_source_str(section.meta().source), - ) - })?; + let name = value_name.as_str(); if let Some(value) = section - .value(value_name) + .value(name) .and_then(|v| (!v.is_empty()).then_some(v)) { if !exclude(name) { diff --git a/src/cmd/branch/list.rs b/src/cmd/branch/list.rs index c377e1b5..220785a0 100644 --- a/src/cmd/branch/list.rs +++ b/src/cmd/branch/list.rs @@ -101,7 +101,7 @@ pub(super) fn dispatch(repo: &gix::Repository, matches: &clap::ArgMatches) -> Re stdout.set_color(&color_spec)?; let description = config - .string_by("branch", Some(branchname.into()), "description") + .string(format!("branch.{branchname}.description").as_str()) .unwrap_or_default(); if description.is_empty() { writeln!(stdout)?; diff --git a/src/cmd/branch/mod.rs b/src/cmd/branch/mod.rs index 1234780c..495350f6 100644 --- a/src/cmd/branch/mod.rs +++ b/src/cmd/branch/mod.rs @@ -151,7 +151,7 @@ fn set_description( value.delete(); } if let Ok(section) = local_config_file.section("branch", Some(branchname.into())) { - if section.num_values() == 0 { + if section.body().num_values() == 0 { local_config_file.remove_section_by_id(section.id()); } } @@ -171,11 +171,7 @@ fn set_description( fn get_stgit_parent(config: &gix::config::Snapshot, branchname: &PartialRefName) -> Option { config - .string_by( - "branch", - Some(format!("{branchname}.stgit").as_str().into()), - "parentbranch", - ) + .string(format!("branch.{branchname}.stgit.parentbranch").as_str()) .and_then(|bs| bs.to_str().ok().map(str::to_string)) } @@ -202,7 +198,7 @@ fn set_stgit_parent( value.delete(); } if let Ok(section) = local_config_file.section("branch", Some(subsection.as_str().into())) { - if section.num_values() == 0 { + if section.body().num_values() == 0 { local_config_file.remove_section_by_id(section.id()); } } diff --git a/src/cmd/branch/rename.rs b/src/cmd/branch/rename.rs index 6a51044d..8f2d9800 100644 --- a/src/cmd/branch/rename.rs +++ b/src/cmd/branch/rename.rs @@ -84,8 +84,7 @@ pub(super) fn dispatch(repo: &gix::Repository, matches: &clap::ArgMatches) -> Re .section("branch", Some(old_section_name)) .is_ok() { - let new_section_name = - std::borrow::Cow::Owned(BString::from(format!("{new_branchname}.stgit"))); + let new_section_name = BString::from(format!("{new_branchname}.stgit")); local_config_file .rename_section( "branch", diff --git a/src/cmd/pick.rs b/src/cmd/pick.rs index 85d22a6c..4b7957c3 100644 --- a/src/cmd/pick.rs +++ b/src/cmd/pick.rs @@ -297,7 +297,7 @@ fn pick_picks( {body}" ) } else if matches.get_flag("expose") { - let expose_format = config.string_by("stgit", Some("pick".into()), "expose-format"); + let expose_format = config.string("stgit.pick.expose-format"); let expose_format = expose_format .as_ref() .map(|bs| bs.to_str().ok()) diff --git a/src/cmd/pull.rs b/src/cmd/pull.rs index 567ec002..4ed5eba1 100644 --- a/src/cmd/pull.rs +++ b/src/cmd/pull.rs @@ -101,11 +101,7 @@ fn run(matches: &ArgMatches) -> Result<()> { let config = repo.config_snapshot(); let policy = PullPolicy::from_str( &config - .string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "pull-policy", - ) + .string(format!("branch.{branch_name}.stgit.pull-policy").as_str()) .or_else(|| config.string("stgit.pull-policy")) .map(|bs| bs.to_str_lossy().to_string()) .unwrap_or_else(|| "pull".to_string()), @@ -125,7 +121,7 @@ fn run(matches: &ArgMatches) -> Result<()> { } PullPolicy::Pull | PullPolicy::FetchRebase => { parent_remote = config - .string_by("branch", Some(branch_name.as_str().into()), "remote") + .string(format!("branch.{branch_name}.remote").as_str()) .and_then(|bs| bs.to_str().map(str::to_string).ok()); let remote_name = matches .get_one::("repository") @@ -163,11 +159,7 @@ fn run(matches: &ArgMatches) -> Result<()> { let rebase_target = match policy { PullPolicy::Pull => { let pull_cmd = config - .string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "pullcmd", - ) + .string(format!("branch.{branch_name}.stgit.pullcmd").as_str()) .or_else(|| config.string("stgit.pullcmd")) .and_then(|bs| bs.to_str().map(str::to_string).ok()) .unwrap_or_else(|| "git pull".to_string()); @@ -183,11 +175,7 @@ fn run(matches: &ArgMatches) -> Result<()> { } PullPolicy::FetchRebase => { let fetch_cmd = config - .string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "fetchcmd", - ) + .string(format!("branch.{branch_name}.stgit.fetchcmd").as_str()) .or_else(|| config.string("stgit.fetchcmd")) .and_then(|bs| bs.to_str().map(str::to_string).ok()) .unwrap_or_else(|| "git fetch".to_string()); @@ -203,11 +191,8 @@ fn run(matches: &ArgMatches) -> Result<()> { Some(target_id) } PullPolicy::Rebase => { - let parent_branch_name = config.string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "parentbranch", - ); + let parent_branch_name = + config.string(format!("branch.{branch_name}.stgit.parentbranch").as_str()); let parent_branch_name = parent_branch_name.as_ref().and_then(|bs| bs.to_str().ok()); let parent_object = if let Some(name) = parent_branch_name { @@ -227,11 +212,7 @@ fn run(matches: &ArgMatches) -> Result<()> { if let Some(rebase_target) = rebase_target { let rebase_cmd = config - .string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "rebasecmd", - ) + .string(format!("branch.{branch_name}.stgit.rebasecmd").as_str()) .or_else(|| config.string("stgit.rebasecmd")) .and_then(|bs| bs.to_str().map(str::to_string).ok()) .unwrap_or_else(|| "git reset --hard".to_string()); diff --git a/src/cmd/rebase.rs b/src/cmd/rebase.rs index d5f03502..42f25240 100644 --- a/src/cmd/rebase.rs +++ b/src/cmd/rebase.rs @@ -175,12 +175,7 @@ fn run(matches: &ArgMatches) -> Result<()> { true } else { config - .boolean_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "autostash", - ) - .transpose() + .try_boolean(format!("branch.{branch_name}.stgit.autostash").as_str()) .unwrap_or_else(|e| { crate::print_warning_message( matches, @@ -189,16 +184,13 @@ fn run(matches: &ArgMatches) -> Result<()> { Some(false) }) .or_else(|| { - config - .try_boolean("stgit.autostash") - .transpose() - .unwrap_or_else(|e| { - crate::print_warning_message( - matches, - &format!("Invalid config value `stgit.autostash`: {e}"), - ); - Some(false) - }) + config.try_boolean("stgit.autostash").unwrap_or_else(|e| { + crate::print_warning_message( + matches, + &format!("Invalid config value `stgit.autostash`: {e}"), + ); + Some(false) + }) }) .unwrap_or(false) }; @@ -225,11 +217,7 @@ fn run(matches: &ArgMatches) -> Result<()> { .execute("rebase (pop)")?; let rebase_cmd = config - .string_by( - "branch", - Some(format!("{branch_name}.stgit").as_str().into()), - "rebasecmd", - ) + .string(format!("branch.{branch_name}.stgit.rebasecmd").as_str()) .or_else(|| config.string("stgit.rebasecmd")) .and_then(|bs| bs.to_str().map(str::to_string).ok()) .unwrap_or_else(|| "git reset --hard".to_string()); diff --git a/src/ext/repository.rs b/src/ext/repository.rs index 7106ca55..0cbcf1db 100644 --- a/src/ext/repository.rs +++ b/src/ext/repository.rs @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -use std::borrow::Cow; - use anyhow::{anyhow, Result}; -use bstr::{BStr, ByteSlice}; +use bstr::{BString, ByteSlice}; use crate::{ stupid::Stupid, @@ -42,7 +40,7 @@ pub(crate) trait RepositoryExtended { /// Get repository-local config file which can be used to change local /// configuration. - fn local_config_file(&self) -> Result>; + fn local_config_file(&self) -> Result; /// Write repository-local config file. fn write_local_config(&self, file: gix::config::File) -> Result<()>; @@ -73,7 +71,7 @@ pub(crate) trait RepositoryExtended { message: &Message, tree_id: gix::ObjectId, parent_ids: impl IntoIterator, - options: &CommitOptions<'_>, + options: &CommitOptions, ) -> Result; /// [`gix::Repository::rev_parse_single()`] with StGit-specific error mapping. @@ -88,9 +86,9 @@ pub(crate) trait RepositoryExtended { } /// Options for creating a git commit object. -pub(crate) struct CommitOptions<'a> { +pub(crate) struct CommitOptions { /// The target encoding for the commit message. - pub(crate) commit_encoding: Option>, + pub(crate) commit_encoding: Option, /// Determine whether the commit object should be signed with GPG. pub(crate) gpgsign: bool, @@ -171,7 +169,7 @@ impl RepositoryExtended for gix::Repository { } } - fn local_config_file(&self) -> Result> { + fn local_config_file(&self) -> Result { let source = gix::config::Source::Local; let local_config_path = self.common_dir().join( @@ -233,11 +231,11 @@ impl RepositoryExtended for gix::Repository { message: &Message, tree_id: gix::ObjectId, parent_ids: impl IntoIterator, - options: &CommitOptions<'_>, + options: &CommitOptions, ) -> Result { let commit_encoding = match &options.commit_encoding { Some(s) => { - let encoding = encoding_rs::Encoding::for_label(s) + let encoding = encoding_rs::Encoding::for_label(s.as_ref()) .ok_or_else(|| anyhow!("unhandled i18n.commitEncoding `{s}`"))?; Some(encoding) } diff --git a/src/hook.rs b/src/hook.rs index c2018973..11a5d3b0 100644 --- a/src/hook.rs +++ b/src/hook.rs @@ -3,7 +3,6 @@ //! Support for using git repository hooks. use std::{ - borrow::Cow, io::Write, path::{Path, PathBuf}, }; @@ -18,22 +17,21 @@ use crate::wrap::Message; /// Returns None if the hook script is not found or is not executable. fn get_hook_path(repo: &gix::Repository, hook_name: &str) -> Result> { let config = repo.config_snapshot(); - let hooks_path = - if let Some(core_hooks_path) = config.trusted_path("core.hookspath").transpose()? { - if core_hooks_path.is_absolute() { - core_hooks_path - } else if repo.is_bare() { - // The hooks path is relative to GIT_DIR in the case of a bare repo - Cow::Owned(repo.common_dir().join(core_hooks_path)) - } else { - // The hooks path is relative to the root of the working tree otherwise - let work_dir = repo.workdir().expect("non-bare repo must have work dir"); - Cow::Owned(work_dir.join(core_hooks_path)) - } + let hooks_path = if let Some(core_hooks_path) = config.trusted_path("core.hookspath")? { + if core_hooks_path.is_absolute() { + core_hooks_path + } else if repo.is_bare() { + // The hooks path is relative to GIT_DIR in the case of a bare repo + repo.common_dir().join(core_hooks_path) } else { - // No core.hookspath, use default .git/hooks location - Cow::Owned(repo.common_dir().join("hooks")) - }; + // The hooks path is relative to the root of the working tree otherwise + let work_dir = repo.workdir().expect("non-bare repo must have work dir"); + work_dir.join(core_hooks_path) + } + } else { + // No core.hookspath, use default .git/hooks location + repo.common_dir().join("hooks") + }; let hook_path = hooks_path.join(hook_name); let hook_meta = match std::fs::metadata(&hook_path) { diff --git a/src/patch/edit/interactive.rs b/src/patch/edit/interactive.rs index 11a10719..4aef69c3 100644 --- a/src/patch/edit/interactive.rs +++ b/src/patch/edit/interactive.rs @@ -135,15 +135,13 @@ fn get_editor(config: &gix::config::Snapshot) -> Result { let editor = if let Some(editor) = std::env::var_os("GIT_EDITOR") { editor } else if let Some(editor) = config - .trusted_path("stgit.editor") - .transpose()? - .map(|p| p.as_os_str().to_os_string()) + .trusted_path("stgit.editor")? + .map(|p| p.into_os_string()) { editor } else if let Some(editor) = config - .trusted_path("core.editor") - .transpose()? - .map(|p| p.as_os_str().to_os_string()) + .trusted_path("core.editor")? + .map(|p| p.into_os_string()) { editor } else if let Some(editor) = std::env::var_os("VISUAL") { diff --git a/src/stack/stack.rs b/src/stack/stack.rs index 847f7135..25049fac 100644 --- a/src/stack/stack.rs +++ b/src/stack/stack.rs @@ -238,12 +238,7 @@ impl<'repo> Stack<'repo> { /// Check whether the stack is marked as protected in the config. pub(crate) fn is_protected(&self, config: &gix::config::Snapshot) -> bool { config - .boolean_by( - "branch", - Some(format!("{}.stgit", self.branch_name).as_str().into()), - "protect", - ) - .unwrap_or(Ok(false)) + .boolean(format!("branch.{}.stgit.protect", self.branch_name).as_str()) .unwrap_or(false) } @@ -271,7 +266,7 @@ impl<'repo> Stack<'repo> { if let Ok(section) = local_config_file .section_by_key(format!("{section}.{subsection}").as_bytes().as_bstr()) { - if section.num_values() == 0 { + if section.body().num_values() == 0 { local_config_file.remove_section_by_id(section.id()); } } diff --git a/src/stack/upgrade.rs b/src/stack/upgrade.rs index 12a28675..4c48ee0a 100644 --- a/src/stack/upgrade.rs +++ b/src/stack/upgrade.rs @@ -325,7 +325,7 @@ fn rm_stackformatversion(repo: &gix::Repository, branch_name: &str) -> Result<() if let Ok(section) = local_config_file.section_by_key(format!("{section}.{subsection}").as_bytes().as_bstr()) { - if section.num_values() == 0 { + if section.body().num_values() == 0 { local_config_file.remove_section_by_id(section.id()); } }