Created
December 23, 2013 22:13
-
-
Save snipsnipsnip/8105743 to your computer and use it in GitHub Desktop.
gas-managerが柔軟すぎて馴染めなかったのでmanager部分だけ取り出してバグチェックとか取っ払ってコマンドインタフェースをコピペしながら再発明した
結構注意点が多くてつらい
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
getもputも危険なので標準でdry-run(行うであろう動作の表示だけして、ファイルの書き込みは行わない)にしてある
実際に実行するためにはgitにならって -f / --force
オプションにしようかと思ったが、
既にfileIdにとられていたのでオプション名は -r / --run
オプションとした
設定ファイルは半端に互換性がある(トークンやenvironment, fileIdなどはそのまま)のでそのままにしてある
何よりこの懇切丁寧なinitウィザードを再利用しないのは勿体無い
ファイル一つ一つのパスとのマッピングを管理せず、単に「インポート/エクスポートするディレクトリ」を一つ覚えるだけにしたところが非互換点
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
プロジェクトにあるソースファイル一覧を取得したいだけなのにソース全文まで一緒についてくるってこのAPIどうよ