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
26 class cvs(GenericRevisionControlSystem
):
27 """Class to manage items under revision control of CVS."""
32 def _readfile(self
, cvsroot
, path
, revision
=None):
34 Read a single file from the CVS repository without checking out a full
37 @param cvsroot: the CVSROOT for the repository
38 @param path: path to the file relative to cvs root
39 @param revision: revision or tag to get (retrieves from HEAD if None)
41 command
= ["cvs", "-d", cvsroot
, "-Q", "co", "-p"]
43 command
.extend(["-r", revision
])
44 # the path is the last argument
46 exitcode
, output
, error
= run_command(command
)
48 raise IOError("[CVS] Could not read '%s' from '%s': %s / %s" % \
49 (path
, cvsroot
, output
, error
))
52 def getcleanfile(self
, revision
=None):
53 """Get the content of the file for the given revision"""
54 parentdir
= os
.path
.dirname(self
.location_abs
)
55 cvsdir
= os
.path
.join(parentdir
, "CVS")
56 cvsroot
= open(os
.path
.join(cvsdir
, "Root"), "r").read().strip()
57 cvspath
= open(os
.path
.join(cvsdir
, "Repository"), "r").read().strip()
58 cvsfilename
= os
.path
.join(cvspath
, os
.path
.basename(self
.location_abs
))
60 cvsentries
= open(os
.path
.join(cvsdir
, "Entries"), "r").readlines()
61 revision
= self
._getcvstag
(cvsentries
)
62 if revision
== "BASE":
63 cvsentries
= open(os
.path
.join(cvsdir
, "Entries"), "r").readlines()
64 revision
= self
._getcvsrevision
(cvsentries
)
65 return self
._readfile
(cvsroot
, cvsfilename
, revision
)
67 def update(self
, revision
=None):
68 """Does a clean update of the given path"""
69 working_dir
= os
.path
.dirname(self
.location_abs
)
70 filename
= os
.path
.basename(self
.location_abs
)
71 filename_backup
= filename
+ os
.path
.extsep
+ "bak"
72 original_dir
= os
.getcwd()
75 # first: check if we are allowed to _change_ to the current dir
76 # (of course, we are already here, but that does not mean so much)
77 os
.chdir(original_dir
)
78 except OSError, error
:
79 raise IOError("[CVS] could not change to directory (%s): %s" \
80 % (original_dir
, error
))
82 # change to the parent directory of the CVS managed file
84 except OSError, error
:
85 raise IOError("[CVS] could not change to directory (%s): %s" \
86 % (working_dir
, error
))
88 os
.rename(filename
, filename_backup
)
89 except OSError, error
:
90 # something went wrong - go back to the original directory
92 os
.chdir(original_dir
)
95 raise IOError("[CVS] could not move the file '%s' to '%s': %s" % \
96 (filename
, filename_backup
, error
))
97 command
= ["cvs", "-Q", "update", "-C"]
99 command
.extend(["-r", revision
])
100 # the filename is the last argument
101 command
.append(filename
)
102 exitcode
, output
, error
= run_command(command
)
103 # restore backup in case of an error - remove backup for success
106 os
.rename(filename_backup
, filename
)
108 os
.remove(filename_backup
)
111 # always go back to the original directory
113 os
.chdir(original_dir
)
116 # raise an error or return successfully - depending on the CVS command
118 raise IOError("[CVS] Error running CVS command '%s': %s" % (command
, error
))
122 def commit(self
, message
=None):
123 """Commits the file and supplies the given commit message if present"""
124 working_dir
= os
.path
.dirname(self
.location_abs
)
125 filename
= os
.path
.basename(self
.location_abs
)
126 original_dir
= os
.getcwd()
129 # first: check if we are allowed to _change_ to the current dir
130 # (of course, we are already here, but that does not mean so much)
131 os
.chdir(original_dir
)
132 except OSError, error
:
133 raise IOError("[CVS] could not change to directory (%s): %s" \
134 % (original_dir
, error
))
136 # change to the parent directory of the CVS managed file
137 os
.chdir(working_dir
)
138 except OSError, error
:
139 raise IOError("[CVS] could not change to directory (%s): %s" \
140 % (working_dir
, error
))
141 command
= ["cvs", "-Q", "commit"]
143 command
.extend(["-m", message
])
144 # the filename is the last argument
145 command
.append(filename
)
146 exitcode
, output
, error
= run_command(command
)
147 # always go back to the original directory
149 os
.chdir(original_dir
)
152 # raise an error or return successfully - depending on the CVS command
154 raise IOError("[CVS] Error running CVS command '%s': %s" % (command
, error
))
158 def _getcvsrevision(self
, cvsentries
):
159 """returns the revision number the file was checked out with by looking
160 in the lines of cvsentries
162 filename
= os
.path
.basename(self
.location_abs
)
163 for cvsentry
in cvsentries
:
164 # an entries line looks like the following:
165 # /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
166 cvsentryparts
= cvsentry
.split("/")
167 if len(cvsentryparts
) < 6:
169 if os
.path
.normcase(cvsentryparts
[1]) == os
.path
.normcase(filename
):
170 return cvsentryparts
[2].strip()
173 def _getcvstag(self
, cvsentries
):
174 """Returns the sticky tag the file was checked out with by looking in
175 the lines of cvsentries.
177 filename
= os
.path
.basename(self
.location_abs
)
178 for cvsentry
in cvsentries
:
179 # an entries line looks like the following:
180 # /README.TXT/1.19/Sun Dec 16 06:00:12 2001//
181 cvsentryparts
= cvsentry
.split("/")
182 if len(cvsentryparts
) < 6:
184 if os
.path
.normcase(cvsentryparts
[1]) == os
.path
.normcase(filename
):
185 if cvsentryparts
[5].startswith("T"):
186 return cvsentryparts
[5][1:].strip()