# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Actions for managing the local file systems."""

import logging
import os
import shutil
from glazier.lib.actions.base import ActionError
from glazier.lib.actions.base import BaseAction
from glazier.lib.actions.base import ValidationError  # pylint:disable=unused-import


class FileSystem(BaseAction):
  """Parent filesystem class with utility functions."""

  def _CreateDirectories(self, path):
    """Create a directory.

    Args:
      path: The full path to the directory to be created.

    Raises:
      ActionError: Failure creating the requested directory.
    """
    if not os.path.isdir(path):
      try:
        logging.debug('Creating directory: %s', path)
        os.makedirs(path)
      except (shutil.Error, OSError) as e:
        raise ActionError('Unable to create directory %s: %s' % (path, str(e)))


class CopyDir(FileSystem):
  """Copies directories on disk."""

  def Run(self):
    try:
      src = self._args[0]
      dst = self._args[1]
    except IndexError:
      raise ActionError('Unable to determine source and destination from %s.' %
                        str(self._args))
    try:
      logging.info('Copying directory: %s to %s', src, dst)
      shutil.copytree(src, dst)
    except (shutil.Error, OSError) as e:
      raise ActionError('Unable to copy %s to %s: %s' % (src, dst, str(e)))

  def Validate(self):
    self._ListOfStringsValidator(self._args, length=2)


class CopyFile(FileSystem):
  """Copies files on disk."""

  def Run(self):
    try:
      src = self._args[0]
      dst = self._args[1]
    except IndexError:
      raise ActionError('Unable to determine source and destination from %s.' %
                        str(self._args))
    try:
      path = os.path.dirname(dst)
      self._CreateDirectories(path)
      shutil.copy2(src, dst)
      logging.info('Copying: %s to %s', src, dst)
    except (shutil.Error, IOError) as e:
      raise ActionError('Unable to copy %s to %s: %s' % (src, dst, str(e)))

  def Validate(self):
    self._ListOfStringsValidator(self._args, length=2)


class MultiCopyFile(BaseAction):
  """Perform CopyFile on multiple sets of files."""

  def Run(self):
    try:
      for arg in self._args:
        cf = CopyFile([arg[0], arg[1]], self._build_info)
        cf.Run()
    except IndexError:
      raise ActionError('Unable to determine copy sets from %s.' %
                        str(self._args))

  def Validate(self):
    self._TypeValidator(self._args, list)
    for arg in self._args:
      cf = CopyFile(arg, self._build_info)
      cf.Validate()


class MkDir(FileSystem):
  """Create a directory."""

  def Run(self):
    try:
      path = self._args[0]
    except IndexError:
      raise ActionError('Unable to determine desired path from %s.' %
                        str(self._args))
    self._CreateDirectories(path)

  def Validate(self):
    self._ListOfStringsValidator(self._args)


class SetupCache(FileSystem):
  """Create the imaging cache directory."""

  def Run(self):
    path = self._build_info.CachePath()
    self._CreateDirectories(path)

  def Validate(self):
    self._TypeValidator(self._args, list)

@@ -1488,32 +1488,60 @@
  def Run(self):%0A
+    remove_existing = False%0A
     try:%0A      s
@@ -1577,32 +1577,102 @@
 = self._args%5B1%5D%0A
+      if len(self._args) %3E 2:%0A        remove_existing = self._args%5B2%5D%0A
     except Index
@@ -1818,287 +1818,892 @@
     
-logging.info('Copying directory: %25s to %25s', src, dst)%0A      shutil.copytree(src, dst)%0A    except (shutil.Error, OSError) as e:%0A      raise ActionError('Unable to copy %25s to %25s: %25s' %25 (src, dst, str(e)))%0A%0A  def Validate(self):%0A    self._ListOfStringsValidator(self._args, length=2
+if os.path.exists(dst) and remove_existing:%0A        logging.info('Deleting existing destination: %25s', dst)%0A        shutil.rmtree(dst)%0A    except (shutil.Error, OSError) as e:%0A      raise ActionError('Unable to delete existing destination folder %25s: %25s' %25%0A                        (dst, str(e)))%0A    try:%0A      logging.info('Copying directory: %25s to %25s', src, dst)%0A      shutil.copytree(src, dst)%0A    except (shutil.Error, OSError) as e:%0A      raise ActionError('Unable to copy %25s to %25s: %25s' %25 (src, dst, str(e)))%0A%0A  def Validate(self):%0A    self._TypeValidator(self._args, list)%0A    if not 2 %3C= len(self._args) %3C= 3:%0A      raise ValidationError('Invalid args length: %25s' %25 self._args)%0A    self._TypeValidator(self._args%5B0%5D, str)  # src%0A    self._TypeValidator(self._args%5B1%5D, str)  # dst%0A    if len(self._args) %3E 2:  # Remove existing folder%0A      self._TypeValidator(self._args%5B2%5D, bool
 )%0A%0A%0A

Add argument to allow deleting the destination folder if it already exists when running CopyDir action.