source: CMT/v1r25-branch/mgr/cmt_svn_checkout.py @ 664

Last change on this file since 664 was 664, checked in by rybkin, 10 years ago

merge -r 646:663 HEAD

  • Property svn:executable set to *
File size: 27.7 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 (also SVNDEVBRANCHES) environment variables specify repository URL of PATH, location of PATH trunk, tags, and branches (also devbranches) (relatively to PATH) respectively.
22
23Report bugs to <CMT-L@IN2P3.FR>.
24"""
25
26__version__ = '0.8.0'
27__date__ = 'Wed Jul 31 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                 devbranches = None,
304                 version = None,
305                 version_dir = None,
306                 directory = None,
307                 offset = '',
308                 modules = []):
309        self.url = url
310        self.trunk = trunk
311        self.tags = tags
312        self.branches = branches
313        self.devbranches = devbranches
314        self.version = version
315        self.version_dir = version_dir
316        self.directory = directory
317        self.offset = offset
318        self.modules = modules
319        self.reposLayout()
320       
321    def reposLayout(self):
322        if self.url is None:
323            self.url = os.getenv('SVNROOT', '')
324#             try:
325#                 self.url = os.environ['SVNROOT']
326#             except KeyError:
327#                 pass
328        if self.trunk is None:
329            self.trunk = os.getenv('SVNTRUNK', 'trunk')
330        if self.tags is None:
331            self.tags = os.getenv('SVNTAGS', 'tags')
332        if self.branches is None:
333            self.branches = os.getenv('SVNBRANCHES', 'branches')
334        if self.devbranches is None:
335            self.devbranches = os.getenv('SVNDEVBRANCHES', 'devbranches')
336
337    def cmtRepos(self):
338        self.url = 'https://svn.lal.in2p3.fr/projects/CMT'
339        self.trunk = 'HEAD'
340        self.tags= '.'
341        self.branches = '.'
342        self.devbranches = '.'
343
344    def add(self, module):
345        self.modules.append(module)
346
347    def info_receiver(self, path, info, pool):
348        self.path = path
349        self.info = info
350        pool.info = info
351
352    def cmp(self, path1, path2, client_context):
353        cmd = 'svn diff %s %s' % (path1, path2)
354#        cmd = 'svn diff --summarize %s %s' % (path1, path2)
355        sc, out = Utils.getstatusoutput(cmd)
356        if sc != 0:
357            return 2
358        if out: return 1
359        else: return 0
360
361#         outfile = tempfile.TemporaryFile('wb')
362#         errfile = tempfile.TemporaryFile('wb')
363#         outb = outfile.tell()
364#         errb = errfile.tell()
365#         client.diff([]
366#                     , path1
367#                     , self.head_revision
368#                     , path2
369#                     , self.head_revision
370#                     , True, True, False
371#                     , outfile
372#                     , errfile
373#                     , client_context())
374
375#         # position at the end of the file
376#         outfile.seek(0, 2)
377#         errfile.seek(0, 2)
378#         oute = outfile.tell()
379#         erre = errfile.tell()
380
381#         if erre > errb: return 2
382#         elif oute > outb: return 1
383#         else: return 0
384
385    def trunk_tag(self, module, client_context):
386        """Attempt to determine the tag of the module's trunk.
387       
388        Return the tag if its files are copied from the trunk and
389        their last_changed_rev numbers are the same as those of the trunk files.
390        """
391        trunk = posixpath.join(module.url, self.trunk)
392#        trunk = posixpath.normpath(posixpath.join(module.url, self.trunk))
393        cmd = 'svn ls -vR %s' % trunk
394        sc, out = Utils.getstatusoutput(cmd)
395        logger.debug('%s\n%s' % (cmd, out))
396        if sc != 0:
397            return None
398        trunk_dirent = [line.split() for line in out.splitlines()]
399        trunk_revs = dict([(line[-1], int(line[0])) for line in trunk_dirent if not line[-1].endswith(posixpath.sep)])
400        logger.debug('%s' % trunk_revs)
401
402        curdir = posixpath.curdir + posixpath.sep
403        for line in trunk_dirent:
404            if line[-1] == curdir:
405                class info(object): pass
406                info.last_changed_rev = int(line[0])
407                self.info_receiver(trunk, info, module)
408                logger.debug('last_changed_rev: %d' % info.last_changed_rev)
409                break
410
411#        cmd = 'svn info %s' % trunk
412#         p = r'last\s+changed\s+rev:\s+(?P<rev>\d+)'
413#         m = re.search(p, out, re.I)
414#         if m:
415#             class info(object): pass
416#             info.last_changed_rev = int(m.group('rev'))
417#             self.info_receiver(trunk, info, module)
418# #            self.info_receiver(trunk, info, None)
419# #             print >>sys.stderr, '%s: last_changed_rev %i' % \
420# #                   (trunk, self.info.last_changed_rev)
421# #            last_changed_rev = int(m.group('rev'))
422#         else:
423#             return None
424
425        tags = posixpath.join(module.url, self.tags)
426#        tags = posixpath.normpath(posixpath.join(module.url, self.tags))
427        cmd = 'svn ls -vR %s' % tags
428#        cmd = 'svn ls -v %s' % tags
429        sc, out = Utils.getstatusoutput(cmd)
430        logger.debug('%s\n%s' % (cmd, out))
431        if sc != 0:
432            return None
433        tags_dirent = [line.split() for line in out.splitlines()]
434        tags_revs = dict()
435        for ent in tags_dirent:
436            try:
437                tag, path = ent[-1].split(posixpath.sep, 1)
438            except ValueError:
439                continue
440            if tag not in tags_revs:
441                tags_revs[tag] = dict()
442            if path and not path.endswith(posixpath.sep):
443                # assume there are no empty directories in the tag
444                tags_revs[tag][path] = int(ent[0])
445        logger.debug('%s' % tags_revs)
446
447        cmd = 'svn info %s' % trunk
448        sc, out = Utils.getstatusoutput(cmd)
449        logger.debug('%s\n%s' % (cmd, out))
450        if sc != 0:
451            return None
452        p = r'repository\s+root:\s+(?P<root>%s://\S+)' % \
453            ('(?:' + '|'.join(map(re.escape, client_context.schemes)) + ')')
454        m = re.search(p, out, re.I)
455        logger.debug('pattern: %r' % (p))
456        if m:
457            root = m.group('root')
458        else:
459            return None
460        logger.debug('root: %s' % root)
461        trunk_path = trunk[len(root):]
462        tags_path = tags[len(root):]
463        logger.debug('trunk_path: %s' % trunk_path)
464        logger.debug('tags_path: %s' % tags_path)
465        offset = len(trunk) - len(root) + len(posixpath.sep)
466       
467        # Usually, a tag is created as a server-side copy.
468        # Sometimes, a tag is created as a copy of WC (working copy)
469        # after commit.
470        # Below, we try to take into account the latter case.
471        cmd = 'svn log -v -q %s' % tags
472        sc, out = Utils.getstatusoutput(cmd)
473        logger.debug('%s\n%s' % (cmd, out))
474        if sc != 0:
475            return None
476        p = re.compile(
477            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)
478            , re.M
479            )
480        tags_copied = list()
481        tags_replaced_revs = dict()
482        for m in p.finditer(out):
483            logger.debug('tag: %s replaced: %r' % (m.group('tag'), m.group('replaced')))
484            tags_copied.append(m.group('tag'))
485            for line in m.group('replaced').strip().splitlines():
486                l = line.split()
487                if len(l) == 2: continue # action code D - deleted paths
488                repl = l[3].rstrip(')')
489                i = repl.rindex(':')
490                path = repl[offset:i]
491                rev = int(repl[i + 1:])
492                logger.debug('path: %s rev: %d' % (path, rev))
493
494                if m.group('tag') not in tags_replaced_revs:
495                    tags_replaced_revs[m.group('tag')] = dict()
496                if path and not path.endswith(posixpath.sep):
497                    # assume there are no empty directories in the tag
498                    tags_replaced_revs[m.group('tag')][path] = rev
499
500        logger.debug('copied: %s' % tags_copied)
501        logger.debug('replaced: %s' % tags_replaced_revs)
502
503        for t in tags_revs.keys():
504            if t not in tags_copied:
505                del tags_revs[t]
506                logger.debug('%s: Not a trunk copy' % t)
507
508        for t in tags_replaced_revs:
509            if t in tags_revs:
510                tags_revs[t].update(tags_replaced_revs[t])
511               
512        for tag in tags_revs:
513            logger.debug('Compare: %s -> %s' % (tag, tags_revs[tag]))
514            if trunk_revs == tags_revs[tag]:
515                return tag
516
517        return None
518
519#         tags_dirent = [line.split() for line in out.splitlines()]
520#         rev_tag = dict([(int(line[0]), line[-1].rstrip(posixpath.sep)) for line in tags_dirent if line[-1].endswith(posixpath.sep)])
521#         revs = rev_tag.keys()
522#         revs.sort()
523#         revs.reverse()
524
525#         for rev in revs:
526#             logger.debug('rev: %s' % rev)
527#             if rev < self.info.last_changed_rev: break
528# #            if rev < last_changed_rev: break
529#             tag = posixpath.join(tags, rev_tag[rev])
530# #            tag = posixpath.normpath(posixpath.join(tags, rev_tag[rev]))
531#             logger.debug('comparing: %s %s(%d)' % (trunk, tag, rev))
532#             if 0 == self.cmp(trunk, tag, client_context):
533#                 return rev_tag[rev]
534
535#         return None
536
537#         try:
538#             trunk = core.svn_path_canonicalize(posixpath.join(module.url, self.trunk))
539#             client.info(trunk,
540#                         self.head_revision,
541#                         self.head_revision,
542#                         self.info_receiver,
543#                         False,
544#                         client_context())
545           
546#             tags = core.svn_path_canonicalize(posixpath.join(module.url, self.tags))
547#             tags_dirent = client.ls(tags,
548#                                     self.head_revision,
549#                                     False,
550#                                     client_context())
551           
552#             rev_tag = dict([(tags_dirent[p].created_rev, p) for p in tags_dirent if tags_dirent[p].kind == core.svn_node_dir])
553#             revs = rev_tag.keys()
554#             revs.sort()
555#             revs.reverse()
556
557#             for rev in revs:
558#                 if rev < self.info.last_changed_rev: break
559#                 tag = core.svn_path_canonicalize(posixpath.join(tags, rev_tag[rev]))
560#                 if 0 == self.cmp(trunk, tag, client_context):
561#                     return rev_tag[rev]
562
563#             return None
564#         except core.SubversionException, e:
565#             return None
566
567    def initialize(self, cmt_context, client_context):
568        sc = 0
569#         self.head_revision = core.svn_opt_revision_t()
570#         self.head_revision.kind = core.svn_opt_revision_head
571
572        # canonicalize:
573        self.url = client_context.svn_path_canonicalize(self.url)
574        self.offset = client_context.svn_path_canonicalize(self.offset)
575
576        for m in self.modules:
577            m.module = client_context.svn_path_canonicalize(m.module)
578            m.url = client_context.urljoin(self.url, self.offset, m.module)
579
580            if urlparse.urlparse(m.url)[0] not in client_context.schemes:
581                error('%s: Not a valid Subversion URL' % m.url)
582                sc += 1; continue
583#             print >>sys.stderr, '%s: URL constructed from %s %s %s' % \
584#                   (m.url, `self.url`, `self.offset`, `m.module`)
585
586            m.package = posixpath.basename(m.url)
587
588            if self.directory is not None:
589                m.path = os.path.normpath(self.directory)
590            else:
591                scheme, netloc, path, query, fragment = urlparse.urlsplit(m.module)
592                if not scheme and not netloc:
593                    m.path = os.path.normpath(os.path.join(*path.split(posixpath.sep)))
594                else:
595                    m.path = posixpath.basename(m.url)
596
597            if self.version is None:
598                m.head = True
599                m.version = self.trunk_tag(m, client_context) or \
600                            cmt_context.eval_head_version(m)
601#                print >>sys.stderr, 'set version: %s' % m.version
602            else:
603                m.head = False
604                m.version = self.version
605
606            if m.head:
607                m.URL = [posixpath.join(m.url, self.trunk)]
608            else:
609                m.URL = [posixpath.join(m.url, p, m.version)
610                         for p in (self.tags, self.branches, self.devbranches)]
611            m.URL = [client_context.svn_path_canonicalize(url) for url in m.URL]
612#            m.URL = [core.svn_path_canonicalize(url) for url in m.URL]
613
614            if cmt_context.with_version_directory:
615                if self.version_dir is None:
616                    m.path = os.path.join(m.path, m.version)
617                else:
618                    m.path = os.path.join(m.path, self.version_dir)
619
620            m.init = True
621#            print m.URL, m.path, m.init
622           
623#        for m in self.modules:
624#            print m.url, m.path, m.init
625        return sc
626
627    def execute(self, cmt_context, client_context):
628        sce = 0
629
630        for m in self.modules:
631            if not m.init: continue
632            done = False
633            err = []
634            for url in m.URL:
635                cmd = 'svn checkout %s %s' % (url, m.path)
636#                cmd = 'svn checkout -q %s %s' % (url, m.path)
637                sc, e = Utils.getstatuserror(cmd)
638#                 cmd = 'svn checkout -q %s %s' % (url, m.path)
639#                 sc, e = Utils.getstatusoutput(cmd)
640                if 0 == sc:
641#                 try:
642#                     #print 'client.checkout2:', url, m.path
643#                     result_rev = client.checkout2(url,
644#                                                   m.path,
645#                                                   self.head_revision,
646#                                                   self.head_revision,
647#                                                   True,
648#                                                   True,
649#                                                   client_context())
650#                 except core.SubversionException, e:
651#                     err.append(e)
652#                     continue
653                    done = True
654                    break
655                else:
656                    err.append(e)
657                    continue
658
659            if not done:
660                for e in err:
661                    error(e)
662#                     #print >> sys.stderr, e
663#                     sc += 1
664#                 print >> sys.stderr, 'Failed to checkout %s into %s.' % \
665#                       (' or '.join(m.URL), m.path)
666                sce += 1
667
668#            print 'Checked out revision %i.' % result_rev
669            scc = cmt_context.configure(m.path, m.version)
670            if scc != 0:
671                print >> sys.stderr, \
672                      '%s %s: configure returned %i.' % (m.path, m.version, scc)
673            sce += scc
674
675        return sce
676
677def main(argv=[__name__]):
678    self = os.path.basename(argv[0])
679    try:
680        opts, args = getopt.getopt(argv[1:],
681                                   "hr:d:o:",
682                                   ["help", "version", "version-tag=",
683                                    "version-dir=", "directory=",
684                                    "offset=", "no_config",
685                                    "with_version_directory",
686                                    "without_version_directory", "url=", "debug"])
687    except getopt.error, e:
688        print >>sys.stderr, '%s: %s' % (self, str(e))
689        print >>sys.stderr, "Try '%s --help' for more information." % self
690        return 1
691
692    global logger
693    logging.basicConfig()
694    logger = logging.getLogger(self)
695    logger.setLevel(logging.INFO)
696    if os.getenv('SVNDEBUG'):
697        logger.setLevel(logging.DEBUG)
698
699    cmt_context = CmtContext()
700    checkout = Checkout()
701
702    for o, v in opts:
703        if o in ("-h", "--help"):
704            print sys.modules[__name__].__doc__
705            return 0
706        elif o in ("--version",):
707            print '%s %s (%s)' % (self, __version__, __date__)
708            print '%sWritten by %s.' % (os.linesep, __author__)
709            return 0
710        elif o in ("-r", "--version-tag"):
711            checkout.version = v
712        elif o in ("--version-dir",):
713            checkout.version_dir = v
714        elif o in ("-d", "--directory"):
715            checkout.directory = v
716        elif o in ("-o", "--offset"):
717            checkout.offset = v
718        elif o in ("--no_config",):
719            cmt_context.config = False
720        elif o in ("--without_version_directory",):
721            cmt_context.with_version_directory = False
722        elif o in ("--with_version_directory",):
723            cmt_context.with_version_directory = True
724        elif o in ("--url",):
725            checkout.url = v
726        elif o in ("--debug",):
727            logger.setLevel(logging.DEBUG)
728
729    if not args:
730        print >>sys.stderr, '%s: missing path argument' % self
731        print >>sys.stderr, "Try '%s --help' for more information." % self
732        return 1
733
734    for arg in args:
735        checkout.add(Module(arg))
736
737    client_context = ClientContext()
738    sci = checkout.initialize(cmt_context, client_context)
739    sce = checkout.execute(cmt_context, client_context)
740
741    if sci != 0 or sce !=0:
742        return 1
743    else:
744        return 0
745
746if __name__ == '__main__':
747    sys.exit(main(sys.argv))
Note: See TracBrowser for help on using the repository browser.