author | wenzelm |
Thu, 15 Aug 2024 12:43:17 +0200 | |
changeset 80712 | 05b16602a683 |
parent 80480 | 972f7a4cdc0e |
permissions | -rw-r--r-- |
80273 | 1 |
/* Title: Pure/Tools/update_tool.scala |
69557 | 2 |
Author: Makarius |
3 |
||
4 |
Update theory sources based on PIDE markup. |
|
5 |
*/ |
|
6 |
||
7 |
package isabelle |
|
8 |
||
9 |
||
80273 | 10 |
object Update_Tool { |
76969 | 11 |
val update_elements: Markup.Elements = |
12 |
Markup.Elements(Markup.UPDATE, Markup.LANGUAGE) |
|
13 |
||
14 |
def update_xml(options: Options, xml: XML.Body): XML.Body = { |
|
76977 | 15 |
val update_path_cartouches = options.bool("update_path_cartouches") |
76981 | 16 |
val update_cite = options.bool("update_cite") |
77014 | 17 |
val cite_commands = Bibtex.cite_commands(options) |
76969 | 18 |
|
19 |
def upd(lang: Markup.Language, ts: XML.Body): XML.Body = |
|
20 |
ts flatMap { |
|
21 |
case XML.Wrapped_Elem(markup, body1, body2) => |
|
22 |
val body = if (markup.name == Markup.UPDATE) body1 else body2 |
|
23 |
upd(lang, body) |
|
24 |
case XML.Elem(Markup.Language(lang1), body) => |
|
76977 | 25 |
if (update_path_cartouches && lang1.is_path) { |
76969 | 26 |
Token.read_embedded(Keyword.Keywords.empty, XML.content(body)) match { |
27 |
case Some(tok) => List(XML.Text(Symbol.cartouche(tok.content))) |
|
28 |
case None => upd(lang1, body) |
|
29 |
} |
|
30 |
} |
|
76984
29432d4a376d
more robust: rely on PIDE markup instead of regex guess;
wenzelm
parents:
76981
diff
changeset
|
31 |
else if (update_cite && lang1.is_antiquotation) { |
76986 | 32 |
List(XML.Text(Bibtex.update_cite_antiquotation(cite_commands, XML.content(body)))) |
76984
29432d4a376d
more robust: rely on PIDE markup instead of regex guess;
wenzelm
parents:
76981
diff
changeset
|
33 |
} |
76969 | 34 |
else upd(lang1, body) |
35 |
case XML.Elem(_, body) => upd(lang, body) |
|
76984
29432d4a376d
more robust: rely on PIDE markup instead of regex guess;
wenzelm
parents:
76981
diff
changeset
|
36 |
case XML.Text(s) if update_cite && lang.is_document => |
29432d4a376d
more robust: rely on PIDE markup instead of regex guess;
wenzelm
parents:
76981
diff
changeset
|
37 |
List(XML.Text(Bibtex.update_cite_commands(s))) |
76969 | 38 |
case t => List(t) |
39 |
} |
|
40 |
upd(Markup.Language.outer, xml) |
|
41 |
} |
|
42 |
||
76979
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
43 |
def default_base_logic: String = Isabelle_System.getenv("ISABELLE_LOGIC") |
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
44 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
45 |
def update(options: Options, |
76927
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
46 |
update_options: List[Options.Spec], |
76920 | 47 |
selection: Sessions.Selection = Sessions.Selection.empty, |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
48 |
base_logics: List[String] = Nil, |
71726
a5fda30edae2
clarified signature: more uniform treatment of stopped/interrupted state;
wenzelm
parents:
71573
diff
changeset
|
49 |
progress: Progress = new Progress, |
76926 | 50 |
build_heap: Boolean = false, |
51 |
clean_build: Boolean = false, |
|
69557 | 52 |
dirs: List[Path] = Nil, |
53 |
select_dirs: List[Path] = Nil, |
|
76920 | 54 |
numa_shuffling: Boolean = false, |
79616 | 55 |
max_jobs: Option[Int] = None, |
76926 | 56 |
fresh_build: Boolean = false, |
77521
5642de4d225d
clarified signature: manage "verbose" flag via "progress";
wenzelm
parents:
77477
diff
changeset
|
57 |
no_build: Boolean = false |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
58 |
): Build.Results = { |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
59 |
/* excluded sessions */ |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
60 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
61 |
val exclude: Set[String] = |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
62 |
if (base_logics.isEmpty) Set.empty |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
63 |
else { |
80182
29f2b8ff84f3
proper support for "isabelle update -D DIR": avoid accidental exclusion of select_dirs (amending e5dafe9e120f);
wenzelm
parents:
80119
diff
changeset
|
64 |
Sessions.load_structure(options, dirs = dirs ::: select_dirs) |
76973 | 65 |
.selection(Sessions.Selection(sessions = base_logics)) |
76980 | 66 |
.build_graph.domain |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
67 |
} |
69557 | 68 |
|
76927
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
69 |
// test |
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
70 |
options ++ update_options |
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
71 |
|
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
72 |
def augment_options(name: String): List[Options.Spec] = |
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
73 |
if (exclude(name)) Nil else update_options |
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
74 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
75 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
76 |
/* build */ |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
77 |
|
77683
3e8e749935fc
proper "build_thorough" for "isabelle update" (amending 9e5f8f6e58a0);
wenzelm
parents:
77624
diff
changeset
|
78 |
val build_options = options + "build_thorough" |
3e8e749935fc
proper "build_thorough" for "isabelle update" (amending 9e5f8f6e58a0);
wenzelm
parents:
77624
diff
changeset
|
79 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
80 |
val build_results = |
77683
3e8e749935fc
proper "build_thorough" for "isabelle update" (amending 9e5f8f6e58a0);
wenzelm
parents:
77624
diff
changeset
|
81 |
Build.build(build_options, progress = progress, dirs = dirs, select_dirs = select_dirs, |
76928 | 82 |
selection = selection, build_heap = build_heap, clean_build = clean_build, |
76974 | 83 |
numa_shuffling = numa_shuffling, max_jobs = max_jobs, fresh_build = fresh_build, |
77521
5642de4d225d
clarified signature: manage "verbose" flag via "progress";
wenzelm
parents:
77477
diff
changeset
|
84 |
no_build = no_build, augment_options = augment_options) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
85 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
86 |
val store = build_results.store |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
87 |
val sessions_structure = build_results.deps.sessions_structure |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
88 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
89 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
90 |
/* update */ |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
91 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
92 |
var seen_theory = Set.empty[String] |
69571 | 93 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
94 |
using(Export.open_database_context(store)) { database_context => |
76920 | 95 |
for { |
96 |
session <- sessions_structure.build_topological_order |
|
97 |
if build_results(session).ok && !exclude(session) |
|
98 |
} { |
|
77009 | 99 |
progress.echo("Updating " + session + " ...") |
76970 | 100 |
val session_options = sessions_structure(session).options |
76929 | 101 |
val proper_session_theory = |
102 |
build_results.deps(session).proper_session_theories.map(_.theory).toSet |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
103 |
using(database_context.open_session0(session)) { session_context => |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
104 |
for { |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
105 |
db <- session_context.session_db() |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
106 |
theory <- store.read_theories(db, session) |
76929 | 107 |
if proper_session_theory(theory) && !seen_theory(theory) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
108 |
} { |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
109 |
seen_theory += theory |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
110 |
val theory_context = session_context.theory(theory) |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
111 |
for { |
78280 | 112 |
theory_snapshot <- Build.read_theory(theory_context) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
113 |
node_name <- theory_snapshot.node_files |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
114 |
snapshot = theory_snapshot.switch(node_name) |
76924 | 115 |
if snapshot.node.source_wellformed |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
116 |
} { |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
117 |
progress.expose_interrupt() |
80480
972f7a4cdc0e
clarified YXML.Source: more direct support for String and Bytes, instead of CharSequence;
wenzelm
parents:
80273
diff
changeset
|
118 |
val xml = |
972f7a4cdc0e
clarified YXML.Source: more direct support for String and Bytes, instead of CharSequence;
wenzelm
parents:
80273
diff
changeset
|
119 |
YXML.parse_body(YXML.bytes_of_body(snapshot.xml_markup(elements = update_elements))) |
76970 | 120 |
val source1 = XML.content(update_xml(session_options, xml)) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
121 |
if (source1 != snapshot.node.source) { |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
122 |
val path = Path.explode(node_name.node) |
77009 | 123 |
progress.echo("File " + quote(File.standard_path(path))) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
124 |
File.write(path, source1) |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
125 |
} |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
126 |
} |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
127 |
} |
70640
5f4b8a505090
more explicit type Dump.Session, with context information;
wenzelm
parents:
69896
diff
changeset
|
128 |
} |
75393 | 129 |
} |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
130 |
} |
70876 | 131 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
132 |
build_results |
69557 | 133 |
} |
134 |
||
135 |
||
136 |
/* Isabelle tool wrapper */ |
|
137 |
||
138 |
val isabelle_tool = |
|
72763 | 139 |
Isabelle_Tool("update", "update theory sources based on PIDE markup", Scala_Project.here, |
75394 | 140 |
{ args => |
141 |
var base_sessions: List[String] = Nil |
|
142 |
var select_dirs: List[Path] = Nil |
|
76920 | 143 |
var numa_shuffling = false |
75394 | 144 |
var requirements = false |
145 |
var exclude_session_groups: List[String] = Nil |
|
146 |
var all_sessions = false |
|
76926 | 147 |
var build_heap = false |
148 |
var clean_build = false |
|
75394 | 149 |
var dirs: List[Path] = Nil |
76926 | 150 |
var fresh_build = false |
75394 | 151 |
var session_groups: List[String] = Nil |
79616 | 152 |
var max_jobs: Option[Int] = None |
76979
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
153 |
var base_logics: List[String] = List(default_base_logic) |
76920 | 154 |
var no_build = false |
75394 | 155 |
var options = Options.init() |
76927
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
156 |
var update_options: List[Options.Spec] = Nil |
75394 | 157 |
var verbose = false |
158 |
var exclude_sessions: List[String] = Nil |
|
69557 | 159 |
|
75394 | 160 |
val getopts = Getopts(""" |
69557 | 161 |
Usage: isabelle update [OPTIONS] [SESSIONS ...] |
162 |
||
163 |
Options are: |
|
164 |
-B NAME include session NAME and all descendants |
|
165 |
-D DIR include session directory and select its sessions |
|
71807 | 166 |
-R refer to requirements of selected sessions |
69557 | 167 |
-X NAME exclude sessions from group NAME and all descendants |
168 |
-a select all sessions |
|
76926 | 169 |
-b build heap images |
170 |
-c clean build |
|
69557 | 171 |
-d DIR include session directory |
76926 | 172 |
-f fresh build |
69557 | 173 |
-g NAME select session group NAME |
76920 | 174 |
-j INT maximum number of parallel jobs (default 1) |
76979
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
175 |
-l NAMES comma-separated list of base logics, to remain unchanged |
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
176 |
(default: """ + quote(default_base_logic) + """) |
77554
4465d9dff448
clarified terminology of "session build database", while "build database" is the one underlying Build_Process;
wenzelm
parents:
77521
diff
changeset
|
177 |
-n no build -- take existing session build databases |
69557 | 178 |
-o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) |
76927
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
179 |
-u OPT override "update" option for selected sessions |
69557 | 180 |
-v verbose |
181 |
-x NAME exclude session NAME and all descendants |
|
182 |
||
76926 | 183 |
Update theory sources based on PIDE markup produced by "isabelle build". |
69557 | 184 |
""", |
75394 | 185 |
"B:" -> (arg => base_sessions = base_sessions ::: List(arg)), |
186 |
"D:" -> (arg => select_dirs = select_dirs ::: List(Path.explode(arg))), |
|
76920 | 187 |
"N" -> (_ => numa_shuffling = true), |
75394 | 188 |
"R" -> (_ => requirements = true), |
189 |
"X:" -> (arg => exclude_session_groups = exclude_session_groups ::: List(arg)), |
|
190 |
"a" -> (_ => all_sessions = true), |
|
76926 | 191 |
"b" -> (_ => build_heap = true), |
192 |
"c" -> (_ => clean_build = true), |
|
75394 | 193 |
"d:" -> (arg => dirs = dirs ::: List(Path.explode(arg))), |
76926 | 194 |
"f" -> (_ => fresh_build = true), |
75394 | 195 |
"g:" -> (arg => session_groups = session_groups ::: List(arg)), |
79616 | 196 |
"j:" -> (arg => max_jobs = Some(Value.Nat.parse(arg))), |
76979
1d4f015a685b
clarified options and defaults: avoid accidental changed of base logic due to augment_options(update_options);
wenzelm
parents:
76977
diff
changeset
|
197 |
"l:" -> (arg => base_logics = space_explode(',', arg)), |
76920 | 198 |
"n" -> (_ => no_build = true), |
75394 | 199 |
"o:" -> (arg => options = options + arg), |
77624 | 200 |
"u:" -> (arg => update_options = update_options ::: List(Options.Spec("update_" + arg))), |
75394 | 201 |
"v" -> (_ => verbose = true), |
202 |
"x:" -> (arg => exclude_sessions = exclude_sessions ::: List(arg))) |
|
69557 | 203 |
|
75394 | 204 |
val sessions = getopts(args) |
69557 | 205 |
|
75394 | 206 |
val progress = new Console_Progress(verbose = verbose) |
69557 | 207 |
|
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
208 |
val results = |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
209 |
progress.interrupt_handler { |
76927
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
wenzelm
parents:
76926
diff
changeset
|
210 |
update(options, update_options, |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
211 |
selection = Sessions.Selection( |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
212 |
requirements = requirements, |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
213 |
all_sessions = all_sessions, |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
214 |
base_sessions = base_sessions, |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
215 |
exclude_session_groups = exclude_session_groups, |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
216 |
exclude_sessions = exclude_sessions, |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
217 |
session_groups = session_groups, |
76920 | 218 |
sessions = sessions), |
219 |
base_logics = base_logics, |
|
220 |
progress = progress, |
|
80119 | 221 |
build_heap = build_heap, |
222 |
clean_build = clean_build, |
|
76920 | 223 |
dirs = dirs, |
224 |
select_dirs = select_dirs, |
|
77477 | 225 |
numa_shuffling = Host.numa_check(progress, numa_shuffling), |
76920 | 226 |
max_jobs = max_jobs, |
80119 | 227 |
fresh_build = fresh_build, |
77521
5642de4d225d
clarified signature: manage "verbose" flag via "progress";
wenzelm
parents:
77477
diff
changeset
|
228 |
no_build = no_build) |
76918
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
229 |
} |
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
230 |
|
19be7d89bf03
isabelle update no longer uses PIDE dump, but regular session build database: more scalable;
wenzelm
parents:
75394
diff
changeset
|
231 |
sys.exit(results.rc) |
75394 | 232 |
}) |
69557 | 233 |
} |