source: pyutilib.svn/trunk/pyutilib/svn/svn_timemachine.py @ 2832

Revision 2832, 4.3 KB checked in by wehart, 2 years ago (diff)

Portability fixes for Python 3.x

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2#  _________________________________________________________________________
3#
4#  PyUtilib: A Python utility library.
5#  Copyright (c) 2008 Sandia Corporation.
6#  This software is distributed under the BSD License.
7#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8#  the U.S. Government retains certain rights in this software.
9#  _________________________________________________________________________
10#
11import os
12import re
13import sys
14
15from datetime import datetime, timedelta
16from subprocess import Popen, PIPE
17
18from pyutilib.svn.repository import svn_info, svn_externals, SvnError
19
20
21def checkout(path_list, date_str):
22    target, url, rev = path_list.pop(0)
23
24    # If the revision wasn't specified (i.e. fixed by the external
25    # itself), then we need to determine the correct revision number
26    # from the main date_str.
27    if rev is None:
28        # find the repo (the deep link may no longer exist) and get the rev
29        tmp_url = url;
30        while len(tmp_url):
31            try:
32                rev = svn_info(tmp_url, '{'+date_str+'}')['revision']
33            except SvnError:
34                pass
35            if rev is not None:
36                break
37            try:
38                tmp_url,junk = tmp_url.rsplit('/',1)
39            except ValueError:
40                tmp_url = ""
41        if not tmp_url:
42            raise SvnError( ("unable to determine repository revision number "
43                             "for '%s' on %s" % (url, date_str) ) )
44
45    # Check out the url to the target path, but DO NOT automatically
46    # checkout the externals
47    print("(INFO) Checking out %s at r%s to %s" % (url, rev, target))
48    cmd = [ 'svn', 'co', '-r', str(rev), '--ignore-externals',
49            url+'@'+str(rev), target ]
50    #print(' '.join(cmd))
51    p = Popen(cmd, stdout=PIPE, stderr=PIPE)
52    stdout, stderr = p.communicate()
53    if p.returncode:
54        raise SvnError( "svn info returned error %i:\n%s" %
55                        (p.returncode, stderr) )
56
57    # Parse the repo and get any externals that still need to be checked
58    # out.  Because we never change the working directory, we need to
59    # prepend the current target path to the external path before pushing
60    # the external onto the list of pending paths.
61    print("(INFO) Parsing externals for %s" % (url))
62    externals, svn15format = svn_externals(url, rev)
63    while externals:
64        tmp = externals.pop(0)
65        path_list.append((target+'/'+tmp.path, tmp.url, tmp.revision))
66
67
68#-----------------------------------------------------------------------
69# MAIN SCRIPT
70#
71
72def main():
73    # Check for sane usage.
74    me = os.path.basename(sys.argv[0])
75    if len(sys.argv) < 3 or len(sys.argv) > 4:
76        print("Usage: %s {revision|date} repo_url [path]" % (me))
77        print("")
78        print("  revision : the revision number to warp back to")
79        print("  date     : the date to warp back to (YYYY-MM-DD hh:mm:ss -TZ)")
80        print("  repo_url : the repository url to check out")
81        print("  path     : the destination path for the working copy")
82        print("")
83        sys.exit(1)
84
85    rev_or_date = sys.argv[1]
86    url = sys.argv[2]
87    if len(sys.argv) > 3:
88        target = sys.argv[3]
89    else:
90        target = url.rsplit('/',1)[1]
91
92    # First, get the date that we will be using to interrogate the repository
93    if re.match('^\d+$', rev_or_date):
94        fields = svn_info(url, rev_or_date)['last changed date'] \
95                 .split('(', 1)[0].strip().split(' ')
96
97        # Because this is the time that the revision was actually committed,
98        # we need to add a second to get the state immediately *after* the
99        # commit.
100        d = [int(x) for x in fields.pop(0).split('-')]
101        f = []
102        if len(fields):
103            f = [int(x) for x in fields.pop(0).split(':')]
104        while len(f) < 3:
105            f.append(0)
106        Date = datetime(d[0],d[1],d[2],f[0],f[1],f[2]) + timedelta(seconds=1)
107        fields.insert(0, Date.isoformat(' '))
108        date_str = ' '.join(fields)
109    else:
110        date_str = rev_or_date
111
112    print("(INFO) checking out the repository as it existed on %s" % date_str)
113
114    # Do the actual checkout -- this is recursive, so it will pick up ALL
115    # externals.
116    path_list = [(target, url, None)]
117    while path_list:
118        checkout(path_list, date_str)
119
120if __name__ == '__main__':
121    main()
Note: See TracBrowser for help on using the repository browser.