Repository: mkdocs/mkdocs

Issue:
Ignore broken symlinks in mkdocs serve.
What I am experiencing:
- When I am editing `index.md` in Emacs, Emacs creates files like:

```
➜  docs git:(master) ✗ ls -al .#*  
lrwxrwxrwx 1 paulproteus paulproteus 36 Jun 17 17:24 .#index.md -> paulproteus@charkha.27783:1434311808
```
- These files are Emacs' way of using symlinks to track which computer+process was Emacs-ing the file, so that in case of a crash, Emacs can figure out how to restore its state.

What I expect:
- When I edit `somethingelse.md` and press save, I expect the mkdocs livereload to reload the browser.

What I see instead:

```
INFO    -  Building documentation... 
ERROR   -  file not found: /home/paulproteus/projects/sandstorm/docs/.#index.md 
ERROR   -  Error building page .#index.md 
[E 150617 17:22:21 ioloop:612] Exception in callback (3, <function null_wrapper at 0x7fc883190500>)
    Traceback (most recent call last):
      File "/home/paulproteus/.local/lib/python2.7/site-packages/tornado/ioloop.py", line 866, in start
        handler_func(fd_obj, events)
      File "/home/paulproteus/.local/lib/python2.7/site-packages/tornado/stack_context.py", line 275, in null_wrapper
        return fn(*args, **kwargs)
      File "/usr/lib/python2.7/dist-packages/pyinotify.py", line 1604, in handle_read
        self.process_events()
      File "/usr/lib/python2.7/dist-packages/pyinotify.py", line 1321, in process_events
        self._default_proc_fun(revent)
      File "/home/paulproteus/.local/lib/python2.7/site-packages/livereload/watcher.py", line 152, in inotify_event
        self.callback()
      File "/home/paulproteus/.local/lib/python2.7/site-packages/livereload/handlers.py", line 65, in poll_tasks
        filepath, delay = cls.watcher.examine()
      File "/home/paulproteus/.local/lib/python2.7/site-packages/livereload/watcher.py", line 72, in examine
        func and func()
      File "/usr/lib/python2.7/dist-packages/mkdocs/serve.py", line 74, in builder
        build(config, live_server=True)
      File "/usr/lib/python2.7/dist-packages/mkdocs/build.py", line 299, in build
        build_pages(config)
      File "/usr/lib/python2.7/dist-packages/mkdocs/build.py", line 259, in build_pages
        dump_json)
      File "/usr/lib/python2.7/dist-packages/mkdocs/build.py", line 171, in _build_page
        input_content = io.open(input_path, 'r', encoding='utf-8').read()
    IOError: [Errno 2] No such file or directory: '/home/paulproteus/projects/sandstorm/docs/.#index.md'
```

What I propose:
- If a "No such file or directory" error occurs, but the problem is a broken symlink, the `mkdocs` build should continue as if the file does not exist. Note that this arguably is a special-case to handle Emacs' own weirdness; a different way to do it would be to look at the list of git ignored files.
- Perhaps in general, `mkdocs` should issue a warning (not an error) on broken symlinks, gracefully ignoring them.

I'm open to a bunch of ideas. I wanted to file this in the hopes of sparking a discussion where the maintainers of mkdocs could express their opinion about the best way forward.

Thanks so much! Also hi! I'm twitter.com/asheeshlaroia and was chatting with a mkdocs developer earlier today. Seems like a great project! I learned about it via http://ericholscher.com/blog/2014/feb/27/how-i-judge-documentation-quality/ !



Discussion:
Interesting, I think we will want to add an extra check in the [file discovery](https://github.com/mkdocs/mkdocs/blob/master/mkdocs/config/config_options.py#L326-L336) to check is the file is a symlink and then check that the target is valid. If it isn't we can ignore it. We can probably do this with a combination of `os.path.islink` and `os.readlink`.

Thanks so much!​ This will make my mkdocs life easier.

Happy to help :)

First I'd like to point out that I like this project quite much and currently implement mkdocs for our internal repository.

Unfortunately I've stumbled on an issue caused by the way this bugfix handles symbolic links. It looks like symbolic links with relative path are not processed properly.

Sample tree (lets assume path `/srv/git/repo`:

```
docs
├── foobar.md -> foobar/README.md
├── foobaz.md -> ../cookbooks/foobaz/README.md
├── Test.md
├── index.md
└── foobaz
    ├── index.md
    └── README.md
```

Neither `docs/foobar.md` nor `docs/foobaz.md` will be built/served (assuming no pages listed in the config file). `walk_docs_dir` from `config/config_options.py` is having some issues with parsing the symlinks.

It looks like this happens because the CWD is different from `dirpath`. In my example it's dirpath: `/srv/git/repo` and cwd was `/srv/git/repo/docs`, which makes mkdocs ignore those 2 files despite they being valid symlinks.

Diff for `config/config_options.py`:

```
@@ -352,7 +349,8 @@
                 # Some editors (namely Emacs) will create temporary symlinks
                 # for internal magic. We can just ignore these files.
                 if os.path.islink(fullpath):
-                    if not os.path.exists(os.readlink(fullpath)):
+                    fp = os.path.join(dirpath, os.readlink(fullpath))
+                    if not os.path.exists(fp):
                         continue

                 relpath = os.path.normpath(os.path.relpath(fullpath, docs_dir))
```

This could be probably written a bit nicer so I'm just pasting the diff here.

PS. I'm using mkdocs installed via `pip` if that matters (ver `0.15.2`)

@ky4n this sounds like a legitimate issue with a reasonable solution. Unfortunately, you risk it getting forgotten as you commented on a closed issue. It would have been better to create a new issue which links to this one for context. Actually, as you have a provided fix, a pull request would be the quickest way to have the fix applied.


Resolving patch:
diff --git a/mkdocs/__init__.py b/mkdocs/__init__.py
--- a/mkdocs/__init__.py
+++ b/mkdocs/__init__.py
@@ -9,4 +9,4 @@
     sys.stderr.write(("WARNING: Support for Python 2.6 will be dropped in the "
                       "1.0.0 release of MkDocs\n\n"))
 
-__version__ = '0.15.2'
+__version__ = '0.15.3'
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -352,7 +352,8 @@ def walk_docs_dir(self, docs_dir):
                 # Some editors (namely Emacs) will create temporary symlinks
                 # for internal magic. We can just ignore these files.
                 if os.path.islink(fullpath):
-                    if not os.path.exists(os.readlink(fullpath)):
+                    fp = os.path.join(dirpath, os.readlink(fullpath))
+                    if not os.path.exists(fp):
                         continue
 
                 relpath = os.path.normpath(os.path.relpath(fullpath, docs_dir))


Test patch: