diff --git a/.github/diy/patches/package-manager.patch b/.github/diy/patches/package-manager.patch new file mode 100644 index 000000000..90c22ca6f --- /dev/null +++ b/.github/diy/patches/package-manager.patch @@ -0,0 +1,213 @@ +--- a/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js ++++ b/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +@@ -186,7 +186,7 @@ function parseList(s, dest) + val = RegExp.$2.trim(); + } + else if (pkg) { +- dest.pkgs[pkg.name] = pkg; ++ dest.pkgs[pkg.name] = dest.pkgs[pkg.name] ? dest.pkgs[pkg.name] : pkg; + + const provides = dest.providers[pkg.name] ? [] : [ pkg.name ]; + +@@ -249,7 +249,7 @@ function display(pattern) + const avail = packages.available.pkgs[name]; + const inst = packages.installed.pkgs[name]; + +- if (!isPkgInstalled(inst)) ++ if (!isPkgInstalled(inst) || pkg.name.includes('busybox') || pkg.name.includes('base-files')) + continue; + + if (!avail || compareVersion(avail.version, pkg.version) <= 0) +@@ -289,7 +289,7 @@ function display(pattern) + 'data-action': 'install', + 'click': handleInstall + }, _('Install…')); +- else if (isPkgInstalled(inst) && inst.version !== pkg.version) ++ else if (isPkgInstalled(inst) && compareVersion(pkg.version, inst.version) > 0) + btn = E('div', { + 'class': 'btn cbi-button-positive', + 'data-package': name, +@@ -791,7 +791,8 @@ function handleInstall(ev) + 'id': 'overwrite-cb', + 'type': 'checkbox', + 'name': 'overwrite', +- 'disabled': isReadonlyView ++ 'disabled': isReadonlyView, ++ 'checked': true + }), ' ', + E('label', { 'for': 'overwrite-cb' }), ' ', + _('Allow overwriting conflicting package files') +@@ -1031,6 +1032,8 @@ function handlePkg(ev) + if (res.pkmcmd) + dlg.appendChild(E('pre', [ res.pkmcmd ])); + ++ const showModalFlag = (cmd !== 'update' && pkg) || res.stderr; ++ if (showModalFlag) { + if (res.stdout) + dlg.appendChild(E('pre', [ res.stdout ])); + +@@ -1058,6 +1061,10 @@ function handlePkg(ev) + resolveFn(res); + }, this, res) + }, _('Dismiss')))); ++ } else { ++ ui.hideModal(); ++ updateLists(); ++ } + }).catch(function(err) { + ui.addNotification(null, E('p', _('Unable to execute %s %s command: %s').format(L.hasSystemFeature('apk') ? 'apk' : 'opkg', cmd, err))); + ui.hideModal(); +@@ -1152,6 +1159,36 @@ return view.extend({ + }, + + render(listData) { ++ const checkUpdateNeeded = function() { ++ return Promise.all([ ++ L.resolveDefault(fs.stat('/tmp/opkg-lists/kwrt_kiddin9'), null), ++ L.resolveDefault(fs.read('/tmp/resolv.conf.d/resolv.conf.auto'), '') ++ ]).then(function(results) { ++ const stat = results[0]; ++ const resolvContent = results[1]; ++ ++ let needUpdate = false; ++ ++ if (stat) { ++ const currentDate = new Date(); ++ const lastUpdateDate = new Date(stat.ctime * 1000); // Convert seconds to milliseconds ++ // 检查是否在今天的零点之后更新过 ++ const today = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()); ++ needUpdate = lastUpdateDate < today; ++ } else { ++ needUpdate = true; ++ } ++ ++ // 检查 resolv.conf.auto 文件内容 ++ const hasResolvContent = resolvContent && resolvContent.trim().length > 0; ++ ++ // 只有当需要更新且 resolv.conf.auto 不为空时,才返回 true ++ return needUpdate && hasResolvContent; ++ }).catch(function(error) { ++ console.error('Error checking update status:', error); ++ return false; // 如果出错,不执行更新 ++ }); ++ }; + const query = decodeURIComponent(L.toArray(location.search.match(/\bquery=([^=]+)\b/))[1] || ''); + + const view = E([], [ +@@ -1193,6 +1230,7 @@ return view.extend({ + E('label', {}, _('Actions') + ':'), ' ', + E('span', { 'class': 'control-group' }, [ + E('button', { 'class': 'btn cbi-button-positive', 'data-command': 'update', 'click': handlePkg, 'disabled': isReadonlyView }, [ _('Update lists…') ]), ' ', ++ E('button', { 'class': 'btn cbi-button-negative', 'data-command': 'upgradeall', 'click': handlePkg, 'disabled': isReadonlyView }, [ _('Upgrade all…') ]), ' ', + E('button', { 'class': 'btn cbi-button-action', 'click': handleUpload, 'disabled': isReadonlyView }, [ _('Upload Package…') ]), ' ', + E('button', { 'class': 'btn cbi-button-neutral', 'click': handleConfig }, [ _('Configure %s').format(L.hasSystemFeature('apk') ? 'apk' : 'opkg') ]) + ]) +@@ -1278,7 +1316,17 @@ return view.extend({ + ]); + + requestAnimationFrame(function() { +- updateLists(listData) ++ updateLists(listData); ++ checkUpdateNeeded().then(function(needUpdate) { ++ if (needUpdate) { ++ setTimeout(function() { ++ const updateButton = document.querySelector('button[data-command="update"]'); ++ if (updateButton) { ++ updateButton.click(); ++ } ++ }, 10) ++ } ++ }); + }); + + return view; + +--- a/luci-app-package-manager/root/usr/libexec/package-manager-call ++++ b/luci-app-package-manager/root/usr/libexec/package-manager-call +@@ -27,7 +27,7 @@ case "$action" in + find "${lists_dir:-/usr/lib/opkg/lists}" -type f '!' -name '*.sig' | xargs -r gzip -cd + fi + ;; +- install|update|upgrade|remove) ++ install|update|upgrade|upgradeall|remove) + ( + cmd="$ipkg_bin" + +@@ -89,10 +89,45 @@ case "$action" in + + if flock -x 200; then + pkmcmd="$cmd $action $@" +- $cmd $action "$@" /tmp/ipkg.out 2>/tmp/ipkg.err +- code=$? +- stdout=$(cat /tmp/ipkg.out) ++ if [ $action == "upgradeall" ]; then ++ $cmd update /tmp/ipkg.out 2>/tmp/ipkg.err ++ code=$? ++ if [ $code == 0 ]; then ++ . /etc/profile.d/opkg.sh ++ if [[ "$(cat `opkg export au`)" ]] && lock -n /var/lock/opkg-upgrade; then ++ opkg upgr >/tmp/ipkg.out 2>>/tmp/ipkg.err ++ code=$? ++ lock -u /var/lock/opkg-upgrade ++ else ++ echo "🎉 所有软件包已是最新~" >>/tmp/ipkg.out ++ code=0 ++ fi ++ fi ++ else ++ $cmd $action "$@" /tmp/ipkg.out 2>/tmp/ipkg.err ++ code=$? ++ fi ++ pkgn="$(echo $@ | cut -d - -f 3-)" ++ case "$action" in ++ install|upgrade) ++ if [ "$(opkg list-installed | cut -f 1 -d ' ' | grep -w $@)" ]; then ++ rm -f /tmp/ipkg.err ++ ([ -f /etc/profile.d/opkg.sh ] && . /etc/profile.d/opkg.sh && opkg save) & ++ fi ++ ;; ++ remove) ++ if [ ! "$(opkg list-installed | cut -f 1 -d ' ' | grep -w $@)" ]; then ++ rm -f /tmp/ipkg.err ++ ([ -f /etc/profile.d/opkg.sh ] && . /etc/profile.d/opkg.sh && opkg save) & ++ fi ++ ;; ++ esac + stderr=$(cat /tmp/ipkg.err) ++ [ -n "$stderr" ] || { ++ echo "🎉 已完成, 请关闭本窗口~" >>/tmp/ipkg.out ++ code=0 ++ } ++ stdout=$(cat /tmp/ipkg.out) + else + code=255 + stderr="Failed to acquire lock" +@@ -110,7 +145,7 @@ case "$action" in + ;; + *) + echo "Usage: $0 {list-installed|list-available|update}" >&2 +- echo " $0 {install|upgrade|remove} pkg[ pkg...]" >&2 ++ echo " $0 {install|upgrade|upgradeall|remove} pkg[ pkg...]" >&2 + exit 1 + ;; + esac + + +--- a/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json ++++ b/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json +@@ -8,6 +8,7 @@ + "/usr/libexec/package-manager-call list-available": [ "exec" ], + "/etc/opkg.conf": [ "read" ], + "/etc/opkg/*.conf": [ "read" ], ++ "/tmp/resolv.conf.d/resolv.conf.auto": [ "read" ], + "/etc/apk/repositories": [ "read" ], + "/etc/apk/repositories.d/distfeeds.list": [ "read" ], + "/etc/apk/repositories.d/customfeeds.list": [ "read" ] +@@ -24,6 +25,7 @@ + "/usr/libexec/package-manager-call update": [ "exec" ], + "/usr/libexec/package-manager-call upgrade": [ "exec" ], + "/usr/libexec/package-manager-call upgrade *": [ "exec" ], ++ "/usr/libexec/package-manager-call upgradeall": [ "exec" ], + "/etc/opkg.conf": [ "write" ], + "/etc/opkg/*.conf": [ "write" ], + "/etc/apk/repositories": [ "write" ],