<commit_before>package uk.co.cacoethes.lazybones.commands

import groovy.util.logging.Log
import joptsimple.OptionParser
import joptsimple.OptionSet
import uk.co.cacoethes.lazybones.LazybonesScriptException
import uk.co.cacoethes.lazybones.NoVersionsFoundException
import uk.co.cacoethes.lazybones.PackageNotFoundException
import uk.co.cacoethes.lazybones.packagesources.PackageSource
import uk.co.cacoethes.lazybones.packagesources.PackageSourceBuilder
import uk.co.cacoethes.lazybones.scm.GitAdapter
import uk.co.cacoethes.util.ArchiveMethods
import wslite.http.HTTPClientException

import java.util.logging.Level

/**
 * Implements Lazybone's create command, which creates a new project based on
 * a specified template.
 */
@Log
class CreateCommand extends AbstractCommand {
    final PackageSourceBuilder packageSourceFactory
    final PackageLocationBuilder packageLocationFactory
    final PackageDownloader packageDownloader
    final Map mappings

    static final String USAGE = """\
USAGE: create <template> <version>? <dir>

  where  template = The name of the project template to use.
         version  = (optional) The version of the project template to use. Uses
                    the latest version of the template by default.
         dir      = The name of the directory in which to create the project
                    structure. This can be '.' to mean 'in the current
                    directory.'
"""
    private static final String README_BASENAME = "README"
    private static final String SPACES_OPT = "spaces"
    private static final String VAR_OPT = "P"
    private static final String GIT_OPT = "with-git"

    CreateCommand(ConfigObject config) {
        this(config.cache.dir as File)
        assert config.cache.dir
        mappings = config.templates.mappings
    }

    CreateCommand(File cacheDir) {
        packageSourceFactory = new PackageSourceBuilder()
        packageLocationFactory = new PackageLocationBuilder(cacheDir)
        packageDownloader = new PackageDownloader()
    }

    @Override
    String getName() { return "create" }

    @Override
    String getDescription() {
        return "Creates a new project from a template."
    }

    @Override
    protected OptionParser doAddToParser(OptionParser parser) {
        parser.accepts(SPACES_OPT, "Sets the number of spaces to use for indent in files.").withRequiredArg()
        parser.accepts(VAR_OPT, "Add a substitution variable for file filtering.").withRequiredArg()
        parser.accepts(GIT_OPT, "Creates a git repository in the new project.")
        return parser
    }

    @Override
    protected IntRange getParameterRange() {
        2..3  // Either a directory or a version + a directory
    }

    @Override
    protected String getUsage() { return USAGE }

    protected int doExecute(OptionSet cmdOptions, Map globalOptions, ConfigObject configuration) {
        try {
            def createData = evaluateArgs(cmdOptions)

            List<PackageSource> packageSources = packageSourceFactory.buildPackageSourceList(configuration)
            PackageLocation packageLocation = packageLocationFactory.buildPackageLocation(
                    createData.packageArg.templateName,
                    createData.requestedVersion,
                    packageSources)
            File pkg = packageDownloader.downloadPackage(
                    packageLocation,
                    createData.packageArg.templateName,
                    createData.requestedVersion)

            def targetDir = createData.targetDir.canonicalFile
            targetDir.mkdirs()
            ArchiveMethods.unzip(pkg, targetDir)

            def scmAdapter = null
            if (cmdOptions.has(GIT_OPT)) scmAdapter = new GitAdapter(configuration)

            def executor = new InstallationScriptExecuter(scmAdapter)
            executor.runPostInstallScriptWithArgs(
                    cmdOptions.valuesOf(VAR_OPT).collectEntries { String it -> it.split('=') as List },
                    createData.packageArg.qualifiers,
                    targetDir)

            logReadme(createData)

            logSuccess(createData)

            return 0
        }
        catch (PackageNotFoundException ex) {
            if (ex.version) {
                log.severe "Cannot find version ${ex.version} of template '${ex.name}'. Project has not been created."
            }
            else {
                log.severe "Cannot find a template named '${ex.name}'. Project has not been created."
            }
            return 1
        }
        catch (NoVersionsFoundException ex) {
            log.severe "No version of '${ex.packageName}' has been published"
            return 1
        }
        catch (HTTPClientException ex) {
            if (OfflineMode.isOffline(ex)) {
                OfflineMode.printlnOfflineMessage(ex, log, globalOptions.stacktrace as boolean)
            }<commit_msg>Tell user of potential Bintray metadata error.<commit_after>package uk.co.cacoethes.lazybones.commands

import groovy.util.logging.Log
import joptsimple.OptionParser
import joptsimple.OptionSet
import uk.co.cacoethes.lazybones.LazybonesScriptException
import uk.co.cacoethes.lazybones.NoVersionsFoundException
import uk.co.cacoethes.lazybones.PackageNotFoundException
import uk.co.cacoethes.lazybones.packagesources.PackageSource
import uk.co.cacoethes.lazybones.packagesources.PackageSourceBuilder
import uk.co.cacoethes.lazybones.scm.GitAdapter
import uk.co.cacoethes.util.ArchiveMethods
import wslite.http.HTTPClientException

import java.util.logging.Level

/**
 * Implements Lazybone's create command, which creates a new project based on
 * a specified template.
 */
@Log
class CreateCommand extends AbstractCommand {
    final PackageSourceBuilder packageSourceFactory
    final PackageLocationBuilder packageLocationFactory
    final PackageDownloader packageDownloader
    final Map mappings

    static final String USAGE = """\
USAGE: create <template> <version>? <dir>

  where  template = The name of the project template to use.
         version  = (optional) The version of the project template to use. Uses
                    the latest version of the template by default.
         dir      = The name of the directory in which to create the project
                    structure. This can be '.' to mean 'in the current
                    directory.'
"""
    private static final String README_BASENAME = "README"
    private static final String SPACES_OPT = "spaces"
    private static final String VAR_OPT = "P"
    private static final String GIT_OPT = "with-git"

    CreateCommand(ConfigObject config) {
        this(config.cache.dir as File)
        assert config.cache.dir
        mappings = config.templates.mappings
    }

    CreateCommand(File cacheDir) {
        packageSourceFactory = new PackageSourceBuilder()
        packageLocationFactory = new PackageLocationBuilder(cacheDir)
        packageDownloader = new PackageDownloader()
    }

    @Override
    String getName() { return "create" }

    @Override
    String getDescription() {
        return "Creates a new project from a template."
    }

    @Override
    protected OptionParser doAddToParser(OptionParser parser) {
        parser.accepts(SPACES_OPT, "Sets the number of spaces to use for indent in files.").withRequiredArg()
        parser.accepts(VAR_OPT, "Add a substitution variable for file filtering.").withRequiredArg()
        parser.accepts(GIT_OPT, "Creates a git repository in the new project.")
        return parser
    }

    @Override
    protected IntRange getParameterRange() {
        2..3  // Either a directory or a version + a directory
    }

    @Override
    protected String getUsage() { return USAGE }

    protected int doExecute(OptionSet cmdOptions, Map globalOptions, ConfigObject configuration) {
        try {
            def createData = evaluateArgs(cmdOptions)

            List<PackageSource> packageSources = packageSourceFactory.buildPackageSourceList(configuration)
            PackageLocation packageLocation = packageLocationFactory.buildPackageLocation(
                    createData.packageArg.templateName,
                    createData.requestedVersion,
                    packageSources)
            File pkg = packageDownloader.downloadPackage(
                    packageLocation,
                    createData.packageArg.templateName,
                    createData.requestedVersion)

            def targetDir = createData.targetDir.canonicalFile
            targetDir.mkdirs()
            ArchiveMethods.unzip(pkg, targetDir)

            def scmAdapter = null
            if (cmdOptions.has(GIT_OPT)) scmAdapter = new GitAdapter(configuration)

            def executor = new InstallationScriptExecuter(scmAdapter)
            executor.runPostInstallScriptWithArgs(
                    cmdOptions.valuesOf(VAR_OPT).collectEntries { String it -> it.split('=') as List },
                    createData.packageArg.qualifiers,
                    targetDir)

            logReadme(createData)

            logSuccess(createData)

            return 0
        }
        catch (PackageNotFoundException ex) {
            if (ex.version) {
                log.severe "Cannot find version ${ex.version} of template '${ex.name}'. Project has not been created."
            }
            else {
                log.severe "Cannot find a template named '${ex.name}'. Project has not been created."
            }
            return 1
        }
        catch (NoVersionsFoundException ex) {
            log.severe "No version of '${ex.packageName}' has been published. This can also happen if " +
                    "the latest version on Bintray is 'null'."
            return 1
        }
        catch (HTTPClientException ex) {
            if (OfflineMode.isOffline(ex)) {
                OfflineMode.printlnOfflineMessage(ex, log, globalOptions.stacktrace as boolean)
            }
{'fraction_non_alphanumeric': 0.06906967378171566, 'fraction_numerical': 0.0010068465565847766, 'mean_word_length': 2.512376237623762, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5741578', 'n_tokens_mistral': 2576, 'n_tokens_neox': 2446, 'n_words': 714}