mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 03:28:28 -04:00
sysupdate: disallow partial updates on arch, add ignored to popout
port 1.5
This commit is contained in:
@@ -50,11 +50,42 @@ func (b pacmanBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine
|
||||
}
|
||||
|
||||
func pacmanUpgradeArgv(opts UpgradeOptions) []string {
|
||||
argv := []string{"pacman", "-Syu", "--noconfirm", "--needed"}
|
||||
if len(opts.Ignored) > 0 {
|
||||
argv = append(argv, "--ignore", strings.Join(opts.Ignored, ","))
|
||||
return privilegedArgv(opts, "pacman", "-Syu", "--noconfirm", "--needed")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
@@ -345,6 +345,9 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
|
||||
opts.Targets = append([]Package(nil), m.state.Packages...)
|
||||
m.mu.RUnlock()
|
||||
}
|
||||
if isPacmanFamily(m.selection.System) {
|
||||
opts.Ignored = dropPacmanRepoIgnores(opts.Ignored, opts.Targets)
|
||||
}
|
||||
opts.Targets = dropIgnoredTargets(opts.Targets, opts.Ignored)
|
||||
|
||||
backends := upgradeBackends(m.selection, opts)
|
||||
|
||||
@@ -50,9 +50,9 @@ func TestUpgradeCommandBuilders(t *testing.T) {
|
||||
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"}}),
|
||||
want: []string{"pkexec", "pacman", "-Syu", "--noconfirm", "--needed", "--ignore", "linux"},
|
||||
want: []string{"pkexec", "pacman", "-Syu", "--noconfirm", "--needed"},
|
||||
},
|
||||
{
|
||||
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) {
|
||||
argv := aptUpgradeArgv("apt-get", UpgradeOptions{Ignored: []string{"linux-image-generic", "bad;name"}})
|
||||
if len(argv) < 2 || argv[len(argv)-2] != "-c" {
|
||||
|
||||
@@ -336,7 +336,10 @@ DankPopout {
|
||||
|
||||
StyledText {
|
||||
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
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
@@ -361,7 +364,10 @@ DankPopout {
|
||||
|
||||
DankListView {
|
||||
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
|
||||
visible: !SystemUpdateService.isUpgrading && SystemUpdateService.updateCount > 0 && !SystemUpdateService.hasError && !SystemUpdateService.isChecking
|
||||
clip: true
|
||||
@@ -467,13 +473,123 @@ DankPopout {
|
||||
iconName: "visibility_off"
|
||||
iconSize: 16
|
||||
iconColor: Theme.surfaceVariantText
|
||||
visible: rowHoverHandler.hovered
|
||||
visible: rowHoverHandler.hovered && SystemUpdateService.canIgnorePackage(packageRow.modelData)
|
||||
tooltipText: I18n.tr("Ignore this package")
|
||||
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 {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
|
||||
@@ -35,6 +35,17 @@ Singleton {
|
||||
readonly property bool helperAvailable: sysupdateAvailable && backends.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 {
|
||||
target: DMSService
|
||||
function onCapabilitiesReceived() {
|
||||
@@ -108,9 +119,11 @@ Singleton {
|
||||
if (!data) {
|
||||
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 || [];
|
||||
availableUpdates = _filterUpdates(_rawUpdates);
|
||||
backends = data.backends || [];
|
||||
distribution = data.distro || "";
|
||||
distributionPretty = data.distroPretty || "";
|
||||
distributionSupported = (backends.length > 0);
|
||||
@@ -145,13 +158,6 @@ Singleton {
|
||||
errorCode = "";
|
||||
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) {
|
||||
@@ -159,6 +165,8 @@ Singleton {
|
||||
return (pkgs || []).filter(p => {
|
||||
if (!SettingsData.updaterAllowAUR && p.repo === "aur")
|
||||
return false;
|
||||
if (!canIgnorePackage(p))
|
||||
return true;
|
||||
return ignored.indexOf(p.name) === -1;
|
||||
});
|
||||
}
|
||||
@@ -177,6 +185,13 @@ Singleton {
|
||||
SettingsData.set("updaterIgnoredPackages", list);
|
||||
}
|
||||
|
||||
function unignorePackage(name) {
|
||||
if (!name)
|
||||
return;
|
||||
const list = (SettingsData.updaterIgnoredPackages || []).filter(p => p !== name);
|
||||
SettingsData.set("updaterIgnoredPackages", list);
|
||||
}
|
||||
|
||||
function checkForUpdates() {
|
||||
DMSService.sysupdateRefresh(false, null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user