Skip to content

Commit

Permalink
fix: Auto eclcc seleciton based on build version
Browse files Browse the repository at this point in the history
Signed-off-by: Gordon Smith <gordonjsmith@gmail.com>
  • Loading branch information
GordonSmith committed May 26, 2018
1 parent 64d36be commit 208bb5d
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 58 deletions.
2 changes: 1 addition & 1 deletion packages/comms/src/clienttools/eclMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ export class Workspace {
}

primeClientTools(): Promise<this> {
return locateClientTools(this._eclccPath, this._workspacePath).then(clientTools => {
return locateClientTools(this._eclccPath, "", this._workspacePath).then(clientTools => {
this._clientTools = clientTools;
return clientTools.paths();
}).then(paths => {
Expand Down
133 changes: 82 additions & 51 deletions packages/comms/src/clienttools/eclcc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as cp from "child_process";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as semver from "semver";
import * as tmp from "tmp";

import { scopedLogger } from "@hpcc-js/util";
Expand All @@ -13,6 +12,50 @@ import { attachWorkspace, Workspace } from "./eclMeta";
const logger = scopedLogger("clienttools/eclcc");
const exeExt = os.type() === "Windows_NT" ? ".exe" : "";

export class Version {
readonly prefix: string = "";
readonly major: number = 0;
readonly minor: number = 0;
readonly patch: number = 0;
readonly postfix: string = "";

constructor(build: string) {
const parts = build.split(" ");
if (parts.length) {
const match = /(?:(\w+)_)?(\d+)\.(\d+)\.(\d+)(?:-(.*))?/.exec(parts[parts.length - 1]);
if (match) {
this.prefix = match[1] || "";
this.major = +match[2] || 0;
this.minor = +match[3] || 0;
this.patch = +match[4] || 0;
this.postfix = match[5] || "";
}
}
}

parse(build: string) {
}

exists(): boolean {
return this.major !== 0 || this.minor !== 0 || this.patch !== 0 || this.postfix !== "";
}

compare(other: Version): number {
if (this.major > other.major) return 1;
if (this.major < other.major) return -1;
if (this.minor > other.minor) return 1;
if (this.minor < other.minor) return -1;
if (this.patch > other.patch) return 1;
if (this.patch < other.patch) return -1;
if (this.postfix === "" && other.postfix !== "") return 1;
return this.postfix.localeCompare(other.postfix);
}

toString(): string {
return `${this.prefix}_${this.major}.${this.minor}.${this.patch}-${this.postfix}`;
}
}

interface IExecFile {
stderr: string;
stdout: string;
Expand Down Expand Up @@ -162,20 +205,20 @@ export class ClientTools {
protected includeFolders: string[];
protected _legacyMode: boolean;
protected _args: string[];
protected _versionPrefix: string;
protected _version: string;
protected _version: Version;

constructor(eclccPath: string, cwd?: string, includeFolders: string[] = [], legacyMode: boolean = false, args: string[] = []) {
constructor(eclccPath: string, cwd?: string, includeFolders: string[] = [], legacyMode: boolean = false, args: string[] = [], version?: Version) {
this.eclccPath = eclccPath;
this.binPath = path.dirname(this.eclccPath);
this.cwd = path.normalize(cwd || this.binPath);
this.includeFolders = includeFolders;
this._legacyMode = legacyMode;
this._args = args;
this._version = version!;
}

clone(cwd?: string, includeFolders?: string[], legacyMode: boolean = false, args: string[] = []) {
return new ClientTools(this.eclccPath, cwd, includeFolders, legacyMode, args);
return new ClientTools(this.eclccPath, cwd, includeFolders, legacyMode, args, this._version);
}

exists(filePath: string) {
Expand All @@ -196,34 +239,17 @@ export class ClientTools {
})).concat(additionalItems);
}

version() {
version(): Promise<Version> {
if (this._version) {
return Promise.resolve(this._version);
}
return this.execFile(this.eclccPath, this.binPath, this.args(["--version"]), "eclcc", `Cannot find ${this.eclccPath}`).then((response: IExecFile) => {
if (response && response.stdout && response.stdout.length) {
const versions = response.stdout.split(" ");
if (versions.length > 1) {
const fullVersionParts = versions[1].split("_");
if (fullVersionParts.length > 1) {
const versionPrefix = fullVersionParts.shift();
const version = fullVersionParts.join("_");
if (semver.valid(version)) {
this._versionPrefix = versionPrefix!;
this._version = version;
}
}
} else if (versions.length) {
if (semver.valid(versions[0])) {
this._version = versions[0];
}
}
}
return this.execFile(this.eclccPath, this.binPath, this.args(["--version"]), "eclcc", `Cannot find ${this.eclccPath}`).then((response: IExecFile): Version => {
this._version = new Version(response.stdout);
return this._version;
});
}

versionSync() {
versionSync(): Version {
return this._version;
}

Expand Down Expand Up @@ -326,67 +352,63 @@ export class ClientTools {
}
}

const allClientToolsCache: ClientTools[] = [];
function locateClientToolsInFolder(rootFolder: string): Array<Promise<any>> {
const promiseArray: Array<Promise<any>> = [];
function locateClientToolsInFolder(rootFolder: string, clientTools: ClientTools[]) {
if (rootFolder) {
const hpccSystemsFolder = path.join(rootFolder, "HPCCSystems");
if (fs.existsSync(hpccSystemsFolder) && fs.statSync(hpccSystemsFolder).isDirectory()) {
if (os.type() !== "Windows_NT") {
const eclccPath = path.join(hpccSystemsFolder, "bin", "eclcc");
if (fs.existsSync(eclccPath)) {
const clientTools = new ClientTools(eclccPath);
allClientToolsCache.push(clientTools);
promiseArray.push(clientTools.version());
clientTools.push(new ClientTools(eclccPath));
}
}
fs.readdirSync(hpccSystemsFolder).forEach((versionFolder) => {
const eclccPath = path.join(hpccSystemsFolder, versionFolder, "clienttools", "bin", "eclcc" + exeExt);
if (fs.existsSync(eclccPath)) {
const name = path.basename(versionFolder);
if (semver.valid(name)) {
const clientTools = new ClientTools(eclccPath);
allClientToolsCache.push(clientTools);
promiseArray.push(clientTools.version());
const version = new Version(name);
if (version.exists()) {
clientTools.push(new ClientTools(eclccPath));
}
}
});
}
}
return promiseArray;
}

let allClientToolsCache: Promise<ClientTools[]>;
export function locateAllClientTools() {
if (allClientToolsCache.length) return Promise.resolve(allClientToolsCache);
let promiseArray: Array<Promise<any>> = [];
if (allClientToolsCache) return allClientToolsCache;
const clientTools: ClientTools[] = [];
switch (os.type()) {
case "Windows_NT":
const rootFolder86 = process.env["ProgramFiles(x86)"] || "";
if (rootFolder86) {
promiseArray = promiseArray.concat(locateClientToolsInFolder(rootFolder86));
locateClientToolsInFolder(rootFolder86, clientTools);
}
const rootFolder = process.env["ProgramFiles"] || "";
if (rootFolder) {
promiseArray = promiseArray.concat(locateClientToolsInFolder(rootFolder));
locateClientToolsInFolder(rootFolder, clientTools);
}
if (!rootFolder86 && !rootFolder) {
promiseArray = promiseArray.concat(locateClientToolsInFolder("c:\\Program Files (x86)"));
locateClientToolsInFolder("c:\\Program Files (x86)", clientTools);
}
break;
case "Linux":
case "Darwin":
promiseArray = promiseArray.concat(locateClientToolsInFolder("/opt"));
locateClientToolsInFolder("/opt", clientTools);
break;
default:
break;
}

return Promise.all(promiseArray).then(() => {
allClientToolsCache.sort((l: ClientTools, r: ClientTools) => {
return semver.compare(r.versionSync(), l.versionSync());
allClientToolsCache = Promise.all(clientTools.map(ct => ct.version())).then(() => {
clientTools.sort((l: ClientTools, r: ClientTools) => {
return r.versionSync().compare(l.versionSync());
});
return allClientToolsCache;
return clientTools;
});
return allClientToolsCache;
}

let eclccPathMsg = "";
Expand All @@ -398,17 +420,26 @@ function logEclccPath(eclccPath: string) {
}
}

export function locateClientTools(overridePath: string = "", cwd: string = ".", includeFolders: string[] = [], legacyMode: boolean = false): Promise<ClientTools> {
export function locateClientTools(overridePath: string = "", build: string = "", cwd: string = ".", includeFolders: string[] = [], legacyMode: boolean = false): Promise<ClientTools> {
if (overridePath && fs.existsSync(overridePath)) {
logEclccPath(overridePath);
return Promise.resolve(new ClientTools(overridePath, cwd, includeFolders, legacyMode));
}
return locateAllClientTools().then((allClientToolsCache2) => {
// TODO find best match ---
if (!allClientToolsCache2.length) {
throw new Error("Unable to locate ECL Client Tools.");
}
logEclccPath(allClientToolsCache2[0].eclccPath);
return allClientToolsCache2[0].clone(cwd, includeFolders, legacyMode);
const buildVersion = new Version(build);
let latest: ClientTools | undefined;
let bestMajor: ClientTools | undefined;
for (const ct of allClientToolsCache2) {
const ctVersion = ct.versionSync();
if (!latest) latest = ct;
if (!bestMajor && buildVersion.major === ctVersion.major) bestMajor = ct;
if (buildVersion.major === ctVersion.major && buildVersion.minor === ctVersion.minor) return ct;
}
const best: ClientTools = bestMajor || latest!;
logEclccPath(best.eclccPath);
return best.clone(cwd, includeFolders, legacyMode);
});
}
2 changes: 1 addition & 1 deletion packages/comms/src/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ if (typeof root.btoa === "undefined") {
export * from "./index-common";

// Client Tools ---
export { EclccErrors, locateAllClientTools, locateClientTools, IECLErrorWarning } from "./clienttools/eclcc";
export { EclccErrors, locateAllClientTools, locateClientTools, IECLErrorWarning, Version } from "./clienttools/eclcc";
export { attachWorkspace, qualifiedIDBoundary, ECLScope } from "./clienttools/eclMeta";
58 changes: 53 additions & 5 deletions tests/test-comms/src/clienttools/eclcc.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,64 @@
import { expect } from "chai";
import { isBrowser } from "../testLib";

import { locateClientTools } from "@hpcc-js/comms";
import { locateClientTools, Version } from "@hpcc-js/comms";

function test(build: string, prefix: string, major: number, minor: number, patch: number, postfix: string): boolean {
const version = new Version(build);
return version.prefix === prefix && version.major === major && version.minor === minor && version.patch === patch && version.postfix === postfix;
}

function logVersion(build: string): Promise<void> {
return locateClientTools("", build).then(ct => {
return ct.version().then(version => {
console.log(`${build} => ${version.toString()}`);
});
});
}

describe("eclcc", function () {
it.only("basic", function () {
if (!isBrowser()) {
if (!isBrowser()) {
it("basic", function () {
expect(locateClientTools).to.be.a("function");
return locateClientTools().then(clienttools => {
}).catch(e => {
// No eclcc on travis...
});
}
});
});

it("version", function () {
expect(test("10.11.12", "", 10, 11, 12, "")).to.be.true;
expect(test("community_4.0.0-9rc", "community", 4, 0, 0, "9rc")).to.be.true;
expect(test("community_4.0.0-rc9", "community", 4, 0, 0, "rc9")).to.be.true;
expect(test("community_4.0.0-rc9[abc]", "community", 4, 0, 0, "rc9[abc]")).to.be.true;
expect(test("community_4.0.0-rc9[community_4.0.0-rc9-4-g826364-dirty]", "community", 4, 0, 0, "rc9[community_4.0.0-rc9-4-g826364-dirty]")).to.be.true;
expect(test("community_54.10.10", "community", 54, 10, 10, "")).to.be.true;
expect(test("6.4.14 community_6.4.14-1", "community", 6, 4, 14, "1")).to.be.true;
});

it("version compare", function () {
const version5_6_8 = new Version("5.6.8");
const version6_6_8 = new Version("6.6.8");
expect(version5_6_8.compare(version6_6_8)).to.be.lessThan(0);
expect(version6_6_8.compare(version5_6_8)).to.be.greaterThan(0);
expect(version6_6_8.compare(version6_6_8)).to.equal(0);
const version6_6_8rc1 = new Version("6.6.8-rc1");
expect(version6_6_8.compare(version6_6_8rc1)).to.greaterThan(0);
const version5_6_8rc1 = new Version("5.6.8-rc1");
const version5_6_8rc2 = new Version("5.6.8-rc2");
expect(version5_6_8rc1.compare(version5_6_8rc2)).to.lessThan(0);
});

it.skip("eclcc locate", function () {
return Promise.all([
logVersion("comms_60.60.0"),
logVersion("comms_6.18.0"),
logVersion("comms_6.13.0"),
logVersion("comms_6.6.0"),
logVersion("comms_6.0.0"),
logVersion("comms_5.10.0"),
logVersion("comms_5.0.0")
]);
});
}
});

0 comments on commit 208bb5d

Please sign in to comment.