# Path: alibuild_helpers/clean.py
# def decideClean(workDir, architecture, aggressiveCleanup):
#   """ Decides what to delete, without actually doing it:
#       - Find all the symlinks in "BUILD"
#       - Find all the directories in "BUILD"
#       - Schedule a directory for deletion if it does not have a symlink
#   """
#   symlinksBuild = [os.readlink(x) for x in glob.glob("%s/BUILD/*-latest*" % workDir)]
#   # $WORK_DIR/TMP should always be cleaned up. This does not happen only
#   # in the case we run out of space while unpacking. INSTALLROOT is similar,
#   # though it is not cleaned up automatically in case of build errors.
#   # $WORK_DIR/<architecture>/store can be cleaned up as well, because
#   # we do not need the actual tarballs after they have been built.
#   toDelete = ["%s/TMP" % workDir, "%s/INSTALLROOT" % workDir]
#   if aggressiveCleanup:
#     toDelete += ["%s/TARS/%s/store" % (workDir, architecture),
#                  "%s/SOURCES" % (workDir)]
#   allBuildStuff = glob.glob("%s/BUILD/*" % workDir)
#   toDelete += [x for x in allBuildStuff
#                if not path.islink(x) and not basename(x) in symlinksBuild]
#   installGlob ="%s/%s/*/" % (workDir, architecture)
#   installedPackages = set([dirname(x) for x in glob.glob(installGlob)])
#   symlinksInstall = []
#   for x in installedPackages:
#     symlinksInstall += [path.realpath(y) for y in glob.glob(x + "/latest*")]
#   toDelete += [x for x in glob.glob(installGlob+ "*")
#                if not path.islink(x) and not path.realpath(x) in symlinksInstall]
#   toDelete = [x for x in toDelete if path.exists(x)]
#   return toDelete
# 
# def doClean(workDir, architecture, aggressiveCleanup, dryRun):
#   """ CLI API to cleanup build area """
#   toDelete = decideClean(workDir, architecture, aggressiveCleanup)
#   if not toDelete:
#     print_results("Nothing to delete.")
#     sys.exit(0)
#   finalMessage = "This will delete the following directories:\n\n" + "\n".join(toDelete)
# 
#   if dryRun:
#     finalMessage += "\n\n--dry-run / -n specified. Doing nothing."
#     print_results(finalMessage)
#     sys.exit(0)
# 
#   print_results(finalMessage)
#   for x in toDelete:
#     try:
#       shutil.rmtree(x)
#     except OSError:
#       print_results("Unable to delete %s." % x)
#       sys.exit(1)
#   sys.exit(0)


from textwrap import dedent
    from unittest.mock import patch, call  # In Python 3, mock is built-in
    from mock import patch, call  # Python 2
from alibuild_helpers.clean import decideClean, doClean
import unittest
                              "sw/osx_x86-64/b/latest-root6"],
  "sw/osx_x86-64/a/latest*": ["sw/osx_x86-64/a/latest", "sw/osx_x86-64/a/latest-release"],
  "sw/osx_x86-64/*/*": ["sw/osx_x86-64/a/latest", "sw/osx_x86-64/a/v1",
                        "sw/osx_x86-64/b/latest", "sw/osx_x86-64/b/v1",
                        "sw/osx_x86-64/b/v2", "sw/osx_x86-64/b/v3",
                        "sw/osx_x86-64/b/v4"],
  "sw/slc7_x86-64/*/": [],
  "sw/slc7_x86-64/*/*": []
}

READLINK_MOCKUP_DB = {
  "sw/BUILD/a-latest": "f339115741c6ab9cf291d3210f44bee795c56e16",
  "sw/BUILD/b-latest": "fcdfc2e1c9f0433c60b3b000e0e2737d297a9b1c"
}

class CleanTestCase(unittest.TestCase):
    @patch('alibuild_helpers.clean.glob')
    @patch('alibuild_helpers.clean.os')
    @patch('alibuild_helpers.clean.path')
    def test_decideClean(self, mock_path, mock_os, mock_glob):
        mock_path.realpath.side_effect = lambda x : REALPATH_WITH_OBSOLETE_FILES[x]
        mock_path.islink.side_effect = lambda x : "latest" in x
        mock_glob.glob.side_effect = lambda x : GLOB_WITH_OBSOLETE_FILES[x]
        mock_os.readlink.side_effect = lambda x : READLINK_MOCKUP_DB[x]
        toDelete = decideClean(workDir="sw", architecture="osx_x86-64", aggressiveCleanup=False)
        mock_os.readlink.assert_called_with("sw/BUILD/b-latest")
        mock_path.islink.assert_called_with("sw/osx_x86-64/b/v4")
        mock_path.exists.assert_called_with("sw/osx_x86-64/b/v3")
        self.assertEqual(toDelete, ['sw/TMP', 'sw/INSTALLROOT', 'sw/BUILD/somethingtodelete',
                                    'sw/osx_x86-64/b/v1', 'sw/osx_x86-64/b/v3'])

# Path: alibuild_helpers/clean.py
# def decideClean(workDir, architecture, aggressiveCleanup):
#   """ Decides what to delete, without actually doing it:
#       - Find all the symlinks in "BUILD"
#       - Find all the directories in "BUILD"
#       - Schedule a directory for deletion if it does not have a symlink
#   """
#   symlinksBuild = [os.readlink(x) for x in glob.glob("%s/BUILD/*-latest*" % workDir)]
#   # $WORK_DIR/TMP should always be cleaned up. This does not happen only
#   # in the case we run out of space while unpacking. INSTALLROOT is similar,
#   # though it is not cleaned up automatically in case of build errors.
#   # $WORK_DIR/<architecture>/store can be cleaned up as well, because
#   # we do not need the actual tarballs after they have been built.
#   toDelete = ["%s/TMP" % workDir, "%s/INSTALLROOT" % workDir]
#   if aggressiveCleanup:
#     toDelete += ["%s/TARS/%s/store" % (workDir, architecture),
#                  "%s/SOURCES" % (workDir)]
#   allBuildStuff = glob.glob("%s/BUILD/*" % workDir)
#   toDelete += [x for x in allBuildStuff
#                if not path.islink(x) and not basename(x) in symlinksBuild]
#   installGlob ="%s/%s/*/" % (workDir, architecture)
#   installedPackages = set([dirname(x) for x in glob.glob(installGlob)])
#   symlinksInstall = []
#   for x in installedPackages:
#     symlinksInstall += [path.realpath(y) for y in glob.glob(x + "/latest*")]
#   toDelete += [x for x in glob.glob(installGlob+ "*")
#                if not path.islink(x) and not path.realpath(x) in symlinksInstall]
#   toDelete = [x for x in toDelete if path.exists(x)]
#   return toDelete
# 
# def doClean(workDir, architecture, aggressiveCleanup, dryRun):
#   """ CLI API to cleanup build area """
#   toDelete = decideClean(workDir, architecture, aggressiveCleanup)
#   if not toDelete:
#     print_results("Nothing to delete.")
#     sys.exit(0)
#   finalMessage = "This will delete the following directories:\n\n" + "\n".join(toDelete)
# 
#   if dryRun:
#     finalMessage += "\n\n--dry-run / -n specified. Doing nothing."
#     print_results(finalMessage)
#     sys.exit(0)
# 
#   print_results(finalMessage)
#   for x in toDelete:
#     try:
#       shutil.rmtree(x)
#     except OSError:
#       print_results("Unable to delete %s." % x)
#       sys.exit(1)
#   sys.exit(0)


# Path: tests/test_clean.py
from textwrap import dedent
    from unittest.mock import patch, call  # In Python 3, mock is built-in
    from mock import patch, call  # Python 2
from alibuild_helpers.clean import decideClean, doClean
import unittest

                              "sw/osx_x86-64/b/latest-root6"],
  "sw/osx_x86-64/a/latest*": ["sw/osx_x86-64/a/latest", "sw/osx_x86-64/a/latest-release"],
  "sw/osx_x86-64/*/*": ["sw/osx_x86-64/a/latest", "sw/osx_x86-64/a/v1",
                        "sw/osx_x86-64/b/latest", "sw/osx_x86-64/b/v1",
                        "sw/osx_x86-64/b/v2", "sw/osx_x86-64/b/v3",
                        "sw/osx_x86-64/b/v4"],
  "sw/slc7_x86-64/*/": [],
  "sw/slc7_x86-64/*/*": []
}

READLINK_MOCKUP_DB = {
  "sw/BUILD/a-latest": "f339115741c6ab9cf291d3210f44bee795c56e16",
  "sw/BUILD/b-latest": "fcdfc2e1c9f0433c60b3b000e0e2737d297a9b1c"
}

class CleanTestCase(unittest.TestCase):
    @patch('alibuild_helpers.clean.glob')
    @patch('alibuild_helpers.clean.os')
    @patch('alibuild_helpers.clean.path')
    def test_decideClean(self, mock_path, mock_os, mock_glob):
        mock_path.realpath.side_effect = lambda x : REALPATH_WITH_OBSOLETE_FILES[x]
        mock_path.islink.side_effect = lambda x : "latest" in x
        mock_glob.glob.side_effect = lambda x : GLOB_WITH_OBSOLETE_FILES[x]
        mock_os.readlink.side_effect = lambda x : READLINK_MOCKUP_DB[x]
        toDelete = decideClean(workDir="sw", architecture="osx_x86-64", aggressiveCleanup=False)
        mock_os.readlink.assert_called_with("sw/BUILD/b-latest")
        mock_path.islink.assert_called_with("sw/osx_x86-64/b/v4")
        mock_path.exists.assert_called_with("sw/osx_x86-64/b/v3")
        self.assertEqual(toDelete, ['sw/TMP', 'sw/INSTALLROOT', 'sw/BUILD/somethingtodelete',
                                    'sw/osx_x86-64/b/v1', 'sw/osx_x86-64/b/v3'])

        toDelete = decideClean(workDir="sw", architecture="osx_x86-64", aggressiveCleanup=True)