--- a/luci-app-package-manager/root/usr/share/luci/menu.d/luci-app-package-manager.json +++ b/luci-app-package-manager/root/usr/share/luci/menu.d/luci-app-package-manager.json @@ -1,5 +1,5 @@ { - "admin/system/package-manager": { + "admin/package-manager": { "title": "Software", "order": 30, "action": { --- 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" ],