1eb8dc403SDave Cobbley# Development tool - deploy/undeploy command plugin
2eb8dc403SDave Cobbley#
3eb8dc403SDave Cobbley# Copyright (C) 2014-2016 Intel Corporation
4eb8dc403SDave Cobbley#
5c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only
6eb8dc403SDave Cobbley#
7eb8dc403SDave Cobbley"""Devtool plugin containing the deploy subcommands"""
8eb8dc403SDave Cobbley
9eb8dc403SDave Cobbleyimport logging
10eb8dc403SDave Cobbleyimport os
11eb8dc403SDave Cobbleyimport shutil
12eb8dc403SDave Cobbleyimport subprocess
13eb8dc403SDave Cobbleyimport tempfile
14eb8dc403SDave Cobbley
15eb8dc403SDave Cobbleyimport bb.utils
16eb8dc403SDave Cobbleyimport argparse_oe
17eb8dc403SDave Cobbleyimport oe.types
18eb8dc403SDave Cobbley
19eb8dc403SDave Cobbleyfrom devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError
20eb8dc403SDave Cobbley
21eb8dc403SDave Cobbleylogger = logging.getLogger('devtool')
22eb8dc403SDave Cobbley
23eb8dc403SDave Cobbleydeploylist_path = '/.devtool'
24eb8dc403SDave Cobbley
25eb8dc403SDave Cobbleydef _prepare_remote_script(deploy, verbose=False, dryrun=False, undeployall=False, nopreserve=False, nocheckspace=False):
26eb8dc403SDave Cobbley    """
27eb8dc403SDave Cobbley    Prepare a shell script for running on the target to
28eb8dc403SDave Cobbley    deploy/undeploy files. We have to be careful what we put in this
29eb8dc403SDave Cobbley    script - only commands that are likely to be available on the
30eb8dc403SDave Cobbley    target are suitable (the target might be constrained, e.g. using
31eb8dc403SDave Cobbley    busybox rather than bash with coreutils).
32eb8dc403SDave Cobbley    """
33eb8dc403SDave Cobbley    lines = []
34eb8dc403SDave Cobbley    lines.append('#!/bin/sh')
35eb8dc403SDave Cobbley    lines.append('set -e')
36eb8dc403SDave Cobbley    if undeployall:
37eb8dc403SDave Cobbley        # Yes, I know this is crude - but it does work
38eb8dc403SDave Cobbley        lines.append('for entry in %s/*.list; do' % deploylist_path)
39eb8dc403SDave Cobbley        lines.append('[ ! -f $entry ] && exit')
40eb8dc403SDave Cobbley        lines.append('set `basename $entry | sed "s/.list//"`')
41eb8dc403SDave Cobbley    if dryrun:
42eb8dc403SDave Cobbley        if not deploy:
43eb8dc403SDave Cobbley            lines.append('echo "Previously deployed files for $1:"')
44eb8dc403SDave Cobbley    lines.append('manifest="%s/$1.list"' % deploylist_path)
45eb8dc403SDave Cobbley    lines.append('preservedir="%s/$1.preserve"' % deploylist_path)
46eb8dc403SDave Cobbley    lines.append('if [ -f $manifest ] ; then')
47eb8dc403SDave Cobbley    # Read manifest in reverse and delete files / remove empty dirs
48eb8dc403SDave Cobbley    lines.append('    sed \'1!G;h;$!d\' $manifest | while read file')
49eb8dc403SDave Cobbley    lines.append('    do')
50eb8dc403SDave Cobbley    if dryrun:
51eb8dc403SDave Cobbley        lines.append('        if [ ! -d $file ] ; then')
52eb8dc403SDave Cobbley        lines.append('            echo $file')
53eb8dc403SDave Cobbley        lines.append('        fi')
54eb8dc403SDave Cobbley    else:
55eb8dc403SDave Cobbley        lines.append('        if [ -d $file ] ; then')
56eb8dc403SDave Cobbley        # Avoid deleting a preserved directory in case it has special perms
57eb8dc403SDave Cobbley        lines.append('            if [ ! -d $preservedir/$file ] ; then')
58eb8dc403SDave Cobbley        lines.append('                rmdir $file > /dev/null 2>&1 || true')
59eb8dc403SDave Cobbley        lines.append('            fi')
60eb8dc403SDave Cobbley        lines.append('        else')
61eb8dc403SDave Cobbley        lines.append('            rm -f $file')
62eb8dc403SDave Cobbley        lines.append('        fi')
63eb8dc403SDave Cobbley    lines.append('    done')
64eb8dc403SDave Cobbley    if not dryrun:
65eb8dc403SDave Cobbley        lines.append('    rm $manifest')
66eb8dc403SDave Cobbley    if not deploy and not dryrun:
67eb8dc403SDave Cobbley        # May as well remove all traces
68eb8dc403SDave Cobbley        lines.append('    rmdir `dirname $manifest` > /dev/null 2>&1 || true')
69eb8dc403SDave Cobbley    lines.append('fi')
70eb8dc403SDave Cobbley
71eb8dc403SDave Cobbley    if deploy:
72eb8dc403SDave Cobbley        if not nocheckspace:
73eb8dc403SDave Cobbley            # Check for available space
74eb8dc403SDave Cobbley            # FIXME This doesn't take into account files spread across multiple
75eb8dc403SDave Cobbley            # partitions, but doing that is non-trivial
76eb8dc403SDave Cobbley            # Find the part of the destination path that exists
77eb8dc403SDave Cobbley            lines.append('checkpath="$2"')
78eb8dc403SDave Cobbley            lines.append('while [ "$checkpath" != "/" ] && [ ! -e $checkpath ]')
79eb8dc403SDave Cobbley            lines.append('do')
80eb8dc403SDave Cobbley            lines.append('    checkpath=`dirname "$checkpath"`')
81eb8dc403SDave Cobbley            lines.append('done')
82eb8dc403SDave Cobbley            lines.append(r'freespace=$(df -P $checkpath | sed -nre "s/^(\S+\s+){3}([0-9]+).*/\2/p")')
83eb8dc403SDave Cobbley            # First line of the file is the total space
84eb8dc403SDave Cobbley            lines.append('total=`head -n1 $3`')
85eb8dc403SDave Cobbley            lines.append('if [ $total -gt $freespace ] ; then')
86eb8dc403SDave Cobbley            lines.append('    echo "ERROR: insufficient space on target (available ${freespace}, needed ${total})"')
87eb8dc403SDave Cobbley            lines.append('    exit 1')
88eb8dc403SDave Cobbley            lines.append('fi')
89eb8dc403SDave Cobbley        if not nopreserve:
90eb8dc403SDave Cobbley            # Preserve any files that exist. Note that this will add to the
91eb8dc403SDave Cobbley            # preserved list with successive deployments if the list of files
92eb8dc403SDave Cobbley            # deployed changes, but because we've deleted any previously
93eb8dc403SDave Cobbley            # deployed files at this point it will never preserve anything
94eb8dc403SDave Cobbley            # that was deployed, only files that existed prior to any deploying
95eb8dc403SDave Cobbley            # (which makes the most sense)
96eb8dc403SDave Cobbley            lines.append('cat $3 | sed "1d" | while read file fsize')
97eb8dc403SDave Cobbley            lines.append('do')
98eb8dc403SDave Cobbley            lines.append('    if [ -e $file ] ; then')
99eb8dc403SDave Cobbley            lines.append('    dest="$preservedir/$file"')
100eb8dc403SDave Cobbley            lines.append('    mkdir -p `dirname $dest`')
101eb8dc403SDave Cobbley            lines.append('    mv $file $dest')
102eb8dc403SDave Cobbley            lines.append('    fi')
103eb8dc403SDave Cobbley            lines.append('done')
104eb8dc403SDave Cobbley            lines.append('rm $3')
105eb8dc403SDave Cobbley        lines.append('mkdir -p `dirname $manifest`')
106eb8dc403SDave Cobbley        lines.append('mkdir -p $2')
107eb8dc403SDave Cobbley        if verbose:
108eb8dc403SDave Cobbley            lines.append('    tar xv -C $2 -f - | tee $manifest')
109eb8dc403SDave Cobbley        else:
110eb8dc403SDave Cobbley            lines.append('    tar xv -C $2 -f - > $manifest')
111eb8dc403SDave Cobbley        lines.append('sed -i "s!^./!$2!" $manifest')
112eb8dc403SDave Cobbley    elif not dryrun:
113eb8dc403SDave Cobbley        # Put any preserved files back
114eb8dc403SDave Cobbley        lines.append('if [ -d $preservedir ] ; then')
115eb8dc403SDave Cobbley        lines.append('    cd $preservedir')
116eb8dc403SDave Cobbley        # find from busybox might not have -exec, so we don't use that
117eb8dc403SDave Cobbley        lines.append('    find . -type f | while read file')
118eb8dc403SDave Cobbley        lines.append('    do')
119eb8dc403SDave Cobbley        lines.append('        mv $file /$file')
120eb8dc403SDave Cobbley        lines.append('    done')
121eb8dc403SDave Cobbley        lines.append('    cd /')
122eb8dc403SDave Cobbley        lines.append('    rm -rf $preservedir')
123eb8dc403SDave Cobbley        lines.append('fi')
124eb8dc403SDave Cobbley
125eb8dc403SDave Cobbley    if undeployall:
126eb8dc403SDave Cobbley        if not dryrun:
127eb8dc403SDave Cobbley            lines.append('echo "NOTE: Successfully undeployed $1"')
128eb8dc403SDave Cobbley        lines.append('done')
129eb8dc403SDave Cobbley
130eb8dc403SDave Cobbley    # Delete the script itself
131eb8dc403SDave Cobbley    lines.append('rm $0')
132eb8dc403SDave Cobbley    lines.append('')
133eb8dc403SDave Cobbley
134eb8dc403SDave Cobbley    return '\n'.join(lines)
135eb8dc403SDave Cobbley
136eb8dc403SDave Cobbley
137eb8dc403SDave Cobbley
138eb8dc403SDave Cobbleydef deploy(args, config, basepath, workspace):
139eb8dc403SDave Cobbley    """Entry point for the devtool 'deploy' subcommand"""
140eb8dc403SDave Cobbley    import math
141eb8dc403SDave Cobbley    import oe.recipeutils
142eb8dc403SDave Cobbley    import oe.package
143*169d7bccSPatrick Williams    import oe.utils
144eb8dc403SDave Cobbley
145eb8dc403SDave Cobbley    check_workspace_recipe(workspace, args.recipename, checksrc=False)
146eb8dc403SDave Cobbley
147eb8dc403SDave Cobbley    try:
148eb8dc403SDave Cobbley        host, destdir = args.target.split(':')
149eb8dc403SDave Cobbley    except ValueError:
150eb8dc403SDave Cobbley        destdir = '/'
151eb8dc403SDave Cobbley    else:
152eb8dc403SDave Cobbley        args.target = host
153eb8dc403SDave Cobbley    if not destdir.endswith('/'):
154eb8dc403SDave Cobbley        destdir += '/'
155eb8dc403SDave Cobbley
156eb8dc403SDave Cobbley    tinfoil = setup_tinfoil(basepath=basepath)
157eb8dc403SDave Cobbley    try:
158eb8dc403SDave Cobbley        try:
159eb8dc403SDave Cobbley            rd = tinfoil.parse_recipe(args.recipename)
160eb8dc403SDave Cobbley        except Exception as e:
161eb8dc403SDave Cobbley            raise DevtoolError('Exception parsing recipe %s: %s' %
162eb8dc403SDave Cobbley                            (args.recipename, e))
163eb8dc403SDave Cobbley        recipe_outdir = rd.getVar('D')
164eb8dc403SDave Cobbley        if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir):
165eb8dc403SDave Cobbley            raise DevtoolError('No files to deploy - have you built the %s '
166eb8dc403SDave Cobbley                            'recipe? If so, the install step has not installed '
167eb8dc403SDave Cobbley                            'any files.' % args.recipename)
168eb8dc403SDave Cobbley
169eb8dc403SDave Cobbley        if args.strip and not args.dry_run:
170eb8dc403SDave Cobbley            # Fakeroot copy to new destination
171eb8dc403SDave Cobbley            srcdir = recipe_outdir
1725f35090dSAndrew Geissler            recipe_outdir = os.path.join(rd.getVar('WORKDIR'), 'devtool-deploy-target-stripped')
173eb8dc403SDave Cobbley            if os.path.isdir(recipe_outdir):
1747e0e3c0cSAndrew Geissler                exec_fakeroot(rd, "rm -rf %s" % recipe_outdir, shell=True)
175eb8dc403SDave Cobbley            exec_fakeroot(rd, "cp -af %s %s" % (os.path.join(srcdir, '.'), recipe_outdir), shell=True)
176eb8dc403SDave Cobbley            os.environ['PATH'] = ':'.join([os.environ['PATH'], rd.getVar('PATH') or ''])
177eb8dc403SDave Cobbley            oe.package.strip_execs(args.recipename, recipe_outdir, rd.getVar('STRIP'), rd.getVar('libdir'),
178*169d7bccSPatrick Williams                        rd.getVar('base_libdir'), oe.utils.get_bb_number_threads(rd), rd)
179eb8dc403SDave Cobbley
180eb8dc403SDave Cobbley        filelist = []
181c9f7865aSAndrew Geissler        inodes = set({})
182eb8dc403SDave Cobbley        ftotalsize = 0
183eb8dc403SDave Cobbley        for root, _, files in os.walk(recipe_outdir):
184eb8dc403SDave Cobbley            for fn in files:
185c9f7865aSAndrew Geissler                fstat = os.lstat(os.path.join(root, fn))
186eb8dc403SDave Cobbley                # Get the size in kiB (since we'll be comparing it to the output of du -k)
187eb8dc403SDave Cobbley                # MUST use lstat() here not stat() or getfilesize() since we don't want to
188eb8dc403SDave Cobbley                # dereference symlinks
189c9f7865aSAndrew Geissler                if fstat.st_ino in inodes:
190c9f7865aSAndrew Geissler                    fsize = 0
191c9f7865aSAndrew Geissler                else:
192c9f7865aSAndrew Geissler                    fsize = int(math.ceil(float(fstat.st_size)/1024))
193c9f7865aSAndrew Geissler                inodes.add(fstat.st_ino)
194eb8dc403SDave Cobbley                ftotalsize += fsize
195eb8dc403SDave Cobbley                # The path as it would appear on the target
196eb8dc403SDave Cobbley                fpath = os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)
197eb8dc403SDave Cobbley                filelist.append((fpath, fsize))
198eb8dc403SDave Cobbley
199eb8dc403SDave Cobbley        if args.dry_run:
200eb8dc403SDave Cobbley            print('Files to be deployed for %s on target %s:' % (args.recipename, args.target))
201eb8dc403SDave Cobbley            for item, _ in filelist:
202eb8dc403SDave Cobbley                print('  %s' % item)
203eb8dc403SDave Cobbley            return 0
204eb8dc403SDave Cobbley
205eb8dc403SDave Cobbley        extraoptions = ''
206eb8dc403SDave Cobbley        if args.no_host_check:
207eb8dc403SDave Cobbley            extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
208eb8dc403SDave Cobbley        if not args.show_status:
209eb8dc403SDave Cobbley            extraoptions += ' -q'
210eb8dc403SDave Cobbley
21119323693SBrad Bishop        scp_sshexec = ''
21219323693SBrad Bishop        ssh_sshexec = 'ssh'
21319323693SBrad Bishop        if args.ssh_exec:
21419323693SBrad Bishop            scp_sshexec = "-S %s" % args.ssh_exec
21519323693SBrad Bishop            ssh_sshexec = args.ssh_exec
216eb8dc403SDave Cobbley        scp_port = ''
217eb8dc403SDave Cobbley        ssh_port = ''
218eb8dc403SDave Cobbley        if args.port:
219eb8dc403SDave Cobbley            scp_port = "-P %s" % args.port
220eb8dc403SDave Cobbley            ssh_port = "-p %s" % args.port
221eb8dc403SDave Cobbley
22264c979e8SBrad Bishop        if args.key:
22364c979e8SBrad Bishop            extraoptions += ' -i %s' % args.key
22464c979e8SBrad Bishop
225eb8dc403SDave Cobbley        # In order to delete previously deployed files and have the manifest file on
226eb8dc403SDave Cobbley        # the target, we write out a shell script and then copy it to the target
227eb8dc403SDave Cobbley        # so we can then run it (piping tar output to it).
228eb8dc403SDave Cobbley        # (We cannot use scp here, because it doesn't preserve symlinks.)
229eb8dc403SDave Cobbley        tmpdir = tempfile.mkdtemp(prefix='devtool')
230eb8dc403SDave Cobbley        try:
231eb8dc403SDave Cobbley            tmpscript = '/tmp/devtool_deploy.sh'
232eb8dc403SDave Cobbley            tmpfilelist = os.path.join(os.path.dirname(tmpscript), 'devtool_deploy.list')
233eb8dc403SDave Cobbley            shellscript = _prepare_remote_script(deploy=True,
234eb8dc403SDave Cobbley                                                verbose=args.show_status,
235eb8dc403SDave Cobbley                                                nopreserve=args.no_preserve,
236eb8dc403SDave Cobbley                                                nocheckspace=args.no_check_space)
237eb8dc403SDave Cobbley            # Write out the script to a file
238eb8dc403SDave Cobbley            with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f:
239eb8dc403SDave Cobbley                f.write(shellscript)
240eb8dc403SDave Cobbley            # Write out the file list
241eb8dc403SDave Cobbley            with open(os.path.join(tmpdir, os.path.basename(tmpfilelist)), 'w') as f:
242eb8dc403SDave Cobbley                f.write('%d\n' % ftotalsize)
243eb8dc403SDave Cobbley                for fpath, fsize in filelist:
244eb8dc403SDave Cobbley                    f.write('%s %d\n' % (fpath, fsize))
245eb8dc403SDave Cobbley            # Copy them to the target
24619323693SBrad Bishop            ret = subprocess.call("scp %s %s %s %s/* %s:%s" % (scp_sshexec, scp_port, extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True)
247eb8dc403SDave Cobbley            if ret != 0:
248eb8dc403SDave Cobbley                raise DevtoolError('Failed to copy script to %s - rerun with -s to '
249eb8dc403SDave Cobbley                                'get a complete error message' % args.target)
250eb8dc403SDave Cobbley        finally:
251eb8dc403SDave Cobbley            shutil.rmtree(tmpdir)
252eb8dc403SDave Cobbley
253eb8dc403SDave Cobbley        # Now run the script
25419323693SBrad Bishop        ret = exec_fakeroot(rd, 'tar cf - . | %s  %s %s %s \'sh %s %s %s %s\'' % (ssh_sshexec, ssh_port, extraoptions, args.target, tmpscript, args.recipename, destdir, tmpfilelist), cwd=recipe_outdir, shell=True)
255eb8dc403SDave Cobbley        if ret != 0:
256eb8dc403SDave Cobbley            raise DevtoolError('Deploy failed - rerun with -s to get a complete '
257eb8dc403SDave Cobbley                            'error message')
258eb8dc403SDave Cobbley
259eb8dc403SDave Cobbley        logger.info('Successfully deployed %s' % recipe_outdir)
260eb8dc403SDave Cobbley
261eb8dc403SDave Cobbley        files_list = []
262eb8dc403SDave Cobbley        for root, _, files in os.walk(recipe_outdir):
263eb8dc403SDave Cobbley            for filename in files:
264eb8dc403SDave Cobbley                filename = os.path.relpath(os.path.join(root, filename), recipe_outdir)
265eb8dc403SDave Cobbley                files_list.append(os.path.join(destdir, filename))
266eb8dc403SDave Cobbley    finally:
267eb8dc403SDave Cobbley        tinfoil.shutdown()
268eb8dc403SDave Cobbley
269eb8dc403SDave Cobbley    return 0
270eb8dc403SDave Cobbley
271eb8dc403SDave Cobbleydef undeploy(args, config, basepath, workspace):
272eb8dc403SDave Cobbley    """Entry point for the devtool 'undeploy' subcommand"""
273eb8dc403SDave Cobbley    if args.all and args.recipename:
274eb8dc403SDave Cobbley        raise argparse_oe.ArgumentUsageError('Cannot specify -a/--all with a recipe name', 'undeploy-target')
275eb8dc403SDave Cobbley    elif not args.recipename and not args.all:
276eb8dc403SDave Cobbley        raise argparse_oe.ArgumentUsageError('If you don\'t specify a recipe, you must specify -a/--all', 'undeploy-target')
277eb8dc403SDave Cobbley
278eb8dc403SDave Cobbley    extraoptions = ''
279eb8dc403SDave Cobbley    if args.no_host_check:
280eb8dc403SDave Cobbley        extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
281eb8dc403SDave Cobbley    if not args.show_status:
282eb8dc403SDave Cobbley        extraoptions += ' -q'
283eb8dc403SDave Cobbley
28419323693SBrad Bishop    scp_sshexec = ''
28519323693SBrad Bishop    ssh_sshexec = 'ssh'
28619323693SBrad Bishop    if args.ssh_exec:
28719323693SBrad Bishop        scp_sshexec = "-S %s" % args.ssh_exec
28819323693SBrad Bishop        ssh_sshexec = args.ssh_exec
289eb8dc403SDave Cobbley    scp_port = ''
290eb8dc403SDave Cobbley    ssh_port = ''
291eb8dc403SDave Cobbley    if args.port:
292eb8dc403SDave Cobbley        scp_port = "-P %s" % args.port
293eb8dc403SDave Cobbley        ssh_port = "-p %s" % args.port
294eb8dc403SDave Cobbley
295eb8dc403SDave Cobbley    args.target = args.target.split(':')[0]
296eb8dc403SDave Cobbley
297eb8dc403SDave Cobbley    tmpdir = tempfile.mkdtemp(prefix='devtool')
298eb8dc403SDave Cobbley    try:
299eb8dc403SDave Cobbley        tmpscript = '/tmp/devtool_undeploy.sh'
300eb8dc403SDave Cobbley        shellscript = _prepare_remote_script(deploy=False, dryrun=args.dry_run, undeployall=args.all)
301eb8dc403SDave Cobbley        # Write out the script to a file
302eb8dc403SDave Cobbley        with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f:
303eb8dc403SDave Cobbley            f.write(shellscript)
304eb8dc403SDave Cobbley        # Copy it to the target
30519323693SBrad Bishop        ret = subprocess.call("scp %s %s %s %s/* %s:%s" % (scp_sshexec, scp_port, extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True)
306eb8dc403SDave Cobbley        if ret != 0:
307eb8dc403SDave Cobbley            raise DevtoolError('Failed to copy script to %s - rerun with -s to '
308eb8dc403SDave Cobbley                                'get a complete error message' % args.target)
309eb8dc403SDave Cobbley    finally:
310eb8dc403SDave Cobbley        shutil.rmtree(tmpdir)
311eb8dc403SDave Cobbley
312eb8dc403SDave Cobbley    # Now run the script
31319323693SBrad Bishop    ret = subprocess.call('%s %s %s %s \'sh %s %s\'' % (ssh_sshexec, ssh_port, extraoptions, args.target, tmpscript, args.recipename), shell=True)
314eb8dc403SDave Cobbley    if ret != 0:
315eb8dc403SDave Cobbley        raise DevtoolError('Undeploy failed - rerun with -s to get a complete '
316eb8dc403SDave Cobbley                           'error message')
317eb8dc403SDave Cobbley
318eb8dc403SDave Cobbley    if not args.all and not args.dry_run:
319eb8dc403SDave Cobbley        logger.info('Successfully undeployed %s' % args.recipename)
320eb8dc403SDave Cobbley    return 0
321eb8dc403SDave Cobbley
322eb8dc403SDave Cobbley
323eb8dc403SDave Cobbleydef register_commands(subparsers, context):
324eb8dc403SDave Cobbley    """Register devtool subcommands from the deploy plugin"""
325eb8dc403SDave Cobbley
326eb8dc403SDave Cobbley    parser_deploy = subparsers.add_parser('deploy-target',
327eb8dc403SDave Cobbley                                          help='Deploy recipe output files to live target machine',
328eb8dc403SDave Cobbley                                          description='Deploys a recipe\'s build output (i.e. the output of the do_install task) to a live target machine over ssh. By default, any existing files will be preserved instead of being overwritten and will be restored if you run devtool undeploy-target. Note: this only deploys the recipe itself and not any runtime dependencies, so it is assumed that those have been installed on the target beforehand.',
329eb8dc403SDave Cobbley                                          group='testbuild')
330eb8dc403SDave Cobbley    parser_deploy.add_argument('recipename', help='Recipe to deploy')
331eb8dc403SDave Cobbley    parser_deploy.add_argument('target', help='Live target machine running an ssh server: user@hostname[:destdir]')
332eb8dc403SDave Cobbley    parser_deploy.add_argument('-c', '--no-host-check', help='Disable ssh host key checking', action='store_true')
333eb8dc403SDave Cobbley    parser_deploy.add_argument('-s', '--show-status', help='Show progress/status output', action='store_true')
334eb8dc403SDave Cobbley    parser_deploy.add_argument('-n', '--dry-run', help='List files to be deployed only', action='store_true')
335eb8dc403SDave Cobbley    parser_deploy.add_argument('-p', '--no-preserve', help='Do not preserve existing files', action='store_true')
336eb8dc403SDave Cobbley    parser_deploy.add_argument('--no-check-space', help='Do not check for available space before deploying', action='store_true')
33719323693SBrad Bishop    parser_deploy.add_argument('-e', '--ssh-exec', help='Executable to use in place of ssh')
338eb8dc403SDave Cobbley    parser_deploy.add_argument('-P', '--port', help='Specify port to use for connection to the target')
33964c979e8SBrad Bishop    parser_deploy.add_argument('-I', '--key',
340d25ed324SAndrew Geissler                               help='Specify ssh private key for connection to the target')
341eb8dc403SDave Cobbley
342eb8dc403SDave Cobbley    strip_opts = parser_deploy.add_mutually_exclusive_group(required=False)
343eb8dc403SDave Cobbley    strip_opts.add_argument('-S', '--strip',
344eb8dc403SDave Cobbley                               help='Strip executables prior to deploying (default: %(default)s). '
345eb8dc403SDave Cobbley                                    'The default value of this option can be controlled by setting the strip option in the [Deploy] section to True or False.',
346eb8dc403SDave Cobbley                               default=oe.types.boolean(context.config.get('Deploy', 'strip', default='0')),
347eb8dc403SDave Cobbley                               action='store_true')
348eb8dc403SDave Cobbley    strip_opts.add_argument('--no-strip', help='Do not strip executables prior to deploy', dest='strip', action='store_false')
349eb8dc403SDave Cobbley
350eb8dc403SDave Cobbley    parser_deploy.set_defaults(func=deploy)
351eb8dc403SDave Cobbley
352eb8dc403SDave Cobbley    parser_undeploy = subparsers.add_parser('undeploy-target',
353eb8dc403SDave Cobbley                                            help='Undeploy recipe output files in live target machine',
354eb8dc403SDave Cobbley                                            description='Un-deploys recipe output files previously deployed to a live target machine by devtool deploy-target.',
355eb8dc403SDave Cobbley                                            group='testbuild')
356eb8dc403SDave Cobbley    parser_undeploy.add_argument('recipename', help='Recipe to undeploy (if not using -a/--all)', nargs='?')
357eb8dc403SDave Cobbley    parser_undeploy.add_argument('target', help='Live target machine running an ssh server: user@hostname')
358eb8dc403SDave Cobbley    parser_undeploy.add_argument('-c', '--no-host-check', help='Disable ssh host key checking', action='store_true')
359eb8dc403SDave Cobbley    parser_undeploy.add_argument('-s', '--show-status', help='Show progress/status output', action='store_true')
360eb8dc403SDave Cobbley    parser_undeploy.add_argument('-a', '--all', help='Undeploy all recipes deployed on the target', action='store_true')
361eb8dc403SDave Cobbley    parser_undeploy.add_argument('-n', '--dry-run', help='List files to be undeployed only', action='store_true')
36219323693SBrad Bishop    parser_undeploy.add_argument('-e', '--ssh-exec', help='Executable to use in place of ssh')
363eb8dc403SDave Cobbley    parser_undeploy.add_argument('-P', '--port', help='Specify port to use for connection to the target')
36464c979e8SBrad Bishop    parser_undeploy.add_argument('-I', '--key',
365d25ed324SAndrew Geissler                               help='Specify ssh private key for connection to the target')
36664c979e8SBrad Bishop
367eb8dc403SDave Cobbley    parser_undeploy.set_defaults(func=undeploy)
368