source: CMT/HEAD/mgr/cmt_svn_checkout.py @ 648

Last change on this file since 648 was 648, checked in by rybkin, 11 years ago

See C.L. 507

  • Property svn:executable set to *
File size: 27.4 KB
Line 
1#!/usr/bin/env python
2
3"""cmt_svn_checkout.py: Checkout CMT package(s) from Subversion repository.
4
5Usage: cmt_svn_checkout.py [OPTION]... PATH...
6Checkout PATH(s) relative to or being Subversion repository URL(s).
7
8Mandatory arguments to long options are mandatory for short options too.
9  -r, --version-tag=REV        checkout version tag REV of PATH
10      --version-dir=DIR        use DIR as version directory instead of version tag
11  -d, --directory=DIR          checkout into DIR instead of (basename of) PATH
12  -o, --offset=OFFSET          checkout PATH at OFFSET relative to repository URL
13      --no_config              disable config step upon checkout
14      --without_version_directory do not create version directory upon PATH checkout
15      --with_version_directory create version directory upon PATH checkout (default)
16      --url=URL                checkout PATH from repository URL
17      --debug                  print lots of debugging information
18  -h, --help                   display this help and exit
19      --version                output version information and exit
20
21The SVNROOT, SVNTRUNK, SVNTAGS, and SVNBRANCHES environment variables specify repository URL of PATH, location of PATH trunk, tags, and branches (relatively to PATH) respectively.
22
23Report bugs to <CMT-L@IN2P3.FR>.
24"""
25
26__version__ = '0.7.0'
27__date__ = 'Tue Jul 09 2013'
28__author__ = 'Grigory Rybkin'
29
30import sys
31import getopt
32import os
33import posixpath
34import os.path
35import urlparse
36# for Python 2.3 and older
37if sys.version_info[0] == 2 and sys.version_info[1] < 4:
38    for p in ('svn', 'svn+ssh'):
39        if p not in urlparse.uses_netloc:
40            urlparse.uses_netloc.append(p)
41import tempfile
42import re
43
44import logging
45
46self = 'cmt_svn_checkout.py'
47# try:
48#     from svn import client, core
49# except ImportError, e:
50#     print >>sys.stderr, '%s: cannot import Subversion Python bindings: %s' \
51#           % (self, str(e))
52#     sys.exit(1)
53os.environ['LC_ALL'] = 'C'
54
55class Utils(object):
56    def getstatusoutput(cmd):
57        """Return (status, stdout + stderr) of executing cmd in a shell.
58       
59        A trailing line separator is removed from the output string. The exit status of the command is encoded in the format specified for wait(), when the exit status is zero (termination without errors), 0 is returned.
60        """
61        p = os.popen('( %s ) 2>&1' % cmd, 'r')
62        out = p.read()
63        sts = p.close()
64        if sts is None: sts = 0
65        if out.endswith(os.linesep):
66            out = out[:out.rindex(os.linesep)]
67        elif out[-1:] == '\n': out = out[:-1]
68        return sts, out
69    getstatusoutput = staticmethod(getstatusoutput)
70   
71    def getstatuserror(cmd):
72        """Return (status, stderr) of executing cmd in a shell.
73       
74        On Unix, the return value is the exit status of the command is encoded in the format specified for wait(). On Windows, on command.com systems (Windows 95, 98 and ME) this is always 0; on cmd.exe systems (Windows NT, 2000 and XP) this is the exit status of the command run.
75        """
76        fd, p = tempfile.mkstemp()
77        os.close(fd)
78#        print >> sys.stderr, 'Created file %s with fd %i' % (p, fd)
79#        p = os.tempnam()
80#        print >> sys.stderr, 'Created file name %s' % (p)
81        sc = os.system('( %s ) 2>%s' % (cmd, p))
82        f = open(p)
83        e = f.read()
84        f.close()
85        os.unlink(p)
86        return sc, e
87    getstatuserror = staticmethod(getstatuserror)
88
89class ClientContext(object):
90
91    schemes = ('http', 'https', 'svn', 'svn+ssh', 'file')
92
93    def svn_path_canonicalize(self, path):
94        """Return a new path (or URL) like path, but transformed such that some types of path specification redundancies are removed.
95
96        This involves collapsing redundant "/./" elements, removing multiple adjacent separator characters, removing trailing separator characters, and possibly other semantically inoperative transformations. Convert the scheme and hostname to lowercase."""
97        scheme, netloc, path, query, fragment = urlparse.urlsplit(path)
98        scheme = scheme.lower()
99        netloc = netloc.lower()
100        if path.startswith('/'): b = '/'
101        else: b = ''
102        path = b + '/'.join([s for s in path.split('/') if s and s != '.'])
103        return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
104
105    def urljoin(self, *args):
106        urls = [urlparse.urlsplit(arg) for arg in args]
107        if not urls: return ''
108       
109        schemes = [url[0] for url in urls]
110        schemes.reverse()
111        for i, s in enumerate(schemes):
112            if s and s in self.schemes:
113                scheme = s
114                index = i
115                break
116        else:
117            scheme = ''
118            index = len(urls) - 1
119       
120        netlocs = [url[1] for url in urls]
121        netlocs.reverse()
122        for i, s in enumerate(netlocs[:index + 1]):
123            if s:
124                netloc = s
125                index = i
126                break
127        else:
128            netloc = ''
129       
130        path = posixpath.join(*[url[2] for url in urls][len(urls) - 1 - index:])
131
132        query = fragment = ''
133        return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
134
135#         scheme = self.last_nonempty([url[0] for url in urls if url[0] in self.schemes])
136#         netloc = self.last_nonempty([url[1] for url in urls])
137#         path = posixpath.join(*[url[2] for url in urls])
138#         query = self.last_nonempty([url[3] for url in urls])
139#         fragment = self.last_nonempty([url[4] for url in urls])
140       
141#         return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
142
143    def last_nonempty(self, list, default = ''):
144        list.reverse()
145        for i in list:
146            if i: return i
147        else:
148            return default
149       
150#     def __init__(self):
151#         core.svn_config_ensure(None)
152#         self.ctx = client.create_context()
153#         self.providers = [
154#             client.get_simple_provider(),
155#             client.get_username_provider(),
156#             client.get_ssl_server_trust_file_provider(),
157#             client.get_ssl_client_cert_file_provider(),
158#             client.get_ssl_client_cert_pw_file_provider()
159#             ]
160#         self.ctx.auth_baton = core.svn_auth_open(self.providers)
161#         self.ctx.config = core.svn_config_get_config(None)
162
163#     def __call__(self):
164#         return self.ctx
165
166def cwd():
167    _gcwd = os.getcwd()
168    try:
169        _cwd = os.environ['PWD']
170        if _cwd and os.path.samefile(_cwd, _gcwd):
171            return _cwd
172        else:
173            return _gcwd
174    except (KeyError, AttributeError):
175        return _gcwd
176
177def cd(path):
178    new = os.path.normpath(os.path.join(cwd(), path))
179    os.chdir(path)
180    _gcwd = os.getcwd()
181    try:
182        if os.path.samefile(new, _gcwd):
183            os.environ['PWD'] = new
184        else:
185            os.environ['PWD'] = _gcwd
186    except AttributeError:
187        pass
188
189def error(instance, location='', file = sys.stderr):
190    try:
191        message = ': '.join([str(arg) for arg in instance.args])
192    except AttributeError:
193        message = str(instance).rstrip()
194    if location: location += ': '
195    print >> file, "%s%s" % (location, message)
196   
197class CmtContext(object):
198    def __init__(self,
199                 config = True,
200                 with_version_directory = True,
201                 cleanup = False,
202                 head_version = None):
203        self.config = config
204        self.with_version_directory = with_version_directory
205        self.cleanup = cleanup
206        self.head_version = head_version
207        self.env()
208
209    def env(self):
210        if self.head_version is None:
211            self.set_head_version(os.getenv('CMTHEADVERSION', 'HEAD'))
212#        print >>sys.stderr, 'env: set head_version: %s' % self.head_version
213
214    def set_head_version(self, version):
215        self.head_version = str(version).replace('<package>', '%(package)s').replace('<PACKAGE>', '%(PACKAGE)s').replace('<revision>', '%(revision)i')
216
217    def eval_head_version(self, m):
218        return self.head_version % \
219               {'package' : m.package,
220                'PACKAGE' : m.package.upper(),
221                'revision' : m.info.last_changed_rev}
222
223    def write(self, p, version):
224        #print >> sys.stderr, 'write:', p, version
225        try:
226            t = version + '\n'
227            if os.path.exists(p):
228                f = open(p, 'r+')
229                b = f.tell()
230                v = f.read()
231                if v != t:
232                    f.seek(b)
233                    f.write(t)
234                    f.truncate()
235            else:
236                f = open(p, 'w')
237                f.write(t)
238            f.close()
239        except IOError, e:
240            print >> sys.stderr, e
241            return 1
242        return 0
243       
244    def generate(self, p):
245        #print >> sys.stderr, 'generate:', p
246        curdir = cwd()
247#        cmd = 'cmt -disable_warnings'
248        cmd = 'cmt -q'
249        if self.with_version_directory:
250            cmd += ' -with_version_directory'
251        else:
252            cmd += ' -without_version_directory'
253        if self.cleanup:
254            cmd += ' -cleanup'
255        else:
256            cmd += ' -no_cleanup'
257        cmd += ' config'
258        cd(p)
259        sc = os.system(cmd)
260        if sc != 0: sc = 1
261        cd(curdir)
262#        return sc
263        return 0
264
265    def configure(self, path, version):
266        sc = 0
267        for d in ('cmt', 'mgr'):
268            p = os.path.join(path, d)
269            if os.path.isdir(p):
270                if not self.with_version_directory:
271                    sc += self.write(os.path.join(p,'version.cmt'), version)
272                elif os.path.exists(os.path.join(p,'version.cmt')):
273                    print >>sys.stderr, 'Warning: file %s normally should not be under version control. Please, consider removing' % os.path.join(d,'version.cmt')
274                    try:
275                        os.rename(os.path.join(p,'version.cmt'),
276                                  os.path.join(p,'version.cmt.orig'))
277                        print >>sys.stderr, 'renamed %s -> %s' % (`os.path.join(p,'version.cmt')`, `os.path.join(p,'version.cmt.orig')`)
278                    except (IOError, os.error), e:
279                        error(e)
280                   
281                if self.config:
282                    sc += self.generate(p)
283                return sc
284        return sc
285        #print >> sys.stderr, 'Cannot configure %s ' % (path, version)
286
287class Module(object):
288    def __init__(self, module):
289        self.module = module
290        self.init = False
291        class info(object):
292            last_changed_rev = 0
293        self.info = info
294#         print >>sys.stderr, 'init module %s: last_changed_rev %i' % \
295#               (self.module, self.info.last_changed_rev)
296       
297class Checkout(object):
298    def __init__(self,
299                 url = None,
300                 trunk = None,
301                 tags = None,
302                 branches = None,
303                 version = None,
304                 version_dir = None,
305                 directory = None,
306                 offset = '',
307                 modules = []):
308        self.url = url
309        self.trunk = trunk
310        self.tags = tags
311        self.branches = branches
312        self.version = version
313        self.version_dir = version_dir
314        self.directory = directory
315        self.offset = offset
316        self.modules = modules
317        self.reposLayout()
318       
319    def reposLayout(self):
320        if self.url is None:
321            self.url = os.getenv('SVNROOT', '')
322#             try:
323#                 self.url = os.environ['SVNROOT']
324#             except KeyError:
325#                 pass
326        if self.trunk is None:
327            self.trunk = os.getenv('SVNTRUNK', 'trunk')
328        if self.tags is None:
329            self.tags = os.getenv('SVNTAGS', 'tags')
330        if self.branches is None:
331            self.branches = os.getenv('SVNBRANCHES', 'branches')
332
333    def cmtRepos(self):
334        self.url = 'https://svn.lal.in2p3.fr/projects/CMT'
335        self.trunk = 'HEAD'
336        self.tags= '.'
337        self.branches = '.'
338
339    def add(self, module):
340        self.modules.append(module)
341
342    def info_receiver(self, path, info, pool):
343        self.path = path
344        self.info = info
345        pool.info = info
346
347    def cmp(self, path1, path2, client_context):
348        cmd = 'svn diff %s %s' % (path1, path2)
349#        cmd = 'svn diff --summarize %s %s' % (path1, path2)
350        sc, out = Utils.getstatusoutput(cmd)
351        if sc != 0:
352            return 2
353        if out: return 1
354        else: return 0
355
356#         outfile = tempfile.TemporaryFile('wb')
357#         errfile = tempfile.TemporaryFile('wb')
358#         outb = outfile.tell()
359#         errb = errfile.tell()
360#         client.diff([]
361#                     , path1
362#                     , self.head_revision
363#                     , path2
364#                     , self.head_revision
365#                     , True, True, False
366#                     , outfile
367#                     , errfile
368#                     , client_context())
369
370#         # position at the end of the file
371#         outfile.seek(0, 2)
372#         errfile.seek(0, 2)
373#         oute = outfile.tell()
374#         erre = errfile.tell()
375
376#         if erre > errb: return 2
377#         elif oute > outb: return 1
378#         else: return 0
379
380    def trunk_tag(self, module, client_context):
381        """Attempt to determine the tag of the module's trunk.
382       
383        Return the tag if its files are copied from the trunk and
384        their last_changed_rev numbers are the same as those of the trunk files.
385        """
386        trunk = posixpath.join(module.url, self.trunk)
387#        trunk = posixpath.normpath(posixpath.join(module.url, self.trunk))
388        cmd = 'svn ls -vR %s' % trunk
389        sc, out = Utils.getstatusoutput(cmd)
390        logger.debug('%s\n%s' % (cmd, out))
391        if sc != 0:
392            return None
393        trunk_dirent = [line.split() for line in out.splitlines()]
394        trunk_revs = dict([(line[-1], int(line[0])) for line in trunk_dirent if not line[-1].endswith(posixpath.sep)])
395        logger.debug('%s' % trunk_revs)
396
397        curdir = posixpath.curdir + posixpath.sep
398        for line in trunk_dirent:
399            if line[-1] == curdir:
400                class info(object): pass
401                info.last_changed_rev = int(line[0])
402                self.info_receiver(trunk, info, module)
403                logger.debug('last_changed_rev: %d' % info.last_changed_rev)
404                break
405
406#        cmd = 'svn info %s' % trunk
407#         p = r'last\s+changed\s+rev:\s+(?P<rev>\d+)'
408#         m = re.search(p, out, re.I)
409#         if m:
410#             class info(object): pass
411#             info.last_changed_rev = int(m.group('rev'))
412#             self.info_receiver(trunk, info, module)
413# #            self.info_receiver(trunk, info, None)
414# #             print >>sys.stderr, '%s: last_changed_rev %i' % \
415# #                   (trunk, self.info.last_changed_rev)
416# #            last_changed_rev = int(m.group('rev'))
417#         else:
418#             return None
419
420        tags = posixpath.join(module.url, self.tags)
421#        tags = posixpath.normpath(posixpath.join(module.url, self.tags))
422        cmd = 'svn ls -vR %s' % tags
423#        cmd = 'svn ls -v %s' % tags
424        sc, out = Utils.getstatusoutput(cmd)
425        logger.debug('%s\n%s' % (cmd, out))
426        if sc != 0:
427            return None
428        tags_dirent = [line.split() for line in out.splitlines()]
429        tags_revs = dict()
430        for ent in tags_dirent:
431            try:
432                tag, path = ent[-1].split(posixpath.sep, 1)
433            except ValueError:
434                continue
435            if tag not in tags_revs:
436                tags_revs[tag] = dict()
437            if path and not path.endswith(posixpath.sep):
438                # assume there are no empty directories in the tag
439                tags_revs[tag][path] = int(ent[0])
440        logger.debug('%s' % tags_revs)
441
442        cmd = 'svn info %s' % trunk
443        sc, out = Utils.getstatusoutput(cmd)
444        logger.debug('%s\n%s' % (cmd, out))
445        if sc != 0:
446            return None
447        p = r'repository\s+root:\s+(?P<root>%s://\S+)' % \
448            ('(?:' + '|'.join(map(re.escape, client_context.schemes)) + ')')
449        m = re.search(p, out, re.I)
450        logger.debug('pattern: %r' % (p))
451        if m:
452            root = m.group('root')
453        else:
454            return None
455        logger.debug('root: %s' % root)
456        trunk_path = trunk[len(root):]
457        tags_path = tags[len(root):]
458        logger.debug('trunk_path: %s' % trunk_path)
459        logger.debug('tags_path: %s' % tags_path)
460        offset = len(trunk) - len(root) + len(posixpath.sep)
461       
462        # Usually, a tag is created as a server-side copy.
463        # Sometimes, a tag is created as a copy of WC (working copy)
464        # after commit.
465        # Below, we try to take into account the latter case.
466        cmd = 'svn log -v -q %s' % tags
467        sc, out = Utils.getstatusoutput(cmd)
468        logger.debug('%s\n%s' % (cmd, out))
469        if sc != 0:
470            return None
471        p = re.compile(
472            r'^-{5,}$\s^r\d+.+$\s^Changed paths:$\s^\s+A\s+%s%s(?P<tag>[^%s]+)\s+\(from %s:\d+\)$(?P<replaced>(?:\s^\s+(?:R|A|D)\s+%s%s(?P=tag)%s(?P<path>.+)(?:\s+\(from %s%s(?P=path):\d+\))?$)*)' % (re.escape(tags_path), posixpath.sep, posixpath.sep, re.escape(trunk_path), re.escape(tags_path), posixpath.sep, posixpath.sep, re.escape(trunk_path), posixpath.sep)
473            , re.M
474            )
475        tags_copied = list()
476        tags_replaced_revs = dict()
477        for m in p.finditer(out):
478            logger.debug('tag: %s replaced: %r' % (m.group('tag'), m.group('replaced')))
479            tags_copied.append(m.group('tag'))
480            for line in m.group('replaced').strip().splitlines():
481                l = line.split()
482                if len(l) == 2: continue # action code D - deleted paths
483                repl = l[3].rstrip(')')
484                i = repl.rindex(':')
485                path = repl[offset:i]
486                rev = int(repl[i + 1:])
487                logger.debug('path: %s rev: %d' % (path, rev))
488
489                if m.group('tag') not in tags_replaced_revs:
490                    tags_replaced_revs[m.group('tag')] = dict()
491                if path and not path.endswith(posixpath.sep):
492                    # assume there are no empty directories in the tag
493                    tags_replaced_revs[m.group('tag')][path] = rev
494
495        logger.debug('copied: %s' % tags_copied)
496        logger.debug('replaced: %s' % tags_replaced_revs)
497
498        for t in tags_revs.keys():
499            if t not in tags_copied:
500                del tags_revs[t]
501                logger.debug('%s: Not a trunk copy' % t)
502
503        for t in tags_replaced_revs:
504            if t in tags_revs:
505                tags_revs[t].update(tags_replaced_revs[t])
506               
507        for tag in tags_revs:
508            logger.debug('Compare: %s -> %s' % (tag, tags_revs[tag]))
509            if trunk_revs == tags_revs[tag]:
510                return tag
511
512        return None
513
514#         tags_dirent = [line.split() for line in out.splitlines()]
515#         rev_tag = dict([(int(line[0]), line[-1].rstrip(posixpath.sep)) for line in tags_dirent if line[-1].endswith(posixpath.sep)])
516#         revs = rev_tag.keys()
517#         revs.sort()
518#         revs.reverse()
519
520#         for rev in revs:
521#             logger.debug('rev: %s' % rev)
522#             if rev < self.info.last_changed_rev: break
523# #            if rev < last_changed_rev: break
524#             tag = posixpath.join(tags, rev_tag[rev])
525# #            tag = posixpath.normpath(posixpath.join(tags, rev_tag[rev]))
526#             logger.debug('comparing: %s %s(%d)' % (trunk, tag, rev))
527#             if 0 == self.cmp(trunk, tag, client_context):
528#                 return rev_tag[rev]
529
530#         return None
531
532#         try:
533#             trunk = core.svn_path_canonicalize(posixpath.join(module.url, self.trunk))
534#             client.info(trunk,
535#                         self.head_revision,
536#                         self.head_revision,
537#                         self.info_receiver,
538#                         False,
539#                         client_context())
540           
541#             tags = core.svn_path_canonicalize(posixpath.join(module.url, self.tags))
542#             tags_dirent = client.ls(tags,
543#                                     self.head_revision,
544#                                     False,
545#                                     client_context())
546           
547#             rev_tag = dict([(tags_dirent[p].created_rev, p) for p in tags_dirent if tags_dirent[p].kind == core.svn_node_dir])
548#             revs = rev_tag.keys()
549#             revs.sort()
550#             revs.reverse()
551
552#             for rev in revs:
553#                 if rev < self.info.last_changed_rev: break
554#                 tag = core.svn_path_canonicalize(posixpath.join(tags, rev_tag[rev]))
555#                 if 0 == self.cmp(trunk, tag, client_context):
556#                     return rev_tag[rev]
557
558#             return None
559#         except core.SubversionException, e:
560#             return None
561
562    def initialize(self, cmt_context, client_context):
563        sc = 0
564#         self.head_revision = core.svn_opt_revision_t()
565#         self.head_revision.kind = core.svn_opt_revision_head
566
567        # canonicalize:
568        self.url = client_context.svn_path_canonicalize(self.url)
569        self.offset = client_context.svn_path_canonicalize(self.offset)
570
571        for m in self.modules:
572            m.module = client_context.svn_path_canonicalize(m.module)
573            m.url = client_context.urljoin(self.url, self.offset, m.module)
574
575            if urlparse.urlparse(m.url)[0] not in client_context.schemes:
576                error('%s: Not a valid Subversion URL' % m.url)
577                sc += 1; continue
578#             print >>sys.stderr, '%s: URL constructed from %s %s %s' % \
579#                   (m.url, `self.url`, `self.offset`, `m.module`)
580
581            m.package = posixpath.basename(m.url)
582
583            if self.directory is not None:
584                m.path = os.path.normpath(self.directory)
585            else:
586                scheme, netloc, path, query, fragment = urlparse.urlsplit(m.module)
587                if not scheme and not netloc:
588                    m.path = os.path.normpath(os.path.join(*path.split(posixpath.sep)))
589                else:
590                    m.path = posixpath.basename(m.url)
591
592            if self.version is None:
593                m.head = True
594                m.version = self.trunk_tag(m, client_context) or \
595                            cmt_context.eval_head_version(m)
596#                print >>sys.stderr, 'set version: %s' % m.version
597            else:
598                m.head = False
599                m.version = self.version
600
601            if m.head:
602                m.URL = [posixpath.join(m.url, self.trunk)]
603            else:
604                m.URL = [posixpath.join(m.url, p, m.version)
605                         for p in (self.tags, self.branches)]
606            m.URL = [client_context.svn_path_canonicalize(url) for url in m.URL]
607#            m.URL = [core.svn_path_canonicalize(url) for url in m.URL]
608
609            if cmt_context.with_version_directory:
610                if self.version_dir is None:
611                    m.path = os.path.join(m.path, m.version)
612                else:
613                    m.path = os.path.join(m.path, self.version_dir)
614
615            m.init = True
616#            print m.URL, m.path, m.init
617           
618#        for m in self.modules:
619#            print m.url, m.path, m.init
620        return sc
621
622    def execute(self, cmt_context, client_context):
623        sce = 0
624
625        for m in self.modules:
626            if not m.init: continue
627            done = False
628            err = []
629            for url in m.URL:
630                cmd = 'svn checkout %s %s' % (url, m.path)
631#                cmd = 'svn checkout -q %s %s' % (url, m.path)
632                sc, e = Utils.getstatuserror(cmd)
633#                 cmd = 'svn checkout -q %s %s' % (url, m.path)
634#                 sc, e = Utils.getstatusoutput(cmd)
635                if 0 == sc:
636#                 try:
637#                     #print 'client.checkout2:', url, m.path
638#                     result_rev = client.checkout2(url,
639#                                                   m.path,
640#                                                   self.head_revision,
641#                                                   self.head_revision,
642#                                                   True,
643#                                                   True,
644#                                                   client_context())
645#                 except core.SubversionException, e:
646#                     err.append(e)
647#                     continue
648                    done = True
649                    break
650                else:
651                    err.append(e)
652                    continue
653
654            if not done:
655                for e in err:
656                    error(e)
657#                     #print >> sys.stderr, e
658#                     sc += 1
659#                 print >> sys.stderr, 'Failed to checkout %s into %s.' % \
660#                       (' or '.join(m.URL), m.path)
661                sce += 1
662
663#            print 'Checked out revision %i.' % result_rev
664            scc = cmt_context.configure(m.path, m.version)
665            if scc != 0:
666                print >> sys.stderr, \
667                      '%s %s: configure returned %i.' % (m.path, m.version, scc)
668            sce += scc
669
670        return sce
671
672def main(argv=[__name__]):
673    self = os.path.basename(argv[0])
674    try:
675        opts, args = getopt.getopt(argv[1:],
676                                   "hr:d:o:",
677                                   ["help", "version", "version-tag=",
678                                    "version-dir=", "directory=",
679                                    "offset=", "no_config",
680                                    "with_version_directory",
681                                    "without_version_directory", "url=", "debug"])
682    except getopt.error, e:
683        print >>sys.stderr, '%s: %s' % (self, str(e))
684        print >>sys.stderr, "Try '%s --help' for more information." % self
685        return 1
686
687    global logger
688    logging.basicConfig()
689    logger = logging.getLogger(self)
690    logger.setLevel(logging.INFO)
691    if os.getenv('SVNDEBUG'):
692        logger.setLevel(logging.DEBUG)
693
694    cmt_context = CmtContext()
695    checkout = Checkout()
696
697    for o, v in opts:
698        if o in ("-h", "--help"):
699            print sys.modules[__name__].__doc__
700            return 0
701        elif o in ("--version",):
702            print '%s %s (%s)' % (self, __version__, __date__)
703            print '%sWritten by %s.' % (os.linesep, __author__)
704            return 0
705        elif o in ("-r", "--version-tag"):
706            checkout.version = v
707        elif o in ("--version-dir",):
708            checkout.version_dir = v
709        elif o in ("-d", "--directory"):
710            checkout.directory = v
711        elif o in ("-o", "--offset"):
712            checkout.offset = v
713        elif o in ("--no_config",):
714            cmt_context.config = False
715        elif o in ("--without_version_directory",):
716            cmt_context.with_version_directory = False
717        elif o in ("--with_version_directory",):
718            cmt_context.with_version_directory = True
719        elif o in ("--url",):
720            checkout.url = v
721        elif o in ("--debug",):
722            logger.setLevel(logging.DEBUG)
723
724    if not args:
725        print >>sys.stderr, '%s: missing path argument' % self
726        print >>sys.stderr, "Try '%s --help' for more information." % self
727        return 1
728
729    for arg in args:
730        checkout.add(Module(arg))
731
732    client_context = ClientContext()
733    sci = checkout.initialize(cmt_context, client_context)
734    sce = checkout.execute(cmt_context, client_context)
735
736    if sci != 0 or sce !=0:
737        return 1
738    else:
739        return 0
740
741if __name__ == '__main__':
742    sys.exit(main(sys.argv))
Note: See TracBrowser for help on using the repository browser.