diff --git a/blindspot.cpp b/blindspot.cpp index a36e366fa27fa1ae3b62a52e6973c65590fbc918..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/blindspot.cpp +++ b/blindspot.cpp @@ -1,486 +0,0 @@ -// blindspot -// For illinois.edu CS 225 spring 2011 -// By Jack Toole - -#include <iostream> -#include <fstream> -#include <map> -#include <sstream> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> -#include <vector> - -#include "util.h" -#include "output.h" - -using namespace std; -using namespace util; -using namespace output; - -namespace blindspot -{ -void find_base_dir(const char * argv0); -void printHelp(); -void printInfo(); -void processArgs(int argc, char ** argv); -void copyRequiredFiles(); -void getLibs(const vector<string> & libs); -string updateFolder(const string & folder, bool link); -string getFolder(const string & folder, bool link); -void importFiles(const string & preservedFolder, const string & sourceFolder, - const string & destFolder, const vector<string> & files); -void exec_command(const string & command); - -string name; - -string testsFolder; -string sourceFolder; -string gradeFolder; -string tempFolder; - -FileMap config; - -int8_t mp_part; -const int8_t no_mp_part = -1; - -namespace opts { -bool clean = true; -bool update = true; -bool staff = false; -#if OPTIMIZE -bool optimize = true; -#else -bool optimize = false; -#endif -} -} - -string kyleGetDate() { - string dateAndTime = "Current Date and Time: "; - - time_t currentTime; - struct tm * timeStructure; - time(¤tTime); - timeStructure = localtime(¤tTime); - dateAndTime += asctime(timeStructure); - - return dateAndTime; -} - - - -int main(int argc, char ** argv) -{ - using namespace blindspot; - - // Find blindspot/ directory - find_base_dir(argv[0]); - - // Read in local config settings. - // Necessary to do this early for [SVN Root] url - readConfig("./", config); - processArgs(argc, argv); - - cout << "CS 225 Conceptual Blindspot" << endl; - cout << "Testing " << name << "..." << endl << endl; - - cout << "Setting up test environment..." << endl; - - // Read in test-specific config settings - if (mp_part == no_mp_part) - readConfig(testsFolder, config); - else - readConfig(testsFolder, config, to_string((int)mp_part)); - - copyRequiredFiles(); - - // Sleep for a second to avoid clock skew warnings - // This cummulatively adds about 5 minutes to grade each mp, - // but with the benefit of avoiding newsgroup posts - // CHANGED: Judging by previous emails, the time needed for - // this would vary significantly. not sure about solution - // sleep(1); - - output::header("Compiling"); - chdir(gradeFolder.c_str()); - - // #define MP_PART_NUMBER in runtests - ofstream mp_part_file; - mp_part_file.open("_mp_part_number.h"); - if (mp_part == no_mp_part) - mp_part_file << "#define MP_PART_NUMBER NO_MP_PART" << endl; - else - mp_part_file << "#define MP_PART_NUMBER " << (int)mp_part << endl; - mp_part_file.close(); - - // run [Pre-Make Commands] config header - const vector<string> & processing_commands = config["Pre-Make Commands"]; - for (size_t i = 0; i < processing_commands.size(); i++) - exec_command(processing_commands[i]); - - string makestr = "/usr/bin/make --warn-undefined-variables"; - if (opts::optimize) - makestr += " OPTIMIZE=on"; - if (!config["Make Options"].empty()) - makestr += " " + config["Make Options"][0]; -#if DEBUG - cout << makestr <<endl; -#endif - - // Compile with make - system(makestr.c_str()); // yes, system is insecure if the user has control - // over config.ini. But students don't. - - cout << endl << endl; - int score = exec("./runtests"); - if (score < 0) - { - output::header("Running tests"); - cout << "Could not execute test cases" << endl << endl; - score = 0; - - cout << endl; - output::total_score(score); - } - - return score; -} - - -void blindspot::processArgs(int argc, char ** argv) -{ - // Create OptionsMap for options and vector for positional arguments: - OptionsMap options; - vector<string> args; - - // Add our possible options to our map - options.insert(make_pair("solution", false)); - options.insert(make_pair("newtests", true)); - options.insert(make_pair("clean", opts::clean)); - options.insert(make_pair("update", opts::update)); - options.insert(make_pair("staff", false)); - options.insert(make_pair("optimize", opts::optimize)); - options.insert(make_pair("help", false)); - options.insert(make_pair("h", false)); - options.insert(make_pair("info", false)); - - // Read in options and arguments - char * badopt = processOptions(argc, argv, options, args); - if (badopt != NULL) - exit(-1); - - // Save out options - bool solution = options["solution"]; - bool newtests = options["newtests"]; - opts::clean = options["clean"]; - opts::update = options["update"]; - opts::staff = options["staff"]; - - // Help - if (options["help"] || options["h"] || - (!args.empty() && strcasecmp(args[0].c_str(), "help") == 0)) - { - printHelp(); - exit(0); - } - - // Info - if (options["info"]) - { - printInfo(); - exit(0); - } - - // Check argument list length - if (args.empty() || args.size() > 1) - { - cout << "Usage: " << argv[0] << " mp1" << endl; - cout << "Run \'" << argv[0] << " --help\' for more information" << endl; - exit(0); - } - - // Find mp/lab name and tests folder - vector<string> splitname = tokenize(args[0], '.'); - name = splitname[0]; - if (splitname.size() == 1) - mp_part = no_mp_part; - else - mp_part = atoi(splitname[1].c_str()); - - // Clean - if (name == "clean") - { - system("/bin/rm -rf *_grade/ *_tests/ *_newtests/ *_solution/"); - exit(0); - } - - gradeFolder = "./" + name + "_grade/"; - if (!exists(gradeFolder)) opts::clean = true; - - if (opts::clean) - tempFolder = ""; - else - tempFolder = "./" + name + "_temp/"; - - // Find source folder (i.e. ../mp1) - if (solution) - sourceFolder = updateFolder(name + "_solution/", false); - else - sourceFolder = getFolder(name + '/', false); - - // tests folder - if (newtests) - testsFolder = updateFolder(name + "_newtests/", false); - else - testsFolder = updateFolder(name + "_tests/", false); -} - - -void blindspot::find_base_dir(const char * argv0) -{ - EXIT_IF_ERROR(argv0 == NULL); - size_t argv0len = strlen(argv0); - char * dir = new char[argv0len + 1]; - strncpy(dir, argv0, argv0len); - dir[argv0len] = '\0'; - - size_t i = argv0len + 1; - do - { - i--; - if (argv0[i] == '/') break; - } while (i != 0); - - // Change directory - if (i != 0) - { - dir[i] = '\0'; - EXIT_IF_ERROR(chdir(dir)); - } - delete [] dir; - - // Ensure the dir is correct - if (!exists("./.blindspotid")) - { - cerr << "Could not find blindspot directory. " - "Please run ./blindspot from the directory it is located in." - << endl; - exit(-1); - } -} - - -void blindspot::printHelp() -{ - cout << "Usage: blindspot ASSIGNMENT [solution]" << endl - << "Runs the tests for ASSIGNMENT (mp1, lab01, ...)" << endl - << "\'../ASSIGNMENT/\' must exist" << endl - << "If \'../ASSIGNMENT_tests/\' or any necessary library directories do not exist, these will be downloaded to ./ from SVN" << endl << endl - << "blindspot settings and individual test settings are stored in config.ini files" << endl - << "The following options are available for blindspot's ./config.ini:" << endl - << "[SVN Root]" << endl - << "; svn base url here (http://.../cs225/)" << endl - << "[Blindspot Files]" << endl - << "; Any files to be copied from blindspot ./ to ./ASSIGNMENT/ testing directory" << endl - << "; By default, runtests.cpp is used to run test cases:" << endl - << "runtests.cpp" << endl << endl - << "The following options are available for individual tests' ../ASSIGNMENT_tests/config.ini:" << endl - << "[Required Files]" << endl - << "; Any files that must be copied from the ../ASSIGNMENT directory" << endl - << "main.cpp" << endl - << "[Testing Files]" << endl - << "; Any files that must be copied from ../ASSIGNMENT_tests" << endl - << "; By default, unit_tests.cpp contains the test cases" << endl - << "unit_tests.cpp" << endl - << "[Libraries]" << endl - << "; Any external library folders to be present in the same directory as the" << endl - << "; testing directory. These should be mirrored in [SVN Root]/_public/" << endl - << "; The 'testutil' library in this directory is also available" << endl - << "EasyBMP" << endl - << endl; - -} - -void blindspot::printInfo() -{ - cout << "CS 225 Conceptual Blindspot" << endl - << "Version 1.0 : 2 February 2011" << endl - << "Developed by Jack Toole Spring 2011" << endl - << "Copyright 2011 Jack Toole" << endl - << "Full rights granted to Jack Toole. Rights to use and modify granted to" << endl - << "University of Illinois Urbana-Champaign Computer Science Data Structures" << endl - << "instructors and course staff" << endl; -} - - -void blindspot::copyRequiredFiles() -{ - // Clear out the temp testing folder - if (opts::clean) - forceRemoveDir(gradeFolder); - else - { - forceRemoveDir(tempFolder); - EXIT_IF_ERROR(rename(gradeFolder.c_str(), tempFolder.c_str())); - } - - exec("/bin/mkdir",gradeFolder.c_str()); - - // Copy and link appropriate files - parsed from config.ini - importFiles(tempFolder, "./", gradeFolder, config["Blindspot Files"]); - importFiles(tempFolder, testsFolder, gradeFolder, config["Testing Files"]); - importFiles("", sourceFolder, gradeFolder, config["Required Files"]); - importFiles(tempFolder, "", gradeFolder, config["Preserved Files"]); - - forceRemoveDir(tempFolder); - - getLibs(config["Libraries"]); -} - - -void blindspot::importFiles(const string & preservedFolder, const string & sourceFolder, - const string & destFolder, const vector<string> & files) -{ - // 0 for student errors for missing Required Files dir - int student_error_code = ((preservedFolder == "") ? 0 : -1); - - assertExists(destFolder); - if (preservedFolder != "") assertExists(preservedFolder); - if (sourceFolder != "") assertExists(sourceFolder, student_error_code); - - for (size_t i = 0; i < files.size(); i++) - { - string preservedFile = preservedFolder + files[i]; - string destFile = destFolder + files[i]; - - // Move the file from it's preservation instance - if (preservedFolder != "" && exists(preservedFile) && - (sourceFolder == "" || (permissions(preservedFile) & S_IWUSR) == 0)) - { -//!! cout << "mv " << preservedFile << ' ' << destFile << endl; - EXIT_IF_ERROR(rename(preservedFile.c_str(), destFile.c_str())); - } - else if (sourceFolder != "") - { - // copy the file from it's source - string sourceFile = sourceFolder + files[i]; - assertExists(sourceFile, student_error_code); -//!! cout << "cp " << sourceFile << ' ' << destFile << endl; - EXIT_IF_ERROR(exec("/bin/cp", sourceFile.c_str(), destFile.c_str()) != 0); - } - else continue; - - EXIT_IF_ERROR(chmod(destFile.c_str(), - S_IRUSR | (permissions(destFile) & S_IXUSR)) != 0); - } -} - - -void blindspot::getLibs(const vector<string> & libs) -{ - for (size_t lib_i = 0; lib_i < libs.size(); lib_i++) - { - string folder = updateFolder(libs[lib_i], false); - protectDir(folder); - chdir(gradeFolder.c_str()); - system(("/bin/ln -s ../"+folder+"* ./").c_str()); - chdir(".."); - } -} - -string blindspot::updateFolder(const string & folder, bool link) -{ - string get = getFolder(folder, link); - if (opts::update) - exec(-1, "/usr/bin/svn","up", get.c_str()); - return get; -} - -string blindspot::getFolder(const string & folder, bool link) -{ - // Look in the current folder - string target = "./" + folder; - if (exists(target + "/")) - return target + "/"; - - // Look in the parent folder - string source = "../" + folder; - if (exists(source + "/")) - { - if (!link) return source + "/"; - EXIT_IF_ERROR(symlink(source.c_str(), target.c_str()) != 0); - return target + "/"; - } - - // Maybe it actually *is* the parent folder - string cwd = getcwdstr(); - size_t cwd_i = findNthLast(cwd, '/', 2); - if (cwd_i != string::npos && - cwd.length() - cwd_i > folder.length() && - cwd.compare(cwd_i, folder.length(), folder) == 0) - { - if (!link) return "../"; - EXIT_IF_ERROR(symlink("../", target.c_str()) != 0); - return target + "/"; - } - - // Look two directories up and over - why not? If the parent folder is - // the target source folder for the mp/lab, then the tests or libs - // may be two up and over - source = "../../" + folder; - if (exists(source + "/")) - { - if (!link) return source + "/"; - EXIT_IF_ERROR(symlink(source.c_str(), target.c_str()) != 0); - return target + "/"; - } - - // Check Subversion - - const char * svn_config_name = NULL; - const char * svn_subdir = NULL; - if (!opts::staff) - { - svn_config_name = "SVN Root"; - svn_subdir = "/_public/"; - } - else - { - svn_config_name = "Staff SVN"; - svn_subdir = "/_current/"; - } - if (!config[svn_config_name].empty()) - { - string svndir = config[svn_config_name][0] + svn_subdir + folder; - - int svnstatus = exec("/usr/bin/svn","co",svndir.c_str()); // No redirect, need user to type password - if (svnstatus == 0) return target + "/"; - } - - cerr << "Error: " << folder << " not found." << endl; - exit(-1); - return ""; -} - - -// Execute a blindspot or command line command -void blindspot::exec_command(const string & command) -{ - vector<string> args = tokenize(command, ' '); - - // Allow processing of special internals - if (args[0] == "rename_main") - { - EXIT_IF_ERROR(args.size() != 3, "rename_main must take 2 arguments: a file and a new name"); - rename_main(args[1], args[2]); - return; - } - - system(command.c_str()); -} - - -