source: CMT/v1r20p20090520/mgr/cmt_svn_checkout.py

Last change on this file was 501, checked in by rybkin, 15 years ago

See C.L. 396

  • Property svn:executable set to *
File size: 13.1 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  -h, --help                   display this help and exit
18      --version                output version information and exit
19
20The SVNROOT, SVNTRUNK, SVNTAGS, and SVNBRANCHES environment variables specify repository URL of PATH, location of PATH trunk, tags, and branches (relatively to PATH) respectively.
21
22Report bugs to <CMT-L@IN2P3.FR>.
23"""
24
25__version__ = '0.1.5'
26__date__ = 'Tue May 05 2009'
27__author__ = 'Grigory Rybkin'
28
29import sys
30import getopt
31import os
32import posixpath
33import os.path
34import urlparse
35
36self = 'cmt_svn_checkout.py'
37try:
38    from svn import client, core
39except ImportError, e:
40    print >>sys.stderr, '%s: cannot import Subversion Python bindings: %s' \
41          % (self, str(e))
42    sys.exit(1)
43
44class ClientContext(object):
45    def __init__(self):
46        core.svn_config_ensure(None)
47        self.ctx = client.create_context()
48        self.providers = [
49            client.get_simple_provider(),
50            client.get_username_provider(),
51            client.get_ssl_server_trust_file_provider(),
52            client.get_ssl_client_cert_file_provider(),
53            client.get_ssl_client_cert_pw_file_provider()
54            ]
55        self.ctx.auth_baton = core.svn_auth_open(self.providers)
56        self.ctx.config = core.svn_config_get_config(None)
57
58    def __call__(self):
59        return self.ctx
60
61def cwd():
62    _gcwd = os.getcwd()
63    try:
64        _cwd = os.environ['PWD']
65        if _cwd and os.path.samefile(_cwd, _gcwd):
66            return _cwd
67        else:
68            return _gcwd
69    except (KeyError, AttributeError):
70        return _gcwd
71
72def cd(path):
73    new = os.path.normpath(os.path.join(cwd(), path))
74    os.chdir(path)
75    _gcwd = os.getcwd()
76    try:
77        if os.path.samefile(new, _gcwd):
78            os.environ['PWD'] = new
79        else:
80            os.environ['PWD'] = _gcwd
81    except AttributeError:
82        pass
83
84def error(instance, location='', file = sys.stderr):
85    try:
86        message = ': '.join([str(arg) for arg in instance.args])
87    except AttributeError:
88        message = instance
89    if location: location += ': '
90    print >> file, "%s%s" % (location, message)
91   
92class CmtContext(object):
93    def __init__(self,
94                 config = True,
95                 with_version_directory = True,
96                 cleanup = False):
97        self.config = config
98        self.with_version_directory = with_version_directory
99        self.cleanup = cleanup
100
101    def write(self, p, version):
102        #print >> sys.stderr, 'write:', p, version
103        try:
104            t = version + '\n'
105            if os.path.exists(p):
106                f = open(p, 'r+')
107                b = f.tell()
108                v = f.read()
109                if v != t:
110                    f.seek(b)
111                    f.write(t)
112                    f.truncate()
113            else:
114                f = open(p, 'w')
115                f.write(t)
116            f.close()
117        except IOError, e:
118            print >> sys.stderr, e
119            return 1
120        return 0
121       
122    def generate(self, p):
123        #print >> sys.stderr, 'generate:', p
124        curdir = cwd()
125        cmd = 'cmt -disable_warnings'
126        if self.with_version_directory:
127            cmd += ' -with_version_directory'
128        else:
129            cmd += ' -without_version_directory'
130        if self.cleanup:
131            cmd += ' -cleanup'
132        else:
133            cmd += ' -no_cleanup'
134        cmd += ' config'
135        cd(p)
136        sc = os.system(cmd)
137        if sc != 0: sc = 1
138        cd(curdir)
139        return sc
140
141    def configure(self, path, version):
142        sc = 0
143        for d in ('cmt', 'mgr'):
144            p = os.path.join(path, d)
145            if os.path.isdir(p):
146                if not self.with_version_directory:
147                    sc += self.write(os.path.join(p,'version.cmt'), version)
148                if self.config:
149                    sc += self.generate(p)
150                return sc
151        return sc
152        #print >> sys.stderr, 'Cannot configure %s ' % (path, version)
153
154class Module(object):
155    def __init__(self, module):
156        self.module = module
157        self.init = False
158       
159class Checkout(object):
160    def __init__(self,
161                 url = None,
162                 trunk = None,
163                 tags = None,
164                 branches = None,
165                 version = None,
166                 version_dir = None,
167                 directory = None,
168                 offset = None,
169                 modules = []):
170        self.url = url
171        self.trunk = trunk
172        self.tags = tags
173        self.branches = branches
174        self.version = version
175        self.version_dir = version_dir
176        self.directory = directory
177        self.offset = offset
178        self.modules = modules
179        self.reposLayout()
180       
181    def reposLayout(self):
182        if self.url is None:
183            try:
184                self.url = os.environ['SVNROOT']
185            except KeyError:
186                pass
187        if self.trunk is None:
188            try:
189                self.trunk = os.environ['SVNTRUNK']
190            except KeyError:
191                self.trunk = 'trunk'
192        if self.tags is None:
193            try:
194                self.tags = os.environ['SVNTAGS']
195            except KeyError:
196                self.tags = 'tags'
197        if self.branches is None:
198            try:
199                self.branches = os.environ['SVNBRANCHES']
200            except KeyError:
201                self.branches = 'branches'
202
203    def cmtRepos(self):
204        self.url = 'https://svn.lal.in2p3.fr/projects/CMT'
205        self.trunk = 'HEAD'
206        self.tags= '.'
207        self.branches = '.'
208
209    def add(self, module):
210        self.modules.append(module)
211
212    def initialize(self, cmt_context, client_context):
213        sc = 0
214        self.head_revision = core.svn_opt_revision_t()
215        self.head_revision.kind = core.svn_opt_revision_head
216
217        for m in self.modules:
218            if urlparse.urlparse(m.module)[0] in ('http', 'https',
219                                                  'svn', 'svn+ssh', 'file'):
220                m.url = m.module
221                m.path = posixpath.basename(m.module)
222            elif posixpath.isabs(m.module):
223                m.url = urlparse.urljoin('file://', m.module)
224                m.path = posixpath.basename(m.module)
225            else:
226                if self.url is None:
227                    self.cmtRepos()
228
229                if self.offset is None:
230                    m.url = posixpath.join(self.url, m.module)
231                else:
232                    m.url = posixpath.join(self.url, self.offset, m.module)
233                m.path = os.path.join(*m.module.split(posixpath.sep))
234
235            if self.directory is not None:
236                m.path = os.path.normpath(self.directory)
237               
238            if self.version is None:
239                m.head = True
240                tags = core.svn_path_canonicalize(posixpath.join(m.url, self.tags))
241                try:
242                    #print 'client.ls2:', tags
243                    ls_tags = client.ls2(tags,
244                                         self.head_revision,
245                                         self.head_revision,
246                                         False,
247                                         client_context())
248                    rev_tag = dict([(ls_tags[p].created_rev, p) for p in ls_tags if ls_tags[p].kind == core.svn_node_dir])
249#                rev_latest = max(rev_tag.keys())
250#                tag_latest = rev_tag[rev_latest]
251                    m.version = rev_tag[max(rev_tag.keys())]
252                except core.SubversionException, e:
253                    error(e)
254                    #print >> sys.stderr, e
255                    m.version = 'HEAD'
256                except ValueError, e: # max() arg is an empty sequence
257                    #print >> sys.stderr, e
258                    m.version = 'HEAD'
259            else:
260                m.head = False
261                m.version = self.version
262
263            if m.head:
264                m.URL = [posixpath.join(m.url, self.trunk)]
265            else:
266#                m.url = posixpath.join(m.url, self.tags, m.version)
267                m.URL = [posixpath.join(m.url, p, m.version)
268                         for p in (self.tags, self.branches)]
269                #m.URL = [posixpath.join(m.url, self.tags, m.version),
270                #         posixpath.join(m.url, self.branches, m.version)]
271            #m.url = core.svn_path_canonicalize(m.url)
272            m.URL = [core.svn_path_canonicalize(url) for url in m.URL]
273
274            if cmt_context.with_version_directory:
275                if self.version_dir is None:
276                    m.path = os.path.join(m.path, m.version)
277                else:
278                    m.path = os.path.join(m.path, self.version_dir)
279
280            m.init = True
281#            print m.URL, m.path, m.init
282           
283#        for m in self.modules:
284#            print m.url, m.path, m.init
285        return sc
286
287    def execute(self, cmt_context, client_context):
288        sc = 0
289
290        for m in self.modules:
291            if not m.init: continue
292            done = False
293            err = []
294            for url in m.URL:
295                try:
296                    #print 'client.checkout2:', url, m.path
297                    result_rev = client.checkout2(url,
298                                                  m.path,
299                                                  self.head_revision,
300                                                  self.head_revision,
301                                                  True,
302                                                  True,
303                                                  client_context())
304                except core.SubversionException, e:
305                    err.append(e)
306                    continue
307                done = True
308                break
309
310            if not done:
311                for e in err:
312                    error(e)
313                    #print >> sys.stderr, e
314                    sc += 1
315                continue
316
317#            print 'Checked out revision %i.' % result_rev
318            scc = cmt_context.configure(m.path, m.version)
319            if scc != 0:
320                print >> sys.stderr, \
321                      '%s %s: configure returned %i.' % (m.path, m.version, scc)
322            sc += scc
323
324        return sc
325
326def main(argv=[__name__]):
327    self = os.path.basename(argv[0])
328    try:
329        opts, args = getopt.getopt(argv[1:],
330                                   "hr:d:o:",
331                                   ["help", "version", "version-tag=",
332                                    "version-dir=", "directory=",
333                                    "offset=", "no_config",
334                                    "with_version_directory",
335                                    "without_version_directory", "url="])
336    except getopt.error, e:
337        print >>sys.stderr, '%s: %s' % (self, str(e))
338        print >>sys.stderr, "Try '%s --help' for more information." % self
339        return 1
340
341    cmt_context = CmtContext()
342    checkout = Checkout()
343
344    for o, v in opts:
345        if o in ("-h", "--help"):
346            print sys.modules[__name__].__doc__
347            return 0
348        elif o in ("--version",):
349            print '%s %s (%s)' % (self, __version__, __date__)
350            print '%sWritten by %s.' % (os.linesep, __author__)
351            return 0
352        elif o in ("-r", "--version-tag"):
353            checkout.version = v
354        elif o in ("--version-dir",):
355            checkout.version_dir = v
356        elif o in ("-d", "--directory"):
357            checkout.directory = v
358        elif o in ("-o", "--offset"):
359            checkout.offset = v
360        elif o in ("--no_config",):
361            cmt_context.config = False
362        elif o in ("--without_version_directory",):
363            cmt_context.with_version_directory = False
364        elif o in ("--with_version_directory",):
365            cmt_context.with_version_directory = True
366        elif o in ("--url",):
367            checkout.url = v
368
369    if not args:
370        print >>sys.stderr, '%s: missing path argument' % self
371        print >>sys.stderr, "Try '%s --help' for more information." % self
372        return 1
373
374    for arg in args:
375        checkout.add(Module(arg))
376
377    client_context = ClientContext()
378    sci = checkout.initialize(cmt_context, client_context)
379    sce = checkout.execute(cmt_context, client_context)
380
381    if sci != 0 or sce !=0:
382        return 1
383    else:
384        return 0
385
386if __name__ == '__main__':
387    sys.exit(main(sys.argv))
Note: See TracBrowser for help on using the repository browser.