2
2
3
3
4
4
import pygit2
5
+ import functools
5
6
6
7
from datetime import datetime
7
8
from pathlib import Path
11
12
class BaseResource :
12
13
''' base class for all resources '''
13
14
14
- def __init__ (self , name , parent , tree_entry , request ):
15
- self .__name__ = name
15
+ def __init__ (self , tree_entry , parent ):
16
+ self .__name__ = tree_entry . name
16
17
self .__parent__ = parent
17
18
self .pygit2_tree_entry = tree_entry
18
- self .request = request
19
- self ._pygit2_object = None
20
- self ._last_commit = None
19
+ self .request = parent .request
21
20
22
21
@property
22
+ @functools .lru_cache (maxsize = 128 )
23
23
def pygit2_object (self ):
24
24
''' lazy loading of the pygit2 object '''
25
- if self ._pygit2_object is None :
26
- oid = self .pygit2_tree_entry .oid
27
- self ._pygit2_object = self .request .repository [oid ]
28
- return self ._pygit2_object
25
+ oid = self .pygit2_tree_entry .oid
26
+ return self .request .repository [oid ]
29
27
30
28
@property
31
29
def type (self ):
32
30
''' returns the type of the resource, either 'tree' or 'blob' '''
33
- if self .__name__ is None :
34
- # Root has no name, but is a Folder
35
- return 'tree'
36
- return self .pygit2_tree_entry .type
31
+ # Root has no tree entry, but is a Folder
32
+ return 'tree' if self .__name__ is None else self .pygit2_tree_entry .type
37
33
38
34
@property
35
+ @functools .lru_cache (maxsize = 128 )
39
36
def last_commit (self ):
40
37
''' get the last commit of the resource
41
38
42
39
from https://stackoverflow.com/questions/13293052/pygit2-blob-history
43
- '''
44
- if self ._last_commit :
45
- return self ._last_commit
46
-
40
+ '''
47
41
# loops through all the commits
48
42
last_oid = None
43
+ last_commit = None
49
44
repo = self .request .repository
50
45
for commit in repo .walk (repo .head .target , pygit2 .GIT_SORT_TIME ):
51
46
@@ -56,14 +51,14 @@ def last_commit(self):
56
51
oid = self .pygit2_tree_entry .oid
57
52
has_changed = (oid != last_oid and last_oid )
58
53
if has_changed :
59
- return self . _last_commit
54
+ return last_commit
60
55
last_oid = oid
61
56
else :
62
57
last_oid = None
63
58
64
- self . _last_commit = commit
59
+ last_commit = commit
65
60
66
- return self . _last_commit
61
+ return last_commit
67
62
68
63
@property
69
64
def author (self ):
@@ -77,41 +72,39 @@ def date(self):
77
72
class Folder (BaseResource ):
78
73
''' Resource representing a git tree (like a folder in a file system) '''
79
74
75
+ @property
76
+ @functools .lru_cache (maxsize = 128 )
77
+ def index (self ):
78
+ ''' get the markup index file of the folder or None '''
79
+ blobs = (e for e in self .pygit2_object if e .type == 'blob' )
80
+ index_files = (e for e in blobs if e .name .lower ().startswith ('index.' ))
81
+ for entry in index_files :
82
+ renderer = self .request .get_markup_renderer (entry .name )
83
+ if renderer :
84
+ return Markup (entry , self , renderer )
85
+ return None
86
+
80
87
def __getitem__ (self , key ):
81
88
''' Dict like access to child resources '''
82
89
83
90
# hidden files (starting with a dot) are forbidden to access
84
91
if key .startswith ('.' ):
85
92
raise KeyError
86
93
87
- # try to directly access a tree entry,
88
- # only blob (binary file) and trees (folders) are allowed
89
- try :
90
- tree_entry = self .pygit2_object [key ]
91
- if tree_entry .type == 'blob' :
92
- return File (key , self , tree_entry , self .request )
93
- elif tree_entry .type == 'tree' :
94
- return Folder (key , self , tree_entry , self .request )
95
- except KeyError :
96
- pass
94
+ tree_entry = self .pygit2_object [key ]
95
+ if tree_entry .type == 'tree' :
96
+ return Folder (tree_entry , self )
97
+
98
+ if tree_entry .type != 'blob' :
99
+ # non file entry, might be a git note object
100
+ # or something else
101
+ raise KeyError
97
102
98
- # look for a text-file, that should be rendered
99
- markdown = self ._search_markdown_file (key )
100
- if markdown :
101
- return markdown
102
-
103
- # nothing found, raise Error
104
- raise KeyError
105
-
106
- def _search_markdown_file (self , name ):
107
- ''' look for a markdown file '''
108
- markdown_file = name + self .request .markdown_extension
109
- blobs = (e for e in self .pygit2_object if e .type == 'blob' )
110
- for entry in blobs :
111
- if entry .name .lower () == markdown_file .lower ():
112
- return Markdown (name , self , entry , self .request )
113
- return None
114
-
103
+ renderer = self .request .get_markup_renderer (key )
104
+ if renderer is None :
105
+ return File (tree_entry , self )
106
+ else :
107
+ return Markup (tree_entry , self , renderer )
115
108
116
109
def __iter__ (self ):
117
110
''' iterate over renderable child resources '''
@@ -121,30 +114,38 @@ def __iter__(self):
121
114
# first list the folders
122
115
trees = (e for e in ordered if e .type == 'tree' )
123
116
for entry in trees :
124
- yield Folder (entry .name , self , entry , self .request )
125
- # then list the markdown files
126
- md_ext = self .request .markdown_extension
117
+ yield Folder (entry , self )
118
+ # then list the markup files
127
119
blobs = (e for e in ordered if e .type == 'blob' )
128
- texts = (e for e in blobs if e .name .endswith (md_ext ))
129
- for entry in texts :
130
- name = entry .name [:- len (md_ext )]
131
- if name != 'index' :
132
- yield Markdown (name , self , entry , self .request )
133
-
134
- @property
135
- def index (self ):
136
- ''' get the markdown index file of the folder or None '''
137
- return self ._search_markdown_file ('index' )
120
+ # except the index file used
121
+ index_name = self .index .__name__ if self .index else None
122
+ non_index = (e for e in blobs if e .name != index_name )
123
+ for entry in non_index :
124
+ renderer = self .request .get_markup_renderer (entry .name )
125
+ if renderer :
126
+ yield Markup (entry , self , renderer )
138
127
139
128
140
129
class Root (Folder ):
141
130
''' the root resource for traversal '''
142
131
143
132
def __init__ (self , request ):
144
- super ().__init__ (None , None , None , request )
145
- head = request .repository .head
146
- self ._last_commit = head .peel ()
147
- self ._pygit2_object = self ._last_commit .tree
133
+ self .__name__ = None
134
+ self .__parent__ = None
135
+ self .request = request
136
+
137
+ @property
138
+ def pygit2_object (self ):
139
+ ''' lazy loading of the pygit2 object not required on root resource'''
140
+ return self .last_commit .tree
141
+
142
+ @property
143
+ def last_commit (self ):
144
+ ''' get the last commit of the resource
145
+
146
+ On the root resource, this is only a simple lookup
147
+ '''
148
+ return self .request .repository .head .peel ()
148
149
149
150
150
151
class File (BaseResource ):
@@ -161,13 +162,21 @@ def size(self):
161
162
return self .pygit2_object .size
162
163
163
164
164
- class Markdown (BaseResource ):
165
- ''' Resource for a Markdown file that could be rendered '''
165
+ class Markup (BaseResource ):
166
+ ''' Resource for a markup file that could be rendered '''
167
+
168
+ def __init__ (self , tree_entry , parent , rendering_func ):
169
+ super ().__init__ (tree_entry , parent )
170
+ self .renderer = rendering_func
166
171
167
172
@property
168
173
def text (self ):
169
174
''' access the text content of the file '''
170
175
return self .pygit2_object .data .decode ('utf-8' )
176
+
177
+ def render (self ):
178
+ ''' returned the rendered representation of the markup file'''
179
+ return self .renderer (self .text )
171
180
172
181
173
182
@@ -191,16 +200,5 @@ def includeme(config):
191
200
reify = True
192
201
)
193
202
194
- markdown_extension = settings .get ('pyragit.markdown_extension' , None )
195
- if markdown_extension is None :
196
- raise ConfigurationError ('Markdown Extension not set' )
197
-
198
- # make request.markdown_extension available for use in Pyramid
199
- config .add_request_method (
200
- lambda r : markdown_extension ,
201
- 'markdown_extension' ,
202
- reify = True
203
- )
204
-
205
203
# set the root factory for traverssal
206
204
config .set_root_factory (Root )
0 commit comments