mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-08 06:28:27 -04:00
sysupdate: disallow partial updates on arch, add ignored to popout
port 1.5
(cherry picked from commit b17a90a412)
This commit is contained in:
@@ -50,11 +50,42 @@ func (b pacmanBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine
|
|||||||
}
|
}
|
||||||
|
|
||||||
func pacmanUpgradeArgv(opts UpgradeOptions) []string {
|
func pacmanUpgradeArgv(opts UpgradeOptions) []string {
|
||||||
argv := []string{"pacman", "-Syu", "--noconfirm", "--needed"}
|
return privilegedArgv(opts, "pacman", "-Syu", "--noconfirm", "--needed")
|
||||||
if len(opts.Ignored) > 0 {
|
}
|
||||||
argv = append(argv, "--ignore", strings.Join(opts.Ignored, ","))
|
|
||||||
|
// Dont allow partial updates on arch, if they wanna break their system they can do it outside of DMS:
|
||||||
|
// https://wiki.archlinux.org/title/System_maintenance#Partial_upgrades_are_unsupported
|
||||||
|
// AUR packages are exempt — holding those cannot break the repo dependency graph.
|
||||||
|
func dropPacmanRepoIgnores(ignored []string, pending []Package) []string {
|
||||||
|
if len(ignored) == 0 {
|
||||||
|
return ignored
|
||||||
|
}
|
||||||
|
repoPending := make(map[string]bool, len(pending))
|
||||||
|
for _, p := range pending {
|
||||||
|
if p.Repo == RepoSystem {
|
||||||
|
repoPending[p.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(ignored))
|
||||||
|
for _, name := range ignored {
|
||||||
|
if repoPending[name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, name)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPacmanFamily(b Backend) bool {
|
||||||
|
if b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch b.ID() {
|
||||||
|
case "pacman", "paru", "yay":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return privilegedArgv(opts, argv...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type archHelperBackend struct {
|
type archHelperBackend struct {
|
||||||
|
|||||||
@@ -345,6 +345,9 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
|
|||||||
opts.Targets = append([]Package(nil), m.state.Packages...)
|
opts.Targets = append([]Package(nil), m.state.Packages...)
|
||||||
m.mu.RUnlock()
|
m.mu.RUnlock()
|
||||||
}
|
}
|
||||||
|
if isPacmanFamily(m.selection.System) {
|
||||||
|
opts.Ignored = dropPacmanRepoIgnores(opts.Ignored, opts.Targets)
|
||||||
|
}
|
||||||
opts.Targets = dropIgnoredTargets(opts.Targets, opts.Ignored)
|
opts.Targets = dropIgnoredTargets(opts.Targets, opts.Ignored)
|
||||||
|
|
||||||
backends := upgradeBackends(m.selection, opts)
|
backends := upgradeBackends(m.selection, opts)
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ func TestUpgradeCommandBuilders(t *testing.T) {
|
|||||||
want: []string{"paru", "-Syu", "--noconfirm", "--needed", "--ignore", "linux,discord"},
|
want: []string{"paru", "-Syu", "--noconfirm", "--needed", "--ignore", "linux,discord"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pacman with ignored packages",
|
name: "pacman never passes --ignore",
|
||||||
got: pacmanUpgradeArgv(UpgradeOptions{Ignored: []string{"linux"}}),
|
got: pacmanUpgradeArgv(UpgradeOptions{Ignored: []string{"linux"}}),
|
||||||
want: []string{"pkexec", "pacman", "-Syu", "--noconfirm", "--needed", "--ignore", "linux"},
|
want: []string{"pkexec", "pacman", "-Syu", "--noconfirm", "--needed"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dnf with ignored packages",
|
name: "dnf with ignored packages",
|
||||||
@@ -106,6 +106,18 @@ func TestUpgradeCommandBuilders(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDropPacmanRepoIgnoresKeepsAURHolds(t *testing.T) {
|
||||||
|
pending := []Package{
|
||||||
|
{Name: "linux", Repo: RepoSystem},
|
||||||
|
{Name: "librewolf", Repo: RepoAUR},
|
||||||
|
}
|
||||||
|
got := dropPacmanRepoIgnores([]string{"linux", "librewolf", "not-pending"}, pending)
|
||||||
|
want := []string{"librewolf", "not-pending"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Fatalf("ignored = %#v, want %#v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAptUpgradeArgvHoldsIgnored(t *testing.T) {
|
func TestAptUpgradeArgvHoldsIgnored(t *testing.T) {
|
||||||
argv := aptUpgradeArgv("apt-get", UpgradeOptions{Ignored: []string{"linux-image-generic", "bad;name"}})
|
argv := aptUpgradeArgv("apt-get", UpgradeOptions{Ignored: []string{"linux-image-generic", "bad;name"}})
|
||||||
if len(argv) < 2 || argv[len(argv)-2] != "-c" {
|
if len(argv) < 2 || argv[len(argv)-2] != "-c" {
|
||||||
|
|||||||
@@ -336,7 +336,10 @@ DankPopout {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: statusText
|
id: statusText
|
||||||
anchors.fill: parent
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: ignoredSection.top
|
||||||
anchors.margins: Theme.spacingM
|
anchors.margins: Theme.spacingM
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -361,7 +364,10 @@ DankPopout {
|
|||||||
|
|
||||||
DankListView {
|
DankListView {
|
||||||
id: packagesList
|
id: packagesList
|
||||||
anchors.fill: parent
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: ignoredSection.top
|
||||||
anchors.margins: Theme.spacingS
|
anchors.margins: Theme.spacingS
|
||||||
visible: !SystemUpdateService.isUpgrading && SystemUpdateService.updateCount > 0 && !SystemUpdateService.hasError && !SystemUpdateService.isChecking
|
visible: !SystemUpdateService.isUpgrading && SystemUpdateService.updateCount > 0 && !SystemUpdateService.hasError && !SystemUpdateService.isChecking
|
||||||
clip: true
|
clip: true
|
||||||
@@ -467,13 +473,123 @@ DankPopout {
|
|||||||
iconName: "visibility_off"
|
iconName: "visibility_off"
|
||||||
iconSize: 16
|
iconSize: 16
|
||||||
iconColor: Theme.surfaceVariantText
|
iconColor: Theme.surfaceVariantText
|
||||||
visible: rowHoverHandler.hovered
|
visible: rowHoverHandler.hovered && SystemUpdateService.canIgnorePackage(packageRow.modelData)
|
||||||
tooltipText: I18n.tr("Ignore this package")
|
tooltipText: I18n.tr("Ignore this package")
|
||||||
onClicked: SystemUpdateService.ignorePackage(packageRow.modelData.name)
|
onClicked: SystemUpdateService.ignorePackage(packageRow.modelData.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: ignoredSection
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
readonly property var ignoredNames: SettingsData.updaterIgnoredPackages || []
|
||||||
|
readonly property bool shown: ignoredNames.length > 0 && !SystemUpdateService.isUpgrading && !SystemUpdateService.isChecking
|
||||||
|
property bool expanded: false
|
||||||
|
|
||||||
|
visible: shown
|
||||||
|
height: shown ? implicitHeight : 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: ignoredToggle
|
||||||
|
width: parent.width
|
||||||
|
height: 32
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: ignoredToggleArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
id: ignoredToggleIcon
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
name: "visibility_off"
|
||||||
|
size: 16
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.left: ignoredToggleIcon.right
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: I18n.tr("Ignored (%1)").arg(ignoredSection.ignoredNames.length)
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
name: ignoredSection.expanded ? "expand_less" : "expand_more"
|
||||||
|
size: 16
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: ignoredToggleArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: ignoredSection.expanded = !ignoredSection.expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankListView {
|
||||||
|
width: parent.width
|
||||||
|
height: ignoredSection.expanded ? Math.min(contentHeight, 150) : 0
|
||||||
|
visible: ignoredSection.expanded
|
||||||
|
clip: true
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
model: ignoredSection.ignoredNames
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: ignoredRow
|
||||||
|
width: ListView.view.width
|
||||||
|
height: 32
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||||
|
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.right: restoreButton.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: ignoredRow.modelData
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: restoreButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingXS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
buttonSize: 24
|
||||||
|
iconName: "visibility"
|
||||||
|
iconSize: 16
|
||||||
|
iconColor: Theme.surfaceVariantText
|
||||||
|
tooltipText: I18n.tr("Stop ignoring %1").arg(ignoredRow.modelData)
|
||||||
|
onClicked: SystemUpdateService.unignorePackage(ignoredRow.modelData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingM
|
anchors.margins: Theme.spacingM
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ Singleton {
|
|||||||
readonly property bool helperAvailable: sysupdateAvailable && backends.length > 0
|
readonly property bool helperAvailable: sysupdateAvailable && backends.length > 0
|
||||||
readonly property bool useCustomCommand: SettingsData.updaterUseCustomCommand && (SettingsData.updaterCustomCommand || "").trim().length > 0
|
readonly property bool useCustomCommand: SettingsData.updaterUseCustomCommand && (SettingsData.updaterCustomCommand || "").trim().length > 0
|
||||||
|
|
||||||
|
// Dont allow partial updates on arch, if they wanna break their system they can do it outside of DMS:
|
||||||
|
// https://wiki.archlinux.org/title/System_maintenance#Partial_upgrades_are_unsupported
|
||||||
|
// AUR/Flatpak packages stay ignorable — holding those cannot break the repo dependency graph.
|
||||||
|
readonly property bool systemHoldsAllowed: !["pacman", "paru", "yay"].includes(pkgManager)
|
||||||
|
|
||||||
|
function canIgnorePackage(pkg) {
|
||||||
|
if (!pkg)
|
||||||
|
return false;
|
||||||
|
return systemHoldsAllowed || pkg.repo !== "system";
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DMSService
|
target: DMSService
|
||||||
function onCapabilitiesReceived() {
|
function onCapabilitiesReceived() {
|
||||||
@@ -108,9 +119,11 @@ Singleton {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
backends = data.backends || [];
|
||||||
|
const systemBackend = backends.find(b => b.repo === "system" || b.repo === "ostree");
|
||||||
|
pkgManager = systemBackend ? systemBackend.id : (backends.length > 0 ? backends[0].id : "");
|
||||||
_rawUpdates = data.packages || [];
|
_rawUpdates = data.packages || [];
|
||||||
availableUpdates = _filterUpdates(_rawUpdates);
|
availableUpdates = _filterUpdates(_rawUpdates);
|
||||||
backends = data.backends || [];
|
|
||||||
distribution = data.distro || "";
|
distribution = data.distro || "";
|
||||||
distributionPretty = data.distroPretty || "";
|
distributionPretty = data.distroPretty || "";
|
||||||
distributionSupported = (backends.length > 0);
|
distributionSupported = (backends.length > 0);
|
||||||
@@ -145,13 +158,6 @@ Singleton {
|
|||||||
errorCode = "";
|
errorCode = "";
|
||||||
errorHint = "";
|
errorHint = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backends.length > 0) {
|
|
||||||
const sys = backends.find(b => b.repo === "system" || b.repo === "ostree");
|
|
||||||
pkgManager = sys ? sys.id : backends[0].id;
|
|
||||||
} else {
|
|
||||||
pkgManager = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _filterUpdates(pkgs) {
|
function _filterUpdates(pkgs) {
|
||||||
@@ -159,6 +165,8 @@ Singleton {
|
|||||||
return (pkgs || []).filter(p => {
|
return (pkgs || []).filter(p => {
|
||||||
if (!SettingsData.updaterAllowAUR && p.repo === "aur")
|
if (!SettingsData.updaterAllowAUR && p.repo === "aur")
|
||||||
return false;
|
return false;
|
||||||
|
if (!canIgnorePackage(p))
|
||||||
|
return true;
|
||||||
return ignored.indexOf(p.name) === -1;
|
return ignored.indexOf(p.name) === -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -177,6 +185,13 @@ Singleton {
|
|||||||
SettingsData.set("updaterIgnoredPackages", list);
|
SettingsData.set("updaterIgnoredPackages", list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unignorePackage(name) {
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
const list = (SettingsData.updaterIgnoredPackages || []).filter(p => p !== name);
|
||||||
|
SettingsData.set("updaterIgnoredPackages", list);
|
||||||
|
}
|
||||||
|
|
||||||
function checkForUpdates() {
|
function checkForUpdates() {
|
||||||
DMSService.sysupdateRefresh(false, null);
|
DMSService.sysupdateRefresh(false, null);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user