5
from juju.charm.base import CharmBase, get_revision
6
from juju.charm.base import CharmBase, get_revision, ZIP_SYMLINK_ATTR
6
7
from juju.charm.bundle import CharmBundle
7
8
from juju.charm.config import ConfigOptions
9
from juju.charm.errors import InvalidCharmFile
8
10
from juju.charm.metadata import MetaData
62
64
zf = zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED)
64
65
for dirpath, dirnames, filenames in os.walk(self.path):
65
66
relative_path = dirpath[len(self.path) + 1:]
66
67
if relative_path and not self._ignore(relative_path):
69
70
archive_name = os.path.join(relative_path, name)
70
71
if not self._ignore(archive_name):
71
72
real_path = os.path.join(dirpath, name)
72
zf.write(real_path, archive_name)
73
self._check_type(real_path)
74
if os.path.islink(real_path):
75
self._check_link(real_path)
77
zf, os.readlink(real_path), archive_name)
79
zf.write(real_path, archive_name)
82
def _check_type(self, path):
86
if stat.S_ISDIR(s.st_mode) or stat.S_ISREG(s.st_mode):
88
raise InvalidCharmFile(
89
self.metadata.name, path, "Invalid file type for a charm")
91
def _check_link(self, path):
92
link_path = os.readlink(path)
93
if link_path[0] == "/":
94
raise InvalidCharmFile(
95
self.metadata.name, path, "Absolute links are invalid")
96
path_dir = os.path.dirname(path)
97
link_path = os.path.join(path_dir, link_path)
98
if not link_path.startswith(os.path.abspath(self.path)):
99
raise InvalidCharmFile(
100
self.metadata.name, path, "Only internal symlinks are allowed")
102
def _write_symlink(self, zf, link_target, link_path):
103
"""Package symlinks with appropriate zipfile metadata."""
104
info = zipfile.ZipInfo()
105
info.filename = link_path
106
info.create_system = 3
107
info.external_attr = ZIP_SYMLINK_ATTR
108
zf.writestr(info, link_target)
76
110
def _ignore(self, path):
77
111
if path == "build" or path.startswith("build/"):