//
// aegis - project change supervisor
// Copyright (C) 1999, 2001-2009, 2012, 2014 Peter Miller
// Copyright (C) 2008 Walter Franzini
//
// 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void
change_run_history_get_command(change::pointer cp, fstate_src_ty *src,
string_ty *output_file_name, user_ty::pointer up)
{
sub_context_ty *scp;
string_ty *hp;
string_ty *hfn;
string_ty *the_command;
pconf_ty *pconf_data;
string_ty *name_of_encoded_file;
output::pointer op;
trace(("change_run_history_get_command(cp = %p)\n{\n", cp.get()));
assert(cp->valid());
assert(src->reference_count >= 1);
assert(src->file_name);
assert(src->edit);
assert(src->edit->revision);
if (src->edit->encoding == history_version_encoding_none)
name_of_encoded_file = output_file_name;
else
name_of_encoded_file = os_edit_filename(0);
trace(("file name = \"%s\";\n", src->file_name->str_text));
trace(("edit number = \"%s\";\n", src->edit->revision->str_text));
//
// If enough information is available use the change-set src
// belongs to for the rest of the processing.
//
// Depending on the presence of the edit.uuid field means this
// feature is available only for project created with 4,26 or
// later. We can probably use the roll_forward machinery to
// locate the change-set responsible of the requested file's
// revision, however that may have negative memory and speed
// effects.
//
if (src->edit->uuid)
{
change::pointer cp2 =
project_uuid_find(cp->project_get(), src->edit->uuid);
assert(cp2);
if (!cp2)
goto old_behavior;
//
// Check for the presence of the history_get_command change's
// attribute. If it's missing we proceed with the old behavior.
//
if (!change_attributes_find(cp2, HISTORY_GET_COMMAND))
goto old_behavior;
cp = cp2;
}
old_behavior:
//
// Inform the user of what we are doing, just in case they can't
// tell from the file names. For example, with a base-64 encoded
// input file and a UUID history file the user has no way of knowing
// which source file this concerns.
//
scp = sub_context_new();
scp->var_set_string("File_Name", src->file_name);
scp->var_set_string("Edit", src->edit->revision);
scp->var_optional("Edit");
change_error(cp, scp, i18n("history get $filename"));
sub_context_delete(scp);
scp = 0;
//
// If the edit numbers differ, extract the
// appropriate edit from the baseline (use the
// history-get-command) into a file in /tmp
//
// Current directory set to the base of the history tree.
// All of the substitutions described in aesub(5) are available;
// in addition
//
// ${History}
// history file
//
// ${Edit}
// edit number
//
// ${Output}
// output file
//
scp = sub_context_new();
hfn = project_history_filename_get(cp->project_get(), src);
trace(("hfn = \"%s\"\n", hfn->str_text));
sub_var_set_string(scp, "History", hfn);
str_free(hfn);
sub_var_set_string(scp, "Edit", src->edit->revision);
sub_var_set_string(scp, "Output", name_of_encoded_file);
//
// Prefer the command stored as change attribute and if not
// available consult the project configuration.
//
the_command = change_attributes_find(cp, HISTORY_GET_COMMAND);
if (!the_command)
{
pconf_data = change_pconf_get(cp, 1);
the_command = pconf_data->history_get_command;
}
if (!the_command)
{
sub_context_ty *scp2;
assert(pconf_data->errpos);
scp2 = sub_context_new();
sub_var_set_string(scp2, "File_Name", pconf_data->errpos);
sub_var_set_charstar(scp2, "FieLD_Name", "history_get_command");
change_fatal
(
cp,
scp2,
i18n("$filename: contains no \"$field_name\" field")
);
sub_context_delete(scp2);
}
the_command = substitute(scp, cp, the_command);
trace(("cmd = \"%s\"\n", the_command->str_text));
sub_context_delete(scp);
//
// run the command as the current user
// (always output is to /tmp)
//
change_env_set(cp, 0);
hp = cp->project_get()->history_path_get();
up->become_begin();
os_execute(the_command, OS_EXEC_FLAG_NO_INPUT | OS_EXEC_FLAG_SILENT, hp);
up->become_end();
str_free(the_command);
if (src->edit->encoding == history_version_encoding_none)
{
assert(name_of_encoded_file == output_file_name);
trace(("}\n"));
return;
}
//
// Decode the file.
//
os_become_orig();
input::pointer ip = input_file::open_text(nstring(name_of_encoded_file));
op = output_file::binary_open(output_file_name);
switch (src->edit->encoding)
{
case history_version_encoding_none:
assert(0);
break;
case history_version_encoding_quoted_printable:
ip = input_quoted_printable::create(ip);
break;
case history_version_encoding_base64:
ip = input_base64::create(ip);
break;
}
op << ip;
ip.reset();
op.reset();
os_unlink(name_of_encoded_file);
os_become_undo();
str_free(name_of_encoded_file);
trace(("}\n"));
}
// vim: set ts=8 sw=4 et :