Revision 4b61ee63

b/ci/filelocker.py
1
# filelocker.py - Cross-platform (posix/nt) API for flock-style file locking.
2
#                 Requires python 1.5.2 or better.
3
"""Cross-platform (posix/nt) API for flock-style file locking.
4

  
5

  
6
Synopsis:
7

  
8
    import filelocker
9
    with filelocker.lock("lockfile", filelocker.LOCK_EX):
10
        print "Got it"
11

  
12

  
13
Methods:
14

  
15
   lock ( file, flags, tries=10 )
16

  
17

  
18
Constants:
19

  
20
   LOCK_EX
21
   LOCK_SH
22
   LOCK_NB
23

  
24

  
25
Exceptions:
26

  
27
    LockException
28

  
29

  
30
Notes:
31

  
32
For the 'nt' platform, this module requires the Python Extensions for Windows.
33
Be aware that this may not work as expected on Windows 95/98/ME.
34

  
35

  
36
History:
37

  
38
I learned the win32 technique for locking files from sample code
39
provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
40
that accompanies the win32 modules.
41

  
42

  
43
Author: Jonathan Feinberg <jdf@pobox.com>,
44
        Lowell Alleman <lalleman@mfps.com>
45
Version: $Id: filelocker.py 5474 2008-05-16 20:53:50Z lowell $
46

  
47

  
48
Modified to work as a contextmanager
49

  
50
"""
51

  
52
import os
53
from contextlib import contextmanager
54

  
55

  
56
class LockException(Exception):
57
    # Error codes:
58
    LOCK_FAILED = 1
59

  
60

  
61
# Import modules for each supported platform
62
if os.name == 'nt':
63
    import win32con
64
    import win32file
65
    import pywintypes
66
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
67
    LOCK_SH = 0  # the default
68
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
69
    # is there any reason not to reuse the following structure?
70
    __overlapped = pywintypes.OVERLAPPED()
71
elif os.name == 'posix':
72
    import fcntl
73
    LOCK_EX = fcntl.LOCK_EX
74
    LOCK_SH = fcntl.LOCK_SH
75
    LOCK_NB = fcntl.LOCK_NB
76
else:
77
    raise RuntimeError("FileLocker only defined for nt and posix platforms")
78

  
79

  
80
# --------------------------------------
81
# Implementation for NT
82
if os.name == 'nt':
83
    @contextmanager
84
    def lock(filename, flags):
85
        file = open(filename, "w+")
86
        hfile = win32file._get_osfhandle(file.fileno())
87

  
88
        try:
89
            win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped)
90
            try:
91
                yield
92
            finally:
93
                file.close()
94
        except pywintypes.error, exc_value:
95
            # error: (33, 'LockFileEx',
96
            #         'The process cannot access the file because another
97
            #          process has locked a portion of the file.')
98
            file.close()
99
            if exc_value[0] == 33:
100
                raise LockException(LockException.LOCK_FAILED, exc_value[2])
101
            else:
102
                # Q:  Are there exceptions/codes we should be dealing with?
103
                raise
104

  
105

  
106
# --------------------------------------
107
# Implementation for Posix
108
elif os.name == 'posix':
109
    @contextmanager
110
    def lock(filename, flags):
111
        file = open(filename, "w+")
112

  
113
        try:
114
            fcntl.flock(file.fileno(), flags)
115
            try:
116
                yield
117
            finally:
118
                file.close()
119
        except IOError, exc_value:
120
            #  IOError: [Errno 11] Resource temporarily unavailable
121
            file.close()
122
            if exc_value[0] == 11:
123
                raise LockException(LockException.LOCK_FAILED, exc_value[1])
124
            else:
125
                raise
b/ci/utils.py
19 19
from kamaki.clients.cyclades import CycladesClient
20 20
from kamaki.clients.image import ImageClient
21 21
from kamaki.clients.compute import ComputeClient
22
import filelocker
22 23

  
23 24
DEFAULT_CONFIG_FILE = "new_config"
24 25
# UUID of owner of system images
......
147 148
        self.config.read(config_file)
148 149

  
149 150
        # Read temporary_config file
150
        temp_config = self.config.get('Global', 'temporary_config')
151
        self.temp_config_file = \
152
            os.path.expanduser(self.config.get('Global', 'temporary_config'))
151 153
        self.temp_config = ConfigParser()
152 154
        self.temp_config.optionxform = str
153
        self.temp_config.read(os.path.expanduser(temp_config))
155
        self.temp_config.read(self.temp_config_file)
154 156
        self.build_id = build_id
155 157
        self.logger.info("Will use \"%s\" as build id" % _green(self.build_id))
156 158

  
......
453 455

  
454 456
    def write_temp_config(self, option, value):
455 457
        """Write changes back to config file"""
456
        # If build_id section doesn't exist create a new one
457
        try:
458
            self.temp_config.add_section(str(self.build_id))
459
            creation_time = time.strftime("%a, %d %b %Y %X", time.localtime())
460
            self.write_temp_config("created", creation_time)
461
        except DuplicateSectionError:
462
            pass
463
        self.temp_config.set(str(self.build_id), option, str(value))
464
        curr_time = time.strftime("%a, %d %b %Y %X", time.localtime())
465
        self.temp_config.set(str(self.build_id), "modified", curr_time)
466
        temp_conf_file = self.config.get('Global', 'temporary_config')
467
        with open(temp_conf_file, 'wb') as tcf:
468
            self.temp_config.write(tcf)
458
        # Acquire the lock to write to temp_config_file
459
        with filelocker.lock("%s.lock" % self.temp_config_file,
460
                             filelocker.LOCK_EX):
461

  
462
            # Read temp_config again to get any new entries
463
            self.temp_config.read(self.temp_config_file)
464

  
465
            # If build_id section doesn't exist create a new one
466
            try:
467
                self.temp_config.add_section(str(self.build_id))
468
                creation_time = \
469
                    time.strftime("%a, %d %b %Y %X", time.localtime())
470
                self.temp_config.set(str(self.build_id),
471
                                     "created", str(creation_time))
472
            except DuplicateSectionError:
473
                pass
474
            self.temp_config.set(str(self.build_id), option, str(value))
475
            curr_time = time.strftime("%a, %d %b %Y %X", time.localtime())
476
            self.temp_config.set(str(self.build_id), "modified", curr_time)
477
            with open(self.temp_config_file, 'wb') as tcf:
478
                self.temp_config.write(tcf)
469 479

  
470 480
    def read_temp_config(self, option):
471 481
        """Read from temporary_config file"""
......
545 555
            # namely to disable host checking.
546 556
            (temp_ssh_file_handle, temp_ssh_file) = tempfile.mkstemp()
547 557
            os.close(temp_ssh_file_handle)
558
            # XXX: git push doesn't read the password
548 559
            cmd = """
549 560
            echo 'exec ssh -o "StrictHostKeyChecking no" \
550 561
                           -o "UserKnownHostsFile /dev/null" \

Also available in: Unified diff