// // quickie - a small fast C++ Wiki Wiki // Copyright (C) 2005 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 2 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. // // MANIFEST: runtime start point // #include #include #include #include #include #include #include #include #include #include #include #include #include static int verbose; static time_t mod_time(const rcstring &path) { struct stat st; if (stat(path.c_str(), &st)) { if (errno != ENOENT) quitter.fatal_error_with_errno("stat \"%s\"", path.c_str()); return 0; } return st.st_mtime; } static bool walk_wiki(const rcstring &root, const rcstring &relative) { bool changed = false; assert(relative.ends_with(".wiki")); assert(relative[0] != '/'); rcstring user_path = "/" + relative.substring(0, relative.size() - 5); rcstring file_system_path = path_join(root, user_path); rcstring wiki_path = file_system_path + ".wiki"; assert(wiki_path == path_join(root, relative)); time_t wiki_mod_time = mod_time(wiki_path); rcstring html_path = file_system_path + ".html"; time_t html_mod_time = mod_time(html_path); if (html_mod_time <= wiki_mod_time) { // // Need to (re)generate the html file. // if (verbose >= 3) quitter.message("%s -> %s", wiki_path.c_str(), html_path.c_str()); file_regular temp(user_path, file_system_path); temp.synthesize(); changed = true; } rcstring svt_path = file_system_path + ",svt"; time_t svt_mod_time = mod_time(svt_path); if (svt_mod_time <= wiki_mod_time) { // // Need to (re)generate the ,svt file. // if (verbose >= 3) quitter.message("%s -> %s", wiki_path.c_str(), svt_path.c_str()); simple_version_tool svt(svt_path); svt.checkin(wiki_path); changed = true; } return changed; } static bool walk(const rcstring &root, const rcstring &relative) { rcstring path(path_join(root, relative)); struct stat st; if (stat(path.c_str(), &st) < 0) { if (errno == ENOENT) { // // Probably an HTML file deleted by this program, // to force a re-calc by a later pass. // return false; } quitter.fatal_error_with_errno("stat \"%s\"", path.c_str()); } if (S_ISREG(st.st_mode)) return (path.ends_with(".wiki") && walk_wiki(root, relative)); if (!S_ISDIR(st.st_mode)) return false; // // Read the directory contents. // if (verbose >= 2) quitter.message("%s...", path.c_str()); DIR *dirp = opendir(path.c_str()); if (!dirp) quitter.fatal_error_with_errno("opendir \"%s\"", path.c_str()); rcstring_list names; for (;;) { dirent *dep = readdir(dirp); if (!dep) break; if ( dep->d_name[0] == '.' && ( dep->d_name[1] == '\0' || dep->d_name[1] == '.' && dep->d_name[2] == '\0' ) ) continue; names.push_back(rcstring(dep->d_name)); } closedir(dirp); // // Now walk each entry. // // If any of the deeper entries terurns true (meaning, something // changed) then this function returns true, too. // bool changed = false; for (size_t j = 0; j < names.size(); ++j) { if (walk(root, path_join(relative, names[j]))) changed = true; } return changed; } static bool prime(const rcstring &dir) { // // Walk down the diurectory tree, looking for *.wiki files. // // If the .wiki file is newer than the ,svt file (or the ,svt file // doesn't exist) use SVT to checkin the .wiki file. // // If the .wiki file is newer than the .html file (or the .html file // doesn't exist) use wiki_to_html to regenerate the .html file. // return walk(dir, "."); } static void usage() { fprintf(stderr, "Usage: %s [ -D ][ -v ]\n", progname_get()); fprintf(stderr, " -D specify which directory to prime\n"); fprintf(stderr, " -v verbose progress messages\n"); quitter.exit(1); } static rcstring current_working_directory() { char buffer[3000]; if (!getcwd(buffer, sizeof(buffer))) quitter.fatal_error_with_errno("getcwd"); return buffer; } int main(int argc, char **argv) { rcstring dir; progname_set(argv[0]); for (;;) { int c = getopt(argc, argv, "D:v"); if (c == EOF) break; switch (c) { case 'D': config.database_read(); if (optarg[0] == '/') { config.set("localstatedir", optarg); } else { config.set ( "localstatedir", path_join(current_working_directory(), optarg) ); } break; case 'v': ++verbose; break; default: usage(); // NOTREACHED } } for (int pass = 1; ; ++pass) { if (verbose >= 1) quitter.message("Pass %d...", pass); if (!prime(config.get_localstatedir())) break; } quitter.exit(0); return 0; }