Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/translate-toolkit-1.5.1/translate/storage/versioncontrol/cvs.py
blob: 15dd52fd3b06e8d035237aea62d45657ccd10bc8 (plain)
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