<commit_before>###
Docpad by <NAME>
Intuitive Web Development
###

# Requirements
fs = require 'fs'
path = require 'path'
sys = require 'util'
caterpillar = require 'caterpillar'
util = require 'bal-util'
exec = require('child_process').exec
growl = require('growl')
express = false
watch = false
queryEngine = false
_ = require 'underscore'
PluginLoader = require "#{__dirname}/plugin-loader.coffee"
require "#{__dirname}/prototypes.coffee"

# -------------------------------------
# Docpad

class Docpad
	# Options
	rootPath: null
	outPath: 'out'
	srcPath: 'src'
	corePath: "#{__dirname}/.."
	libPath: "#{__dirname}"
	mainPath: "#{__dirname}/docpad.coffee"
	layoutsPath: null
	documentsPath: null
	publicPath: null
	skeleton: 'bootstrap'
	maxAge: false
	logLevel: 6

	# Docpad
	version: null
	packageData: null
	config: null
	generating: false
	loading: true
	generateTimeout: null
	actionTimeout: null
	server: null
	port: 9778
	logger: null

	# Models
	File: null
	Layout: null
	Document: null
	layouts: null
	documents: null
	
	# Plugins
	pluginsArray: []
	pluginsObject: {}

	# Skeletons
	skeletons:
		bootstrap:
			repo: 'https://github.com/balupton/bootstrap.docpad.git'


	# ---------------------------------
	# Main

	# Init
	constructor: ({rootPath,outPath,srcPath,skeleton,maxAge,port,server,logLevel,config}={}) ->
		# Options
		@config = {}
		@pluginsArray = []
		@pluginsObject = {}
		@port = port  if port
		@maxAge = maxAge  if maxAge
		@server = server  if server
		@rootPath = path.normalize(rootPath || process.cwd())
		@outPath = path.normalize(outPath || "#{@rootPath}/#{@outPath}")
		@srcPath = path.normalize(srcPath || "#{@rootPath}/#{@srcPath}")
		@layoutsPath = @srcPath+'/layouts'
		@documentsPath = @srcPath+'/documents'
		@publicPath = @srcPath+'/public'
		@skeleton = skeleton  if skeleton

		# Logger
		@logLevel = logLevel or @logLevel
		@logger = new caterpillar.Logger
			transports:
				level: @logLevel
				formatter:
					module: module
		
		# Configure
		@loadConfiguration(config)

		# Version Check
		@compareVersion()
		
		# Load Plugins
		@loadPlugins null, (err) =>
			@error(err)  if err
			@loading = false
	
	# Load Configuration
	loadConfiguration: (config={}) ->
		# Prepare
		@config =
			enableUnlistedPlugins: true
			enabledPlugins: {}
			plugins: {}

		# Docpad Configuration
		@packageData = JSON.parse(fs.readFileSync("#{@corePath}/package.json").toString()) or {}
		@version = @packageData.version
		_.extend @config, @packageData.docpad or {}

		# Website Configuration
		try
			websiteData = JSON.parse(fs.readFileSync("#{@rootPath}/package.json").toString()) or {}
			_.extend @config, websiteData.docpad or {}
		catch err
			@error('Failed to load the website configuration')
		
		# User Configuration
		_.extend @config, config
		
		# Prepare enabled plugins
		if typeof @config.enabledPlugins is 'string'
			enabledPlugins = {}
			for enabledPlugin in @config.enabledPlugins.split(/[ ,]+/)
				enabledPlugins[enabledPlugin] = true
			@config.enabledPlugins = enabledPlugins
		
		# Chain
		@
	
	# Layout Document
	createDocument: (meta={}) ->
		# Prepare
		config = docpad: @, layouts: @layouts, logger: @logger, meta: meta
		
		# Create and return
		document = new @Document config
	
	# Create Layout
	createLayout: (meta={}) ->
		# Prepare
		config = docpad: @, layouts: @layouts, logger: @logger, meta: meta

		# Create and return
		layout = new @Layout config

	# Clean Models
	cleanModels: (next) ->
		# Prepare
		File = @File = require("#{@libPath}/file.coffee")
		Layout = @Layout = class extends File
		Document = @Document = class extends File
		layouts = @layouts = new queryEngine.Collection
		documents = @documents = new queryEngine.Collection
		
		# Extend
		Layout::store = ->
			layouts[@id] = @
		Document::store = ->
			documents[@id] = @
		
		# Next
		next()  if next

		# Chain
		@

	# Compare versions
	compareVersion: ->
		util.packageCompare
			local: "#{@corePath}/package.json"
			remote: 'https://raw.github.com/balupton/docpad/master/package.json'
			newVersionCallback: (details) =>
				growl.notify 'There is a new version of docpad available'
				@logger.log 'notice', """
					There is a new version of docpad available, you should probably upgrade...
					current version:  #{details.local.version}
					new version:      #{details.remote.version}
					grab it here:     #{details.remote.homepage}
					"""
		@

	# Initialise the Skeleton
	initialiseSkeleton: (skeleton, destinationPath, next) ->
		# Prepare
		logger = @logger
		skeletonRepo = @skeletons[skeleton].repo
		logger.log 'info', "[#{skeleton}] Initialising the Skeleton to #{destinationPath}"
		snoring = false
		notice = setTimeout(
			->
				snoring = true
				logger.log 'notice', "[#{skeleton}] This could take a while, grab a snickers"
			2000
		)

		# Async
		tasks = new util.Group (err) ->
			logger.log 'info', "[#{skeleton}] Initialised the Skeleton"  unless err
			next(err)
		tasks.total = 2
		
		# Pull
		logger.log 'debug', "[#{skeleton}] Pulling in the Skeleton"
		child = exec(
			# Command
			"git init; git remote add skeleton #{skeletonRepo}; git pull skeleton master"
			
			# Options
			{
				cwd: destinationPath
			}

			# Next
			(err,stdout,stderr) ->
				# Output
				if err
					console.log stdout.replace(/\s+$/,'')  if stdout
					console.log stderr.replace(/\s+$/,'')  if stderr
					return next(err)
				
				# Log
				logger.log 'debug', "[#{skeleton}] Pulled in the Skeleton"

				# Submodules
				path.exists "#{destinationPath}/.gitmodules", (exists) ->
					tasks.complete()  unless exists
					logger.log 'debug', "[#{skeleton}] Initialising Submodules for Skeleton"
					child = exec(
						# Command
						'git submodule init; git submodule update; git submodule foreach --recursive "git init; git checkout master; git submodule init; git submodule update"'
						<commit_msg>Expanded exec commands for windows support<commit_after>###
Docpad by <NAME>
Intuitive Web Development
###

# Requirements
fs = require 'fs'
path = require 'path'
sys = require 'util'
caterpillar = require 'caterpillar'
util = require 'bal-util'
child_process = require('child_process')
growl = require('growl')
express = false
watch = false
queryEngine = false
_ = require 'underscore'
PluginLoader = require "#{__dirname}/plugin-loader.coffee"
require "#{__dirname}/prototypes.coffee"
exec = (commands,options,callback) ->
	# Sync
	tasks = new util.Group callback
	
	# Tasks
	commands = [commands]  unless commands instanceof Array
	for command in commands
		console.log "Adding [#{command}]"
		tasks.push ->
			console.log "Running [#{command}] [#{tasks.queueIndex}]"
			child_process.exec command, options, tasks.completer()

	# Execute the tasks synchronously
	console.log require('util').inspect tasks.queue
	tasks.sync()


# -------------------------------------
# Docpad

class Docpad
	# Options
	rootPath: null
	outPath: 'out'
	srcPath: 'src'
	corePath: "#{__dirname}/.."
	libPath: "#{__dirname}"
	mainPath: "#{__dirname}/docpad.coffee"
	layoutsPath: null
	documentsPath: null
	publicPath: null
	skeleton: 'bootstrap'
	maxAge: false
	logLevel: 6

	# Docpad
	version: null
	packageData: null
	config: null
	generating: false
	loading: true
	generateTimeout: null
	actionTimeout: null
	server: null
	port: 9778
	logger: null

	# Models
	File: null
	Layout: null
	Document: null
	layouts: null
	documents: null
	
	# Plugins
	pluginsArray: []
	pluginsObject: {}

	# Skeletons
	skeletons:
		bootstrap:
			repo: 'https://github.com/balupton/bootstrap.docpad.git'


	# ---------------------------------
	# Main

	# Init
	constructor: ({rootPath,outPath,srcPath,skeleton,maxAge,port,server,logLevel,config}={}) ->
		# Options
		@config = {}
		@pluginsArray = []
		@pluginsObject = {}
		@port = port  if port
		@maxAge = maxAge  if maxAge
		@server = server  if server
		@rootPath = path.normalize(rootPath || process.cwd())
		@outPath = path.normalize(outPath || "#{@rootPath}/#{@outPath}")
		@srcPath = path.normalize(srcPath || "#{@rootPath}/#{@srcPath}")
		@layoutsPath = @srcPath+'/layouts'
		@documentsPath = @srcPath+'/documents'
		@publicPath = @srcPath+'/public'
		@skeleton = skeleton  if skeleton

		# Logger
		@logLevel = logLevel or @logLevel
		@logger = new caterpillar.Logger
			transports:
				level: @logLevel
				formatter:
					module: module
		
		# Configure
		@loadConfiguration(config)

		# Version Check
		@compareVersion()
		
		# Load Plugins
		@loadPlugins null, (err) =>
			@error(err)  if err
			@loading = false
	
	# Load Configuration
	loadConfiguration: (config={}) ->
		# Prepare
		@config =
			enableUnlistedPlugins: true
			enabledPlugins: {}
			plugins: {}

		# Docpad Configuration
		@packageData = JSON.parse(fs.readFileSync("#{@corePath}/package.json").toString()) or {}
		@version = @packageData.version
		_.extend @config, @packageData.docpad or {}

		# Website Configuration
		try
			websiteData = JSON.parse(fs.readFileSync("#{@rootPath}/package.json").toString()) or {}
			_.extend @config, websiteData.docpad or {}
		catch err
			@error('Failed to load the website configuration')
		
		# User Configuration
		_.extend @config, config
		
		# Prepare enabled plugins
		if typeof @config.enabledPlugins is 'string'
			enabledPlugins = {}
			for enabledPlugin in @config.enabledPlugins.split(/[ ,]+/)
				enabledPlugins[enabledPlugin] = true
			@config.enabledPlugins = enabledPlugins
		
		# Chain
		@
	
	# Layout Document
	createDocument: (meta={}) ->
		# Prepare
		config = docpad: @, layouts: @layouts, logger: @logger, meta: meta
		
		# Create and return
		document = new @Document config
	
	# Create Layout
	createLayout: (meta={}) ->
		# Prepare
		config = docpad: @, layouts: @layouts, logger: @logger, meta: meta

		# Create and return
		layout = new @Layout config

	# Clean Models
	cleanModels: (next) ->
		# Prepare
		File = @File = require("#{@libPath}/file.coffee")
		Layout = @Layout = class extends File
		Document = @Document = class extends File
		layouts = @layouts = new queryEngine.Collection
		documents = @documents = new queryEngine.Collection
		
		# Extend
		Layout::store = ->
			layouts[@id] = @
		Document::store = ->
			documents[@id] = @
		
		# Next
		next()  if next

		# Chain
		@

	# Compare versions
	compareVersion: ->
		util.packageCompare
			local: "#{@corePath}/package.json"
			remote: 'https://raw.github.com/balupton/docpad/master/package.json'
			newVersionCallback: (details) =>
				growl.notify 'There is a new version of docpad available'
				@logger.log 'notice', """
					There is a new version of docpad available, you should probably upgrade...
					current version:  #{details.local.version}
					new version:      #{details.remote.version}
					grab it here:     #{details.remote.homepage}
					"""
		@

	# Initialise the Skeleton
	initialiseSkeleton: (skeleton, destinationPath, next) ->
		# Prepare
		logger = @logger
		skeletonRepo = @skeletons[skeleton].repo
		logger.log 'info', "[#{skeleton}] Initialising the Skeleton to #{destinationPath}"
		snoring = false
		notice = setTimeout(
			->
				snoring = true
				logger.log 'notice', "[#{skeleton}] This could take a while, grab a snickers"
			2000
		)

		# Async
		tasks = new util.Group (err) ->
			logger.log 'info', "[#{skeleton}] Initialised the Skeleton"  unless err
			next(err)
		tasks.total = 2
		
		# Pull
		logger.log 'debug', "[#{skeleton}] Pulling in the Skeleton"
		child = exec(
			# Commands
			[
				"git init"
				"git remote add skeleton #{skeletonRepo}"
				"git pull skeleton master"
			]
			
			# Options
			{
				cwd: destinationPath
			}

			# Next
			(err,stdout,stderr) ->
				# Output
				if err
					console.log stdout.replace(/\s+$/,'')  if stdout
					console.log stderr.replace(/\s+$/,'')  if stderr
					return next(err)
				
				# Log
				logger.log 'debug', "[#{skeleton}] Pulled in the Skeleton"

				# Submodules
				path.exists "#{destinationPath}/.gitmodules", (exists) ->
					tasks.complete()  unless exists
					logger.log 'debug', "[#{skeleton}] Initialising Submodules for Skeleton"
					child = exec(
						# Commands
						[
							'git submodule init'
							'git submodule update'
							'git submodule foreach --recursive "git init"'
							'git submodule foreach --recursive "git checkout master"'
							'git submodule foreach --recursive "git submodule init"'
							'git submodule foreach --recursive "git submodule update"'
						]
						
{'fraction_non_alphanumeric': 0.13975981300878537, 'fraction_numerical': 0.0016119932296284356, 'mean_word_length': 3.3354297693920336, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 37, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3662500', 'n_tokens_mistral': 4663, 'n_tokens_neox': 3905, 'n_words': 1049}