26
26
27
27
# For more information, please refer to <http://unlicense.org>
28
28
29
- """Check for broken links."""
29
+ """Check for broken links.
30
+
31
+ This finds links like this...
32
+
33
+ [click here](some-file.md)
34
+ [or here](../some/path/another-file.md)
35
+ 
36
+
37
+ ...but not like this:
38
+
39
+ [some website](http://github.com/)
40
+ [another website](https://github.com/)
41
+ [local header](#some-header)
42
+ """
30
43
31
44
# The markdown files use posix-style paths, so we need posixpath for
32
45
# processing them. See help('posixpath').
38
51
import common
39
52
40
53
41
- Link = collections . namedtuple ( ' Link' , 'text target markdown lineno file' )
54
+ class Link :
42
55
56
+ def __init__ (self , regexmatch , filepath , lineno ):
57
+ # The .group(0) is not perfect, but it's good enough.
58
+ self .markdown = regexmatch .group (0 )
59
+ self .text = regexmatch .group (1 )
60
+ self .target = regexmatch .group (2 )
61
+ self .filepath = filepath
62
+ self .lineno = lineno
63
+ self .status = None
43
64
44
- def check_link (link ):
45
- """Check if the link's target exists.
46
-
47
- Return an error message string or "ok".
48
- """
49
- if link .target .startswith (('http://' , 'https://' )):
50
- # Checking for http(s) links can be added later, but currently
51
- # it's not needed.
52
- return "ok"
53
- path = posixpath .join (posixpath .dirname (link .file ), link .target )
54
- realpath = path .replace ('/' , os .sep )
55
- if not os .path .exists (realpath ):
56
- return "doesn't exist"
57
- if path .endswith ('/' ):
58
- # A directory.
59
- if os .path .isdir (realpath ):
60
- return "ok"
61
- return "not a directory"
62
- else :
63
- # A file.
64
- if os .path .isfile (realpath ):
65
+ def _get_status (self ):
66
+ if self .target .startswith (('http://' , 'https://' )):
67
+ # Checking for http(s) links can be added later, but
68
+ # currently it's not needed.
65
69
return "ok"
66
- return "not a file"
70
+
71
+ target = self .target
72
+ if '#' in target :
73
+ where = target .index ('#' )
74
+ if where == 0 :
75
+ # It's a link to a title in the same file, we need to
76
+ # skip it.
77
+ return "ok"
78
+ target = target [:where ]
79
+
80
+ path = posixpath .join (posixpath .dirname (self .filepath ), target )
81
+ realpath = path .replace ('/' , os .sep )
82
+
83
+ if not os .path .exists (realpath ):
84
+ return "doesn't exist"
85
+ if target .endswith ('/' ):
86
+ # A directory.
87
+ if os .path .isdir (directory ):
88
+ return "ok"
89
+ return "not a directory"
90
+ else :
91
+ # A file.
92
+ if os .path .isfile (realpath ):
93
+ return "ok"
94
+ return "not a file"
95
+
96
+ def check (self ):
97
+ """Check if the link's target is like it should be.
98
+
99
+ Return an error message string or "ok". The return value is also
100
+ assigned to the status attribute.
101
+ """
102
+ self .status = self ._get_status ()
103
+ return self .status
104
+
105
+ def print_status (self ):
106
+ print (" file {0.filepath}, line {0.lineno}: {0.status}" .format (self ))
107
+ print (" " + self .markdown )
108
+ print ()
67
109
68
110
69
111
def main ():
@@ -72,35 +114,22 @@ def main():
72
114
for path in common .get_markdown_files ():
73
115
with open (path .replace ('/' , os .sep ), 'r' ) as f :
74
116
for match , lineno in common .find_links (f ):
75
- target = match .group (2 )
76
- if '#' in target :
77
- where = target .index ('#' )
78
- target = target [:where ]
79
- link = Link (
80
- text = match .group (1 ),
81
- target = target ,
82
- markdown = match .group (0 ),
83
- lineno = lineno ,
84
- file = path )
85
- links .append (link )
117
+ links .append (Link (match , path , lineno ))
118
+ print (" found" , len (links ), "links" )
86
119
87
120
print ("Checking for broken links..." )
88
- broken = [] # [(Link, check result), ...]
121
+ brokens = 0
89
122
for link in links :
90
- result = check_link (link )
91
- if result != "ok" :
92
- broken .append ((link , result ))
93
-
94
- if broken :
95
- print ("\n *** %d/%d links seem to be broken! ***\n "
96
- % (len (broken ), len (links )))
97
- for link , error in broken :
98
- print (" file {0.file}, line {0.lineno}: {1}"
99
- .format (link , error ))
100
- print (" " , link .markdown .replace ('\n ' , ' ' ))
101
- print ()
123
+ if link .check () != "ok" :
124
+ link .print_status ()
125
+ brokens += 1
126
+
127
+ if brokens == 0 :
128
+ print ("All links seem to be OK." )
129
+ elif brokens == 1 :
130
+ print ("1 link is broken!" )
102
131
else :
103
- print ("All" , len ( links ), "links seem to be OK. " )
132
+ print (brokens , "links are broken! " )
104
133
105
134
106
135
if __name__ == '__main__' :
0 commit comments