lib/mnit: move mnit implementations as submodules
[nit.git] / src / loader.nit
index d3c9f7e..337ec61 100644 (file)
@@ -18,6 +18,7 @@
 module loader
 
 import modelbuilder_base
+import ini
 
 redef class ToolContext
        # Option --path
@@ -351,7 +352,7 @@ redef class ModelBuilder
                        mgroup = new MGroup(pn, mproject, null) # same name for the root group
                        mgroup.filepath = path
                        mproject.root = mgroup
-                       toolcontext.info("found project `{pn}` at {path}", 2)
+                       toolcontext.info("found singleton project `{pn}` at {path}", 2)
                end
 
                var res = new ModulePath(pn, path, mgroup)
@@ -387,42 +388,63 @@ redef class ModelBuilder
                        return mgroups[rdp]
                end
 
-               # Hack, a group is determined by one of the following:
-               # * the presence of a honomymous nit file
-               # * the fact that the directory is named `src`
-               # * the fact that there is a sub-directory named `src`
+               # Filter out non-directories
+               var stat = dirpath.file_stat
+               if stat == null or not stat.is_dir then
+                       mgroups[rdp] = null
+                       return null
+               end
+
+               # By default, the name of the project or group is the base_name of the directory
                var pn = rdp.basename(".nit")
-               var mp = dirpath.join_path(pn + ".nit").simplify_path
-
-               # dirpath2 is the root directory
-               # dirpath is the src subdirectory directory, if any, else it is the same that dirpath2
-               var dirpath2 = dirpath
-               if not mp.file_exists then
-                       if pn == "src" then
-                               # With a src directory, the group name is the name of the parent directory
-                               dirpath2 = rdp.dirname
-                               pn = dirpath2.basename
-                       else
-                               # Check a `src` subdirectory
-                               dirpath = dirpath2 / "src"
-                               if not dirpath.file_exists then
-                                       # All rules failed, so return null
+
+               # Check `project.ini` that indicate a project
+               var ini = null
+               var parent = null
+               var inipath = dirpath / "project.ini"
+               if inipath.file_exists then
+                       ini = new ConfigTree(inipath)
+               end
+
+               if ini == null then
+                       # No ini, multiple course of action
+
+                       # The root of the directory hierarchy in the file system.
+                       if rdp == "/" then
+                               mgroups[rdp] = null
+                               return null
+                       end
+
+                       # Special stopper `projects.ini`
+                       if (dirpath/"projects.ini").file_exists then
+                               # dirpath cannot be a project since it is a project directory
+                               mgroups[rdp] = null
+                               return null
+                       end
+
+                       # check the parent directory (if it does not contain the stopper file)
+                       var parentpath = dirpath.join_path("..").simplify_path
+                       var stopper = parentpath / "projects.ini"
+                       if not stopper.file_exists then
+                               # Recursively get the parent group
+                               parent = get_mgroup(parentpath)
+                               if parent == null then
+                                       # Parent is not a group, thus we are not a group either
+                                       mgroups[rdp] = null
                                        return null
                                end
                        end
                end
 
-               # check parent directory
-               var parentpath = dirpath2.join_path("..").simplify_path
-               var parent = get_mgroup(parentpath)
-
                var mgroup
                if parent == null then
                        # no parent, thus new project
+                       if ini != null and ini.has_key("name") then pn = ini["name"]
                        var mproject = new MProject(pn, model)
                        mgroup = new MGroup(pn, mproject, null) # same name for the root group
                        mproject.root = mgroup
                        toolcontext.info("found project `{mproject}` at {dirpath}", 2)
+                       mproject.ini = ini
                else
                        mgroup = new MGroup(pn, parent.mproject, parent)
                        toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
@@ -432,8 +454,6 @@ redef class ModelBuilder
                # in src first so the documentation of the project code can be distinct for the documentation of the project usage
                var readme = dirpath.join_path("README.md")
                if not readme.file_exists then readme = dirpath.join_path("README")
-               if not readme.file_exists then readme = dirpath2.join_path("README.md")
-               if not readme.file_exists then readme = dirpath2.join_path("README")
                if readme.file_exists then
                        var mdoc = load_markdown(readme)
                        mgroup.mdoc = mdoc
@@ -441,8 +461,7 @@ redef class ModelBuilder
                end
 
                mgroup.filepath = dirpath
-               mgroups[module_absolute_path(dirpath)] = mgroup
-               mgroups[module_absolute_path(dirpath2)] = mgroup
+               mgroups[rdp] = mgroup
                return mgroup
        end
 
@@ -737,7 +756,7 @@ redef class ModelBuilder
                        mmodule.set_visibility_for(sup, mvisibility)
                end
                if stdimport then
-                       var mod_name = "standard"
+                       var mod_name = "core"
                        var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
                        if sup == null then
                                nmodule.mmodule = null # invalidate the module
@@ -796,9 +815,9 @@ redef class ModelBuilder
 
                self.toolcontext.info("{mmodule} imports {mmodule.in_importation.direct_greaters.join(", ")}", 3)
 
-               # Force standard to be public if imported
+               # Force `core` to be public if imported
                for sup in mmodule.in_importation.greaters do
-                       if sup.name == "standard" then
+                       if sup.name == "core" then
                                mmodule.set_visibility_for(sup, public_visibility)
                        end
                end
@@ -918,6 +937,15 @@ class ModulePath
        redef fun to_s do return filepath
 end
 
+redef class MProject
+       # The associated `.ini` file, if any
+       #
+       # The `ini` file is given as is and might contain invalid or missing information.
+       #
+       # Some projects, like stand-alone projects or virtual projects have no `ini` file associated.
+       var ini: nullable ConfigTree = null
+end
+
 redef class MGroup
        # Modules paths associated with the group
        var module_paths = new Array[ModulePath]