@@ -6,7 +6,7 @@ import path from 'path';
6
6
import stream from 'stream' ;
7
7
import tar from 'tar-fs' ;
8
8
import tmp from 'tmp-promise' ;
9
- import util from 'util' ;
9
+ import util , { promisify } from 'util' ;
10
10
import { BuildVariant , Config , Platform } from './config' ;
11
11
12
12
const pipeline = util . promisify ( stream . pipeline ) ;
@@ -42,11 +42,17 @@ enum Arch {
42
42
}
43
43
44
44
export class Barque {
45
+ public static readonly PPA_REPO_BASE_URL = 'https://repo.mongodb.org' as const ;
46
+
45
47
private config : Config ;
46
48
private mongodbEdition : string ;
47
49
private mongodbVersion : string ;
48
50
49
51
constructor ( config : Config ) {
52
+ if ( config . platform !== Platform . Linux ) {
53
+ throw new Error ( 'Barque publishing is only supported on linux platforms' ) ;
54
+ }
55
+
50
56
this . config = config ;
51
57
// hard code mongodb edition to 'org' for now
52
58
this . mongodbEdition = 'org' ;
@@ -56,29 +62,31 @@ export class Barque {
56
62
}
57
63
58
64
/**
59
- * Upload current package to barque, MongoDB's PPA for linux distros.
65
+ * Upload a distributable package to barque, MongoDB's PPA for linux distros.
66
+ *
67
+ * Note that this method returns the URLs where the packages _will_ be available.
68
+ * This method does not wait for the packages to really be available.
69
+ * Use `waitUntilPackagesAreAvailable` for this purpose.
60
70
*
61
- * @param { string } tarballURL - The uploaded to Evergreen tarball URL .
62
- * @param { Config } config - Config object .
71
+ * @param buildVariant - The distributable package build variant to publish .
72
+ * @param packageUrl - The Evergreen URL of the distributable package .
63
73
*
64
- * @returns { Promise } The promise .
74
+ * @returns The URLs where the packages will be available .
65
75
*/
66
- async releaseToBarque ( buildVariant : BuildVariant , tarballURL : string ) : Promise < any > {
67
- if ( this . config . platform !== Platform . Linux ) {
68
- return ;
69
- }
70
-
76
+ async releaseToBarque ( buildVariant : BuildVariant , packageUrl : string ) : Promise < string [ ] > {
71
77
const repoConfig = path . join ( this . config . rootDir , 'config' , 'repo-config.yml' ) ;
72
78
const curatorDirPath = await this . createCuratorDir ( ) ;
73
79
await this . extractLatestCurator ( curatorDirPath ) ;
74
80
75
81
const targetDistros = this . getTargetDistros ( buildVariant ) ;
76
82
const targetArchitecture = this . getTargetArchitecture ( buildVariant ) ;
83
+
84
+ const publishedPackageUrls : string [ ] = [ ] ;
77
85
for ( const distro of targetDistros ) {
78
86
try {
79
87
await this . execCurator (
80
88
curatorDirPath ,
81
- tarballURL ,
89
+ packageUrl ,
82
90
repoConfig ,
83
91
distro ,
84
92
targetArchitecture
@@ -87,12 +95,15 @@ export class Barque {
87
95
console . error ( 'Curator failed' , error ) ;
88
96
throw new Error ( `Curator is unable to upload to barque ${ error } ` ) ;
89
97
}
98
+
99
+ publishedPackageUrls . push ( this . computePublishedPackageUrl ( distro , targetArchitecture , packageUrl ) ) ;
90
100
}
101
+ return publishedPackageUrls ;
91
102
}
92
103
93
104
async execCurator (
94
105
curatorDirPath : string ,
95
- tarballURL : string ,
106
+ packageUrl : string ,
96
107
repoConfig : string ,
97
108
distro : Distro ,
98
109
architecture : Arch
@@ -107,7 +118,7 @@ export class Barque {
107
118
'--arch' , architecture ,
108
119
'--edition' , this . mongodbEdition ,
109
120
'--version' , this . mongodbVersion ,
110
- '--packages' , tarballURL
121
+ '--packages' , packageUrl
111
122
] , {
112
123
// curator looks for these options in env
113
124
env : {
@@ -147,6 +158,61 @@ export class Barque {
147
158
}
148
159
}
149
160
161
+ computePublishedPackageUrl ( distro : Distro , targetArchitecture : Arch , packageUrl : string ) : string {
162
+ const packageFileName = packageUrl . split ( '/' ) . slice ( - 1 ) ;
163
+ const packageFolderVersion = this . mongodbVersion . split ( '.' ) . slice ( 0 , 2 ) . join ( '.' ) ;
164
+ switch ( distro ) {
165
+ case Distro . Debian10 :
166
+ return `${ Barque . PPA_REPO_BASE_URL } /apt/debian/dists/buster/mongodb-org/${ packageFolderVersion } /main/binary-${ targetArchitecture } /${ packageFileName } ` ;
167
+ case Distro . Ubuntu1804 :
168
+ return `${ Barque . PPA_REPO_BASE_URL } /apt/ubuntu/dists/bionic/mongodb-org/${ packageFolderVersion } /multiverse/binary-${ targetArchitecture } /${ packageFileName } ` ;
169
+ case Distro . Ubuntu2004 :
170
+ return `${ Barque . PPA_REPO_BASE_URL } /apt/ubuntu/dists/focal/mongodb-org/${ packageFolderVersion } /multiverse/binary-${ targetArchitecture } /${ packageFileName } ` ;
171
+ case Distro . Redhat80 :
172
+ return `${ Barque . PPA_REPO_BASE_URL } /yum/redhat/8/mongodb-org/${ packageFolderVersion } /${ targetArchitecture } /RPMS/${ packageFileName } ` ;
173
+ default :
174
+ throw new Error ( `Unsupported distro: ${ distro } ` ) ;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Waits until the given packages are available under the specified URLs or throws an error if there
180
+ * are still remaining packages after the timeout.
181
+ *
182
+ * Note that the method will try all URLs at least once after an initial delay of `sleepTimeSeconds`.
183
+ */
184
+ async waitUntilPackagesAreAvailable ( publishedPackageUrls : string [ ] , timeoutSeconds : number , sleepTimeSeconds = 10 ) : Promise < void > {
185
+ let remainingPackages = [ ...publishedPackageUrls ] ;
186
+ const sleep = promisify ( setTimeout ) ;
187
+
188
+ const startMs = new Date ( ) . getTime ( ) ;
189
+ const failOnTimeout = ( ) => {
190
+ if ( new Date ( ) . getTime ( ) - startMs > timeoutSeconds * 1000 ) {
191
+ throw new Error ( `Barque timed out - the following packages are still not available: ${ remainingPackages . join ( ', ' ) } ` ) ;
192
+ }
193
+ } ;
194
+
195
+ while ( remainingPackages . length ) {
196
+ console . info ( `Waiting for availability of:\n - ${ remainingPackages . join ( '\n - ' ) } ` ) ;
197
+ await sleep ( sleepTimeSeconds * 1000 ) ;
198
+
199
+ const promises = remainingPackages . map ( async url => await fetch ( url , {
200
+ method : 'HEAD'
201
+ } ) ) ;
202
+ const responses = await Promise . all ( promises ) ;
203
+
204
+ const newRemainingPackages : string [ ] = [ ] ;
205
+ for ( let i = 0 ; i < remainingPackages . length ; i ++ ) {
206
+ if ( responses [ i ] . status !== 200 ) {
207
+ newRemainingPackages . push ( remainingPackages [ i ] ) ;
208
+ }
209
+ }
210
+ remainingPackages = newRemainingPackages ;
211
+
212
+ failOnTimeout ( ) ;
213
+ }
214
+ }
215
+
150
216
/**
151
217
* Create a staging dir in /tmp to download the latest version of curator.
152
218
*
0 commit comments