public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => (reader.Value != null) ? VersionInfo.Parse((string)reader.Value) : null;
//--- Constructors --- public LambdaSharpToolOutOfDateException(VersionInfo version) : base() { Version = version ?? throw new ArgumentNullException(nameof(version)); }
public async Task <ModuleLocation> ResolveInfoToLocationAsync(ModuleInfo moduleInfo, ModuleManifestDependencyType dependencyType, bool allowImport, bool showError) { LogInfoVerbose($"=> Resolving module {moduleInfo}"); // check if module can be found in the deployment bucket var result = await FindNewestModuleVersionAsync(Settings.DeploymentBucketName); // check if the origin bucket needs to be checked if ( allowImport && (Settings.DeploymentBucketName != moduleInfo.Origin) && ( // no version has been found (result.Version == null) // no module version constraint was given; the ultimate floating version || (moduleInfo.Version == null) // the module version constraint is for a pre-release; we always prefer the origin version then || moduleInfo.Version.IsPreRelease // the module version constraint is floating; we need to check if origin has a newer version || moduleInfo.Version.HasFloatingConstraints ) ) { var originResult = await FindNewestModuleVersionAsync(moduleInfo.Origin); // check if module found at origin should be kept instead if ( (originResult.Version != null) && ( (result.Version == null) || (moduleInfo.Version?.IsPreRelease ?? false) || originResult.Version.IsGreaterThanVersion(result.Version) ) ) { result = originResult; } } // check if a module was found if (result.Version == null) { // could not find a matching version var versionConstraint = (moduleInfo.Version != null) ? $"v{moduleInfo.Version} or later" : "any version"; if (showError) { LogError($"could not find module '{moduleInfo}' ({versionConstraint})"); } return(null); } LogInfoVerbose($"=> Selected module {moduleInfo.WithVersion(result.Version)} from {result.Origin}"); return(MakeModuleLocation(result.Origin, result.Manifest)); // local functions async Task <(string Origin, VersionInfo Version, ModuleManifest Manifest)> FindNewestModuleVersionAsync(string bucketName) { // enumerate versions in bucket var found = await FindModuleVersionsAsync(bucketName); if (!found.Any()) { return(Origin : bucketName, Version : null, Manifest : null); } // NOTE (2019-08-12, bjorg): unless the module is shared, we filter the list of found versions to // only contain versions that meet the module version constraint; for shared modules, we want to // keep the latest version that is compatible with the tool and is equal-or-greater than the // module version constraint. if ((dependencyType != ModuleManifestDependencyType.Shared) && (moduleInfo.Version != null)) { found = found.Where(version => version.MatchesConstraint(moduleInfo.Version)).ToList(); } // attempt to identify the newest module version compatible with the tool ModuleManifest manifest = null; var match = VersionInfo.FindLatestMatchingVersion(found, moduleInfo.Version, candidate => { var candidateModuleInfo = new ModuleInfo(moduleInfo.Namespace, moduleInfo.Name, candidate, moduleInfo.Origin); var candidateManifestText = GetS3ObjectContentsAsync(bucketName, candidateModuleInfo.VersionPath).Result; manifest = JsonConvert.DeserializeObject <ModuleManifest>(candidateManifestText); // check if module is compatible with this tool return(manifest.CoreServicesVersion.IsCoreServicesCompatible(Settings.CoreServicesVersion)); }); return(Origin : bucketName, Version : match, Manifest : manifest); } async Task <IEnumerable <VersionInfo> > FindModuleVersionsAsync(string bucketName) { // get bucket region specific S3 client var s3Client = await GetS3ClientByBucketNameAsync(bucketName); if (s3Client == null) { // nothing to do; GetS3ClientByBucketName already emitted an error return(new List <VersionInfo>()); } // enumerate versions in bucket var versions = new List <VersionInfo>(); var request = new ListObjectsV2Request { BucketName = bucketName, Prefix = $"{moduleInfo.Origin ?? Settings.DeploymentBucketName}/{moduleInfo.Namespace}/{moduleInfo.Name}/", Delimiter = "/", MaxKeys = 100, RequestPayer = RequestPayer.Requester }; do { try { var response = await s3Client.ListObjectsV2Async(request); versions.AddRange(response.S3Objects .Select(s3Object => s3Object.Key.Substring(request.Prefix.Length)) .Select(found => VersionInfo.Parse(found)) .Where(version => (moduleInfo.Version == null) || version.IsGreaterOrEqualThanVersion(moduleInfo.Version, strict: true)) ); request.ContinuationToken = response.NextContinuationToken; } catch (AmazonS3Exception e) when(e.Message == "Access Denied") { break; } } while(request.ContinuationToken != null); LogInfoVerbose($"==> Found {versions.Count} version{((versions.Count == 1) ? "" : "s")} in {bucketName} [{s3Client.Config.RegionEndpoint.SystemName}]"); return(versions); } ModuleLocation MakeModuleLocation(string sourceBucketName, ModuleManifest manifest) => new ModuleLocation(sourceBucketName, manifest.ModuleInfo, manifest.TemplateChecksum); }