diff --git a/ci.Dockerfile b/ci.Dockerfile index 1b64380d..01320d26 100644 --- a/ci.Dockerfile +++ b/ci.Dockerfile @@ -9,9 +9,9 @@ COPY go.mod . # asciidoc, doxygen, meson needed for pacman-git RUN set -eux; \ pacman-key --init; \ - pacman -Syu --noconfirm --needed archlinux-keyring pacman go git gcc make base-devel sudo asciidoc doxygen meson; \ sed -i 's/^#DisableSandboxFilesystem/DisableSandboxFilesystem/' /etc/pacman.conf; \ sed -i 's/^#DisableSandboxSyscalls/DisableSandboxSyscalls/' /etc/pacman.conf; \ + pacman -Syu --noconfirm --needed archlinux-keyring pacman go git gcc make base-devel sudo asciidoc doxygen meson; \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v2.7.2; \ go mod download; \ rm -rf /var/lib/pacman/sync/* /var/cache/pacman/* /tmp/* /var/tmp/*; \ diff --git a/cmd.go b/cmd.go index 3149e1e0..ab1855b6 100644 --- a/cmd.go +++ b/cmd.go @@ -328,11 +328,7 @@ func handleUpgrade(ctx context.Context, func handleBuild(ctx context.Context, run *runtime.Runtime, dbExecutor db.Executor, cmdArgs *parser.Arguments, ) error { - if cmdArgs.ExistsArg("i", "install") { - return installLocalPKGBUILD(ctx, run, cmdArgs, dbExecutor) - } - - return nil + return installLocalPKGBUILD(ctx, run, cmdArgs, dbExecutor) } func handleSync(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.Arguments, dbExecutor db.Executor) error { diff --git a/cmd_test.go b/cmd_test.go index 5f3a3cdd..65f62d49 100644 --- a/cmd_test.go +++ b/cmd_test.go @@ -132,7 +132,7 @@ func TestYogurtMenuAURDB(t *testing.T) { show := call.Args[0].(*exec.Cmd).String() show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) diff --git a/doc/yay.8 b/doc/yay.8 index 3167bce1..da320195 100644 --- a/doc/yay.8 +++ b/doc/yay.8 @@ -203,16 +203,18 @@ The command to use for \fBmakepkg\fR calls. This can be a command in The command to use for \fBpacman\fR calls. This can be a command in \fBPATH\fR or an absolute path to the file. -.TP -.B \-\-tar -The command to use for \fBbsdtar\fR calls. This can be a command in -\fBPATH\fR or an absolute path to the file. - .TP .B \-\-git The command to use for \fBgit\fR calls. This can be a command in \fBPATH\fR or an absolute path to the file. +.TP +.B \-\-gitflags +Passes arguments to git. These flags get passed to every instance where +git is called by yay. Arguments are split on whitespace before being +passed to git. Multiple arguments may be passed by supplying a space +separated list that is quoted by the shell. + .TP .B \-\-gpg The command to use for \fBgpg\fR calls. This can be a command in diff --git a/local_install_test.go b/local_install_test.go index 1f96d90b..31e50eb1 100644 --- a/local_install_test.go +++ b/local_install_test.go @@ -172,13 +172,153 @@ func TestIntegrationLocalInstall(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) } } +func TestIntegrationLocalBuildOnly(t *testing.T) { + makepkgBin := t.TempDir() + "/makepkg" + pacmanBin := t.TempDir() + "/pacman" + gitBin := t.TempDir() + "/git" + tmpDir := t.TempDir() + f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755) + require.NoError(t, err) + require.NoError(t, f.Close()) + + f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755) + require.NoError(t, err) + require.NoError(t, f.Close()) + + f, err = os.OpenFile(gitBin, os.O_RDONLY|os.O_CREATE, 0o755) + require.NoError(t, err) + require.NoError(t, f.Close()) + + tars := []string{ + tmpDir + "/jellyfin-10.8.4-1-x86_64.pkg.tar.zst", + tmpDir + "/jellyfin-web-10.8.4-1-x86_64.pkg.tar.zst", + tmpDir + "/jellyfin-server-10.8.4-1-x86_64.pkg.tar.zst", + } + + wantShow := []string{ + "makepkg --verifysource --skippgpcheck -f -Cc", + "pacman -S --config /etc/pacman.conf -- community/dotnet-sdk-6.0 community/dotnet-runtime-6.0", + "pacman -D -q --asdeps --config /etc/pacman.conf -- dotnet-runtime-6.0 dotnet-sdk-6.0", + "makepkg --nobuild -f -C --ignorearch", + "makepkg -c --nobuild --noextract --ignorearch", + "makepkg --nobuild -f -C --ignorearch", + "makepkg -c --nobuild --noextract --ignorearch", + } + + wantCapture := []string{ + "makepkg --packagelist", + "git -C testdata/jfin git reset --hard HEAD", + "git -C testdata/jfin git merge --no-edit --ff", + "makepkg --packagelist", + } + + captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) { + return strings.Join(tars, "\n"), "", nil + } + + once := sync.Once{} + + showOverride := func(cmd *exec.Cmd) error { + once.Do(func() { + for _, tar := range tars { + f, err := os.OpenFile(tar, os.O_RDONLY|os.O_CREATE, 0o666) + require.NoError(t, err) + require.NoError(t, f.Close()) + } + }) + return nil + } + + mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride} + cmdBuilder := &exe.CmdBuilder{ + MakepkgBin: makepkgBin, + SudoBin: "su", + PacmanBin: pacmanBin, + PacmanConfigPath: "/etc/pacman.conf", + GitBin: "git", + Runner: mockRunner, + SudoLoopEnabled: false, + } + + cmdArgs := parser.MakeArguments() + cmdArgs.AddArg("B") + cmdArgs.AddTarget("testdata/jfin") + settings.NoConfirm = true + defer func() { settings.NoConfirm = false }() + db := &mock.DBExecutor{ + AlpmArchitecturesFn: func() ([]string, error) { + return []string{"x86_64"}, nil + }, + LocalSatisfierExistsFn: func(s string) bool { + switch s { + case "dotnet-sdk>=6", "dotnet-sdk<7", "dotnet-runtime>=6", "dotnet-runtime<7", "jellyfin-server=10.8.4", "jellyfin-web=10.8.4": + return false + } + + return true + }, + SyncSatisfierFn: func(s string) mock.IPackage { + switch s { + case "dotnet-runtime>=6", "dotnet-runtime<7": + return &mock.Package{ + PName: "dotnet-runtime-6.0", + PBase: "dotnet-runtime-6.0", + PVersion: "6.0.100-1", + PDB: mock.NewDB("community"), + } + case "dotnet-sdk>=6", "dotnet-sdk<7": + return &mock.Package{ + PName: "dotnet-sdk-6.0", + PBase: "dotnet-sdk-6.0", + PVersion: "6.0.100-1", + PDB: mock.NewDB("community"), + } + } + + return nil + }, + LocalPackageFn: func(s string) mock.IPackage { return nil }, + InstalledRemotePackageNamesFn: func() []string { return []string{} }, + } + + run := &runtime.Runtime{ + Cfg: &settings.Configuration{ + RemoveMake: "no", + }, + Logger: newTestLogger(), + CmdBuilder: cmdBuilder, + VCSStore: &vcs.Mock{}, + AURClient: &mockaur.MockAUR{ + GetFn: func(ctx context.Context, query *aur.Query) ([]aur.Pkg, error) { + return []aur.Pkg{}, nil + }, + }, + } + + err = handleCmd(context.Background(), run, cmdArgs, db) + require.NoError(t, err) + + require.Len(t, mockRunner.ShowCalls, len(wantShow)) + require.Len(t, mockRunner.CaptureCalls, len(wantCapture)) + + for i, call := range mockRunner.ShowCalls { + show := call.Args[0].(*exec.Cmd).String() + show = strings.ReplaceAll(show, tmpDir, "/testdir") + show = strings.ReplaceAll(show, makepkgBin, "makepkg") + show = strings.ReplaceAll(show, pacmanBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") + + assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) + } +} + func TestIntegrationLocalInstallMissingDep(t *testing.T) { wantErr := ErrPackagesNotFound makepkgBin := t.TempDir() + "/makepkg" @@ -291,7 +431,7 @@ func TestIntegrationLocalInstallMissingDep(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -447,7 +587,7 @@ func TestIntegrationLocalInstallNeeded(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -607,7 +747,7 @@ func TestIntegrationLocalInstallGenerateSRCINFO(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -743,7 +883,7 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -869,7 +1009,7 @@ func TestIntegrationLocalInstallWithDepsProvides(t *testing.T) { show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -1010,7 +1150,7 @@ func TestIntegrationLocalInstallTwoSrcInfosWithDeps(t *testing.T) { show = strings.ReplaceAll(show, tmpDir2, "/testdir2") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) diff --git a/main.go b/main.go index 5e47bc61..2ff441ad 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ import ( ) var ( - yayVersion = "12.0.4" // To be set by compiler. + yayVersion = "12.5.3" // To be set by compiler. localePath = "/usr/share/locale" // To be set by compiler. ) diff --git a/pkg/sync/build/installer.go b/pkg/sync/build/installer.go index 84f2f8c7..45fa116c 100644 --- a/pkg/sync/build/installer.go +++ b/pkg/sync/build/installer.go @@ -22,16 +22,17 @@ import ( type ( PostInstallHookFunc func(ctx context.Context) error Installer struct { - dbExecutor db.Executor - postInstallHooks []PostInstallHookFunc - failedAndIgnored map[string]error - exeCmd exe.ICmdBuilder - vcsStore vcs.Store - targetMode parser.TargetMode - rebuildMode parser.RebuildMode - origTargets mapset.Set[string] - downloadOnly bool - log *text.Logger + dbExecutor db.Executor + postInstallHooks []PostInstallHookFunc + failedAndIgnored map[string]error + exeCmd exe.ICmdBuilder + vcsStore vcs.Store + targetMode parser.TargetMode + rebuildMode parser.RebuildMode + origTargets mapset.Set[string] + downloadOnly bool + installBuiltPackages bool + log *text.Logger manualConfirmRequired bool } @@ -50,11 +51,16 @@ func NewInstaller(dbExecutor db.Executor, targetMode: targetMode, rebuildMode: rebuildMode, downloadOnly: downloadOnly, + installBuiltPackages: true, log: logger, manualConfirmRequired: true, } } +func (installer *Installer) SetInstallBuiltPackages(install bool) { + installer.installBuiltPackages = install +} + func (installer *Installer) CompileFailedAndIgnored() (map[string]error, error) { if len(installer.failedAndIgnored) == 0 { return installer.failedAndIgnored, nil @@ -275,6 +281,10 @@ func (installer *Installer) installAURPackages(ctx context.Context, } } + if len(pkgArchives) == 0 || !installer.installBuiltPackages { + return nil + } + if err := installPkgArchive(ctx, installer.exeCmd, installer.targetMode, installer.vcsStore, cmdArgs, pkgArchives, noConfirm); err != nil { return fmt.Errorf("%s - %w", fmt.Sprintf(gotext.Get("error installing:")+" %v", pkgArchives), err) diff --git a/pkg/sync/build/installer_test.go b/pkg/sync/build/installer_test.go index f3e88007..3404b85b 100644 --- a/pkg/sync/build/installer_test.go +++ b/pkg/sync/build/installer_test.go @@ -182,6 +182,102 @@ func TestInstaller_InstallNeeded(t *testing.T) { } } +func TestInstaller_BuildOnlySkipsInstall(t *testing.T) { + t.Parallel() + + makepkgBin := t.TempDir() + "/makepkg" + pacmanBin := t.TempDir() + "/pacman" + f, err := os.OpenFile(makepkgBin, os.O_RDONLY|os.O_CREATE, 0o755) + require.NoError(t, err) + require.NoError(t, f.Close()) + + f, err = os.OpenFile(pacmanBin, os.O_RDONLY|os.O_CREATE, 0o755) + require.NoError(t, err) + require.NoError(t, f.Close()) + + tmpDir := t.TempDir() + pkgTar := tmpDir + "/yay-91.0.0-1-x86_64.pkg.tar.zst" + + captureOverride := func(cmd *exec.Cmd) (stdout string, stderr string, err error) { + return pkgTar, "", nil + } + + i := 0 + showOverride := func(cmd *exec.Cmd) error { + i++ + if i == 2 { + f, err := os.OpenFile(pkgTar, os.O_RDONLY|os.O_CREATE, 0o666) + require.NoError(t, err) + require.NoError(t, f.Close()) + } + return nil + } + + mockDB := &mock.DBExecutor{} + mockRunner := &exe.MockRunner{CaptureFn: captureOverride, ShowFn: showOverride} + cmdBuilder := &exe.CmdBuilder{ + MakepkgBin: makepkgBin, + SudoBin: "su", + PacmanBin: pacmanBin, + Runner: mockRunner, + SudoLoopEnabled: false, + } + + cmdBuilder.Runner = mockRunner + + installer := NewInstaller(mockDB, cmdBuilder, &vcs.Mock{}, parser.ModeAny, + parser.RebuildModeNo, false, newTestLogger()) + installer.SetInstallBuiltPackages(false) + + cmdArgs := parser.MakeArguments() + cmdArgs.AddTarget("yay") + + pkgBuildDirs := map[string]string{ + "yay": tmpDir, + } + + targets := []map[string]*dep.InstallInfo{ + { + "yay": { + Source: dep.AUR, + Reason: dep.Explicit, + Version: "91.0.0-1", + SrcinfoPath: ptrString(tmpDir + "/.SRCINFO"), + AURBase: ptrString("yay"), + }, + }, + } + + err = installer.Install(context.Background(), cmdArgs, targets, pkgBuildDirs, []string{}, false) + require.NoError(t, err) + + wantShow := []string{ + "makepkg --nobuild -f -C --ignorearch", + "makepkg -f -c --noconfirm --noextract --noprepare --holdver --ignorearch", + } + + require.Len(t, mockRunner.ShowCalls, len(wantShow)) + require.Len(t, mockRunner.CaptureCalls, 1) + + for i, call := range mockRunner.ShowCalls { + show := call.Args[0].(*exec.Cmd).String() + show = strings.ReplaceAll(show, tmpDir, "/testdir") + show = strings.ReplaceAll(show, makepkgBin, "makepkg") + show = strings.ReplaceAll(show, pacmanBin, "pacman") + + assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), show) + assert.NotContains(t, show, "pacman -U") + } + + for _, call := range mockRunner.CaptureCalls { + capture := call.Args[0].(*exec.Cmd).String() + capture = strings.ReplaceAll(capture, tmpDir, "/testdir") + capture = strings.ReplaceAll(capture, makepkgBin, "makepkg") + capture = strings.ReplaceAll(capture, pacmanBin, "pacman") + assert.Subset(t, strings.Split(capture, " "), strings.Split("makepkg --packagelist", " "), capture) + } +} + func TestInstaller_InstallMixedSourcesAndLayers(t *testing.T) { t.Parallel() diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index d3ca2f7e..4d0e27a1 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -50,6 +50,12 @@ func (o *OperationService) Run(ctx context.Context, run *runtime.Runtime, run.VCSStore, o.cfg.Mode, o.cfg.ReBuild, cmdArgs.ExistsArg("w", "downloadonly"), run.Logger.Child("installer")) + shouldInstall := !cmdArgs.ExistsArg("w", "downloadonly") + if cmdArgs.Op == "B" && !cmdArgs.ExistsArg("i", "install") { + shouldInstall = false + } + installer.SetInstallBuiltPackages(shouldInstall) + pkgBuildDirs, errInstall := preparer.Run(ctx, run, targets) if errInstall != nil { return errInstall diff --git a/sync_test.go b/sync_test.go index e1c6ca32..f0a18d08 100644 --- a/sync_test.go +++ b/sync_test.go @@ -136,7 +136,7 @@ func TestSyncUpgrade(t *testing.T) { show := call.Args[0].(*exec.Cmd).String() show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -247,7 +247,7 @@ func TestSyncUpgrade_IgnoreAll(t *testing.T) { show := call.Args[0].(*exec.Cmd).String() show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -378,7 +378,7 @@ func TestSyncUpgrade_IgnoreOne(t *testing.T) { show := call.Args[0].(*exec.Cmd).String() show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show)) @@ -571,7 +571,7 @@ pkgname = python-vosk show = strings.ReplaceAll(show, tmpDir, "/testdir") // replace the temp dir with a static path show = strings.ReplaceAll(show, makepkgBin, "makepkg") show = strings.ReplaceAll(show, pacmanBin, "pacman") - show = strings.ReplaceAll(show, gitBin, "pacman") + show = strings.ReplaceAll(show, gitBin, "git") // options are in a different order on different systems and on CI root user is used assert.Subset(t, strings.Split(show, " "), strings.Split(wantShow[i], " "), fmt.Sprintf("%d - %s", i, show))