File: manifest.py

package info (click to toggle)
python-jenkinsapi 0.3.15-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 408 kB
  • sloc: python: 4,275; makefile: 3
file content (105 lines) | stat: -rw-r--r-- 3,340 bytes parent folder | download
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
"""
This module enables Manifest file parsing.
Copied from
https://chromium.googlesource.com/external/googleappengine/python/+/master
/google/appengine/tools/jarfile.py
"""

import zipfile

_MANIFEST_NAME = "META-INF/MANIFEST.MF"


class InvalidJarError(Exception):
    """
    InvalidJar exception class
    """

    pass


class Manifest(object):
    """
    The parsed manifest from a jar file.
    Attributes:
      main_section: a dict representing the main (first)
        section of the manifest.
        Each key is a string that is an attribute, such as
        'Manifest-Version', and the corresponding value is a string that
        is the value of the attribute, such as '1.0'.
      sections: a dict representing the other sections of the manifest.
        Each key is a string that is the value of the 'Name' attribute for
        the section, and the corresponding value is a dict like the
        main_section one, for the other attributes.
    """

    def __init__(self, main_section, sections):
        self.main_section = main_section
        self.sections = sections


def read_manifest(jar_file_name):
    """
    Read and parse the manifest out of the given jar.
    Args:
        jar_file_name: the name of the jar from which the manifest is to be read.

    Returns:
        A parsed Manifest object, or None if the jar has no manifest.

    Raises:
        IOError: if the jar does not exist or cannot be read.
    """
    with zipfile.ZipFile(jar_file_name) as jar:
        try:
            manifest_string = jar.read(_MANIFEST_NAME).decode("UTF-8")
        except KeyError:
            return None
        return _parse_manifest(manifest_string)


def _parse_manifest(manifest_string):
    """
    Parse a Manifest object out of the given string.
    Args:
      manifest_string: a str or unicode that is the manifest contents.
    Returns:
      A Manifest object parsed out of the string.
    Raises:
      InvalidJarError: if the manifest is not well-formed.
    """
    manifest_string = "\n".join(manifest_string.splitlines()).rstrip("\n")
    section_strings = manifest_string.split("\n\n")
    parsed_sections = [_parse_manifest_section(s) for s in section_strings]
    main_section = parsed_sections[0]
    sections = dict()
    try:
        for entry in parsed_sections[1:]:
            sections[entry["Name"]] = entry
    except KeyError:
        raise InvalidJarError(
            "Manifest entry has no Name attribute: %s" % entry
        )
    return Manifest(main_section, sections)


def _parse_manifest_section(section):
    """Parse a dict out of the given manifest section string.
    Args:
      section: a str or unicode that is the manifest section.
        It looks something like this (without the >):
        > Name: section-name
        > Some-Attribute: some value
        > Another-Attribute: another value
    Returns:
      A dict where the keys are the attributes (here, 'Name', 'Some-Attribute',
      'Another-Attribute'), and the values are the corresponding
      attribute values.
    Raises:
      InvalidJarError: if the manifest section is not well-formed.
    """
    section = section.replace("\n ", "")
    try:
        return dict(line.split(": ", 1) for line in section.split("\n"))
    except ValueError:
        raise InvalidJarError("Invalid manifest %r" % section)