private Bucket NewBucket(GcsPath gcsPath, NewGcsBucketDynamicParameters dynamicParams)
        {
            if (dynamicParams.Project == null)
            {
                var property = dynamicParams.GetType().GetProperty(nameof(Project));
                ConfigPropertyNameAttribute configPropertyName =
                    (ConfigPropertyNameAttribute)Attribute.GetCustomAttribute(
                        property, typeof(ConfigPropertyNameAttribute));
                configPropertyName.SetObjectConfigDefault(property, dynamicParams);
            }

            var bucket = new Bucket
            {
                Name         = gcsPath.Bucket,
                Location     = dynamicParams.Location,
                StorageClass = dynamicParams.StorageClass
            };

            BucketsResource.InsertRequest insertReq = Service.Buckets.Insert(bucket, dynamicParams.Project);
            insertReq.PredefinedAcl = dynamicParams.DefaultBucketAcl;
            insertReq.PredefinedDefaultObjectAcl = dynamicParams.DefaultObjectAcl;
            Bucket newBucket = insertReq.Execute();
            // If the bucket cache is not initialized, then don't bother initializing it
            // because that will cause a long wait time and we may not even know whether
            // the user needs to use all the other buckets right away. Also, we should not
            // refresh the whole cache right at this instance (which is why we call
            // GetValueWithoutUpdate) for the same reason.
            Dictionary <string, Bucket> bucketDict = BucketCache.GetLastValueWithoutUpdate();

            if (bucketDict != null)
            {
                bucketDict[newBucket.Name] = newBucket;
            }
            return(newBucket);
        }
        /// <summary>
        /// PowerShell uses this to check if items exist.
        /// </summary>
        protected override bool ItemExists(string path)
        {
            var gcsPath = GcsPath.Parse(path);

            switch (gcsPath.Type)
            {
            case GcsPath.GcsPathType.Drive:
                return(true);

            case GcsPath.GcsPathType.Bucket:
                Dictionary <string, Bucket> bucketDict = null;
                // If the bucket cache is not initialized, then don't bother initializing it
                // because that will cause a long wait time and we may not even know whether
                // the user needs to use all the other buckets right away. Also, we should not
                // refresh the whole cache right at this instance (which is why we call
                // GetValueWithoutUpdate) for the same reason.
                bucketDict = BucketCache.GetLastValueWithoutUpdate();
                if (bucketDict != null && bucketDict.ContainsKey(gcsPath.Bucket))
                {
                    return(true);
                }

                try
                {
                    var bucket = Service.Buckets.Get(gcsPath.Bucket).Execute();
                    if (bucketDict != null)
                    {
                        bucketDict[bucket.Name] = bucket;
                    }
                    return(true);
                }
                catch
                {
                    return(false);
                }

            case GcsPath.GcsPathType.Object:
                BucketModel model        = GetBucketModel(gcsPath.Bucket);
                bool        objectExists = model.ObjectExists(gcsPath.ObjectPath);
                return(objectExists);

            default:
                throw new InvalidOperationException($"Unknown Path Type {gcsPath.Type}");
            }
        }
 /// <summary>
 /// If the BucketCache is not out of date, simply perform the action on each bucket.
 /// Otherwise, we update the cache and perform the action while doing that (for example,
 /// we can write the bucket to the command line as they become available instead of writing
 /// all at once).
 /// </summary>
 /// <param name="actionOnBucket">Action to be performed on each bucket if cache is out of date.</param>
 private void PerformActionOnBucketAndOptionallyUpdateCache(Action <Bucket> actionOnBucket)
 {
     // If the cache is already initialized and not stale, simply perform the action on each bucket.
     // Otherwise, we update the cache and perform action on each of the item while doing so.
     if (!BucketCache.CacheOutOfDate())
     {
         Dictionary <string, Bucket> bucketDict = BucketCache.GetLastValueWithoutUpdate();
         foreach (Bucket bucket in bucketDict.Values)
         {
             actionOnBucket(bucket);
         }
     }
     else
     {
         Func <Dictionary <string, Bucket> > functionToUpdateCacheAndPerformActionOnBucket = () => UpdateBucketCacheAndPerformActionOnBucket(actionOnBucket);
         BucketCache.GetValueWithUpdateFunction(functionToUpdateCacheAndPerformActionOnBucket);
     }
 }
        /// <summary>
        /// Deletes a Google Cloud Storage object or bucket. Used by Remove-Item.
        /// </summary>
        /// <param name="path">The path to the object or bucket to remove.</param>
        /// <param name="recurse">If true, will remove the desendants of the item as well. Required for a
        /// non-empty bucket.</param>
        protected override void RemoveItem(string path, bool recurse)
        {
            if (!ShouldProcess(path, "Remove-Item"))
            {
                return;
            }
            var gcsPath = GcsPath.Parse(path);

            switch (gcsPath.Type)
            {
            case GcsPath.GcsPathType.Drive:
                throw new InvalidOperationException("Use Remove-PSDrive to remove a drive.");

            case GcsPath.GcsPathType.Bucket:
                RemoveBucket(gcsPath, recurse);
                // If the bucket cache is not initialized, then don't bother initializing it
                // because that will cause a long wait time and we may not even know whether
                // the user needs to use all the other buckets right away. Also, we should not
                // refresh the whole cache right at this instance (which is why we call
                // GetValueWithoutUpdate) for the same reason.
                Dictionary <string, Bucket> bucketDict = BucketCache.GetLastValueWithoutUpdate();
                if (bucketDict != null)
                {
                    bucketDict.Remove(gcsPath.Bucket);
                }
                break;

            case GcsPath.GcsPathType.Object:
                if (IsItemContainer(path))
                {
                    RemoveFolder(GcsPath.Parse(path + "/"), recurse);
                }
                else
                {
                    Service.Objects.Delete(gcsPath.Bucket, gcsPath.ObjectPath).Execute();
                }
                BucketModels.Clear();
                break;

            default:
                throw new InvalidOperationException($"Unknown Path Type {gcsPath.Type}");
            }
            TelemetryReporter.ReportSuccess(nameof(GoogleCloudStorageProvider), nameof(RemoveItem));
        }
        /// <summary>
        /// Writes the object describing the item to the output. Used by Get-Item.
        /// </summary>
        /// <param name="path">The path of the item to get.</param>
        protected override void GetItem(string path)
        {
            var gcsPath = GcsPath.Parse(path);

            switch (gcsPath.Type)
            {
            case GcsPath.GcsPathType.Drive:
                WriteItemObject(PSDriveInfo, path, true);
                break;

            case GcsPath.GcsPathType.Bucket:
                Dictionary <string, Bucket> bucketDict = null;
                Bucket bucket;
                // If the bucket cache is not initialized, then don't bother initializing it
                // because that will cause a long wait time and we may not even know whether
                // the user needs to use all the other buckets right away. Also, we should not
                // refresh the whole cache right at this instance (which is why we call
                // GetValueWithoutUpdate) for the same reason.
                bucketDict = BucketCache.GetLastValueWithoutUpdate();
                if (bucketDict != null && bucketDict.ContainsKey(gcsPath.Bucket))
                {
                    bucket = bucketDict[gcsPath.Bucket];
                    break;
                }

                bucket = Service.Buckets.Get(gcsPath.Bucket).Execute();
                if (bucketDict != null)
                {
                    bucketDict[bucket.Name] = bucket;
                }
                WriteItemObject(bucket, path, true);
                break;

            case GcsPath.GcsPathType.Object:
                Object gcsObject = GetBucketModel(gcsPath.Bucket).GetGcsObject(gcsPath.ObjectPath);
                WriteItemObject(gcsObject, path, IsItemContainer(path));
                break;

            default:
                throw new InvalidOperationException($"Unknown Path Type {gcsPath.Type}");
            }
            TelemetryReporter.ReportSuccess(nameof(GoogleCloudStorageProvider), nameof(GetItem));
        }