@@ -9,10 +9,10 @@ import 'package:collection/collection.dart' show UnmodifiableSetView;
9
9
import 'package:gcloud/service_scope.dart' as ss;
10
10
import 'package:json_annotation/json_annotation.dart' ;
11
11
import 'package:meta/meta.dart' ;
12
+ import 'package:path/path.dart' as path;
13
+ import 'package:pub_dev/frontend/static_files.dart' ;
12
14
import 'package:yaml/yaml.dart' ;
13
15
14
- import 'env_config.dart' ;
15
-
16
16
part 'configuration.g.dart' ;
17
17
18
18
final _configurationKey = #_active_configuration;
@@ -21,7 +21,7 @@ final _configurationKey = #_active_configuration;
21
21
Configuration get activeConfiguration {
22
22
Configuration ? config = ss.lookup (_configurationKey) as Configuration ? ;
23
23
if (config == null ) {
24
- config = Configuration .fromEnv (envConfig );
24
+ config = Configuration .fromEnv ();
25
25
ss.register (_configurationKey, config);
26
26
}
27
27
return config;
@@ -32,10 +32,6 @@ void registerActiveConfiguration(Configuration configuration) {
32
32
ss.register (_configurationKey, configuration);
33
33
}
34
34
35
- /// The OAuth audience (`client_id` ) that the `pub` client uses.
36
- const _pubClientAudience =
37
- '818368855108-8grd2eg9tj9f38os6f1urbcvsq399u8n.apps.googleusercontent.com' ;
38
-
39
35
/// Special value to indicate that the site is running in fake mode, and the
40
36
/// client side authentication should use the fake authentication tokens.
41
37
const _fakeSiteAudience = 'fake-site-audience' ;
@@ -45,6 +41,7 @@ const _fakeSiteAudience = 'fake-site-audience';
45
41
/// The configuration define the location of the Datastore with the
46
42
/// package metadata and the Cloud Storage bucket for the actual package
47
43
/// tar files.
44
+ @sealed
48
45
@JsonSerializable (
49
46
anyMap: true ,
50
47
explicitToJson: true ,
@@ -143,116 +140,22 @@ class Configuration {
143
140
/// The identifier of admins.
144
141
final List <AdminId >? admins;
145
142
143
+ /// Load [Configuration] from YAML file at [path] substituting `{{ENV}}` for
144
+ /// the value of environment variable `ENV` .
146
145
factory Configuration .fromYamlFile (final String path) {
147
- final file = File (path);
148
- final content = file.readAsStringSync ();
149
- final map =
150
- json.decode (json.encode (loadYaml (content))) as Map <String , dynamic >;
151
- return Configuration .fromJson (map);
152
- }
153
-
154
- /// Create a configuration for production deployment.
155
- ///
156
- /// This will use the Datastore from the cloud project and the Cloud Storage
157
- /// bucket 'pub-packages'. The credentials for accessing the Cloud
158
- /// Storage is retrieved from the Datastore.
159
- @visibleForTesting
160
- factory Configuration .prod () {
161
- final projectId = 'dartlang-pub' ;
162
- return Configuration (
163
- projectId: projectId,
164
- packageBucketName: 'pub-packages' ,
165
- imageBucketName: '$projectId --pub-images' ,
166
- dartdocStorageBucketName: '$projectId --dartdoc-storage' ,
167
- popularityDumpBucketName: '$projectId --popularity' ,
168
- searchSnapshotBucketName: '$projectId --search-snapshot' ,
169
- searchServicePrefix: 'https://search-dot-$projectId .appspot.com' ,
170
- storageBaseUrl: 'https://storage.googleapis.com/' ,
171
- pubClientAudience: _pubClientAudience,
172
- pubSiteAudience:
173
- '818368855108-e8skaopm5ih5nbb82vhh66k7ft5o7dn3.apps.googleusercontent.com' ,
174
- adminAudience: 'https://pub.dev' ,
175
- gmailRelayServiceAccount:
176
-
177
- gmailRelayImpersonatedGSuiteUser
: '[email protected] ' ,
178
- uploadSignerServiceAccount:
179
-
180
- blockRobots: false ,
181
- productionHosts: const ['pub.dartlang.org' , 'pub.dev' , 'api.pub.dev' ],
182
- primaryApiUri: Uri .parse ('https://pub.dartlang.org/' ),
183
- primarySiteUri: Uri .parse ('https://pub.dev/' ),
184
- admins: [
185
- AdminId (
186
-
187
- oauthUserId: '106306194842560376600' ,
188
- permissions: {AdminPermission .manageAssignedTags},
189
- ),
190
- AdminId (
191
-
192
- oauthUserId: '114536496314409930448' ,
193
- permissions: {
194
- AdminPermission .listUsers,
195
- AdminPermission .managePackageOwnership,
196
- AdminPermission .removeUsers,
197
- },
198
- ),
199
- AdminId (
200
-
201
- oauthUserId: '108693445730271975989' ,
202
- permissions: AdminPermission .values,
203
- )
204
- ],
205
- );
206
- }
207
-
208
- /// Create a configuration for development/staging deployment.
209
- @visibleForTesting
210
- factory Configuration .staging () {
211
- final projectId = 'dartlang-pub-dev' ;
212
- return Configuration (
213
- projectId: projectId,
214
- packageBucketName: '$projectId --pub-packages' ,
215
- imageBucketName: '$projectId --pub-images' ,
216
- dartdocStorageBucketName: '$projectId --dartdoc-storage' ,
217
- popularityDumpBucketName: '$projectId --popularity' ,
218
- searchSnapshotBucketName: '$projectId --search-snapshot' ,
219
- // TODO: Support finding search on localhost when envConfig.isRunningLocally
220
- // is true, this also requires running search on localhost.
221
- searchServicePrefix: 'https://search-dot-$projectId .appspot.com' ,
222
- storageBaseUrl: 'https://storage.googleapis.com/' ,
223
- pubClientAudience: _pubClientAudience,
224
- pubSiteAudience:
225
- '621485135717-idb8t8nnguphtu2drfn2u4ig7r56rm6n.apps.googleusercontent.com' ,
226
- adminAudience: 'https://pub.dev' ,
227
- gmailRelayServiceAccount: null , // disable email sending
228
- gmailRelayImpersonatedGSuiteUser: null , // disable email sending
229
- uploadSignerServiceAccount:
230
-
231
- blockRobots: true ,
232
- productionHosts: envConfig.isRunningLocally
233
- ? ['localhost' ]
234
- : [
235
- 'dartlang-pub-dev.appspot.com' ,
236
- '${envConfig .gaeService }-dot-dartlang-pub-dev.appspot.com' ,
237
- ],
238
- primaryApiUri: Uri .parse ('https://dartlang-pub-dev.appspot.com' ),
239
- primarySiteUri: envConfig.isRunningLocally
240
- ? Uri .parse ('http://localhost:8080' )
241
- : Uri .parse (
242
- 'https://${envConfig .gaeVersion }-dot-dartlang-pub-dev.appspot.com' ,
243
- ),
244
- admins: [
245
- AdminId (
246
- oauthUserId: '111042304059633250784' ,
247
-
248
- permissions: AdminPermission .values,
249
- ),
250
- AdminId (
251
- oauthUserId: '117672289743137340098' ,
252
-
253
- permissions: {AdminPermission .manageAssignedTags},
254
- )
255
- ],
146
+ final content = File (path)
147
+ .readAsStringSync ()
148
+ .replaceAllMapped (RegExp (r'\{\{([A-Z]+[A-Z0-9_]*)\}\}' ), (match) {
149
+ final name = match.group (1 );
150
+ if (name != null &&
151
+ Platform .environment.containsKey (name) &&
152
+ Platform .environment[name]! .isNotEmpty) {
153
+ return Platform .environment[name]! ;
154
+ }
155
+ return match.group (0 )! ;
156
+ });
157
+ return Configuration .fromJson (
158
+ json.decode (json.encode (loadYaml (content))) as Map <String , dynamic >,
256
159
);
257
160
}
258
161
@@ -278,21 +181,25 @@ class Configuration {
278
181
required this .admins,
279
182
});
280
183
281
- /// Create a configuration based on the environment variables.
282
- factory Configuration .fromEnv (EnvConfig env) {
283
- if (env.gcloudProject == 'dartlang-pub' ) {
284
- return Configuration .prod ();
285
- } else if (env.gcloudProject == 'dartlang-pub-dev' ) {
286
- return Configuration .staging ();
287
- } else if (env.configPath? .isEmpty ?? true ) {
288
- throw Exception (
289
- 'Unknown project id: ${env .gcloudProject }. Please setup env var GCLOUD_PROJECT or PUB_SERVER_CONFIG' );
290
- } else if (File (env.configPath! ).existsSync ()) {
291
- return Configuration .fromYamlFile (env.configPath! );
292
- } else {
293
- throw Exception (
294
- 'File ${env .configPath } doesnt exist. Please ensure PUB_SERVER_CONFIG env is pointing to the existing config' );
184
+ /// Load configuration from `app/config/<projectId>.yaml` where `projectId`
185
+ /// is the GCP Project ID (specified using `GOOGLE_CLOUD_PROJECT` ).
186
+ factory Configuration .fromEnv () {
187
+ // The GOOGLE_CLOUD_PROJECT is the canonical manner to specify project ID.
188
+ // This is undocumented for appengine custom runtime, but documented for the
189
+ // other runtimes:
190
+ // https://cloud.google.com/appengine/docs/standard/nodejs/runtime
191
+ final projectId = Platform .environment['GOOGLE_CLOUD_PROJECT' ];
192
+ if (projectId == null || projectId.isEmpty) {
193
+ throw StateError (
194
+ 'Environment variable \$ GOOGLE_CLOUD_PROJECT must be specified!' ,
195
+ );
196
+ }
197
+
198
+ final configFile = path.join (resolveAppDir (), projectId + '.yaml' );
199
+ if (! File (configFile).existsSync ()) {
200
+ throw StateError ('Could not find configuration file: "$configFile "' );
295
201
}
202
+ return Configuration .fromYamlFile (configFile);
296
203
}
297
204
298
205
/// Configuration for pkg/fake_pub_server.
0 commit comments