# Path: alibuild_helpers/workarea.py
# def updateReferenceRepo(referenceSources, p, spec, fetch=True, usePartialClone=True):
#   """
#   Update source reference area, if possible.
#   If the area is already there and cannot be written, assume it maintained
#   by someone else.
# 
#   If the area can be created, clone a bare repository with the sources.
# 
#   Returns the reference repository's local path if available, otherwise None.
#   Throws a fatal error in case repository cannot be updated even if it appears
#   to be writeable.
# 
#   @referenceSources : a string containing the path to the sources to be updated
#   @p                : the name of the package to be updated
#   @spec             : the spec of the package to be updated (an OrderedDict)
#   @fetch            : whether to fetch updates: if False, only clone if not found
#   """
#   assert(type(spec) == OrderedDict)
#   if not "source" in spec:
#     return
# 
#   debug("Updating references.")
#   referenceRepo = os.path.join(abspath(referenceSources), p.lower())
# 
#   try:
#     os.makedirs(abspath(referenceSources))
#   except:
#     pass
# 
#   if not is_writeable(referenceSources):
#     if path.exists(referenceRepo):
#       debug("Using %s as reference for %s", referenceRepo, p)
#       return referenceRepo  # reference is read-only
#     else:
#       debug("Cannot create reference for %s in %s", p, referenceSources)
#       return None  # no reference can be found and created (not fatal)
# 
#   err = False
#   logPath = os.path.join(dirname(referenceRepo), "fetch-log.txt")
#   if not path.exists(referenceRepo):
#     cmd = ["git", "clone"] + (usePartialClone and [partialCloneFilter] or []) + ["--bare", spec["source"], referenceRepo]
#     cmd = [x for x in cmd if x]
#     debug("Cloning reference repository: %s", " ".join(cmd))
#     err = execute(cmd)
#   elif fetch:
#     cmd = format("cd %(referenceRepo)s && "
#                  "git fetch -f --tags %(source)s >%(logPath)s 2>&1 && "
#                  "git fetch -f %(source)s '+refs/heads/*:refs/heads/*' >>%(logPath)s 2>&1",
#                  referenceRepo=referenceRepo,
#                  source=spec["source"],
#                  logPath=logPath)
#     debug("Updating reference repository: %s", cmd)
#     err = execute(cmd)
#   if os.path.exists(logPath):
#     execute("cat " + logPath)
#   dieOnError(err, "Error while updating reference repos %s." % spec["source"])
#   return referenceRepo  # reference is read-write
# 
# def updateReferenceRepoSpec(referenceSources, p, spec, fetch, usePartialClone=True):
#   """
#   Update source reference area whenever possible, and set the spec's "reference"
#   if available for reading.
# 
#   @referenceSources : a string containing the path to the sources to be updated
#   @p                : the name of the package to be updated
#   @spec             : the spec of the package to be updated (an OrderedDict)
#   @fetch            : whether to fetch updates: if False, only clone if not found
#   """
#   spec["reference"] = updateReferenceRepo(referenceSources, p, spec, fetch, usePartialClone)
#   if not spec["reference"]:
#     del spec["reference"]


    from unittest import mock
    from unittest.mock import patch, call, MagicMock  # In Python 3, mock is built-in
    from mock import patch, call, MagicMock  # Python 2
  from collections import OrderedDict
  from ordereddict import OrderedDict
from alibuild_helpers.workarea import updateReferenceRepo, updateReferenceRepoSpec
from os.path import abspath, join
from os import getcwd
    import mock
import re
import unittest
      mock_os.makedirs.reset_mock()
      mock_git_clone.reset_mock()
      mock_git_fetch.reset_mock()
      updateReferenceRepoSpec(referenceSources=referenceSources, p="AliRoot", spec=spec, fetch=True)
      mock_os.makedirs.assert_called_with('%s/sw/MIRROR' % getcwd())
      self.assertEqual(mock_git_fetch.call_count, 0, "Expected no calls to git fetch (called %d times instead)" % mock_git_fetch.call_count)
      self.assertEqual(mock_git_clone.call_count, 0, "Expected no calls to git clone (called %d times instead)" % mock_git_clone.call_count)
      self.assertEqual(spec.get("reference"), reference)
      self.assertEqual(True, call('Updating references.') in mock_debug.mock_calls)

    @mock.patch("alibuild_helpers.workarea.execute")
    @mock.patch("alibuild_helpers.workarea.path")
    @mock.patch("alibuild_helpers.workarea.debug")
    @mock.patch("alibuild_helpers.workarea.os")
    @mock.patch("alibuild_helpers.workarea.is_writeable")
    def test_referenceSourceExistsWriteable(self, mock_is_writeable, mock_os, mock_debug, mock_path, mock_execute):
      # Reference sources exists and can be written
      # The reference repo is set nevertheless but not updated
      mock_path.exists.side_effect = lambda x: True
      mock_is_writeable.side_effect = lambda x: True
      mock_os.path.join.side_effect = join
      mock_git_clone = MagicMock(return_value=None)
      mock_git_fetch = MagicMock(return_value=None)
      mock_execute.side_effect = lambda x, **k: allow_git_clone(x, mock_git_clone, mock_git_fetch, *k)
      spec = OrderedDict({"source": "https://github.com/alisw/AliRoot"})
      referenceSources = "sw/MIRROR"
      reference = abspath(referenceSources) + "/aliroot"
      mock_os.makedirs.reset_mock()
      mock_git_clone.reset_mock()
      mock_git_fetch.reset_mock()

# Path: alibuild_helpers/workarea.py
# def updateReferenceRepo(referenceSources, p, spec, fetch=True, usePartialClone=True):
#   """
#   Update source reference area, if possible.
#   If the area is already there and cannot be written, assume it maintained
#   by someone else.
# 
#   If the area can be created, clone a bare repository with the sources.
# 
#   Returns the reference repository's local path if available, otherwise None.
#   Throws a fatal error in case repository cannot be updated even if it appears
#   to be writeable.
# 
#   @referenceSources : a string containing the path to the sources to be updated
#   @p                : the name of the package to be updated
#   @spec             : the spec of the package to be updated (an OrderedDict)
#   @fetch            : whether to fetch updates: if False, only clone if not found
#   """
#   assert(type(spec) == OrderedDict)
#   if not "source" in spec:
#     return
# 
#   debug("Updating references.")
#   referenceRepo = os.path.join(abspath(referenceSources), p.lower())
# 
#   try:
#     os.makedirs(abspath(referenceSources))
#   except:
#     pass
# 
#   if not is_writeable(referenceSources):
#     if path.exists(referenceRepo):
#       debug("Using %s as reference for %s", referenceRepo, p)
#       return referenceRepo  # reference is read-only
#     else:
#       debug("Cannot create reference for %s in %s", p, referenceSources)
#       return None  # no reference can be found and created (not fatal)
# 
#   err = False
#   logPath = os.path.join(dirname(referenceRepo), "fetch-log.txt")
#   if not path.exists(referenceRepo):
#     cmd = ["git", "clone"] + (usePartialClone and [partialCloneFilter] or []) + ["--bare", spec["source"], referenceRepo]
#     cmd = [x for x in cmd if x]
#     debug("Cloning reference repository: %s", " ".join(cmd))
#     err = execute(cmd)
#   elif fetch:
#     cmd = format("cd %(referenceRepo)s && "
#                  "git fetch -f --tags %(source)s >%(logPath)s 2>&1 && "
#                  "git fetch -f %(source)s '+refs/heads/*:refs/heads/*' >>%(logPath)s 2>&1",
#                  referenceRepo=referenceRepo,
#                  source=spec["source"],
#                  logPath=logPath)
#     debug("Updating reference repository: %s", cmd)
#     err = execute(cmd)
#   if os.path.exists(logPath):
#     execute("cat " + logPath)
#   dieOnError(err, "Error while updating reference repos %s." % spec["source"])
#   return referenceRepo  # reference is read-write
# 
# def updateReferenceRepoSpec(referenceSources, p, spec, fetch, usePartialClone=True):
#   """
#   Update source reference area whenever possible, and set the spec's "reference"
#   if available for reading.
# 
#   @referenceSources : a string containing the path to the sources to be updated
#   @p                : the name of the package to be updated
#   @spec             : the spec of the package to be updated (an OrderedDict)
#   @fetch            : whether to fetch updates: if False, only clone if not found
#   """
#   spec["reference"] = updateReferenceRepo(referenceSources, p, spec, fetch, usePartialClone)
#   if not spec["reference"]:
#     del spec["reference"]


# Path: tests/test_workarea.py
    from unittest import mock
    from unittest.mock import patch, call, MagicMock  # In Python 3, mock is built-in
    from mock import patch, call, MagicMock  # Python 2
  from collections import OrderedDict
  from ordereddict import OrderedDict
from alibuild_helpers.workarea import updateReferenceRepo, updateReferenceRepoSpec
from os.path import abspath, join
from os import getcwd
    import mock
import re
import unittest

      mock_os.makedirs.reset_mock()
      mock_git_clone.reset_mock()
      mock_git_fetch.reset_mock()
      updateReferenceRepoSpec(referenceSources=referenceSources, p="AliRoot", spec=spec, fetch=True)
      mock_os.makedirs.assert_called_with('%s/sw/MIRROR' % getcwd())
      self.assertEqual(mock_git_fetch.call_count, 0, "Expected no calls to git fetch (called %d times instead)" % mock_git_fetch.call_count)
      self.assertEqual(mock_git_clone.call_count, 0, "Expected no calls to git clone (called %d times instead)" % mock_git_clone.call_count)
      self.assertEqual(spec.get("reference"), reference)
      self.assertEqual(True, call('Updating references.') in mock_debug.mock_calls)

    @mock.patch("alibuild_helpers.workarea.execute")
    @mock.patch("alibuild_helpers.workarea.path")
    @mock.patch("alibuild_helpers.workarea.debug")
    @mock.patch("alibuild_helpers.workarea.os")
    @mock.patch("alibuild_helpers.workarea.is_writeable")
    def test_referenceSourceExistsWriteable(self, mock_is_writeable, mock_os, mock_debug, mock_path, mock_execute):
      # Reference sources exists and can be written
      # The reference repo is set nevertheless but not updated
      mock_path.exists.side_effect = lambda x: True
      mock_is_writeable.side_effect = lambda x: True
      mock_os.path.join.side_effect = join
      mock_git_clone = MagicMock(return_value=None)
      mock_git_fetch = MagicMock(return_value=None)
      mock_execute.side_effect = lambda x, **k: allow_git_clone(x, mock_git_clone, mock_git_fetch, *k)
      spec = OrderedDict({"source": "https://github.com/alisw/AliRoot"})
      referenceSources = "sw/MIRROR"
      reference = abspath(referenceSources) + "/aliroot"
      mock_os.makedirs.reset_mock()
      mock_git_clone.reset_mock()
      mock_git_fetch.reset_mock()

      updateReferenceRepoSpec(referenceSources=referenceSources, p="AliRoot", spec=spec, fetch=True)