//
// aegis - project change supervisor
// Copyright (C) 1999, 2000, 2002-2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include // for assert
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static pconf_file_template_ty *
find(change::pointer cp, string_ty *file_name)
{
trace(("change_file_template_string(file_name = \"%s\")\n{\n",
file_name->str_text));
assert(cp->reference_count>=1);
pconf_file_template_ty *result = 0;
pconf_ty *pconf_data = change_pconf_get(cp, 0);
if (!pconf_data->file_template)
goto done;
for (size_t j = 0; j < pconf_data->file_template->length; ++j)
{
pconf_file_template_ty *ftp = pconf_data->file_template->list[j];
if (!ftp->pattern)
continue;
for (size_t k = 0; k < ftp->pattern->length; ++k)
{
string_ty *s = ftp->pattern->list[k];
int m = gmatch(s->str_text, file_name->str_text);
if (m < 0)
{
sub_context_ty sc;
sc.var_set_string("File_Name", s);
change_fatal(cp, &sc, i18n("bad pattern $filename"));
// NOTREACHED
}
if (m)
{
result = ftp;
goto done;
}
}
}
//
// here for all exits
//
done:
trace(("return %08lX;\n", (long)result));
trace(("}\n"));
return result;
}
static bool
painful_development_directory_style(change::pointer cp)
{
trace(("painful_development_directory_style(cp = %08lX)\n{\n", (long)cp));
pconf_ty *pconf_data = change_pconf_get(cp, 0);
bool result =
(
pconf_data
&&
pconf_data->development_directory_style
&&
(
pconf_data->development_directory_style->source_file_link
||
pconf_data->development_directory_style->source_file_copy
)
);
trace(("return %d\n", result));
trace(("}\n"));
return result;
}
void
change_file_template(change::pointer cp, string_ty *filename,
user_ty::pointer up, int use_template)
{
trace(("change_file_template(cp = %08lX, filename = \"%s\", ip = %08lX, "
"use_template = %d)\n{\n", (long)cp, filename->str_text, (long)up.get(),
use_template));
//
// figure the absolute path of the file
//
trace(("change_file_template(name = \"%s\")\n{\n", filename->str_text));
assert(cp->reference_count>=1);
string_ty *dd = change_development_directory_get(cp, 0);
string_ty *path = os_path_join(dd, filename);
//
// If the file exists, do not over-write what the user has
// already written.
//
up->become_begin();
os_mkdir_between(dd, filename, 02755);
bool exists = false;
if (os_symlink_query(path))
{
//
// Source files can't be symbolic links, and we are about to
// create a source file, so remove any symlink that may be
// present. It's probably left-over from the development
// directory style.
//
os_unlink(path);
up->become_end();
}
else
{
//
// Test to see if the file exists.
//
trace(("path = \"%s\"\n", path->str_text));
exists = os_exists(path);
up->become_end();
//
// If the development directory style makes hard links or
// copies, we have a problem. We have to distinguish between
// something the user edited, and wants to keep, from a copy of
// a baseline file (which may be obsolete), or a hard link to a
// baseline file (which may be been changed in the baseline, and
// now the link count is one).
//
if
(
exists
&&
painful_development_directory_style(cp)
&&
project_file_find(cp->pp, filename, view_path_extreme)
)
{
//
// At present, we will err on the side of caution, and
// discard the file in the development directory, if the
// development directory style permits these kinds of
// artifacts.
//
user_ty::become scoped(up);
os_unlink(path);
exists = false;
}
}
trace(("exists = %d\n", exists));
int keep = 0;
if (exists)
{
trace(("Should we keep it?\n"));
keep = !up->delete_file_query(nstring(filename), false, false);
}
trace(("keep = %d\n", keep));
//
// The logic here is controlled by the following truth table:
//
// exists keep use_template | action
// -------------------------+-------
// 0 X 0 | create, empty
// 0 X !=0 | create, template
// 1 0 0 | create, empty
// 1 0 !=0 | create, template
// 1 1 X | do nothing
//
if (!exists || !keep)
{
//
// Find the template to be used to construct the new file.
//
pconf_file_template_ty *tp = use_template ? find(cp, filename) : 0;
trace(("tp = %08lX\n", (long)tp));
if (tp && tp->body_command)
{
//
// Build the command to be executed.
//
sub_context_ty sc;
sc.var_set_string("File_Name", filename);
string_ty *the_command = sc.substitute(cp, tp->body_command);
//
// Execute the command.
//
int flags = OS_EXEC_FLAG_NO_INPUT;
change_env_set(cp, 1);
up->become_begin();
if (exists)
os_unlink_errok(path);
os_execute(the_command, flags, dd);
exists = os_exists(path);
up->become_end();
str_free(the_command);
//
// It is an error if the command didn't create
// the file.
//
if (!exists)
{
sub_context_ty err;
err.var_set_string("File_Name", filename);
change_fatal(cp, &err, i18n("new file $filename not created"));
// NOTREACHED
}
}
else
{
//
// There is no command, it must be a string template.
//
string_ty *body = 0;
if (!tp)
body = str_from_c("");
else
{
sub_context_ty sc;
sc.var_set_string("File_Name", filename);
sc.var_optional("File_Name");
body = sc.substitute(cp, tp->body);
}
//
// Now we have the string, write it to the file.
//
int mode = 0644 & ~change_umask(cp);
user_ty::become scoped(up);
file_from_string(path, body, mode);
str_free(body);
}
}
str_free(path);
trace(("}\n"));
}