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

Last change on this file since 679 was 679, checked in by rybkin, 8 years ago

See C.L. 528

  • Property svn:executable set to *
File size: 28.9 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.10.0'
27__date__ = 'Fri May 27 2016'
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        if head_version:
207            self.set_head_version(head_version)
208        else:
209            self.set_head_version(os.getenv('CMTHEADVERSION', ''))
210
211    def set_head_version(self, version):
212        if not version:
213            self.head_version = ''
214            self.head_version_tag = False
215        elif version.startswith('!'):
216            # strip the leading '!'
217            # require synchronization with C++ code
218            self.head_version = version[1:]
219            self.head_version_tag = False
220        else:
221            self.head_version = version
222            self.head_version_tag = True
223
224    def eval_head_version(self, m):
225        return str(self.head_version).replace('<package>', '%(package)s').replace('<PACKAGE>', '%(PACKAGE)s').replace('<revision>', '%(revision)i') % \
226            {'package' : m.package,
227             'PACKAGE' : m.package.upper(),
228             'revision' : m.info.last_changed_rev} \
229             or 'HEAD'
230
231    def write(self, p, version):
232        #print >> sys.stderr, 'write:', p, version
233        try:
234            t = version + '\n'
235            if os.path.exists(p):
236                f = open(p, 'r+')
237                b = f.tell()
238                v = f.read()
239                if v != t:
240                    f.seek(b)
241                    f.write(t)
242                    f.truncate()
243            else:
244                f = open(p, 'w')
245                f.write(t)
246            f.close()
247        except IOError, e:
248            print >> sys.stderr, e
249            return 1
250        return 0
251       
252    def generate(self, p):
253        #print >> sys.stderr, 'generate:', p
254        curdir = cwd()
255#        cmd = 'cmt -disable_warnings'
256        cmd = 'cmt -q'
257        if self.with_version_directory:
258            cmd += ' -with_version_directory'
259        else:
260            cmd += ' -without_version_directory'
261        if self.cleanup:
262            cmd += ' -cleanup'
263        else:
264            cmd += ' -no_cleanup'
265        cmd += ' config'
266        cd(p)
267        sc = os.system(cmd)
268        if sc != 0: sc = 1
269        cd(curdir)
270#        return sc
271        return 0
272
273    def configure(self, path, version):
274        sc = 0
275        for d in ('cmt', 'mgr'):
276            p = os.path.join(path, d)
277            if os.path.isdir(p):
278                if not self.with_version_directory:
279                    sc += self.write(os.path.join(p,'version.cmt'), version)
280                elif os.path.exists(os.path.join(p,'version.cmt')):
281                    print >>sys.stderr, 'Warning: file %s normally should not be under version control. Please, consider removing' % os.path.join(d,'version.cmt')
282                    try:
283                        os.rename(os.path.join(p,'version.cmt'),
284                                  os.path.join(p,'version.cmt.orig'))
285                        print >>sys.stderr, 'renamed %s -> %s' % (`os.path.join(p,'version.cmt')`, `os.path.join(p,'version.cmt.orig')`)
286                    except (IOError, os.error), e:
287                        error(e)
288                   
289                if self.config:
290                    sc += self.generate(p)
291                return sc
292        return sc
293        #print >> sys.stderr, 'Cannot configure %s ' % (path, version)
294
295class Module(object):
296    def __init__(self, module):
297        self.module = module
298        self.init = False
299        class info(object):
300            last_changed_rev = 0
301        self.info = info
302#         print >>sys.stderr, 'init module %s: last_changed_rev %i' % \
303#               (self.module, self.info.last_changed_rev)
304       
305class Checkout(object):
306    def __init__(self,
307                 url = None,
308                 trunk = None,
309                 tags = None,
310                 branches = None,
311                 devbranches = None,
312                 version = None,
313                 version_dir = None,
314                 directory = None,
315                 offset = '',
316                 modules = []):
317        self.url = url
318        self.trunk = trunk
319        self.tags = tags
320        self.branches = branches
321        self.devbranches = devbranches
322        self.version = version
323        self.version_dir = version_dir
324        self.directory = directory
325        self.offset = offset
326        self.modules = modules
327        self.reposLayout()
328       
329    def reposLayout(self):
330        if self.url is None:
331            self.url = os.getenv('SVNROOT', '')
332#             try:
333#                 self.url = os.environ['SVNROOT']
334#             except KeyError:
335#                 pass
336        if self.trunk is None:
337            self.trunk = os.getenv('SVNTRUNK', 'trunk')
338        if self.tags is None:
339            self.tags = os.getenv('SVNTAGS', 'tags')
340        if self.branches is None:
341            self.branches = os.getenv('SVNBRANCHES', 'branches')
342        if self.devbranches is None:
343            self.devbranches = os.getenv('SVNDEVBRANCHES', 'devbranches')
344
345    def cmtRepos(self):
346        self.url = 'https://svn.lal.in2p3.fr/projects/CMT'
347        self.trunk = 'HEAD'
348        self.tags= '.'
349        self.branches = '.'
350        self.devbranches = '.'
351
352    def add(self, module):
353        self.modules.append(module)
354
355    def info_receiver(self, path, info, pool):
356        self.path = path
357        self.info = info
358        pool.info = info
359
360    def cmp(self, path1, path2, client_context):
361        cmd = 'svn diff %s %s' % (path1, path2)
362#        cmd = 'svn diff --summarize %s %s' % (path1, path2)
363        sc, out = Utils.getstatusoutput(cmd)
364        if sc != 0:
365            return 2
366        if out: return 1
367        else: return 0
368
369#         outfile = tempfile.TemporaryFile('wb')
370#         errfile = tempfile.TemporaryFile('wb')
371#         outb = outfile.tell()
372#         errb = errfile.tell()
373#         client.diff([]
374#                     , path1
375#                     , self.head_revision
376#                     , path2
377#                     , self.head_revision
378#                     , True, True, False
379#                     , outfile
380#                     , errfile
381#                     , client_context())
382
383#         # position at the end of the file
384#         outfile.seek(0, 2)
385#         errfile.seek(0, 2)
386#         oute = outfile.tell()
387#         erre = errfile.tell()
388
389#         if erre > errb: return 2
390#         elif oute > outb: return 1
391#         else: return 0
392
393    def trunk_tag(self, module, client_context):
394        """Attempt to determine the tag of the module's trunk.
395       
396        Return the tag if its files are copied from the trunk and
397        their last_changed_rev numbers are the same as those of the trunk files.
398        """
399        trunk = posixpath.join(module.url, self.trunk)
400#        trunk = posixpath.normpath(posixpath.join(module.url, self.trunk))
401        cmd = 'svn ls -vR %s' % trunk
402        sc, out = Utils.getstatusoutput(cmd)
403        logger.debug('%s\n%s' % (cmd, out))
404        if sc != 0:
405            return None
406        trunk_dirent = [line.split() for line in out.splitlines()]
407        trunk_revs = dict([(line[-1], int(line[0])) for line in trunk_dirent if not line[-1].endswith(posixpath.sep)])
408        logger.debug('%s' % trunk_revs)
409
410        curdir = posixpath.curdir + posixpath.sep
411        for line in trunk_dirent:
412            if line[-1] == curdir:
413                class info(object): pass
414                info.last_changed_rev = int(line[0])
415                self.info_receiver(trunk, info, module)
416                logger.debug('last_changed_rev: %d' % info.last_changed_rev)
417                break
418
419#        cmd = 'svn info %s' % trunk
420#         p = r'last\s+changed\s+rev:\s+(?P<rev>\d+)'
421#         m = re.search(p, out, re.I)
422#         if m:
423#             class info(object): pass
424#             info.last_changed_rev = int(m.group('rev'))
425#             self.info_receiver(trunk, info, module)
426# #            self.info_receiver(trunk, info, None)
427# #             print >>sys.stderr, '%s: last_changed_rev %i' % \
428# #                   (trunk, self.info.last_changed_rev)
429# #            last_changed_rev = int(m.group('rev'))
430#         else:
431#             return None
432
433        tags = posixpath.join(module.url, self.tags)
434#        tags = posixpath.normpath(posixpath.join(module.url, self.tags))
435        cmd = 'svn ls -vR %s' % tags
436#        cmd = 'svn ls -v %s' % tags
437        sc, out = Utils.getstatusoutput(cmd)
438        logger.debug('%s\n%s' % (cmd, out))
439        if sc != 0:
440            return None
441        tags_dirent = [line.split() for line in out.splitlines()]
442        tags_revs = dict()
443        for ent in tags_dirent:
444            try:
445                tag, path = ent[-1].split(posixpath.sep, 1)
446            except ValueError:
447                continue
448            if tag not in tags_revs:
449                tags_revs[tag] = dict()
450            if path and not path.endswith(posixpath.sep):
451                # assume there are no empty directories in the tag
452                tags_revs[tag][path] = int(ent[0])
453        logger.debug('%s' % tags_revs)
454
455        cmd = 'svn info %s' % trunk
456        sc, out = Utils.getstatusoutput(cmd)
457        logger.debug('%s\n%s' % (cmd, out))
458        if sc != 0:
459            return None
460        p = r'repository\s+root:\s+(?P<root>%s://\S+)' % \
461            ('(?:' + '|'.join(map(re.escape, client_context.schemes)) + ')')
462        m = re.search(p, out, re.I)
463        logger.debug('pattern: %r' % (p))
464        if m:
465            root = m.group('root')
466        else:
467            return None
468        logger.debug('root: %s' % root)
469        trunk_path = trunk[len(root):]
470        tags_path = tags[len(root):]
471        logger.debug('trunk_path: %s' % trunk_path)
472        logger.debug('tags_path: %s' % tags_path)
473        offset = len(trunk) - len(root) + len(posixpath.sep)
474       
475        # Usually, a tag is created as a server-side copy.
476        # Sometimes, a tag is created as a copy of WC (working copy)
477        # after commit.
478        # Below, we try to take into account the latter case.
479        cmd = 'svn log -v -q %s' % tags
480        sc, out = Utils.getstatusoutput(cmd)
481        logger.debug('%s\n%s' % (cmd, out))
482        if sc != 0:
483            return None
484        p = re.compile(
485            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)
486            , re.M
487            )
488        tags_copied = list()
489        tags_replaced_revs = dict()
490        for m in p.finditer(out):
491            logger.debug('tag: %s replaced: %r' % (m.group('tag'), m.group('replaced')))
492            tags_copied.append(m.group('tag'))
493            for line in m.group('replaced').strip().splitlines():
494                l = line.split()
495                if len(l) == 2: continue # action code D - deleted paths
496                repl = l[3].rstrip(')')
497                i = repl.rindex(':')
498                path = repl[offset:i]
499                rev = int(repl[i + 1:])
500                logger.debug('path: %s rev: %d' % (path, rev))
501
502                if m.group('tag') not in tags_replaced_revs:
503                    tags_replaced_revs[m.group('tag')] = dict()
504                if path and not path.endswith(posixpath.sep):
505                    # assume there are no empty directories in the tag
506                    tags_replaced_revs[m.group('tag')][path] = rev
507
508        logger.debug('copied: %s' % tags_copied)
509        logger.debug('replaced: %s' % tags_replaced_revs)
510
511        for t in tags_revs.keys():
512            if t not in tags_copied:
513                del tags_revs[t]
514                logger.debug('%s: Not a trunk copy' % t)
515
516        for t in tags_replaced_revs:
517            if t in tags_revs:
518                tags_revs[t].update(tags_replaced_revs[t])
519               
520        for tag in tags_revs:
521            logger.debug('Compare: %s -> %s' % (tag, tags_revs[tag]))
522            if trunk_revs == tags_revs[tag]:
523                return tag
524
525        return None
526
527#         tags_dirent = [line.split() for line in out.splitlines()]
528#         rev_tag = dict([(int(line[0]), line[-1].rstrip(posixpath.sep)) for line in tags_dirent if line[-1].endswith(posixpath.sep)])
529#         revs = rev_tag.keys()
530#         revs.sort()
531#         revs.reverse()
532
533#         for rev in revs:
534#             logger.debug('rev: %s' % rev)
535#             if rev < self.info.last_changed_rev: break
536# #            if rev < last_changed_rev: break
537#             tag = posixpath.join(tags, rev_tag[rev])
538# #            tag = posixpath.normpath(posixpath.join(tags, rev_tag[rev]))
539#             logger.debug('comparing: %s %s(%d)' % (trunk, tag, rev))
540#             if 0 == self.cmp(trunk, tag, client_context):
541#                 return rev_tag[rev]
542
543#         return None
544
545#         try:
546#             trunk = core.svn_path_canonicalize(posixpath.join(module.url, self.trunk))
547#             client.info(trunk,
548#                         self.head_revision,
549#                         self.head_revision,
550#                         self.info_receiver,
551#                         False,
552#                         client_context())
553           
554#             tags = core.svn_path_canonicalize(posixpath.join(module.url, self.tags))
555#             tags_dirent = client.ls(tags,
556#                                     self.head_revision,
557#                                     False,
558#                                     client_context())
559           
560#             rev_tag = dict([(tags_dirent[p].created_rev, p) for p in tags_dirent if tags_dirent[p].kind == core.svn_node_dir])
561#             revs = rev_tag.keys()
562#             revs.sort()
563#             revs.reverse()
564
565#             for rev in revs:
566#                 if rev < self.info.last_changed_rev: break
567#                 tag = core.svn_path_canonicalize(posixpath.join(tags, rev_tag[rev]))
568#                 if 0 == self.cmp(trunk, tag, client_context):
569#                     return rev_tag[rev]
570
571#             return None
572#         except core.SubversionException, e:
573#             return None
574
575    def initialize(self, cmt_context, client_context):
576        sc = 0
577#         self.head_revision = core.svn_opt_revision_t()
578#         self.head_revision.kind = core.svn_opt_revision_head
579
580        # canonicalize:
581        self.url = client_context.svn_path_canonicalize(self.url)
582        self.offset = client_context.svn_path_canonicalize(self.offset)
583
584        for m in self.modules:
585            m.module = client_context.svn_path_canonicalize(m.module)
586            m.url = client_context.urljoin(self.url, self.offset, m.module)
587
588            if urlparse.urlparse(m.url)[0] not in client_context.schemes:
589                error('%s: Not a valid Subversion URL' % m.url)
590                sc += 1; continue
591#             print >>sys.stderr, '%s: URL constructed from %s %s %s' % \
592#                   (m.url, `self.url`, `self.offset`, `m.module`)
593
594            m.package = posixpath.basename(m.url)
595
596            if self.directory is not None:
597                m.path = os.path.normpath(self.directory)
598            else:
599                scheme, netloc, path, query, fragment = urlparse.urlsplit(m.module)
600                if not scheme and not netloc:
601                    m.path = os.path.normpath(os.path.join(*path.split(posixpath.sep)))
602                else:
603                    m.path = posixpath.basename(m.url)
604
605            if self.version is None:
606                m.head = True
607                if cmt_context.head_version_tag:
608                    m.version = self.trunk_tag(m, client_context) or \
609                        cmt_context.eval_head_version(m)
610                else:
611                    trunk = posixpath.join(m.url, self.trunk)
612                    cmd = 'svn info %s' % trunk
613                    scc, out = Utils.getstatusoutput(cmd)
614                    logger.debug('%s\n%s' % (cmd, out))
615                    if scc != 0:
616                        logger.error('%s\n%s' % (cmd, out))
617                        sc += 1; continue
618                    p = r'last\s+changed\s+rev:\s+(?P<rev>\d+)'
619                    M = re.search(p, out, re.I)
620                    if M:
621                        class info(object): pass
622                        info.last_changed_rev = int(M.group('rev'))
623                        self.info_receiver(trunk, info, m)
624                        logger.debug('last_changed_rev: %d' % info.last_changed_rev)
625                    else:
626                        logger.warning('%s: last_changed_rev: Not found' % trunk)
627                    m.version = cmt_context.eval_head_version(m)
628                logger.debug('set version: %s' % m.version)
629            else:
630                m.head = False
631                m.version = self.version
632
633            if m.head:
634                m.URL = [posixpath.join(m.url, self.trunk)]
635            else:
636                m.URL = [posixpath.join(m.url, p, m.version)
637                         for p in (self.tags, self.branches, self.devbranches)]
638            m.URL = [client_context.svn_path_canonicalize(url) for url in m.URL]
639#            m.URL = [core.svn_path_canonicalize(url) for url in m.URL]
640
641            if cmt_context.with_version_directory:
642                if self.version_dir is None:
643                    m.path = os.path.join(m.path, m.version)
644                else:
645                    m.path = os.path.join(m.path, self.version_dir)
646
647            m.init = True
648#            print m.URL, m.path, m.init
649           
650#        for m in self.modules:
651#            print m.url, m.path, m.init
652        return sc
653
654    def execute(self, cmt_context, client_context):
655        sce = 0
656
657        for m in self.modules:
658            if not m.init: continue
659            done = False
660            err = []
661            for url in m.URL:
662                cmd = 'svn checkout %s %s' % (url, m.path)
663#                cmd = 'svn checkout -q %s %s' % (url, m.path)
664                sc, e = Utils.getstatuserror(cmd)
665#                 cmd = 'svn checkout -q %s %s' % (url, m.path)
666#                 sc, e = Utils.getstatusoutput(cmd)
667                if 0 == sc:
668#                 try:
669#                     #print 'client.checkout2:', url, m.path
670#                     result_rev = client.checkout2(url,
671#                                                   m.path,
672#                                                   self.head_revision,
673#                                                   self.head_revision,
674#                                                   True,
675#                                                   True,
676#                                                   client_context())
677#                 except core.SubversionException, e:
678#                     err.append(e)
679#                     continue
680                    done = True
681                    break
682                else:
683                    err.append(e)
684                    continue
685
686            if not done:
687                for e in err:
688                    error(e)
689#                     #print >> sys.stderr, e
690#                     sc += 1
691#                 print >> sys.stderr, 'Failed to checkout %s into %s.' % \
692#                       (' or '.join(m.URL), m.path)
693                sce += 1
694
695#            print 'Checked out revision %i.' % result_rev
696            scc = cmt_context.configure(m.path, m.version)
697            if scc != 0:
698                print >> sys.stderr, \
699                      '%s %s: configure returned %i.' % (m.path, m.version, scc)
700            sce += scc
701
702        return sce
703
704def main(argv=[__name__]):
705    self = os.path.basename(argv[0])
706    try:
707        opts, args = getopt.getopt(argv[1:],
708                                   "hr:d:o:",
709                                   ["help", "version", "version-tag=",
710                                    "version-dir=", "directory=",
711                                    "offset=", "no_config",
712                                    "with_version_directory",
713                                    "without_version_directory", "url=", "debug"])
714    except getopt.error, e:
715        print >>sys.stderr, '%s: %s' % (self, str(e))
716        print >>sys.stderr, "Try '%s --help' for more information." % self
717        return 1
718
719    global logger
720    logging.basicConfig()
721    logger = logging.getLogger(self)
722    logger.setLevel(logging.INFO)
723    if os.getenv('SVNDEBUG'):
724        logger.setLevel(logging.DEBUG)
725
726    cmt_context = CmtContext()
727    checkout = Checkout()
728
729    for o, v in opts:
730        if o in ("-h", "--help"):
731            print sys.modules[__name__].__doc__
732            return 0
733        elif o in ("--version",):
734            print '%s %s (%s)' % (self, __version__, __date__)
735            print '%sWritten by %s.' % (os.linesep, __author__)
736            return 0
737        elif o in ("-r", "--version-tag"):
738            checkout.version = v
739        elif o in ("--version-dir",):
740            checkout.version_dir = v
741        elif o in ("-d", "--directory"):
742            checkout.directory = v
743        elif o in ("-o", "--offset"):
744            checkout.offset = v
745        elif o in ("--no_config",):
746            cmt_context.config = False
747        elif o in ("--without_version_directory",):
748            cmt_context.with_version_directory = False
749        elif o in ("--with_version_directory",):
750            cmt_context.with_version_directory = True
751        elif o in ("--url",):
752            checkout.url = v
753        elif o in ("--debug",):
754            logger.setLevel(logging.DEBUG)
755
756    if not args:
757        print >>sys.stderr, '%s: missing path argument' % self
758        print >>sys.stderr, "Try '%s --help' for more information." % self
759        return 1
760
761    for arg in args:
762        checkout.add(Module(arg))
763
764    client_context = ClientContext()
765    sci = checkout.initialize(cmt_context, client_context)
766    sce = checkout.execute(cmt_context, client_context)
767
768    if sci != 0 or sce !=0:
769        return 1
770    else:
771        return 0
772
773if __name__ == '__main__':
774    sys.exit(main(sys.argv))
Note: See TracBrowser for help on using the repository browser.