autorest.modeler/.gulp/common.iced

507 строки
14 KiB
CoffeeScript

through = require 'through2'
util = require 'util'
# place an object into global namespace
global['Import'] = (object) ->
for key, value of object
global[key] = value
Import
# require into the global namespace (modulename = module)
Install: (modulename, module) ->
global[modulename] = require module or modulename
# require a gulp-Plugin into the global namespace
Plugin: () ->
Install module,"gulp-#{module}" for module in arguments
# require a module, placing exports into global namespace
Include: () ->
Import require module for module in arguments
Tasks: () ->
require "#{__dirname}/#{module}" for module in arguments
###############################################
# force-global a bunch of stuff.
require 'shelljs/global'
Install 'marked'
Install 'vinyl'
Install 'os'
Install 'path'
Install 'fs'
Install 'gulp'
Install 'util'
Install 'moment'
Install 'chalk'
Install 'yargs'
Install 'semver'
Install 'eol', 'gulp-line-ending-corrector'
Install 'through', 'through2-parallel'
Install 'run', 'run-sequence'
# do a bit of monkeypatching
_gulpStart = gulp.Gulp::start
_runTask = gulp.Gulp::_runTask
gulp.Gulp::start = (taskName) ->
@currentStartTaskName = taskName
_gulpStart.apply this, arguments
return
gulp.Gulp::_runTask = (task) ->
@currentRunTaskName = task.name
_runTask.apply this, arguments
return
# echo 'this.currentStartTaskName: ' + this.currentStartTaskName
# echo 'this.currentRunTaskName: ' + this.currentRunTaskName
# bring some gulp-Plugins along
# Plugin 'filter',
# 'zip'
#'unzip'
#'rename'
# force this into global namespace
global['argv'] = yargs.argv
fs = require('fs')
path = require('path')
concurrency = 0
queue = []
global.completed = []
vfs = require('vinyl-fs');
module.exports =
# lets us just handle each item in a stream easily.
foreach: (delegate) ->
through.obj { concurrency: threshold }, ( each, enc, done ) ->
delegate each, done, this
count: (result,passthru) =>
foreach (each,done) =>
result++
done null
hashCode: (s) ->
(s.split('').reduce ((a, b) ->
a = (a << 5) - a + b.charCodeAt(0)
a & a
), 0 ) .toString(16)
toArray: (result,passthru) =>
foreach (each,done) =>
result.push(each)
if passthru
done null, each
else
done null
showFiles: () ->
foreach (each,done) ->
echo info each.path
done null, each
onlyFiles: () ->
foreach (each,done) ->
return done null, each if fs.statSync(each.path).isFile()
done null
source: (globs, options ) ->
options = options or { }
options.follow = true
vfs.src( globs, options)
watchFiles: (src,tasks) ->
return gulp.watch( src,tasks)
destination: (globs, options ) ->
gulp.dest( globs, options)
later: (fn) ->
setTimeout fn, 10
mklink: (link,target) ->
# unlink link
if ! test "-d", link
fs.symlinkSync target, link, "junction"
unlink: (link) ->
if test "-d", link
fs.unlinkSync link
erase: (file) ->
if test "-f", file
fs.unlinkSync file
task: (name, description, deps, fn) ->
throw "Invalid task name " if typeof name isnt 'string'
throw "Invalid task description #{name} " if typeof description isnt 'string'
if typeof deps == 'function'
fn = deps
deps = []
# chain the task if it's a repeat
if name of gulp.tasks
prev = gulp.tasks[name]
# reset the name of this task to be a 'child'' task
name = "#{name}/#{description}"
description = ''
# add this task as a dependency of the original task.
prev.dep.unshift name
# add the new task.
# gulp.task name, deps, fn
skip = (name.startsWith "init") or (name.startsWith "npm-install") or (name.startsWith "clean") or (name is "copy-dts-files") or (name.startsWith "nuke") or (name.startsWith "reset") or (name.startsWith "autorest") or description.endsWith("!")
description = '' if description = '!'
if !skip
deps.unshift "init"
if fn.length # see if the task function has arguments (betcha never saw that before!)
gulp.task name, deps, (done)->
if not global.completed[name]
#echo warning "Running task #{name} #{typeof done}"
global.completed[name] = true
return fn(done)
#echo warning "Skipping completed task #{name}"
return done()
else
gulp.task name, deps, ()->
if not global.completed[name]
#echo warning "Running task #{name}"
global.completed[name] = true
return fn()
#echo warning "Skipping completed task #{name}"
return null
# set the description
gulp.tasks[name].description = description
return
where: (predicate) ->
foreach (each,done) ->
#return done null if each?
return done null, each if predicate each
done null
splitPath: (path) ->
s = path.match /^(.+)[\\\/]([^\/]+)$/ or [path, '',path]
f = s[2].match(/^(.*)([\\.].*)$/ ) or [s[2],s[2],'']
d = (path.match /^(.:)[\\\/]?(.*)$/ ) or ['','',path]
return {
fullname : path
folder : s[1]
filename : s[2]
basename : f[1]
extension : f[2]
drive: d[1] or ''
folders: (d[2].split /[\\\/]/ )or path
}
folder: (path) ->
return '' if not path
return (splitPath path).folder
split: (path) ->
return '' if not path
return (splitPath path).folders
filename: (path) ->
return '' if not path
p = splitPath path
return p.filename
extension: (path) ->
return '' if not path
p = splitPath path
return p.extension
basename: (path) ->
return '' if not path
p = splitPath path
return p.basename
exists: (path) ->
return test '-f', path
fileExists: (path) ->
return test '-f', path
dirExists: (path) ->
return test '-d', path
newer: (first,second) ->
return true if (!test "-d", second) and (!test "-f", second)
return false if (!test "-d",first) and (!test "-f", first)
f = fs.statSync(first).mtime
s = fs.statSync(second).mtime
return f > s
flattenEncode: (path) ->
path.basename = "#{ path.dirname.replace(/[\/\\]/g, '_') }_#{path.basename}"
path.dirname = ""
flattenDecode: (path) ->
f = path.basename.match(/^(.*)_(.*)$/ )
path.basename = "#{f[1].replace(/[_]/g, '/') }/#{f[2]}"
path.dirname = ""
except: (match) ->
# await through.obj defer file, enc, callback
through.obj (file, enc, callback) ->
# check if the file is an actual file.
# if it's not, just skip this tool.
if !file or !file.path
return callback null, file
# do something with the file
if file.path.match( match )
return callback null
return callback null, file
rmfile: (dir, file, callback) ->
p = path.join(dir, file)
fs.lstat p, (err, stat) ->
if err
callback.call null, err
else if stat.isDirectory()
rmdir p, callback
else
fs.unlink p, callback
return
return
rmdir: (dir, callback) ->
#echo "RMDIR #{dir}"
fs.readdir dir, (err, files) ->
if err
callback.call null, err
else if files.length
i = undefined
j = undefined
i = j = files.length
while i--
rmfile dir, files[i], (err) ->
if err
callback.call null, err
else if --j == 0
fs.rmdir dir, callback
return
else
fs.rmdir dir, callback
return
return
guid: ->
x = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring 1
"#{x()}#{x()}-#{x()}-#{x()}-#{x()}-#{x()}#{x()}#{x()}"
Fail: (text) ->
echo ""
echo "#{ error 'Task Failed:' } #{error_message text}"
echo ""
rm '-rf', workdir
process.exit(1)
execute: (cmdline,options,callback, ondata)->
if typeof options == 'function'
ondata = callback
callback = options
options = { }
# if we're busy, schedule again...
if concurrency >= threshold
queue.push(->
execute cmdline, options, callback, ondata
)
return
concurrency++
options.cwd = options.cwd or basefolder
echo " #{quiet_info options.cwd} :: #{info cmdline}" if !options.silent
options.silent = !verbose
proc = exec cmdline, options, (code,stdout,stderr)->
concurrency--
if code and (options.retry or 0) > 0
echo warning "retrying #{options.retry} #{options.cwd}/#{cmdline}"
options.retry--
return execute cmdline,options,callback,ondata
# run the next one in the queue
if queue.length
fn = (queue.shift())
fn()
if code and !options.ignoreexitcode
echo error "Exec Failed #{quiet_info options.cwd} :: #{info cmdline}"
if( stderr.length )
echo error "(stderr)"
echo marked ">> #{error stderr}"
if( stdout.length )
echo warning "(stdout)"
echo warning stdout
Fail "Execute Task failed, fast exit"
callback(code,stdout,stderr)
proc.stdout.on 'data', ondata if ondata
return proc
autorest: (args,done,ignoreexitcode) ->
echo info "Queuing up: AutoRest #{args.join(' ')}"
execute "#{basefolder}/node_modules/.bin/autorest \"--use=#{basefolder}\" #{args.map((a) -> "\"#{a}\"").join(' ')}" , { silent:true, ignoreexitcode: ignoreexitcode || false }, (code,stdout,stderr) ->
return done(code,stdout,stderr)
# build task for global build
module.exports.task 'build', 'builds project', ->
echo "Building project in #{basefolder}"
module.exports.task 'clean', 'cleans the project files', ->
module.exports.task 'regenerate', 'regenerates expected files for testing', ->
# task for vs code
module.exports.task 'code', 'launches vs code', ->
exec "code #{basefolder}"
module.exports.task 'release-only', '', (done)->
Fail( "This command requires --configuration release" ) if configuration isnt "Release"
done()
configString = (s)->
"#{s.charAt 0 .toUpperCase()}#{s.slice 1 .toLowerCase() }"
# bring current module into global namespace.
Import module.exports
###############################################
# Global values
process.env.tmp = process.env.tmp or "#{basefolder}/tmp"
package_json = require("#{basefolder}/package.json")
Import
stable: argv.stable or false
configuration: if argv.configuration then configString( argv.configuration) else (if argv.release then 'Release' else 'Debug')
github_apikey: argv.github_apikey or process.env.GITHUB_APIKEY or null
nuget_apikey: argv.nuget_apikey or process.env.NUGET_APIKEY or null
npm_apikey: argv.npm_apikey or process.env.NPM_APIKEY or null
today: moment().format('YYYYMMDD')
now: moment().format('YYYYMMDD-HHmm')
force: argv.force or false
threshold: argv.threshold or ((os.cpus().length)-1) or 1
verbose: argv.verbose or null
workdir: "#{process.env.tmp}/gulp/#{module.exports.guid()}"
watch: argv.watch or false
mkdir "-p", workdir if !test "-d", workdir
###############################################
# UI stuff
TerminalRenderer = require('marked-terminal')
marked.setOptions {
renderer: new TerminalRenderer({
heading: chalk.green.bold,
firstHeading: chalk.green.bold,
showSectionPrefix: false,
strong: chalk.bold.cyan,
em: chalk.cyan,
blockquote: chalk.magenta,
tab: 2
})
}
set '+e'
Import
error: chalk.bold.red
error_message: chalk.bold.cyan
warning: chalk.bold.yellow
info: chalk.bold.green
quiet_info: chalk.green
###############################################
task 'default','', ->
cmds = ""
for name, t of gulp.tasks
cmds += "\n gulp **#{name}** - #{t.description}" if t.description? and t.description.length
switches = ""
echo marked """
# Usage
## gulp commands
#{cmds}
## available switches
*--force* specify when you want to force an action (restore, etc)
*--configuration* 'debug' or 'release'
*--verbose* enable verbose output
*--threshold=nn* set parallelism threshold (default = 10)
#{switches}
"""
task 'test', "Run Tests", ->
task 'fix-line-endings', 'Fixes line endings to file-type appropriate values.', ->
source "**/*.iced"
.pipe eol {eolc: 'LF', encoding:'utf8'}
.pipe destination '.'
task 'get-tag', '!', (done)->
if argv.tag
# take the argument if they specified it.
global.tag = argv.tag
done()
else
# pick up the tag from the pkg.json version entry
global.tag = semver.parse((package_json.version).trim()).prerelease.join(".")
if( global.tag )
return done()
# if branch is provided by environment
if( env.BUILD_SOURCEBRANCHNAME )
global.tag = if ( env.BUILD_SOURCEBRANCHNAME == "master" || env.BUILD_SOURCEBRANCHNAME =="HEAD" ) then "preview" else env.BUILD_SOURCEBRANCHNAME
return done();
# grab the git branch name.
execute "git rev-parse --abbrev-ref HEAD" , {silent:true}, (c,o,e)->
o = "preview" if( o == undefined || o == null || o == "" || o.trim() == 'master' || o.trim() == 'HEAD')
global.tag = o.trim()
done();
task 'version-number', '!', (done)->
if argv.version
global.version = argv.version if argv.version
done();
else
# git rev-list --parents HEAD --count --full-history
execute "git rev-list --parents HEAD --count --full-history" , {silent:true}, (c,o,e)->
pv = (package_json.version).trim()
global.version = "#{semver.major(pv)}.#{semver.minor(pv)}.#{o.trim()}"
done();