# 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: