// // aegis - project change supervisor // Copyright (C) 2006-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 #include #include // for assert #include #include #include #include #include #include #include #include repository_subversion::~repository_subversion() { trace(("repository_subversion::~repository_subversion()\n")); } repository_subversion::repository_subversion() { trace(("repository_subversion::repository_subversion()\n")); } void repository_subversion::checkout(const nstring &a_mod, const nstring &a_dir) { trace(("repository_subversion::checkout(module = %s, directory = %s)\n{\n", a_mod.quote_c().c_str(), a_dir.quote_c().c_str())); module = a_mod; assert(!module.empty()); if (!strstr(module.c_str(), ":/")) fatal_raw("must specify the repository URL for the module"); directory = a_dir; if (directory.empty()) directory = nstring(os_edit_filename(0)); else if (directory[0] != '/') directory = os_path_cat(nstring(os_curdir()), directory); // // If anything goes wrong from here, remove the checkout directory // and everything below it. // undo_rmdir_bg(directory); // // Run the subversion checkout command. // nstring command = "svn checkout" + auth + " " + module.quote_shell() + " " + directory.quote_shell(); int flags = 0; os_execute(command, flags, os_dirname_relative(directory)); trace(("}\n")); } nstring repository_subversion::get_directory() const { return directory; } void repository_subversion::remove_file(const nstring &file_name) { trace(("repository_subversion::remove_file(file_name = %s)\n{\n", file_name.quote_c().c_str())); nstring path = os_path_cat(directory, file_name); nstring command = "svn delete --force " + path.quote_shell(); int flags = 0; os_execute(command, flags, directory); trace(("}\n")); } void repository_subversion::add_file(const nstring &file_name, const nstring &from) { trace(("repository_subversion::add_file(file_name = %s, from = %s)\n{\n", file_name.quote_c().c_str(), from.quote_c().c_str())); // // Make sure all the directories exist, // and subversion add them if they don't. // for (const char *cp = file_name.c_str(); *cp; ++cp) { if (*cp != '/') continue; nstring s1(file_name.c_str(), cp - file_name.c_str()); nstring s2(os_path_cat(directory, s1)); if (!os_exists(s2)) { trace(("mkdir %s\n", s2.c_str())); os_mkdir(s2, 0755); nstring command = "svn add --non-recursive " + s2.quote_shell(); int flags = 0; os_execute(command, flags, directory); } } // // Copy the baseline file into the subversion work area. // nstring dest = os_path_cat(directory, file_name); copy_whole_file(from, dest, false); // // Now let subversion know it is supposed to manage this new file. // nstring command = "svn add " + dest.quote_shell(); int flags = 0; os_execute(command, flags, directory); // // FIXME: Subversion has file properties, do we want to set // properties from the file Aegis attributes? // trace(("}\n")); } void repository_subversion::modify_file(const nstring &filename, const nstring &from) { trace(("repository_subversion::modify_file(filename = %s, from = %s)\n{\n", filename.quote_c().c_str(), from.quote_c().c_str())); // // Copy the baseline file into the subversion work area. // No special command lets subversion know it was changed. // copy_whole_file(from, os_path_cat(directory, filename), false); trace(("}\n")); } void repository_subversion::rename_file(const nstring &old_file_name, const nstring &new_file_name, const nstring &from) { trace(("repository_subversion::rename_file(old_file_name = %s, " "new_file_name = %s, from = %s)\n{\n", old_file_name.quote_c().c_str(), new_file_name.quote_c().c_str(), from.quote_c().c_str())); // // Make sure all the directories exist, // and subversion add them if they don't. // for (const char *cp = new_file_name.c_str(); *cp; ++cp) { if (*cp != '/') continue; nstring s1(new_file_name.c_str(), cp - new_file_name.c_str()); nstring s2(os_path_cat(directory, s1)); if (!os_exists(s2)) { trace(("mkdir %s\n", s2.c_str())); os_mkdir(s2, 0755); nstring command = "svn add --non-recursive " + s2.quote_shell(); int flags = 0; os_execute(command, flags, directory); } } // // Now let subversion know the file moved. // nstring command = "svn move " + old_file_name.quote_shell() + " " + new_file_name.quote_shell(); int flags = 0; os_execute(command, flags, directory); // // Copy the baseline file into the subversion work area. // There is no special subversion command to let it know he content // changed (if it did) subversion will work it out for itself. // nstring dest = os_path_cat(directory, new_file_name); copy_whole_file(from, dest, false); trace(("}\n")); } void repository_subversion::file_attribute(const nstring &filename, const nstring &attribute_name, const nstring &attribute_value) { nstring attribute_lname = attribute_name.downcase(); if (attribute_lname == "content-type") attribute_lname = "svn:mime-type"; else if (attribute_lname == "executable") attribute_lname = "svn:executable"; else if (!strchr(attribute_lname.c_str(), ':')) attribute_lname = "aegis:" + attribute_lname; nstring dest = os_path_cat(directory, filename); nstring command = "svn propset -q " + attribute_lname.quote_shell() + " " + attribute_value.quote_shell() + " " + dest.quote_shell(); int flags = 0; os_execute(command, flags, directory); } void repository_subversion::commit(const nstring &comment) { trace(("repository_subversion::commit(comment = %s)\n{\n", comment.quote_c().c_str())); // // Give all of the files to subversion // // FIME: how do you set the author field for the checkin? It // would be nice to use that option to set the developer, rather // than the project owner. // nstring command = "svn commit -m " + comment.quote_shell() + " --non-interactive" + auth; int flags = 0; os_execute(command, flags, directory); // // Get rid of the work area. // os_rmdir_tree(directory); trace(("}\n")); } void repository_subversion::change_specific_attributes(change::pointer cp) { // // Subversion is a PITA when it comes to background execution. // It repeatedly fails with "Can't get password" errors. As a // work-around for the problem, specify the username and password on // the command line, via the svn:username and svn:password project // specific attributes. // attributes_ty *psp = 0; pconf_ty *pconf_data = change_pconf_get(cp, 0); assert(pconf_data); if (!pconf_data->project_specific) return; psp = attributes_list_find(pconf_data->project_specific, "svn:username"); if (psp) auth += " --username=" + nstring(psp->value).quote_shell(); psp = attributes_list_find(pconf_data->project_specific, "svn:password"); if (psp) auth += " --password=" + nstring(psp->value).quote_shell(); }