// // aegis - project change supervisor // Copyright (C) 2004-2008, 2011-2014 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 #include #include #include #include #include #include #include #include module_project::~module_project() { pp->free(); pp = 0; } module_project::module_project(project *arg) : pp(arg) { } void module_project::groan(server_ty *sp, const char *request_name) { server_error ( sp, "%s: project \"%s\": you may not alter project files directly, you " "must use an Aegis change instead, and the corresponding module", request_name, project_name_get(pp).c_str() ); } void module_project::modified(server_ty *sp, string_ty *, file_info_ty *, const input::pointer &) { // // It is an error to try to write a project file. // groan(sp, "Modified"); } string_ty * module_project::calculate_canonical_name() const { return project_name_get(pp).get_ref_copy(); } bool module_project::update(server_ty *sp, string_ty *, string_ty *server_side_0, const options &opt) { // // Form a list of files by unioning the source files of the project // and all the ancestor branches together. // // For each of these files, send information about their contents. // for (size_t j = 0; ; ++j) { fstate_src_ty *src; string_ty *client_side; string_ty *server_side; string_ty *path; int mode; string_ty *version; file_info_ty *fip; src = pp->file_nth(j, view_path_extreme); if (!src) break; switch (src->usage) { case file_usage_build: continue; case file_usage_source: case file_usage_config: case file_usage_test: case file_usage_manual_test: break; } switch (src->action) { case file_action_remove: continue; case file_action_transparent: assert(0); continue; case file_action_create: case file_action_modify: case file_action_insulate: break; } // // Make sure the client creates the directories for us. // server_side = os_path_cat(name(), src->file_name); if (!is_update_prefix(server_side_0, server_side, opt.d)) { // // don't create files which are not under one of the // Directories specified by the client. // str_free(server_side); continue; } client_side = server_directory_calc_client_side(sp, server_side); // // Make sure the directory exists. // server_mkdir_above(sp, client_side, server_side); server_updating_verbose(sp, client_side); // // Determine where to get the file from. // bool need_to_unlink = false; path = pp->file_version_path(src, need_to_unlink); os_become_orig(); input::pointer ip = input_file::open(nstring(path), need_to_unlink); os_become_undo(); str_free(path); // // Determine the file mode. // mode = 0666; if (src->executable) mode |= 0111; mode &= ~project_umask_get(pp); // // Determine the version string to send to the client. // Special cases: // "" - no user file, // "0" - new user file, // "-" - user file to be removed // version = 0; switch (src->action) { case file_action_remove: version = str_from_c("-"); break; case file_action_transparent: version = str_from_c("0"); break; case file_action_create: case file_action_modify: case file_action_insulate: if (src->edit && src->edit->revision) version = str_copy(src->edit->revision); else version = str_from_c("0"); break; } if (!version) version = str_from_c(""); // // Queue the response to be sent. // fip = server_file_info_find(sp, server_side, 0); if (!fip) { server_response_queue ( sp, new response_created ( client_side, server_side, ip, mode, version ) ); } else if (str_equal(fip->version, version)) { // // What they copied the first time is still the current // version on the server side. // if (fip->modified > 0) { string_ty *sub; // // Remind them they need to commit it. // Except they can't, bwah ha ha ha. // sub = os_entryname(client_side); server_m(sp, "M %s (oops)\n", sub->str_text); str_free(sub); } } else { server_response_queue ( sp, new response_update_existing ( client_side, server_side, ip, mode, version ) ); } str_free(server_side); str_free(client_side); str_free(version); os_become_orig(); ip.reset(); os_become_undo(); } return true; } bool module_project::checkin(server_ty *sp, string_ty *, string_ty *) { groan(sp, "ci"); return false; } bool module_project::add(server_ty *sp, string_ty *, string_ty *, const options &) { groan(sp, "add"); return false; } bool module_project::remove(server_ty *sp, string_ty *, string_ty *, const options &) { groan(sp, "remove"); return false; } module_ty * module_project_new(string_ty *project_name) { project *pp = project_alloc(project_name); if (!pp->bind_existing_errok()) { pp->free(); return new module_project_bogus(project_name); } return new module_project(pp); } // vim: set ts=8 sw=4 et :