# Part of the A-A-P recipe executive: Generic Version Control # Copyright (C) 2002 Stichting NLnet Labs # Permission to copy and use this file is specified in the file COPYING. # If this file is missing you can find it here: http://www.a-a-p.org/COPYING # # Functions to get files out of a version control system and put them back. # Most of the work is directed to one of the modules for a specific version # control system. # Uploading/downloading is done by functions in Remote.py. # import os import string from Process import recipe_error from Cvs import * from Work import getwork from Node import Node def separate_scheme(url): """Isolate the scheme of the URL.""" # TODO: how about "file:~user"? i = string.find(url, "://") if i < 0: raise UserError, _('No :// found in "%s"') % url scheme = string.lower(url[:i]) for c in scheme: if not c in string.lowercase: raise UserError, _('Illegal character before colon in "%s"') % url return scheme, url[i + 3:] def verscont_command(globals, dict, node, use_cache, action): """Try performing "action" on node "node" from the semi-URL "dict["name"]". May Use a cached file when "use_cache" is non-zero. Returns non-zero when it succeeds.""" scheme, name = separate_scheme(dict["name"]) # Handle a scheme for which there is a scheme_command() function. if globals.has_key(scheme + "_command"): return globals[scheme + "_command"](name, dict, [ node ], command) # Handle the "cvs://" scheme. if scheme == "cvs": return cvs_command(name, dict, [ node ], action) # Assume it's a normal URL, try downloading/uploading/removing the file. if action in ["refresh", "checkout"]: return download_file(globals, dict, node, use_cache) if action in ["commit", "checkin", "publish", "add"]: return upload_file(globals) if action == "remove": return remote_remove(globals) return 0 def handle_node(rpstack, globals, node, use_cache, action, attrnames): """Common code for refreshing, committing, etc. "action" is the name of the command: "refresh", "commit", etc. "attrnames" is a list of attribute names that can be used. """ # Use the first attribute that exists and isn't empty. attr = '' for n in attrnames: if node.attributes.has_key(n): attr = node.attributes[n] if attr: break if not attr: recipe_error(rpstack, _("Missing %s attribute for %s") % (attrnames[0], node.short_name())) # Replace all occurences of "%file%" with the node name (relative to the # recipe it was specified in). while 1: i = string.find(attr, "%file%") if i < 0: break attr = attr[:i] + node.name + attr[i+6:] from Dictlist import string2dictlist list = string2dictlist(rpstack, attr) if not list: recipe_error(rpstack, _("%s attribute for %s is empty") % (attrname, node.short_name())) # Loop over the list of refresh locations. Quit as soon as refreshing # worked. for org in list: # Try downloading this node, return when it worked if verscont_command(globals, org, node, use_cache, action): return 1 return 0 def refresh_node(rpstack, globals, node, use_cache): """Refresh "node" according to its "refresh" attribute. When there is no "refresh" attribute use "commit". Only use cached files when "use_cache" is non-zero. Return non-zero for success.""" return handle_node(rpstack, globals, node, use_cache, "refresh", [ "refresh", "commit" ]) def verscont_node(rpstack, globals, node, action): """Checkout "node" according to its "commit" attribute. When there is no "commit" attribute use "refresh". Return non-zero for success.""" return handle_node(rpstack, globals, node, 0, action, [ "commit" ]) def publish_node(rpstack, globals, node): """Publish "node" according to its "publish" attribute. When there is no "publish" attribute use "commit". Return non-zero for success.""" return handle_node(rpstack, globals, node, 0, "publish", [ "publish", "commit" ]) def verscont_removeall(rpstack, globals, dir, recursive): """Remove all files in directory "dir" of VCS that don't belong there. "dir" is a dictionary for the directory and its attributes. Enter directories recursively when "recursive" is non-zero. """ if not dir.has_key("commit"): recipe_error(rpstack, _("no commit attribute for %s") % dir["name"]) from Dictlist import string2dictlist commit_list = string2dictlist(rpstack, dir["commit"]) if not commit_list: recipe_error(rpstack, _("commit attribute for %s is empty") % dir["name"]) dirname = os.path.abspath(dir["name"]) list = None for commit_item in commit_list: scheme, name = separate_scheme(commit_item["name"]) # Handle a scheme for which there is a scheme_list() function. if globals.has_key(scheme + "_list"): list = globals[scheme + "_list"](name, commit_item, dirname, recursive) break # Handle the "cvs://" scheme. if scheme == "cvs": list = cvs_list(name, commit_item, dirname, recursive) break if list is None: recipe_error(rpstack, _("No working item in commit attribute for %s") % dir["name"]) # Loop over all items found in the VCS. work = getwork(globals) for item in list: node = work.find_node(item) if not node or not node.attributes.has_key("commit"): if not node: node = Node(item) # Do something with errors? verscont_command(globals, commit_item, node, 0, "remove") # vim: set sw=4 sts=4 tw=79 fo+=l: .