~ggouzi/obinstall/obinstall

« back to all changes in this revision

Viewing changes to demos/app-bundles/reddit/reddit_store/precise/reddit/scripts/charm_helpers_sync.py

  • Committer: MMorana
  • Date: 2016-03-24 01:18:40 UTC
  • Revision ID: mass@ubuntu.com-20160324011840-blxydmf7ca4ggle0
Splitting out demos from install

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
# Copyright 2013 Canonical Ltd.
3
 
 
4
 
# Authors:
5
 
#   Adam Gandelman <adamg@ubuntu.com>
6
 
 
7
 
import logging
8
 
import optparse
9
 
import os
10
 
import subprocess
11
 
import shutil
12
 
import sys
13
 
import tempfile
14
 
import yaml
15
 
 
16
 
from fnmatch import fnmatch
17
 
 
18
 
CHARM_HELPERS_BRANCH = 'lp:charm-helpers'
19
 
 
20
 
 
21
 
def parse_config(conf_file):
22
 
    if not os.path.isfile(conf_file):
23
 
        logging.error('Invalid config file: %s.' % conf_file)
24
 
        return False
25
 
    return yaml.load(open(conf_file).read())
26
 
 
27
 
 
28
 
def clone_helpers(work_dir, branch):
29
 
    dest = os.path.join(work_dir, 'charm-helpers')
30
 
    logging.info('Checking out %s to %s.' % (branch, dest))
31
 
    cmd = ['bzr', 'branch', branch, dest]
32
 
    subprocess.check_call(cmd)
33
 
    return dest
34
 
 
35
 
 
36
 
def _module_path(module):
37
 
    return os.path.join(*module.split('.'))
38
 
 
39
 
 
40
 
def _src_path(src, module):
41
 
    return os.path.join(src, 'charmhelpers', _module_path(module))
42
 
 
43
 
 
44
 
def _dest_path(dest, module):
45
 
    return os.path.join(dest, _module_path(module))
46
 
 
47
 
 
48
 
def _is_pyfile(path):
49
 
    return os.path.isfile(path + '.py')
50
 
 
51
 
 
52
 
def ensure_init(path):
53
 
    '''
54
 
    ensure directories leading up to path are importable, omitting
55
 
    parent directory, eg path='/hooks/helpers/foo'/:
56
 
        hooks/
57
 
        hooks/helpers/__init__.py
58
 
        hooks/helpers/foo/__init__.py
59
 
    '''
60
 
    for d, dirs, files in os.walk(os.path.join(*path.split('/')[:2])):
61
 
        _i = os.path.join(d, '__init__.py')
62
 
        if not os.path.exists(_i):
63
 
            logging.info('Adding missing __init__.py: %s' % _i)
64
 
            open(_i, 'wb').close()
65
 
 
66
 
 
67
 
def sync_pyfile(src, dest):
68
 
    src = src + '.py'
69
 
    src_dir = os.path.dirname(src)
70
 
    logging.info('Syncing pyfile: %s -> %s.' % (src, dest))
71
 
    if not os.path.exists(dest):
72
 
        os.makedirs(dest)
73
 
    shutil.copy(src, dest)
74
 
    if os.path.isfile(os.path.join(src_dir, '__init__.py')):
75
 
        shutil.copy(os.path.join(src_dir, '__init__.py'),
76
 
                    dest)
77
 
    ensure_init(dest)
78
 
 
79
 
 
80
 
def get_filter(opts=None):
81
 
    opts = opts or []
82
 
    if 'inc=*' in opts:
83
 
        # do not filter any files, include everything
84
 
        return None
85
 
 
86
 
    def _filter(dir, ls):
87
 
        incs = [opt.split('=').pop() for opt in opts if 'inc=' in opt]
88
 
        _filter = []
89
 
        for f in ls:
90
 
            _f = os.path.join(dir, f)
91
 
 
92
 
            if not os.path.isdir(_f) and not _f.endswith('.py') and incs:
93
 
                if True not in [fnmatch(_f, inc) for inc in incs]:
94
 
                    logging.debug('Not syncing %s, does not match include '
95
 
                                  'filters (%s)' % (_f, incs))
96
 
                    _filter.append(f)
97
 
                else:
98
 
                    logging.debug('Including file, which matches include '
99
 
                                  'filters (%s): %s' % (incs, _f))
100
 
            elif (os.path.isfile(_f) and not _f.endswith('.py')):
101
 
                logging.debug('Not syncing file: %s' % f)
102
 
                _filter.append(f)
103
 
            elif (os.path.isdir(_f) and not
104
 
                  os.path.isfile(os.path.join(_f, '__init__.py'))):
105
 
                logging.debug('Not syncing directory: %s' % f)
106
 
                _filter.append(f)
107
 
        return _filter
108
 
    return _filter
109
 
 
110
 
 
111
 
def sync_directory(src, dest, opts=None):
112
 
    if os.path.exists(dest):
113
 
        logging.debug('Removing existing directory: %s' % dest)
114
 
        shutil.rmtree(dest)
115
 
    logging.info('Syncing directory: %s -> %s.' % (src, dest))
116
 
 
117
 
    shutil.copytree(src, dest, ignore=get_filter(opts))
118
 
    ensure_init(dest)
119
 
 
120
 
 
121
 
def sync(src, dest, module, opts=None):
122
 
    if os.path.isdir(_src_path(src, module)):
123
 
        sync_directory(_src_path(src, module), _dest_path(dest, module), opts)
124
 
    elif _is_pyfile(_src_path(src, module)):
125
 
        sync_pyfile(_src_path(src, module),
126
 
                    os.path.dirname(_dest_path(dest, module)))
127
 
    else:
128
 
        logging.warn('Could not sync: %s. Neither a pyfile or directory, '
129
 
                     'does it even exist?' % module)
130
 
 
131
 
 
132
 
def parse_sync_options(options):
133
 
    if not options:
134
 
        return []
135
 
    return options.split(',')
136
 
 
137
 
 
138
 
def extract_options(inc, global_options=None):
139
 
    global_options = global_options or []
140
 
    if global_options and isinstance(global_options, basestring):
141
 
        global_options = [global_options]
142
 
    if '|' not in inc:
143
 
        return (inc, global_options)
144
 
    inc, opts = inc.split('|')
145
 
    return (inc, parse_sync_options(opts) + global_options)
146
 
 
147
 
 
148
 
def sync_helpers(include, src, dest, options=None):
149
 
    if not os.path.isdir(dest):
150
 
        os.mkdir(dest)
151
 
 
152
 
    global_options = parse_sync_options(options)
153
 
 
154
 
    for inc in include:
155
 
        if isinstance(inc, str):
156
 
            inc, opts = extract_options(inc, global_options)
157
 
            sync(src, dest, inc, opts)
158
 
        elif isinstance(inc, dict):
159
 
            # could also do nested dicts here.
160
 
            for k, v in inc.iteritems():
161
 
                if isinstance(v, list):
162
 
                    for m in v:
163
 
                        inc, opts = extract_options(m, global_options)
164
 
                        sync(src, dest, '%s.%s' % (k, inc), opts)
165
 
 
166
 
if __name__ == '__main__':
167
 
    parser = optparse.OptionParser()
168
 
    parser.add_option('-c', '--config', action='store', dest='config',
169
 
                      default=None, help='helper config file')
170
 
    parser.add_option('-D', '--debug', action='store_true', dest='debug',
171
 
                      default=False, help='debug')
172
 
    parser.add_option('-b', '--branch', action='store', dest='branch',
173
 
                      help='charm-helpers bzr branch (overrides config)')
174
 
    parser.add_option('-d', '--destination', action='store', dest='dest_dir',
175
 
                      help='sync destination dir (overrides config)')
176
 
    (opts, args) = parser.parse_args()
177
 
 
178
 
    if opts.debug:
179
 
        logging.basicConfig(level=logging.DEBUG)
180
 
    else:
181
 
        logging.basicConfig(level=logging.INFO)
182
 
 
183
 
    if opts.config:
184
 
        logging.info('Loading charm helper config from %s.' % opts.config)
185
 
        config = parse_config(opts.config)
186
 
        if not config:
187
 
            logging.error('Could not parse config from %s.' % opts.config)
188
 
            sys.exit(1)
189
 
    else:
190
 
        config = {}
191
 
 
192
 
    if 'branch' not in config:
193
 
        config['branch'] = CHARM_HELPERS_BRANCH
194
 
    if opts.branch:
195
 
        config['branch'] = opts.branch
196
 
    if opts.dest_dir:
197
 
        config['destination'] = opts.dest_dir
198
 
 
199
 
    if 'destination' not in config:
200
 
        logging.error('No destination dir. specified as option or config.')
201
 
        sys.exit(1)
202
 
 
203
 
    if 'include' not in config:
204
 
        if not args:
205
 
            logging.error('No modules to sync specified as option or config.')
206
 
            sys.exit(1)
207
 
        config['include'] = []
208
 
        [config['include'].append(a) for a in args]
209
 
 
210
 
    sync_options = None
211
 
    if 'options' in config:
212
 
        sync_options = config['options']
213
 
    tmpd = tempfile.mkdtemp()
214
 
    try:
215
 
        checkout = clone_helpers(tmpd, config['branch'])
216
 
        sync_helpers(config['include'], checkout, config['destination'],
217
 
                     options=sync_options)
218
 
    except Exception, e:
219
 
        logging.error("Could not sync: %s" % e)
220
 
        raise e
221
 
    finally:
222
 
        logging.debug('Cleaning up %s' % tmpd)
223
 
        shutil.rmtree(tmpd)