Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Is it possible to fix the current working directory? #4233

Closed
gagle opened this Issue Nov 3, 2012 · 5 comments

Comments

Projects
None yet
3 participants

gagle commented Nov 3, 2012

As you may know the cwd isn't pointing to the application real cwd. From the app point of view the cwd is the same as __dirname if we read this variable from the main file.

If you use the . path with an I/O built-in function, e.g. fs.writeFile("./file", ...) it won't always work. This is because if you execute the app from a different directory where the main file is located, e.g. node myapp/main.js, . is pointing to the directory that contains myapp, so instead of doing fs.writeFile("./file", ...) you must to use the path myapp, fs.writeFile("myapp/file", ...).

Ok, you can simply use __dirname, fs.writeFile(__dirname + "/file", ...). But this won't always work because if you are writing a module __dirname will point to a directory inside node_modules.

If you cannot use __dirname it's impossible to fix the cwd because you then need to use the proces.cwd() and the process.mainModule.filename to solve the problem:

var realCWD = path.relative (process.cwd (), path.dirname (process.mainModule.filename));
writeFile (realCWD + "/file", ...);

This snippet works from inside modules and normal scripts but again, is not always working. Inside a global module the process.mainModule.filename points to the global module main file, e.g. in mocha it points to /usr/local/lib/node_modules/mocha/bin/_mocha if you are on Linux.

Concluding,

  • On local modules and normal scripts this issue can be solved with the previous snippet.
  • On global modules cannot be solved because the process.mainModule.filename points to the global module main file (and it's impossible to know the real main file because it depends on the module, process.MainModule.filename is correct).

The only case where you need the real cwd and cannot be calculated is when you execute a script that is located inside node_modules (local or inside the global module's node_modules folder, doesn't matter) and needs to write a file in the real cwd using a global module because you can't use neither __dirname nor process.mainModule.filename. The first because it points to a folder inside node_modules and the second because it points to the global module main file.

Example:
You have a module called log installed locally in test/node_modules and a global module, for example global. If you execute global test/test.js you want to write a log file inside test (test.js executes log ("message") and you wan't to fix thw cwd issue internally without any parameter that the users need to pass: log (__dirname, "message") -> NO!). Currently this is impossible to do.

I know, it's hard to understand but try to do the above test case. You will simply can't. The global module is not yours, it's implemented by other people and have not take into account this little big problem, the log module it's yours.

To solve this issue you can simply set a global property __caller with the __filename of the caller script. For example:

a.js -> __filename = /bla/bla/a.js, __caller = null (if node a, a.js __caller = null)
b.js -> is called by a.js, __filename = /does/not/matter, __caller = /bla/bla/a.js

Now we can modify the previous snippet:

var realCWD = path.relative (process.cwd (),  path.dirname (__caller ?  __caller : process.mainModule.filename));
writeFile (realCWD + "/file", ...);

This will work 100% of time.

Sorry for my english.

Owner

bnoordhuis commented Nov 3, 2012

process.cwd() is just a thin wrapper around getcwd(3), we're not changing its behavior.

@bnoordhuis bnoordhuis closed this Nov 3, 2012

gagle commented Nov 4, 2012

The node.js will be bugged forever... Have you read the entire post? I'm not asking about changing the cwd function.

In your example, you seem to be trying to get the log() function to drop its log file in the "right" place without your client code (test.js) configuring that. That will only work in limited scenarios anyway, so it's a flawed approach. Let's say log() uses your __caller to determine where to place its log file. In your example, when test.js calls log(), the file will land in the 'test' directory. So far, so good.

Now let's assume that someone refactors the test.js code and splits out a lib/loghelper.js module that makes the actual calls to log(), and now the code in test.js calls loghelper.dolog(), which in turn calls the original log() function. Now the log code will use __caller to determine that the 'lib' directory is the right place for the log file, since that's where log() was called from. Probably not what you want. The right answer here is for the client code to be configuring the logger to tell it where to put its log file, rather than relying on a fragile approach based on which file contains the calling function.

Owner

bnoordhuis commented Nov 4, 2012

Have you read the entire post?

Yes, though I admit to being confused about what your point really is: changing how process.cwd() works or the module system. Anyway, in both cases the answer is 'no'.

To paraphrase what @mfncooper said: you should rethink your approach.

gagle commented Nov 4, 2012

Ok, thanks for your time. The log example was just an example to help you understand the problem. At the moment it's impossible to get the correct path without the user interaction in the scenario described above. I see that the __caller approach fails when the log module is called from a location different where the real main file is located. Believe me when I say that I've been thinking about this for a couple of hours and I can't find a good solution without any real path coming from you. Thanks anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment