工作環境有不少Web Farm主機,部署程式時需要將一或多個檔案同步複製到多台主機上,依上線流程需產生指令檔交給OP人員執行。這種需求用COPY、XCOPY或ROBOCOPY指令寫成批次檔是最直覺有效的做法,但以「將四個檔案複製到八台主機」為例,需寫成32條指令,沒營養又躲不掉的枯躁苦工,交給機器人才是王道。
輸入IP清單轉成一串指令的小工具,印象裡我寫過WinForm版也寫過WebForm版,最近有類似需求,卻不幸遇到記憶斷層,怎麼也想不起程式放哪… Orz 心一橫,索性拿它當成練功題材,花了點時間寫成純前端網頁版,順手分享出來。
操作介面如上圖,設好來源項目與目標IP按個鈕即展開成批次指令,亦提供複製到剪貼簿的功能。Script Template是產生指令的樣版字串,{0}代表來源清單的項目,{1}則是對象機器IP,另外有個{0:path}語法可以只取來源項目資料夾路徑,方便組裝COPY指令。主機清單通常是固定的,右上方我放了快捷鈕,可直接帶入預先定義的主機IP清單,IP資料由一個JavaScript物件提供,使用時請自行調整成實際在用的群組名稱與IP。
var groups = {
"GRP1": "191.168.1.1\n192.168.1.2",
"GRP2": "10.10.100.1\n10.10.100.2\n10.10.100.3\n10.10.100.4"
}
程式靠Angular MVVM配合JavsScript輕鬆搞定,沒什麼技術含量,寫成網頁的好處是只需單一檔案,丟上網路人人可用,懂JavaScript就能修改,差不多是路邊奉茶的概念(笑)。
程式碼如下,同時我也放上JSBin了,有需要的朋友請自取。
<!DOCTYPEhtml>
<htmlng-app="app">
<head>
<metacharset="utf-8">
<metaname="viewport"content="width=device-width">
<title>Copy Script Generator</title>
<style>
.deploy {
width: 1024px;
}
legend {
font-size: 9pt;
}
.list {
width: 100%;
margin: 6px 0;
}
.list td {
padding-right: 6px;
}
textarea {
max-width: 100%;
width: 100%;
height: 100px;
}
input {
max-width: 100%;
}
.op {
margin: 12px 0;
background-color: #ccc;
padding: 3px;
}
.result {
height: 200px;
}
.show-hide {
transition: all linear 0.5s;
}
.show-hide.ng-hide {
opacity: 0;
}
.txt-button {
color: blue;
text-decoration: underline;
cursor: pointer;
margin-right: 3px;
}
</style>
</head>
<body>
<divng-controller="ctrl"class="deploy"ng-cloakafa-loading-indicator="vm.IsBusy">
<h3>
Copy Script Generator by darkthread
</h3>
<div>
<tableclass="list">
<tr>
<td>Source Item</td>
<td>
Source IPs
<spanstyle="float: right">
IP Groups:
<spanng-repeat="(k,v) in vm.Groups"
class="txt-button"ng-click="vm.SetDest(k)">{{k}}</span>
</span>
</td>
</tr>
<tr>
<td>
<textareang-model="vm.SrcList"></textarea>
</td>
<td>
<textareang-model="vm.DstList"></textarea>
</td>
</tr>
</table>
</div>
<divclass="op">
<div>Script Template</div>
<textareang-model="vm.ScriptTmpl"style="height: 50px"></textarea>
<buttonng-click="vm.GenScript()">Generate Script</button>
<buttonng-click="vm.CopyScript()">Copy to Clipboard</button>
<spanclass="show-hide"ng-bind="vm.Msg"ng-show="vm.ShowMsg"></span>
</div>
<div>
<fieldset>
<legend>Scripts</legend>
<textareang-model="vm.Script"class="result"></textarea>
</fieldset>
</div>
</div>
<scriptsrc="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js">
</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.min.js">
</script>
<script>
//REF: http://stackoverflow.com/a/30810322/4335757
function copyTextToClipboard(text) {
var textArea = document.createElement("textarea");
textArea.style.position = 'fixed';
textArea.style.top = 0;
textArea.style.left = 0;
textArea.style.width = '2em';
textArea.style.height = '2em';
textArea.style.padding = 0;
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
textArea.style.background = 'transparent';
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
}
catch (err) {
console.log('Oops, unable to copy');
}
document.body.removeChild(textArea);
}
var groups = {
"GRP1": "191.168.1.1\n192.168.1.2",
"GRP2": "10.10.100.1\n10.10.100.2\n10.10.100.3\n10.10.100.4"
}
angular
.module("app", ["ngAnimate"])
.controller("ctrl", function($scope) {
function myViewModel() {
var self = this;
self.IsBusy = false;
self.SrcList = "scripts\\common.js\nscripts\\common.min.js\ncss\\style.css";
self.DstList = "192.168.1.1\n192.168.1.2";
self.ScriptTmpl = "copy d:\\WWW\\blah\\{0} \\\\{1}\\d$\\WWW\\blah\\{0:path} /Y";
self.ShowMsg = false;
self.GenScript = function() {
var self = this;
var srcAry = self.SrcList.split('\n');
var dstAry = self.DstList.split('\n');
var cmds = [];
$.each(srcAry, function(i, src) {
var p = src.split('\\');
p.pop();
var srcPath = p.length ? p.join('\\') : src;
$.each(dstAry, function(j, dst) {
cmds.push(self.ScriptTmpl
.replace(/[{]0[}]/g, src)
.replace(/[{]0:path[}]/g, srcPath)
.replace(/[{]1[}]/g, dst));
});
});
self.Script = cmds.join('\n') + "\n";
};
self.GenScript();
self.CopyScript = function() {
var self = this;
copyTextToClipboard(self.Script);
self.Msg = "Copied!";
self.ShowMsg = true;
setTimeout(function() {
self.Msg = "";
self.ShowMsg = false;
$scope.$digest();
}, 2000);
};
self.Groups = groups;
self.SetDest = function(grpName) {
var self = this;
self.DstList = groups[grpName];
};
}
$scope.vm = new myViewModel();
});
</script>
</body>
</html>
後記:小工具寫完沒幾天,NG2正式版就閃電問市惹… 所以,敬請期待「COPY指令產生器 in NG2」,Coming Soon~