forked from Akuli/python-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinkcheck.py
executable file
·103 lines (82 loc) · 3.28 KB
/
linkcheck.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env python3
# This is free and unencumbered software released into the public
# domain.
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a
# compiled binary, for any purpose, commercial or non-commercial, and
# by any means.
# In jurisdictions that recognize copyright laws, the author or
# authors of this software dedicate any and all copyright interest in
# the software to the public domain. We make this dedication for the
# benefit of the public at large and to the detriment of our heirs
# and successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to
# this software under copyright law.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# For more information, please refer to <http://unlicense.org>
"""Check for broken links.
This finds links like this...
[click here](some-file.md)
[or here](../some/path/another-file.md)
![here's an image](../images/some-cool-image.png)
...but not like this:
[some website](http://github.com/)
[another website](https://github.com/)
[local header](#some-header)
"""
import os
import posixpath
import common
def check(filepath, target):
"""Check if a link's target is like it should be.
Return an error message string or "ok".
"""
if target.startswith(('http://', 'https://')):
# We don't need this currently, but checking these links could
# be added later.
return "ok"
if '#' in target:
where = target.index('#')
if where == 0:
# It's a link to a title in the same file, we need to skip it.
return "ok"
target = target[:where]
path = posixpath.join(posixpath.dirname(filepath), target)
realpath = common.slashfix(path)
if not os.path.exists(realpath):
return "doesn't exist"
if target.endswith('/'):
# A directory.
if os.path.isdir(realpath):
return "ok"
return "not a directory"
else:
# A file.
if os.path.isfile(realpath):
return "ok"
return "not a file"
def main():
print("Searching and checking links...")
broken = 0
total = 0
for path in common.get_markdown_files():
with common.slashfix_open(path, 'r') as f:
for match, lineno in common.find_links(f):
text, target = match.groups()
status = check(path, target)
if status != "ok":
# The .group(0) is not perfect, but it's good enough.
print(" file %s, line %d: %s" % (path, lineno, status))
print(" " + match.group(0))
print()
broken += 1
total += 1
print("%d/%d links seem to be broken." % (broken, total))
if __name__ == '__main__':
main()