瀏覽代碼

fix(pgp): package key importing

jguer 4 年之前
父節點
當前提交
42f337f2a5

+ 13 - 1
.pre-commit-config.yaml

@@ -1,6 +1,6 @@
 repos:
   - repo: git://github.com/dnephin/pre-commit-golang
-    rev: master
+    rev: v0.3.5
     hooks:
       - id: go-fmt
       - id: go-imports
@@ -8,3 +8,15 @@ repos:
       - id: golangci-lint
       - id: go-unit-tests
       - id: go-build
+
+  - repo: https://github.com/prettier/prettier
+    rev: 2.0.5 # Use the sha or tag you want to point at
+    hooks:
+      - id: prettier
+
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v3.1.0 # Use the ref you want to point at
+    hooks:
+      - id: trailing-whitespace
+      - id: check-json
+      - id: check-yaml

+ 2 - 2
clean.go

@@ -98,7 +98,7 @@ func syncClean(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error {
 
 	fmt.Println(gotext.Get("\nBuild directory:"), config.BuildDir)
 
-	if continueTask(question, true) {
+	if text.ContinueTask(question, true, config.NoConfirm) {
 		if err := cleanAUR(keepInstalled, keepCurrent, removeAll, alpmHandle); err != nil {
 			return err
 		}
@@ -108,7 +108,7 @@ func syncClean(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle) error {
 		return nil
 	}
 
-	if continueTask(gotext.Get("Do you want to remove ALL untracked AUR files?"), true) {
+	if text.ContinueTask(gotext.Get("Do you want to remove ALL untracked AUR files?"), true, config.NoConfirm) {
 		return cleanUntracked()
 	}
 

+ 0 - 30
config.go

@@ -91,36 +91,6 @@ func editor() (editor string, args []string) {
 	}
 }
 
-// ContinueTask prompts if user wants to continue task.
-// If NoConfirm is set the action will continue without user input.
-func continueTask(s string, cont bool) bool {
-	if config.NoConfirm {
-		return cont
-	}
-
-	var response string
-	var postFix string
-	yes := gotext.Get("yes")
-	no := gotext.Get("no")
-	y := string([]rune(yes)[0])
-	n := string([]rune(no)[0])
-
-	if cont {
-		postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n)
-	} else {
-		postFix = fmt.Sprintf(" [%s/%s] ", y, strings.ToUpper(n))
-	}
-
-	text.Info(bold(s), bold(postFix))
-
-	if _, err := fmt.Scanln(&response); err != nil {
-		return cont
-	}
-
-	response = strings.ToLower(response)
-	return response == yes || response == y
-}
-
 func getInput(defaultValue string) (string, error) {
 	text.Info()
 	if defaultValue != "" || config.NoConfirm {

+ 2 - 2
download.go

@@ -269,11 +269,11 @@ func getPkgbuildsfromABS(pkgs []string, path string, alpmHandle *alpm.Handle, fo
 		_, err = os.Stat(filepath.Join(path, name))
 		switch {
 		case err != nil && !os.IsNotExist(err):
-			fmt.Fprintln(os.Stderr, bold(red(smallArrow)), err)
+			text.Errorln(err)
 			continue
 		case os.IsNotExist(err), force:
 			if err = os.RemoveAll(filepath.Join(path, name)); err != nil {
-				fmt.Fprintln(os.Stderr, bold(red(smallArrow)), err)
+				text.Errorln(err)
 				continue
 			}
 		default:

+ 2 - 0
go.mod

@@ -4,6 +4,8 @@ require (
 	github.com/Jguer/go-alpm v0.0.0-20200405152916-a3feea4322e9
 	github.com/Morganamilo/go-pacmanconf v0.0.0-20180910220353-9c5265e1b14f
 	github.com/Morganamilo/go-srcinfo v1.0.0
+	github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/leonelquinteros/gotext v1.4.0
 	github.com/mikkeloscar/aur v0.0.0-20200113170522-1cb4e2949656
 	github.com/pkg/errors v0.9.1

+ 4 - 0
go.sum

@@ -4,8 +4,12 @@ github.com/Morganamilo/go-pacmanconf v0.0.0-20180910220353-9c5265e1b14f h1:ptFKy
 github.com/Morganamilo/go-pacmanconf v0.0.0-20180910220353-9c5265e1b14f/go.mod h1:Hk55m330jNiwxRodIlMCvw5iEyoRUCIY64W1p9D+tHc=
 github.com/Morganamilo/go-srcinfo v1.0.0 h1:Wh4nEF+HJWo+29hnxM18Q2hi+DUf0GejS13+Wg+dzmI=
 github.com/Morganamilo/go-srcinfo v1.0.0/go.mod h1:MP6VGY1NNpVUmYIEgoM9acix95KQqIRyqQ0hCLsyYUY=
+github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
+github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk=
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/leonelquinteros/gotext v1.4.0 h1:2NHPCto5IoMXbrT0bldPrxj0qM5asOCwtb1aUQZ1tys=
 github.com/leonelquinteros/gotext v1.4.0/go.mod h1:yZGXREmoGTtBvZHNcc+Yfug49G/2spuF/i/Qlsvz1Us=
 github.com/mikkeloscar/aur v0.0.0-20200113170522-1cb4e2949656 h1:j679+jxcDkCFblYk+I+G71HQTFxM3PacYbVCiYmhRhU=

+ 6 - 5
install.go

@@ -18,6 +18,7 @@ import (
 	"github.com/Jguer/yay/v10/pkg/dep"
 	"github.com/Jguer/yay/v10/pkg/intrange"
 	"github.com/Jguer/yay/v10/pkg/multierror"
+	"github.com/Jguer/yay/v10/pkg/pgp"
 	"github.com/Jguer/yay/v10/pkg/query"
 	"github.com/Jguer/yay/v10/pkg/settings"
 	"github.com/Jguer/yay/v10/pkg/stringset"
@@ -239,7 +240,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide
 		case "no":
 			break
 		default:
-			if continueTask(gotext.Get("Remove make dependencies after install?"), false) {
+			if text.ContinueTask(gotext.Get("Remove make dependencies after install?"), false, config.NoConfirm) {
 				defer func() {
 					err = removeMake(do)
 				}()
@@ -287,7 +288,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide
 		oldValue := config.NoConfirm
 		config.NoConfirm = false
 		fmt.Println()
-		if !continueTask(gotext.Get("Proceed with install?"), true) {
+		if !text.ContinueTask(gotext.Get("Proceed with install?"), true, config.NoConfirm) {
 			return fmt.Errorf(gotext.Get("aborting due to user"))
 		}
 		err = updatePkgbuildSeenRef(toDiff)
@@ -327,7 +328,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide
 		oldValue := config.NoConfirm
 		config.NoConfirm = false
 		fmt.Println()
-		if !continueTask(gotext.Get("Proceed with install?"), true) {
+		if !text.ContinueTask(gotext.Get("Proceed with install?"), true, config.NoConfirm) {
 			return errors.New(gotext.Get("aborting due to user"))
 		}
 		config.NoConfirm = oldValue
@@ -339,7 +340,7 @@ func install(cmdArgs *settings.Arguments, alpmHandle *alpm.Handle, ignoreProvide
 	}
 
 	if config.PGPFetch {
-		err = checkPgpKeys(do.Aur, srcinfos)
+		err = pgp.CheckPgpKeys(do.Aur, srcinfos, config.GpgBin, config.GpgFlags, config.NoConfirm)
 		if err != nil {
 			return err
 		}
@@ -506,7 +507,7 @@ nextpkg:
 
 		fmt.Println()
 
-		if !continueTask(gotext.Get("Try to build them anyway?"), true) {
+		if !text.ContinueTask(gotext.Get("Try to build them anyway?"), true, config.NoConfirm) {
 			return nil, errors.New(gotext.Get("aborting due to user"))
 		}
 	}

+ 5 - 0
pkg/pgp/.snapshots/TestCheckPgpKeys-Two_dummy_packages_requiring_the_same_key

@@ -0,0 +1,5 @@
+
+:: PGP keys need importing:
+ -> ABAF11C65A2970B130ABE3C479BE3E4300411886, required by: dummy-1 (dummy-1 dummy-2)
+:: Importing keys with gpg...
+

+ 5 - 0
pkg/pgp/.snapshots/TestCheckPgpKeys-_one_valid_key_not_yet_in_the_keyring

@@ -0,0 +1,5 @@
+
+:: PGP keys need importing:
+ -> 487EACC08557AD082088DABA1EB2638FF56C0C53, required by: cower
+:: Importing keys with gpg...
+

+ 5 - 0
pkg/pgp/.snapshots/TestCheckPgpKeys-one_already_in_keyring

@@ -0,0 +1,5 @@
+
+:: PGP keys need importing:
+ -> C52048C0C0748FEE227D47A2702353E0F7E48EDB, required by: dummy-3
+:: Importing keys with gpg...
+

+ 1 - 0
pkg/pgp/.snapshots/TestCheckPgpKeys-two_existing

@@ -0,0 +1 @@
+

+ 6 - 0
pkg/pgp/.snapshots/TestCheckPgpKeys-two_valid_keys_not_yet_in_the_keyring

@@ -0,0 +1,6 @@
+
+:: PGP keys need importing:
+ -> 11E521D646982372EB577A1F8F0871F202119294, required by: libc++
+ -> B6C8F98282B944E3B0D5C2530FC3042E345AD05D, required by: libc++
+:: Importing keys with gpg...
+

+ 13 - 13
keys.go

@@ -1,4 +1,4 @@
-package main
+package pgp
 
 import (
 	"bytes"
@@ -40,13 +40,14 @@ func (set pgpKeySet) get(key string) bool {
 	return exists
 }
 
-// checkPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
+// CheckPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
 // asks the user whether yay should try to import them.
-func checkPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error {
+func CheckPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo,
+	gpgBin, gpgFlags string, noConfirm bool) error {
 	// Let's check the keys individually, and then we can offer to import
 	// the problematic ones.
 	problematic := make(pgpKeySet)
-	args := append(strings.Fields(config.GpgFlags), "--list-keys")
+	args := append(strings.Fields(gpgFlags), "--list-keys")
 
 	// Mapping all the keys.
 	for _, base := range bases {
@@ -61,7 +62,7 @@ func checkPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error {
 				continue
 			}
 
-			cmd := exec.Command(config.GpgBin, append(args, key)...)
+			cmd := exec.Command(gpgBin, append(args, key)...)
 			err := cmd.Run()
 			if err != nil {
 				problematic.set(key, base)
@@ -82,17 +83,17 @@ func checkPgpKeys(bases []dep.Base, srcinfos map[string]*gosrc.Srcinfo) error {
 	fmt.Println()
 	fmt.Println(str)
 
-	if continueTask(gotext.Get("Import?"), true) {
-		return importKeys(problematic.toSlice())
+	if text.ContinueTask(gotext.Get("Import?"), true, noConfirm) {
+		return importKeys(problematic.toSlice(), gpgBin, gpgFlags)
 	}
 
 	return nil
 }
 
 // importKeys tries to import the list of keys specified in its argument.
-func importKeys(keys []string) error {
-	args := append(strings.Fields(config.GpgFlags), "--recv-keys")
-	cmd := exec.Command(config.GpgBin, append(args, keys...)...)
+func importKeys(keys []string, gpgBin, gpgFlags string) error {
+	args := append(strings.Fields(gpgFlags), "--recv-keys")
+	cmd := exec.Command(gpgBin, append(args, keys...)...)
 	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
 
 	text.OperationInfoln(gotext.Get("Importing keys with gpg..."))
@@ -111,15 +112,14 @@ func formatKeysToImport(keys pgpKeySet) (string, error) {
 	}
 
 	var buffer bytes.Buffer
-	buffer.WriteString(bold(green(arrow) + " "))
-	buffer.WriteString(bold(green(gotext.Get("PGP keys need importing:"))))
+	buffer.WriteString(text.SprintOperationInfo(gotext.Get("PGP keys need importing:")))
 	for key, bases := range keys {
 		pkglist := ""
 		for _, base := range bases {
 			pkglist += base.String() + "  "
 		}
 		pkglist = strings.TrimRight(pkglist, " ")
-		buffer.WriteString(gotext.Get("\n%s %s, required by: %s", yellow(bold(smallArrow)), cyan(key), cyan(pkglist)))
+		buffer.WriteString("\n" + text.SprintWarn(gotext.Get("%s, required by: %s", text.Cyan(key), text.Cyan(pkglist))))
 	}
 	return buffer.String(), nil
 }

+ 35 - 21
keys_test.go

@@ -1,4 +1,4 @@
-package main
+package pgp
 
 import (
 	"bytes"
@@ -12,10 +12,10 @@ import (
 	"testing"
 
 	gosrc "github.com/Morganamilo/go-srcinfo"
+	"github.com/bradleyjkemp/cupaloy"
 	rpc "github.com/mikkeloscar/aur"
 
 	"github.com/Jguer/yay/v10/pkg/dep"
-	"github.com/Jguer/yay/v10/pkg/settings"
 )
 
 const (
@@ -46,7 +46,7 @@ func newPkg(basename string) *rpc.Pkg {
 func getPgpKey(key string) string {
 	var buffer bytes.Buffer
 
-	if contents, err := ioutil.ReadFile(path.Join("testdata", "keys", key)); err == nil {
+	if contents, err := ioutil.ReadFile(path.Join("testdata", key)); err == nil {
 		buffer.WriteString("-----BEGIN PGP PUBLIC KEY BLOCK-----\n")
 		buffer.WriteString("Version: SKS 1.1.6\n")
 		buffer.WriteString("Comment: Hostname: yay\n\n")
@@ -75,10 +75,6 @@ func TestImportKeys(t *testing.T) {
 	}
 	defer os.RemoveAll(keyringDir)
 
-	config = settings.MakeConfig()
-	config.GpgBin = "gpg"
-	config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir)
-
 	server := startPgpKeyServer()
 	defer func() {
 		err := server.Shutdown(context.TODO())
@@ -129,7 +125,7 @@ func TestImportKeys(t *testing.T) {
 	}
 
 	for _, tt := range casetests {
-		err := importKeys(tt.keys)
+		err := importKeys(tt.keys, "gpg", fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir))
 		if !tt.wantError {
 			if err != nil {
 				t.Fatalf("Got error %q, want no error", err)
@@ -158,9 +154,6 @@ func TestCheckPgpKeys(t *testing.T) {
 	}
 	defer os.RemoveAll(keyringDir)
 
-	config.GpgBin = "gpg"
-	config.GpgFlags = fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir)
-
 	server := startPgpKeyServer()
 	defer func() {
 		err := server.Shutdown(context.TODO())
@@ -170,6 +163,7 @@ func TestCheckPgpKeys(t *testing.T) {
 	}()
 
 	casetests := []struct {
+		name      string
 		pkgs      dep.Base
 		srcinfos  map[string]*gosrc.Srcinfo
 		wantError bool
@@ -177,6 +171,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		// cower: single package, one valid key not yet in the keyring.
 		// 487EACC08557AD082088DABA1EB2638FF56C0C53: Dave Reisner.
 		{
+			name:      " one valid key not yet in the keyring",
 			pkgs:      dep.Base{newPkg("cower")},
 			srcinfos:  map[string]*gosrc.Srcinfo{"cower": makeSrcinfo("cower", "487EACC08557AD082088DABA1EB2638FF56C0C53")},
 			wantError: false,
@@ -185,6 +180,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		// 11E521D646982372EB577A1F8F0871F202119294: Tom Stellard.
 		// B6C8F98282B944E3B0D5C2530FC3042E345AD05D: Hans Wennborg.
 		{
+			name: "two valid keys not yet in the keyring",
 			pkgs: dep.Base{newPkg("libc++")},
 			srcinfos: map[string]*gosrc.Srcinfo{
 				"libc++": makeSrcinfo("libc++", "11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"),
@@ -194,6 +190,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		// Two dummy packages requiring the same key.
 		// ABAF11C65A2970B130ABE3C479BE3E4300411886: Linus Torvalds.
 		{
+			name: "Two dummy packages requiring the same key",
 			pkgs: dep.Base{newPkg("dummy-1"), newPkg("dummy-2")},
 			srcinfos: map[string]*gosrc.Srcinfo{
 				"dummy-1": makeSrcinfo("dummy-1",
@@ -207,6 +204,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		// 11E521D646982372EB577A1F8F0871F202119294: Tom Stellard.
 		// C52048C0C0748FEE227D47A2702353E0F7E48EDB: Thomas Dickey.
 		{
+			name: "one already in keyring",
 			pkgs: dep.Base{newPkg("dummy-3")},
 			srcinfos: map[string]*gosrc.Srcinfo{
 				"dummy-3": makeSrcinfo("dummy-3", "11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB"),
@@ -215,6 +213,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		},
 		// Two dummy packages with existing keys.
 		{
+			name: "two existing",
 			pkgs: dep.Base{newPkg("dummy-4"), newPkg("dummy-5")},
 			srcinfos: map[string]*gosrc.Srcinfo{
 				"dummy-4": makeSrcinfo("dummy-4", "11E521D646982372EB577A1F8F0871F202119294"),
@@ -224,6 +223,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		},
 		// Dummy package with invalid key, should fail.
 		{
+			name:      "one invalid",
 			pkgs:      dep.Base{newPkg("dummy-7")},
 			srcinfos:  map[string]*gosrc.Srcinfo{"dummy-7": makeSrcinfo("dummy-7", "THIS-SHOULD-FAIL")},
 			wantError: true,
@@ -231,6 +231,7 @@ func TestCheckPgpKeys(t *testing.T) {
 		// Dummy package with both an invalid an another valid key, should fail.
 		// A314827C4E4250A204CE6E13284FC34C8E4B1A25: Thomas Bächler.
 		{
+			name:      "one invalid, one valid",
 			pkgs:      dep.Base{newPkg("dummy-8")},
 			srcinfos:  map[string]*gosrc.Srcinfo{"dummy-8": makeSrcinfo("dummy-8", "A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL")},
 			wantError: true,
@@ -238,16 +239,29 @@ func TestCheckPgpKeys(t *testing.T) {
 	}
 
 	for _, tt := range casetests {
-		err := checkPgpKeys([]dep.Base{tt.pkgs}, tt.srcinfos)
-		if !tt.wantError {
-			if err != nil {
-				t.Fatalf("Got error %q, want no error", err)
+		t.Run(tt.name, func(t *testing.T) {
+			rescueStdout := os.Stdout
+			r, w, _ := os.Pipe()
+			os.Stdout = w
+
+			err := CheckPgpKeys([]dep.Base{tt.pkgs}, tt.srcinfos, "gpg",
+				fmt.Sprintf("--homedir %s --keyserver 127.0.0.1", keyringDir), true)
+			if !tt.wantError {
+				if err != nil {
+					t.Fatalf("Got error %q, want no error", err)
+				}
+
+				w.Close()
+				out, _ := ioutil.ReadAll(r)
+				os.Stdout = rescueStdout
+
+				cupaloy.SnapshotT(t, string(out))
+				return
 			}
-			continue
-		}
-		// Here, we want to see the error.
-		if err == nil {
-			t.Fatalf("Got no error; want error")
-		}
+			// Here, we want to see the error.
+			if err == nil {
+				t.Fatalf("Got no error; want error")
+			}
+		})
 	}
 }

testdata/keys/11E521D646982372EB577A1F8F0871F202119294 → pkg/pgp/testdata/11E521D646982372EB577A1F8F0871F202119294


testdata/keys/487EACC08557AD082088DABA1EB2638FF56C0C53 → pkg/pgp/testdata/487EACC08557AD082088DABA1EB2638FF56C0C53


testdata/keys/647F28654894E3BD457199BE38DBBDC86092693E → pkg/pgp/testdata/647F28654894E3BD457199BE38DBBDC86092693E


testdata/keys/A314827C4E4250A204CE6E13284FC34C8E4B1A25 → pkg/pgp/testdata/A314827C4E4250A204CE6E13284FC34C8E4B1A25


testdata/keys/ABAF11C65A2970B130ABE3C479BE3E4300411886 → pkg/pgp/testdata/ABAF11C65A2970B130ABE3C479BE3E4300411886


testdata/keys/B6C8F98282B944E3B0D5C2530FC3042E345AD05D → pkg/pgp/testdata/B6C8F98282B944E3B0D5C2530FC3042E345AD05D


testdata/keys/C52048C0C0748FEE227D47A2702353E0F7E48EDB → pkg/pgp/testdata/C52048C0C0748FEE227D47A2702353E0F7E48EDB


+ 4 - 0
pkg/text/print.go

@@ -35,6 +35,10 @@ func Infoln(a ...interface{}) {
 	fmt.Fprintln(os.Stdout, append([]interface{}{Bold(green(arrow))}, a...)...)
 }
 
+func SprintWarn(a ...interface{}) string {
+	return fmt.Sprint(append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
+}
+
 func Warn(a ...interface{}) {
 	fmt.Fprint(os.Stdout, append([]interface{}{Bold(yellow(smallArrow + " "))}, a...)...)
 }

+ 33 - 0
pkg/text/text.go

@@ -1,8 +1,11 @@
 package text
 
 import (
+	"fmt"
 	"strings"
 	"unicode"
+
+	"github.com/leonelquinteros/gotext"
 )
 
 // SplitDBFromName split apart db/package to db and package
@@ -41,3 +44,33 @@ func LessRunes(iRunes, jRunes []rune) bool {
 
 	return len(iRunes) < len(jRunes)
 }
+
+// ContinueTask prompts if user wants to continue task.
+// If NoConfirm is set the action will continue without user input.
+func ContinueTask(s string, cont, noConfirm bool) bool {
+	if noConfirm {
+		return cont
+	}
+
+	var response string
+	var postFix string
+	yes := gotext.Get("yes")
+	no := gotext.Get("no")
+	y := string([]rune(yes)[0])
+	n := string([]rune(no)[0])
+
+	if cont {
+		postFix = fmt.Sprintf(" [%s/%s] ", strings.ToUpper(y), n)
+	} else {
+		postFix = fmt.Sprintf(" [%s/%s] ", y, strings.ToUpper(n))
+	}
+
+	Info(Bold(s), Bold(postFix))
+
+	if _, err := fmt.Scanln(&response); err != nil {
+		return cont
+	}
+
+	response = strings.ToLower(response)
+	return response == yes || response == y
+}

+ 2 - 6
po/en.po

@@ -420,12 +420,8 @@ msgid "[N]one"
 msgstr "[N]one"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, required by: %s"
+msgid "%s, required by: %s"
+msgstr "%s, required by: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/es.po

@@ -426,12 +426,8 @@ msgid "[N]one"
 msgstr "[N]inguno"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, necesario para: %s"
+msgid "%s, required by: %s"
+msgstr "%s, necesario para: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/eu.po

@@ -424,12 +424,8 @@ msgid "[N]one"
 msgstr "I[N]or ez"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, beharrezkoa egiteko: %s"
+msgid "%s, required by: %s"
+msgstr "%s, beharrezkoa egiteko: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/fr_FR.po

@@ -425,12 +425,8 @@ msgid "[N]one"
 msgstr "[N]Aucun"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, requis par : %s"
+msgid "%s, required by: %s"
+msgstr "%s, requis par : %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/pl_PL.po

@@ -431,12 +431,8 @@ msgid "[N]one"
 msgstr "[N]Żadne"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, wymagane przez: %s"
+msgid "%s, required by: %s"
+msgstr "%s, wymagane przez: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/pt.po

@@ -421,12 +421,8 @@ msgid "[N]one"
 msgstr "[N]enhum"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, necessário para: %s"
+msgid "%s, required by: %s"
+msgstr "%s, necessário para: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/pt_BR.po

@@ -422,12 +422,8 @@ msgid "[N]one"
 msgstr "[N]Nenhum"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, requeridos por: %s"
+msgid "%s, required by: %s"
+msgstr "%s, requeridos por: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/ru_RU.po

@@ -426,12 +426,8 @@ msgid "[N]one"
 msgstr "[N]Нет"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, требуется: %s"
+msgid "%s, required by: %s"
+msgstr "%s, требуется: %s"
 
 #: clean.go:96
 msgid ""

+ 2 - 6
po/zh_CN.po

@@ -421,12 +421,8 @@ msgid "[N]one"
 msgstr "[N]没有"
 
 #: keys.go:122
-msgid ""
-"\n"
-"%s %s, required by: %s"
-msgstr ""
-"\n"
-"%s %s, 需要: %s"
+msgid "%s, required by: %s"
+msgstr "%s, 需要: %s"
 
 #: clean.go:96
 msgid ""

+ 0 - 10
print.go

@@ -18,11 +18,6 @@ import (
 	"github.com/Jguer/yay/v10/pkg/text"
 )
 
-const (
-	arrow      = "==>"
-	smallArrow = " ->"
-)
-
 // PrintSearch handles printing search results in a given format
 func (q aurQuery) printSearch(start int, alpmHandle *alpm.Handle) {
 	localDB, _ := alpmHandle.LocalDB()
@@ -320,7 +315,6 @@ outer:
 const (
 	redCode     = "\x1b[31m"
 	greenCode   = "\x1b[32m"
-	yellowCode  = "\x1b[33m"
 	blueCode    = "\x1b[34m"
 	magentaCode = "\x1b[35m"
 	cyanCode    = "\x1b[36m"
@@ -345,10 +339,6 @@ func green(in string) string {
 	return stylize(greenCode, in)
 }
 
-func yellow(in string) string {
-	return stylize(yellowCode, in)
-}
-
 func blue(in string) string {
 	return stylize(blueCode, in)
 }