~ubuntu-branches/ubuntu/saucy/click/saucy-proposed

« back to all changes in this revision

Viewing changes to click/arfile.py

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2013-06-27 15:57:25 UTC
  • Revision ID: package-import@ubuntu.com-20130627155725-1kpggp0xots3peir
Tags: 0.1.3
Rename to click, per Mark Shuttleworth.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2013 Canonical Ltd.
 
2
# Author: Colin Watson <cjwatson@ubuntu.com>
 
3
 
 
4
# This program is free software: you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; version 3 of the License.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
"""Basic support for writing ar archive files.
 
17
 
 
18
We do things this way so that Click packages can be created with minimal
 
19
dependencies (e.g. on non-Ubuntu systems).  No read support is needed, since
 
20
Click packages are always installed on systems that have dpkg.
 
21
 
 
22
Some method names and general approach come from the tarfile module in
 
23
Python's standard library; details of the format come from dpkg.
 
24
"""
 
25
 
 
26
from __future__ import print_function
 
27
 
 
28
__metaclass__ = type
 
29
__all__ = [
 
30
    'ArFile',
 
31
    ]
 
32
 
 
33
import os
 
34
import shutil
 
35
import time
 
36
 
 
37
 
 
38
class ArFile:
 
39
    def __init__(self, name=None, mode="w", fileobj=None):
 
40
        if mode != "w":
 
41
            raise ValueError("only mode 'w' is supported")
 
42
        self.mode = mode
 
43
        self.real_mode = "wb"
 
44
 
 
45
        if fileobj:
 
46
            if name is None and hasattr(fileobj, "name"):
 
47
                name = fileobj.name
 
48
            if hasattr(fileobj, "mode"):
 
49
                if fileobj.mode != "wb":
 
50
                    raise ValueError("fileobj must be opened with mode='wb'")
 
51
                self._mode = fileobj.mode
 
52
            self.opened_fileobj = False
 
53
        else:
 
54
            fileobj = open(name, self.real_mode)
 
55
            self.opened_fileobj = True
 
56
        self.name = name
 
57
        self.fileobj = fileobj
 
58
        self.closed = False
 
59
 
 
60
    def close(self):
 
61
        if self.opened_fileobj:
 
62
            self.fileobj.close()
 
63
        self.closed = True
 
64
 
 
65
    def _check(self):
 
66
        if self.closed:
 
67
            raise IOError("ArFile %s is closed" % self.name)
 
68
 
 
69
    def __enter__(self):
 
70
        self._check()
 
71
        return self
 
72
 
 
73
    def __exit__(self, *args):
 
74
        self.close()
 
75
 
 
76
    def add_magic(self):
 
77
        self.fileobj.write(b"!<arch>\n")
 
78
 
 
79
    def add_header(self, name, size):
 
80
        if len(name) > 15:
 
81
            raise ValueError("ar member name '%s' length too long" % name)
 
82
        if size > 9999999999:
 
83
            raise ValueError("ar member size %d too large" % size)
 
84
        header = ("%-16s%-12u0     0     100644  %-10d`\n" % (
 
85
            name, int(time.time()), size)).encode()
 
86
        assert len(header) == 60  # sizeof(struct ar_hdr)
 
87
        self.fileobj.write(header)
 
88
 
 
89
    def add_data(self, name, data):
 
90
        size = len(data)
 
91
        self.add_header(name, size)
 
92
        self.fileobj.write(data)
 
93
        if size & 1:
 
94
            self.fileobj.write(b"\n")  # padding
 
95
 
 
96
    def add_file(self, name, path):
 
97
        with open(path, "rb") as fobj:
 
98
            size = os.fstat(fobj.fileno()).st_size
 
99
            self.add_header(name, size)
 
100
            shutil.copyfileobj(fobj, self.fileobj)
 
101
        if size & 1:
 
102
            self.fileobj.write(b"\n")  # padding