Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
174 lines
6 KiB
Python
Executable file
174 lines
6 KiB
Python
Executable file
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
from abc import ABCMeta, abstractmethod
|
|
import os
|
|
import shutil
|
|
|
|
import mozlog
|
|
|
|
|
|
class GaiaFileManager(object):
|
|
"""Abstract file manager for Gaia."""
|
|
__metaclass__ = ABCMeta
|
|
|
|
def __init__(self, device, log_level=mozlog.unstructured.ERROR):
|
|
self._logger = mozlog.unstructured.getLogger('GaiaFileManager')
|
|
self._logger.setLevel(log_level)
|
|
self.device = device
|
|
|
|
@abstractmethod
|
|
def copy_file(self, source, destination):
|
|
"""Copy a file."""
|
|
|
|
@abstractmethod
|
|
def dir_exists(self, path):
|
|
"""Return true if path exists and is a directory."""
|
|
return
|
|
|
|
def duplicate_file(self, path, count):
|
|
"""Create duplicates of a file on the system and remove original."""
|
|
original = path
|
|
path, sep, filename = path.rpartition('/')
|
|
# We copy the file we've just created rather than pushing it
|
|
# multiple times, which would be much slower.
|
|
for i in range(1, count + 1):
|
|
# Make the remote filename unique by including an index
|
|
if '.' in filename:
|
|
indexed_filename = '_%d.'.join(iter(
|
|
filename.rsplit('.', 1))) % i
|
|
else:
|
|
indexed_filename = '%s_%d' % (filename, i)
|
|
duplicate = '/'.join([path, indexed_filename])
|
|
self.copy_file(original, duplicate)
|
|
self.remove(original)
|
|
|
|
@abstractmethod
|
|
def file_exists(self, path):
|
|
"""Return true if path exists and is a file."""
|
|
return
|
|
|
|
@abstractmethod
|
|
def list_items(self, path):
|
|
"""List items in path."""
|
|
return
|
|
|
|
@abstractmethod
|
|
def make_dirs(self, filename):
|
|
"""Make directory structure."""
|
|
|
|
@abstractmethod
|
|
def pull_file(self, path):
|
|
"""Returns contents of file."""
|
|
|
|
@abstractmethod
|
|
def push_file(self, local_path, remote_path=None, count=1):
|
|
"""Push a file to the system."""
|
|
|
|
@abstractmethod
|
|
def remove(self, path):
|
|
"""Remove file or directory."""
|
|
|
|
|
|
class GaiaDeviceFileManager(GaiaFileManager):
|
|
"""File manager for Gaia instance running on a B2G device or emulator."""
|
|
|
|
def copy_file(self, source, destination):
|
|
self._logger.debug('Copying: %s to: %s' % (source, destination))
|
|
self.device.manager.copyTree(source, destination)
|
|
|
|
def dir_exists(self, path):
|
|
self._logger.debug('Checking for existance of directory: %s' % path)
|
|
return self.device.manager.dirExists(path)
|
|
|
|
def file_exists(self, path):
|
|
self._logger.debug('Checking for existance of file: %s' % path)
|
|
return self.device.manager.fileExists(path)
|
|
|
|
def list_items(self, path):
|
|
self._logger.debug('Listing items in: %s' % path)
|
|
return self.device.manager.listFiles(path)
|
|
|
|
def make_dirs(self, filename):
|
|
self.device.manager.mkDirs(filename)
|
|
|
|
def pull_file(self, path):
|
|
return self.device.manager.pullFile(path)
|
|
|
|
def push_file(self, local_path, remote_path=None, count=1):
|
|
# If remote path is not specified, use the storage path
|
|
remote_path = remote_path or self.device.storage_path
|
|
filename = local_path.rpartition(os.path.sep)[-1]
|
|
remote_file = '/'.join([remote_path, filename])
|
|
self.make_dirs(remote_file)
|
|
self.device.manager.pushFile(local_path, remote_file)
|
|
if count > 1:
|
|
self.duplicate_file(remote_file, count)
|
|
|
|
def remove(self, path):
|
|
self._logger.debug('Removing: %s' % path)
|
|
self.device.manager.removeDir(path)
|
|
|
|
|
|
class GaiaLocalFileManager(GaiaFileManager):
|
|
"""File manager for Gaia instance running locally such as desktop B2G."""
|
|
|
|
def copy_file(self, source, destination):
|
|
source = os.path.normpath(source)
|
|
destination = os.path.normpath(destination)
|
|
self._logger.debug('Copying: %s to: %s' % (source, destination))
|
|
shutil.copy(source, destination)
|
|
|
|
def dir_exists(self, path):
|
|
path = os.path.normpath(path)
|
|
self._logger.debug('Checking for existance of directory: %s' % path)
|
|
return os.path.isdir(path)
|
|
|
|
def file_exists(self, path):
|
|
path = os.path.normpath(path)
|
|
self._logger.debug('Checking for existance of file: %s' % path)
|
|
return os.path.isfile(path)
|
|
|
|
def list_items(self, path):
|
|
path = os.path.normpath(path)
|
|
self._logger.debug('Listing items in: %s' % path)
|
|
return os.listdir(path)
|
|
|
|
def make_dirs(self, filename):
|
|
filename = os.path.normpath(filename)
|
|
containing = os.path.dirname(filename)
|
|
if not os.path.isdir(containing):
|
|
self._logger.debug('Making path: %s' % containing)
|
|
os.makedirs(containing)
|
|
|
|
def pull_file(self, path):
|
|
with open(path) as f:
|
|
return f.read()
|
|
|
|
def push_file(self, local_path, remote_path=None, count=1):
|
|
# If remote path is not specified, use the storage path
|
|
remote_path = remote_path or self.device.storage_path
|
|
filename = local_path.rpartition(os.path.sep)[-1]
|
|
remote_file = '/'.join([remote_path, filename])
|
|
self.make_dirs(remote_file)
|
|
|
|
path = os.path.normpath(remote_file)
|
|
if os.path.isdir(path):
|
|
raise Exception('Attempted to push a file (%s) to a directory '
|
|
'(%s)!' % (local_path, path))
|
|
if not os.access(local_path, os.F_OK):
|
|
raise Exception('File not found: %s' % local_path)
|
|
self._logger.debug('Pushing: %s to: %s' % (local_path, path))
|
|
self.copy_file(local_path, path)
|
|
if count > 1:
|
|
self.duplicate_file(remote_file, count)
|
|
|
|
def remove(self, path):
|
|
path = os.path.normpath(path)
|
|
if os.path.isfile(path):
|
|
self._logger.debug('Removing file: %s' % path)
|
|
os.remove(path)
|
|
elif os.path.isdir(path):
|
|
self._logger.debug('Removing directory: %s' % path)
|
|
shutil.rmtree(path)
|