Mercurial > treepkg
comparison contrib/sawmill/web/details.py @ 452:333232953771
Initial check-in of sawmill a simple mod_python based
web application to render build reports of treepkg.
author | Sascha Teichmann <teichmann@intevation.de> |
---|---|
date | Fri, 20 Aug 2010 16:15:29 +0000 |
parents | |
children | 52f841330c16 |
comparison
equal
deleted
inserted
replaced
451:eacfd3744d16 | 452:333232953771 |
---|---|
1 # -*- coding: UTF-8 -*- | |
2 # | |
3 # Copyright (C) 2010 by Intevation GmbH | |
4 # Authors: | |
5 # Sascha L. Teichmann <sascha.teichmann@intevation.de> | |
6 # | |
7 # This program is free software under the GPL (>=v2) | |
8 # Read the file COPYING coming with the software for details. | |
9 | |
10 from mod_python import apache, psp, util | |
11 | |
12 import os | |
13 import re | |
14 import datetime | |
15 import time | |
16 | |
17 from lxml import etree | |
18 | |
19 BASE_DIR = "treepkgs" | |
20 | |
21 TREEPKG_DIR = os.path.join(os.path.dirname(__file__), BASE_DIR) | |
22 | |
23 STATUS_LINE = re.compile(r"^([^:]+):(.+)") | |
24 | |
25 UNDER_SCORE = re.compile(r"_+(\w)") | |
26 | |
27 def _create_time(s, format="%Y-%m-%d %H:%M:%S"): | |
28 return datetime.datetime(*(time.strptime(s, format)[0:6])) | |
29 | |
30 def _pretty_log_name(log): | |
31 log = log.replace(".txt", "").replace(".gz", "").capitalize() | |
32 return UNDER_SCORE.sub(lambda x: " %s" % x.group(1).upper(), log) | |
33 | |
34 class TrackItem(object): | |
35 | |
36 def __init__(self, treepkg, track, revision, status_file): | |
37 self.treepkg = treepkg | |
38 self.track = track | |
39 self.revision = revision | |
40 self.status_file = status_file | |
41 self.loaded = False | |
42 self.status = None | |
43 self.start = None | |
44 self.stop = None | |
45 self.logs = None | |
46 | |
47 def check_loaded(self): | |
48 if not self.loaded: | |
49 f = open(self.status_file) | |
50 try: | |
51 for line in f: | |
52 m = STATUS_LINE.match(line) | |
53 if not m: continue | |
54 key, value = [x.strip() for x in m.groups()] | |
55 | |
56 if key == 'status': self.status = value | |
57 elif key == 'start': self.start = _create_time(value) | |
58 elif key == 'stop': self.stop = _create_time(value) | |
59 finally: | |
60 f.close() | |
61 self.loaded = True | |
62 | |
63 def get_build_status(self): | |
64 self.check_loaded() | |
65 return self.status | |
66 | |
67 def get_build_start(self): | |
68 self.check_loaded() | |
69 return self.start | |
70 | |
71 def get_build_stop(self): | |
72 self.check_loaded() | |
73 return self.stop | |
74 | |
75 def log_path(self, log): | |
76 return "%s/tracks/%s/pkg/%s/log/%s" % ( | |
77 self.treepkg, self.track, self.revision, log) | |
78 | |
79 def get_build_logs(self): | |
80 oj = os.path.join | |
81 if self.logs is None: | |
82 log_dir = oj(os.path.dirname(self.status_file), "log") | |
83 if not os.path.isdir(log_dir): | |
84 self.logs = [] | |
85 else: | |
86 self.logs =[(_pretty_log_name(f), self.log_path(f)) | |
87 for f in os.listdir(log_dir) | |
88 if os.path.isfile(oj(log_dir, f)) and f.find("txt") >= 0] | |
89 return self.logs | |
90 | |
91 build_status = property(get_build_status) | |
92 build_start = property(get_build_start) | |
93 build_stop = property(get_build_stop) | |
94 build_logs = property(get_build_logs) | |
95 | |
96 | |
97 def __scan_track_items(treepkg, path): | |
98 items = [] | |
99 | |
100 tracks_path = os.path.join(path, "tracks") | |
101 for track in os.listdir(tracks_path): | |
102 track_path = os.path.join(tracks_path, track) | |
103 if not os.path.isdir(track_path): continue | |
104 revisions_path = os.path.join(track_path, "pkg") | |
105 for revision in os.listdir(revisions_path): | |
106 revision_path = os.path.join(revisions_path, revision) | |
107 if not os.path.isdir(revision_path): continue | |
108 status_file = os.path.join(revision_path, "status") | |
109 if not os.path.isfile(status_file): continue | |
110 items.append(TrackItem(treepkg, track, revision, status_file)) | |
111 | |
112 return items | |
113 | |
114 def __description_header(treepkg): | |
115 treepkg_xml = os.path.join(treepkg, "treepkg.xml") | |
116 if os.path.isfile(treepkg_xml): | |
117 xml = None | |
118 try: | |
119 xml = open(treepkg_xml, "rb") | |
120 dom = etree.parse(xml) | |
121 finally: | |
122 if xml: xml.close() | |
123 | |
124 description = ''.join(dom.xpath("//description/text()")) | |
125 header = ''.join([etree.tostring(x, encoding="UTF-8", method="html") | |
126 for x in dom.xpath("//header/*")]) | |
127 return description, header | |
128 return "unknown", "" | |
129 | |
130 def index(req, treepkg=''): | |
131 if not treepkg: util.redirect(req, "index.py") | |
132 | |
133 found = None | |
134 for d in os.listdir(TREEPKG_DIR): | |
135 dp = os.path.join(TREEPKG_DIR, d) | |
136 if os.path.isdir(dp) and d == treepkg: | |
137 found = dp | |
138 break | |
139 | |
140 if not found: | |
141 req.status = apache.HTTP_NOT_FOUND | |
142 return "requested TreePkg not found" | |
143 | |
144 description, header = __description_header(found) | |
145 | |
146 track_items = __scan_track_items(treepkg, found) | |
147 | |
148 req.content_type = 'text/html;charset=utf-8' | |
149 template = psp.PSP(req, filename='templates/details.html') | |
150 template.run({ | |
151 'base_dir': BASE_DIR, | |
152 'description': description, | |
153 'header': header, | |
154 'track_items': track_items | |
155 }) |