bool DirectoryUtilities::copyDirectory(const QString &sourceDirectoryPath, const QString &destinationDirectoryPath)
{
    QDir sourceDirectory(sourceDirectoryPath), destinationDirectory(destinationDirectoryPath);
    QStringList files, directories;

    if (!sourceDirectory.exists())
    {
        ERROR_LOG(QString("El directori origen %1 no existeix").arg(sourceDirectoryPath));
        return false;
    }

    if (!destinationDirectory.exists())
    {
        if (!destinationDirectory.mkdir(destinationDirectoryPath))
        {
            ERROR_LOG("No s'ha pogut crear el directori " + destinationDirectoryPath);
            return false;
        }
    }

    // Copiem els fitxers del directori
    files = sourceDirectory.entryList(QDir::Files);
    for (int i = 0; i < files.count(); i++)
    {
        QString sourceFile = sourceDirectoryPath + QDir::separator() + files[i];
        QString destinationFile = destinationDirectoryPath + QDir::separator() + files[i];

        if (!QFile::copy(sourceFile, destinationFile))
        {
            ERROR_LOG(QString("No s'ha pogut copiar l'arxiu %1 al seu destí %2").arg(sourceFile, destinationFile));
            return false;
        }
    }

    // Copiem els subdirectoris
    directories = sourceDirectory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
    for (int i = 0; i < directories.count(); i++)
    {
        QString sourceSubDirectory = sourceDirectoryPath + QDir::separator() + directories[i];
        QString destinationSubDirectory = destinationDirectoryPath + QDir::separator() + directories[i];
        if (!copyDirectory(sourceSubDirectory, destinationSubDirectory))
        {
            return false;
        }
    }

    return true;
}
ofPackage ofPackageManager::installPackageByUrl(std::string url, std::string checkout, std::string destinationPath)
{
	if (destinationPath.empty())
	{
		destinationPath = _configJson["localAddonsPath"];
	}
	destinationPath = getAbsolutePath(destinationPath);
	auto name = ofSplitString(url, "/").back();
	// TODO: check if url ends with .git
	name = name.substr(0, name.size() - 4);

	ofDirectory destinationDirectory(destinationPath);
	auto repoPath = ofFilePath::join(destinationPath, name);
	ofDirectory repoDirectory(repoPath);
	ofxGit::repository repo(ofFilePath::join(destinationPath, name));
	if (destinationDirectory.exists())
	{
		if (repoDirectory.exists())
		{
			if (getBoolAnswer(destinationPath + "/" + name + " already exists. Do you want to pull and checkout the specified commit?", true))
			{
				ofLogNotice("TODO") << "Unfortunately it is not yet implemented due to missing ofxGit::repo::pull";
				// TODO: pull and checkout, pull still does not work in ofxGit2
			}
		}
		else
		{
			if (repo.clone(url))
			{
				ofLogNotice("install") << "Successfully cloned repo" << url;
			}
			if (checkout != "latest")
			{
				// checkout the version
				repo.checkout(checkout);
			}
			else
			{
				// get commit hash
				checkout = repo.getCommitHash();
			}
		}
	}
	else
	{
		destinationDirectory.create();
		if (repo.clone(url))
		{
			ofLogNotice("install") << "Successfully cloned repo" << url;
		}
		if (checkout != "latest")
		{
			// checkout the version
			repo.checkout(checkout);
		}
		else
		{
			// get commit hash
			checkout = repo.getCommitHash();
		}
	}

	if (hasAddonsConfigFile(ofFilePath::join(destinationPath, name)))
	{
		installDependenciesFromAddonConfig(ofFilePath::join(destinationPath, name), destinationPath);
	}

	return ofPackage(ofFilePath::join(ofFilePath::makeRelative(_cwdPath, destinationPath), name), url, checkout);
}