import string
import os
import os.path
from Error import *
from Message import *
from Util import *
def cvs_command(recdict, server, url_dict, nodelist, action):
"""Handle CVS command "action".
Return non-zero when it worked."""
if action == "fetch":
action = "checkout"
elif action in [ "checkin", "publish" ]:
action = "commit"
elif action == "unlock":
return []
if not server:
try:
f = open("CVS/Root")
except StandardError, e:
msg_extra(recdict,
_('Cannot open for obtaining CVSROOT: "CVS/Root"') + str(e))
else:
try:
server = f.readline()
f.close()
except StandardError, e:
msg_warning(recdict,
_('Cannot read for obtaining CVSROOT: "CVS/Root"') + str(e))
server = ''
else:
if server[-1] == '\n':
server = server[:-1]
if server:
serverarg = "-d" + server
else:
serverarg = ''
failed = []
if action == "tag":
todolist = nodelist[:]
while todolist:
tag = ''
thislist = []
for node in todolist[:]:
if not node.attributes.has_key("tag"):
msg_error(recdict, _('tag attribute missing for "%s"')
% node.short_name())
failed.extend(todolist)
failed.extend(thislist)
return failed
if not tag or node.attributes["tag"] == tag:
thislist.append(node)
todolist.remove(node)
tag = node.attributes["tag"]
f = cvs_tag(recdict, serverarg, tag, thislist)
if f:
failed.extend(f)
else:
for node in nodelist:
if not cvs_command_node(recdict, serverarg, url_dict, node, action):
failed.append(node)
return failed
def cvs_prepare(recdict):
"""
Prepare for using the cvs command. Returns the program name.
"""
from DoInstall import assert_pkg
assert_pkg([], recdict, "cvs")
if os.environ.get("HOME"):
fn = os.path.expanduser("~/.cvspass")
if not os.path.exists(fn):
from Commands import touch_file
touch_file(fn, 0644)
n = get_var_val(0, recdict, "_no", "CVSCMD")
if n:
return n
return get_progname(recdict, "CVS", "cvs", "")
def cvs_tag(recdict, serverarg, tag, nodelist):
"""Handle CVS tag command for a list of nodes.
Return list of nodes that failed."""
msg_info(recdict, _('CVS tag for nodes %s')
% str(map(lambda x: x.short_name(), nodelist)))
cvscmd = cvs_prepare(recdict)
names = ''
for node in nodelist:
names = names + '"' + node.short_name() + '" '
if logged_system(recdict,
'"%s" %s tag "%s" %s' % (cvscmd, serverarg, tag, names)) == 0:
return []
return nodelist
def cvs_get_repository(recdict, dir):
"""Get the first line of the CVS/Repository file in directory "dir"."""
cvspath = ''
fname = os.path.join(dir, "CVS/Repository")
try:
f = open(fname)
except StandardError, e:
if os.path.exists(os.path.join(dir, "CVS")):
msg_warning(recdict,
(_('Cannot open for obtaining path in module: "%s"')
% fname) + str(e))
else:
try:
cvspath = f.readline()
f.close()
except StandardError, e:
msg_warning(recdict,
(_('Cannot read for obtaining path in module: "%s"')
% fname) + str(e))
else:
if cvspath[-1] == '\n':
cvspath = cvspath[:-1]
return cvspath
def cvs_command_node(recdict, serverarg, url_dict, node, action):
"""Handle CVS command "action" for one node.
Return non-zero when it worked."""
msg_info(recdict, _('CVS %s for node "%s"') % (action, node.short_name()))
n = node.short_name()
dirlevels = 0
while n:
prev = n
n = os.path.dirname(n)
if n == prev:
break
dirlevels = dirlevels + 1
if action == "checkout":
cvspath = ''
if url_dict.has_key("path"):
cvspath = url_dict["path"]
dir_for_path = node.recipe_dir
else:
if os.path.isdir(os.path.join(node.absname, "CVS")):
dir_for_path = node.absname
else:
dir_for_path = os.path.dirname(node.absname)
cvspath = cvs_get_repository(recdict, dir_for_path)
adir = fname_fold(dir_for_path)
path = fname_fold(cvspath)
while path:
if os.path.basename(adir) != os.path.basename(path):
msg_note(recdict, _('mismatch between path in cvs:// and tail of recipe directory: "%s" and "%s"') % (cvspath, dir_for_path))
break
ndir = os.path.dirname(adir)
if ndir == adir:
msg_error(recdict, _('path in cvs:// is longer than recipe directory: "%s" and "%s"') % (cvspath, dir_for_path))
break
adir = ndir
npath = os.path.dirname(path)
if npath == path:
break
path = npath
if not path:
break
p = cvs_get_repository(recdict, adir)
if not p:
break
if fname_fold(os.path.basename(p)) != os.path.basename(path):
msg_note(recdict, _('mismatch between contents of CVS/Repository at different levels: "%s" and "%s"') % (adir, path))
break
else:
adir = os.path.dirname(node.absname)
if url_dict.has_key("logentry"):
logentry = url_dict["logentry"]
elif node.attributes.has_key("logentry"):
logentry = node.attributes["logentry"]
else:
logentry = get_var_val_int(recdict, "LOGENTRY")
cwd = os.getcwd()
if fname_equal(cwd, adir):
cwd = ''
else:
try:
os.chdir(adir)
except StandardError, e:
msg_warning(recdict,
(_('Could not change to directory "%s"') % adir) + str(e))
return 0
msg_log(recdict, 'Cvs command in "%s"' % adir)
node_name = node.short_name()
tmpname = ''
if action == "remove" and os.path.exists(node_name):
assert_aap_dir(recdict)
tmpname = in_aap_dir(node_name)
try:
os.rename(node_name, tmpname)
except:
tmpname = ''
try:
if node.attributes.get("binary"):
addbinarg = "-kb"
else:
addbinarg = ""
ok = exec_cvs_cmd(recdict, serverarg, action, addbinarg,
logentry, node_name, dirlevels = dirlevels)
if ok and action in [ "remove", "add" ]:
ok = exec_cvs_cmd(recdict, serverarg, "commit", "", logentry,
node_name, dirlevels = dirlevels, auto_add = 0)
finally:
if tmpname:
try:
os.rename(tmpname, node_name)
except StandardError, e:
msg_error(recdict, (_('Could not move file "%s" back to "%s"')
% (tmpname, node_name)) + str(e))
if cwd:
try:
os.chdir(cwd)
except StandardError, e:
msg_error(recdict, (_('Could not go back to directory "%s"')
% cwd) + str(e))
return ok
def exec_cvs_cmd(recdict, serverarg, action, addbinarg, logentry, node_name,
dirlevels = 1, auto_add = 1):
"""Execute the CVS command for "action". Handle failure.
For "commit" may create directories up to "dirlevels" upwards.
When "auto_add" is non-zero and committing fails, try to add the file
first.
Return non-zero when it worked."""
cvscmd = cvs_prepare(recdict)
if logentry:
logarg = '-m "%s"' % logentry
else:
logarg = ''
if action == "commit":
did_add_dir = 0
while 1:
cmd = ('"%s" %s commit %s "%s"'
% (cvscmd, serverarg, logarg, node_name))
ok, text = redir_system_int(recdict, cmd)
if text:
msg_log(recdict, text)
if ((string.find(text, "no version here") >= 0
or string.find(text, "not open CVS/Entries") >= 0)
and not did_add_dir
and auto_add):
msg_info(recdict, _("Directory does not appear to exist in repository, adding it"))
commit_dir(recdict, node_name, serverarg, dirlevels, cvscmd)
did_add_dir = 1
continue
if ok and (string.find(text, "nothing known about") >= 0
or string.find(text, "cvs add") >= 0):
ok = 0
break
if ok or not auto_add or string.find(text, "Up-to-date check failed") >= 0:
return ok
try:
msg_info(recdict,
_("File does not appear to exist in repository, adding it"))
logged_system(recdict, '"%s" %s add %s "%s"'
% (cvscmd, serverarg, addbinarg, node_name))
except StandardError, e:
msg_warning(recdict, _('Adding file failed: ') + str(e))
return logged_system(recdict, '"%s" %s commit %s "%s"'
% (cvscmd, serverarg, logarg, node_name)) == 0
if action != "add":
addbinarg = ""
return logged_system(recdict, '"%s" %s %s %s "%s"'
% (cvscmd, serverarg, action, addbinarg, node_name)) == 0
def commit_dir(recdict, node_name, serverarg, dirlevels, cvscmd):
"""Commit to create the current directory. If its parent is not in CVS
either go up further."""
cwd = os.getcwd()
try:
os.chdir("..")
dirname = os.path.dirname(node_name)
if not dirname:
dirname = os.path.basename(cwd)
if dirlevels > 0 and not os.path.isdir("CVS"):
commit_dir(recdict, dirname, serverarg, dirlevels - 1, cvscmd)
logged_system(recdict, '"%s" %s add "%s"'
% (cvscmd, serverarg, dirname))
except:
pass
os.chdir(cwd)
def cvs_list(recdict, name, commit_item, dirname, recursive):
"""Obtain a list of items in CVS for directory "dirname".
Recursively entry directories if "recursive" is non-zero.
"name" is not used, we don't access the server."""
fname = os.path.join(dirname, "CVS/Entries")
try:
f = open(fname)
except StandardError, e:
msg_error(recdict, (_('Cannot open "%s": ') % fname) + str(e))
return []
try:
lines = f.readlines()
f.close()
except StandardError, e:
msg_error(recdict, (_('Cannot read "%s": ') % fname) + str(e))
return []
res = []
for line in lines:
s = string.find(line, "/")
if s < 0:
continue
s = s + 1
e = string.find(line, "/", s)
if e < 0:
continue
item = os.path.join(dirname, line[s:e])
if line[0] == 'D' and recursive:
res.extend(cvs_list(recdict, name, commit_item, item, 1))
else:
res.append(item)
return res