11import requests , html , re , os , random
22import xml .etree .ElementTree as ET
3- from cfengine import PromiseModule , ValidationError , Result
3+ from cfengine_module_library import PromiseModule , ValidationError , Result
44
55
66class RssPromiseTypeModule (PromiseModule ):
77 def __init__ (self ):
88 super ().__init__ ("rss_promise_module" , "0.0.3" )
99
10-
1110 def validate_promise (self , promiser , attributes , metadata ):
1211 # check promiser type
1312 if type (promiser ) is not str :
1413 raise ValidationError ("invalid type for promiser: expected string" )
1514
1615 # check that promiser is a valid file path
1716 if not self ._is_unix_file (promiser ) and not self ._is_win_file (promiser ):
18- raise ValidationError (f"invalid value '{ promiser } ' for promiser: must be a filepath" )
17+ raise ValidationError (
18+ f"invalid value '{ promiser } ' for promiser: must be a filepath"
19+ )
1920
2021 # check that required attribute feed is present
2122 if "feed" not in attributes :
2223 raise ValidationError ("Missing required attribute feed" )
2324
2425 # check that attribute feed has a valid type
25- feed = attributes [' feed' ]
26+ feed = attributes [" feed" ]
2627 if type (feed ) is not str :
2728 raise ValidationError ("Invalid type for attribute feed: expected string" )
2829
2930 # check that attribute feed is a valid file path or url
30- if not (self ._is_unix_file (feed ) or self ._is_win_file (feed ) or self ._is_url (feed )):
31- raise ValidationError (f"Invalid value '{ feed } ' for attribute feed: must be a file path or url" )
31+ if not (
32+ self ._is_unix_file (feed ) or self ._is_win_file (feed ) or self ._is_url (feed )
33+ ):
34+ raise ValidationError (
35+ f"Invalid value '{ feed } ' for attribute feed: must be a file path or url"
36+ )
3237
3338 # additional checks if optional attribute select is present
3439 if "select" in attributes :
35- select = attributes [' select' ]
40+ select = attributes [" select" ]
3641
3742 # check that attribute select has a valid type
3843 if type (select ) is not str :
39- raise ValidationError (f"Invalid type for attribute select: expected string" )
44+ raise ValidationError (
45+ f"Invalid type for attribute select: expected string"
46+ )
4047
4148 # check that attribute select has a valid value
42- if select != 'newest' and select != 'oldest' and select != 'random' :
43- raise ValidationError (f"Invalid value '{ select } ' for attribute select: must be newest, oldest or random" )
44-
49+ if select != "newest" and select != "oldest" and select != "random" :
50+ raise ValidationError (
51+ f"Invalid value '{ select } ' for attribute select: must be newest, oldest or random"
52+ )
4553
4654 def evaluate_promise (self , promiser , attributes , metadata ):
4755 # get attriute feed
48- feed = attributes [' feed' ]
56+ feed = attributes [" feed" ]
4957
5058 # fetch resource
5159 resource = self ._get_resource (feed )
@@ -65,81 +73,83 @@ def evaluate_promise(self, promiser, attributes, metadata):
6573
6674 return result
6775
68-
6976 def _get_resource (self , path ):
7077 if self ._is_url (path ):
7178 # fetch from url
7279 self .log_verbose (f"Fetching feed from url '{ path } '" )
7380 response = requests .get (path )
7481 if response .ok :
7582 return response .content
76- self .log_error (f"Failed to fetch feed from url '{ path } '': status code '{ response .status_code } '" )
83+ self .log_error (
84+ f"Failed to fetch feed from url '{ path } '': status code '{ response .status_code } '"
85+ )
7786 return None
7887
7988 # fetch from file
8089 try :
8190 self .log_verbose (f"Reading feed from file '{ path } '" )
82- with open (path , 'r' , encoding = ' utf-8' ) as f :
91+ with open (path , "r" , encoding = " utf-8" ) as f :
8392 resource = f .read ()
8493 return resource
8594 except Exception as e :
8695 self .log_error (f"Failed to open file '{ path } ' for reading: { e } " )
8796 return None
8897
89-
9098 def _get_items (self , res , path ):
9199 # extract descriptions in /channel/item
92100 try :
93101 self .log_verbose (f"Parsing feed '{ path } '" )
94102 items = []
95103 root = ET .fromstring (res )
96- for item in root .findall (' ./channel/item' ):
104+ for item in root .findall (" ./channel/item" ):
97105 for child in item :
98- if child .tag == ' description' :
106+ if child .tag == " description" :
99107 items .append (child .text )
100108 return items
101109 except Exception as e :
102110 self .log_error (f"Failed to parse feed '{ path } ': { e } " )
103111 return None
104112
105-
106113 def _pick_item (self , items , attributes ):
107114 # Pick newest item as default
108115 item = items [0 ]
109116
110117 # Select item from feed
111118 if "select" in attributes :
112- select = attributes [' select' ]
113- if select == ' random' :
119+ select = attributes [" select" ]
120+ if select == " random" :
114121 self .log_verbose ("Selecting random item from feed" )
115122 item = random .choice (items )
116- elif select == ' oldest' :
123+ elif select == " oldest" :
117124 self .log_verbose ("Selecting oldest item from feed" )
118- item = items [- 1 ]
125+ item = items [- 1 ]
119126 else :
120127 self .log_verbose ("Selecting newest item from feed" )
121128 else :
122129 self .log_verbose ("Selecting newest item as default" )
123130 return item
124131
125-
126132 def _write_promiser (self , item , promiser ):
127133 file_exist = os .path .isfile (promiser )
128134
129135 if file_exist :
130136 try :
131- with open (promiser , 'r' , encoding = ' utf-8' ) as f :
137+ with open (promiser , "r" , encoding = " utf-8" ) as f :
132138 if f .read () == item :
133- self .log_verbose (f"File '{ promiser } ' exists and is up to date, no changes needed" )
139+ self .log_verbose (
140+ f"File '{ promiser } ' exists and is up to date, no changes needed"
141+ )
134142 return Result .KEPT
135143 except Exception as e :
136144 self .log_error (f"Failed to open file '{ promiser } ' for reading: { e } " )
137145 return Result .NOT_KEPT
138146
139147 try :
140- with open (promiser , 'w' , encoding = ' utf-8' ) as f :
148+ with open (promiser , "w" , encoding = " utf-8" ) as f :
141149 if file_exist :
142- self .log_info (f"File '{ promiser } ' exists but contents differ, updating content" )
150+ self .log_info (
151+ f"File '{ promiser } ' exists but contents differ, updating content"
152+ )
143153 else :
144154 self .log_info (f"File '{ promiser } ' does not exist, creating file" )
145155 f .write (item )
@@ -148,17 +158,20 @@ def _write_promiser(self, item, promiser):
148158 self .log_error (f"Failed to open file '{ promiser } ' for writing: { e } " )
149159 return Result .NOT_KEPT
150160
151-
152161 def _is_win_file (self , path ):
153162 return re .search (r"^[a-zA-Z]:\\[\\\S|*\S]?.*$" , path ) != None
154163
155-
156164 def _is_unix_file (self , path ):
157165 return re .search (r"^(/[^/ ]*)+/?$" , path ) != None
158166
159-
160167 def _is_url (self , path ):
161- return re .search (r"^http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+" , path ) != None
168+ return (
169+ re .search (
170+ r"^http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+" ,
171+ path ,
172+ )
173+ != None
174+ )
162175
163176
164177if __name__ == "__main__" :
0 commit comments