Repository: mesonbuild/meson

Issue:
Wrong error message when using meson incorrectly: faulty use of "wrap-mode=" versus "--wrap-mode="
So I was using this commandline invocation:

    meson --prefix=/home/Programs/Pangomm/2.50.0/ --libdir=/home/Programs/Pangomm/2.50.0/lib wrap-mode=nodownload BUILD_DIRECTORY/ 2>&1

For those who do not see the error: "wrap-mode=nodownload" should instead be "--wrap-mode=nodownload".

Now here is the interesting thing:

meson showed this error message:

    ERROR: Neither directory contains a build file meson.build.
    WARNING: Running the setup command as `meson [options]` instead of `meson setup [options]` is ambiguous and deprecated.


However had, in the base directory "meson.build" exists.

Furthermore I believe the term "neither directory" is not good because I ask myself WHICH directory? What does
meson mean with "neither"? It is not specified. It could be any directory. I highly recommend to include
WHICH directory meson refers to, rather than leaving the user guessing with mystic psy-powers to mind
read what meson means with "neither". But this is besides the point.

The message "no meson.build" file, implied by the above, was incorrect, as I did:

    stat meson.build

So the file DOES exist.

And now here is the interesting part.

I will now use another commandline invocation of meson:

    meson --prefix=/home/Programs/Pangomm/2.50.0/ --libdir=/home/Programs/Pangomm/2.50.0/lib --wrap-mode=nodownload BUILD_DIRECTORY/ 2>&1

This time it proceeded (and ended with another, unrelated error of a missing package).

So, I was using meson incorrectly, BUT the message displayed by meson is incorrect as well. The faulty
part was a missing "--" part before wrap. (I store these options in a local file from where they are 
fetched automatically, and I simply forgot the -- as I am a bit used to being able to omit them due
to how I store them. This came from my time with GNU configure where I got tired of pre-fixing all
options via -- so I wanted to be lazy).

My recommendation is to first check whether the command, such as wrap-mode, is correct or not,
rather than assume it must be correct, then continue, and report a very confusing message to the
user. Now that I am aware of the problem I can work around it just fine, or add code to my own
scripts to work around this if I want to be lazy and omit the "--" in a local file - but I am reporting
this here too because I think the behaviour, or, at the least the REPORTING done by meson is
currently not correct in this regard. Either way thank you for reading, this is just meant as reporting -
you guys can of course proceed how you want to in this regard.


Discussion:

Resolving patch:
diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py
--- a/mesonbuild/msetup.py
+++ b/mesonbuild/msetup.py
@@ -15,7 +15,7 @@
 
 import typing as T
 import time
-import sys, stat
+import sys
 import datetime
 import os.path
 import platform
@@ -118,6 +118,7 @@ def has_build_file(self, dirname: str) -> bool:
         return os.path.exists(fname)
 
     def validate_core_dirs(self, dir1: str, dir2: str) -> T.Tuple[str, str]:
+        invalid_msg_prefix = f'Neither source directory {dir1!r} nor build directory {dir2!r}'
         if dir1 is None:
             if dir2 is None:
                 if not os.path.exists('meson.build') and os.path.exists('../meson.build'):
@@ -129,14 +130,16 @@ def validate_core_dirs(self, dir1: str, dir2: str) -> T.Tuple[str, str]:
             dir2 = os.getcwd()
         ndir1 = os.path.abspath(os.path.realpath(dir1))
         ndir2 = os.path.abspath(os.path.realpath(dir2))
-        if not os.path.exists(ndir1):
-            os.makedirs(ndir1)
-        if not os.path.exists(ndir2):
-            os.makedirs(ndir2)
-        if not stat.S_ISDIR(os.stat(ndir1).st_mode):
-            raise MesonException(f'{dir1} is not a directory')
-        if not stat.S_ISDIR(os.stat(ndir2).st_mode):
-            raise MesonException(f'{dir2} is not a directory')
+        if not os.path.exists(ndir1) and not os.path.exists(ndir2):
+            raise MesonException(f'{invalid_msg_prefix} exist.')
+        try:
+            os.makedirs(ndir1, exist_ok=True)
+        except FileExistsError as e:
+            raise MesonException(f'{dir1} is not a directory') from e
+        try:
+            os.makedirs(ndir2, exist_ok=True)
+        except FileExistsError as e:
+            raise MesonException(f'{dir2} is not a directory') from e
         if os.path.samefile(ndir1, ndir2):
             # Fallback to textual compare if undefined entries found
             has_undefined = any((s.st_ino == 0 and s.st_dev == 0) for s in (os.stat(ndir1), os.stat(ndir2)))
@@ -148,7 +151,7 @@ def validate_core_dirs(self, dir1: str, dir2: str) -> T.Tuple[str, str]:
             return ndir1, ndir2
         if self.has_build_file(ndir2):
             return ndir2, ndir1
-        raise MesonException(f'Neither directory contains a build file {environment.build_filename}.')
+        raise MesonException(f'{invalid_msg_prefix} contain a build file {environment.build_filename}.')
 
     def add_vcs_ignore_files(self, build_dir: str) -> None:
         if os.listdir(build_dir):


Test patch: