/* Splits up a full_name into it's component parts: archive, category, etc. The branch and revision are returned as fully qualified names including the archive. Copyright 2002, 2003 Walter Landry and the Regents of the University of California. Copyright (C) 2004 Walter Landry 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-1307 USA */ #include #include "boost/regex.hpp" #include "get_config_option.hpp" #include "Component_Regexes.hpp" #include "arx_error.hpp" #include "gvfs.hpp" #include "create_archive_registration.hpp" #include "Parsed_Name.hpp" #include "boost/filesystem/operations.hpp" #include "read_archive_locations.hpp" using namespace std; using namespace boost; namespace fs=boost::filesystem; using fs::path; void Parsed_Name::parse_package_name(bool require_archive) { Component_Regexes component_regex; /* If passed the null string, just return the default archive. */ if(Full_Name.empty()) { throw arx_error("Empty name passed to parse_package_name"); } /* Get the archive name */ match_results m; string package_name; if(regex_search(Full_Name,m,regex("/[^/]*$"))) { Archive=Full_Name.substr(0,m[-1].length()); package_name=Full_Name.substr(m[-1].length()+1); /* If we just have a uri, not the actual archive name, then automatically get the archive name and register the archive. */ if(regex_search(Archive,m,regex(":"))) { gvfs::Init(); /* Set the location for the archive to the uri provided. */ Archive_Location=Archive; if(gvfs::exists(Archive_Location/",meta-info/name")) { Archive=gvfs::read_archive(Archive_Location/",meta-info/name"); create_archive_registration(Archive,Archive_Location.string()); } else { throw arx_error("Can't read the archive rooted at " + Archive); } } if(!regex_match(Archive,component_regex.archive)) { throw arx_error("Invalid archive name: " + Archive); } /* If it is just an archive appended with "/", return. This is rather ugly, since we're returning in the middle of a long function. */ if(package_name.empty()) return; } else { if(require_archive) { throw arx_error("Archive name required: " + Full_Name); } else { Archive=get_config_option("default-archive"); if(Archive.empty()) throw arx_error("No default archive set and no archive specified\n\t" + Full_Name + "\nTo set a default archive, use \"arx param default-archive \".\nTo specify the archive in the name, for an archive \"foo\" and\na branch \"bar\", the syntax is \"foo/bar\"."); package_name=Full_Name; } } /* Get all of the components */ vector temp_list; int num_components=regex_split(back_inserter(temp_list),package_name, regex(",")); if(num_components==2) { if(regex_match("," + temp_list[1],component_regex.revision)) { Short_Revision=temp_list[1]; } else { throw arx_error("Bad revision name: " + temp_list[1]); } } num_components=regex_split(back_inserter(components),temp_list[0], regex("\\.")); if(num_components==0) { throw arx_error("Bad package name: " + package_name + "\nIt is entirely composed of separators"); } for(list::iterator i=components.begin(); i!=components.end(); ++i) { if(!regex_match(*i,component_regex.component)) throw arx_error("Bad branch name: " + *i); } } bool Parsed_Name::is_subbranch(const Parsed_Name &p) const { if(p.empty()) return true; if(p.Archive!=Archive) return false; std::list::const_iterator i=components.begin(), j=p.components.begin(); while(i!=components.end() && j!=p.components.end()) { if(*i!=*j) return false; ++i; ++j; } if(j==p.components.end()) return true; return false; } /* Return the location association with an archive. If the location is already known (e.g. because it was directly specified), then just that is returned. Otherwise, it reads the archive registration to find out. Since an archive can have multiple registered locations, it returns the first one. */ gvfs::uri Parsed_Name::archive_location() const { if(Archive_Location.empty()) { if(Archive.empty()) throw arx_error("Empty archive name passed to archive_location"); path home(getenv("HOME")); path config_path(home / ".arx/archives" / Archive / "uri"); list locations; if(!lexists(config_path)) { throw arx_error("Archive is not registered: " + Archive); } else { locations=read_archive_locations(config_path); if(locations.empty()) { throw arx_error("Error when reading location file for " + Archive); } } Archive_Location=gvfs::uri(*locations.begin()); } return Archive_Location; }