1 from xml
.dom
import minidom
2 from zeroinstall
.zerostore
import Store
, manifest
4 from zeroinstall
.zerostore
import unpack
6 # Older versions don't have it
8 from zeroinstall
.injector
import namespaces
9 import os
, time
, re
, shutil
, tempfile
11 def manifest_for_dir(dir, alg
):
13 # (for older versions of the injector)
16 def new_digest(self
): return sha
.new()
17 def generate_manifest(self
, dir): return manifest
.generate_manifest(dir)
18 def getID(self
, digest
): return 'sha1=' + digest
.hexdigest()
21 algorithm
= manifest
.get_algorithm(alg
)
23 digest
= algorithm
.new_digest()
24 for line
in algorithm
.generate_manifest(dir):
25 digest
.update(line
+ '\n')
26 return algorithm
.getID(digest
)
28 def autopackage_get_start_offset(package
):
29 for line
in file(package
):
30 if line
.startswith('export dataSize='):
31 return os
.path
.getsize(package
) - int(line
.split('"', 2)[1])
32 raise Exception("Can't find payload in autopackage (missing 'dataSize')")
34 def add_archive(data
, url
, local_file
, extract
, alg
):
35 if local_file
is None:
36 local_file
= os
.path
.abspath(os
.path
.basename(url
))
37 if not os
.path
.exists(local_file
):
38 raise Exception("Use --archive-file option to specify a local copy of the archive "
39 "(default file '%s' does not exist)" % local_file
)
41 doc
= minidom
.parseString(data
)
44 if local_file
.endswith('.deb') or local_file
.endswith('.zip') or \
45 local_file
.endswith('.package'):
46 # These require 0launch >= 0.20 anyway, so use the new hash to avoid
47 # problems with directory mtimes
52 if local_file
.endswith('.package'):
53 start_offset
= autopackage_get_start_offset(local_file
)
54 type = 'application/x-bzip-compressed-tar'
59 all_impls
= doc
.documentElement
.getElementsByTagNameNS(namespaces
.XMLNS_IFACE
, 'implementation')
60 tmpdir
= tempfile
.mkdtemp('-0publish')
62 if start_offset
or type:
63 unpack
.unpack_archive(url
, file(local_file
), tmpdir
, extract
, start_offset
= start_offset
, type = type)
65 unpack
.unpack_archive(url
, file(local_file
), tmpdir
, extract
)
67 extracted
= os
.path
.join(tmpdir
, extract
)
71 archive_id
= manifest_for_dir(extracted
, alg
)
76 for impl
in all_impls
:
77 this_id
= impl
.getAttribute('id')
78 if this_id
== archive_id
:
80 if this_id
.startswith('/') or this_id
.startswith('.'):
81 local_ifaces
.append(impl
)
83 if len(local_ifaces
) == 0:
84 raise Exception('Nothing with id "%s", and no local implementations' % archive_id
)
85 if len(local_ifaces
) > 1:
86 raise Exception('Nothing with id "%s", and multiple local implementations!' % archive_id
)
87 impl
= local_ifaces
[0]
88 impl
.setAttribute('id', archive_id
)
90 assert impl
.getAttribute('id') == archive_id
92 nl
= doc
.createTextNode('\n ')
95 archive
= doc
.createElementNS(namespaces
.XMLNS_IFACE
, 'archive')
96 impl
.appendChild(archive
)
97 archive
.setAttribute('href', url
)
98 archive
.setAttribute('size', str(os
.stat(local_file
).st_size
- start_offset
))
99 if extract
is not None:
100 archive
.setAttribute('extract', extract
)
102 archive
.setAttribute('start-offset', str(start_offset
))
104 archive
.setAttribute('type', type)
106 nl
= doc
.createTextNode('\n ')