~landscape/landscape-bundles/trunk

14.1.1 by David Britton
add update-charm-revision-numbers here.
1
#!/usr/bin/python3
2
3
import argparse
4
import fileinput
47.1.1 by Adam Collard
Port update-charm-revisions script to (snap'd) charm CLI
5
from glob import glob
6
import json
14.1.1 by David Britton
add update-charm-revision-numbers here.
7
import re
47.1.1 by Adam Collard
Port update-charm-revisions script to (snap'd) charm CLI
8
import subprocess
14.1.1 by David Britton
add update-charm-revision-numbers here.
9
import sys
10
11
12
class Charm(object):
13
14
    def __init__(self, charm_name, series):
15
        """Create a charm object.
16
        @param charm_name: name of charm
17
        """
18
        reference = "cs:{}/{}".format(series, charm_name)
47.1.1 by Adam Collard
Port update-charm-revisions script to (snap'd) charm CLI
19
        json_info = subprocess.check_output(
20
            ["charm", "show", "--format=json", reference, "id"])
21
        charm_data = json.loads(json_info)
22
        self.revision = charm_data.get("id", {}).get("Revision")
23
        if self.revision is None:
24
            raise IOError("{}: {}".format(charm_name, charm_data))
14.1.1 by David Britton
add update-charm-revision-numbers here.
25
        self.name = charm_name
47.1.1 by Adam Collard
Port update-charm-revisions script to (snap'd) charm CLI
26
        self.store_url = charm_data.get("id", {}).get("Id")
14.1.1 by David Britton
add update-charm-revision-numbers here.
27
28
29
def _get_charm(charm_name, series):
30
    """
31
    Small wrapper to try to get the series charm you specify.  Falls back
32
    to precise if you specified something else
33
    """
34
    try:
35
        return Charm(charm_name, series)
36
    except IOError as e:
2.2.9 by Andreas Hasenack
Fallback to trusty charms, not precise.
37
        if series != "trusty":
14.1.1 by David Britton
add update-charm-revision-numbers here.
38
            try:
2.2.9 by Andreas Hasenack
Fallback to trusty charms, not precise.
39
                return Charm(charm_name, series="trusty")
40
            except IOError as trusty_e:
14.1.3 by David Britton
ack[diff]: mostly nits
41
                raise IOError(
2.2.9 by Andreas Hasenack
Fallback to trusty charms, not precise.
42
                    "%s: not found? (even tried trusty): {}, {}".format(
43
                        charm_name, e, trusty_e))
14.1.1 by David Britton
add update-charm-revision-numbers here.
44
        raise
45
46
47
def replace_in_config(filename, charms, series):
48
    """
49
    Iterate over each charm, replacing all occurences of old charm store
50
    urls with new versions.  Intent is to leave file in a state that can
51
    be tested and checked in if successful.
52
53
    Look for lines like:
54.1.1 by Simon Poirier
update-charm-revisions regexp to match current charm Id scheme.
54
      charm: cs:juju-gui-83
14.1.1 by David Britton
add update-charm-revision-numbers here.
55
56
    Or:
57
      series: trusty
58
    """
59
    for line in fileinput.input(filename, inplace=1):
60
        pattern = "^(\s*)series:\s.*$"
61
        line = re.sub(pattern, r"\1series: %s" % series, line)
62
        for charm in charms:
54.1.1 by Simon Poirier
update-charm-revisions regexp to match current charm Id scheme.
63
            pattern = "cs:{}-[0-9]+".format(charm.name)
14.1.1 by David Britton
add update-charm-revision-numbers here.
64
            line = re.sub(pattern, charm.store_url, line)
65
        sys.stdout.write(line)
66
67
    print("# Config written, use `bzr diff %s` to see any changes" % filename)
68
69
70
def get_options():
71
    """Parse and return command line options."""
72
    description = "Put new charmstore descriptors into a deployer file."
73
    parser = argparse.ArgumentParser(description=description)
74
    parser.add_argument("charms", help="List charms to update", nargs='*')
43.1.1 by Simon Poirier
add bionic to series
75
    parser.add_argument("--series", help="Charm series", default="bionic")
14.1.1 by David Britton
add update-charm-revision-numbers here.
76
    return parser.parse_args()
77
78
79
def main():
80
    options = get_options()
81
    charms = []
82
    if len(options.charms):
83
        print("# Latest upstream versions of charms ({}):".format(
84
            options.series))
85
    for charm_name in options.charms:
86
        charm = _get_charm(charm_name, series=options.series)
87
        print("#   {}: {}".format(charm_name, charm.revision))
88
        charms.append(charm)
89
90
    for filename in glob("*.jinja2"):
91
        replace_in_config(filename, charms, series=options.series)
92
93
94
if __name__ == "__main__":
47.1.2 by Adam Collard
Minor cleanup
95
    sys.exit(main())