mirror of
https://github.com/ganelson/inform.git
synced 2024-06-30 22:14:58 +03:00
Tidied up inpolicy
This commit is contained in:
parent
5af2ac1396
commit
3271eae5f6
|
@ -6,11 +6,14 @@ this plan out.
|
|||
@h Main routine.
|
||||
|
||||
@e SILENCE_CLSW
|
||||
@e VERBOSE_CLSW
|
||||
@e PROBLEMS_CLSW
|
||||
@e ADVANCE_CLSW
|
||||
|
||||
=
|
||||
int return_happy = TRUE, silence_mode = FALSE;
|
||||
pathname *path_to_inpolicy = NULL; /* where we are installed */
|
||||
pathname *path_to_inpolicy_materials = NULL; /* the materials pathname */
|
||||
int return_happy = TRUE, silence_mode = FALSE, verbose_mode = FALSE;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Foundation::start();
|
||||
|
@ -19,15 +22,22 @@ int main(int argc, char **argv) {
|
|||
L"[[Purpose]]\n\n"
|
||||
L"usage: inpolicy [options]\n");
|
||||
|
||||
CommandLine::declare_boolean_switch(SILENCE_CLSW, L"silence", 1,
|
||||
L"print nothing unless there's something wrong");
|
||||
CommandLine::declare_switch(PROBLEMS_CLSW, L"check-problems", 1,
|
||||
L"check problem test case coverage");
|
||||
CommandLine::declare_switch(ADVANCE_CLSW, L"advance-build", 2,
|
||||
L"increment daily build code for web X");
|
||||
|
||||
CommandLine::declare_boolean_switch(SILENCE_CLSW, L"silence", 1,
|
||||
L"print nothing unless there's something wrong");
|
||||
CommandLine::declare_boolean_switch(VERBOSE_CLSW, L"verbose", 1,
|
||||
L"explain what inpolicy is doing");
|
||||
|
||||
CommandLine::read(argc, argv, NULL, &Main::respond, &Main::disallow);
|
||||
|
||||
path_to_inpolicy = Pathnames::installation_path("INPOLICY_PATH", I"inpolicy");
|
||||
path_to_inpolicy_materials = Pathnames::subfolder(path_to_inpolicy, I"Materials");
|
||||
if (verbose_mode) PRINT("Installation path is %p\n", path_to_inpolicy);
|
||||
|
||||
Foundation::end();
|
||||
if (return_happy) return 0; else return 1;
|
||||
}
|
||||
|
@ -39,6 +49,8 @@ void Main::disallow(int id, text_stream *arg, void *state) {
|
|||
@
|
||||
|
||||
@d RUNTEST(Routine)
|
||||
path_to_inpolicy = Pathnames::installation_path("INPOLICY_PATH", I"inpolicy");
|
||||
path_to_inpolicy_materials = Pathnames::subfolder(path_to_inpolicy, I"Materials");
|
||||
if (silence_mode) {
|
||||
if (Routine(NULL) == FALSE) { return_happy = FALSE; Routine(STDERR); }
|
||||
} else {
|
||||
|
@ -51,5 +63,6 @@ void Main::respond(int id, int val, text_stream *arg, void *state) {
|
|||
case ADVANCE_CLSW: Inversion::maintain(arg); break;
|
||||
case PROBLEMS_CLSW: RUNTEST(Coverage::check); break;
|
||||
case SILENCE_CLSW: silence_mode = val; break;
|
||||
case VERBOSE_CLSW: verbose_mode = val; break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,21 +4,25 @@ To see which problem messages have test cases and which are linked
|
|||
to the documentation.
|
||||
|
||||
@h Observation.
|
||||
Problem messages are identified by their code-names, e.g., |PM_MisplacedFrom|;
|
||||
those names should be unique, but any number of problems can instead be
|
||||
marked with one of three special names.
|
||||
|
||||
@d CASE_EXISTS_PCON 0x00000001
|
||||
@d DOC_MENTIONS_PCON 0x00000002
|
||||
@d CODE_MENTIONS_PCON 0x00000004
|
||||
@d IMPOSSIBLE_PCON 0x00000008
|
||||
@d UNTESTABLE_PCON 0x00000010
|
||||
@d NAMELESS_PCON 0x00000020
|
||||
Problems can be mentioned in the code, in the documentation, or in the
|
||||
set of Inform test cases.
|
||||
|
||||
@d CASE_EXISTS_PCON 0x00000001 /* mentioned in test cases */
|
||||
@d DOC_MENTIONS_PCON 0x00000002 /* mentioned in documentation */
|
||||
@d CODE_MENTIONS_PCON 0x00000004 /* mentioned in source code */
|
||||
@d IMPOSSIBLE_PCON 0x00000008 /* this is |BelievedImpossible| */
|
||||
@d UNTESTABLE_PCON 0x00000010 /* this is |Untestable| */
|
||||
@d NAMELESS_PCON 0x00000020 /* this is |...| */
|
||||
|
||||
=
|
||||
dictionary *problems_dictionary = NULL;
|
||||
|
||||
typedef struct known_problem {
|
||||
struct text_stream *name;
|
||||
int contexts_observed;
|
||||
int contexts_observed_multiple_times;
|
||||
int contexts_observed; /* bitmap of the above bits */
|
||||
int contexts_observed_multiple_times; /* bitmap of the above bits */
|
||||
MEMORY_MANAGEMENT
|
||||
} known_problem;
|
||||
|
||||
|
@ -26,6 +30,8 @@ typedef struct known_problem {
|
|||
and augment its bitmap of known contexts:
|
||||
|
||||
=
|
||||
dictionary *problems_dictionary = NULL;
|
||||
|
||||
void Coverage::observe_problem(text_stream *name, int context) {
|
||||
if (problems_dictionary == NULL)
|
||||
problems_dictionary = Dictionaries::new(1000, FALSE);
|
||||
|
@ -92,23 +98,29 @@ void Coverage::xref_harvester(text_stream *text, text_file_position *tfp, void *
|
|||
}
|
||||
|
||||
@h Problems generated in the I7 source.
|
||||
Which is to say, actually existing problem messages.
|
||||
Which is to say, actually existing problem messages. Ideally, this code
|
||||
should find the modules included in Inform in some more sophisticated way.
|
||||
|
||||
=
|
||||
void Coverage::which_problems_exist(pathname *Workspace) {
|
||||
Coverage::which_problems_exist_inner(
|
||||
Pathnames::from_text(I"inform7"), Workspace);
|
||||
Coverage::which_problems_exist_inner(
|
||||
Pathnames::from_text(I"inform7/core-module"), Workspace);
|
||||
Coverage::which_problems_exist_inner(
|
||||
Pathnames::from_text(I"inform7/if-module"), Workspace);
|
||||
Coverage::which_problems_exist_inner(
|
||||
Pathnames::from_text(I"inform7/multimedia-module"), Workspace);
|
||||
Coverage::which_problems_exist_inner(
|
||||
Pathnames::from_text(I"inter/codegen-module"), Workspace);
|
||||
void Coverage::which_problems_exist(void) {
|
||||
Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7"));
|
||||
Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/core-module"));
|
||||
Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/if-module"));
|
||||
Coverage::which_problems_exist_inner(Pathnames::from_text(I"inform7/multimedia-module"));
|
||||
Coverage::which_problems_exist_inner(Pathnames::from_text(I"inter/codegen-module"));
|
||||
}
|
||||
|
||||
void Coverage::which_problems_exist_inner(pathname *D, pathname *Workspace) {
|
||||
@ So now we have to read the contents page of a web, to see what section
|
||||
files it contains:
|
||||
|
||||
=
|
||||
typedef struct existence_state {
|
||||
struct pathname *web_path;
|
||||
struct pathname *chapter_path;
|
||||
struct filename *section;
|
||||
} existence_state;
|
||||
|
||||
void Coverage::which_problems_exist_inner(pathname *D) {
|
||||
filename *C = Filenames::in_folder(D, I"Contents.w");
|
||||
existence_state es;
|
||||
es.web_path = D;
|
||||
|
@ -117,12 +129,6 @@ void Coverage::which_problems_exist_inner(pathname *D, pathname *Workspace) {
|
|||
&Coverage::section_harvester, NULL, &es);
|
||||
}
|
||||
|
||||
typedef struct existence_state {
|
||||
struct pathname *web_path;
|
||||
struct pathname *chapter_path;
|
||||
struct filename *section;
|
||||
} existence_state;
|
||||
|
||||
void Coverage::section_harvester(text_stream *text, text_file_position *tfp, void *state) {
|
||||
existence_state *es = (existence_state *) state;
|
||||
match_results mr = Regexp::create_mr();
|
||||
|
@ -143,6 +149,11 @@ void Coverage::section_harvester(text_stream *text, text_file_position *tfp, voi
|
|||
Regexp::dispose_of(&mr);
|
||||
}
|
||||
|
||||
@ So now we're working through individual section files. The exclusion of
|
||||
the case called |sigil| throws out a macro definition in the source code,
|
||||
not a specific problem case.
|
||||
|
||||
=
|
||||
void Coverage::existence_harvester(text_stream *text, text_file_position *tfp, void *state) {
|
||||
existence_state *es = (existence_state *) state;
|
||||
match_results mr = Regexp::create_mr();
|
||||
|
@ -151,64 +162,78 @@ void Coverage::existence_harvester(text_stream *text, text_file_position *tfp, v
|
|||
WRITE_TO(text, "%S%S", mr.exp[0], mr.exp[2]);
|
||||
TEMPORARY_TEXT(name);
|
||||
Str::copy(name, mr.exp[1]);
|
||||
if (Str::eq_wide_string(name, L"sigil")) break;
|
||||
if (Str::eq(name, I"sigil")) break;
|
||||
int context = CODE_MENTIONS_PCON;
|
||||
if (Str::eq_wide_string(name, L"BelievedImpossible")) { context = IMPOSSIBLE_PCON; @<Suffix location@> }
|
||||
else if (Str::eq_wide_string(name, L"Untestable")) { context = UNTESTABLE_PCON; @<Suffix location@> }
|
||||
else if (Str::eq_wide_string(name, L"...")) { context = NAMELESS_PCON; @<Suffix location@> }
|
||||
if (Str::eq_wide_string(name, L"BelievedImpossible")) @<Suffix location@>
|
||||
if (Str::eq(name, I"BelievedImpossible")) {
|
||||
context = IMPOSSIBLE_PCON;
|
||||
WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count);
|
||||
} else if (Str::eq(name, I"Untestable")) {
|
||||
context = UNTESTABLE_PCON;
|
||||
WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count);
|
||||
} else if (Str::eq(name, I"...")) {
|
||||
context = NAMELESS_PCON;
|
||||
WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count);
|
||||
}
|
||||
Coverage::observe_problem(name, context);
|
||||
DISCARD_TEXT(name);
|
||||
}
|
||||
Regexp::dispose_of(&mr);
|
||||
}
|
||||
|
||||
@<Suffix location@> =
|
||||
WRITE_TO(name, "_%f_line%d", es->section, tfp->line_count);
|
||||
|
||||
@h Checking.
|
||||
So the actual policy-enforcement routine is here:
|
||||
|
||||
=
|
||||
int observations_made = FALSE;
|
||||
int Coverage::check(OUTPUT_STREAM) {
|
||||
if (observations_made == FALSE) {
|
||||
pathname *P =
|
||||
Pathnames::subfolder(Pathnames::from_text(I"inpolicy"), I"Workspace");
|
||||
Coverage::which_problems_have_test_cases(P);
|
||||
Coverage::which_problems_are_referenced(P);
|
||||
Coverage::which_problems_exist(P);
|
||||
@<Perform the observations@>;
|
||||
observations_made = TRUE;
|
||||
}
|
||||
|
||||
int all_is_well = TRUE;
|
||||
@<Report and decide how grave the situation is@>;
|
||||
if (all_is_well) WRITE("All is well.\n");
|
||||
else WRITE("This needs attention.\n");
|
||||
WRITE("\n");
|
||||
return all_is_well;
|
||||
}
|
||||
|
||||
@<Perform the observations@> =
|
||||
Coverage::which_problems_have_test_cases(path_to_inpolicy_materials);
|
||||
Coverage::which_problems_are_referenced(path_to_inpolicy_materials);
|
||||
Coverage::which_problems_exist();
|
||||
|
||||
@ Okay, so that's all of the scanning done; now to report on it.
|
||||
|
||||
@<Report and decide how grave the situation is@> =
|
||||
WRITE("%d problem name(s) have been observed:\n", NUMBER_CREATED(known_problem)); INDENT;
|
||||
|
||||
WRITE("Problems actually existing (the source code refers to them):\n"); INDENT;
|
||||
Coverage::cite(OUT, CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON,
|
||||
L"are named and in principle testable");
|
||||
I"are named and in principle testable");
|
||||
if (Coverage::cite(OUT, 0, CODE_MENTIONS_PCON, CODE_MENTIONS_PCON,
|
||||
L"are named more than once:") > 0) {
|
||||
I"are named more than once:") > 0) {
|
||||
all_is_well = FALSE;
|
||||
Coverage::list(OUT, 0, CODE_MENTIONS_PCON, CODE_MENTIONS_PCON);
|
||||
}
|
||||
Coverage::cite(OUT, IMPOSSIBLE_PCON, 0, IMPOSSIBLE_PCON,
|
||||
L"are 'BelievedImpossible', that is, no known source text causes them");
|
||||
I"are 'BelievedImpossible', that is, no known source text causes them");
|
||||
Coverage::cite(OUT, UNTESTABLE_PCON, 0, UNTESTABLE_PCON,
|
||||
L"are 'Untestable', that is, not mechanically testable");
|
||||
I"are 'Untestable', that is, not mechanically testable");
|
||||
Coverage::cite(OUT, NAMELESS_PCON, 0, NAMELESS_PCON,
|
||||
L"are '...', that is, they need to be give a name and a test case");
|
||||
I"are '...', that is, they need to be give a name and a test case");
|
||||
OUTDENT;
|
||||
|
||||
WRITE("Problems which should have test cases:\n"); INDENT;
|
||||
Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON+CODE_MENTIONS_PCON,
|
||||
L"have test cases");
|
||||
I"have test cases");
|
||||
if (Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON,
|
||||
L"have no test case yet:") > 0) {
|
||||
I"have no test case yet:") > 0) {
|
||||
Coverage::list(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CODE_MENTIONS_PCON);
|
||||
}
|
||||
if (Coverage::cite(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON,
|
||||
L"are spurious test cases, since no such problems exist:") > 0) {
|
||||
I"are spurious test cases, since no such problems exist:") > 0) {
|
||||
all_is_well = FALSE;
|
||||
Coverage::list(OUT, CASE_EXISTS_PCON+CODE_MENTIONS_PCON, 0, CASE_EXISTS_PCON);
|
||||
}
|
||||
|
@ -216,45 +241,39 @@ int Coverage::check(OUTPUT_STREAM) {
|
|||
|
||||
WRITE("Problems which are cross-referenced in 'Writing with Inform':\n"); INDENT;
|
||||
Coverage::cite(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON,
|
||||
L"are cross-referenced");
|
||||
I"are cross-referenced");
|
||||
if (Coverage::cite(OUT, 0, DOC_MENTIONS_PCON, DOC_MENTIONS_PCON,
|
||||
L"are cross-referenced more than once:") > 0) {
|
||||
I"are cross-referenced more than once:") > 0) {
|
||||
all_is_well = FALSE;
|
||||
Coverage::list(OUT, 0, DOC_MENTIONS_PCON, DOC_MENTIONS_PCON);
|
||||
}
|
||||
if (Coverage::cite(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, DOC_MENTIONS_PCON,
|
||||
L"are spurious references, since no such problems exist:") > 0) {
|
||||
I"are spurious references, since no such problems exist:") > 0) {
|
||||
all_is_well = FALSE;
|
||||
Coverage::list(OUT, CODE_MENTIONS_PCON+DOC_MENTIONS_PCON, 0, DOC_MENTIONS_PCON);
|
||||
}
|
||||
OUTDENT;
|
||||
|
||||
OUTDENT;
|
||||
if (all_is_well) WRITE("All is well.\n");
|
||||
else WRITE("This needs attention.\n");
|
||||
WRITE("\n");
|
||||
return all_is_well;
|
||||
}
|
||||
|
||||
int Coverage::cite(OUTPUT_STREAM, int mask, int mask2, int val, wchar_t *message) {
|
||||
@ =
|
||||
int Coverage::cite(OUTPUT_STREAM, int mask, int mask2, int val, text_stream *message) {
|
||||
int N = 0;
|
||||
known_problem *KP;
|
||||
LOOP_OVER(KP, known_problem) {
|
||||
if ((KP->contexts_observed & mask) == val) N++;
|
||||
if ((KP->contexts_observed_multiple_times & mask2) == val) N++;
|
||||
}
|
||||
if ((N>0) && (message)) WRITE("%d problem(s) %w\n", N, message);
|
||||
if ((N>0) && (message)) WRITE("%d problem(s) %S\n", N, message);
|
||||
return N;
|
||||
}
|
||||
|
||||
void Coverage::list(OUTPUT_STREAM, int mask, int mask2, int val) {
|
||||
INDENT;
|
||||
known_problem *KP;
|
||||
LOOP_OVER(KP, known_problem) {
|
||||
LOOP_OVER(KP, known_problem)
|
||||
if (((KP->contexts_observed & mask) == val) ||
|
||||
((KP->contexts_observed_multiple_times & mask2) == val)) {
|
||||
WRITE("%S\n", KP->name);
|
||||
}
|
||||
}
|
||||
OUTDENT;
|
||||
}
|
|
@ -3,6 +3,10 @@
|
|||
To update the build number(s) and versions for the intools.
|
||||
|
||||
@h The build-numbers file.
|
||||
The scheme here is that each project can optionally contain a UTF-8 encoded
|
||||
text file called |versions.txt|, which lists all of its version history;
|
||||
a line of that file corresponds to a "version". Out of these versions, one
|
||||
must be marked as the current version.
|
||||
|
||||
=
|
||||
typedef struct project {
|
||||
|
@ -11,7 +15,7 @@ typedef struct project {
|
|||
int manual_updating;
|
||||
struct text_stream *web;
|
||||
struct filename *versions_file;
|
||||
struct version *first_version;
|
||||
struct linked_list *versions; /* of |version| */
|
||||
struct version *current_version;
|
||||
struct text_stream *conts;
|
||||
MEMORY_MANAGEMENT
|
||||
|
@ -23,42 +27,58 @@ typedef struct version {
|
|||
struct text_stream *build_code;
|
||||
struct text_stream *date;
|
||||
struct text_stream *notes;
|
||||
int unstable;
|
||||
struct version *next_version;
|
||||
MEMORY_MANAGEMENT
|
||||
} version;
|
||||
|
||||
@ And here we turn a named web into its |project| structure. We print its
|
||||
current version number when we first load a project in:
|
||||
|
||||
=
|
||||
project *Inversion::read(text_stream *web) {
|
||||
project *P;
|
||||
LOOP_OVER(P, project)
|
||||
if (Str::eq(web, P->web))
|
||||
return P;
|
||||
LOOP_OVER(P, project) if (Str::eq(web, P->web)) return P;
|
||||
P = CREATE(project);
|
||||
P->sync_line = Str::new();
|
||||
P->sync_to = NULL;
|
||||
P->manual_updating = TRUE;
|
||||
P->web = Str::duplicate(web);
|
||||
P->first_version = NULL;
|
||||
P->versions = NEW_LINKED_LIST(version);
|
||||
P->current_version = NULL;
|
||||
P->versions_file = Filenames::in_folder(Pathnames::from_text(web), I"versions.txt");
|
||||
TextFiles::read(P->versions_file, FALSE, "unable to read roster of version numbers", TRUE,
|
||||
&Inversion::version_harvester, NULL, P);
|
||||
P->conts = Str::new();
|
||||
P->versions_file = Filenames::in_folder(Pathnames::from_text(web), I"versions.txt");
|
||||
@<Read in the versions file@>;
|
||||
@<Print the current version number@>;
|
||||
return P;
|
||||
}
|
||||
|
||||
@<Print the current version number@> =
|
||||
if (P->current_version == NULL) {
|
||||
Errors::with_text("warning: no version marked as current", web);
|
||||
} else {
|
||||
PRINT("%S: %S %S (build %S)\n", web,
|
||||
P->current_version->name, P->current_version->number, P->current_version->build_code);
|
||||
}
|
||||
return P;
|
||||
}
|
||||
|
||||
@<Read in the versions file@> =
|
||||
TextFiles::read(P->versions_file, FALSE, "unable to read roster of version numbers", TRUE,
|
||||
&Inversion::version_harvester, NULL, P);
|
||||
|
||||
@ A version file contains lines which can either be a special command, or
|
||||
give details of a version. The commands are |Automatic| or |Manual| (the
|
||||
latter is the default), or |Sync to W|, where |W| is another project.
|
||||
(All of this is infrastructure left over from when the Inform tools were
|
||||
syncing version numbers to the main Inform 7 version number: with the
|
||||
transition to Github, this scheme was dropped.)
|
||||
|
||||
=
|
||||
void Inversion::version_harvester(text_stream *text, text_file_position *tfp, void *state) {
|
||||
project *P = (project *) state;
|
||||
match_results mr = Regexp::create_mr();
|
||||
if (Str::len(text) == 0) return;
|
||||
if (Regexp::match(&mr, text, L"Automatic")) {
|
||||
P->manual_updating = FALSE;
|
||||
} else if (Regexp::match(&mr, text, L"Manual")) {
|
||||
P->manual_updating = TRUE;
|
||||
} else if (Regexp::match(&mr, text, L"Sync to (%c*)")) {
|
||||
P->sync_to = Inversion::read(mr.exp[0]);
|
||||
P->manual_updating = FALSE;
|
||||
|
@ -70,39 +90,39 @@ void Inversion::version_harvester(text_stream *text, text_file_position *tfp, vo
|
|||
V->date = Str::duplicate(mr.exp[3]);
|
||||
V->notes = Str::duplicate(mr.exp[4]);
|
||||
if (Str::get_first_char(V->build_code) == '*') {
|
||||
V->unstable = TRUE;
|
||||
Str::delete_first_character(V->build_code);
|
||||
P->current_version = V;
|
||||
} else V->unstable = FALSE;
|
||||
if (P->first_version == NULL) P->first_version = V;
|
||||
else {
|
||||
version *W = P->first_version;
|
||||
while ((W) && (W->next_version)) W = W->next_version;
|
||||
W->next_version = V;
|
||||
}
|
||||
ADD_TO_LINKED_LIST(V, version, P->versions);
|
||||
} else {
|
||||
Errors::in_text_file("can't parse version line", tfp);
|
||||
}
|
||||
Regexp::dispose_of(&mr);
|
||||
}
|
||||
|
||||
@ The following then writes back the versions file, following a version
|
||||
increment:
|
||||
|
||||
=
|
||||
void Inversion::write(project *P) {
|
||||
text_stream vr_stream;
|
||||
text_stream *OUT = &vr_stream;
|
||||
if (Streams::open_to_file(OUT, P->versions_file, UTF8_ENC) == FALSE)
|
||||
Errors::fatal_with_file("can't write versions file", P->versions_file);
|
||||
if (P->sync_to) WRITE("Sync to %S\n", P->sync_to->web);
|
||||
for (version *V = P->first_version; V; V = V->next_version) {
|
||||
WRITE("%S\t%S\t",
|
||||
V->name, V->number);
|
||||
if (V->unstable) WRITE("*");
|
||||
WRITE("%S\t%S\t%S\n",
|
||||
V->build_code, V->date, V->notes);
|
||||
else if (P->manual_updating) WRITE("Manual\n");
|
||||
else WRITE("Automatic\n");
|
||||
version *V;
|
||||
LOOP_OVER_LINKED_LIST(V, version, P->versions) {
|
||||
WRITE("%S\t%S\t", V->name, V->number);
|
||||
if (V == P->current_version) WRITE("*");
|
||||
WRITE("%S\t%S\t%S\n", V->build_code, V->date, V->notes);
|
||||
}
|
||||
Streams::close(OUT);
|
||||
}
|
||||
|
||||
@h Updating.
|
||||
The standard date format we use is "26 February 2018".
|
||||
|
||||
=
|
||||
int Inversion::dated_today(project *P, text_stream *dateline) {
|
||||
|
@ -116,6 +136,13 @@ int Inversion::dated_today(project *P, text_stream *dateline) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
@ Here we read the Inform four-character code, e.g., |3Q27|, and increase it
|
||||
by one. The two-digit code at the back is incremented, but rolls around from
|
||||
|99| to |01|, in which case the letter is advanced, except that |I| and |O|
|
||||
are skipped, and if the letter passes |Z| then it rolls back around to |A|
|
||||
and the initial digit is incremented.
|
||||
|
||||
=
|
||||
void Inversion::increment(project *P) {
|
||||
if (P->current_version == NULL) return;
|
||||
text_stream *T = P->current_version->build_code;
|
||||
|
@ -145,6 +172,8 @@ void Inversion::increment(project *P) {
|
|||
}
|
||||
|
||||
@h Imposition.
|
||||
When we impose a new version number on a web that has a contents page, we
|
||||
update the metadata in that contents page.
|
||||
|
||||
=
|
||||
void Inversion::impose(project *P) {
|
||||
|
@ -179,6 +208,27 @@ void Inversion::impose_helper(text_stream *text, text_file_position *tfp, void *
|
|||
Regexp::dispose_of(&mr);
|
||||
}
|
||||
|
||||
@h Daily build maintenance.
|
||||
|
||||
=
|
||||
void Inversion::maintain(text_stream *web) {
|
||||
project *P = Inversion::read(web);
|
||||
if (Inversion::needs_update(P)) {
|
||||
Inversion::write(P);
|
||||
Inversion::impose(P);
|
||||
if ((Str::eq(web, I"inform7")) && (P->current_version)) {
|
||||
filename *F = Filenames::from_text(I"build-code.mk");
|
||||
text_stream as_stream;
|
||||
text_stream *OUT = &as_stream;
|
||||
if (Streams::open_to_file(OUT, F, UTF8_ENC) == FALSE)
|
||||
Errors::fatal_with_file("unable to write archive settings", F);
|
||||
WRITE("BUILDCODE = %S\n", P->current_version->build_code);
|
||||
Streams::close(OUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ =
|
||||
int Inversion::needs_update(project *P) {
|
||||
int rv = FALSE;
|
||||
if ((P->manual_updating == FALSE) && (P->current_version)) {
|
||||
|
@ -204,23 +254,3 @@ int Inversion::needs_update(project *P) {
|
|||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@h Daily build maintenance.
|
||||
|
||||
=
|
||||
void Inversion::maintain(text_stream *web) {
|
||||
project *P = Inversion::read(web);
|
||||
if (Inversion::needs_update(P)) {
|
||||
Inversion::write(P);
|
||||
Inversion::impose(P);
|
||||
if ((Str::eq(web, I"inform7")) && (P->current_version)) {
|
||||
filename *F = Filenames::from_text(I"build-code.mk");
|
||||
text_stream as_stream;
|
||||
text_stream *OUT = &as_stream;
|
||||
if (Streams::open_to_file(OUT, F, UTF8_ENC) == FALSE)
|
||||
Errors::fatal_with_file("unable to write archive settings", F);
|
||||
WRITE("BUILDCODE = %S\n", P->current_version->build_code);
|
||||
Streams::close(OUT);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,8 +12,13 @@ Build Date: 10 February 2019
|
|||
|
||||
Import: foundation
|
||||
|
||||
Chapter 1: What It Does
|
||||
Preliminaries
|
||||
Using Inpolicy
|
||||
|
||||
Chapter 1: Setting Up
|
||||
Basics
|
||||
Main
|
||||
|
||||
Chapter 2: Policies
|
||||
Problem Coverage
|
||||
Version Numbering
|
||||
|
|
66
inpolicy/Preliminaries/Using Inpolicy.w
Executable file
66
inpolicy/Preliminaries/Using Inpolicy.w
Executable file
|
@ -0,0 +1,66 @@
|
|||
Using Inpolicy.
|
||||
|
||||
A very short guide to a very small program.
|
||||
|
||||
@h What Inpolicy is.
|
||||
Inpolicy is a command-line tool whose sole purpose is to help keep the
|
||||
Inform 7 source code tidy. Unlike Inweb, Intest and Indoc, this tool
|
||||
can't sensibly be used for any project other than Inform.
|
||||
|
||||
If you have compiled the standard distribution of the command-line tools
|
||||
for Inform then the Inpolicy executable will be at |inpolicy/Tangled/inpolicy|.
|
||||
Usage is very simple:
|
||||
|
||||
|$ inpolicy/Tangled/inpolicy POLICY|
|
||||
|
||||
where |POLICY| is whatever we want to check. There are very few at present;
|
||||
in some ways this program is a placeholder for future tightening-up of the
|
||||
style rules.
|
||||
|
||||
@ When it runs, Inpolicy needs to know where it is installed in the file
|
||||
system. There is no completely foolproof, cross-platform way to know this
|
||||
(on some Unixes, a program cannot determine its own location), so Inpolicy
|
||||
decides by the following set of rules:
|
||||
|
||||
(a) If the user, at the command line, specified |-at P|, for some path
|
||||
|P|, then we use that.
|
||||
(b) Otherwise, if the host operating system can indeed tell us where the
|
||||
executable is, we use that. This is currently implemented only on MacOS,
|
||||
Windows and Linux.
|
||||
(c) Otherwise, if the environment variable |$INPOLICY_PATH| exists and is
|
||||
non-empty, we use that.
|
||||
(d) And if all else fails, we assume that the location is |inpolicy|, with
|
||||
respect to the current working directory.
|
||||
|
||||
If you're not sure what Inpolicy has decided and suspect it may be wrong,
|
||||
running Inpolicy with the |-verbose| switch will cause it to print its belief
|
||||
about its location as it starts up.
|
||||
|
||||
@h Policies.
|
||||
|-check-problems| makes a survey of (a) all of the Problem messages issued
|
||||
within the Inform 7 compiler, (b) all of the Problem test cases, and (c) all
|
||||
of the advisory references to Problems in the Inform documentation, and
|
||||
attempts to match these up. It prints out a report, and concludes with either
|
||||
"All is well" or a recommendation for changes. For example:
|
||||
|
||||
|1009 problem name(s) have been observed:|
|
||||
| Problems actually existing (the source code refers to them):|
|
||||
| 906 problem(s) are named and in principle testable|
|
||||
| 81 problem(s) are 'BelievedImpossible', that is, no known source text causes them|
|
||||
| 14 problem(s) are 'Untestable', that is, not mechanically testable|
|
||||
| 8 problem(s) are '...', that is, they need to be give a name and a test case|
|
||||
| Problems which should have test cases:|
|
||||
| 904 problem(s) have test cases|
|
||||
| 2 problem(s) have no test case yet:|
|
||||
| PM_SuperfluousOf|
|
||||
| PM_MisplacedFrom|
|
||||
| Problems which are cross-referenced in 'Writing with Inform':|
|
||||
| 483 problem(s) are cross-referenced|
|
||||
|All is well.|
|
||||
|
||||
As this example report shows, small sins are forgiven.
|
||||
|
||||
@ |-advance-build W| tries to advance the build code for the web |W|. In
|
||||
practice, this is used only when the web is |inform7|. The build code is
|
||||
the familiar (to Inform users) four-character version number, such as
|
||||
|3K27| or |6P98|.
|
|
@ -345,6 +345,7 @@ endef
|
|||
pages:
|
||||
$(INWEBX) inblorb -weave-docs -weave-into docs/inblorb
|
||||
$(INWEBX) indoc -weave-docs -weave-into docs/indoc
|
||||
$(INWEBX) inpolicy -weave-docs -weave-into docs/inpolicy
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Target "clean"
|
||||
|
|
Loading…
Reference in a new issue