Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-21 Thread Johan Vromans
Chip Salzenberg [EMAIL PROTECTED] writes:

 According to Michael G Schwern:
 In the same way that we have open() not fopen, fdopen, freopen... we
 can choose the safest and most sensible technique for determining
 the cwd and use that.

 And there is more than one open.  Perl does have fopen/fdopen/freopen,
 but they're accessed through other techniques besides the name of the
 operator.  For example, Perl spells Cfh = fdopen(5, r) as Copen
 $fh, =5).  The unique technique is there, just pushed out of the
 operator name and into its parameters.
 And then there's sysopen().

This is exactly the point (I think) Schwern is trying to make.  There
is 'open', that will do most of the time. If a novice user asks how to
open a file, you can say Well, just 'open $fh, $file'. If you want
more than vanilla file access, there are all the other forms of open
and open parameters.

From the perspective of 'current directory' there should also be a
simple and elegant way that will do in most cases. Advanced tricks can
be made possible using separate modules and such.

Maybe the basic problem is that 'current directory' is a system
dependent file system location that is not a fixed string, although it
usually can be represented as a string. Similar to a simple 'open', I
think the most common use of 'cwd' (or whatever) is to return a file
system location that can be returned to later, much in the sense of
'tell' and 'seek'. I think this can be implemented in a quite fail
safe way on most platforms.

-- Johan


Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-21 Thread Juerd
Johan Vromans skribis 2005-04-21  8:22 (+0200):
 This is exactly the point (I think) Schwern is trying to make.  There
 is 'open', that will do most of the time. If a novice user asks how to
 open a file, you can say Well, just 'open $fh, $file'. If you want
 more than vanilla file access, there are all the other forms of open
 and open parameters.

Just for the record, that's spelled $fh = open $file in Perl 6.


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html


Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-16 Thread Chip Salzenberg
According to Michael G Schwern:
 On Fri, Apr 15, 2005 at 08:31:57PM -0400, Chip Salzenberg wrote:
  There are several methods to determine the current directory.
 
 Perl 6 is going to have to decide on some sort of standard internal getcwd 
 technique, $CWD or not.

I don't think Perl 6 has to do anything of the kind.  It would
be a mistake to try.

 In the same way that we have open() not fopen, fdopen, freopen... we
 can choose the safest and most sensible technique for determining
 the cwd and use that.

There's more than one sensible thing.  There's more than one safe
thing.

And there is more than one open.  Perl does have fopen/fdopen/freopen,
but they're accessed through other techniques besides the name of the
operator.  For example, Perl spells Cfh = fdopen(5, r) as Copen
$fh, =5).  The unique technique is there, just pushed out of the
operator name and into its parameters.

And then there's sysopen().

But open() is beside the point, no matter that it supports my point. :-)

As you know, under Unix, there's no such thing as the current
directory as a string.  The only durable current directory is the
device and inode of Cstat('.').  It's not wise to conflate the
current directory with a name that at some point in the past could
have been used to reach it.

 You have to because when a new user asks how do I get the current
 working directory? [...]

Then I answer him with the same patience I answer someone who asks
how to get the filename corresponding to an open file descriptor:
There is no portable way.  Tell me what you want to do, and maybe
I can help you.
-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-16 Thread Michael G Schwern
On Fri, Apr 15, 2005 at 09:32:23PM -0400, Chip Salzenberg wrote:
  Perl 6 is going to have to decide on some sort of standard internal getcwd 
  technique, $CWD or not.
 
 I don't think Perl 6 has to do anything of the kind.  It would
 be a mistake to try.

Sorry, I had assumed that having a simple cwd() was a forgone conclusion 
so I just tried to bull through it.  My bad.  Lemme back up a few steps and 
try again. [1]

Yes, there are lots of ways to check the cwd each filling in one edge
case or another.  However I'd like to believe its possible to come up with
one simple, safe cwd() that works for 99.9% of the cases and call that cwd().
Then have a Cwd module full of all the various other techniques (or perhaps
attributes to alter the behavior of cwd()).  This lets you answer the 
question How do I get the current working directory? with Short answer: 
cwd().  Long answer: For this set of conditions, use this... 
This avoids the current state of things where a user with a simple
desire must slog through the rather daunting choices provided by Cwd.pm
and probably wind up making the wrong decision. [2]  A high level language
really should smooth all that over.

How cwd() is implemented is not so important as what happens when it hits
an edge case.  So maybe we can try to come up with a best fit cwd().  I'd 
start by listing out the edge cases and what the possible behaviors are.  
Maybe we can choose a set of behaviors which is most sensible across all 
scenarios and define cwd() to act that way.  Or maybe even just define what 
various cwd variations currently do.

Here's the ones I know of off the top of my head.  You probably know more.

* The cwd is deleted
* A parent directory is renamed
* A parent directory is a symlink


[1]  http://angryflower.com/pathof.gif
[2]  The state of Cwd.pm's docs add to my anxiety.



Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-16 Thread John Macdonald
On Saturday 16 April 2005 01:53, Michael G Schwern wrote:
 How cwd() is implemented is not so important as what happens when it hits
 an edge case.  So maybe we can try to come up with a best fit cwd().  I'd 
 start by listing out the edge cases and what the possible behaviors are.  
 Maybe we can choose a set of behaviors which is most sensible across all 
 scenarios and define cwd() to act that way.  Or maybe even just define what 
 various cwd variations currently do.
 
 Here's the ones I know of off the top of my head.  You probably know more.
 
 * The cwd is deleted
 * A parent directory is renamed
 * A parent directory is a symlink

There is also the possibility for permissions issues:

* You don't have permissions to determine cwd as an absolute pathname
* You are in a directory that you couldn't have chdir'ed into (that makes the
   localized $CWD fail to return you to the original location when it goes out
   of scope).

It's not hard to run a program that is setuid (to a non-root account) from 
within
a directory that is owner-only accessible.


Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-16 Thread Chip Salzenberg
According to Michael G Schwern:
 Yes, there are lots of ways to check the cwd each filling in one edge
 case or another.  However I'd like to believe its possible to come up with
 one simple, safe cwd() that works for 99.9% of the cases and call that cwd().

Well, it's certainly possible ... and it's not up to me, anyway; but I
still think it's a Bad Idea to standardize like that.  I've already
said why (there's no good reason to pick one over another), though it
doesn't surprise me opinions differ.  :-,

 A high level language really should smooth all that over.

An HLL or LLL, it doesn't really matter.  This isn't a language
feature, this is an _operating_system_ feature.  Pretending that the
system is providing an attribute that it really isn't just confuses
people in the long run.

 * The cwd is deleted
 * A parent directory is renamed
 * A parent directory is a symlink

s/parent/parent or current/g.  Also:

 * A parent or current directory is relocated entirely,
   not just renamed within the same parent
 * A parent or current directory has become unreadable
 * Any of the above happens _during_ the execution of cwd(),
   rather than beforehand

 [2]  The state of Cwd.pm's docs add to my anxiety.

Sucker punch.  :-)
-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-16 Thread Dave Whipp
Chip Salzenberg wrote:
As you know, under Unix, there's no such thing as the current
directory as a string.  The only durable current directory is the
device and inode of Cstat('.').  It's not wise to conflate the
current directory with a name that at some point in the past could
have been used to reach it.
So can we make a stronger statement, and say that Perl6 won't think of 
directories as strings, either. When you ask for a directory, it'll give 
you an object. If you use one in string context then it will try its 
best to give you a string that your OS might be able to use to access it 
(or, thinking about cygwin, a string that a different OS might be able 
to use...). But if it can't (e.g. when you access a directory relative 
to one whose name it doesn't know), then it will fail.

A directory object could have a method to tell you if it thinks its 
stringification is currently valid (i.e. if it can stat it and get the 
same device+inode). It could also have a method that attempts obtain a 
currently-valid name.

It'd also suggest that Copen et al should be methods on a directory 
object (default object for the global forms would be $*ENV.cwd)

And Csystem, Cexec, Cqx etc. shoul be methods on an environment 
object, again defaulting to $*ENV. I should be able to do

  my Env $env = $*ENV.clone;
  $env.cwd ~= /..;
  $env.system(foo);
$env.fork might be interesting, too -- I'd expect it to set $*ENV = $env 
in the child process. Which could be nice if an Env also has stdout, 
stdin, etc. methods.

You have to because when a new user asks how do I get the current
working directory? [...]
How do you get the cwd? You call $*ENV.cwd. How to you get its name? You 
use it in string context. (Of course, a new user probably won't think to 
ask that second question: they'll print it, and it'll do what they 
expect ... most of the time).


Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Larry Wall
On Fri, Apr 15, 2005 at 03:11:59AM -0700, Michael G Schwern wrote:
: Error handling is simple, a failed chdir returns undef and sets errno.
: 
:   $CWD = $dir err die Can't chdir to $dir: $!;

Offhand, I guess my main semantic problem with it is that if a chdir
fails, you aren't in an undefined location, which the new value of $CWD
would seem to indicate.  You're just where you were.  Then the user
either has to remember that, or there still has to be some other
means of finding out the real location.

The other problem with it is the fact that people will assign relative
paths to it and expect to get the relative path back out instead
of the absolute path.

: I encourage Perl 6 to adapt $*CWD similar to File::chdir and simply eliminate
: chdir() and cwd().  They're just an unlocalizable store and fetch for global
: data.

Your assumption there is a bit inaccurate--in P6 you are allowed to
temporize (localize) the effects of functions and methods that are
prepared to deal with it.  However, I agree that it's nice to have an
easily interpolatable value.  So I think I'd rather see $CWD always
return the current absolute path even after failure, and

temp chdir($dir) err fail Can't chdir to $dir: $!;

be made to work as a temporizable function at some point, via the TEMP
mechanism described in A4.

Larry


Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Michael G Schwern
Thus spake Larry Wall:
 Offhand, I guess my main semantic problem with it is that if a chdir
 fails, you aren't in an undefined location, which the new value of $CWD
 would seem to indicate.  You're just where you were.  Then the user
 either has to remember that, or there still has to be some other
 means of finding out the real location.

To be clear:  Only the store operation will return undef on failure.  
Additional fetches on $CWD will continue to return the cwd.

$CWD = '/path/which/exists';
$CWD = '/i/do/not/exist' err warn $!;
print $CWD;

This prints /path/which/exists/.


 The other problem with it is the fact that people will assign relative
 paths to it and expect to get the relative path back out instead
 of the absolute path.

I honestly never had this problem until I sat down and thought about it. :)
THEN I got all confused and started to do things like $CWD .= '/subdir';
instead of simply $CWD = 'subdir';.  But the rule is simple and natural.
It takes a relative or absolute directory and ALWAYS returns an absolute 
path.  Lax in what inputs it accepts, strict in what it emits.  This is no
more to remember than what chdir() and cwd() would do.

The result from $CWD would simply be a Dir object similar to Ken Williams' 
Path::Class or Ruby's Dir object.  One of the methods would be .relative.

I didn't bring up @CWD because I thought it would be too much in one sitting.
Basically it allows you to do this:

pop @CWD;   # chdir ('..');
push @CWD, 'dir';   # chdir ('dir');
print $CWD[0];  # (File::Spec-splitdir(abs_path()))[0];
# ie. What top level directory am I in?

and all sorts of other operations that would normally involve a lot of
splitdir'ing.

And then there's %CWD which I'm toying with being a per-volume chdir like
you can do on Windows but that may be too much of a questionable thing.


 Your assumption there is a bit inaccurate--in P6 you are allowed to
 temporize (localize) the effects of functions and methods that are
 prepared to deal with it.  

Yeah, we were talking about it on #perl6 a bit.  That seems to me the more
bizarre idea than assigning to something which can fail.  Localizing an
assignment is easy, there's just one thing to revert.  But function calls can
do lots of things.  Just how much does it reverse?  I guess if its used
sensibly on sharp functions, such as chdir, and the behavior is 
user-definable it can work but I don't know if the behavior will ever
be obvious for anything beyond the trivial.

FWIW my prompting to write File::chdir was a desire was for local chdir.
So if temp chdir can be made to work that would solve most of the problem.

If nothing else perhaps chdir() should be eliminated and cwd() simply takes
an argument to make it a getter/setter.


 However, I agree that it's nice to have an
 easily interpolatable value.  So I think I'd rather see $CWD always
 return the current absolute path even after failure

The problem there is it leaves $CWD without an error mechanism and thus
becomes an unverifiable operation.  You have to use chdir() if you want to
error check and $CWD is reduced to a scripting feature.

It could throw an exception but then you have to wrap everything in a try
block.  Unless Perl 6 is going this route for I/O errors in general I'd
rather not.

I'll give the error mechanism some more thought.


Anyhow, I encourage folks to play with File::chdir and see what they think
of the idea.  I'm fixing up the Windows nits in the tests now.



Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Juerd
Michael G Schwern skribis 2005-04-15 13:12 (-0700):
 To be clear:  Only the store operation will return undef on failure.  
 Additional fetches on $CWD will continue to return the cwd.

Still breaks

$ref = \($CWD = $foo);

I'm not sure this breakage matters, but if it breaks one thing, it's
likely to break more than just that one thing, and I wonder how much
attention this has been given.

Hm, but $CWD++ is nice! Especially if after photos9 it goes to photos10,
and not photot0. How does string ++ work in Perl 6, anyway?

 The problem there is it leaves $CWD without an error mechanism and thus
 becomes an unverifiable operation.  You have to use chdir() if you want to
 error check and $CWD is reduced to a scripting feature.

Well, after failure it can be cwd() but false without breaking any real
code, because normally, you'd never if (cwd) { ... }, simply because
there's ALWAYS a cwd. If this is done, the thing returned by the STORE
can still be an lvalue and thus be properly reffed.

This would mean you'd use or instead of err, but I don't understand the
point of err meaning error together with the introduction of
true-but-false values anyway. Low-prec // should imo just be spelled
dor. But it's too late for that, of course.


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html


Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Larry Wall
On Fri, Apr 15, 2005 at 01:12:46PM -0700, Michael G Schwern wrote:
: Thus spake Larry Wall:
:  Offhand, I guess my main semantic problem with it is that if a chdir
:  fails, you aren't in an undefined location, which the new value of $CWD
:  would seem to indicate.  You're just where you were.  Then the user
:  either has to remember that, or there still has to be some other
:  means of finding out the real location.
: 
: To be clear:  Only the store operation will return undef on failure.  

That doesn't square with the notion that an assignment returns the
actual lvalue:

($new = $old) =~ s/foo/bar/;

: Additional fetches on $CWD will continue to return the cwd.
: 
:   $CWD = '/path/which/exists';
:   $CWD = '/i/do/not/exist' err warn $!;
:   print $CWD;
: 
: This prints /path/which/exists/.

Except that the err should be looking at $CWD, not some other return value
of the assignment.

:  The other problem with it is the fact that people will assign relative
:  paths to it and expect to get the relative path back out instead
:  of the absolute path.
: 
: I honestly never had this problem until I sat down and thought about it. :)
: THEN I got all confused and started to do things like $CWD .= '/subdir';
: instead of simply $CWD = 'subdir';.  But the rule is simple and natural.
: It takes a relative or absolute directory and ALWAYS returns an absolute 
: path.  Lax in what inputs it accepts, strict in what it emits.  This is no
: more to remember than what chdir() and cwd() would do.
: 
: The result from $CWD would simply be a Dir object similar to Ken Williams' 
: Path::Class or Ruby's Dir object.  One of the methods would be .relative.
: 
: I didn't bring up @CWD because I thought it would be too much in one sitting.
: Basically it allows you to do this:
: 
:   pop @CWD;   # chdir ('..');
:   push @CWD, 'dir';   # chdir ('dir');
:   print $CWD[0];  # (File::Spec-splitdir(abs_path()))[0];
:   # ie. What top level directory am I in?
: 
: and all sorts of other operations that would normally involve a lot of
: splitdir'ing.
: 
: And then there's %CWD which I'm toying with being a per-volume chdir like
: you can do on Windows but that may be too much of a questionable thing.

You could multiplex both the array and hash roles into the object
returned by $CWD, much like the $/ pattern match result object can
be subscripted as either $/[1] or $/mantissa.  $CWD would itself
behave like a string in string context, but $CWD[] would get you to
the array value, and $CWD{} the hash value for systems that have
more than one current directory.

:  Your assumption there is a bit inaccurate--in P6 you are allowed to
:  temporize (localize) the effects of functions and methods that are
:  prepared to deal with it.  
: 
: Yeah, we were talking about it on #perl6 a bit.  That seems to me the more
: bizarre idea than assigning to something which can fail.  Localizing an
: assignment is easy, there's just one thing to revert.  But function calls can
: do lots of things.  Just how much does it reverse?  I guess if its used
: sensibly on sharp functions, such as chdir, and the behavior is 
: user-definable it can work but I don't know if the behavior will ever
: be obvious for anything beyond the trivial.

The function reverses whatever its TEMP property's closure knows how
to reverse.  It's up to the function to know what its side effects are
and arrange to undo them.

: FWIW my prompting to write File::chdir was a desire was for local chdir.
: So if temp chdir can be made to work that would solve most of the problem.
: 
: If nothing else perhaps chdir() should be eliminated and cwd() simply takes
: an argument to make it a getter/setter.

If you're going to throw away the verb then the noun might as well be
a variable.  But I like verbs for their readability, even if the verb
is push.  Note that push could be made to work with temp as well:

temp push $CWD, subdir err fail ...

This would automatically pop $CWD at the end of the dynamic scope.

:  However, I agree that it's nice to have an
:  easily interpolatable value.  So I think I'd rather see $CWD always
:  return the current absolute path even after failure
: 
: The problem there is it leaves $CWD without an error mechanism and thus
: becomes an unverifiable operation.  You have to use chdir() if you want to
: error check and $CWD is reduced to a scripting feature.

That was my point.  And if you look back at what you wrote, you just
called $CWD an operation.  It's not--it's a noun.  I like nouns,
but I also like verbs, and unlike in Perl 5 we don't have to rely on
the magical side effects of certain mystical nouns to do localization
any more.

But I don't understand what you mean by a scripting feature, or
how getting reduced to one is antithetical to a blissful existence.

: It could throw an exception but then you have to wrap everything in a try
: block.  Unless Perl 6 is going this 

Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread chromatic
On Fri, 2005-04-15 at 23:52 +0200, Juerd wrote:

 Well, after failure it can be cwd() but false without breaking any real
 code, because normally, you'd never if (cwd) { ... }, simply because
 there's ALWAYS a cwd.

Not always -- try removing a directory that's the pwd of another
process.

-- c



Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Michael G Schwern
On Fri, Apr 15, 2005 at 11:52:38PM +0200, Juerd wrote:
  becomes an unverifiable operation.  You have to use chdir() if you want to
  error check and $CWD is reduced to a scripting feature.
 
 Well, after failure it can be cwd() but false without breaking any real
 code, because normally, you'd never if (cwd) { ... }, simply because
 there's ALWAYS a cwd. If this is done, the thing returned by the STORE
 can still be an lvalue and thus be properly reffed.

Good idea!



Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Larry Wall
On Fri, Apr 15, 2005 at 03:22:48PM -0700, Michael G Schwern wrote:
: On Fri, Apr 15, 2005 at 11:52:38PM +0200, Juerd wrote:
:   becomes an unverifiable operation.  You have to use chdir() if you want to
:   error check and $CWD is reduced to a scripting feature.
:  
:  Well, after failure it can be cwd() but false without breaking any real
:  code, because normally, you'd never if (cwd) { ... }, simply because
:  there's ALWAYS a cwd. If this is done, the thing returned by the STORE
:  can still be an lvalue and thus be properly reffed.
: 
: Good idea!

But if cwd() or chdir() doesn't fail(), you probably won't get any
information on *why* the chdir failed in either the return value or $!.
That could be construed as antisocial.

In general I think but should be reserved for situations where the
original interface designer showed sufficient lack of imagination to
warrant such workarounds.  That is how I treated all the RFCs that
made use of but for built-in functionality, and I haven't seen any
good reasons to alter my views on that.  About the closest we get
to it is that interesting values of undef can be thought of as new
Exception(...) but undefined, or some such.  But even that is usually
hidden behind the fail() predicate, and the undef role is probably
composed into exceptions in the first place.  Or maybe it's the
other way around.

Larry


Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Chip Salzenberg
According to Michael G Schwern:
 And this is exactly what File::chdir does.  $CWD is a tied scalar.

I don't think current directory maps well on a variable.  That won't
stop people from using it, of course.  :-(

There are several methods to determine the current directory.  Each
one has its corner cases, strengths and weaknesses (thus the
proliferation of Cwd module functions), and it doesn't make any sense
to me to elevate one over the rest through the proposed $CWD.

mkdir '/tmp/foo';
$CWD = '/tmp/foo';
rename '../foo', '../bar';
say $CWD;  # Well?  Which is it?

-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: $*CWD instead of chdir() and cwd()

2005-04-15 Thread Chip Salzenberg
According to chromatic:
 On Fri, 2005-04-15 at 23:52 +0200, Juerd wrote:
  Well, after failure it can be cwd() but false without breaking any real
  code, because normally, you'd never if (cwd) { ... }, simply because
  there's ALWAYS a cwd.
 
 Not always -- try removing a directory that's the pwd of another
 process.

Oh, the _directory_ is still there.  :-)
-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Unify cwd() [was: Re: $*CWD instead of chdir() and cwd()]

2005-04-15 Thread Michael G Schwern
On Fri, Apr 15, 2005 at 08:31:57PM -0400, Chip Salzenberg wrote:
 According to Michael G Schwern:
  And this is exactly what File::chdir does.  $CWD is a tied scalar.
 
 I don't think current directory maps well on a variable.  That won't
 stop people from using it, of course.  :-(
 
 There are several methods to determine the current directory.  Each
 one has its corner cases, strengths and weaknesses (thus the
 proliferation of Cwd module functions), and it doesn't make any sense
 to me to elevate one over the rest through the proposed $CWD.

This is orthoginal to $CWD.  

Perl 6 is going to have to decide on some sort of standard internal getcwd 
technique, $CWD or not.  In the same way that we have open() not fopen, 
fdopen, freopen... we can choose the safest and most sensible technique for 
determining the cwd and use that.  You have to because when a new user asks 
how do I get the current working directory? you want to say cwd() and 
not Well, there are a variety of different techniques...  Cwd.pm is a 
perfect example of this problem.  Which one should a user use?  Most folks 
just won't care and the micro-differences between the functions in Cwd.pm
aren't worth the trouble.  

Present a sensible default.  Write a module with all the other options for 
those who need it.


   mkdir '/tmp/foo';
   $CWD = '/tmp/foo';
   rename '../foo', '../bar';
   say $CWD;  # Well?  Which is it?

Its exactly the same as...

mkdir '/tmp/foo';
chdir '/tmp/foo';
rename '../foo', '../bar';
say cwd();