blob: f15a6a9ed7b234789edb4222734dcead1543c979 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Development tool - sdk-update command plugin
2
3import os
4import subprocess
5import logging
6import glob
7import shutil
8import errno
9import sys
10from devtool import exec_build_env_command, setup_tinfoil, DevtoolError
11
12logger = logging.getLogger('devtool')
13
14def plugin_init(pluginlist):
15 """Plugin initialization"""
16 pass
17
18def parse_locked_sigs(sigfile_path):
19 """Return <pn:task>:<hash> dictionary"""
20 sig_dict = {}
21 with open(sigfile_path) as f:
22 lines = f.readlines()
23 for line in lines:
24 if ':' in line:
25 taskkey, _, hashval = line.rpartition(':')
26 sig_dict[taskkey.strip()] = hashval.split()[0]
27 return sig_dict
28
29def generate_update_dict(sigfile_new, sigfile_old):
30 """Return a dict containing <pn:task>:<hash> which indicates what need to be updated"""
31 update_dict = {}
32 sigdict_new = parse_locked_sigs(sigfile_new)
33 sigdict_old = parse_locked_sigs(sigfile_old)
34 for k in sigdict_new:
35 if k not in sigdict_old:
36 update_dict[k] = sigdict_new[k]
37 continue
38 if sigdict_new[k] != sigdict_old[k]:
39 update_dict[k] = sigdict_new[k]
40 continue
41 return update_dict
42
Patrick Williamsf1e5d692016-03-30 15:21:19 -050043def get_sstate_objects(update_dict, sstate_dir):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044 """Return a list containing sstate objects which are to be installed"""
45 sstate_objects = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 for k in update_dict:
47 files = set()
48 hashval = update_dict[k]
49 p = sstate_dir + '/' + hashval[:2] + '/*' + hashval + '*.tgz'
50 files |= set(glob.glob(p))
51 p = sstate_dir + '/*/' + hashval[:2] + '/*' + hashval + '*.tgz'
52 files |= set(glob.glob(p))
53 files = list(files)
54 if len(files) == 1:
55 sstate_objects.extend(files)
56 elif len(files) > 1:
57 logger.error("More than one matching sstate object found for %s" % hashval)
58
59 return sstate_objects
60
61def mkdir(d):
62 try:
63 os.makedirs(d)
64 except OSError as e:
65 if e.errno != errno.EEXIST:
66 raise e
67
68def install_sstate_objects(sstate_objects, src_sdk, dest_sdk):
69 """Install sstate objects into destination SDK"""
70 sstate_dir = os.path.join(dest_sdk, 'sstate-cache')
71 if not os.path.exists(sstate_dir):
72 logger.error("Missing sstate-cache directory in %s, it might not be an extensible SDK." % dest_sdk)
73 raise
74 for sb in sstate_objects:
75 dst = sb.replace(src_sdk, dest_sdk)
76 destdir = os.path.dirname(dst)
77 mkdir(destdir)
78 logger.debug("Copying %s to %s" % (sb, dst))
79 shutil.copy(sb, dst)
80
81def sdk_update(args, config, basepath, workspace):
82 # Fetch locked-sigs.inc file from remote/local destination
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083 updateserver = args.updateserver
84 if not updateserver:
Patrick Williamsf1e5d692016-03-30 15:21:19 -050085 updateserver = config.get('SDK', 'updateserver', '')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086 if not updateserver:
87 raise DevtoolError("Update server not specified in config file, you must specify it on the command line")
Patrick Williamsf1e5d692016-03-30 15:21:19 -050088 logger.debug("updateserver: %s" % updateserver)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
90 # Make sure we are using sdk-update from within SDK
91 logger.debug("basepath = %s" % basepath)
92 old_locked_sig_file_path = os.path.join(basepath, 'conf/locked-sigs.inc')
93 if not os.path.exists(old_locked_sig_file_path):
94 logger.error("Not using devtool's sdk-update command from within an extensible SDK. Please specify correct basepath via --basepath option")
95 return -1
96 else:
97 logger.debug("Found conf/locked-sigs.inc in %s" % basepath)
98
Patrick Williamsf1e5d692016-03-30 15:21:19 -050099 if ':' in updateserver:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100 is_remote = True
101 else:
102 is_remote = False
103
104 if not is_remote:
105 # devtool sdk-update /local/path/to/latest/sdk
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500106 new_locked_sig_file_path = os.path.join(updateserver, 'conf/locked-sigs.inc')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107 if not os.path.exists(new_locked_sig_file_path):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500108 logger.error("%s doesn't exist or is not an extensible SDK" % updateserver)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109 return -1
110 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500111 logger.debug("Found conf/locked-sigs.inc in %s" % updateserver)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112 update_dict = generate_update_dict(new_locked_sig_file_path, old_locked_sig_file_path)
113 logger.debug("update_dict = %s" % update_dict)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500114 sstate_dir = os.path.join(newsdk_path, 'sstate-cache')
115 if not os.path.exists(sstate_dir):
116 logger.error("sstate-cache directory not found under %s" % newsdk_path)
117 return 1
118 sstate_objects = get_sstate_objects(update_dict, sstate_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 logger.debug("sstate_objects = %s" % sstate_objects)
120 if len(sstate_objects) == 0:
121 logger.info("No need to update.")
122 return 0
123 logger.info("Installing sstate objects into %s", basepath)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500124 install_sstate_objects(sstate_objects, updateserver.rstrip('/'), basepath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 logger.info("Updating configuration files")
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500126 new_conf_dir = os.path.join(updateserver, 'conf')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127 old_conf_dir = os.path.join(basepath, 'conf')
128 shutil.rmtree(old_conf_dir)
129 shutil.copytree(new_conf_dir, old_conf_dir)
130 logger.info("Updating layers")
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500131 new_layers_dir = os.path.join(updateserver, 'layers')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 old_layers_dir = os.path.join(basepath, 'layers')
133 shutil.rmtree(old_layers_dir)
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500134 ret = subprocess.call("cp -a %s %s" % (new_layers_dir, old_layers_dir), shell=True)
135 if ret != 0:
136 logger.error("Copying %s to %s failed" % (new_layers_dir, old_layers_dir))
137 return ret
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 else:
139 # devtool sdk-update http://myhost/sdk
140 tmpsdk_dir = '/tmp/sdk-ext'
141 if os.path.exists(tmpsdk_dir):
142 shutil.rmtree(tmpsdk_dir)
143 os.makedirs(tmpsdk_dir)
144 os.makedirs(os.path.join(tmpsdk_dir, 'conf'))
145 # Fetch locked-sigs.inc from update server
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500146 ret = subprocess.call("wget -q -O - %s/conf/locked-sigs.inc > %s/locked-sigs.inc" % (updateserver, os.path.join(tmpsdk_dir, 'conf')), shell=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147 if ret != 0:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500148 logger.error("Fetching conf/locked-sigs.inc from %s to %s/locked-sigs.inc failed" % (updateserver, os.path.join(tmpsdk_dir, 'conf')))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149 return ret
150 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500151 logger.info("Fetching conf/locked-sigs.inc from %s to %s/locked-sigs.inc succeeded" % (updateserver, os.path.join(tmpsdk_dir, 'conf')))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152 new_locked_sig_file_path = os.path.join(tmpsdk_dir, 'conf/locked-sigs.inc')
153 update_dict = generate_update_dict(new_locked_sig_file_path, old_locked_sig_file_path)
154 logger.debug("update_dict = %s" % update_dict)
155 if len(update_dict) == 0:
156 logger.info("No need to update.")
157 return 0
158 # Update metadata
159 logger.debug("Updating meta data via git ...")
160 # Try using 'git pull', if failed, use 'git clone'
161 if os.path.exists(os.path.join(basepath, 'layers/.git')):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500162 ret = subprocess.call("cd layers && git pull %s/layers/.git" % updateserver, shell=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 else:
164 ret = -1
165 if ret != 0:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500166 ret = subprocess.call("rm -rf layers && git clone %s/layers/.git" % updateserver, shell=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167 if ret != 0:
168 logger.error("Updating meta data via git failed")
169 return ret
170 logger.debug("Updating conf files ...")
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500171 conf_files = ['local.conf', 'bblayers.conf', 'devtool.conf', 'locked-sigs.inc']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172 for conf in conf_files:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500173 ret = subprocess.call("wget -q -O - %s/conf/%s > conf/%s" % (updateserver, conf, conf), shell=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174 if ret != 0:
175 logger.error("Update %s failed" % conf)
176 return ret
177 with open(os.path.join(basepath, 'conf/local.conf'), 'a') as f:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500178 f.write('SSTATE_MIRRORS_append = " file://.* %s/sstate-cache/PATH \\n "\n' % updateserver)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179
180 # Run bitbake command for the whole SDK
181 sdk_targets = config.get('SDK', 'sdk_targets')
182 logger.info("Executing 'bitbake %s' ... (This may take some time.)" % sdk_targets)
183 try:
184 exec_build_env_command(config.init_path, basepath, 'bitbake %s' % sdk_targets)
185 except:
186 logger.error('bitbake %s failed' % sdk_targets)
187 return -1
188 return 0
189
190def register_commands(subparsers, context):
191 """Register devtool subcommands from the sdk plugin"""
192 if context.fixed_setup:
193 parser_sdk = subparsers.add_parser('sdk-update', help='Update SDK components from a nominated location')
194 parser_sdk.add_argument('updateserver', help='The update server to fetch latest SDK components from', nargs='?')
195 parser_sdk.set_defaults(func=sdk_update)