summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2016-02-19 22:38:57 +1300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-02-21 09:32:42 +0000
commitb95c72c4dcac97b00ad46cd6b0ff0a854a0e867f (patch)
treedd753c778d8ba4b3764ebd8bb03dd76b199d2e15
parent62989efe6d65d438f578dbeb8a8831d900dac891 (diff)
downloadpoky-b95c72c4dcac97b00ad46cd6b0ff0a854a0e867f.tar.gz
devtool: deploy-target: write deployed files list to target
When running devtool deploy-target, we save a list of deployed files, and this list is used by devtool undeploy-target (or the next time deploy-target is run if the list is present, in case any files have been renamed or deleted since the first time). We were writing this file to the host, but it makes more sense to write the list to the target instead, so that if we for example swap in a different board, or switch hosts, things will work as expected. In order to do this properly we have to construct a shell script and ship it over to the target so we can run it. The manifest is written out to a hidden directory in the root (/.devtool). Fixes [YOCTO #7908]. (From OE-Core rev: a16a0c9334b785e2df896266c8911a2c7a1806b8) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--scripts/lib/devtool/deploy.py144
1 files changed, 103 insertions, 41 deletions
diff --git a/scripts/lib/devtool/deploy.py b/scripts/lib/devtool/deploy.py
index d742ed3f8e..d2a314b236 100644
--- a/scripts/lib/devtool/deploy.py
+++ b/scripts/lib/devtool/deploy.py
@@ -1,6 +1,6 @@
1# Development tool - deploy/undeploy command plugin 1# Development tool - deploy/undeploy command plugin
2# 2#
3# Copyright (C) 2014-2015 Intel Corporation 3# Copyright (C) 2014-2016 Intel Corporation
4# 4#
5# This program is free software; you can redistribute it and/or modify 5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as 6# it under the terms of the GNU General Public License version 2 as
@@ -19,10 +19,57 @@
19import os 19import os
20import subprocess 20import subprocess
21import logging 21import logging
22import tempfile
23import shutil
22from devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError 24from devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError
23 25
24logger = logging.getLogger('devtool') 26logger = logging.getLogger('devtool')
25 27
28deploylist_path = '/.devtool'
29
30def _prepare_remote_script(deploy, verbose=False):
31 """
32 Prepare a shell script for running on the target to
33 deploy/undeploy files. We have to be careful what we put in this
34 script - only commands that are likely to be available on the
35 target are suitable (the target might be constrained, e.g. using
36 busybox rather than bash with coreutils).
37 """
38 lines = []
39 lines.append('#!/bin/sh')
40 lines.append('set -e')
41 lines.append('manifest="%s/$1.list"' % deploylist_path)
42 lines.append('if [ -f $manifest ] ; then')
43 # Read manifest in reverse and delete files / remove empty dirs
44 lines.append(' sed \'1!G;h;$!d\' $manifest | while read file')
45 lines.append(' do')
46 lines.append(' if [ -d $file ] ; then')
47 lines.append(' rmdir $file > /dev/null 2>&1 || true')
48 lines.append(' else')
49 lines.append(' rm $file')
50 lines.append(' fi')
51 lines.append(' done')
52 lines.append(' rm $manifest')
53 if not deploy:
54 # May as well remove all traces
55 lines.append(' rmdir `dirname $manifest` > /dev/null 2>&1 || true')
56 lines.append('fi')
57
58 if deploy:
59 lines.append('mkdir -p `dirname $manifest`')
60 lines.append('mkdir -p $2')
61 if verbose:
62 lines.append(' tar xv -C $2 -f - | tee $manifest')
63 else:
64 lines.append(' tar xv -C $2 -f - > $manifest')
65 lines.append('sed -i "s!^./!$2!" $manifest')
66 # Delete the script itself
67 lines.append('rm $0')
68 lines.append('')
69
70 return '\n'.join(lines)
71
72
26def deploy(args, config, basepath, workspace): 73def deploy(args, config, basepath, workspace):
27 """Entry point for the devtool 'deploy' subcommand""" 74 """Entry point for the devtool 'deploy' subcommand"""
28 import re 75 import re
@@ -36,9 +83,8 @@ def deploy(args, config, basepath, workspace):
36 destdir = '/' 83 destdir = '/'
37 else: 84 else:
38 args.target = host 85 args.target = host
39 86 if not destdir.endswith('/'):
40 deploy_dir = os.path.join(basepath, 'target_deploy', args.target) 87 destdir += '/'
41 deploy_file = os.path.join(deploy_dir, args.recipename + '.list')
42 88
43 tinfoil = setup_tinfoil(basepath=basepath) 89 tinfoil = setup_tinfoil(basepath=basepath)
44 try: 90 try:
@@ -59,74 +105,90 @@ def deploy(args, config, basepath, workspace):
59 print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)) 105 print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn))
60 return 0 106 return 0
61 107
62 if os.path.exists(deploy_file):
63 if undeploy(args, config, basepath, workspace):
64 # Error already shown
65 return 1
66 108
67 extraoptions = '' 109 extraoptions = ''
68 if args.no_host_check: 110 if args.no_host_check:
69 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' 111 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
70 if args.show_status: 112 if not args.show_status:
71 tarextractopts = 'xv'
72 else:
73 tarextractopts = 'x'
74 extraoptions += ' -q' 113 extraoptions += ' -q'
75 # We cannot use scp here, because it doesn't preserve symlinks 114
76 ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'tar %s -C %s -f -\'' % (extraoptions, args.target, tarextractopts, destdir), cwd=recipe_outdir, shell=True) 115 # In order to delete previously deployed files and have the manifest file on
116 # the target, we write out a shell script and then copy it to the target
117 # so we can then run it (piping tar output to it).
118 # (We cannot use scp here, because it doesn't preserve symlinks.)
119 tmpdir = tempfile.mkdtemp(prefix='devtool')
120 try:
121 tmpscript = '/tmp/devtool_deploy.sh'
122 shellscript = _prepare_remote_script(deploy=True, verbose=args.show_status)
123 # Write out the script to a file
124 with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f:
125 f.write(shellscript)
126 # Copy it to the target
127 ret = subprocess.call("scp %s %s/* %s:%s" % (extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True)
128 if ret != 0:
129 raise DevtoolError('Failed to copy script to %s - rerun with -s to '
130 'get a complete error message' % args.target)
131 finally:
132 shutil.rmtree(tmpdir)
133
134 # Now run the script
135 ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'sh %s %s %s\'' % (extraoptions, args.target, tmpscript, args.recipename, destdir), cwd=recipe_outdir, shell=True)
77 if ret != 0: 136 if ret != 0:
78 raise DevtoolError('Deploy failed - rerun with -s to get a complete ' 137 raise DevtoolError('Deploy failed - rerun with -s to get a complete '
79 'error message') 138 'error message')
80 139
81 logger.info('Successfully deployed %s' % recipe_outdir) 140 logger.info('Successfully deployed %s' % recipe_outdir)
82 141
83 if not os.path.exists(deploy_dir):
84 os.makedirs(deploy_dir)
85
86 files_list = [] 142 files_list = []
87 for root, _, files in os.walk(recipe_outdir): 143 for root, _, files in os.walk(recipe_outdir):
88 for filename in files: 144 for filename in files:
89 filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) 145 filename = os.path.relpath(os.path.join(root, filename), recipe_outdir)
90 files_list.append(os.path.join(destdir, filename)) 146 files_list.append(os.path.join(destdir, filename))
91 147
92 with open(deploy_file, 'w') as fobj:
93 fobj.write('\n'.join(files_list))
94
95 return 0 148 return 0
96 149
97def undeploy(args, config, basepath, workspace): 150def undeploy(args, config, basepath, workspace):
98 """Entry point for the devtool 'undeploy' subcommand""" 151 """Entry point for the devtool 'undeploy' subcommand"""
99 deploy_file = os.path.join(basepath, 'target_deploy', args.target, args.recipename + '.list')
100 if not os.path.exists(deploy_file):
101 raise DevtoolError('%s has not been deployed' % args.recipename)
102
103 if args.dry_run:
104 print('Previously deployed files to be un-deployed for %s on target %s:' % (args.recipename, args.target))
105 with open(deploy_file, 'r') as f:
106 for line in f:
107 print(' %s' % line.rstrip())
108 return 0
109
110 extraoptions = '' 152 extraoptions = ''
111 if args.no_host_check: 153 if args.no_host_check:
112 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' 154 extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
113 if not args.show_status: 155 if not args.show_status:
114 extraoptions += ' -q' 156 extraoptions += ' -q'
115 157
116 ret = subprocess.call("scp %s %s %s:/tmp" % (extraoptions, deploy_file, args.target), shell=True) 158 args.target = args.target.split(':')[0]
117 if ret != 0:
118 raise DevtoolError('Failed to copy file list to %s - rerun with -s to '
119 'get a complete error message' % args.target)
120 159
121 ret = subprocess.call("ssh %s %s 'xargs -n1 rm -f </tmp/%s'" % (extraoptions, args.target, os.path.basename(deploy_file)), shell=True) 160 if args.dry_run:
122 if ret == 0: 161 listfile = os.path.join(deploylist_path, '%s.list' % args.recipename)
123 logger.info('Successfully undeployed %s' % args.recipename) 162 print('Previously deployed files to be un-deployed for %s on target %s:' % (args.recipename, args.target))
124 os.remove(deploy_file) 163 ret = subprocess.call('ssh %s %s \'[ -f %s ] && cat %s || true\'' % (extraoptions, args.target, listfile, listfile), shell=True)
125 else: 164 if ret != 0:
165 raise DevtoolError('Undeploy failed - rerun with -s to get a complete '
166 'error message')
167 return 0
168
169 tmpdir = tempfile.mkdtemp(prefix='devtool')
170 try:
171 tmpscript = '/tmp/devtool_undeploy.sh'
172 shellscript = _prepare_remote_script(deploy=False)
173 # Write out the script to a file
174 with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f:
175 f.write(shellscript)
176 # Copy it to the target
177 ret = subprocess.call("scp %s %s/* %s:%s" % (extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True)
178 if ret != 0:
179 raise DevtoolError('Failed to copy script to %s - rerun with -s to '
180 'get a complete error message' % args.target)
181 finally:
182 shutil.rmtree(tmpdir)
183
184 # Now run the script
185 ret = subprocess.call('ssh %s %s \'sh %s %s\'' % (extraoptions, args.target, tmpscript, args.recipename), shell=True)
186 if ret != 0:
126 raise DevtoolError('Undeploy failed - rerun with -s to get a complete ' 187 raise DevtoolError('Undeploy failed - rerun with -s to get a complete '
127 'error message') 188 'error message')
128 189
129 return ret 190 logger.info('Successfully undeployed %s' % args.recipename)
191 return 0
130 192
131 193
132def register_commands(subparsers, context): 194def register_commands(subparsers, context):