source: tailor/vcpx/tailor.py @ 51

Revision 51, 8.2 KB checked in by lele@…, 9 years ago (diff)

Use the logger instead of print statements

Line 
1#! /usr/bin/python
2# -*- mode: python; coding: utf-8 -*-
3# :Progetto: vcpx -- Frontend capabilities
4# :Creato:   dom 04 lug 2004 00:40:54 CEST
5# :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
6#
7
8"""
9Implement the basic capabilities of the frontend.
10
11This implementation stores the relevant project information, needed to
12keep the whole thing going on, such as the last synced revision, in a
13unversioned file named `tailor.info` at the root.
14"""
15
16__docformat__ = 'reStructuredText'
17
18from dualwd import DualWorkingDir
19
20STATUS_FILENAME = 'tailor.info'
21LOG_FILENAME = 'tailor.log'
22   
23class TailorizedProject(object):
24    """
25    A TailorizedProject has two main capabilities: it may be bootstrapped
26    from an upstream repository or brought in sync with current upstream
27    revision.
28    """
29   
30    def __init__(self, root):
31        import logging
32        from os import makedirs
33        from os.path import join, exists
34
35        self.root = root
36        if not exists(root):
37            makedirs(root)
38       
39        self.logger = logging.getLogger('tailor')
40        hdlr = logging.FileHandler(join(root, LOG_FILENAME))
41        formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
42        hdlr.setFormatter(formatter)
43        self.logger.addHandler(hdlr) 
44        self.logger.setLevel(logging.INFO)
45
46        self.source_kind = self.target_kind = None
47               
48    def __saveStatus(self):
49        """
50        Save relevant project information in a persistent way.
51        """
52       
53        from os.path import join, exists
54
55        statusfilename = join(self.root, STATUS_FILENAME)
56        f = open(statusfilename, 'w')
57        print >>f, self.source_kind
58        print >>f, self.target_kind       
59        print >>f, self.module       
60        print >>f, self.upstream_repos
61        print >>f, self.upstream_revision
62        f.close()
63       
64    def __loadStatus(self):
65        """
66        Load relevant project information.
67        """
68       
69        from os.path import join, exists
70
71        statusfilename = join(self.root, STATUS_FILENAME)
72        f = open(statusfilename)
73        (srck, dstk,
74         module, upstream_repos, upstream_revision) = f.readlines()
75        self.source_kind = srck[:-1]
76        self.target_kind = dstk[:-1]
77        self.module = module[:-1]
78        self.upstream_repos = upstream_repos[:-1]
79        self.upstream_revision = upstream_revision[:-1]
80        f.close()
81
82    def bootstrap(self, source_kind, target_kind,
83                  repository, module, revision):
84        """
85        Bootstrap a new tailorized module.
86
87        Extract a copy of the `repository` at given `revision` in the `root`
88        directory and initialize a target repository with its content.
89
90        The actual information on the project are stored in a text file.
91        """
92
93        from os.path import join
94       
95        self.logger.info("Bootstrapping '%s'" % (self.root,))
96
97        dwd = DualWorkingDir(source_kind, target_kind)
98        self.logger.info("getting %s revision '%s' of '%s' from '%s'" % (
99            source_kind, revision, module, repository))
100        actual = dwd.checkoutUpstreamRevision(self.root, repository,
101                                              module, revision,
102                                              logger=self.logger)
103        self.logger.info("initializing %s shadow" % target_kind)
104        dwd.initializeNewWorkingDir(self.root, repository, module, actual)
105
106        self.source_kind = source_kind
107        self.target_kind = target_kind
108        self.upstream_repos = repository
109        self.module = module       
110        self.upstream_revision = actual
111
112        self.__saveStatus()
113
114        self.logger.info("Bootstrap completed")
115
116    def update(self):
117        """
118        Update an existing tailorized project.
119
120        Fetch the upstream changesets and apply them to the working copy.
121        Use the information stored in the `tailor.info` file to ask just
122        the new changeset since last bootstrap/synchronization.
123        """
124       
125        from os.path import join
126       
127        self.__loadStatus()
128
129        proj = join(self.root, self.module)
130        self.logger.info("Updating '%s' from revision '%s'" % (
131            proj, self.upstream_revision))
132       
133        dwd = DualWorkingDir(self.source_kind, self.target_kind)
134        actual,conflicts = dwd.applyUpstreamChangesets(proj,
135                                                       self.upstream_revision,
136                                                       logger=self.logger)
137        if actual:
138            self.upstream_revision = actual.revision
139            self.__saveStatus()
140            self.logger.info("Update completed, now at revision '%s'" % (
141                self.upstream_revision,))
142        else:
143            self.logger.info("Update completed with no upstream changes")
144
145
146from optparse import OptionParser, OptionError, OptionGroup, make_option
147
148OPTIONS = [
149    make_option("-D", "--debug", dest="debug",
150                action="store_true", default=False),
151    make_option("-s", "--source-kind", dest="source_kind", metavar="VC-KIND",
152                help="Select the backend for the upstream source "
153                     "version control VC-KIND. Default is 'cvs'.",
154                default="cvs"),
155    make_option("-t", "--target-kind", dest="target_kind", metavar="VC-KIND",
156                help="Select VC-KIND as backend for the shadow repository, "
157                     "with 'darcs' as default.",
158                default="darcs"),   
159]   
160
161ACTIONS = [
162    make_option("-b", "--bootstrap", action="store_true", default=False,
163                help="Bootstrap mode, that is the initial copy of the "
164                     "upstream tree, given as an URI possibly followed "
165                     "by a revision."),
166    make_option("-i", "--info", action="store_true", default=False,
167                help="Just show ancestry information."),
168]
169
170class ExistingProjectError(Exception):
171    """
172    Raised when, in bootstrap mode, the directory for the project is already
173    there.
174    """
175
176class UnknownProjectError(Exception):
177    """
178    Raised when, in normal mode, the directory for the project does not
179    exist.
180    """
181
182class ProjectNotTailored(Exception):
183    """
184    Raised when trying to do something on a project that has not been
185    tailored.
186    """
187   
188def main():
189    """
190    Script entry point.
191
192    Parse the command line options and arguments, and for each
193    specified working copy directory (the current working directory by
194    default) execute the tailorization steps.
195    """
196   
197    from os import getcwd, chdir
198    from os.path import abspath, exists, join, split
199    from shwrap import SystemCommand
200   
201    parser = OptionParser(usage='%prog [options] [proj [URI[@revision]]]...',
202                          option_list=OPTIONS)
203    actions = OptionGroup(parser, "Other actions")
204    actions.add_options(ACTIONS)
205    parser.add_option_group(actions)
206   
207    options, args = parser.parse_args()
208   
209    SystemCommand.VERBOSE = options.debug
210   
211    base = getcwd()
212   
213    if len(args) == 0:
214        args.append(base)
215       
216    while args:
217        chdir(base)
218       
219        proj = args.pop(0)
220        root = abspath(proj)
221
222        if exists(join(root, STATUS_FILENAME)):
223            basedir = root
224        else:
225            basedir, module = split(root)
226       
227        if options.bootstrap:
228            if exists(join(basedir, STATUS_FILENAME)):
229                raise ExistingProjectError(
230                    "Project %r cannot be bootstrapped twice" % proj)
231           
232            if not args:
233                raise OptionError('expected the source URI for %r' % proj,
234                                  '--bootstrap')
235            uri = args.pop(0)
236        else:               
237            uri = None
238           
239        if not options.bootstrap and not exists(proj):
240            raise UnknownProjectError("Project %r does not exist" % proj)
241           
242        tailored = TailorizedProject(basedir)
243       
244        if options.bootstrap:
245            if uri and '@' in uri:
246                uri, rev = uri.split('@')
247            else:
248                rev = 'HEAD'
249            tailored.bootstrap(options.source_kind, options.target_kind,
250                               uri, module, rev)
251        elif options.info:
252            pass
253        else:
254            tailored.update()
255
Note: See TracBrowser for help on using the repository browser.