Skip to content

Instantly share code, notes, and snippets.

@esnya
Created April 27, 2015 04:24
Show Gist options
  • Save esnya/433333a9e1911d8ec45f to your computer and use it in GitHub Desktop.
Save esnya/433333a9e1911d8ec45f to your computer and use it in GitHub Desktop.
Linux で SoftEther VPN の更新があればダウンロードしてビルドして配置する何か
import std.algorithm;
import std.conv;
import std.exception;
import std.getopt;
import std.net.curl;
import std.path;
import std.process;
import std.range;
import std.regex;
import std.stdio;
import std.typecons;
auto currentVersion() {
auto pipe = pipeProcess(["vpncmd"]);
auto versionLine = pipe.stdout.byLine.drop(2).front;
pipe.stdin.close();
pipe.stdout.close();
pipe.stderr.close();
return Tuple!(
uint, "major_version",
uint, "minor_version",
uint, "build")(
cast(uint[3])versionLine.match(`Version ([0-9]+)\.([0-9]+) Build ([0-9]+)`)
.enforce()
.captures.drop(1)
.map!(a => a.to!uint())()
.array
[0 .. 3]
);
}
auto download(S)(S url) {
import std.file;
url = `http://jp.softether-download.com` ~ url;
auto path = buildPath(tempDir, url.baseName());
writeln("Download ", url, " -> ", path);
std.net.curl.download(url, path);
return path;
}
auto extract(S)(S path) {
import std.file;
enforce(spawnProcess(["tar", "-xvf", path, "-C", tempDir]).wait() == 0);
return buildPath(tempDir, path.baseName().find("vpn").until('-').array.to!string());
}
auto build(S)(S dir) {
enforce(spawnProcess(["make"], null, Config.none, dir).wait() == 0);
return dir;
}
auto copy(S)(S dir) {
import std.file;
void _copy(R)(R files) {
if (files.empty) return;
auto src = files.front[0];
auto dst = files.front[1];
string backup;
uint n;
do {
enforce(n >= 0);
backup = buildPath(tempDir, `backup-` ~ (n++).to!string() ~ '-' ~ dst.baseName);
} while (backup.exists);
if (dst.exists) {
writeln("Backup ", dst, " -> ", backup);
dst.copy(backup);
}
scope (exit) {
if (backup.exists) {
writeln("Remove backup ", backup);
backup.remove();
}
}
scope (failure) {
if (backup.exists) {
writeln("Rollback ", backup, " -> ", dst);
backup.copy(dst);
}
}
writeln("Copy ", src, " -> ", dst);
src.copy(dst);
_copy(files.drop(1));
}
_copy(["vpncmd", "vpnserver", "vpnclient"]
.map!(a => tuple(a, buildPath(dir, a)))()
.filter!(a => a[1].exists())()
.map!(a => tuple(a[1], buildPath(`/usr/local/bin`, a[0])))()
);
}
void update(R)(R revision, string product) {
get(`http://jp.softether-download.com`
~ revision.path
~ `Linux/SoftEther_VPN_` ~ product
~ `/64bit_-_Intel_x64_or_AMD64/`)
.match(regex(`href="([^"]+\.tar\.gz)"`, "i"))
.enforce()
.captures[1]
.download()
.extract()
.build()
.copy()
;
}
void main(string[] args) {
bool force;
args.getopt("force|f", &force);
auto current = currentVersion;
auto list = get("http://jp.softether-download.com/files/softether/");
alias Revision = Tuple!(
string, "path",
uint, "major_version",
uint, "minor_version",
uint, "build",
string, "release",
uint, "year",
uint, "month",
uint, "date"
);
auto revisions = list.matchAll(`/files/softether/v([0-9]+)\.([0-9]+)-([0-9]+)-([0-9a-z]+)-([0-9]+)\.([0-9]+)\.([0-9]+)-tree/`)
.map!`a.captures`()
.map!((c) {
Revision r;
foreach (i, ref v; r) {
v = c[i].to!(typeof(v))();
}
return r;
})()
.array;
revisions.sort!`a.build > b.build`();
auto latest = revisions.front;
if (force || latest.build > current.build) {
writefln("Update: v%s.%s %s -> v%s.%s %s",
current.major_version, current.minor_version, current.build,
latest.major_version, latest.minor_version, latest.build);
update(latest, "Server");
update(latest, "Client");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment