fix git support for v1.5.3 (or higher) by setting "--work-tree"
[translate_toolkit.git] / storage / versioncontrol / cvs.py
blob02de05c64248262ab2b7b532656c570df8f1bcb7
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2004-2007 Zuza Software Foundation
5 #
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
22 import os
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."""
29 RCS_METADIR = "CVS"
30 SCAN_PARENTS = False
32 def _readfile(self, cvsroot, path, revision=None):
33 """
34 Read a single file from the CVS repository without checking out a full
35 working directory.
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)
40 """
41 command = ["cvs", "-d", cvsroot, "-Q", "co", "-p"]
42 if revision:
43 command.extend(["-r", revision])
44 # the path is the last argument
45 command.append(path)
46 exitcode, output, error = run_command(command)
47 if exitcode != 0:
48 raise IOError("[CVS] Could not read '%s' from '%s': %s / %s" % \
49 (path, cvsroot, output, error))
50 return output
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))
59 if revision is None:
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()
73 if working_dir:
74 try:
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))
81 try:
82 # change to the parent directory of the CVS managed file
83 os.chdir(working_dir)
84 except OSError, error:
85 raise IOError("[CVS] could not change to directory (%s): %s" \
86 % (working_dir, error))
87 try:
88 os.rename(filename, filename_backup)
89 except OSError, error:
90 # something went wrong - go back to the original directory
91 try:
92 os.chdir(original_dir)
93 except OSError:
94 pass
95 raise IOError("[CVS] could not move the file '%s' to '%s': %s" % \
96 (filename, filename_backup, error))
97 command = ["cvs", "-Q", "update", "-C"]
98 if revision:
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
104 try:
105 if exitcode != 0:
106 os.rename(filename_backup, filename)
107 else:
108 os.remove(filename_backup)
109 except OSError:
110 pass
111 # always go back to the original directory
112 try:
113 os.chdir(original_dir)
114 except OSError:
115 pass
116 # raise an error or return successfully - depending on the CVS command
117 if exitcode != 0:
118 raise IOError("[CVS] Error running CVS command '%s': %s" % (command, error))
119 else:
120 return output
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()
127 if working_dir:
128 try:
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))
135 try:
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"]
142 if message:
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
148 try:
149 os.chdir(original_dir)
150 except OSError:
151 pass
152 # raise an error or return successfully - depending on the CVS command
153 if exitcode != 0:
154 raise IOError("[CVS] Error running CVS command '%s': %s" % (command, error))
155 else:
156 return output
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:
168 continue
169 if os.path.normcase(cvsentryparts[1]) == os.path.normcase(filename):
170 return cvsentryparts[2].strip()
171 return None
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:
183 continue
184 if os.path.normcase(cvsentryparts[1]) == os.path.normcase(filename):
185 if cvsentryparts[5].startswith("T"):
186 return cvsentryparts[5][1:].strip()
187 return None