~jelmer/bzr-builddeb/merge-upstream-svn-branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#    repack_tarball.py -- Repack files/dirs in to tarballs.
#    Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
#
#    This file is part of bzr-builddeb.
#
#    bzr-builddeb is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    bzr-builddeb is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with bzr-builddeb; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#

import gzip
import os
import tarfile
import bz2
import sha

from bzrlib.errors import (
                           FileExists,
                           BzrCommandError,
                           NotADirectory,
                           )
from bzrlib.transport import get_transport
from bzrlib import urlutils


def repack_tarball(orig_name, new_name, target_dir=None):
  """Repack the file/dir named to a .tar.gz with the chosen name.

  This function takes a named file of either .tar.gz, .tar .tgz .tar.bz2 
  or .zip type, or a directory, and creates the file named in the second
  argument in .tar.gz format.

  If target_dir is specified then that directory will be created if it
  doesn't exist, and the new_name will be interpreted relative to that
  directory.
  
  The source must exist, and the target cannot exist.

  :param orig_name: the curent name of the file/dir
  :type orig_name: string
  :param new_name: the desired name of the tarball
  :type new_name: string
  :keyword target_dir: the directory to consider new_name relative to, and
                       will be created if non-existant.
  :type target_dir: string
  :return: None
  :warning: .zip files are currently unsupported.
  :throws NoSuchFile: if orig_name doesn't exist.
  :throws NotADirectory: if target_dir exists and is not a directory.
  :throws FileExists: if the target filename (after considering target_dir)
                      exists, and is not identical to the source.
  :throes BzrCommandError: if the source isn't supported for repacking.
  """
  if target_dir is not None:
    if not os.path.exists(target_dir):
      os.mkdir(target_dir)
    else:
      if not os.path.isdir(target_dir):
        raise NotADirectory(target_dir)
    new_name = os.path.join(target_dir, new_name)
  if os.path.exists(new_name):
    if not orig_name.endswith('.tar.gz'):
      raise FileExists(new_name)
    f = open(orig_name)
    try:
      orig_sha = sha.sha(f.read()).hexdigest()
    finally:
      f.close()
    f = open(new_name)
    try:
      new_sha = sha.sha(f.read()).hexdigest()
    finally:
      f.close()
    if orig_sha != new_sha:
      raise FileExists(new_name)
    return
  if os.path.isdir(orig_name):
    tar = tarfile.open(new_name, 'w:gz')
    try:
      tar.add(orig_name, os.path.basename(orig_name))
    finally:
      tar.close()
  else:
    if isinstance(orig_name, unicode):
      orig_name = orig_name.encode('utf-8')
    if isinstance(new_name, unicode):
      new_name = new_name.encode('utf-8')
    base_dir, path = urlutils.split(orig_name)
    transport = get_transport(base_dir)
    trans_file = transport.get(path)
    try:
      if orig_name.endswith('.tar.gz') or orig_name.endswith('.tgz'):
        dest = open(new_name, 'wb')
        try:
          dest.write(trans_file.read())
        finally:
          dest.close()
      elif orig_name.endswith('.tar'):
        gz = gzip.GzipFile(new_name, 'w')
        try:
          gz.write(trans_file.read())
        finally:
          gz.close()
      elif orig_name.endswith('.tar.bz2'):
        old_tar_content = trans_file.read()
        old_tar_content_decompressed = bz2.decompress(old_tar_content)
        gz = gzip.GzipFile(new_name, 'w')
        try:
          gz.write(old_tar_content_decompressed)
        finally:
          gz.close()
      else:
        raise BzrCommandError('Unsupported format for repack: %s' % orig_name)
      # TODO: handle zip files.
    finally:
      trans_file.close()

# vim: ts=2 sts=2 sw=2