Merge lp:~terceiro/lava-dispatcher/nexus into lp:lava-dispatcher

Proposed by Antonio Terceiro
Status: Merged
Merged at revision: 543
Proposed branch: lp:~terceiro/lava-dispatcher/nexus
Merge into: lp:lava-dispatcher
Diff against target: 262 lines (+242/-0)
3 files modified
lava_dispatcher/config.py (+3/-0)
lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf (+46/-0)
lava_dispatcher/device/nexus.py (+193/-0)
To merge this branch: bzr merge lp:~terceiro/lava-dispatcher/nexus
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle (community) Approve
Review via email: mp+144204@code.launchpad.net

This proposal supersedes a proposal from 2013-01-15.

Description of the change

Hi guys,

I tried to address all your concerns and this is an improved version of the code.

The only issue I did not handle was Andy's point about exception handling in file_system. I didn't see the point in catching an eventual exception there just to raise a new exception. If anything in there blows up, the job will just be terminated.

Please let me know what you think.

To post a comment you must log in.
Revision history for this message
Andy Doan (doanac) wrote : Posted in a previous version of this proposal

On 01/15/2013 01:18 PM, Antonio Terceiro wrote:
> + def power_on(self):

Seems like you might want to add some check like:

            if not self.deployment_data.get('boot_image', False):
                raise CriticalError('Deploy action must be run first')

> + self.reboot_os()
> + self.reboot_bootloader()
> + self.boot_test_image()
> +
> + self._powered_on = True
> + proc = self.adb('shell', spawn = True)
> + proc.sendline("") # required to put the adb shell in a reasonable state
> + proc.sendline("export PS1='%s'" % self.deployment_data['TESTER_PS1'])
> + self._runner = self._get_runner(proc)
> +
> + return proc

> + def power_off(self, proc):
> + # there is no way to power off the Nexus while USB is plugged on; even
> + # if you remove power, it will stay on.
> + pass
> +
This might be correct, but I fear a bad image could put us in an
irrecoverable state. One thing we might consider adding is some type of
logic like I did in sdmux.sh:

<http://bazaar.launchpad.net/~linaro-validation/lava-dispatcher/trunk/view/head:/lava_dispatcher/device/sdmux.sh>

This essentially powers down a USB port and might solve your problem.
However, since you use ADB over USB be aware of this issue:

  https://groups.google.com/forum/#!topic/android-platform/hLmD0DDAzj8

Lastly, the filesystem function looks like it might need some exception
handling logic. Not sure about this, but I found the need when
implementing that logic for other targets.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote : Posted in a previous version of this proposal
Download full text (10.8 KiB)

Antonio Terceiro <email address hidden> writes:

> Antonio Terceiro has proposed merging lp:~terceiro/lava-dispatcher/nexus into lp:lava-dispatcher.
>
> Requested reviews:
> Linaro Validation Team (linaro-validation)
>
> For more details, see:
> https://code.launchpad.net/~terceiro/lava-dispatcher/nexus/+merge/143385
>
> Hi,
>
> This time is for real. :-)
>
> I don't see any pending issues, so know you can have a hard review on the code.
> --
> https://code.launchpad.net/~terceiro/lava-dispatcher/nexus/+merge/143385
> You are subscribed to branch lp:lava-dispatcher.
> === modified file 'lava_dispatcher/config.py'
> --- lava_dispatcher/config.py 2013-01-10 21:37:58 +0000
> +++ lava_dispatcher/config.py 2013-01-15 19:17:23 +0000
> @@ -91,6 +91,9 @@
> arm_probe_config = schema.StringOption(default='/usr/local/etc/arm-probe-config')
> arm_probe_channels = schema.ListOption(default=['VDD_VCORE1'])
>
> + adb_command = schema.StringOption()
> + fastboot_command = schema.StringOption()
> + nexus_working_directory = schema.StringOption(default = None)

It's super nitty, but "default=None" (i.e. without the spaces) would be
more conventional.

> class OptionDescriptor(object):
> def __init__(self, name):
>
> === added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf'
> --- lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 1970-01-01 00:00:00 +0000
> +++ lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 2013-01-15 19:17:23 +0000
> @@ -0,0 +1,40 @@
> +client_type = nexus
> +
> +# The ADB command line.
> +#
> +# In the case where there are more than one android devices plugged into a

s/are/is/ or s/more than one/multiple/ (English grammar makes no sense)

> +# single host, this connection command must be overriden on each device to
> +# include the serial number of the device, e.g.
> +#
> +# serial_number = XXXXXXXXXXXXXXXX
> +# adb_command = adb -s %(serial_number)s
> +adb_command = adb
> +
> +# The fastboot command.
> +#
> +# The same as above: if you have more than one device, you will want to
> +# override this in your device config to add a serial number, e.g.
> +#
> +# serial_number = XXXXXXXXXXXXXXXX
> +# fastboot_command = sudo fastboot -s %(serial_number)s
> +#
> +# Of course, in the case you override both adb_command *and* fastboot_command,
> +# you don't need to specify `serial_number` twice.
> +fastboot_command = sudo fastboot
> +
> +# Working directory for temporary. By default, the usual place for LAVA images
> +# will be used.
> +#
> +# This is useful when the lava dispatcher is controlling Nexus phones that are
> +# physically plugged to other machines. In this case, you should set
> +# nexus_work_directory to a shared directory between the machine running the
> +# dispatcher and the machine where the phone is plugged.

I don't entirely understand when this would be useful.

> +# OBS: this shared directory must have the same path in both machines.

OBS?

> +nexus_working_directory =
> +
> +connection_command = %(adb_command)s shell
> +
> +enable_network_after_boot_android = false
> +android_adb_over_usb = true
> +android_adb_...

Revision history for this message
Antonio Terceiro (terceiro) wrote : Posted in a previous version of this proposal

Hi,

On Tue, Jan 15, 2013 at 11:37:22PM -0000, Andy Doan wrote:
> On 01/15/2013 01:18 PM, Antonio Terceiro wrote:
> > + def power_on(self):
>
> Seems like you might want to add some check like:
>
> if not self.deployment_data.get('boot_image', False):
> raise CriticalError('Deploy action must be run first')

Done, thanks.

> > + self.reboot_os()
> > + self.reboot_bootloader()
> > + self.boot_test_image()
> > +
> > + self._powered_on = True
> > + proc = self.adb('shell', spawn = True)
> > + proc.sendline("") # required to put the adb shell in a reasonable state
> > + proc.sendline("export PS1='%s'" % self.deployment_data['TESTER_PS1'])
> > + self._runner = self._get_runner(proc)
> > +
> > + return proc
>
> > + def power_off(self, proc):
> > + # there is no way to power off the Nexus while USB is plugged on; even
> > + # if you remove power, it will stay on.
> > + pass
> > +
> This might be correct, but I fear a bad image could put us in an
> irrecoverable state. One thing we might consider adding is some type of
> logic like I did in sdmux.sh:
>
>
> <http://bazaar.launchpad.net/~linaro-validation/lava-dispatcher/trunk/view/head:/lava_dispatcher/device/sdmux.sh>
>
> This essentially powers down a USB port and might solve your problem.
> However, since you use ADB over USB be aware of this issue:
>
> https://groups.google.com/forum/#!topic/android-platform/hLmD0DDAzj8

Actually, I investigated a little more and found that:

  - in android, just cutting the power works
  - in fastboot, cutting the power sometimes works, sometimes not. But
    if I tell fastboot to reboot after cutting the power, then it
    actually goes off.

I will try that.

> Lastly, the filesystem function looks like it might need some exception
> handling logic. Not sure about this, but I found the need when
> implementing that logic for other targets.

ok - I will look at it.

--
Antonio Terceiro
Software Engineer - Linaro
http://www.linaro.org

Revision history for this message
Antonio Terceiro (terceiro) wrote : Posted in a previous version of this proposal
Download full text (12.2 KiB)

On Wed, Jan 16, 2013 at 12:16:20AM -0000, Michael Hudson-Doyle wrote:
> Antonio Terceiro <email address hidden> writes:
>
> > Antonio Terceiro has proposed merging lp:~terceiro/lava-dispatcher/nexus into lp:lava-dispatcher.
> >
> > Requested reviews:
> > Linaro Validation Team (linaro-validation)
> >
> > For more details, see:
> > https://code.launchpad.net/~terceiro/lava-dispatcher/nexus/+merge/143385
> >
> > Hi,
> >
> > This time is for real. :-)
> >
> > I don't see any pending issues, so know you can have a hard review on the code.
> > --
> > https://code.launchpad.net/~terceiro/lava-dispatcher/nexus/+merge/143385
> > You are subscribed to branch lp:lava-dispatcher.
> > === modified file 'lava_dispatcher/config.py'
> > --- lava_dispatcher/config.py 2013-01-10 21:37:58 +0000
> > +++ lava_dispatcher/config.py 2013-01-15 19:17:23 +0000
> > @@ -91,6 +91,9 @@
> > arm_probe_config = schema.StringOption(default='/usr/local/etc/arm-probe-config')
> > arm_probe_channels = schema.ListOption(default=['VDD_VCORE1'])
> >
> > + adb_command = schema.StringOption()
> > + fastboot_command = schema.StringOption()
> > + nexus_working_directory = schema.StringOption(default = None)
>
> It's super nitty, but "default=None" (i.e. without the spaces) would be
> more conventional.

Fixed.

> > class OptionDescriptor(object):
> > def __init__(self, name):
> >
> > === added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf'
> > --- lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 1970-01-01 00:00:00 +0000
> > +++ lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 2013-01-15 19:17:23 +0000
> > @@ -0,0 +1,40 @@
> > +client_type = nexus
> > +
> > +# The ADB command line.
> > +#
> > +# In the case where there are more than one android devices plugged into a
>
> s/are/is/ or s/more than one/multiple/ (English grammar makes no sense)

Fixed

> > +# single host, this connection command must be overriden on each device to
> > +# include the serial number of the device, e.g.
> > +#
> > +# serial_number = XXXXXXXXXXXXXXXX
> > +# adb_command = adb -s %(serial_number)s
> > +adb_command = adb
> > +
> > +# The fastboot command.
> > +#
> > +# The same as above: if you have more than one device, you will want to
> > +# override this in your device config to add a serial number, e.g.
> > +#
> > +# serial_number = XXXXXXXXXXXXXXXX
> > +# fastboot_command = sudo fastboot -s %(serial_number)s
> > +#
> > +# Of course, in the case you override both adb_command *and* fastboot_command,
> > +# you don't need to specify `serial_number` twice.
> > +fastboot_command = sudo fastboot
> > +
> > +# Working directory for temporary. By default, the usual place for LAVA images
> > +# will be used.
> > +#
> > +# This is useful when the lava dispatcher is controlling Nexus phones that are
> > +# physically plugged to other machines. In this case, you should set
> > +# nexus_work_directory to a shared directory between the machine running the
> > +# dispatcher and the machine where the phone is plugged.
>
> I don't entirely understand when this would be useful.

I will try to explain it...

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote : Posted in a previous version of this proposal
Download full text (6.5 KiB)

Antonio Terceiro <email address hidden> writes:

> On Wed, Jan 16, 2013 at 12:16:20AM -0000, Michael Hudson-Doyle wrote:
>> Antonio Terceiro <email address hidden> writes:
>> > +# Working directory for temporary. By default, the usual place for LAVA images
>> > +# will be used.
>> > +#
>> > +# This is useful when the lava dispatcher is controlling Nexus phones that are
>> > +# physically plugged to other machines. In this case, you should set
>> > +# nexus_work_directory to a shared directory between the machine running the
>> > +# dispatcher and the machine where the phone is plugged.
>>
>> I don't entirely understand when this would be useful.
>
> I will try to explain it better. :)

Did you do this? I'm guessing you use it when LAVA is running in a VM?

>> > +# OBS: this shared directory must have the same path in both machines.
>>
>> OBS?
>
> heh, that's the equivalent of "N.B." in Portuguese, I guess it doesn't
> exist in English. :) I will rewrite that doc, so for now I just removed
> the OBS.

Heh.

>> > +nexus_working_directory =
>> > +
>> > +connection_command = %(adb_command)s shell
>> > +
>> > +enable_network_after_boot_android = false
>> > +android_adb_over_usb = true
>> > +android_adb_over_tcp = false
>> >
>> > === added file 'lava_dispatcher/device/nexus.py'
>> > --- lava_dispatcher/device/nexus.py 1970-01-01 00:00:00 +0000
>> > +++ lava_dispatcher/device/nexus.py 2013-01-15 19:17:23 +0000
>> > @@ -0,0 +1,168 @@
>> > +# Copyright (C) 2012 Linaro Limited
>> > +#
>> > +# Author: Antonio Terceiro <email address hidden>
>> > +#
>> > +# This file is part of LAVA Dispatcher.
>> > +#
>> > +# LAVA Dispatcher is free software; you can redistribute it and/or modify
>> > +# it under the terms of the GNU General Public License as published by
>> > +# the Free Software Foundation; either version 2 of the License, or
>> > +# (at your option) any later version.
>> > +#
>> > +# LAVA Dispatcher is distributed in the hope that it will be useful,
>> > +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> > +# GNU General Public License for more details.
>> > +#
>> > +# You should have received a copy of the GNU General Public License
>> > +# along
>> > +# with this program; if not, see <http://www.gnu.org/licenses>.
>> > +
>> > +import subprocess
>> > +import pexpect
>> > +from time import sleep
>> > +import logging
>> > +import contextlib
>> > +
>> > +from lava_dispatcher.device.target import (
>> > + Target
>> > +)
>> > +from lava_dispatcher.downloader import (
>> > + download_image
>> > +)
>> > +from lava_dispatcher.utils import (
>> > + logging_spawn,
>> > + mkdtemp
>> > +)
>>
>> OK, so this is probably mostly the dispatcher's fault for being
>> confusing, but there are a few things I don't really understand here.
>> If I get you to explain them to me in excruciating detail, maybe we can
>> make the code clearer for the next person.
>>
>> > +class NexusTarget(Target):
>> > +
>> > + def __init__(self, context, config):
>> > + super(NexusTarget, self).__init__(context, config)
>> > + self._powered_on = Fal...

Read more...

Revision history for this message
Antonio Terceiro (terceiro) wrote : Posted in a previous version of this proposal

On Mon, Jan 21, 2013 at 11:19:21PM -0000, Michael Hudson-Doyle wrote:
> Antonio Terceiro <email address hidden> writes:
>
> > On Wed, Jan 16, 2013 at 12:16:20AM -0000, Michael Hudson-Doyle wrote:
> >> Antonio Terceiro <email address hidden> writes:
> >> > +# Working directory for temporary. By default, the usual place for LAVA images
> >> > +# will be used.
> >> > +#
> >> > +# This is useful when the lava dispatcher is controlling Nexus phones that are
> >> > +# physically plugged to other machines. In this case, you should set
> >> > +# nexus_work_directory to a shared directory between the machine running the
> >> > +# dispatcher and the machine where the phone is plugged.
> >>
> >> I don't entirely understand when this would be useful.
> >
> > I will try to explain it better. :)
>
> Did you do this? I'm guessing you use it when LAVA is running in a VM?

Yes! :-)

It works for lava-test-shell, but not for lava-android-test, because the
later syncs files from its installed code base directly into the device
with adb, without using the file_system API call.

--
Antonio Terceiro
Software Engineer - Linaro
http://www.linaro.org

Revision history for this message
Michael Hudson-Doyle (mwhudson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lava_dispatcher/config.py'
2--- lava_dispatcher/config.py 2013-01-18 11:08:24 +0000
3+++ lava_dispatcher/config.py 2013-01-22 02:17:24 +0000
4@@ -92,6 +92,9 @@
5 arm_probe_config = schema.StringOption(default='/usr/local/etc/arm-probe-config')
6 arm_probe_channels = schema.ListOption(default=['VDD_VCORE1'])
7
8+ adb_command = schema.StringOption()
9+ fastboot_command = schema.StringOption()
10+ nexus_working_directory = schema.StringOption(default=None)
11
12 class OptionDescriptor(object):
13 def __init__(self, name):
14
15=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf'
16--- lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 1970-01-01 00:00:00 +0000
17+++ lava_dispatcher/default-config/lava-dispatcher/device-types/nexus.conf 2013-01-22 02:17:24 +0000
18@@ -0,0 +1,46 @@
19+client_type = nexus
20+
21+# The ADB command line.
22+#
23+# In the case where there are multiple android devices plugged into a
24+# single host, this connection command must be overriden on each device to
25+# include the serial number of the device, e.g.
26+#
27+# serial_number = XXXXXXXXXXXXXXXX
28+# adb_command = adb -s %(serial_number)s
29+adb_command = adb
30+
31+# The fastboot command.
32+#
33+# The same as above: if you have more than one device, you will want to
34+# override this in your device config to add a serial number, e.g.
35+#
36+# serial_number = XXXXXXXXXXXXXXXX
37+# fastboot_command = fastboot -s %(serial_number)s
38+#
39+# Of course, in the case you override both adb_command *and* fastboot_command,
40+# you don't need to specify `serial_number` twice.
41+fastboot_command = fastboot
42+
43+# Working directory for temporary files. By default, the usual place for LAVA
44+# images will be used.
45+#
46+# This is useful when the lava dispatcher is controlling Nexus phones that are
47+# physically plugged to other machines by setting adb_command to something like
48+# "ssh <phone-host> adb" and fastboot_command to something like "ssh
49+# <phone-host> fastboot". adb and fastboot always operate on local files, so
50+# you need your local files to also be seen as local files on the host where
51+# adb/fastboot are executed.
52+#
53+# In this case, you should set nexus_work_directory to a shared directory
54+# between the machine running the dispatcher and the machine where the phone is
55+# plugged. This shared directory must have the same path in both machines.
56+# For example, you can have your /var/tmp/lava mounted at /var/tmp/lava at
57+# <phone-host> (or the other way around).
58+nexus_working_directory =
59+
60+connection_command = %(adb_command)s shell
61+
62+enable_network_after_boot_android = false
63+android_adb_over_usb = true
64+android_adb_over_tcp = false
65
66=== added file 'lava_dispatcher/device/nexus.py'
67--- lava_dispatcher/device/nexus.py 1970-01-01 00:00:00 +0000
68+++ lava_dispatcher/device/nexus.py 2013-01-22 02:17:24 +0000
69@@ -0,0 +1,193 @@
70+# Copyright (C) 2012 Linaro Limited
71+#
72+# Author: Antonio Terceiro <antonio.terceiro@linaro.org>
73+#
74+# This file is part of LAVA Dispatcher.
75+#
76+# LAVA Dispatcher is free software; you can redistribute it and/or modify
77+# it under the terms of the GNU General Public License as published by
78+# the Free Software Foundation; either version 2 of the License, or
79+# (at your option) any later version.
80+#
81+# LAVA Dispatcher is distributed in the hope that it will be useful,
82+# but WITHOUT ANY WARRANTY; without even the implied warranty of
83+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84+# GNU General Public License for more details.
85+#
86+# You should have received a copy of the GNU General Public License
87+# along
88+# with this program; if not, see <http://www.gnu.org/licenses>.
89+
90+import subprocess
91+import pexpect
92+from time import sleep
93+import logging
94+import contextlib
95+
96+from lava_dispatcher.device.target import (
97+ Target
98+)
99+from lava_dispatcher.downloader import (
100+ download_image
101+)
102+from lava_dispatcher.utils import (
103+ logging_system,
104+ logging_spawn,
105+ mkdtemp
106+)
107+from lava_dispatcher.errors import (
108+ CriticalError
109+)
110+
111+class NexusTarget(Target):
112+
113+ def __init__(self, context, config):
114+ super(NexusTarget, self).__init__(context, config)
115+
116+ if not config.hard_reset_command:
117+ logging.warn(
118+ "Setting the hard_reset_command config option "
119+ "is highly recommended!"
120+ )
121+
122+ self._booted = False
123+ self._working_dir = None
124+
125+ def deploy_android(self, boot, system, userdata):
126+
127+ boot = self._get_image(boot)
128+ system = self._get_image(system)
129+ userdata = self._get_image(userdata)
130+
131+ self._enter_fastboot()
132+ self._fastboot('erase boot')
133+ self._fastboot('flash system %s' % system)
134+ self._fastboot('flash userdata %s' % userdata)
135+
136+ self.deployment_data = Target.android_deployment_data
137+ self.deployment_data['boot_image'] = boot
138+
139+ def power_on(self):
140+ if not self.deployment_data.get('boot_image', False):
141+ raise CriticalError('Deploy action must be run first')
142+
143+ self._enter_fastboot()
144+ self._boot_test_image()
145+
146+ self._booted = True
147+ proc = self._adb('shell', spawn = True)
148+ proc.sendline("") # required to put the adb shell in a reasonable state
149+ proc.sendline("export PS1='%s'" % self.deployment_data['TESTER_PS1'])
150+ self._runner = self._get_runner(proc)
151+
152+ return proc
153+
154+ def power_off(self, proc):
155+ # We always leave the device on
156+ pass
157+
158+ @contextlib.contextmanager
159+ def file_system(self, partition, directory):
160+
161+ if not self._booted:
162+ self.power_on()
163+
164+ mount_point = self._get_partition_mount_point(partition)
165+
166+ host_dir = '%s/mnt/%s' % (self.working_dir, directory)
167+ target_dir = '%s/%s' % (mount_point, directory)
168+
169+ subprocess.check_call(['mkdir', '-p', host_dir])
170+ self._adb('pull %s %s' % (target_dir, host_dir), ignore_failure = True)
171+
172+ yield host_dir
173+
174+ self._adb('push %s %s' % (host_dir, target_dir))
175+
176+ def get_device_version(self):
177+ # this is tricky, because fastboot does not have a visible version
178+ # number. For now let's use just the adb version number.
179+ return subprocess.check_output(
180+ "%s version | sed 's/.* version //'" % self.config.adb_command,
181+ shell = True
182+ ).strip()
183+
184+ # start of private methods
185+
186+ def _enter_fastboot(self):
187+ if self._already_on_fastboot():
188+ logging.debug("Device is on fastboot - no need to hard reset")
189+ return
190+ try:
191+ # First we try a gentle reset
192+ self._adb('reboot')
193+ except subprocess.CalledProcessError:
194+ # Now a more brute force attempt. In this case the device is
195+ # probably hung.
196+ if self.config.hard_reset_command:
197+ logging.debug("Will hard reset the device")
198+ logging_system(self.config.hard_reset_command)
199+ else:
200+ logging.critical(
201+ "Hard reset command not configured. "
202+ "Please reset the device manually."
203+ )
204+
205+ def _already_on_fastboot(self):
206+ try:
207+ self._fastboot('getvar all', timeout = 2)
208+ return True
209+ except subprocess.CalledProcessError:
210+ return False
211+
212+ def _boot_test_image(self):
213+ # We need an extra bootloader reboot before actually booting the image
214+ # to avoid the phone entering charging mode and getting stuck.
215+ self._fastboot('reboot')
216+ # specifically after `fastboot reset`, we have to wait a little
217+ sleep(10)
218+ self._fastboot('boot %s' % self.deployment_data['boot_image'])
219+ self._adb('wait-for-device')
220+
221+ def _get_partition_mount_point(self, partition):
222+ lookup = {
223+ self.config.data_part_android_org: '/data',
224+ self.config.sys_part_android_org: '/system',
225+ }
226+ return lookup[partition]
227+
228+ def _adb(self, args, ignore_failure = False, spawn = False, timeout = 600):
229+ cmd = self.config.adb_command + ' ' + args
230+ if spawn:
231+ return logging_spawn(cmd, timeout = 60)
232+ else:
233+ self._call(cmd, ignore_failure, timeout)
234+
235+ def _fastboot(self, args, ignore_failure = False, timeout = 600):
236+ self._call(self.config.fastboot_command + ' ' + args, ignore_failure, timeout)
237+
238+ def _call(self, cmd, ignore_failure, timeout):
239+ cmd = 'timeout ' + str(timeout) + 's ' + cmd
240+ logging.debug("Running on the host: %s" % cmd)
241+ if ignore_failure:
242+ subprocess.call(cmd, shell = True)
243+ else:
244+ subprocess.check_call(cmd, shell = True)
245+
246+ def _get_image(self, url):
247+ sdir = self.working_dir
248+ image = download_image(url, self.context, sdir, decompress=False)
249+ return image
250+
251+ @property
252+ def working_dir(self):
253+ if (self.config.nexus_working_directory is None or
254+ self.config.nexus_working_directory.strip() == ''):
255+ return self.scratch_dir
256+
257+ if self._working_dir is None:
258+ self._working_dir = mkdtemp(self.config.nexus_working_directory)
259+ return self._working_dir
260+
261+
262+target_class = NexusTarget

Subscribers

People subscribed via source and target branches