1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2004-2007 Zuza Software Foundation
#
# This file is part of translate.
#
# translate 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.
#
# translate 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 translate; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
from translate.storage.versioncontrol import run_command
from translate.storage.versioncontrol import GenericRevisionControlSystem
def is_available():
"""check if cvs is installed"""
exitcode, output, error = run_command(["cvs", "--version"])
return exitcode == 0
class cvs(GenericRevisionControlSystem):
"""Class to manage items under revision control of CVS."""
RCS_METADIR = "CVS"
SCAN_PARENTS = False
def _readfile(self, cvsroot, path, revision=None):
"""
Read a single file from the CVS repository without checking out a full
working directory.
@param cvsroot: the CVSROOT for the repository
@param path: path to the file relative to cvs root
@param revision: revision or tag to get (retrieves from HEAD if None)
"""
command = ["cvs", "-d", cvsroot, "-Q", "co", "-p"]
if revision:
command.extend(["-r", revision])
# the path is the last argument
command.append(path)
exitcode, output, error = run_command(command)
if exitcode != 0:
raise IOError("[CVS] Could not read '%s' from '%s': %s / %s" % \
(path, cvsroot, output, error))
return output
def getcleanfile(self, revision=None):
"""Get the content of the file for the given revision"""
parentdir = os.path.dirname(self.location_abs)
cvsdir = os.path.join(parentdir, "CVS")
cvsroot = open(os.path.join(cvsdir, "Root"), "r").read().strip()
cvspath = open(os.path.join(cvsdir, "Repository"), "r").read().strip()
cvsfilename = os.path.join(cvspath, os.path.basename(self.location_abs))
if revision is None:
cvsentries = open(os.path.join(cvsdir, "Entries"), "r").readlines()
revision = self._getcvstag(cvsentries)
if revision == "BASE":
cvsentries = open(os.path.join(cvsdir, "Entries"), "r").readlines()
revision = self._getcvsrevision(cvsentries)
return self._readfile(cvsroot, cvsfilename, revision)
def update(self, revision=None):
"""Does a clean update of the given path"""
working_dir = os.path.dirname(self.location_abs)
filename = self.location_abs
filename_backup = filename + os.path.extsep + "bak"
# rename the file to be updated
try:
os.rename(filename, filename_backup)
except OSError, error:
raise IOError("[CVS] could not move the file '%s' to '%s': %s" % \
(filename, filename_backup, error))
command = ["cvs", "-Q", "update", "-C"]
if revision:
command.extend(["-r", revision])
# the filename is the last argument
command.append(os.path.basename(filename))
# run the command within the given working_dir
exitcode, output, error = run_command(command, working_dir)
# restore backup in case of an error - remove backup for success
try:
if exitcode != 0:
os.rename(filename_backup, filename)
else:
os.remove(filename_backup)
except OSError:
pass
# raise an error or return successfully - depending on the CVS command
if exitcode != 0:
raise IOError("[CVS] Error running CVS command '%s': %s" \
% (command, error))
else:
return output
def commit(self, message=None, author=None):
"""Commits the file and supplies the given commit message if present
the 'author' parameter is not suitable for CVS, thus it is ignored
"""
working_dir = os.path.dirname(self.location_abs)
filename = os.path.basename(self.location_abs)
command = ["cvs", "-Q", "commit"]
if message:
command.extend(["-m", message])
# the filename is the last argument
command.append(filename)
exitcode, output, error = run_command(command, working_dir)
# raise an error or return successfully - depending on the CVS command
if exitcode != 0:
raise IOError("[CVS] Error running CVS command '%s': %s" \
% (command, error))
else:
return output
def _getcvsrevision(self, cvsentries):
"""returns the revision number the file was checked out with by looking
in the lines of cvsentries
"""
filename = os.path.basename(self.location_abs)
for cvsentry in cvsentries:
# an entries line looks like the following:
# /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
cvsentryparts = cvsentry.split("/")
if len(cvsentryparts) < 6:
continue
if os.path.normcase(cvsentryparts[1]) == os.path.normcase(filename):
return cvsentryparts[2].strip()
return None
def _getcvstag(self, cvsentries):
"""Returns the sticky tag the file was checked out with by looking in
the lines of cvsentries.
"""
filename = os.path.basename(self.location_abs)
for cvsentry in cvsentries:
# an entries line looks like the following:
# /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
cvsentryparts = cvsentry.split("/")
if len(cvsentryparts) < 6:
continue
if os.path.normcase(cvsentryparts[1]) == os.path.normcase(filename):
if cvsentryparts[5].startswith("T"):
return cvsentryparts[5][1:].strip()
return None
|