2020-02-09 01:28:32 +02:00
|
|
|
[TemplateManager::] Template Manager.
|
|
|
|
|
2020-03-31 02:17:21 +03:00
|
|
|
Claiming and creating copies of the template genre: used for website and
|
|
|
|
interpreter templates when releasing an Inform project.
|
2020-02-09 01:28:32 +02:00
|
|
|
|
|
|
|
@h Genre definition.
|
2020-03-30 15:25:23 +03:00
|
|
|
The |template_genre| can be summarised as follows. Website templates
|
|
|
|
are directories. They are recognised by containing either a metadata file
|
|
|
|
called |(manifest).txt| or |index.html|, or both. They are stored in
|
|
|
|
nests, in |N/Templates/Title-vVersion|. Their build graphs are single
|
|
|
|
vertices with no build or use edges.
|
2020-02-09 01:28:32 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
void TemplateManager::start(void) {
|
2023-07-10 23:34:25 +03:00
|
|
|
template_genre = Genres::new(I"template", I"template", TRUE);
|
2020-02-09 01:28:32 +02:00
|
|
|
METHOD_ADD(template_genre, GENRE_WRITE_WORK_MTID, TemplateManager::write_work);
|
|
|
|
METHOD_ADD(template_genre, GENRE_CLAIM_AS_COPY_MTID, TemplateManager::claim_as_copy);
|
|
|
|
METHOD_ADD(template_genre, GENRE_SEARCH_NEST_FOR_MTID, TemplateManager::search_nest_for);
|
|
|
|
METHOD_ADD(template_genre, GENRE_COPY_TO_NEST_MTID, TemplateManager::copy_to_nest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TemplateManager::write_work(inbuild_genre *gen, OUTPUT_STREAM, inbuild_work *work) {
|
|
|
|
WRITE("%S", work->title);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Templates live in the |Templates| subdirectory of a nest:
|
|
|
|
|
|
|
|
=
|
|
|
|
pathname *TemplateManager::path_within_nest(inbuild_nest *N) {
|
|
|
|
if (N == NULL) internal_error("no nest");
|
2020-04-16 01:49:59 +03:00
|
|
|
return Pathnames::down(N->location, I"Templates");
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@ Template copies are annotated with a structure called an |inform_template|,
|
|
|
|
which stores data about extensions used by the Inform compiler.
|
|
|
|
|
|
|
|
=
|
|
|
|
inform_template *TemplateManager::from_copy(inbuild_copy *C) {
|
|
|
|
if ((C) && (C->edition->work->genre == template_genre)) {
|
2020-05-05 01:34:55 +03:00
|
|
|
return RETRIEVE_POINTER_inform_template(C->metadata);
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-08-28 13:02:45 +03:00
|
|
|
inbuild_copy *TemplateManager::new_copy(text_stream *name, pathname *P, inbuild_nest *N) {
|
2020-02-09 01:28:32 +02:00
|
|
|
inbuild_work *work = Works::new(template_genre, Str::duplicate(name), NULL);
|
2020-05-05 01:34:55 +03:00
|
|
|
inbuild_edition *edition = Editions::new(work, VersionNumbers::null());
|
2022-08-28 13:02:45 +03:00
|
|
|
inbuild_copy *C = Copies::new_in_path(edition, P, N);
|
2020-05-05 01:34:55 +03:00
|
|
|
Templates::scan(C);
|
|
|
|
return C;
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@h Claiming.
|
|
|
|
Here |arg| is a textual form of a filename or pathname, such as may have been
|
|
|
|
supplied at the command line; |ext| is a substring of it, and is its extension
|
|
|
|
(e.g., |jpg| if |arg| is |Geraniums.jpg|), or is empty if there isn't one;
|
|
|
|
|directory_status| is true if we know for some reason that this is a directory
|
|
|
|
not a file, false if we know the reverse, and otherwise not applicable.
|
|
|
|
|
|
|
|
Templates are slightly hard to recognise in isolation, but they contain
|
|
|
|
either a manifest file, or else an |index.html|, so that will have to do.
|
|
|
|
|
|
|
|
=
|
|
|
|
void TemplateManager::claim_as_copy(inbuild_genre *gen, inbuild_copy **C,
|
|
|
|
text_stream *arg, text_stream *ext, int directory_status) {
|
|
|
|
if (directory_status == FALSE) return;
|
|
|
|
pathname *P = Pathnames::from_text(arg);
|
2022-08-28 13:02:45 +03:00
|
|
|
*C = TemplateManager::claim_folder_as_copy(P, NULL);
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 13:02:45 +03:00
|
|
|
inbuild_copy *TemplateManager::claim_folder_as_copy(pathname *P, inbuild_nest *N) {
|
2020-04-16 01:49:59 +03:00
|
|
|
filename *canary1 = Filenames::in(P, I"(manifest).txt");
|
|
|
|
filename *canary2 = Filenames::in(P, I"index.html");
|
2020-05-09 18:25:04 +03:00
|
|
|
if ((TextFiles::exists(canary1)) || (TextFiles::exists(canary2)))
|
2022-08-28 13:02:45 +03:00
|
|
|
return TemplateManager::new_copy(Pathnames::directory_name(P), P, N);
|
2020-02-09 01:28:32 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Searching.
|
|
|
|
Here we look through a nest to find all kits matching the supplied
|
|
|
|
requirements.
|
|
|
|
|
|
|
|
=
|
|
|
|
void TemplateManager::search_nest_for(inbuild_genre *gen, inbuild_nest *N,
|
|
|
|
inbuild_requirement *req, linked_list *search_results) {
|
2020-02-09 13:35:57 +02:00
|
|
|
if ((req->work->genre) && (req->work->genre != template_genre)) return;
|
2020-02-09 01:28:32 +02:00
|
|
|
pathname *P = TemplateManager::path_within_nest(N);
|
2022-04-20 00:05:06 +03:00
|
|
|
linked_list *L = Directories::listing(P);
|
|
|
|
text_stream *entry;
|
|
|
|
LOOP_OVER_LINKED_LIST(entry, text_stream, L) {
|
|
|
|
if (Platform::is_folder_separator(Str::get_last_char(entry))) {
|
|
|
|
Str::delete_last_character(entry);
|
|
|
|
pathname *Q = Pathnames::down(P, entry);
|
2022-08-28 13:02:45 +03:00
|
|
|
inbuild_copy *C = TemplateManager::claim_folder_as_copy(Q, N);
|
2022-04-20 00:05:06 +03:00
|
|
|
if ((C) && (Requirements::meets(C->edition, req))) {
|
|
|
|
Nests::add_search_result(search_results, N, C, req);
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Copying.
|
|
|
|
Now the task is to copy a template into place in a nest. Since a template is
|
|
|
|
a folder, we need to |rsync| it.
|
|
|
|
|
|
|
|
=
|
2020-03-10 02:08:35 +02:00
|
|
|
pathname *TemplateManager::pathname_in_nest(inbuild_nest *N, inbuild_edition *E) {
|
2020-06-28 01:18:54 +03:00
|
|
|
TEMPORARY_TEXT(leaf)
|
2020-03-10 02:08:35 +02:00
|
|
|
Editions::write_canonical_leaf(leaf, E);
|
2020-04-16 01:49:59 +03:00
|
|
|
pathname *P = Pathnames::down(TemplateManager::path_within_nest(N), leaf);
|
2020-06-28 01:18:54 +03:00
|
|
|
DISCARD_TEXT(leaf)
|
2020-03-10 02:08:35 +02:00
|
|
|
return P;
|
2020-02-09 01:28:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void TemplateManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
|
|
|
|
int syncing, build_methodology *meth) {
|
2020-03-10 02:08:35 +02:00
|
|
|
pathname *P = TemplateManager::pathname_in_nest(N, C->edition);
|
2020-04-16 01:49:59 +03:00
|
|
|
filename *canary1 = Filenames::in(P, I"(manifest).txt");
|
|
|
|
filename *canary2 = Filenames::in(P, I"index.html");
|
2020-02-09 01:28:32 +02:00
|
|
|
if ((TextFiles::exists(canary1)) || (TextFiles::exists(canary2))) {
|
2020-03-29 19:39:17 +03:00
|
|
|
if (syncing == FALSE) { Copies::overwrite_error(C, N); return; }
|
2020-02-09 01:28:32 +02:00
|
|
|
} else {
|
|
|
|
if (meth->methodology == DRY_RUN_METHODOLOGY) {
|
2020-06-28 01:18:54 +03:00
|
|
|
TEMPORARY_TEXT(command)
|
2020-02-09 01:28:32 +02:00
|
|
|
WRITE_TO(command, "mkdir -p ");
|
|
|
|
Shell::quote_path(command, P);
|
|
|
|
WRITE_TO(STDOUT, "%S\n", command);
|
2020-06-28 01:18:54 +03:00
|
|
|
DISCARD_TEXT(command)
|
2020-02-09 01:28:32 +02:00
|
|
|
} else {
|
|
|
|
Pathnames::create_in_file_system(N->location);
|
|
|
|
Pathnames::create_in_file_system(TemplateManager::path_within_nest(N));
|
|
|
|
Pathnames::create_in_file_system(P);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (meth->methodology == DRY_RUN_METHODOLOGY) {
|
2020-06-28 01:18:54 +03:00
|
|
|
TEMPORARY_TEXT(command)
|
2020-02-09 01:28:32 +02:00
|
|
|
WRITE_TO(command, "rsync -a --delete ");
|
|
|
|
Shell::quote_path(command, C->location_if_path);
|
|
|
|
Shell::quote_path(command, P);
|
|
|
|
WRITE_TO(STDOUT, "%S\n", command);
|
2020-06-28 01:18:54 +03:00
|
|
|
DISCARD_TEXT(command)
|
2020-02-09 01:28:32 +02:00
|
|
|
} else {
|
|
|
|
Pathnames::rsync(C->location_if_path, P);
|
|
|
|
}
|
|
|
|
}
|