root/applicationScripts/FontLab/ScriptBrowser.py

Revision 8, 6.4 kB (checked in by tal, 1 year ago)
Handle overlapping directories found in multiple script directories.
Line 
1 """
2 ScriptBrowser:  A nicer way to browse and execute scripts in FontLab.
3 Version 1.0
4
5 This script scans a directory or list of directories for sub directories which are then scanned for scripts.
6
7 Main Directory
8     Sub-Directory A
9         a_script.py
10         another_script.py
11     Sub-Directory B
12         a_script.py
13         another_script.py
14     etc.
15
16 This is useful for categorizing scripts. For example my scripts are organized like this:
17
18 FontLab_Scripts
19     Font
20         DecomposeComponents.py
21         BuildAccents.py
22     Glyph
23         CorrectPathDirection.py
24         RemoveOverlap.py
25     UFO
26         ExportCurrent.py
27         ImportOne.py
28         ExportDirectory.py
29         ImportDirectory.py
30     etc.
31
32 This will also scan the scripts for a title and some documentation.
33 The title must be on the first line of the script and it must be preceeded by a #.
34 Documentation will be read as the first triple quoted string in the script.
35 This info will be displayed in the UI when a script is selected.
36
37 THIS SCRIPT IS SUPPLIED AS IS. NO WARRANTEES. NO GUARANTEES. NO QUESTIONS.
38 (C) 2005 Tal Leming
39 """
40
41 ###########################################
42 # you must hardwire the location of your scripts directory here
43 #
44 SCRIPT_DIRECTORY = None
45 #
46 ###########################################
47
48 import os
49 import sys
50 import re
51 from FL import *
52
53 assert SCRIPT_DIRECTORY is not None, "Path to script directory is undefined!"
54 if isinstance(SCRIPT_DIRECTORY, list):
55     for p in SCRIPT_DIRECTORY:
56         assert os.path.isdir(p)
57 else:
58     assert os.path.isdir(SCRIPT_DIRECTORY)
59
60 ##
61 ## functions for loading data from scripts
62 ##
63
64 def runScriptDirectory(path):
65     """run through a directory and get script from each sub directory"""
66     sections = {}
67     if isinstance(path, list):
68         for p in path:
69             for section, scripts in runScriptDirectory(p).items():
70                 if section not in sections:
71                     sections[section] = {}
72                 sections[section].update(scripts)
73     else:
74         for fileName in os.listdir(path):
75             if fileName.startswith("."):
76                 continue
77             fullPath = os.path.join(path, fileName)
78             if os.path.isdir(fullPath):
79                 found = runSubDirectory(fullPath)
80                 if fileName in sections:
81                     sections[fileName].extend(found)
82                 else:
83                     sections[fileName] = found
84     return sections
85
86 def runSubDirectory(path):
87     """run through a directory of scripts and gather information about each script"""
88     scripts = {}
89     for fileName in os.listdir(path):
90         if fileName.startswith("."):
91             continue
92         base, ext = os.path.splitext(fileName)
93         if ext.lower() == ".py":
94             fullPath = os.path.join(path, fileName)
95             title, doc = scanScript(fullPath)
96             if title is None or len(title) == 0:
97                 title = base
98             if doc is None:
99                 doc = ""
100             scripts[title] = (doc, fullPath)
101     return scripts
102
103 doc_RE = re.compile(
104         "[\"\']{3}" # triple quote
105         "([\S\s]*)" # text
106         "[\"\']{3}" # triple quote
107         )
108 title_RE = re.compile(
109         "#\s*"
110         "(.*)"
111         )
112
113 def scanScript(path):
114     """get the title and documentation from the script"""
115     title = None
116     doc = None
117     f = open(path, "rb")
118     text = f.read().replace("\r\n", "\n").replace("\r", "\n")
119     f.close()
120     # extract doc
121     docSearch = doc_RE.findall(text)
122     if docSearch:
123         doc = docSearch[0].strip()
124     # extract name
125     titleSearch = title_RE.match(text)
126     if titleSearch is not None:
127         title = titleSearch.group(1)
128         if title[:4] == "FLM:":
129             title = title[4:]
130         title = title.strip()
131     return title, doc
132
133 ##
134 ## the UI
135 ##
136
137 width = 365
138 height = 400
139
140 class ScriptBrowser:
141
142     """A user freindly interface for executing scripts"""
143
144     def __init__(self, scriptDirectory):
145
146         self.d = Dialog(self)
147         self.d.size = Point(width, height)
148         self.d.Center()
149         self.d.title = "ScriptBrowser"
150
151         self.scriptDict = runScriptDirectory(scriptDirectory)
152         self.category_select = self.scriptDict.keys()
153         self.category_select.sort()
154         self.category_select_index = None
155         self.script_select = []
156         self.script_select_index = None
157         self.doc_label = "Documentation..."
158         self.selected = ""
159
160         self.d.AddControl(LISTCONTROL, Rect(15, 15, 120, height-130),  "category_select", STYLE_LIST, "")
161         self.d.AddControl(LISTCONTROL, Rect(130, 15, 350, height-130),  "script_select", STYLE_LIST, "")
162         self.d.AddControl(STATICCONTROL, Rect(15, height-120, width-15, height-100), "selected_label", STYLE_LABEL, "Selected:")
163         self.d.AddControl(STATICCONTROL, Rect(15, height-100, width-15, height-60), "doc_label", STYLE_LABEL, "Documentation...")
164
165         self.d.Run()
166
167     def on_category_select(self, code):
168         self.d.GetValue("category_select")
169         if self.category_select_index != '-1':
170             self.category = self.category_select[int(self.category_select_index)]
171             self.script_select = self.scriptDict[self.category].keys()
172             self.script_select.sort()
173             self.d.PutValue("script_select")
174
175     def on_script_select(self, code):
176         self.d.GetValue("script_select")
177         if self.script_select_index != "-1":
178             name = self.script_select[int(self.script_select_index)]
179             self.selected = self.scriptDict[self.category][name]
180             doc, path = self.selected
181             self.doc_label = doc
182             self.selected_label = name
183             self.d.PutValue("doc_label")
184             self.d.PutValue("selected_label")
185
186     def on_ok(self, code):
187         self.d.End()
188         # run the selected script
189         if self.selected != "":
190             doc, path = self.selected
191             saveArgv = sys.argv
192             saveChdir = os.getcwd()
193             sys.argv = [path]
194             os.chdir(os.path.dirname(path))
195             try:
196                 namespace = {
197                         "__file__" : path,
198                         "__name__" : "__main__",
199                         }
200                
201                 f = open(path, 'rb')
202                 data = '\n'.join(f.read().splitlines()) + '\n'
203                 f.close()
204                 exec data in namespace
205             finally:
206                 sys.argv = saveArgv
207                 os.chdir(saveChdir)
208
209     def on_cancel(self, code):
210         pass
211
212
213 ScriptBrowser(SCRIPT_DIRECTORY)
Note: See TracBrowser for help on using the browser.