Skip to content

Commit f6c1b34

Browse files
committed
Expand the concept of the homeDir on Windows
Allow env vars HOME, HOMEDRIVE/HOMEPATH, and USERCONFIG to all denote a possible home directory Favor an existing .kube/config file Favor existing, writable home-ish directories And finally favor existing home-ish directories (which at this point aren't writable, but that's how the Kubernetes go-client does it). Use the same determination of the .kube/config-based home dir on Windows that the
1 parent d44fa64 commit f6c1b34

File tree

2 files changed

+149
-33
lines changed

2 files changed

+149
-33
lines changed

src/config.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -518,32 +518,45 @@ export function bufferFromFileOrString(file?: string, data?: string): Buffer | n
518518

519519
// Only public for testing.
520520
export function findHomeDir(): string | null {
521-
if (process.env.HOME) {
522-
try {
523-
fs.accessSync(process.env.HOME);
524-
return process.env.HOME;
525-
// tslint:disable-next-line:no-empty
526-
} catch (ignore) {}
527-
}
528521
if (process.platform !== 'win32') {
522+
if (process.env.HOME) {
523+
try {
524+
fs.accessSync(process.env.HOME);
525+
return process.env.HOME;
526+
// tslint:disable-next-line:no-empty
527+
} catch (ignore) {}
528+
}
529529
return null;
530530
}
531-
if (process.env.HOMEDRIVE && process.env.HOMEPATH) {
532-
const dir = path.join(process.env.HOMEDRIVE, process.env.HOMEPATH);
531+
const homeDrivePath = process.env.HOMEDRIVE && process.env.HOMEPATH ? path.join(process.env.HOMEDRIVE, process.env.HOMEPATH) : null;
532+
const dirList1 = [process.env.HOME, homeDrivePath, process.env.USERPROFILE].filter(x => x);
533+
const dirList2 = [process.env.HOME, process.env.USERPROFILE, homeDrivePath].filter(x => x);
534+
// 1. the first of %HOME%, %HOMEDRIVE%%HOMEPATH%, %USERPROFILE% containing a `.kube\config` file is returned.
535+
for (const dir of dirList1) {
533536
try {
534-
fs.accessSync(dir);
537+
fs.accessSync(path.join(dir, '.kube', 'config'));
535538
return dir;
536539
// tslint:disable-next-line:no-empty
537540
} catch (ignore) {}
538541
}
539-
if (process.env.USERPROFILE) {
542+
// 2. ...the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists and is writeable is returned
543+
for (const dir of dirList2) {
544+
const lstat = fs.lstatSync(dir, { throwIfNoEntry: false });
545+
// tslint:disable-next-line:no-bitwise
546+
if (lstat && (lstat.mode & fs.constants.S_IXUSR) === fs.constants.S_IXUSR) {
547+
return dir;
548+
}
549+
}
550+
// 3. ...the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists is returned.
551+
for (const dir of dirList2) {
540552
try {
541-
fs.accessSync(process.env.USERPROFILE);
542-
return process.env.USERPROFILE;
553+
fs.accessSync(dir);
554+
return dir;
543555
// tslint:disable-next-line:no-empty
544556
} catch (ignore) {}
545557
}
546-
return null;
558+
// 4. if none of those locations exists, the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that is set is returned.
559+
return dirList2[0] ?? null;
547560
}
548561

549562
export interface Named {

src/config_test.ts

Lines changed: 122 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -466,34 +466,137 @@ describe('KubeConfig', () => {
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+
before(() => {
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;
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;
495+
allDirs[dir]['.kube'] = { config: 'data' };
496+
allDirs[homeDrive]['.kube'] = { config: 'data' };
497+
allDirs[process.env.USERPROFILE]['.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(arg);
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]['.kube'] = { config: 'data' };
521+
mockfs(arg);
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;
531+
allDirs[dir]['.kube'] = { config: 'data' };
532+
mockfs(arg);
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 writability order
542+
describe('look for an existing directory', () => {
543+
let allDirs;
544+
let homeDrive;
545+
before(() => {
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 = {
555+
[process.env.HOME]: 'data',
556+
[homeDrive]: 'data',
557+
[process.env.USERPROFILE]: 'data'
558+
}
559+
const dir = process.env.HOME
560+
mockfs(allDirs);
561+
562+
const home = findHomeDir();
485563

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);
564+
mockfs.restore();
565+
expect(home).to.equal(dir);
566+
});
567+
it('should load from homeDrive if present', () => {
568+
allDirs = {
569+
[homeDrive]: 'data',
570+
[process.env.USERPROFILE]: 'data'
571+
}
572+
const dir = process.env.HOME
573+
mockfs(allDirs);
574+
575+
const home = findHomeDir();
576+
577+
mockfs.restore();
578+
expect(home).to.equal(homeDrive);
579+
});
580+
it('should load from USERPROFILE if present', () => {
581+
allDirs = {
582+
[process.env.USERPROFILE]: 'data'
583+
}
584+
const dir = process.env.USERPROFILE;
585+
mockfs(allDirs);
586+
587+
const home = findHomeDir();
588+
589+
mockfs.restore();
590+
expect(home).to.equal(dir);
591+
});
592+
});
593+
it('should return null if nothing is present', () => {
594+
mockfs({});
492595

493596
const home = findHomeDir();
494597

495598
mockfs.restore();
496-
expect(home).to.equal(dir);
599+
expect(home).to.equal(null);
497600
});
498601
});
499602

0 commit comments

Comments
 (0)