blob: 6b63f22cd3886d8cfab86a6fe5b3209936143a1f [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Implementation of graphyte.link.DeviceLink on local system."""
import pipes
import shutil
import subprocess
import six
import graphyte_common # pylint: disable=unused-import
from graphyte import link
class LocalLink(link.DeviceLink):
"""Runs locally on a device."""
def __init__(self, shell_path=None):
"""Link constructor.
Args:
shell_path: A string for the path of default shell.
"""
self._shell_path = shell_path
def Push(self, local, remote):
shutil.copy(local, remote)
def PushDirectory(self, local, remote):
shutil.copytree(local, remote)
def Pull(self, remote, local=None):
if local is None:
with open(remote) as f:
return f.read()
shutil.copy(remote, local)
def Shell(self, command, stdin=None, stdout=None, stderr=None):
# On most remote links, we always need to execute the commands via shell. To
# unify the behavior we should always run the command using shell even on
# local links. Ideally python should find the right shell intepreter for us,
# however at least in Python 2.x, it was unfortunately hard-coded as
# (['/bin/sh', '-c'] + args) when shell=True. In other words, if your
# default shell is not sh or if it is in other location (for instance,
# Android only has /system/bin/sh) then calling Popen may give you 'No such
# file or directory' error.
if not isinstance(command, six.string_types):
command = ' '.join(pipes.quote(param) for param in command)
if self._shell_path:
# Shell path is specified and we have to quote explicitly.
command = [self._shell_path, '-c', command]
shell = False
else:
# Trust default path specified by Python runtime. Useful for non-POSIX
# systems like Windows.
shell = True
return subprocess.Popen(command, shell=shell, close_fds=True, stdin=stdin,
stdout=stdout, stderr=stderr)
def IsReady(self):
return True