Merge pull request #1779 from Jguer/jguer/migrate-provides

Config: Add migration service and migrate provides default value
This commit is contained in:
Jo 2022-08-05 21:41:26 +00:00 committed by GitHub
commit e2f61255cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 282 additions and 54 deletions

View File

@ -29,7 +29,7 @@ jobs:
DOCKER_BUILDKIT: 0 DOCKER_BUILDKIT: 0
COMPOSE_DOCKER_CLI_BUILD: 0 COMPOSE_DOCKER_CLI_BUILD: 0
with: with:
platforms: linux/amd64, linux/arm/v6,linux/arm/v7,linux/arm64 platforms: linux/amd64,linux/arm/v7,linux/arm64
file: ci.Dockerfile file: ci.Dockerfile
push: true push: true
tags: jguer/yay-builder:latest tags: jguer/yay-builder:latest

View File

@ -11,7 +11,6 @@ jobs:
arch: arch:
[ [
"linux/amd64 x86_64", "linux/amd64 x86_64",
"linux/arm/v6 armv6h",
"linux/arm/v7 armv7h", "linux/arm/v7 armv7h",
"linux/arm64 aarch64", "linux/arm64 aarch64",
] ]
@ -73,9 +72,6 @@ jobs:
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: yay_armv7h name: yay_armv7h
- uses: actions/download-artifact@v2
with:
name: yay_armv6h
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: yay_aarch64 name: yay_aarch64
@ -109,16 +105,6 @@ jobs:
asset_path: ./yay_${{ steps.tags.outputs.version }}_armv7h.tar.gz asset_path: ./yay_${{ steps.tags.outputs.version }}_armv7h.tar.gz
asset_name: yay_${{ steps.tags.outputs.version }}_armv7h.tar.gz asset_name: yay_${{ steps.tags.outputs.version }}_armv7h.tar.gz
asset_content_type: application/tar+gzip asset_content_type: application/tar+gzip
- name: Upload armv6h asset
id: upload-release-asset-armv6h
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./yay_${{ steps.tags.outputs.version }}_armv6h.tar.gz
asset_name: yay_${{ steps.tags.outputs.version }}_armv6h.tar.gz
asset_content_type: application/tar+gzip
- name: Upload aarch64 asset - name: Upload aarch64 asset
id: upload-release-asset-aarch64 id: upload-release-asset-aarch64
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1

View File

@ -12,7 +12,7 @@ PREFIX := /usr/local
MAJORVERSION := 11 MAJORVERSION := 11
MINORVERSION := 2 MINORVERSION := 2
PATCHVERSION := 0 PATCHVERSION := 1
VERSION ?= ${MAJORVERSION}.${MINORVERSION}.${PATCHVERSION} VERSION ?= ${MAJORVERSION}.${MINORVERSION}.${PATCHVERSION}
LOCALEDIR := po LOCALEDIR := po

View File

@ -1,11 +1,11 @@
FROM docker.io/lopsided/archlinux:devel FROM docker.io/jguer/yay-builder:latest
ENV GO111MODULE=on ENV GO111MODULE=on
WORKDIR /app WORKDIR /app
COPY go.mod . COPY go.mod .
RUN pacman -Syu --overwrite=* --needed --noconfirm go git && \ RUN pacman -Sy && pacman -S --overwrite=* --noconfirm archlinux-keyring && pacman -Su --overwrite=* --needed --noconfirm go git && \
rm -rfv /var/cache/pacman/* /var/lib/pacman/sync/* && \ rm -rfv /var/cache/pacman/* /var/lib/pacman/sync/* && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.44.2 && \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.48.0 && \
go mod download go mod download

View File

@ -550,7 +550,7 @@ func pkgbuildsToSkip(bases []dep.Base, targets stringset.StringSet) stringset.St
pkgbuild, err := gosrc.ParseFile(dir) pkgbuild, err := gosrc.ParseFile(dir)
if err == nil { if err == nil {
if alpm.VerCmp(pkgbuild.Version(), base.Version()) >= 0 { if db.VerCmp(pkgbuild.Version(), base.Version()) >= 0 {
toSkip.Set(base.Pkgbase()) toSkip.Set(base.Pkgbase())
} }
} }
@ -812,7 +812,8 @@ func doInstall(ctx context.Context, arguments, cmdArgs *parser.Arguments, pkgDep
func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.StringSet, func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.StringSet,
arguments, cmdArgs *parser.Arguments, pkgdests map[string]string, arguments, cmdArgs *parser.Arguments, pkgdests map[string]string,
deps, exp []string, name string, optional bool) (newDeps, newExp []string, err error) { deps, exp []string, name string, optional bool,
) (newDeps, newExp []string, err error) {
pkgdest, ok := pkgdests[name] pkgdest, ok := pkgdests[name]
if !ok { if !ok {
if optional { if optional {

View File

@ -114,6 +114,11 @@ func main() {
return return
} }
if errS := config.RunMigrations(
settings.DefaultMigrations(), config.Runtime.ConfigPath); errS != nil {
text.Errorln(errS)
}
cmdArgs := parser.MakeArguments() cmdArgs := parser.MakeArguments()
if err = config.ParseCommandLine(cmdArgs); err != nil { if err = config.ParseCommandLine(cmdArgs); err != nil {

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"errors" "errors"
"io/ioutil" "io"
"net/http" "net/http"
"testing" "testing"
@ -45,7 +45,7 @@ func (m *mockDoer) Do(req *http.Request) (*http.Response, error) {
assert.Equal(m.t, m.wantUrl, req.URL.String()) assert.Equal(m.t, m.wantUrl, req.URL.String())
return &http.Response{ return &http.Response{
StatusCode: m.returnStatusCode, StatusCode: m.returnStatusCode,
Body: ioutil.NopCloser(bytes.NewBufferString(m.returnBody)), Body: io.NopCloser(bytes.NewBufferString(m.returnBody)),
}, m.returnErr }, m.returnErr
} }

View File

@ -11,8 +11,10 @@ type (
Depend = alpm.Depend Depend = alpm.Depend
) )
func VerCmp(a, b string) int { // VerCmp performs version comparison according to Pacman conventions. Return
return alpm.VerCmp(a, b) // value is <0 if and only if v1 is older than v2.
func VerCmp(v1, v2 string) int {
return alpm.VerCmp(v1, v2)
} }
type Upgrade struct { type Upgrade struct {

View File

@ -12,6 +12,7 @@ import (
"sort" "sort"
"strings" "strings"
"testing" "testing"
"time"
aur "github.com/Jguer/aur" aur "github.com/Jguer/aur"
gosrc "github.com/Morganamilo/go-srcinfo" gosrc "github.com/Morganamilo/go-srcinfo"
@ -59,7 +60,7 @@ func getPgpKey(key string) string {
} }
func startPgpKeyServer() *http.Server { func startPgpKeyServer() *http.Server {
srv := &http.Server{Addr: fmt.Sprintf("127.0.0.1:%d", gpgServerPort)} srv := &http.Server{Addr: fmt.Sprintf("127.0.0.1:%d", gpgServerPort), ReadHeaderTimeout: 1 * time.Second}
go func() { go func() {
err := srv.ListenAndServe() err := srv.ListenAndServe()

View File

@ -3,7 +3,7 @@ package query
import ( import (
"bytes" "bytes"
"context" "context"
"io/ioutil" "io"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
@ -83,7 +83,7 @@ type mockDoer struct{}
func (m *mockDoer) Do(req *http.Request) (*http.Response, error) { func (m *mockDoer) Do(req *http.Request) (*http.Response, error) {
return &http.Response{ return &http.Response{
StatusCode: 200, StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString(validPayload)), Body: io.NopCloser(bytes.NewBufferString(validPayload)),
}, nil }, nil
} }

View File

@ -213,7 +213,7 @@ func DefaultConfig(version string) *Configuration {
AnswerEdit: "", AnswerEdit: "",
AnswerUpgrade: "", AnswerUpgrade: "",
RemoveMake: "ask", RemoveMake: "ask",
Provides: true, Provides: false,
UpgradeMenu: true, UpgradeMenu: true,
CleanMenu: true, CleanMenu: true,
DiffMenu: true, DiffMenu: true,

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
// GIVEN no user directories and sudo user // GIVEN no user directories and sudo user
@ -13,11 +14,15 @@ import (
// THEN the selected cache home should be in the tmp dir // THEN the selected cache home should be in the tmp dir
func Test_getCacheHome(t *testing.T) { func Test_getCacheHome(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
os.Unsetenv("XDG_CACHE_HOME") require.NoError(t, os.Unsetenv("XDG_CACHE_HOME"))
os.Unsetenv("HOME") require.NoError(t, os.Unsetenv("HOME"))
os.Setenv("SUDO_USER", "test") require.NoError(t, os.Setenv("SUDO_USER", "test"))
os.Setenv("TMPDIR", dir) require.NoError(t, os.Setenv("TMPDIR", dir))
got, err := getCacheHome() got, err := getCacheHome()
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, filepath.Join(dir, "yay"), got) assert.Equal(t, filepath.Join(dir, "yay"), got)
require.NoError(t, os.Unsetenv("TMPDIR"))
require.NoError(t, os.Unsetenv("SUDO_USER"))
} }

View File

@ -0,0 +1,67 @@
package settings
import (
"fmt"
"github.com/Jguer/yay/v11/pkg/db"
"github.com/Jguer/yay/v11/pkg/text"
"github.com/leonelquinteros/gotext"
)
type configMigration interface {
// Description of what the migration does
fmt.Stringer
// return true if migration was done
Do(config *Configuration) bool
// Target version of the migration (e.g. "11.2.1")
// Should match the version of yay releasing this migration
TargetVersion() string
}
type configProviderMigration struct{}
func (migration *configProviderMigration) String() string {
return gotext.Get("Disable 'provides' setting by default")
}
func (migration *configProviderMigration) Do(config *Configuration) bool {
if config.Provides {
config.Provides = false
return true
}
return false
}
func (migration *configProviderMigration) TargetVersion() string {
return "11.2.1"
}
func DefaultMigrations() []configMigration {
return []configMigration{
&configProviderMigration{},
}
}
func (c *Configuration) RunMigrations(migrations []configMigration, configPath string) error {
saveConfig := false
for _, migration := range migrations {
if db.VerCmp(migration.TargetVersion(), c.Version) > 0 {
if migration.Do(c) {
text.Infoln("Config migration executed (",
migration.TargetVersion(), "):", migration)
saveConfig = true
}
}
}
if saveConfig {
return c.Save(configPath)
}
return nil
}

View File

@ -0,0 +1,151 @@
package settings
import (
"encoding/json"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMigrationNothingToDo(t *testing.T) {
t.Parallel()
// Create temporary file for config
configFile, err := os.CreateTemp("/tmp", "yay-*-config.json")
require.NoError(t, err)
testFilePath := configFile.Name()
defer os.Remove(testFilePath)
// Create config with configVersion
config := Configuration{
Version: "99.0.0",
// Create runtime with runtimeVersion
Runtime: &Runtime{Version: "20.0.0"},
}
// Run Migration
err = config.RunMigrations(DefaultMigrations(), testFilePath)
require.NoError(t, err)
// Check file contents if wantSave otherwise check file empty
cfile, err := os.Open(testFilePath)
require.NoError(t, err)
defer cfile.Close()
decoder := json.NewDecoder(cfile)
newConfig := Configuration{}
err = decoder.Decode(&newConfig)
require.Error(t, err)
assert.Empty(t, newConfig.Version)
}
func TestProvidesMigrationDo(t *testing.T) {
migration := &configProviderMigration{}
config := Configuration{Provides: true}
assert.True(t, migration.Do(&config))
falseConfig := Configuration{Provides: false}
assert.False(t, migration.Do(&falseConfig))
}
func TestProvidesMigration(t *testing.T) {
t.Parallel()
type testCase struct {
desc string
testConfig *Configuration
wantSave bool
}
testCases := []testCase{
{
desc: "to upgrade",
testConfig: &Configuration{
Version: "11.0.1",
Runtime: &Runtime{Version: "11.2.1"},
Provides: true,
},
wantSave: true,
},
{
desc: "to upgrade-git",
testConfig: &Configuration{
Version: "11.2.0.r7.g6f60892",
Runtime: &Runtime{Version: "11.2.1"},
Provides: true,
},
wantSave: true,
},
{
desc: "to not upgrade",
testConfig: &Configuration{
Version: "11.2.0",
Runtime: &Runtime{Version: "11.2.1"},
Provides: false,
},
wantSave: false,
},
{
desc: "to not upgrade - target version",
testConfig: &Configuration{
Version: "11.2.1",
Runtime: &Runtime{Version: "11.2.1"},
Provides: true,
},
wantSave: false,
},
{
desc: "to not upgrade - new version",
testConfig: &Configuration{
Version: "11.3.0",
Runtime: &Runtime{Version: "11.3.0"},
Provides: true,
},
wantSave: false,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
// Create temporary file for config
configFile, err := os.CreateTemp("/tmp", "yay-*-config.json")
require.NoError(t, err)
testFilePath := configFile.Name()
defer os.Remove(testFilePath)
// Create config with configVersion and provides
tcConfig := Configuration{
Version: tc.testConfig.Version,
Provides: tc.testConfig.Provides,
// Create runtime with runtimeVersion
Runtime: &Runtime{Version: tc.testConfig.Runtime.Version},
}
// Run Migration
err = tcConfig.RunMigrations(
[]configMigration{&configProviderMigration{}},
testFilePath)
require.NoError(t, err)
// Check file contents if wantSave otherwise check file empty
cfile, err := os.Open(testFilePath)
require.NoError(t, err)
defer cfile.Close()
decoder := json.NewDecoder(cfile)
newConfig := Configuration{}
err = decoder.Decode(&newConfig)
if tc.wantSave {
require.NoError(t, err)
assert.Equal(t, tc.testConfig.Runtime.Version, newConfig.Version)
assert.Equal(t, false, newConfig.Provides)
} else {
require.Error(t, err)
assert.Empty(t, newConfig.Version)
}
})
}
}

View File

@ -30,6 +30,7 @@ type OriginInfoByURL map[string]OriginInfo
// OriginInfo contains the last commit sha of a repo // OriginInfo contains the last commit sha of a repo
// Example: // Example:
//
// "github.com/Jguer/yay.git": { // "github.com/Jguer/yay.git": {
// "protocols": [ // "protocols": [
// "https" // "https"
@ -90,7 +91,8 @@ func (v *InfoStore) getCommit(ctx context.Context, url, branch string, protocols
} }
func (v *InfoStore) Update(ctx context.Context, pkgName string, func (v *InfoStore) Update(ctx context.Context, pkgName string,
sources []gosrc.ArchString, mux sync.Locker, wg *sync.WaitGroup) { sources []gosrc.ArchString, mux sync.Locker, wg *sync.WaitGroup,
) {
defer wg.Done() defer wg.Done()
info := make(OriginInfoByURL) info := make(OriginInfoByURL)

View File

@ -13,6 +13,7 @@ import (
gosrc "github.com/Morganamilo/go-srcinfo" gosrc "github.com/Morganamilo/go-srcinfo"
"github.com/bradleyjkemp/cupaloy" "github.com/bradleyjkemp/cupaloy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/Jguer/yay/v11/pkg/settings/exe" "github.com/Jguer/yay/v11/pkg/settings/exe"
) )
@ -261,9 +262,9 @@ func TestInfoStore_Update(t *testing.T) {
}, },
} }
file, err := os.CreateTemp("/tmp", "yay-vcs-test") file, err := os.CreateTemp("/tmp", "yay-infostore-*-test")
assert.NoError(t, err) filePath := file.Name()
defer os.Remove(file.Name()) require.NoError(t, err)
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
@ -271,7 +272,7 @@ func TestInfoStore_Update(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
OriginsByPackage: tt.fields.OriginsByPackage, OriginsByPackage: tt.fields.OriginsByPackage,
FilePath: file.Name(), FilePath: filePath,
CmdBuilder: tt.fields.CmdBuilder, CmdBuilder: tt.fields.CmdBuilder,
} }
var mux sync.Mutex var mux sync.Mutex
@ -296,6 +297,8 @@ func TestInfoStore_Update(t *testing.T) {
cupaloy.SnapshotT(t, marshalledinfo) cupaloy.SnapshotT(t, marshalledinfo)
}) })
} }
require.NoError(t, os.Remove(filePath))
} }
func TestInfoStore_Remove(t *testing.T) { func TestInfoStore_Remove(t *testing.T) {
@ -325,9 +328,9 @@ func TestInfoStore_Remove(t *testing.T) {
}, },
} }
file, err := os.CreateTemp("/tmp", "yay-vcs-test") file, err := os.CreateTemp("/tmp", "yay-vcs-*-test")
assert.NoError(t, err) filePath := file.Name()
defer os.Remove(file.Name()) require.NoError(t, err)
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
@ -335,10 +338,12 @@ func TestInfoStore_Remove(t *testing.T) {
t.Parallel() t.Parallel()
v := &InfoStore{ v := &InfoStore{
OriginsByPackage: tt.fields.OriginsByPackage, OriginsByPackage: tt.fields.OriginsByPackage,
FilePath: file.Name(), FilePath: filePath,
} }
v.RemovePackage(tt.args.pkgs) v.RemovePackage(tt.args.pkgs)
assert.Len(t, tt.fields.OriginsByPackage, 2) assert.Len(t, tt.fields.OriginsByPackage, 2)
}) })
} }
require.NoError(t, os.Remove(filePath))
} }

View File

@ -35,7 +35,8 @@ func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade {
// upList returns lists of packages to upgrade from each source. // upList returns lists of packages to upgrade from each source.
func upList(ctx context.Context, warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool, func upList(ctx context.Context, warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool,
filter upgrade.Filter) (aurUp, repoUp upgrade.UpSlice, err error) { filter upgrade.Filter,
) (aurUp, repoUp upgrade.UpSlice, err error) {
remote, remoteNames := query.GetRemotePackages(dbExecutor) remote, remoteNames := query.GetRemotePackages(dbExecutor)
var ( var (
@ -125,7 +126,8 @@ func upList(ctx context.Context, warnings *query.AURWarnings, dbExecutor db.Exec
} }
func printLocalNewerThanAUR( func printLocalNewerThanAUR(
remote []alpm.IPackage, aurdata map[string]*aur.Pkg) { remote []alpm.IPackage, aurdata map[string]*aur.Pkg,
) {
for _, pkg := range remote { for _, pkg := range remote {
aurPkg, ok := aurdata[pkg.Name()] aurPkg, ok := aurdata[pkg.Name()]
if !ok { if !ok {
@ -134,7 +136,7 @@ func printLocalNewerThanAUR(
left, right := upgrade.GetVersionDiff(pkg.Version(), aurPkg.Version) left, right := upgrade.GetVersionDiff(pkg.Version(), aurPkg.Version)
if !isDevelPackage(pkg) && alpm.VerCmp(pkg.Version(), aurPkg.Version) > 0 { if !isDevelPackage(pkg) && db.VerCmp(pkg.Version(), aurPkg.Version) > 0 {
text.Warnln(gotext.Get("%s: local (%s) is newer than AUR (%s)", text.Warnln(gotext.Get("%s: local (%s) is newer than AUR (%s)",
text.Cyan(pkg.Name()), text.Cyan(pkg.Name()),
left, right, left, right,
@ -233,7 +235,8 @@ func upgradePkgsMenu(aurUp, repoUp upgrade.UpSlice) (stringset.StringSet, []stri
// Targets for sys upgrade. // Targets for sys upgrade.
func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor, func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor,
enableDowngrade bool) (stringset.StringSet, []string, error) { enableDowngrade bool,
) (stringset.StringSet, []string, error) {
warnings := query.NewWarnings() warnings := query.NewWarnings()
aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade, aurUp, repoUp, err := upList(ctx, warnings, dbExecutor, enableDowngrade,