2 # -*- coding: utf-8 -*-
4 # Copyright 2004-2007 Zuza Software Foundation
6 # This file is part of translate.
8 # translate is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 from translate
.storage
.versioncontrol
import run_command
24 from translate
.storage
.versioncontrol
import GenericRevisionControlSystem
28 """check if cvs is installed"""
29 exitcode
, output
, error
= run_command(["cvs", "--version"])
33 class cvs(GenericRevisionControlSystem
):
34 """Class to manage items under revision control of CVS."""
39 def _readfile(self
, cvsroot
, path
, revision
=None):
41 Read a single file from the CVS repository without checking out a full
44 @param cvsroot: the CVSROOT for the repository
45 @param path: path to the file relative to cvs root
46 @param revision: revision or tag to get (retrieves from HEAD if None)
48 command
= ["cvs", "-d", cvsroot
, "-Q", "co", "-p"]
50 command
.extend(["-r", revision
])
51 # the path is the last argument
53 exitcode
, output
, error
= run_command(command
)
55 raise IOError("[CVS] Could not read '%s' from '%s': %s / %s" % \
56 (path
, cvsroot
, output
, error
))
59 def getcleanfile(self
, revision
=None):
60 """Get the content of the file for the given revision"""
61 parentdir
= os
.path
.dirname(self
.location_abs
)
62 cvsdir
= os
.path
.join(parentdir
, "CVS")
63 cvsroot
= open(os
.path
.join(cvsdir
, "Root"), "r").read().strip()
64 cvspath
= open(os
.path
.join(cvsdir
, "Repository"), "r").read().strip()
65 cvsfilename
= os
.path
.join(cvspath
, os
.path
.basename(self
.location_abs
))
67 cvsentries
= open(os
.path
.join(cvsdir
, "Entries"), "r").readlines()
68 revision
= self
._getcvstag
(cvsentries
)
69 if revision
== "BASE":
70 cvsentries
= open(os
.path
.join(cvsdir
, "Entries"), "r").readlines()
71 revision
= self
._getcvsrevision
(cvsentries
)
72 return self
._readfile
(cvsroot
, cvsfilename
, revision
)
74 def update(self
, revision
=None):
75 """Does a clean update of the given path"""
76 working_dir
= os
.path
.dirname(self
.location_abs
)
77 filename
= os
.path
.basename(self
.location_abs
)
78 filename_backup
= filename
+ os
.path
.extsep
+ "bak"
79 original_dir
= os
.getcwd()
82 # first: check if we are allowed to _change_ to the current dir
83 # (of course, we are already here, but that does not mean so much)
84 os
.chdir(original_dir
)
85 except OSError, error
:
86 raise IOError("[CVS] could not change to directory (%s): %s" \
87 % (original_dir
, error
))
89 # change to the parent directory of the CVS managed file
91 except OSError, error
:
92 raise IOError("[CVS] could not change to directory (%s): %s" \
93 % (working_dir
, error
))
95 os
.rename(filename
, filename_backup
)
96 except OSError, error
:
97 # something went wrong - go back to the original directory
99 os
.chdir(original_dir
)
102 raise IOError("[CVS] could not move the file '%s' to '%s': %s" % \
103 (filename
, filename_backup
, error
))
104 command
= ["cvs", "-Q", "update", "-C"]
106 command
.extend(["-r", revision
])
107 # the filename is the last argument
108 command
.append(filename
)
109 exitcode
, output
, error
= run_command(command
)
110 # restore backup in case of an error - remove backup for success
113 os
.rename(filename_backup
, filename
)
115 os
.remove(filename_backup
)
118 # always go back to the original directory
120 os
.chdir(original_dir
)
123 # raise an error or return successfully - depending on the CVS command
125 raise IOError("[CVS] Error running CVS command '%s': %s" % (command
, error
))
129 def commit(self
, message
=None):
130 """Commits the file and supplies the given commit message if present"""
131 working_dir
= os
.path
.dirname(self
.location_abs
)
132 filename
= os
.path
.basename(self
.location_abs
)
133 original_dir
= os
.getcwd()
136 # first: check if we are allowed to _change_ to the current dir
137 # (of course, we are already here, but that does not mean so much)
138 os
.chdir(original_dir
)
139 except OSError, error
:
140 raise IOError("[CVS] could not change to directory (%s): %s" \
141 % (original_dir
, error
))
143 # change to the parent directory of the CVS managed file
144 os
.chdir(working_dir
)
145 except OSError, error
:
146 raise IOError("[CVS] could not change to directory (%s): %s" \
147 % (working_dir
, error
))
148 command
= ["cvs", "-Q", "commit"]
150 command
.extend(["-m", message
])
151 # the filename is the last argument
152 command
.append(filename
)
153 exitcode
, output
, error
= run_command(command
)
154 # always go back to the original directory
156 os
.chdir(original_dir
)
159 # raise an error or return successfully - depending on the CVS command
161 raise IOError("[CVS] Error running CVS command '%s': %s" % (command
, error
))
165 def _getcvsrevision(self
, cvsentries
):
166 """returns the revision number the file was checked out with by looking
167 in the lines of cvsentries
169 filename
= os
.path
.basename(self
.location_abs
)
170 for cvsentry
in cvsentries
:
171 # an entries line looks like the following:
172 # /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
173 cvsentryparts
= cvsentry
.split("/")
174 if len(cvsentryparts
) < 6:
176 if os
.path
.normcase(cvsentryparts
[1]) == os
.path
.normcase(filename
):
177 return cvsentryparts
[2].strip()
180 def _getcvstag(self
, cvsentries
):
181 """Returns the sticky tag the file was checked out with by looking in
182 the lines of cvsentries.
184 filename
= os
.path
.basename(self
.location_abs
)
185 for cvsentry
in cvsentries
:
186 # an entries line looks like the following:
187 # /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
188 cvsentryparts
= cvsentry
.split("/")
189 if len(cvsentryparts
) < 6:
191 if os
.path
.normcase(cvsentryparts
[1]) == os
.path
.normcase(filename
):
192 if cvsentryparts
[5].startswith("T"):
193 return cvsentryparts
[5][1:].strip()