Skip to content

Commit

Permalink
feat(pkgbuild): add PKGBUILD editing functionality
Browse files Browse the repository at this point in the history
Add support for editing PKGBUILDs before building packages, similar to yay's
--editmenu option. This allows users to review and modify PKGBUILDs before
they are built.

The implementation includes:
- New editor selection logic that respects --editor flag, $VISUAL, and $EDITOR
- Command line options --editmenu, --editor, and --editorflags

Usage:
  paru --editmenu -S package            # Enable PKGBUILD editing
  paru --editor vim --editmenu package  # Use specific editor
  • Loading branch information
Roman Stingler committed Dec 28, 2024
1 parent d0329e3 commit e9016d2
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 7 deletions.
35 changes: 35 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ regex = "1.11.1"
signal-hook = "0.3.17"
bitflags = "2.6.0"
toml = { version = "0.8.19", features = ["preserve_order"] }
which = "7.0.0"
shell-words = "1.1.0"

[profile.release]
codegen-units = 1
Expand Down
7 changes: 3 additions & 4 deletions src/command_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ impl Config {
Arg::Long("fm") => self.fm = Some(value?.to_string()),
Arg::Long("pager") => self.pager_cmd = Some(value?.to_string()),
Arg::Long("config") => self.pacman_conf = Some(value?.to_string()),

Arg::Long("editor") => self.editor = Some(value?.to_string()),
Arg::Long("editorflags") => self.editor_flags.extend(split_whitespace(value?)),
Arg::Long("editmenu") => self.edit_menu = true,
Arg::Long("builddir") | Arg::Long("clonedir") => self.build_dir = value?.into(),
Arg::Long("develfile") => self.devel_path = value?.into(),
Arg::Long("makepkgconf") => self.makepkg_conf = Some(value?.to_string()),
Expand All @@ -198,11 +200,9 @@ impl Config {
Arg::Long("chrootpkgs") => self
.chroot_pkgs
.extend(value?.split(',').map(|s| s.to_string())),

Arg::Long("develsuffixes") => self.devel_suffixes = split_whitespace(value?),
Arg::Long("installdebug") => self.install_debug = true,
Arg::Long("noinstalldebug") => self.install_debug = false,

Arg::Long("completioninterval") => {
self.completion_interval = value?
.parse()
Expand Down Expand Up @@ -295,7 +295,6 @@ impl Config {
Arg::Long("list") | Arg::Short('l') => self.list = true,
Arg::Long("delete") | Arg::Short('d') => self.delete += 1,
Arg::Long("noinstall") => self.no_install = true,

Arg::Long("print") | Arg::Short('p') => self.print = true,
Arg::Long("newsonupgrade") => self.news_on_upgrade = true,
Arg::Long("nonewsonupgrade") => self.news_on_upgrade = false,
Expand Down
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,10 @@ pub struct Config {
pub ignore_devel_builder: GlobSetBuilder,
pub assume_installed: Vec<String>,

pub edit_menu: bool,
pub editor: Option<String>,
pub editor_flags: Vec<String>,

#[default(PkgbuildRepos::new(aur_fetch::Fetch::with_cache_dir("repo")))]
pub pkgbuild_repos: PkgbuildRepos,
}
Expand Down Expand Up @@ -1023,6 +1027,9 @@ then initialise it with:
"FileManagerFlags" => self.fm_flags.extend(split),
"ChrootFlags" => self.chroot_flags.extend(split),
"PreBuildCommand" => self.pre_build_command = Some(value),
"Editor" => self.editor = Some(value),
"EditorFlags" => self.editor_flags.extend(split),
"EditMenu" => self.edit_menu = true,
_ => eprintln!(
"{}",
tr!("error: unknown option '{}' in section [bin]", key)
Expand Down Expand Up @@ -1135,6 +1142,11 @@ then initialise it with:
self.mode |= word.parse()?;
}
}
"Editor" => self.editor = Some(value?),
"EditorFlags" => self
.editor_flags
.extend(value?.split_whitespace().map(|s| s.to_string())),
"EditMenu" => self.edit_menu = true,
_ => ok2 = false,
};

Expand Down
22 changes: 19 additions & 3 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::devel::{fetch_devel_info, load_devel_info, save_devel_info, DevelInfo
use crate::download::{self, Bases};
use crate::fmt::{print_indent, print_install, print_install_verbose};
use crate::keys::check_pgp_keys;
use crate::pkgbuild::PkgbuildRepo;
use crate::pkgbuild::{edit_pkgbuilds, PkgbuildRepo};
use crate::resolver::{flags, resolver};
use crate::upgrade::{get_upgrades, Upgrades};
use crate::util::{ask, repo_aur_pkgs, split_repo_aur_targets};
Expand Down Expand Up @@ -206,6 +206,7 @@ impl Installer {
bail!(tr!("could not find .SRCINFO for '{}'", base.package_base()));
}
}

Ok(())
}

Expand Down Expand Up @@ -1109,7 +1110,12 @@ impl Installer {
};

if !config.skip_review && actions.iter_aur_pkgs().next().is_some() {
if !ask(config, &tr!("Proceed to review?"), true) {
let msg = if config.edit_menu {
tr!("Proceed to edit and review?")
} else {
tr!("Proceed to review?")
};
if !ask(config, &msg, true) {
return Status::err(1);
}
} else if !ask(config, &tr!("Proceed with installation?"), true) {
Expand All @@ -1126,6 +1132,16 @@ impl Installer {
let bases = actions.iter_aur_pkgs().cloned().collect();
self.download_pkgbuilds(config, &bases).await?;

if config.edit_menu {
let paths: Vec<PathBuf> = bases
.bases
.iter()
.map(|base| config.build_dir.join(base.package_base()))
.collect();

edit_pkgbuilds(config, &paths)?;
}

for pkg in &actions.build {
match pkg {
Base::Aur(base) => {
Expand Down Expand Up @@ -1155,6 +1171,7 @@ impl Installer {
Base::Pkgbuild(_) => None,
})
.collect::<Vec<_>>();

review(config, &config.fetch, &pkgs)?;
}

Expand Down Expand Up @@ -1257,7 +1274,6 @@ fn print_warnings(config: &Config, cache: &Cache, actions: Option<&Actions>) {
if !config.mode.aur() && !config.mode.pkgbuild() {
return;
}

if config.args.has_arg("u", "sysupgrade") && config.mode.aur() {
let (_, mut pkgs) = repo_aur_pkgs(config);
pkgs.retain(|pkg| config.pkgbuild_repos.pkg(config, pkg.name()).is_none());
Expand Down
64 changes: 64 additions & 0 deletions src/pkgbuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ use url::Url;

use crate::{config::Config, print_error};

use shell_words::split;
use std::env;
use std::process::Command;

#[derive(Debug, Default, Clone)]
pub enum RepoSource {
Url(Url, Option<PathBuf>),
Expand Down Expand Up @@ -410,3 +414,63 @@ pub fn read_srcinfo_from_pkgbuild(config: &Config, dir: &Path) -> Result<Srcinfo
.with_context(|| dir.display().to_string())?;
Ok(srcinfo)
}

pub fn get_editor(config: &Config) -> Result<(String, Vec<String>)> {
if let Some(editor) = &config.editor {
let editor_path =
which::which(editor).with_context(|| tr!("editor '{}' not found", editor))?;
return Ok((
editor_path.to_string_lossy().to_string(),
config.editor_flags.clone(),
));
}

if let Ok(visual) = env::var("VISUAL") {
if !visual.is_empty() {
let args: Vec<String> = split(&visual)?;
if let Some(editor) = args.first() {
if let Ok(editor_path) = which::which(editor) {
return Ok((
editor_path.to_string_lossy().to_string(),
args[1..].to_vec(),
));
}
}
}
}

if let Ok(editor) = env::var("EDITOR") {
if !editor.is_empty() {
let args: Vec<String> = split(&editor)?;
if let Some(editor) = args.first() {
if let Ok(editor_path) = which::which(editor) {
return Ok((
editor_path.to_string_lossy().to_string(),
args[1..].to_vec(),
));
}
}
}
}

bail!(tr!("no editor found, please set $EDITOR or $VISUAL"))
}

pub fn edit_pkgbuilds(config: &Config, paths: &[PathBuf]) -> Result<()> {
let (editor, mut editor_args) = get_editor(config)?;

for path in paths {
editor_args.push(path.join("PKGBUILD").to_string_lossy().to_string());
}

let status = Command::new(&editor)
.args(&editor_args)
.status()
.with_context(|| tr!("failed to run editor '{}'", editor))?;

if !status.success() {
bail!(tr!("editor did not exit successfully"));
}

Ok(())
}

0 comments on commit e9016d2

Please sign in to comment.