-
-
Notifications
You must be signed in to change notification settings - Fork 25
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
Save cached config to standard directories #38
Conversation
Instead of placing the configuration file in the home directory it should be placed in the [appropriate directory](https://wiki.archlinux.org/index.php/XDG_Base_Directory_support) per OS. Breaking change: resolves issue #37
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.
Thanks. This can be reduced by a lot though. There also needs to be tests over the new .js
file.
env-paths.js
Outdated
const path = require('path'); | ||
const os = require('os'); | ||
|
||
const homedir = require('user-home'); |
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 https://www.npmjs.com/package/homedir-polyfill
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'm simply using user-home
because it's already a dependency.
Edit: I looked into using the homedir-polyfill
but would rather stick with user-home
because it has no dependencies and is used a bit more.
env-paths.js
Outdated
const appData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local'); | ||
|
||
return { | ||
// data/config/cache/log are invented by me as Windows isn't opinionated about this |
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.
There isn't a point in ripping this module verbatim. The usage just plucks the .cache
property so the API should be reduced to that use case.
index.js
Outdated
|
||
const configfile = '.v8flags.'+process.versions.v8+'.'+crypto.createHash('md5').update(user).digest('hex')+'.json'; | ||
const configPath = envPaths('js-v8flags').cache; |
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 API should be reduced to just return the .cache
property (and not generate objects with a bunch of properties). This also removes the need for attribution since it isn't even the same module anymore.
if (err) return tryOpenConfig(path.join(os.tmpdir(), configfile), cb); | ||
return cb(null, fd); | ||
}); | ||
fs.mkdir(configPath, function () { |
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.
Wouldn't this need to be mkdirp
? By that I mean, is there a chance the multiple directory paths will need to be created?
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 question, I'm not sure what the proper solution is here. It should only create one directory unless the user deleted a default OS directory which would probably also break other apps...
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.
You can definitely count on some environments not being able to make this directory. It's a crazy world out there.
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.
@tkellen I understand but regardless of an error or not tryOpenConfig
will be called so if the directory can not be created os.tmpdir
will be used. Is that enough or would using mkdirp
be better in some 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.
To clarify, by "multiple" I think @phated meant nested. It doesn't seem unlikely that the user would define a nested directory in config, in which case you would either need to recreate the logic in mkdirp
and loop over the directory segments to create each one, or just use mkdirp
so you don't need to think about edge cases.
also, is there a reason the error isn't being handled?
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 I understand @phated meant nested directories. With my reply I meant that it's nested inside a default OS directory so I'm wondering if the case needs to be handled.
Regarding error handling, if for some reason we can't create the directory the next function tryOpenConfig
will handle the logic of falling back to a temporary directory so that's why there is no need to handle it.
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.
If you handle the error (and it's not EEXIST - which you wouldn't need to worry about with mkdirp) you could avoid an extra tryOpenConfig
on the configPath before attempting tmpdir
, 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.
Yes that's true. Do you think using mkdirp
has enough benefit: avoiding an extra tryOpenConfig
in edge cases to justify including this new dependency?
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.
Even if it isn't worth the added dependency (not sure if so), checking the error might still be worth it.
cache-paths.js
Outdated
|
||
const env = process.env; | ||
|
||
const macos = function (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.
Prefer named functions over function assignments
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 taking a name
, can just have 'js-v8flags'
assigned as a variable at the top of file.
cache-paths.js
Outdated
return path.join(library, 'Caches', name); | ||
}; | ||
|
||
const windows = function (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.
Prefer named functions over function assignments
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 taking a name
, can just have 'js-v8flags'
assigned as a variable at the top of file.
cache-paths.js
Outdated
}; | ||
|
||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
const linux = function (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.
Prefer named functions over function assignments
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 taking a name
, can just have 'js-v8flags'
assigned as a variable at the top of file.
cache-paths.js
Outdated
return path.join(env.XDG_CACHE_HOME || path.join(homedir, '.cache'), name); | ||
}; | ||
|
||
module.exports = function (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.
Instead of calling this as a function, it should probably just export the proper path based on platform
if (err) return tryOpenConfig(path.join(os.tmpdir(), configfile), cb); | ||
return cb(null, fd); | ||
}); | ||
fs.mkdir(configPath, function () { |
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.
If you handle the error (and it's not EEXIST - which you wouldn't need to worry about with mkdirp) you could avoid an extra tryOpenConfig
on the configPath before attempting tmpdir
, right?
config-path.js
Outdated
module.exports = windows(); | ||
} | ||
|
||
module.exports = linux(); |
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 will always overwrite the value with the result of linux()
. I believe this outlines why this needs extra unit tests added.
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.
Oh whoops my bad, it's because I quickly removed it from the function late in the evening ^^.
What kind of unit tests would you add, hardcode the expected path in the test?
For some reason the CI test on Node 0.10 fails at one unit test and I don't understand why. Any help would be appreciated! :) |
config-path.js
Outdated
if (process.platform === 'darwin') { | ||
module.exports = macos(); | ||
} else if (process.platform === 'win32') { | ||
module.exports = windows(); |
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.
extra space after =
config-path.js
Outdated
function macos () { | ||
const library = path.join(userHome, 'Library'); | ||
return path.join(library, 'Caches', 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.
no semi-colon after named functions
config-path.js
Outdated
function windows () { | ||
const appData = env.LOCALAPPDATA || path.join(userHome, 'AppData', 'Local'); | ||
return path.join(appData, name, 'Cache'); | ||
}; |
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 semi-colon after named functions
config-path.js
Outdated
function linux () { | ||
const username = path.basename(userHome); | ||
return path.join(env.XDG_CACHE_HOME || path.join(userHome, '.cache'), 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.
no semi-colon after named functions
test.js
Outdated
afterEach(cleanup); | ||
|
||
it('should return default linux path in other environments', function(done) { | ||
Object.defineProperty(process, 'platform', {value: 'other'}); |
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 needs to be reset/cleaned-up
test.js
Outdated
}); | ||
|
||
it('should return default macos path in darwin environment', function(done) { | ||
Object.defineProperty(process, 'platform', {value: 'darwin'}); |
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 needs to be reset/cleaned-up
test.js
Outdated
}); | ||
|
||
it('should return default windows path in win32 environment', function(done) { | ||
Object.defineProperty(process, 'platform', {value: 'win32'}); |
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 needs to be reset/cleaned-up
config-path.js
Outdated
return path.join(env.XDG_CACHE_HOME || path.join(userHome, '.cache'), name); | ||
} | ||
|
||
if (process.platform === 'darwin') { |
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.
While I doubt it matters for this module, this approach for dynamic exporting makes it impossible to statically analyze this. Can you update this to export a single function that takes process.platform
as an argument and returns the correct result accordingly?
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.
You realize that it was initially exporting a function but phated told me to change it?
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.
My apologies, I did not--I have not been watching as closely as he has. Mind sharing what you think the most appropriate approach is here?
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 problem, I'm not sure as both ways of their pros and cons. Think as it is now it's very specific to this package so I would leave it as it is. When this package drops support for < Node 4 ideally we would swap it with the env-paths
package, by then the 'new ES import' will be in place too so it has more significance to be able to statically analyze it.
🤔
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.
Speaking of Node 0.10, do you have any idea why it's failing in CI? Really need some help to get that fixed. :(
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.
@phated yes I already tried debugging locally but can't figure it out. Node 0.10 is acting weird, test doesn't find the user-home
module when process.platform
is win32
. Just changing process.platform
is enough to make it work. :/
All newer Node versions work fine.
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.
Alright after giving this more debugging time I'm still stuck. What do you think of reversing the earlier change and returning a function instead passing it the platform instead of using a global?
Or dropping 0.10 support but you probably have a reason not to ...?
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.
We aren't dropping 0.10 support because it is still the latest node version shipped in official channels on some linux.
I don't like returning the function; we should really just figure out what is going on here.
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 not returning the function; it’s exporting it.
module.exports = function (process) {
if (process.platform === …) {
⋮
}
};
would make it possible to pass an object in in tests without changing process
itself, which is what causes the breakage on 0.10, and additionally clean up the require cache hack.
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.
Oops, bad wording from my end. That's what I meant. @phated thoughts?
It's working with all versions now. |
config-path.js
Outdated
} | ||
|
||
return linux(); | ||
} |
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.
Missing a semicolon.
config-path.js
Outdated
const name = 'js-v8flags'; | ||
|
||
function macos () { | ||
const library = path.join(userHome, 'Library'); |
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.
Seems as though this project uses two-space indentation, not tabs.
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.
Correct, this project really needs an editorconfig.
test.js
Outdated
@@ -16,6 +16,9 @@ function eraseHome() { | |||
delete env.USER; | |||
delete env.LNAME; | |||
delete env.USERNAME; | |||
delete env.XDG_CACHE_HOME; | |||
delete env.LOCALAPPDATA; | |||
delete process.platform; |
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 doesn’t seem very nice.
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 mostly needed though.
afterEach(cleanup); | ||
|
||
it('should return default linux path in other environments', function(done) { | ||
delete require.cache[require.resolve('./config-path.js')]; |
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.
Is this still necessary?
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.
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’d be best to make it so it isn’t, then. Is this somehow clearing the cache for user-home
?
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 been a while back but I think it does yes. I consider it bad but this pattern is used in other existing tests too. The best way to test this would be in sandboxes but that falls outside the scope of this PR.
@Siilwyn I needed to put this on the backburner to push through the last couple of gulp4 blockers. I'll do a more in-depth review of everything once that is shipped. |
Okay nice! I already love using Gulp 4 in the alpha. |
@tkellen do you have some time to review in advance? |
@tkellen could you review the PR? :) |
Apologies for the delay @Siilwyn. I've just added you as a collaborator on this repo / author on npm. Thank you for this work! I'm actually leaving for a much needed vacation this morning and will be offline for the next week. If you'd like to land and publish this, please feel free to do so as long as you keep a close eye on the issue tracker and fix any issues that crop up as a result. |
Thank you for your reply and the given trust @tkellen! I'll let this sit for a bit more today so there's some room for further replies. Enjoy your vacation, going offline for a while is always refreshing! ⛱️ |
The v8flags dependency got updated so that it follows the OS cache location conventions. See [the PR](gulpjs/v8flags#38) for more information.
Instead of placing the configuration file in the home directory it should be placed in the appropriate directory per OS.
Breaking change: resolves issue #37