//
// aegis - project change supervisor
// Copyright (C) 2001-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
#include // for assert
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static string_ty *
branch_description_invent(project_ty *pp)
{
string_ty *s1;
string_ty *s2;
size_t len;
string_ty *result;
s2 = project_version_short_get(pp);
pp = pp->trunk_get();
s1 = project_description_get(pp);
if (s1->str_length == 0)
{
str_free(s2);
return str_copy(s1);
}
for (len = s1->str_length; len; --len)
{
unsigned char c;
c = s1->str_text[len - 1];
if (c == '.')
continue;
// C locale
if (isspace(c))
continue;
break;
}
result =
str_format("%.*s, branch %s.", (int)len, s1->str_text, s2->str_text);
// do not free s1
str_free(s2);
return result;
}
project_ty *
project_new_branch(project_ty *ppp, user_ty::pointer up, long change_number,
string_ty *topdir, string_ty *reason)
{
cstate_ty *cstate_data;
cstate_history_ty *history_data;
change::pointer cp;
size_t j;
pconf_ty *pconf_data;
string_ty *s;
project_ty *pp;
//
// On entry it is assumed that you have
// a project state lock, to create the branches
//
trace(("project_new_branch(ppp = %8.8lX, change_number = %ld, "
"topdir = %ld, reason = %ld)\n{\n", (long)ppp, change_number,
(long)topdir, (long)reason));
//
// create the new branch.
// validity of the branch number was checked elsewhere.
//
cp = change_alloc(ppp, change_number);
change_bind_new(cp);
change_branch_new(cp);
pp = ppp->bind_branch(cp);
//
// The copyright years are not copied from the parent, because
// they are updated by integrations. The copyright years thus
// represent the copyright years for the changes made by the
// branch.
//
// However, when copyright years are calculated for "ael
// version" the branch's copyright years (actually, all
// ancestors') are included.
//
//
// Create the change (branch) directory.
//
// It is in the same place as the rest of the project, unless
// otherwise specified. This makes it easy to collect the whole
// project tree, branches, info and all, in a simple tar or cpio
// command for archiving or moving.
//
if (!topdir)
{
sub_context_ty *scp;
topdir =
str_format
(
"%s/branch.%ld",
project_top_path_get(ppp, 0)->str_text,
magic_zero_decode(change_number)
);
scp = sub_context_new();
sub_var_set_string(scp, "File_Name", topdir);
change_verbose(cp, scp, i18n("development directory \"$filename\""));
sub_context_delete(scp);
}
change_top_path_set(cp, topdir);
//
// Create the development directory.
//
// In a branch, the development directory contains
// (a) a directory called "baseline" for the branch's baseline
// (b) directories called "delta.*" for integrations, later
// (c) directories called "branch.*" for branches, later
//
// A branch's development directory is owned by the project
// owner, not the creating user.
//
// The "info" and "history" directories are only present in the
// development directory of the trunk. DO NOT create them here.
//
s = str_format("%s/baseline", topdir->str_text);
project_become(pp);
os_mkdir(topdir, 02755);
os_mkdir(s, 02755);
undo_rmdir_errok(s);
undo_rmdir_errok(topdir);
project_become_undo(pp);
str_free(s);
//
// create the change history,
// and advance the change to 'being developed'
//
history_data = change_history_new(cp, up);
history_data->what = cstate_history_what_new_change;
if (reason)
history_data->why = str_copy(reason);
history_data = change_history_new(cp, up);
history_data->what = cstate_history_what_develop_begin;
cstate_data = cp->cstate_get();
cstate_data->state = cstate_state_being_developed;
//
// set the attributes
//
cstate_data->description = branch_description_invent(pp);
cstate_data->brief_description = str_copy(cstate_data->description);
cstate_data->cause = change_cause_internal_enhancement;
cstate_data->test_exempt = true;
cstate_data->test_baseline_exempt = true;
cstate_data->regression_test_exempt = true;
//
// Create symbolic links from the the branch's baseline into the
// branch's parent's baseline. This is similar to what happens
// at develop begin.
//
pconf_data = change_pconf_get(cp, 0);
assert(pconf_data->integration_directory_style);
work_area_style_ty style = *pconf_data->integration_directory_style;
if (!style.during_build_only)
change_create_symlinks_to_baseline(cp, project_user(ppp), style);
//
// Clear the time fields.
//
change_build_times_clear(cp);
//
// many of the branch attributes are inherited from the parent
//
change_branch_umask_set(cp, project_umask_get(ppp));
change_branch_developer_may_review_set
(
cp,
project_developer_may_review_get(ppp)
);
change_branch_developer_may_integrate_set
(
cp,
project_developer_may_integrate_get(ppp)
);
change_branch_reviewer_may_integrate_set
(
cp,
project_reviewer_may_integrate_get(ppp)
);
change_branch_developers_may_create_changes_set
(
cp,
project_developers_may_create_changes_get(ppp)
);
change_branch_forced_develop_begin_notify_command_set
(
cp,
project_forced_develop_begin_notify_command_get(ppp)
);
change_branch_develop_end_notify_command_set
(
cp,
project_develop_end_notify_command_get(ppp)
);
change_branch_develop_end_undo_notify_command_set
(
cp,
project_develop_end_undo_notify_command_get(ppp)
);
change_branch_review_begin_notify_command_set
(
cp,
project_review_begin_notify_command_get(ppp)
);
change_branch_review_begin_undo_notify_command_set
(
cp,
project_review_begin_undo_notify_command_get(ppp)
);
change_branch_review_pass_notify_command_set
(
cp,
project_review_pass_notify_command_get(ppp)
);
change_branch_review_pass_undo_notify_command_set
(
cp,
project_review_pass_undo_notify_command_get(ppp)
);
change_branch_review_fail_notify_command_set
(
cp,
project_review_fail_notify_command_get(ppp)
);
change_branch_integrate_pass_notify_command_set
(
cp,
project_integrate_pass_notify_command_get(ppp)
);
change_branch_integrate_fail_notify_command_set
(
cp,
project_integrate_fail_notify_command_get(ppp)
);
change_branch_default_test_exemption_set
(
cp,
project_default_test_exemption_get(ppp)
);
change_branch_default_test_regression_exemption_set
(
cp,
project_default_test_regression_exemption_get(ppp)
);
change_branch_default_development_directory_set
(
cp,
project_default_development_directory_get(ppp)
);
change_branch_compress_database_set
(
cp,
project_compress_database_get(ppp)
);
change_branch_protect_development_directory_set
(
cp,
project_protect_development_directory_get(ppp)
);
//
// staff lists are inherited from the parent
//
for (j = 0;; ++j)
{
s = project_administrator_nth(ppp, j);
if (!s)
break;
change_branch_administrator_add(cp, s);
}
for (j = 0;; ++j)
{
s = project_developer_nth(ppp, j);
if (!s)
break;
change_branch_developer_add(cp, s);
}
for (j = 0;; ++j)
{
s = project_reviewer_nth(ppp, j);
if (!s)
break;
change_branch_reviewer_add(cp, s);
}
for (j = 0;; ++j)
{
s = project_integrator_nth(ppp, j);
if (!s)
break;
change_branch_integrator_add(cp, s);
}
change_branch_minimum_change_number_set
(
cp,
project_minimum_change_number_get(ppp)
);
change_branch_reuse_change_numbers_set
(
cp,
project_reuse_change_numbers_get(ppp)
);
change_branch_minimum_branch_number_set
(
cp,
project_minimum_branch_number_get(ppp)
);
change_branch_skip_unlucky_set(cp, project_skip_unlucky_get(ppp));
change_branch_develop_end_action_set
(
cp,
project_develop_end_action_get(ppp)
);
//
// architecture is inherited from parent
//
assert(pconf_data->architecture);
change_architecture_clear(cp);
for (j = 0; j < pconf_data->architecture->length; ++j)
{
change_architecture_add(cp, pconf_data->architecture->list[j]->name);
}
//
// Add the change to the list of existing changes
//
project_change_append(ppp, change_number, 1);
trace(("return %8.8lX;\n", (long)pp));
trace(("}\n"));
return pp;
}