1
1
import { exec as _exec } from 'child_process' ;
2
2
import colors = require( 'colors/safe' ) ;
3
- import { close as _close , open as _open , stat as _stat } from 'fs' ;
3
+ import fs = require( 'fs-extra' ) ;
4
+ import os = require( 'os' ) ;
5
+ import path = require( 'path' ) ;
4
6
import semver = require( 'semver' ) ;
5
7
import { promisify } from 'util' ;
6
- import { debug , print , warning } from '../lib/logging' ;
8
+ import { debug , print } from '../lib/logging' ;
7
9
import { formatAsBanner } from '../lib/util/console-formatters' ;
8
10
9
11
const ONE_DAY_IN_SECONDS = 1 * 24 * 60 * 60 ;
10
12
11
- const close = promisify ( _close ) ;
12
13
const exec = promisify ( _exec ) ;
13
- const open = promisify ( _open ) ;
14
- const stat = promisify ( _stat ) ;
15
14
16
15
export const DISPLAY_VERSION = `${ versionNumber ( ) } (build ${ commit ( ) } )` ;
17
16
@@ -23,23 +22,39 @@ function commit(): string {
23
22
return require ( '../build-info.json' ) . commit ;
24
23
}
25
24
26
- export class TimestampFile {
25
+ export class VersionCheckTTL {
26
+ public static timestampFilePath ( ) : string {
27
+ // Get the home directory from the OS, first. Fallback to $HOME.
28
+ const homedir = os . userInfo ( ) . homedir || os . homedir ( ) ;
29
+ if ( ! homedir || ! homedir . trim ( ) ) {
30
+ throw new Error ( 'Cannot determine home directory' ) ;
31
+ }
32
+ // Using the same path from account-cache.ts
33
+ return path . join ( homedir , '.cdk' , 'cache' , 'repo-version-ttl' ) ;
34
+ }
35
+
27
36
private readonly file : string ;
28
37
29
- // File modify times are accurate only till the second, hence using seconds as precision
38
+ // File modify times are accurate only to the second
30
39
private readonly ttlSecs : number ;
31
40
32
- constructor ( file : string , ttlSecs : number ) {
33
- this . file = file ;
34
- this . ttlSecs = ttlSecs ;
41
+ constructor ( file ?: string , ttlSecs ?: number ) {
42
+ this . file = file || VersionCheckTTL . timestampFilePath ( ) ;
43
+ try {
44
+ fs . mkdirsSync ( path . dirname ( this . file ) ) ;
45
+ fs . accessSync ( path . dirname ( this . file ) , fs . constants . W_OK ) ;
46
+ } catch {
47
+ throw new Error ( `Directory (${ path . dirname ( this . file ) } ) is not writable.` ) ;
48
+ }
49
+ this . ttlSecs = ttlSecs || ONE_DAY_IN_SECONDS ;
35
50
}
36
51
37
52
public async hasExpired ( ) : Promise < boolean > {
38
53
try {
39
- const lastCheckTime = ( await stat ( this . file ) ) . mtimeMs ;
54
+ const lastCheckTime = ( await fs . stat ( this . file ) ) . mtimeMs ;
40
55
const today = new Date ( ) . getTime ( ) ;
41
56
42
- if ( ( today - lastCheckTime ) / 1000 > this . ttlSecs ) { // convert ms to secs
57
+ if ( ( today - lastCheckTime ) / 1000 > this . ttlSecs ) { // convert ms to sec
43
58
return true ;
44
59
}
45
60
return false ;
@@ -52,15 +67,17 @@ export class TimestampFile {
52
67
}
53
68
}
54
69
55
- public async update ( ) : Promise < void > {
56
- const fd = await open ( this . file , 'w' ) ;
57
- await close ( fd ) ;
70
+ public async update ( latestVersion ?: string ) : Promise < void > {
71
+ if ( ! latestVersion ) {
72
+ latestVersion = '' ;
73
+ }
74
+ await fs . writeFile ( this . file , latestVersion ) ;
58
75
}
59
76
}
60
77
61
78
// Export for unit testing only.
62
79
// Don't use directly, use displayVersionMessage() instead.
63
- export async function latestVersionIfHigher ( currentVersion : string , cacheFile : TimestampFile ) : Promise < string | null > {
80
+ export async function latestVersionIfHigher ( currentVersion : string , cacheFile : VersionCheckTTL ) : Promise < string | null > {
64
81
if ( ! ( await cacheFile . hasExpired ( ) ) ) {
65
82
return null ;
66
83
}
@@ -74,7 +91,7 @@ export async function latestVersionIfHigher(currentVersion: string, cacheFile: T
74
91
throw new Error ( `npm returned an invalid semver ${ latestVersion } ` ) ;
75
92
}
76
93
const isNewer = semver . gt ( latestVersion , currentVersion ) ;
77
- await cacheFile . update ( ) ;
94
+ await cacheFile . update ( latestVersion ) ;
78
95
79
96
if ( isNewer ) {
80
97
return latestVersion ;
@@ -83,14 +100,13 @@ export async function latestVersionIfHigher(currentVersion: string, cacheFile: T
83
100
}
84
101
}
85
102
86
- const versionCheckCache = new TimestampFile ( `${ __dirname } /../.LAST_VERSION_CHECK` , ONE_DAY_IN_SECONDS ) ;
87
-
88
103
export async function displayVersionMessage ( ) : Promise < void > {
89
104
if ( ! process . stdout . isTTY ) {
90
105
return ;
91
106
}
92
107
93
108
try {
109
+ const versionCheckCache = new VersionCheckTTL ( ) ;
94
110
const laterVersion = await latestVersionIfHigher ( versionNumber ( ) , versionCheckCache ) ;
95
111
if ( laterVersion ) {
96
112
const bannerMsg = formatAsBanner ( [
@@ -100,6 +116,6 @@ export async function displayVersionMessage(): Promise<void> {
100
116
bannerMsg . forEach ( ( e ) => print ( e ) ) ;
101
117
}
102
118
} catch ( err ) {
103
- warning ( `Could not run version check due to error ${ err . message } ` ) ;
119
+ debug ( `Could not run version check - ${ err . message } ` ) ;
104
120
}
105
- }
121
+ }
0 commit comments