Skip to content

Commit b92ddb7

Browse files
authored
Merge pull request #748 from ericpromislow/644-expand-find-home-dir-logic
Expand the concept of the homeDir on Windows
2 parents 035b5a4 + ad25e51 commit b92ddb7

File tree

2 files changed

+166
-35
lines changed

2 files changed

+166
-35
lines changed

src/config.ts

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -516,34 +516,70 @@ export function bufferFromFileOrString(file?: string, data?: string): Buffer | n
516516
return null;
517517
}
518518

519+
function dropDuplicatesAndNils(a: string[]): string[] {
520+
return a.reduce(
521+
(acceptedValues, currentValue) => {
522+
// Good-enough algorithm for reducing a small (3 items at this point) array into an ordered list
523+
// of unique non-empty strings.
524+
if (currentValue && !acceptedValues.includes(currentValue)) {
525+
return acceptedValues.concat(currentValue);
526+
} else {
527+
return acceptedValues;
528+
}
529+
},
530+
[] as string[],
531+
);
532+
}
533+
519534
// Only public for testing.
520535
export function findHomeDir(): string | null {
521-
if (process.env.HOME) {
536+
if (process.platform !== 'win32') {
537+
if (process.env.HOME) {
538+
try {
539+
fs.accessSync(process.env.HOME);
540+
return process.env.HOME;
541+
// tslint:disable-next-line:no-empty
542+
} catch (ignore) {}
543+
}
544+
return null;
545+
}
546+
// $HOME is always favoured, but the k8s go-client prefers the other two env vars
547+
// differently depending on whether .kube/config exists or not.
548+
const homeDrivePath =
549+
process.env.HOMEDRIVE && process.env.HOMEPATH
550+
? path.join(process.env.HOMEDRIVE, process.env.HOMEPATH)
551+
: '';
552+
const homePath = process.env.HOME || '';
553+
const userProfile = process.env.USERPROFILE || '';
554+
const favourHomeDrivePathList: string[] = dropDuplicatesAndNils([homePath, homeDrivePath, userProfile]);
555+
const favourUserProfileList: string[] = dropDuplicatesAndNils([homePath, userProfile, homeDrivePath]);
556+
// 1. the first of %HOME%, %HOMEDRIVE%%HOMEPATH%, %USERPROFILE% containing a `.kube\config` file is returned.
557+
for (const dir of favourHomeDrivePathList) {
522558
try {
523-
fs.accessSync(process.env.HOME);
524-
return process.env.HOME;
559+
fs.accessSync(path.join(dir, '.kube', 'config'));
560+
return dir;
525561
// tslint:disable-next-line:no-empty
526562
} catch (ignore) {}
527563
}
528-
if (process.platform !== 'win32') {
529-
return null;
530-
}
531-
if (process.env.HOMEDRIVE && process.env.HOMEPATH) {
532-
const dir = path.join(process.env.HOMEDRIVE, process.env.HOMEPATH);
564+
// 2. ...the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists and is writeable is returned
565+
for (const dir of favourUserProfileList) {
533566
try {
534-
fs.accessSync(dir);
567+
fs.accessSync(dir, fs.constants.W_OK);
535568
return dir;
536569
// tslint:disable-next-line:no-empty
537570
} catch (ignore) {}
538571
}
539-
if (process.env.USERPROFILE) {
572+
// 3. ...the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists is returned.
573+
for (const dir of favourUserProfileList) {
540574
try {
541-
fs.accessSync(process.env.USERPROFILE);
542-
return process.env.USERPROFILE;
575+
fs.accessSync(dir);
576+
return dir;
543577
// tslint:disable-next-line:no-empty
544578
} catch (ignore) {}
545579
}
546-
return null;
580+
// 4. if none of those locations exists, the first of
581+
// %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that is set is returned.
582+
return favourUserProfileList[0] || null;
547583
}
548584

549585
export interface Named {

src/config_test.ts

Lines changed: 117 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -461,39 +461,134 @@ describe('KubeConfig', () => {
461461
process.env.HOMEPATH = originalEnvVars.HOMEPATH;
462462
});
463463

464-
it('should return null if no home is present', () => {
464+
it('should return null if no home-ish env vars are set', () => {
465465
const dir = findHomeDir();
466466
expect(dir).to.equal(null);
467467
});
468468

469-
it('should load from HOMEDRIVE/HOMEPATH if present', () => {
470-
process.env.HOMEDRIVE = 'foo';
471-
process.env.HOMEPATH = 'bar';
472-
const dir = join(process.env.HOMEDRIVE, process.env.HOMEPATH);
473-
const arg = {};
474-
arg[dir] = { config: 'data' };
475-
mockfs(arg);
469+
describe('look for an existing .kube/config', () => {
470+
let allDirs;
471+
let homeDrive;
472+
beforeEach(() => {
473+
allDirs = {};
474+
process.env.HOME = 'home';
475+
process.env.HOMEDRIVE = 'drive';
476+
process.env.HOMEPATH = 'a-path';
477+
process.env.USERPROFILE = 'a-userprofile';
478+
homeDrive = join(process.env.HOMEDRIVE, process.env.HOMEPATH);
479+
allDirs[process.env.HOME] = {};
480+
allDirs[homeDrive] = {};
481+
allDirs[process.env.USERPROFILE] = {};
482+
});
483+
it('should load from HOME if present', () => {
484+
const dir = process.env.HOME as string;
485+
allDirs[dir]['.kube'] = { config: 'data' };
486+
mockfs(allDirs);
476487

477-
const home = findHomeDir();
488+
const home = findHomeDir();
478489

479-
mockfs.restore();
480-
expect(home).to.equal(dir);
490+
mockfs.restore();
491+
expect(home).to.equal(dir);
492+
});
493+
it('should favor HOME when present', () => {
494+
const dir = process.env.HOME as string;
495+
allDirs[dir]['.kube'] = { config: 'data' };
496+
allDirs[homeDrive]['.kube'] = { config: 'data' };
497+
allDirs[process.env.USERPROFILE as string]['.kube'] = { config: 'data' };
498+
mockfs(allDirs);
499+
500+
const home = findHomeDir();
501+
502+
mockfs.restore();
503+
expect(home).to.equal(dir);
504+
});
505+
506+
it('should load from HOMEDRIVE/HOMEPATH if present', () => {
507+
const dir = homeDrive;
508+
allDirs[dir]['.kube'] = { config: 'data' };
509+
mockfs(allDirs);
510+
511+
const home = findHomeDir();
512+
513+
mockfs.restore();
514+
expect(home).to.equal(dir);
515+
});
516+
517+
it('should favor HOMEDRIVE/HOMEPATH over USERPROFILE', () => {
518+
const dir = homeDrive;
519+
allDirs[dir]['.kube'] = { config: 'data' };
520+
allDirs[process.env.USERPROFILE as string]['.kube'] = { config: 'data' };
521+
mockfs(allDirs);
522+
523+
const home = findHomeDir();
524+
525+
mockfs.restore();
526+
expect(home).to.equal(dir);
527+
});
528+
529+
it('should load from USERPROFILE if present', () => {
530+
const dir = process.env.USERPROFILE as string;
531+
allDirs[dir]['.kube'] = { config: 'data' };
532+
mockfs(allDirs);
533+
534+
const home = findHomeDir();
535+
536+
mockfs.restore();
537+
expect(home).to.equal(dir);
538+
});
481539
});
482540

483-
it('should load from USERPROFILE if present', () => {
484-
const dir = 'someplace';
541+
// Just test for existence,but this will include the writeability order
542+
describe('look for an existing directory', () => {
543+
let allDirs;
544+
let homeDrive;
545+
beforeEach(() => {
546+
allDirs = {};
547+
process.env.HOME = 'home';
548+
process.env.HOMEDRIVE = 'drive';
549+
process.env.HOMEPATH = 'a-path';
550+
process.env.USERPROFILE = 'a-userprofile';
551+
homeDrive = join(process.env.HOMEDRIVE, process.env.HOMEPATH);
552+
});
553+
it('should load from HOME if present', () => {
554+
allDirs[process.env.HOME as string] = 'data';
555+
allDirs[homeDrive] = 'data';
556+
allDirs[process.env.USERPROFILE as string] = 'data';
557+
const dir = process.env.HOME;
558+
mockfs(allDirs);
485559

486-
process.env.HOMEDRIVE = 'foo';
487-
process.env.HOMEPATH = 'bar';
488-
process.env.USERPROFILE = dir;
489-
const arg = {};
490-
arg[dir] = { config: 'data' };
491-
mockfs(arg);
560+
const home = findHomeDir();
492561

493-
const home = findHomeDir();
562+
mockfs.restore();
563+
expect(home).to.equal(dir);
564+
});
565+
it('should load from USERPROFILE if present', () => {
566+
allDirs[homeDrive] = 'data';
567+
allDirs[process.env.USERPROFILE as string] = 'data';
568+
mockfs(allDirs);
494569

495-
mockfs.restore();
496-
expect(home).to.equal(dir);
570+
const home = findHomeDir();
571+
572+
mockfs.restore();
573+
expect(home).to.equal(process.env.USERPROFILE);
574+
});
575+
it('should load from homeDrive if present', () => {
576+
allDirs[homeDrive] = 'data';
577+
mockfs(allDirs);
578+
579+
const home = findHomeDir();
580+
581+
mockfs.restore();
582+
expect(home).to.equal(homeDrive);
583+
});
584+
it('should return HOME when no home-ish directories are present', () => {
585+
mockfs({});
586+
587+
const home = findHomeDir();
588+
589+
mockfs.restore();
590+
expect(home).to.equal(process.env.HOME);
591+
});
497592
});
498593
});
499594

0 commit comments

Comments
 (0)