~cjohnston/landscape-bundles/1823279

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
#!/usr/bin/python3

import argparse
import fileinput
import re
import sys
from urllib.request import urlopen
from yaml import load
from glob import glob


class Charm(object):

    def __init__(self, charm_name, series):
        """Create a charm object.
        @param charm_name: name of charm
        """
        reference = "cs:{}/{}".format(series, charm_name)
        base_url = "https://store.juju.ubuntu.com/charm-info?charms="
        url = "{}{}".format(base_url, reference)
        response = urlopen(url)
        self.charm_data = load(response)[reference]
        self.name = charm_name
        if "errors" in self.charm_data:
            raise IOError("{}: {}".format(
                charm_name, self.charm_data["errors"]))
        self.revision = self.charm_data["revision"]
        self.store_url = "cs:{}/{}-{}".format(series, self.name, self.revision)


def _get_charm(charm_name, series):
    """
    Small wrapper to try to get the series charm you specify.  Falls back
    to precise if you specified something else
    """
    try:
        return Charm(charm_name, series)
    except IOError as e:
        if series != "trusty":
            try:
                return Charm(charm_name, series="trusty")
            except IOError as trusty_e:
                raise IOError(
                    "%s: not found? (even tried trusty): {}, {}".format(
                        charm_name, e, trusty_e))
        raise


def replace_in_config(filename, charms, series):
    """
    Iterate over each charm, replacing all occurences of old charm store
    urls with new versions.  Intent is to leave file in a state that can
    be tested and checked in if successful.

    Look for lines like:
      charm: cs:trusty/juju-gui-83

    Or:
      series: trusty
    """
    for line in fileinput.input(filename, inplace=1):
        pattern = "^(\s*)series:\s.*$"
        line = re.sub(pattern, r"\1series: %s" % series, line)
        for charm in charms:
            pattern = "cs:[^/]+/{}-[0-9]+".format(charm.name)
            line = re.sub(pattern, charm.store_url, line)
        sys.stdout.write(line)

    print("# Config written, use `bzr diff %s` to see any changes" % filename)


def get_options():
    """Parse and return command line options."""
    description = "Put new charmstore descriptors into a deployer file."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument("charms", help="List charms to update", nargs='*')
    parser.add_argument("--series", help="Charm series", default="bionic")
    return parser.parse_args()


def main():
    options = get_options()
    charms = []
    if len(options.charms):
        print("# Latest upstream versions of charms ({}):".format(
            options.series))
    for charm_name in options.charms:
        charm = _get_charm(charm_name, series=options.series)
        print("#   {}: {}".format(charm_name, charm.revision))
        charms.append(charm)

    for filename in glob("*.jinja2"):
        replace_in_config(filename, charms, series=options.series)

    sys.exit(0)

if __name__ == "__main__":
    main()