<commit_before>fs = require "fs"
spawn = require("child_process").spawn
exec = require("child_process").exec
rimraf = require "rimraf"
Path = require "path"
semver = require "semver"
settings = require "settings-sharelatex"
knox = require "knox"

SERVICES = [{
	name: "web"
	repo: "https://github.com/sharelatex/web-sharelatex.git"
}, {
	name: "document-updater"
	repo: "https://github.com/sharelatex/document-updater-sharelatex.git"
}, {
	name: "clsi"
	repo: "https://github.com/sharelatex/clsi-sharelatex.git"
}, {
	name: "filestore"
	repo: "https://github.com/sharelatex/filestore-sharelatex.git"
}]


module.exports = (grunt) ->
	grunt.loadNpmTasks 'grunt-bunyan'
	grunt.loadNpmTasks 'grunt-execute'
	grunt.loadNpmTasks 'grunt-available-tasks'
	grunt.loadNpmTasks 'grunt-concurrent'

	execute = {}
	for service in SERVICES
		execute[service.name] =
			src: "#{service.name}/app.js"

	grunt.initConfig
		execute: execute

		concurrent:
			all:
				tasks: ("run:#{service.name}" for service in SERVICES)
				options:
					limit: SERVICES.length
					logConcurrentOutput: true

		availabletasks:
			tasks:
				options:
					filter: 'exclude',
					tasks: [
						'concurrent'
						'execute'
						'bunyan'
						'availabletasks'
						]
					groups:
						"Run tasks": [
							"run"
							"run:all"
							"default"
						].concat ("run:#{service.name}" for service in SERVICES)
						"Misc": [
							"help"
						]
						"Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install"])
						"Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"])
						"Config tasks": ["install:config"]
						"Checks": ["check", "check:redis", "check:latexmk"]

	for service in SERVICES
		do (service) ->
			grunt.registerTask "install:#{service.name}", "Download and set up the #{service.name} service", () ->
				done = @async()
				Helpers.installService(service.repo, service.name, done)
			grunt.registerTask "update:#{service.name}", "Checkout and update the #{service.name} service", () ->
				done = @async()
				Helpers.updateService(service.name, done)
			grunt.registerTask "run:#{service.name}", "Run the ShareLaTeX #{service.name} service", ["bunyan", "execute:#{service.name}"]

	grunt.registerTask 'install:config', "Copy the example config into the real config", () ->
		Helpers.installConfig @async()
	grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services",
		("install:#{service.name}" for service in SERVICES).concat(["install:config"])
	grunt.registerTask 'install', 'install:all'
	grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
		("update:#{service.name}" for service in SERVICES)
	grunt.registerTask 'update', 'update:all'
	grunt.registerTask 'run', "Run all of the sharelatex processes", ['concurrent:all']
	grunt.registerTask 'run:all', 'run'

	grunt.registerTask 'help', 'Display this help list', 'availabletasks'
	grunt.registerTask 'default', 'run'

	grunt.registerTask "check:redis", "Check that redis is installed and running", () ->
		Helpers.checkRedis @async()
	grunt.registerTask "check:latexmk", "Check that latexmk is installed", () ->
		Helpers.checkLatexmk @async()
	grunt.registerTask "check:s3", "Check that Amazon S3 credentials are configured", () ->
		Helpers.checkS3 @async()
	grunt.registerTask "check", "Check that you have the required dependencies installed", ["check:redis", "check:latexmk", "check:s3"]

	Helpers =
		installService: (repo_src, dir, callback = (error) ->) ->
			Helpers.cloneGitRepo repo_src, dir, (error) ->
				return callback(error) if error?
				Helpers.installNpmModules dir, (error) ->
					return callback(error) if error?
					Helpers.runGruntInstall dir, (error) ->
						return callback(error) if error?
						callback()

		updateService: (dir, callback = (error) ->) ->
			Helpers.updateGitRepo dir, (error) ->
				return callback(error) if error?
				Helpers.installNpmModules dir, (error) ->
					return callback(error) if error?
					Helpers.runGruntInstall dir, (error) ->
						return callback(error) if error?
						callback()

		cloneGitRepo: (repo_src, dir, callback = (error) ->) ->
			if !fs.existsSync(dir)
				proc = spawn "git", ["clone", repo_src, dir], stdio: "inherit"
				proc.on "close", () ->
					callback()
			else
				console.log "#{dir} already installed, skipping."
				callback()

		updateGitRepo: (dir, callback = (error) ->) ->
			proc = spawn "git", ["checkout", "master"], cwd: dir, stdio: "inherit"
			proc.on "close", () ->
				proc = spawn "git", ["pull"], cwd: dir, stdio: "inherit"
				proc.on "close", () ->
					callback()

		installNpmModules: (dir, callback = (error) ->) ->
			proc = spawn "npm", ["install"], stdio: "inherit", cwd: dir
			proc.on "close", () ->
				callback()

		installConfig: (callback = (error) ->) ->
			if !fs.existsSync("config/settings.development.coffee")
				grunt.log.writeln "Copying example config into config/settings.development.coffee"
				exec "cp config/settings.development.coffee.example config/settings.development.coffee", (error, stdout, stderr) ->
					callback(error)
			else
				grunt.log.writeln "Config file already exists. Skipping."
				callback()

		runGruntInstall: (dir, callback = (error) ->) ->
			proc = spawn "grunt", ["install"], stdio: "inherit", cwd: dir
			proc.on "close", () ->
				callback()

		checkRedis: (callback = (error) ->) ->
			grunt.log.write "Checking Redis is running... "
			exec "redis-cli info", (error, stdout, stderr) ->
				if error? and error.message.match("Could not connect")
					grunt.log.error "FAIL. Redis is not running"
					return callback(error)
				else if error?
					return callback(error)
				else
					m = stdout.match(/redis_version:(.*)/)
					if !m?
						grunt.log.error "FAIL."
						grunt.log.error "Unknown redis version"
						error = new Error("Unknown redis version")
					else
						version = m[1]
						if semver.gt(version, "2.6.0")
							grunt.log.writeln "OK."
							grunt.log.writeln "Running Redis version #{version}"
						else
							grunt.log.error "FAIL."
							grunt.log.error "Redis version is too old (#{version}). Must be 2.6.0 or greater."
							error = new Error("Redis version is too old (#{version}). Must be 2.6.0 or greater.")
				callback(error)

		checkLatexmk: (callback = (error) ->) ->
			grunt.log.write "Checking latexmk is installed... "
			exec "latexmk --version", (error, stdout, stderr) ->
				if error? and error.message.match("command not found")
					grunt.log.error "FAIL."
					grunt.log.errorlns """
					Either latexmk is not installed or is not in your PATH.

					latexmk comes with TexLive 2013, and must be a version from 2013 or later.
					This is a not a fatal error, but compiling will not work without latexmk
					"""
					return callback(error)
				else if error?
					return callback(error)
				else
					m = stdout.match(/Version (.*)/)
					if !m?
						grunt.log.error "FAIL."
						grunt.log.error "Unknown latexmk version"
						error = new Error("Unknown latexmk version")
					else
						version = m[1]
						if semver.gte(version + ".0", "4.39.0")
							grunt.log.writeln "OK."
							grunt.log.writeln "Running latexmk version #{version}"
						else
							grunt.log.error "FAIL."
							grunt.log.errorlns """
							latexmk version is too old (#{version}). Must be 4.39 or greater.
							This is a not a fatal error, but compiling will not work without latexmk
							"""
							error = new Error("latexmk is too old")
				callback(error)

		checkS3: (callback = (error) ->) ->
			grunt.log.write "Checking S3 credentials... "
			try
				client = knox.createClient({
					key: settings.s3.key
					secret: settings.s3.secret
					bucket: settings.s3.buckets.user_files
				})
			catch e
				grunt.log.error "FAIL."
				grunt.log.errorlns """
				Please configure you Amazon S3 credentials in config/settings.development.coffee

				Amazon S3 (Simple Storage Service) is a cloud storage service provided by
				Amazon. ShareLaTeX uses S3 for storing binary files like images. You can 
				sign up for an account and find out more at:

				    http://aws.amazon.com/s3/
                  
				"""
				return callback()

			client.getFile "does-not-exist", (error, response) ->
				unless response? and response.statusCode == 404
					grunt.log.error "FAIL."
					grunt.log.errorlns """
					Could not connect to Amazon S3. Please check your credentials.
					"""
				else
					grunt.log.write "OK."
				callback()

<commit_msg>Check that make is installed before installing modules that need compiling<commit_after>fs = require "fs"
spawn = require("child_process").spawn
exec = require("child_process").exec
rimraf = require "rimraf"
Path = require "path"
semver = require "semver"
settings = require "settings-sharelatex"
knox = require "knox"

SERVICES = [{
	name: "web"
	repo: "https://github.com/sharelatex/web-sharelatex.git"
}, {
	name: "document-updater"
	repo: "https://github.com/sharelatex/document-updater-sharelatex.git"
}, {
	name: "clsi"
	repo: "https://github.com/sharelatex/clsi-sharelatex.git"
}, {
	name: "filestore"
	repo: "https://github.com/sharelatex/filestore-sharelatex.git"
}]


module.exports = (grunt) ->
	grunt.loadNpmTasks 'grunt-bunyan'
	grunt.loadNpmTasks 'grunt-execute'
	grunt.loadNpmTasks 'grunt-available-tasks'
	grunt.loadNpmTasks 'grunt-concurrent'

	execute = {}
	for service in SERVICES
		execute[service.name] =
			src: "#{service.name}/app.js"

	grunt.initConfig
		execute: execute

		concurrent:
			all:
				tasks: ("run:#{service.name}" for service in SERVICES)
				options:
					limit: SERVICES.length
					logConcurrentOutput: true

		availabletasks:
			tasks:
				options:
					filter: 'exclude',
					tasks: [
						'concurrent'
						'execute'
						'bunyan'
						'availabletasks'
						]
					groups:
						"Run tasks": [
							"run"
							"run:all"
							"default"
						].concat ("run:#{service.name}" for service in SERVICES)
						"Misc": [
							"help"
						]
						"Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install", "install:config"])
						"Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"])
						"Config tasks": ["install:config"]
						"Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make"]

	for service in SERVICES
		do (service) ->
			grunt.registerTask "install:#{service.name}", "Download and set up the #{service.name} service", () ->
				done = @async()
				Helpers.installService(service.repo, service.name, done)
			grunt.registerTask "update:#{service.name}", "Checkout and update the #{service.name} service", () ->
				done = @async()
				Helpers.updateService(service.name, done)
			grunt.registerTask "run:#{service.name}", "Run the ShareLaTeX #{service.name} service", ["bunyan", "execute:#{service.name}"]

	grunt.registerTask 'install:config', "Copy the example config into the real config", () ->
		Helpers.installConfig @async()
	grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services",
		["check:make"].concat(
			("install:#{service.name}" for service in SERVICES)
		).concat(["install:config"])
	grunt.registerTask 'install', 'install:all'
	grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
		["check:make"].concat(
			("update:#{service.name}" for service in SERVICES)
		)
	grunt.registerTask 'update', 'update:all'
	grunt.registerTask 'run', "Run all of the sharelatex processes", ['concurrent:all']
	grunt.registerTask 'run:all', 'run'

	grunt.registerTask 'help', 'Display this help list', 'availabletasks'
	grunt.registerTask 'default', 'run'

	grunt.registerTask "check:redis", "Check that redis is installed and running", () ->
		Helpers.checkRedis @async()
	grunt.registerTask "check:latexmk", "Check that latexmk is installed", () ->
		Helpers.checkLatexmk @async()
	grunt.registerTask "check:s3", "Check that Amazon S3 credentials are configured", () ->
		Helpers.checkS3 @async()
	grunt.registerTask "check:make", "Check that make is installed", () ->
		Helpers.checkMake @async()
	grunt.registerTask "check", "Check that you have the required dependencies installed", ["check:redis", "check:latexmk", "check:s3"]

	Helpers =
		installService: (repo_src, dir, callback = (error) ->) ->
			Helpers.cloneGitRepo repo_src, dir, (error) ->
				return callback(error) if error?
				Helpers.installNpmModules dir, (error) ->
					return callback(error) if error?
					Helpers.runGruntInstall dir, (error) ->
						return callback(error) if error?
						callback()

		updateService: (dir, callback = (error) ->) ->
			Helpers.updateGitRepo dir, (error) ->
				return callback(error) if error?
				Helpers.installNpmModules dir, (error) ->
					return callback(error) if error?
					Helpers.runGruntInstall dir, (error) ->
						return callback(error) if error?
						callback()

		cloneGitRepo: (repo_src, dir, callback = (error) ->) ->
			if !fs.existsSync(dir)
				proc = spawn "git", ["clone", repo_src, dir], stdio: "inherit"
				proc.on "close", () ->
					callback()
			else
				console.log "#{dir} already installed, skipping."
				callback()

		updateGitRepo: (dir, callback = (error) ->) ->
			proc = spawn "git", ["checkout", "master"], cwd: dir, stdio: "inherit"
			proc.on "close", () ->
				proc = spawn "git", ["pull"], cwd: dir, stdio: "inherit"
				proc.on "close", () ->
					callback()

		installNpmModules: (dir, callback = (error) ->) ->
			proc = spawn "npm", ["install"], stdio: "inherit", cwd: dir
			proc.on "close", () ->
				callback()

		installConfig: (callback = (error) ->) ->
			if !fs.existsSync("config/settings.development.coffee")
				grunt.log.writeln "Copying example config into config/settings.development.coffee"
				exec "cp config/settings.development.coffee.example config/settings.development.coffee", (error, stdout, stderr) ->
					callback(error)
			else
				grunt.log.writeln "Config file already exists. Skipping."
				callback()

		runGruntInstall: (dir, callback = (error) ->) ->
			proc = spawn "grunt", ["install"], stdio: "inherit", cwd: dir
			proc.on "close", () ->
				callback()

		checkRedis: (callback = (error) ->) ->
			grunt.log.write "Checking Redis is running... "
			exec "redis-cli info", (error, stdout, stderr) ->
				if error? and error.message.match("Could not connect")
					grunt.log.error "FAIL. Redis is not running"
					return callback(error)
				else if error?
					return callback(error)
				else
					m = stdout.match(/redis_version:(.*)/)
					if !m?
						grunt.log.error "FAIL."
						grunt.log.error "Unknown redis version"
						error = new Error("Unknown redis version")
					else
						version = m[1]
						if semver.gt(version, "2.6.0")
							grunt.log.writeln "OK."
							grunt.log.writeln "Running Redis version #{version}"
						else
							grunt.log.error "FAIL."
							grunt.log.error "Redis version is too old (#{version}). Must be 2.6.0 or greater."
							error = new Error("Redis version is too old (#{version}). Must be 2.6.0 or greater.")
				callback(error)

		checkLatexmk: (callback = (error) ->) ->
			grunt.log.write "Checking latexmk is installed... "
			exec "latexmk --version", (error, stdout, stderr) ->
				if error? and error.message.match("command not found")
					grunt.log.error "FAIL."
					grunt.log.errorlns """
					Either latexmk is not installed or is not in your PATH.

					latexmk comes with TexLive 2013, and must be a version from 2013 or later.
					This is a not a fatal error, but compiling will not work without latexmk
					"""
					return callback(error)
				else if error?
					return callback(error)
				else
					m = stdout.match(/Version (.*)/)
					if !m?
						grunt.log.error "FAIL."
						grunt.log.error "Unknown latexmk version"
						error = new Error("Unknown latexmk version")
					else
						version = m[1]
						if semver.gte(version + ".0", "4.39.0")
							grunt.log.writeln "OK."
							grunt.log.writeln "Running latexmk version #{version}"
						else
							grunt.log.error "FAIL."
							grunt.log.errorlns """
							latexmk version is too old (#{version}). Must be 4.39 or greater.
							This is a not a fatal error, but compiling will not work without latexmk
							"""
							error = new Error("latexmk is too old")
				callback(error)

		checkS3: (callback = (error) ->) ->
			grunt.log.write "Checking S3 credentials... "
			try
				client = knox.createClient({
					key: settings.s3.key
					secret: settings.s3.secret
					bucket: settings.s3.buckets.user_files
				})
			catch e
				grunt.log.error "FAIL."
				grunt.log.errorlns """
				Please configure you Amazon S3 credentials in config/settings.development.coffee

				Amazon S3 (Simple Storage Service) is a cloud storage service provided by
				Amazon. ShareLaTeX uses S3 for storing binary files like images. You can 
				sign up for an account and find out more at:

				    http://aws.amazon.com/s3/
                  
				"""
				return callback()

			client.getFile "does-not-exist", (error, response) ->
				unless response? and response.statusCode == 404
					grunt.log.error "FAIL."
					grunt.log.errorlns """
					Could not connect to Amazon S3. Please check your credentials.
					"""
				else
					grunt.log.write "OK."
				callback()

		checkMake: (callback = (error) ->) ->
			grunt.log.write "Checking make is installed... "
			exec "make --version", (error, stdout, stderr) ->
				if error? and error.message.match("command not found")
					grunt.log.error "FAIL."
					grunt.log.errorlns """
					Either make is not installed or is not in your path.

					On Ubuntu you can install make with:

					    sudo apt-get install build-essential

					"""
					return callback(error)
				else if error?
					return callback(error)
				else
					grunt.log.write "OK."
					return callback()




{'fraction_non_alphanumeric': 0.1431123018530922, 'fraction_numerical': 0.004967626702388926, 'mean_word_length': 3.1979850046860356, 'pattern_counts': {'":': 12, '<': 3, '<?xml version=': 0, '>': 93, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5126664', 'n_tokens_mistral': 7101, 'n_tokens_neox': 5661, 'n_words': 1588}