<commit_before>//
// SwiftGen
// Copyright © 2019 SwiftGen
// MIT Licence
//

import Commander
import PathKit
import StencilSwiftKit
import SwiftGenKit

extension ConfigEntryOutput {
  func checkPaths() throws {
    guard self.output.parent().exists else {
      throw Config.Error.pathNotFound(path: self.output.parent())
    }
  }
}

extension ConfigEntry {
  func checkPaths() throws {
    for inputPath in self.inputs {
      guard inputPath.exists else {
        throw Config.Error.pathNotFound(path: inputPath)
      }
    }
    for output in outputs {
      try output.checkPaths()
    }
  }

  func run(parserCommand: ParserCLI) throws {
    let parser = try parserCommand.parserType.init(options: [:]) { msg, _, _ in
      logMessage(.warning, msg)
    }
    let filter = try Filter(pattern: self.filter ?? parserCommand.parserType.defaultFilter)
    try parser.searchAndParse(paths: inputs, filter: filter)
    let context = parser.stencilContext()

    for entryOutput in outputs {
      let templateRealPath = try entryOutput.template.resolvePath(forSubcommand: parserCommand.name)
      let template = try StencilSwiftTemplate(
        templateString: templateRealPath.read(),
        environment: stencilSwiftEnvironment()
      )

      let enriched = try StencilContext.enrich(context: context, parameters: entryOutput.parameters)
      let rendered = try template.render(enriched)
      let output = OutputDestination.file(entryOutput.output)
      try output.write(content: rendered, onlyIfChanged: true)
    }
  }
}

// MARK: - Commands

enum ConfigCLI {
  private enum CLIOption {
    static let config = Option<Path>(
      "config",
      default: "swiftgen.yml",
      flag: "c",
      description: "Path to the configuration file to use",
      validator: checkPath(type: "config file") { $0.isFile }
    )
  }

  // MARK: Lint

  static let lint = command(
    CLIOption.config
  ) { file in
    try ErrorPrettifier.execute {
      logMessage(.info, "Linting \(file)")
      let config = try Config(file: file)
      config.lint()
    }
  }

  // MARK: Run

  static let run = command(
    CLIOption.config,
    Flag("verbose", default: false, flag: "v", description: "Print each command being executed")
  ) { file, verbose in
    do {
      try ErrorPrettifier.execute {
        let config = try Config(file: file)

        if verbose {
          logMessage(.info, "Executing configuration file \(file)")
        }
        try file.parent().chdir {
          for (cmd, entries) in config.commands {
            for var entry in entries {
              guard let parserCmd = ParserCLI.command(named: cmd) else {
                throw Config.Error.missingEntry(key: cmd)
              }
              entry.makingRelativeTo(inputDir: config.inputDir, outputDir: config.outputDir)
              if verbose {
                for item in entry.commandLine(forCommand: cmd) {
                  logMessage(.info, " $ \(item)")
                }
              }
              try entry.checkPaths()
              try entry.run(parserCommand: parserCmd)
            }
          }
        }
      }
    } catch let error as Config.Error {
      logMessage(.error, error)
    }
  }
}<commit_msg>Add a help message if there's an error<commit_after>//
// SwiftGen
// Copyright © 2019 SwiftGen
// MIT Licence
//

import Commander
import PathKit
import StencilSwiftKit
import SwiftGenKit

extension ConfigEntryOutput {
  func checkPaths() throws {
    guard self.output.parent().exists else {
      throw Config.Error.pathNotFound(path: self.output.parent())
    }
  }
}

extension ConfigEntry {
  func checkPaths() throws {
    for inputPath in self.inputs {
      guard inputPath.exists else {
        throw Config.Error.pathNotFound(path: inputPath)
      }
    }
    for output in outputs {
      try output.checkPaths()
    }
  }

  func run(parserCommand: ParserCLI) throws {
    let parser = try parserCommand.parserType.init(options: [:]) { msg, _, _ in
      logMessage(.warning, msg)
    }
    let filter = try Filter(pattern: self.filter ?? parserCommand.parserType.defaultFilter)
    try parser.searchAndParse(paths: inputs, filter: filter)
    let context = parser.stencilContext()

    for entryOutput in outputs {
      let templateRealPath = try entryOutput.template.resolvePath(forSubcommand: parserCommand.name)
      let template = try StencilSwiftTemplate(
        templateString: templateRealPath.read(),
        environment: stencilSwiftEnvironment()
      )

      let enriched = try StencilContext.enrich(context: context, parameters: entryOutput.parameters)
      let rendered = try template.render(enriched)
      let output = OutputDestination.file(entryOutput.output)
      try output.write(content: rendered, onlyIfChanged: true)
    }
  }
}

// MARK: - Commands

enum ConfigCLI {
  private enum CLIOption {
    static let config = Option<Path>(
      "config",
      default: "swiftgen.yml",
      flag: "c",
      description: "Path to the configuration file to use",
      validator: checkPath(type: "config file") { $0.isFile }
    )
  }

  // MARK: Lint

  static let lint = command(
    CLIOption.config
  ) { file in
    try ErrorPrettifier.execute {
      logMessage(.info, "Linting \(file)")
      let config = try Config(file: file)
      config.lint()
    }
  }

  // MARK: Run

  static let run = command(
    CLIOption.config,
    Flag("verbose", default: false, flag: "v", description: "Print each command being executed")
  ) { file, verbose in
    do {
      try ErrorPrettifier.execute {
        let config = try Config(file: file)

        if verbose {
          logMessage(.info, "Executing configuration file \(file)")
        }
        try file.parent().chdir {
          for (cmd, entries) in config.commands {
            for var entry in entries {
              guard let parserCmd = ParserCLI.command(named: cmd) else {
                throw Config.Error.missingEntry(key: cmd)
              }
              entry.makingRelativeTo(inputDir: config.inputDir, outputDir: config.outputDir)
              if verbose {
                for item in entry.commandLine(forCommand: cmd) {
                  logMessage(.info, " $ \(item)")
                }
              }
              try entry.checkPaths()
              try entry.run(parserCommand: parserCmd)
            }
          }
        }
      }
    } catch let error as Config.Error {
      logMessage(.error, error)
      logMessage(.info, """
        It seems like there was an error running SwiftGen. Please verify that your configuration file is valid by running:
        > swiftgen config lint

        If you have any other questions or issues, we have extensive documentation and an issue tracker on GitHub:
        > https://github.com/SwiftGen/SwiftGen
        """)
    }
  }
}
{'fraction_non_alphanumeric': 0.09742836149889787, 'fraction_numerical': 0.0014695077149155032, 'mean_word_length': 2.3659742828882293, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5004052', 'n_tokens_mistral': 1955, 'n_tokens_neox': 1871, 'n_words': 531}