Skip to content

Instantly share code, notes, and snippets.

@snipsnipsnip
Created December 23, 2013 22:13
Show Gist options
  • Save snipsnipsnip/8105743 to your computer and use it in GitHub Desktop.
Save snipsnipsnip/8105743 to your computer and use it in GitHub Desktop.
gas-managerが柔軟すぎて馴染めなかったのでmanager部分だけ取り出してバグチェックとか取っ払ってコマンドインタフェースをコピペしながら再発明した 結構注意点が多くてつらい
fs = require 'fs'
path = require 'path'
async = require 'async'
commander = require 'commander'
gas_manager = require 'gas-manager'
request = require 'request'
util = require 'gas-manager/out/lib/commands/util'
main = ->
commander
.version("v0.0.1")
.option('-f, --fileId <fileId>', "target gas project fileId")
.option('-c, --config <path>', "credential config file path", path.resolve(util.getUserHome() , 'gas-config.json'))
.option('-s, --setting <path>', "project setting file path", "./gas-project.json")
.option('-e, --env <env>', 'the environment of target sources', "src")
.option('-d, --workdir <path>', 'working directory', process.cwd())
.option('-r, --run', 'execute operations actually', false)
commander
.command("init")
.description("starts wizard for creating initial config file")
.option('-P --only-project', "Creating only a project setting file")
.action(init)
commander
.command("list")
.description("list all projects you have")
.action(list)
commander
.command("get")
.description("download all files from the apps script project to local (overwrites all existing files)")
.action(get)
commander
.command("put")
.description("upload all local files to the apps script project (overwrites all existing files)")
.action(put)
commander.parse(process.argv)
init = require('gas-manager/out/lib/commands/init-command').init
get = (options) ->
config = util.loadConfig(@)
manager = new gas_manager.Manager(config)
fileId = @.fileId || config[@.env].fileId
workdir = @.workdir || config[@.env].workdir
run = @.run
fileId or throw new Error("please specify fileId")
manager.getProject fileId, (err, project) ->
throw err if err
tasks = []
files = project.getFiles()
if not is_unique(file.name.toLowerCase() for file in files)
throw new Error("we won't export the files because some file name is not unique")
for file in files
tasks.push do (file = file) -> (cb) ->
ext = if file.type == "server_js" then ".js" else ".html"
outPath = path.resolve(workdir, file.name + ext)
if run
fs.writeFile outPath, file.source, (err) ->
cb(err, [file.name, outPath])
else
cb(err, [file.name, outPath])
async.parallel tasks, (err, pathes) ->
throw err if err
async.each pathes, (path, cb) ->
console.log "#{path[0]} -> #{path[1]}"
cb()
, (err) ->
throw err if err
put = (options) ->
config = util.loadConfig(@)
manager = new gas_manager.Manager(config)
fileId = @.fileId || config[@.env].fileId
workdir = @.workdir || config[@.env].workdir
run = @.run
local_files = []
for file in fs.readdirSync(workdir)
match = file.match /^(.+)\.(?:([jg]s)|html)$/i
filepath = path.resolve(workdir, file)
if match and fs.statSync(filepath).isFile()
name = match[1]
is_js = match[2]
local_files.push {
name: name
type: (if is_js then "server_js" else "html")
path: filepath
}
if not is_unique(file.name.toLowerCase() for file in local_files)
throw new Error("we won't upload the files because some file name is not unique")
manager.getProject fileId, (err, project) ->
throw err if err
filebag = {}
for file in project.getFiles()
filebag[file.name] = true
for info in local_files
if filebag[info.name]
remoteType = project.getFileByName(info.name).type
if info.type != remoteType
throw new Error("file type conflict between local (#{info.type}) and remote (#{remoteType}) for #{name}")
filebag[info.name] = false
project.deleteFile(info.name)
project.addFile info.name, info.type, if run then fs.readFileSync(info.path, {encoding: 'utf-8'}) else "<omit>"
console.log("#{if filebag[info.name] then 'update' else 'create'} #{info.name} (#{info.type})")
for name, remain of filebag
if remain
project.deleteFile(name)
console.log("delete #{name}")
if run
project.deploy (err) ->
throw err if err
list = (options) ->
config = util.loadConfig(@)
manager = new gas_manager.Manager(config)
manager.tokenProvider.getToken (err, accessToken) ->
throw err if err
request.get {
url: "https://www.googleapis.com/drive/v2/files?q=mimeType%3D'application%2Fvnd.google-apps.script'+and+'me'+in+owners"
qs: {'access_token': accessToken}
}, (error, response, body) ->
if !error && response.statusCode == 200
for item in JSON.parse(body).items
console.log("#{item.title}: #{item.id}")
return
console.log(error, response)
throw new Error("failed to request")
return
is_unique = (arr) ->
bag = {}
for x in arr
if bag[x]
return false
bag[x] = true
return true
main()
@snipsnipsnip
Copy link
Author

プロジェクトにあるソースファイル一覧を取得したいだけなのにソース全文まで一緒についてくるってこのAPIどうよ

@snipsnipsnip
Copy link
Author

getもputも危険なので標準でdry-run(行うであろう動作の表示だけして、ファイルの書き込みは行わない)にしてある
実際に実行するためにはgitにならって -f / --force オプションにしようかと思ったが、
既にfileIdにとられていたのでオプション名は -r / --run オプションとした

@snipsnipsnip
Copy link
Author

設定ファイルは半端に互換性がある(トークンやenvironment, fileIdなどはそのまま)のでそのままにしてある
何よりこの懇切丁寧なinitウィザードを再利用しないのは勿体無い
ファイル一つ一つのパスとのマッピングを管理せず、単に「インポート/エクスポートするディレクトリ」を一つ覚えるだけにしたところが非互換点

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment