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

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

See C.L. 527

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