-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
storage: Install NFS packages on demand #8913
storage: Install NFS packages on demand #8913
Conversation
Super quick demo: https://www.youtube.com/watch?v=gpoF3cU-Y0U |
@larskarlitski, fyi. |
This probably need the DependsOn PackageKit method, which isn't supported for dnf, so yeah. |
Nice video! I like that it is fairly unintrusive. Curious that you already have an NFS mount even before you install necessary software :-) |
That's a great demo! I wonder if having it that easy to install software might make some sysdamins feel a bit leery. 😉 |
c9f2e56
to
8459e1d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial review. Thanks!
pkg/lib/packagekit.es6
Outdated
* will take, but, PackageKit... | ||
*/ | ||
|
||
export function check_optional_packages(names, progress_cb) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"optional" is IMHO a bit confusing - we are using this for use cases where said packages are actually required. How about check_missing_packages()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, very good! I didn't like "optional" either.
pkg/lib/packagekit.es6
Outdated
*/ | ||
|
||
export function check_optional_packages(names, progress_cb) { | ||
if (names.length == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
===
pkg/lib/packagekit.es6
Outdated
{ | ||
Package: (info, package_id) => { | ||
console.log("P", info, package_id); | ||
var repos = package_id.split(";")[3].split(":"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use var
in arrow functions (const
or let
), var
has broken scoping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. But is there something special with var
in arrow functions? I think it's not anymore broken with arrow functions than with function
functions.
pkg/lib/packagekit.es6
Outdated
console.log("P", info, package_id); | ||
var repos = package_id.split(";")[3].split(":"); | ||
if (repos.indexOf("installed") == -1) | ||
ids.push(package_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what your IRC ping from yesterday was about, right? Really weird that PK_FILTER_ENUM_NOT_INSTALLED
does not work - what other purpose would that have? But this workaround looks simple enough.
pkg/lib/packagekit.es6
Outdated
return refresh().then(resolve).then(get_deps); | ||
} | ||
|
||
export function install_optional_packages(data, progress_cb) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function does almost nothing on top of InstallPackages, so it feels a bit like noise. But I have no strong opinion if you want to keep this wrapper. But then please call it install_packages()
and give it its own documentation comment.
pkg/lib/packagekit.es6
Outdated
|
||
export function check_optional_packages(names, progress_cb) { | ||
if (names.length == 0) | ||
return cockpit.resolve(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use/return standard Promise
instead of cockpit.defer
, as the rest of this library already does that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/lib/packagekit.es6
Outdated
}, | ||
}).then(() => { | ||
return data; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.then( () => data);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/lib/packagekit.es6
Outdated
if (ids.length == 0) | ||
return null; | ||
else | ||
return { pkg_ids: ids }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you rely on the special null
case in particular? It seems more consistent to always just return ids
even if empty. install_packages()
below in particular deals fine with this, and it also makes it easier to log/print/check the value without always having to consider the null
special case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the point, but with the current API, pkg_ids
is internal and the client shouldn't access it. I had some public fields like package_count
, but without a working DependsOn, it would be misleading to display "1 software package will be installed" when in fact we will install 20 (because of deps).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
aa19d15
to
ecd6592
Compare
ecd6592
to
2b035cd
Compare
2b035cd
to
86080b3
Compare
86080b3
to
22edefc
Compare
22edefc
to
c196c03
Compare
c196c03
to
4d2d667
Compare
4d2d667
to
4da7875
Compare
4da7875
to
dc74c93
Compare
dc74c93
to
93675a2
Compare
I've updated the mockup:
Concerns:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! I haven't tested it yet, just reviewed the code. I found a few issues.
pkg/lib/packagekit.es6
Outdated
[ Enum.FILTER_ARCH | | ||
Enum.FILTER_NOT_SOURCE | | ||
Enum.FILTER_NEWEST, | ||
names |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation is off here (I wonder why eslint didn't spot that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what eslint wants. It rejects the 'correct' indentation. Maybe it doesn't handle this style of multi-line arrays. I have put it all on one line, which fits now.
pkg/lib/packagekit.es6
Outdated
{ | ||
Package: (info, package_id) => { | ||
var parts = package_id.split(";"); | ||
var repos = parts[3].split(":"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var
→ let
in arrow functions or nested scopes please; scoping of var
doesn't go well with either. Same problem further down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. What's wrong with var
in arrow functions? It's as broken as with normal functions, but not more broken, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, let
has a scope of the enclosing { }
block, i. e. what you intuitively expect. var
's scope is always the innermost enclosing function
(not arrow-closure!), so that if you declare a var
in an arrow function, for
loop, if
block etc., it will still exist outside of that block. I. e. var
other than directly in a function
is conceptually broken and error prone, and should be avoided.
See https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/let
pkg/lib/packagekit.es6
Outdated
.then(() => { | ||
for (var i = 0; i < names.length; i++) { | ||
if (!installed_names[names[i]] && data.missing_names.indexOf(names[i]) == -1) | ||
data.unavailable_names.push(names[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of accessing names[i]
several times, how about names.forEach(name => { ... })
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
#cockpit_modal_dialog .modal-body { | ||
max-height: calc(75vh - 10rem); | ||
overflow: auto; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scrolling the entire dialog body seems a bit odd; don't we want to just scroll the package list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, @garrett?
pkg/lib/packagekit.es6
Outdated
@@ -244,7 +244,8 @@ export function cancellableTransaction(method, arglist, progress_cb, signalHandl | |||
// avoid calling progress_cb after ending the transaction, to avoid flickering cancel buttons | |||
ErrorCode: (code, detail) => { | |||
progress_cb = null; | |||
reject({ detail, code: cancelled ? "cancelled" : code }); | |||
reject({ detail, code: cancelled ? "cancelled" : code, | |||
toString: () => detail }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a nice trick, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's obsolete now with the use of TransactionError, right?
pkg/storaged/client.js
Outdated
}, | ||
function () { | ||
return PK.call("/org/freedesktop/PackageKit", "org.freedesktop.DBus.Properties", | ||
"Get", [ "org.freedesktop.PackageKit", "VersionMajor" ]).then( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also a good candidate for moving into lib/packagekit. (Not a blocker for this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been moved.
pkg/storaged/optional-panel.jsx
Outdated
if (data.extra_names.length > 0 && data.remove_names.length == 0) { | ||
summary = ( | ||
<p> | ||
{ format_to_array(_("$0 will be installed, along with additional packages:"), missing_names) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should use ngettext. Depending on if it's one or more packages, translation will be different in non-English languages; e. g. in German, "a wird installiert" vs. "a, b werden installiert". This also occurs a few times below.
# The first simulated install seems to silently not report | ||
# anything on the Debian test images, for unknown reasons. So | ||
# we install a dummy package to warm up all parts of the | ||
# machinery and distribute the fluids evenly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a stupendously exact technical explanation what's going on 🤣
Could it perhaps be limited to if "debian" in m.image or "ubuntu" in m.image
, to ensure we know when it happens elsewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
So I was thinking about this issue:
Having it jump with that information is not so nice. Therefore, I figured out how to make it scale with a bit of CSS (and a tiny bit of JS to add a CSS class): https://garrett.github.io/cockpit-mockweb/dialog-scale/ The idea is the scale would be triggered between step 1 and 2 (and not when clicking a button, like in the demo itself). |
6eb7bda
to
e766996
Compare
There is now a new cockpit-component-install-dialog that encapsulates all the work. The OptionalPanel isn't meant to be reusable anymore but I left the API as it is, without putting back the old assumptions of how we store our feature flags in the client. That's a bit more verbose, but the feature detection business can use some cleanup and this could be the first step. |
By using "super()" instead of hardcoding the base class.
The cancel handler can now also be handed in via a progress report on the action promise. In addition, the Cancel button itself now is only enabled during an action when there is a cancel handler.
e766996
to
d3e4cb2
Compare
@martinpitt, ptal! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works nicely, and the code now looks by and large good to me, too. Would be nice to fix the (apparently) broken commit message and add a "Closes #" to make this button-mergeable. @andreasn, do you want to review the design, too? You have a pending review.
}) | ||
.catch(error => { | ||
dfd.reject(error); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: should suffice to write just .then(dfd.resolve)
and .catch(dfd.reject)
; but it's fine like that. Does the caller firmly expect a cockpit promise? A standard Promise doesn't work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not convinced that the two forms are equivalent, because of this
. With a call like dfd.resolve()
, the resolve method will have this == dfd
. With just .then(dfd.resolve)
, this
is likely undefined. This might not matter depending on whether the resolve method actually uses this
or not. I think it doesn't, but that's just luck. Am I wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, could be. We use that pattern a lot (git grep fail.*reject
) and it seems to work, but indeed it could be that this is by luck.
@@ -0,0 +1,38 @@ | |||
.package-list-ct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit log looks like you got a phone call when starting to type it? :-) ("lib/cockpit-components-install-dialog: New ").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was on purpose and how we did it back in the days. :-) What else do you expect for a completely new module?
d3e4cb2
to
6111d7a
Compare
Do you have a newer video of this? Because I'm having trouble getting it to run :( |
@andreasn: The video in the description seems current, that's how it looks like for me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to go!
Testing
Currently, this just install the "nfs-utils" package. So to test, remove "nfs-utils" first.
Tasks
Demo for release notes: https://youtu.be/Gaioqm7sLEo