Repository: mkdocs/mkdocs

Issue:
Advice: Do not set site_dir to /
Just a warning to anyone who might want to change their project build directory to the root of the project, with a .yml file like this:

```yaml
site_name: My Docs
site_dir: /
pages:
  - Home: index.md
theme: material
```

It won't do what you think it will. If you run ```mkdocs build --clean``` you will have it recursively delete everything it can from your system root folder until it runs into a file it can't delete without sudo. You will lose the entire contents of your home folder as well as your Ubuntu profile, and do unknown damage to your system.

Time to reformat. :D

Discussion:

Patch:
diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md
index ea3550fc..7a96769c 100644
--- a/docs/about/release-notes.md
+++ b/docs/about/release-notes.md
@@ -21,6 +21,14 @@ The current and past members of the MkDocs team.
 * [@d0ugal](https://github.com/d0ugal/)
 * [@waylan](https://github.com/waylan/)
 
+## Version 0.16.2 (2017-03-??)
+
+* System root (`/`) is not a valid path for site_dir or docs_dir (#1161)
+* Refactor readthedocs theme navigation (#1155 & #1156)
+* Add support to dev server to serve custom error pages (#1040)
+* Ensure nav.homepage.url is not blank on error pages (#1131)
+* Increase livereload dependency to 2.5.1 (#1106)
+
 ## Version 0.16.1 (2016-12-22)
 
 * Ensure scrollspy behavior does not affect nav bar (#1094)
diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md
index 76652fe0..40f45196 100644
--- a/docs/user-guide/configuration.md
+++ b/docs/user-guide/configuration.md
@@ -181,8 +181,8 @@ up.
 
 Lets you set the directory containing the documentation source markdown files.
 This can either be a relative directory, in which case it is resolved relative
-to the directory containing you configuration file, or it can be an absolute
-directory path.
+to the directory containing your configuration file, or it can be an absolute
+directory path from the root of your local file system.
 
 **default**: `'docs'`
 
@@ -190,8 +190,8 @@ directory path.
 
 Lets you set the directory where the output HTML and other files are created.
 This can either be a relative directory, in which case it is resolved relative
-to the directory containing you configuration file, or it can be an absolute
-directory path.
+to the directory containing your configuration file, or it can be an absolute
+directory path from the root of your local file system.
 
 **default**: `'site'`
 
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
index 7fa3ac6f..d5e656fd 100644
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -253,14 +253,14 @@ class SiteDir(Dir):
         # Validate that the docs_dir and site_dir don't contain the
         # other as this will lead to copying back and forth on each
         # and eventually make a deep nested mess.
-        if (config['docs_dir'] + os.sep).startswith(config['site_dir'] + os.sep):
+        if (config['docs_dir'] + os.sep).startswith(config['site_dir'].rstrip(os.sep) + os.sep):
             raise ValidationError(
                 ("The 'docs_dir' should not be within the 'site_dir' as this "
                  "can mean the source files are overwritten by the output or "
                  "it will be deleted if --clean is passed to mkdocs build."
                  "(site_dir: '{0}', docs_dir: '{1}')"
                  ).format(config['site_dir'], config['docs_dir']))
-        elif (config['site_dir'] + os.sep).startswith(config['docs_dir'] + os.sep):
+        elif (config['site_dir'] + os.sep).startswith(config['docs_dir'].rstrip(os.sep) + os.sep):
             raise ValidationError(
                 ("The 'site_dir' should not be within the 'docs_dir' as this "
                  "leads to the build directory being copied into itself and "


Test patch:
diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py
index 284dbdc6..041dd21b 100644
--- a/mkdocs/tests/config/config_options_tests.py
+++ b/mkdocs/tests/config/config_options_tests.py
@@ -203,11 +203,21 @@ class DirTest(unittest.TestCase):
 
 class SiteDirTest(unittest.TestCase):
 
+    def validate_config(self, config):
+        """ Given a config with values for site_dir and doc_dir, run site_dir post_validation. """
+        site_dir = config_options.SiteDir()
+        docs_dir = config_options.Dir()
+
+        config['config_file_path'] = os.path.join(os.path.abspath('..'), 'mkdocs.yml')
+
+        config['docs_dir'] = docs_dir.validate(config['docs_dir'])
+        config['site_dir'] = site_dir.validate(config['site_dir'])
+        site_dir.post_validation(config, 'site_dir')
+        return True  # No errors were raised
+
     def test_doc_dir_in_site_dir(self):
 
         j = os.path.join
-        option = config_options.SiteDir()
-        docs_dir = config_options.Dir()
         # The parent dir is not the same on every system, so use the actual dir name
         parent_dir = mkdocs.__file__.split(os.sep)[-3]
 
@@ -218,16 +228,12 @@ class SiteDirTest(unittest.TestCase):
             {'docs_dir': 'docs', 'site_dir': ''},
             {'docs_dir': '', 'site_dir': ''},
             {'docs_dir': j('..', parent_dir, 'docs'), 'site_dir': 'docs'},
+            {'docs_dir': 'docs', 'site_dir': '/'}
         )
 
         for test_config in test_configs:
-            test_config['config_file_path'] = j(os.path.abspath('..'), 'mkdocs.yml')
-
-            test_config['docs_dir'] = docs_dir.validate(test_config['docs_dir'])
-            test_config['site_dir'] = option.validate(test_config['site_dir'])
-
             self.assertRaises(config_options.ValidationError,
-                              option.post_validation, test_config, 'site_dir')
+                              self.validate_config, test_config)
 
     def test_site_dir_in_docs_dir(self):
 
@@ -237,19 +243,23 @@ class SiteDirTest(unittest.TestCase):
             {'docs_dir': 'docs', 'site_dir': j('docs', 'site')},
             {'docs_dir': '.', 'site_dir': 'site'},
             {'docs_dir': '', 'site_dir': 'site'},
+            {'docs_dir': '/', 'site_dir': 'site'},
         )
 
         for test_config in test_configs:
-            test_config['config_file_path'] = j(os.path.abspath('..'), 'mkdocs.yml')
+            self.assertRaises(config_options.ValidationError,
+                              self.validate_config, test_config)
 
-            docs_dir = config_options.Dir()
-            option = config_options.SiteDir()
+    def test_common_prefix(self):
+        """ Legitimate settings with common prefixes should not fail validation. """
 
-            test_config['docs_dir'] = docs_dir.validate(test_config['docs_dir'])
-            test_config['site_dir'] = option.validate(test_config['site_dir'])
+        test_configs = (
+            {'docs_dir': 'docs', 'site_dir': 'docs-site'},
+            {'docs_dir': 'site-docs', 'site_dir': 'site'},
+        )
 
-            self.assertRaises(config_options.ValidationError,
-                              option.post_validation, test_config, 'site_dir')
+        for test_config in test_configs:
+            assert self.validate_config(test_config)
 
 
 class ThemeTest(unittest.TestCase):