basho/rebar — pull request #192 by choptastic (2012-02-17 10:19:41+00:00)
Title: Fix copying dir to non-existing dir in Win32

Alrighty, I've restructured this to actually conform to the desired
commit guidelines. It's a continuation of the discussion here:

https://github.com/basho/rebar/pull/187

Anyway, here's a brief description of this error, and why it's needed:

I'm not sure all the differences between xcopy and cp -r. I'm just
making an effort to work within the constraints and fixing the errors
where they crop up.

The *primary* issue is the failure to copy the directory with the
current version of rebar using the reltool's generate.

The fix to check if a directory is not a file is merely an attempt to
be proactive for what would otherwise be a cryptic and non-helpful
error for a user who might have a misconfigured reltool.config.

On linux, with the current version of rebar, if you tried to copy a
directory onto a file, you get this somewhat cryptic message, but
useful because at least says the problem "cannot overwrite a
non-directory `path/to/dir` with a directory `path/to/file` ":

```erlang
ERROR: Unexpected error: {'EXIT',
{{badmatch,
{error,
{1,
"cp: cannot overwrite
non-directory `/home/gumm/www/nitrogen-temp/nitrogen/rel/nitrogen/Makefile'
with directory `/home/gumm/www/nitrogen-temp/nitrogen/rel/../deps/sync'\n"}}},
[{rebar_file_utils,cp_r,2,[]},
```
On windows, the error provides very minimal information. It's
something about no matching function clause.

This is because of how, at this line:
https://github.com/basho/rebar/blob/master/src/rebar_file_utils.erl#L156

It calls cp_r_win32, with the is_dir check, and that's how it chooses a path.

In each of the clauses, you have the following:

cp_r_win32({true,_},{true,_});
cp_r_win32({true,_},{false,_});
cp_r_win32({false,_},{false,_});

But there are two situations, currently, where this will generate the
one combination that's missing:
1) If you're trying to copy a directory onto a file (not so common)
2) If you're trying to copy a directory onto a non-existing directory,
expecting it to be created

either of those will attempt to call "cp_r_win32({false,_},{true,_})",
and throw the no matching clause error. My proposed error message is
the result of a check that *has* to happen anyway to copy the
directory, so we might as well be useful with the error message it
makes.

You *could* just use the results of filelib:ensure_dir and get
{error,eexists}, but frankly, I find my message more helpful.

In any case, if there's a better way to do it with xcopy, I don't know, but
this patch has solved my compilation problems and also provides a helpful
error message for folks.