Parcourir la source

Fix install reason preservation when package is reinstalled (#2195)

smolx il y a 1 an
Parent
commit
c5a18e5000
3 fichiers modifiés avec 169 ajouts et 9 suppressions
  1. 5 0
      local_install_test.go
  2. 27 9
      pkg/dep/dep_graph.go
  3. 137 0
      pkg/dep/dep_graph_test.go

+ 5 - 0
local_install_test.go

@@ -138,6 +138,7 @@ func TestIntegrationLocalInstall(t *testing.T) {
 
 			return nil
 		},
+		LocalPackageFn: func(s string) mock.IPackage { return nil },
 	}
 
 	config := &settings.Configuration{
@@ -258,6 +259,7 @@ func TestIntegrationLocalInstallMissingDep(t *testing.T) {
 
 			return nil
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 	}
 
 	config := &settings.Configuration{
@@ -557,6 +559,7 @@ func TestIntegrationLocalInstallGenerateSRCINFO(t *testing.T) {
 
 			return true
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 		SyncSatisfierFn: func(s string) mock.IPackage {
 			switch s {
 			case "dotnet-runtime>=6", "dotnet-runtime<7":
@@ -838,6 +841,7 @@ func TestIntegrationLocalInstallWithDepsProvides(t *testing.T) {
 		SyncSatisfierFn: func(s string) mock.IPackage {
 			return nil
 		},
+		LocalPackageFn: func(s string) mock.IPackage { return nil },
 	}
 
 	config := &settings.Configuration{
@@ -976,6 +980,7 @@ func TestIntegrationLocalInstallTwoSrcInfosWithDeps(t *testing.T) {
 		SyncSatisfierFn: func(s string) mock.IPackage {
 			return nil
 		},
+		LocalPackageFn: func(s string) mock.IPackage { return nil },
 	}
 
 	config := &settings.Configuration{

+ 27 - 9
pkg/dep/dep_graph.go

@@ -140,9 +140,14 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 			if pkg := g.dbExecutor.SyncSatisfier(target.Name); pkg != nil {
 				dbName := pkg.DB().Name()
 
+				reason := Explicit
+				if localPkg := g.dbExecutor.LocalPackage(pkg.Name()); localPkg != nil {
+					reason = Reason(localPkg.Reason())
+				}
+
 				g.GraphSyncPkg(ctx, graph, pkg, &InstallInfo{
 					Source:     Sync,
-					Reason:     Explicit,
+					Reason:     reason,
 					Version:    pkg.Version(),
 					SyncDBName: &dbName,
 				})
@@ -173,13 +178,18 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 		case "aur":
 			aurTargets = append(aurTargets, target.Name)
 		default:
+			reason := Explicit
+			if pkg := g.dbExecutor.LocalPackage(target.Name); pkg != nil {
+				reason = Reason(pkg.Reason())
+			}
+
 			graph.AddNode(target.Name)
 			g.ValidateAndSetNodeInfo(graph, target.Name, &topo.NodeInfo[*InstallInfo]{
-				Color:      colorMap[Explicit],
+				Color:      colorMap[reason],
 				Background: bgColorMap[Sync],
 				Value: &InstallInfo{
 					Source:     Sync,
-					Reason:     Explicit,
+					Reason:     reason,
 					Version:    target.Version,
 					SyncDBName: &target.DB,
 				},
@@ -267,16 +277,21 @@ func (g *Grapher) GraphFromSrcInfos(ctx context.Context, graph *topo.Graph[strin
 		for _, pkg := range aurPkgs {
 			pkg := pkg
 
+			reason := Explicit
+			if pkg := g.dbExecutor.LocalPackage(pkg.Name); pkg != nil {
+				reason = Reason(pkg.Reason())
+			}
+
 			graph.AddNode(pkg.Name)
 
 			g.addAurPkgProvides(pkg, graph)
 
 			g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
-				Color:      colorMap[Explicit],
+				Color:      colorMap[reason],
 				Background: bgColorMap[AUR],
 				Value: &InstallInfo{
 					Source:      SrcInfo,
-					Reason:      Explicit,
+					Reason:      reason,
 					SrcinfoPath: &pkgBuildDir,
 					AURBase:     &pkg.PackageBase,
 					Version:     pkg.Version,
@@ -328,7 +343,7 @@ func (g *Grapher) GraphSyncPkg(ctx context.Context,
 	})
 
 	g.ValidateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
-		Color:      colorMap[Explicit],
+		Color:      colorMap[Reason(pkg.Reason())],
 		Background: bgColorMap[Sync],
 		Value:      instalInfo,
 	})
@@ -407,8 +422,11 @@ func (g *Grapher) GraphFromAUR(ctx context.Context,
 			g.providerCache[target] = []aurc.Pkg{*aurPkg}
 		}
 
-		if g.needed {
-			if pkg := g.dbExecutor.LocalPackage(aurPkg.Name); pkg != nil {
+		reason := Explicit
+		if pkg := g.dbExecutor.LocalPackage(aurPkg.Name); pkg != nil {
+			reason = Reason(pkg.Reason())
+
+			if g.needed {
 				if db.VerCmp(pkg.Version(), aurPkg.Version) >= 0 {
 					g.logger.Warnln(gotext.Get("%s is up to date -- skipping", text.Cyan(pkg.Name()+"-"+pkg.Version())))
 					continue
@@ -418,7 +436,7 @@ func (g *Grapher) GraphFromAUR(ctx context.Context,
 
 		graph = g.GraphAURTarget(ctx, graph, aurPkg, &InstallInfo{
 			AURBase: &aurPkg.PackageBase,
-			Reason:  Explicit,
+			Reason:  reason,
 			Source:  AUR,
 			Version: aurPkg.Version,
 		})

+ 137 - 0
pkg/dep/dep_graph_test.go

@@ -76,6 +76,7 @@ func TestGrapher_GraphFromTargets_jellyfin(t *testing.T) {
 
 			return true
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 	}
 
 	mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
@@ -249,6 +250,7 @@ func TestGrapher_GraphProvides_androidsdk(t *testing.T) {
 
 			panic("implement me " + s)
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 	}
 
 	mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
@@ -348,6 +350,7 @@ func TestGrapher_GraphFromAUR_Deps_ceph_bin(t *testing.T) {
 
 			panic("implement me " + s)
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 	}
 
 	mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
@@ -553,6 +556,7 @@ func TestGrapher_GraphFromAUR_Deps_gourou(t *testing.T) {
 
 			panic("implement me " + s)
 		},
+		LocalPackageFn: func(string) mock.IPackage { return nil },
 	}
 
 	mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
@@ -667,3 +671,136 @@ func TestGrapher_GraphFromAUR_Deps_gourou(t *testing.T) {
 		})
 	}
 }
+
+func TestGrapher_GraphFromTargets_ReinstalledDeps(t *testing.T) {
+	mockDB := &mock.DBExecutor{
+		SyncPackageFn:       func(string) mock.IPackage { return nil },
+		PackagesFromGroupFn: func(string) []mock.IPackage { return []mock.IPackage{} },
+		SyncSatisfierFn: func(s string) mock.IPackage {
+			switch s {
+			case "gourou":
+				return nil
+			case "libzip":
+				return &mock.Package{
+					PName:    "libzip",
+					PVersion: "1.9.2-1",
+					PDB:      mock.NewDB("extra"),
+				}
+			}
+
+			panic("implement me " + s)
+		},
+
+		LocalSatisfierExistsFn: func(s string) bool {
+			switch s {
+			case "gourou", "libzip":
+				return true
+			}
+
+			panic("implement me " + s)
+		},
+		LocalPackageFn: func(s string) mock.IPackage {
+			switch s {
+			case "libzip":
+				return &mock.Package{
+					PName:    "libzip",
+					PVersion: "1.9.2-1",
+					PDB:      mock.NewDB("extra"),
+					PReason:  alpm.PkgReasonDepend,
+				}
+			case "gourou":
+				return &mock.Package{
+					PName:    "gourou",
+					PVersion: "0.8.1",
+					PDB:      mock.NewDB("aur"),
+					PReason:  alpm.PkgReasonDepend,
+				}
+			}
+			return nil
+		},
+	}
+
+	mockAUR := &mockaur.MockAUR{GetFn: func(ctx context.Context, query *aurc.Query) ([]aur.Pkg, error) {
+		mockPkgs := map[string]aur.Pkg{
+			"gourou": {
+				Name:        "gourou",
+				PackageBase: "gourou",
+				Version:     "0.8.1",
+				Depends:     []string{"libzip"},
+			},
+		}
+
+		pkgs := []aur.Pkg{}
+		for _, needle := range query.Needles {
+			if pkg, ok := mockPkgs[needle]; ok {
+				pkgs = append(pkgs, pkg)
+			} else {
+				panic(fmt.Sprintf("implement me %v", needle))
+			}
+		}
+
+		return pkgs, nil
+	}}
+
+	installInfos := map[string]*InstallInfo{
+		"gourou dep": {
+			Source:  AUR,
+			Reason:  Dep,
+			Version: "0.8.1",
+			AURBase: ptrString("gourou"),
+		},
+		"libzip dep": {
+			Source:     Sync,
+			Reason:     Dep,
+			Version:    "1.9.2-1",
+			SyncDBName: ptrString("extra"),
+		},
+		// In an ideal world this should be the same as "libzip dep",
+		// but due to the difference in handling cases with specified and
+		// unspecified dbs, this is how it is.
+		"extra/libzip dep": {
+			Source:     Sync,
+			Reason:     Dep,
+			Version:    "",
+			SyncDBName: ptrString("extra"),
+		},
+	}
+
+	tests := []struct {
+		name       string
+		targets    []string
+		wantLayers []map[string]*InstallInfo
+		wantErr    bool
+	}{
+		{
+			name:    "gourou libzip",
+			targets: []string{"gourou", "libzip"},
+			wantLayers: []map[string]*InstallInfo{
+				{"gourou": installInfos["gourou dep"]},
+				{"libzip": installInfos["libzip dep"]},
+			},
+			wantErr: false,
+		},
+		{
+			name:    "aur/gourou extra/libzip",
+			targets: []string{"aur/gourou", "extra/libzip"},
+			wantLayers: []map[string]*InstallInfo{
+				{"gourou": installInfos["gourou dep"]},
+				{"libzip": installInfos["extra/libzip dep"]},
+			},
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := NewGrapher(mockDB, mockAUR,
+				false, true, false, false, false,
+				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
+			got, err := g.GraphFromTargets(context.Background(), nil, tt.targets)
+			require.NoError(t, err)
+			layers := got.TopoSortedLayerMap(nil)
+			require.EqualValues(t, tt.wantLayers, layers, layers)
+		})
+	}
+}