//
// aegis - project change supervisor
// Copyright (C) 2012 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
#include
#include
#include
#include
validation_man_pages::~validation_man_pages()
{
}
validation_man_pages::validation_man_pages()
{
}
validation_man_pages::pointer
validation_man_pages::create(void)
{
return pointer(new validation_man_pages());
}
static nstring
extract_man_page_details(const nstring_list &part, size_t idx)
{
if (idx + 2 != part.size())
return nstring();
if (!part[idx].gmatch("man[18nl]*"))
return nstring();
nstring section = "." + part[idx].substr(3, 1);
nstring progname = part[idx + 1];
const char *s = progname.c_str();
const char *extn = strstr(s, section.c_str());
if (!extn || extn == s)
return nstring();
progname = nstring(s, extn - s);
return progname;
}
static nstring
extract_man_page_details(const nstring &filename)
{
nstring_list part;
part.split(filename, "/");
// e.g. man/man1/fred.1
if (part.size() == 3 && part[0] == "man")
{
nstring progname = extract_man_page_details(part, 1);
if (!progname.empty())
return progname;
}
// e.g. "man1/fred.1"
if (part.size() == 2)
{
nstring progname = extract_man_page_details(part, 0);
if (!progname.empty())
return progname;
}
// e.g. "lib/en/man1/fred.1"
if (part.size() >= 3 && part[part.size() - 3] == "en")
{
nstring progname = extract_man_page_details(part, part.size() - 2);
if (!progname.empty())
return progname;
}
return nstring();
}
static nstring
extract_progname_details(const nstring &filename)
{
nstring_list part;
part.split(filename, "/");
if (part.size() != 2)
return nstring();
// look for C and C++ program entry points
if (part[1] == "main.c" || part[1] == "main.cc")
return part[0];
// look for sripts
if (part[0] == "script" || part[0] == "scripts")
{
nstring progname = part[1];
if (progname.ends_with(".in"))
progname = progname.substr(0, progname.size() - 3);
if (progname.ends_with(".sh") || progname.ends_with(".pl"))
return progname.substr(0, progname.size() - 3);
}
// i gots nufink
return nstring();
}
static nstring
extract_progname_details_generous(const nstring &filename)
{
nstring_list part;
part.split(filename, "/");
if (part.size() < 2)
return nstring();
// looks for scripts
if (part[0] == "script" || part[0] == "scripts")
{
nstring progname = part[1];
if (progname.ends_with(".in"))
progname = progname.substr(0, progname.size() - 3);
if (progname.ends_with(".sh") || progname.ends_with(".pl"))
return progname.substr(0, progname.size() - 3);
}
// looks for C and C++ programs
if (part[1].ends_with(".c") || part[1].ends_with(".cc"))
return part[0];
// i gots nufink
return nstring();
}
static bool
file_attr_noinst(fstate_src_ty *src)
{
return
(
src
&&
src->attribute
&&
attributes_list_find_boolean(src->attribute, "aemakegen:noinst")
);
}
bool
validation_man_pages::run(change::pointer cp)
{
//
// Don't check branches, only individual changes have control over
// the presence of man pages.
//
if (cp->was_a_branch())
return true;
//
// Don't perform this check for changes downloaded and applied by
// aedist, because the original developer is no longer in control.
//
if (was_downloaded(cp))
return true;
//
// Don't perform this check for change sets marked as owning a
// foreign copyright.
//
if (cp->attributes_get_boolean("foreign-copyright"))
return true;
//
// Look at every file in the (project + change set), building lists
// of program names and man page names.
//
nstring_list man_pages;
nstring_list programs;
for (long j = 0; ; ++j)
{
fstate_src_ty *src = change_file_nth(cp, j, view_path_extreme);
if (!src)
break;
nstring filename(src->file_name);
// remember man page names, but only sections 1 and 8
{
nstring progname = extract_man_page_details(filename);
if (!progname.empty())
{
man_pages.push_back_unique(progname);
}
}
// remember program names, but only installable ones
{
nstring progname = extract_progname_details(filename);
if
(
!progname.empty()
&&
!file_attr_noinst(src)
&&
!progname.starts_with("test_")
&&
!progname.starts_with("test-")
&&
!progname.starts_with("noinst_")
&&
!progname.starts_with("noinst-")
)
{
programs.push_back_unique(progname);
}
}
}
//
// Check each file in the change set.
// If a file is a part of a specific program,
// verify that the program has a man page.
//
unsigned number_of_errors = 0;
for (long j = 0; ; ++j)
{
fstate_src_ty *src = change_file_nth(cp, j, view_path_first);
if (!src)
break;
nstring filename(src->file_name);
nstring candidate = extract_progname_details_generous(filename);
if (!candidate.empty() && programs.member(candidate))
{
if (!man_pages.member(candidate))
{
sub_context_ty sc;
sc.var_set_string("File_Name", candidate);
change_error(cp, &sc, i18n("prog $filename has no man page"));
++number_of_errors;
}
// only check once per program
programs.remove(candidate);
}
}
return (number_of_errors == 0);
}
// vim: set ts=8 sw=4 et :