From 1f1359c1f35b2641b9836a95f7109b9d6756227d Mon Sep 17 00:00:00 2001 From: Xavier Hainaux Date: Thu, 25 May 2023 12:53:24 +0200 Subject: [PATCH] Prepare mono package --- .github/workflows/test.yaml | 4 + .gitignore | 2 +- analysis_options.yaml | 4 - aws_client/CHANGELOG.md | 4 + aws_client/README.md | 353 +++++++++++++++++- aws_client/README.template.md | 53 +++ aws_client/build.yml | 19 - aws_client/examples/lambda.example.dart | 33 +- aws_client/examples/sqs.dart | 13 + aws_client/lib/aws_client.dart | 38 -- aws_client/lib/lambda.dart | 65 ---- aws_client/lib/sns.dart | 186 --------- aws_client/lib/sqs.dart | 187 ---------- aws_client/lib/src/credentials.dart | 24 -- aws_client/lib/src/request.dart | 235 ------------ .../src/protocol/endpoint_config_data.dart | 112 ++++++ aws_client/pubspec.yaml | 24 +- aws_client/test/impl_test.dart | 52 --- generator/bin/generate.dart | 2 + generator/lib/builders/library_builder.dart | 30 +- .../builders/protocols/rest_json_builder.dart | 10 +- .../lib/generate_single_package_command.dart | 240 ++++++++++++ generator/lib/model/api.dart | 40 +- generator/lib/utils/case.dart | 4 + generator/lib/utils/fix_absolute_import.dart | 33 ++ generator/pubspec.yaml | 3 + 26 files changed, 905 insertions(+), 865 deletions(-) create mode 100644 aws_client/README.template.md delete mode 100644 aws_client/build.yml create mode 100644 aws_client/examples/sqs.dart delete mode 100644 aws_client/lib/aws_client.dart delete mode 100644 aws_client/lib/lambda.dart delete mode 100644 aws_client/lib/sns.dart delete mode 100644 aws_client/lib/sqs.dart delete mode 100644 aws_client/lib/src/credentials.dart delete mode 100644 aws_client/lib/src/request.dart create mode 100644 aws_client/lib/src/shared/src/protocol/endpoint_config_data.dart delete mode 100644 aws_client/test/impl_test.dart create mode 100644 generator/lib/generate_single_package_command.dart create mode 100644 generator/lib/utils/fix_absolute_import.dart diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 88b63bdd0..1f57b5ddf 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -43,6 +43,10 @@ jobs: run: dart pub get && dart analyze --fatal-infos working-directory: document_client + - name: Analyze aws_client package + run: dart pub get && dart analyze --fatal-infos + working-directory: aws_client + - name: "check for uncommitted changes" run: git diff --exit-code --stat -- . diff --git a/.gitignore b/.gitignore index 26940321a..c08fe2a50 100644 --- a/.gitignore +++ b/.gitignore @@ -24,5 +24,5 @@ doc/api/ *.iws # Generated directories -**/apis/ +generator/apis/ /all_apis/lib/ diff --git a/analysis_options.yaml b/analysis_options.yaml index 0ea2ebd52..5fdf7d53c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,10 +4,6 @@ include: package:lints/recommended.yaml analyzer: exclude: [generated/**] errors: - unused_element: error - unused_import: error - unused_local_variable: error - dead_code: error deprecated_member_use_from_same_package: ignore language: strict-casts: true diff --git a/aws_client/CHANGELOG.md b/aws_client/CHANGELOG.md index 57becce7d..634e5ff8b 100644 --- a/aws_client/CHANGELOG.md +++ b/aws_client/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.4.0 + +- Generate all the APIs with version v2.1384.0 of the AWS SDK + ## 0.3.0 - Repository refactoring in preparation for API code generator. diff --git a/aws_client/README.md b/aws_client/README.md index bfa28b68e..00326f628 100644 --- a/aws_client/README.md +++ b/aws_client/README.md @@ -1,7 +1,5 @@ # High-level APIs for Amazon Web Services (AWS) in Dart -Warning: incomplete, untested, but we accept pull requests :-) - ## Usage A simple usage example: @@ -47,3 +45,354 @@ meaning we have APIs here that we care about. Looking for contributions: [source]: https://github.com/agilord/aws_client [agilord]: https://www.agilord.com/ + +## Available AWS APIs + +The following is a list of APIs that are currently available inside this package. + +- AWS Migration Hub (`package:aws_client/migration_hub/`) +- Access Analyzer (`package:aws_client/access_analyzer/`) +- AWS Account (`package:aws_client/account/`) +- AWS Certificate Manager (`package:aws_client/acm/`) +- AWS Certificate Manager Private Certificate Authority (`package:aws_client/acm_pca/`) +- Alexa For Business (`package:aws_client/alexa_for_business/`) +- Amazon Prometheus Service (`package:aws_client/amp/`) +- AWS Amplify (`package:aws_client/amplify/`) +- AmplifyBackend (`package:aws_client/amplify_backend/`) +- AWS Amplify UI Builder (`package:aws_client/amplify_ui_builder/`) +- Amazon API Gateway (`package:aws_client/api_gateway/`) +- AmazonApiGatewayManagementApi (`package:aws_client/api_gateway_management_api/`) +- AmazonApiGatewayV2 (`package:aws_client/api_gateway_v2/`) +- Amazon AppConfig (`package:aws_client/app_config/`) +- AWS AppConfig Data (`package:aws_client/app_config_data/`) +- Amazon Appflow (`package:aws_client/appflow/`) +- Amazon AppIntegrations Service (`package:aws_client/app_integrations/`) +- Application Auto Scaling (`package:aws_client/application_auto_scaling/`) +- Amazon CloudWatch Application Insights (`package:aws_client/application_insights/`) +- AWS Application Cost Profiler (`package:aws_client/application_cost_profiler/`) +- AWS App Mesh (`package:aws_client/app_mesh/`) +- AWS App Runner (`package:aws_client/app_runner/`) +- Amazon AppStream (`package:aws_client/app_stream/`) +- AWS AppSync (`package:aws_client/app_sync/`) +- AWS ARC - Zonal Shift (`package:aws_client/arc_zonal_shift/`) +- Amazon Athena (`package:aws_client/athena/`) +- AWS Audit Manager (`package:aws_client/audit_manager/`) +- Auto Scaling (`package:aws_client/auto_scaling/`) +- AWS Auto Scaling Plans (`package:aws_client/auto_scaling_plans/`) +- AWS Backup (`package:aws_client/backup/`) +- AWS Backup Gateway (`package:aws_client/backup_gateway/`) +- AWS Backup Storage (`package:aws_client/backup_storage/`) +- AWS Batch (`package:aws_client/batch/`) +- AWSBillingConductor (`package:aws_client/billingconductor/`) +- Braket (`package:aws_client/braket/`) +- AWS Budgets (`package:aws_client/budgets/`) +- AWS Cost Explorer Service (`package:aws_client/cost_explorer/`) +- Amazon Chime (`package:aws_client/chime/`) +- Amazon Chime SDK Identity (`package:aws_client/chime_sdk_identity/`) +- Amazon Chime SDK Media Pipelines (`package:aws_client/chime_sdk_media_pipelines/`) +- Amazon Chime SDK Meetings (`package:aws_client/chime_sdk_meetings/`) +- Amazon Chime SDK Messaging (`package:aws_client/chime_sdk_messaging/`) +- Amazon Chime SDK Voice (`package:aws_client/chime_sdk_voice/`) +- AWS Clean Rooms Service (`package:aws_client/clean_rooms/`) +- AWS Cloud9 (`package:aws_client/cloud9/`) +- AWS Cloud Control API (`package:aws_client/cloud_control/`) +- Amazon CloudDirectory (`package:aws_client/cloud_directory/`) +- AWS CloudFormation (`package:aws_client/cloud_formation/`) +- Amazon CloudFront (`package:aws_client/cloud_front/`) +- Amazon CloudHSM (`package:aws_client/cloud_hsm/`) +- AWS CloudHSM V2 (`package:aws_client/cloud_hsm_v2/`) +- Amazon CloudSearch (`package:aws_client/cloud_search/`) +- Amazon CloudSearch Domain (`package:aws_client/cloud_search_domain/`) +- AWS CloudTrail (`package:aws_client/cloud_trail/`) +- AWS CloudTrail Data Service (`package:aws_client/cloud_trail_data/`) +- CodeArtifact (`package:aws_client/codeartifact/`) +- AWS CodeBuild (`package:aws_client/code_build/`) +- Amazon CodeCatalyst (`package:aws_client/code_catalyst/`) +- AWS CodeCommit (`package:aws_client/code_commit/`) +- AWS CodeDeploy (`package:aws_client/code_deploy/`) +- Amazon CodeGuru Reviewer (`package:aws_client/code_guru_reviewer/`) +- Amazon CodeGuru Profiler (`package:aws_client/code_guru_profiler/`) +- AWS CodePipeline (`package:aws_client/code_pipeline/`) +- AWS CodeStar (`package:aws_client/code_star/`) +- AWS CodeStar connections (`package:aws_client/code_star_connections/`) +- AWS CodeStar Notifications (`package:aws_client/codestar_notifications/`) +- Amazon Cognito Identity (`package:aws_client/cognito_identity/`) +- Amazon Cognito Identity Provider (`package:aws_client/cognito_identity_provider/`) +- Amazon Cognito Sync (`package:aws_client/cognito_sync/`) +- Amazon Comprehend (`package:aws_client/comprehend/`) +- AWS Comprehend Medical (`package:aws_client/comprehend_medical/`) +- AWS Compute Optimizer (`package:aws_client/compute_optimizer/`) +- AWS Config (`package:aws_client/config_service/`) +- Amazon Connect Service (`package:aws_client/connect/`) +- Amazon Connect Contact Lens (`package:aws_client/connect_contact_lens/`) +- AmazonConnectCampaignService (`package:aws_client/connect_campaigns/`) +- Amazon Connect Cases (`package:aws_client/connect_cases/`) +- Amazon Connect Participant Service (`package:aws_client/connect_participant/`) +- AWS Control Tower (`package:aws_client/control_tower/`) +- AWS Cost and Usage Report Service (`package:aws_client/cost_and_usage_report_service/`) +- Amazon Connect Customer Profiles (`package:aws_client/customer_profiles/`) +- AWS Glue DataBrew (`package:aws_client/data_brew/`) +- AWS Data Exchange (`package:aws_client/data_exchange/`) +- AWS Data Pipeline (`package:aws_client/data_pipeline/`) +- AWS DataSync (`package:aws_client/data_sync/`) +- Amazon DynamoDB Accelerator (DAX) (`package:aws_client/dax/`) +- Amazon Detective (`package:aws_client/detective/`) +- AWS Device Farm (`package:aws_client/device_farm/`) +- Amazon DevOps Guru (`package:aws_client/dev_ops_guru/`) +- AWS Direct Connect (`package:aws_client/direct_connect/`) +- AWS Application Discovery Service (`package:aws_client/application_discovery_service/`) +- Amazon Data Lifecycle Manager (`package:aws_client/dlm/`) +- AWS Database Migration Service (`package:aws_client/database_migration_service/`) +- Amazon DocumentDB with MongoDB compatibility (`package:aws_client/doc_db/`) +- Amazon DocumentDB Elastic Clusters (`package:aws_client/doc_db_elastic/`) +- Elastic Disaster Recovery Service (`package:aws_client/drs/`) +- AWS Directory Service (`package:aws_client/directory_service/`) +- Amazon DynamoDB (`package:aws_client/dynamo_db/`) +- Amazon Elastic Block Store (`package:aws_client/ebs/`) +- Amazon Elastic Compute Cloud (`package:aws_client/ec2/`) +- AWS EC2 Instance Connect (`package:aws_client/ec2_instance_connect/`) +- Amazon EC2 Container Registry (`package:aws_client/ecr/`) +- Amazon Elastic Container Registry Public (`package:aws_client/ecr_public/`) +- Amazon EC2 Container Service (`package:aws_client/ecs/`) +- Amazon Elastic Kubernetes Service (`package:aws_client/eks/`) +- Amazon Elastic Inference (`package:aws_client/elastic_inference/`) +- Amazon ElastiCache (`package:aws_client/elasti_cache/`) +- AWS Elastic Beanstalk (`package:aws_client/elastic_beanstalk/`) +- Amazon Elastic File System (`package:aws_client/efs/`) +- Elastic Load Balancing (`package:aws_client/elastic_load_balancing/`) +- Elastic Load Balancing (`package:aws_client/elastic_load_balancing_v2/`) +- Amazon EMR (`package:aws_client/emr/`) +- Amazon Elastic Transcoder (`package:aws_client/elastic_transcoder/`) +- Amazon Simple Email Service (`package:aws_client/ses/`) +- Amazon EMR Containers (`package:aws_client/emr_containers/`) +- EMR Serverless (`package:aws_client/emr_serverless/`) +- AWS Marketplace Entitlement Service (`package:aws_client/marketplace_entitlement_service/`) +- Amazon Elasticsearch Service (`package:aws_client/elasticsearch_service/`) +- Amazon EventBridge (`package:aws_client/event_bridge/`) +- Amazon CloudWatch Events (`package:aws_client/cloud_watch_events/`) +- Amazon CloudWatch Evidently (`package:aws_client/evidently/`) +- FinSpace User Environment Management service (`package:aws_client/finspace/`) +- FinSpace Public API (`package:aws_client/finspace_data/`) +- Amazon Kinesis Firehose (`package:aws_client/firehose/`) +- AWS Fault Injection Simulator (`package:aws_client/fis/`) +- Firewall Management Service (`package:aws_client/fms/`) +- Amazon Forecast Service (`package:aws_client/forecast/`) +- Amazon Forecast Query Service (`package:aws_client/forecastquery/`) +- Amazon Fraud Detector (`package:aws_client/fraud_detector/`) +- Amazon FSx (`package:aws_client/f_sx/`) +- Amazon GameLift (`package:aws_client/game_lift/`) +- GameSparks (`package:aws_client/game_sparks/`) +- Amazon Glacier (`package:aws_client/glacier/`) +- AWS Global Accelerator (`package:aws_client/global_accelerator/`) +- AWS Glue (`package:aws_client/glue/`) +- Amazon Managed Grafana (`package:aws_client/grafana/`) +- AWS Greengrass (`package:aws_client/greengrass/`) +- AWS IoT Greengrass V2 (`package:aws_client/greengrass_v2/`) +- AWS Ground Station (`package:aws_client/ground_station/`) +- Amazon GuardDuty (`package:aws_client/guard_duty/`) +- AWS Health APIs and Notifications (`package:aws_client/health/`) +- Amazon HealthLake (`package:aws_client/health_lake/`) +- Amazon Honeycode (`package:aws_client/honeycode/`) +- AWS Identity and Access Management (`package:aws_client/iam/`) +- AWS SSO Identity Store (`package:aws_client/identitystore/`) +- EC2 Image Builder (`package:aws_client/imagebuilder/`) +- AWS Import/Export (`package:aws_client/import_export/`) +- Amazon Inspector (`package:aws_client/inspector/`) +- Inspector2 (`package:aws_client/inspector2/`) +- Amazon CloudWatch Internet Monitor (`package:aws_client/internet_monitor/`) +- AWS IoT (`package:aws_client/iot/`) +- AWS IoT Data Plane (`package:aws_client/iot_data_plane/`) +- AWS IoT Jobs Data Plane (`package:aws_client/iot_jobs_data_plane/`) +- AWS IoT RoboRunner (`package:aws_client/iot_robo_runner/`) +- AWS IoT 1-Click Devices Service (`package:aws_client/iot_1_click_devices_service/`) +- AWS IoT 1-Click Projects Service (`package:aws_client/iot_1_click_projects/`) +- AWS IoT Analytics (`package:aws_client/iot_analytics/`) +- AWS IoT Core Device Advisor (`package:aws_client/iot_device_advisor/`) +- AWS IoT Events (`package:aws_client/iot_events/`) +- AWS IoT Events Data (`package:aws_client/iot_events_data/`) +- AWS IoT Fleet Hub (`package:aws_client/iot_fleet_hub/`) +- AWS IoT FleetWise (`package:aws_client/iot_fleet_wise/`) +- AWS IoT Secure Tunneling (`package:aws_client/iot_secure_tunneling/`) +- AWS IoT SiteWise (`package:aws_client/iot_site_wise/`) +- AWS IoT Things Graph (`package:aws_client/iot_things_graph/`) +- AWS IoT TwinMaker (`package:aws_client/iot_twin_maker/`) +- AWS IoT Wireless (`package:aws_client/iot_wireless/`) +- Amazon Interactive Video Service (`package:aws_client/ivs/`) +- Amazon Interactive Video Service RealTime (`package:aws_client/ivs_real_time/`) +- Amazon Interactive Video Service Chat (`package:aws_client/ivschat/`) +- Managed Streaming for Kafka (`package:aws_client/kafka/`) +- Managed Streaming for Kafka Connect (`package:aws_client/kafka_connect/`) +- AWSKendraFrontendService (`package:aws_client/kendra/`) +- Amazon Kendra Intelligent Ranking (`package:aws_client/kendra_ranking/`) +- Amazon Keyspaces (`package:aws_client/keyspaces/`) +- Amazon Kinesis (`package:aws_client/kinesis/`) +- Amazon Kinesis Video Streams Archived Media (`package:aws_client/kinesis_video_archived_media/`) +- Amazon Kinesis Video Streams Media (`package:aws_client/kinesis_video_media/`) +- Amazon Kinesis Video Signaling Channels (`package:aws_client/kinesis_video_signaling/`) +- Amazon Kinesis Video WebRTC Storage (`package:aws_client/kinesis_video_web_rtc_storage/`) +- Amazon Kinesis Analytics (`package:aws_client/kinesis_analytics/`) +- Amazon Kinesis Analytics (`package:aws_client/kinesis_analytics_v2/`) +- Amazon Kinesis Video Streams (`package:aws_client/kinesis_video/`) +- AWS Key Management Service (`package:aws_client/kms/`) +- AWS Lake Formation (`package:aws_client/lake_formation/`) +- AWS Lambda (`package:aws_client/lambda/`) +- Amazon Lex Model Building Service (`package:aws_client/lex_model_building_service/`) +- AWS License Manager (`package:aws_client/license_manager/`) +- AWS License Manager Linux Subscriptions (`package:aws_client/license_manager_linux_subscriptions/`) +- AWS License Manager User Subscriptions (`package:aws_client/license_manager_user_subscriptions/`) +- Amazon Lightsail (`package:aws_client/lightsail/`) +- Amazon Location Service (`package:aws_client/location/`) +- Amazon CloudWatch Logs (`package:aws_client/cloud_watch_logs/`) +- Amazon Lookout for Equipment (`package:aws_client/lookout_equipment/`) +- Amazon Lookout for Metrics (`package:aws_client/lookout_metrics/`) +- Amazon Lookout for Vision (`package:aws_client/lookout_vision/`) +- AWSMainframeModernization (`package:aws_client/m2/`) +- Amazon Machine Learning (`package:aws_client/machine_learning/`) +- Amazon Macie (`package:aws_client/macie/`) +- Amazon Macie 2 (`package:aws_client/macie2/`) +- Amazon Managed Blockchain (`package:aws_client/managed_blockchain/`) +- AWS Marketplace Catalog Service (`package:aws_client/marketplace_catalog/`) +- AWS Marketplace Commerce Analytics (`package:aws_client/marketplace_commerce_analytics/`) +- AWS MediaConnect (`package:aws_client/media_connect/`) +- AWS Elemental MediaConvert (`package:aws_client/media_convert/`) +- AWS Elemental MediaLive (`package:aws_client/media_live/`) +- AWS Elemental MediaPackage (`package:aws_client/media_package/`) +- AWS Elemental MediaPackage VOD (`package:aws_client/media_package_vod/`) +- AWS Elemental MediaPackage v2 (`package:aws_client/media_package_v2/`) +- AWS Elemental MediaStore (`package:aws_client/media_store/`) +- AWS Elemental MediaStore Data Plane (`package:aws_client/media_store_data/`) +- AWS MediaTailor (`package:aws_client/media_tailor/`) +- Amazon MemoryDB (`package:aws_client/memory_db/`) +- AWSMarketplace Metering (`package:aws_client/marketplace_metering/`) +- Application Migration Service (`package:aws_client/mgn/`) +- AWS Migration Hub Refactor Spaces (`package:aws_client/migration_hub_refactor_spaces/`) +- AWS Migration Hub Config (`package:aws_client/migration_hub_config/`) +- AWS Migration Hub Orchestrator (`package:aws_client/migration_hub_orchestrator/`) +- Migration Hub Strategy Recommendations (`package:aws_client/migration_hub_strategy/`) +- AWS Mobile (`package:aws_client/mobile/`) +- Amazon Mobile Analytics (`package:aws_client/mobile_analytics/`) +- Amazon Lex Model Building V2 (`package:aws_client/lex_models_v2/`) +- Amazon CloudWatch (`package:aws_client/cloud_watch/`) +- AmazonMQ (`package:aws_client/mq/`) +- Amazon Mechanical Turk (`package:aws_client/m_turk/`) +- AmazonMWAA (`package:aws_client/mwaa/`) +- Amazon Neptune (`package:aws_client/neptune/`) +- AWS Network Firewall (`package:aws_client/network_firewall/`) +- AWS Network Manager (`package:aws_client/network_manager/`) +- AmazonNimbleStudio (`package:aws_client/nimble/`) +- CloudWatch Observability Access Manager (`package:aws_client/oam/`) +- Amazon Omics (`package:aws_client/omics/`) +- Amazon OpenSearch Service (`package:aws_client/open_search/`) +- OpenSearch Service Serverless (`package:aws_client/open_search_serverless/`) +- AWS OpsWorks (`package:aws_client/ops_works/`) +- AWS OpsWorks CM (`package:aws_client/ops_works_cm/`) +- AWS Organizations (`package:aws_client/organizations/`) +- Amazon OpenSearch Ingestion (`package:aws_client/osis/`) +- AWS Outposts (`package:aws_client/outposts/`) +- AWS Panorama (`package:aws_client/panorama/`) +- Amazon Personalize (`package:aws_client/personalize/`) +- Amazon Personalize Events (`package:aws_client/personalize_events/`) +- Amazon Personalize Runtime (`package:aws_client/personalize_runtime/`) +- AWS Performance Insights (`package:aws_client/pi/`) +- Amazon Pinpoint (`package:aws_client/pinpoint/`) +- Amazon Pinpoint Email Service (`package:aws_client/pinpoint_email/`) +- Amazon Pinpoint SMS Voice V2 (`package:aws_client/pinpoint_sms_voice_v2/`) +- Amazon EventBridge Pipes (`package:aws_client/pipes/`) +- Amazon Polly (`package:aws_client/polly/`) +- AWS Price List Service (`package:aws_client/pricing/`) +- AWS Private 5G (`package:aws_client/private_networks/`) +- AWS Proton (`package:aws_client/proton/`) +- Amazon QLDB (`package:aws_client/qldb/`) +- Amazon QLDB Session (`package:aws_client/qldb_session/`) +- Amazon QuickSight (`package:aws_client/quick_sight/`) +- AWS Resource Access Manager (`package:aws_client/ram/`) +- Amazon Recycle Bin (`package:aws_client/rbin/`) +- Amazon Relational Database Service (`package:aws_client/rds/`) +- AWS RDS DataService (`package:aws_client/rds_data/`) +- Amazon Redshift (`package:aws_client/redshift/`) +- Redshift Data API Service (`package:aws_client/redshift_data/`) +- Redshift Serverless (`package:aws_client/redshift_serverless/`) +- Amazon Rekognition (`package:aws_client/rekognition/`) +- AWS Resilience Hub (`package:aws_client/resiliencehub/`) +- AWS Resource Explorer (`package:aws_client/resource_explorer_2/`) +- AWS Resource Groups (`package:aws_client/resource_groups/`) +- AWS Resource Groups Tagging API (`package:aws_client/resource_groups_tagging_api/`) +- AWS RoboMaker (`package:aws_client/robo_maker/`) +- IAM Roles Anywhere (`package:aws_client/roles_anywhere/`) +- Amazon Route 53 (`package:aws_client/route_53/`) +- Route53 Recovery Cluster (`package:aws_client/route_53_recovery_cluster/`) +- AWS Route53 Recovery Control Config (`package:aws_client/route_53_recovery_control_config/`) +- AWS Route53 Recovery Readiness (`package:aws_client/route_53_recovery_readiness/`) +- Amazon Route 53 Domains (`package:aws_client/route_53_domains/`) +- Amazon Route 53 Resolver (`package:aws_client/route_53_resolver/`) +- CloudWatch RUM (`package:aws_client/rum/`) +- Amazon Lex Runtime Service (`package:aws_client/lex_runtime_service/`) +- Amazon Lex Runtime V2 (`package:aws_client/lex_runtime_v2/`) +- Amazon SageMaker Runtime (`package:aws_client/sage_maker_runtime/`) +- Amazon Simple Storage Service (`package:aws_client/s3/`) +- AWS S3 Control (`package:aws_client/s3_control/`) +- Amazon S3 on Outposts (`package:aws_client/s3_outposts/`) +- Amazon SageMaker Service (`package:aws_client/sage_maker/`) +- Amazon Augmented AI Runtime (`package:aws_client/sage_maker_a2i_runtime/`) +- Amazon Sagemaker Edge Manager (`package:aws_client/sagemaker_edge/`) +- Amazon SageMaker Feature Store Runtime (`package:aws_client/sage_maker_feature_store_runtime/`) +- Amazon SageMaker geospatial capabilities (`package:aws_client/sage_maker_geospatial/`) +- Amazon SageMaker Metrics Service (`package:aws_client/sage_maker_metrics/`) +- AWS Savings Plans (`package:aws_client/savingsplans/`) +- Amazon EventBridge Scheduler (`package:aws_client/scheduler/`) +- Schemas (`package:aws_client/schemas/`) +- Amazon SimpleDB (`package:aws_client/simple_db/`) +- AWS Secrets Manager (`package:aws_client/secrets_manager/`) +- AWS SecurityHub (`package:aws_client/security_hub/`) +- Amazon Security Lake (`package:aws_client/security_lake/`) +- AWSServerlessApplicationRepository (`package:aws_client/serverless_application_repository/`) +- Service Quotas (`package:aws_client/service_quotas/`) +- AWS Service Catalog (`package:aws_client/service_catalog/`) +- AWS Service Catalog App Registry (`package:aws_client/service_catalog_app_registry/`) +- AWS Cloud Map (`package:aws_client/service_discovery/`) +- Amazon Simple Email Service (`package:aws_client/se_sv2/`) +- AWS Shield (`package:aws_client/shield/`) +- AWS Signer (`package:aws_client/signer/`) +- AWS SimSpace Weaver (`package:aws_client/sim_space_weaver/`) +- AWS Server Migration Service (`package:aws_client/sms/`) +- Amazon Pinpoint SMS and Voice Service (`package:aws_client/pinpoint_sms_voice/`) +- AWS Snow Device Management (`package:aws_client/snow_device_management/`) +- Amazon Import/Export Snowball (`package:aws_client/snowball/`) +- Amazon Simple Notification Service (`package:aws_client/sns/`) +- Amazon Simple Queue Service (`package:aws_client/sqs/`) +- Amazon Simple Systems Manager (SSM) (`package:aws_client/ssm/`) +- AWS Systems Manager Incident Manager Contacts (`package:aws_client/ssm_contacts/`) +- AWS Systems Manager Incident Manager (`package:aws_client/ssm_incidents/`) +- AWS Systems Manager for SAP (`package:aws_client/ssm_sap/`) +- AWS Single Sign-On (`package:aws_client/sso/`) +- AWS Single Sign-On Admin (`package:aws_client/sso_admin/`) +- AWS SSO OIDC (`package:aws_client/sso_oidc/`) +- AWS Step Functions (`package:aws_client/sfn/`) +- AWS Storage Gateway (`package:aws_client/storage_gateway/`) +- Amazon DynamoDB Streams (`package:aws_client/dynamo_db_streams/`) +- AWS Security Token Service (`package:aws_client/sts/`) +- AWS Support (`package:aws_client/support/`) +- AWS Support App (`package:aws_client/support_app/`) +- Amazon Simple Workflow Service (`package:aws_client/swf/`) +- Synthetics (`package:aws_client/synthetics/`) +- Amazon Textract (`package:aws_client/textract/`) +- Amazon Timestream Query (`package:aws_client/timestream_query/`) +- Amazon Timestream Write (`package:aws_client/timestream_write/`) +- AWS Telco Network Builder (`package:aws_client/tnb/`) +- Amazon Transcribe Service (`package:aws_client/transcribe/`) +- AWS Transfer Family (`package:aws_client/transfer/`) +- Amazon Translate (`package:aws_client/translate/`) +- Amazon Voice ID (`package:aws_client/voice_id/`) +- Amazon VPC Lattice (`package:aws_client/vpc_lattice/`) +- AWS WAF (`package:aws_client/waf/`) +- AWS WAF Regional (`package:aws_client/waf_regional/`) +- AWS WAFV2 (`package:aws_client/wafv2/`) +- AWS Well-Architected Tool (`package:aws_client/well_architected/`) +- Amazon Connect Wisdom Service (`package:aws_client/wisdom/`) +- Amazon WorkDocs (`package:aws_client/work_docs/`) +- Amazon WorkLink (`package:aws_client/work_link/`) +- Amazon WorkMail (`package:aws_client/work_mail/`) +- Amazon WorkMail Message Flow (`package:aws_client/work_mail_message_flow/`) +- Amazon WorkSpaces (`package:aws_client/work_spaces/`) +- Amazon WorkSpaces Web (`package:aws_client/work_spaces_web/`) +- AWS X-Ray (`package:aws_client/x_ray/`) \ No newline at end of file diff --git a/aws_client/README.template.md b/aws_client/README.template.md new file mode 100644 index 000000000..a966f3cfe --- /dev/null +++ b/aws_client/README.template.md @@ -0,0 +1,53 @@ +# High-level APIs for Amazon Web Services (AWS) in Dart + +## Usage + +A simple usage example: + +````dart +import 'package:aws_client/aws_client.dart'; +import 'package:http_client/console.dart'; + +main() async { + var httpClient = newHttpClient(); + var credentials = new Credentials(accessKey: 'MY_ACCESS_KEY', secretKey: 'MY_SECRET_KEY'); + var aws = new Aws(credentials: credentials, httpClient: httpClient); + var queue = aws.sqs.queue('https://my-queue-url/number/queue-name'); + await queue.sendMessage('Hello from Dart client!'); + httpClient.close(); +} +```` + +## How to contribute + +This library is not an official library from Amazon or Google. +It is developed by best effort, in the motto of _"Scratch your own itch!"_, +meaning we have APIs here that we care about. Looking for contributions: + +- tests: + + - never put AWS credentials inside the code + - read AWS credentials from environment variables in the beginning + - provide description what setup it needs upfront + +- API documentation + +- New API contribution: + + - please open an issue ticket first about what you are planning to implement + - take a look at the implementation of the others, most of the API calls will be similar + - always include a link to AWS API docs + +## Links + +- [source code][source] +- contributors: [Agilord][agilord] + +[source]: https://github.com/agilord/aws_client +[agilord]: https://www.agilord.com/ + +## Available AWS APIs + +The following is a list of APIs that are currently available inside this package. + + \ No newline at end of file diff --git a/aws_client/build.yml b/aws_client/build.yml deleted file mode 100644 index 5966460a7..000000000 --- a/aws_client/build.yml +++ /dev/null @@ -1,19 +0,0 @@ -targets: - $default: - builders: - json_serializable: - options: - # Options configure how source code is generated for every - # `@JsonSerializable`-annotated class in the package. - # - # The default value for each is listed. - any_map: false - checked: false - create_factory: true - create_to_json: true - disallow_unrecognized_keys: false - explicit_to_json: false - field_rename: none - ignore_unannotated: false - include_if_null: false - nullable: true \ No newline at end of file diff --git a/aws_client/examples/lambda.example.dart b/aws_client/examples/lambda.example.dart index b1add0b66..4fdc28697 100644 --- a/aws_client/examples/lambda.example.dart +++ b/aws_client/examples/lambda.example.dart @@ -2,38 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be found // in the LICENSE file. -import 'dart:convert'; -import 'dart:io'; - -import 'package:aws_client/aws_client.dart'; -import 'package:aws_client/lambda.dart'; -import 'package:aws_client/src/credentials.dart'; -import 'package:http_client/console.dart'; +import 'package:aws_client/lambda_2015_03_31.dart'; Future main(List args) async { - final environment = Platform.environment; - final Client httpClient = ConsoleClient(); - final credentials = Credentials( - accessKey: environment['AWS_ACCESS_KEY_ID'], - secretKey: environment['AWS_SECRET_ACCESS_KEY'], - sessionToken: environment['AWS_SESSION_TOKEN'], - ); + final lambda = Lambda(region: 'us-west-1'); + try { - final aws = Aws(credentials: credentials, httpClient: httpClient); - final response = await aws.lambda(environment['AWS_DEFAULT_REGION']).invoke( - 'my-function', - json.encode({'number': 4}), - invocationType: LambdaInvocationType.RequestResponse, - headers: {'X-Amz-Log-Type': 'Tail'}, + final response = await lambda.invoke( + functionName: 'my-function', + invocationType: InvocationType.requestResponse, ); print('StatusCode: ${response.statusCode}'); - print('Headers: ${response.headers}'); - final respPayloadString = await response.readAsString(); - print('Payload: $respPayloadString'); - } catch (e) { - print('ERROR!!! $e'); } finally { - await httpClient.close(); + lambda.close(); } } diff --git a/aws_client/examples/sqs.dart b/aws_client/examples/sqs.dart new file mode 100644 index 000000000..aa11f9753 --- /dev/null +++ b/aws_client/examples/sqs.dart @@ -0,0 +1,13 @@ +import 'package:aws_client/sqs_2012_11_05.dart'; + +void main() async { + final sqs = Sqs( + region: 'us-east-1', + credentials: AwsClientCredentials.fromProfileFile(profile: 'prod')); + final queue = await sqs.createQueue( + queueName: 'bucket2', attributes: {QueueAttributeName.delaySeconds: '5'}); + + print(queue.queueUrl); + await sqs.deleteQueue(queueUrl: queue.queueUrl!); + sqs.close(); +} diff --git a/aws_client/lib/aws_client.dart b/aws_client/lib/aws_client.dart deleted file mode 100644 index 73a34f596..000000000 --- a/aws_client/lib/aws_client.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2016, project contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -import 'package:http_client/http_client.dart' as http; - -import 'lambda.dart'; -import 'sns.dart'; -import 'sqs.dart'; -import 'src/credentials.dart'; - -/// AWS access facade that helps to initialize multiple services with common -/// settings (credentials and HTTP client). -class Aws { - final Credentials _credentials; - final http.Client _httpClient; - - Sqs _sqs; - - /// - Aws({Credentials credentials, http.Client httpClient}) - : _credentials = credentials, - _httpClient = httpClient { - assert(_credentials != null); - assert(_httpClient != null); - } - - /// Returns an SQS service, inheriting the properties of this instance. - Sqs get sqs => - _sqs ??= Sqs(credentials: _credentials, httpClient: _httpClient); - - /// Returns an SNS service, inheriting the properties of this instance. - Sns sns(String region) => - Sns(credentials: _credentials, httpClient: _httpClient, region: region); - - Lambda lambda(String region) => Lambda( - credentials: _credentials, httpClient: _httpClient, region: region); -} diff --git a/aws_client/lib/lambda.dart b/aws_client/lib/lambda.dart deleted file mode 100644 index f077c89f5..000000000 --- a/aws_client/lib/lambda.dart +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2019, project contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; - -import 'package:http_client/http_client.dart' as http; - -import 'src/credentials.dart'; -import 'src/request.dart'; - -/// AWS Lambda -class Lambda { - final Credentials _credentials; - final http.Client _httpClient; - final String _region; - - Lambda({Credentials credentials, http.Client httpClient, String region}) - : _credentials = credentials, - _httpClient = httpClient, - _region = region { - assert(_credentials != null); - assert(_httpClient != null); - } - - /// execute real request - Future _sendRequest(String functionName, String body, - Map headers, LambdaInvocationType invocationType) async { - final response = await AwsRequestBuilder( - method: 'POST', - headers: { - 'X-Amz-Invocation-Type': invocationType.toString().split('.')[1], - }..addAll(headers), - baseUrl: - 'https://lambda.$_region.amazonaws.com/2015-03-31/functions/$functionName/invocations', - body: utf8.encode(body), - credentials: _credentials, - httpClient: _httpClient, - region: _region) - .sendRequest(); - response.validateStatus(); - return response; - } - - /// https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html - /// **Optional additional headers** - /// 'X-Amz-Log-Type': 'Tail', - /// 'X-Amz-Client-Context': base64.encode(utf8.encode('{"dart":true}')) - /// - /// functionName: arn:aws:lambda:us-west-2:123456789012:function:my-function <--format not working - /// functionName: my-function:$LATEST, my-function:v1 <--format not working - /// functionName: my-function <--Works! - Future invoke( - String functionName, - String payload, { - Map headers = const {}, - LambdaInvocationType invocationType = LambdaInvocationType.RequestResponse, - }) async { - return _sendRequest(functionName, payload, headers, invocationType); - } -} - -/// https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax -enum LambdaInvocationType { Event, RequestResponse, DryRun } diff --git a/aws_client/lib/sns.dart b/aws_client/lib/sns.dart deleted file mode 100644 index a5bc4b86c..000000000 --- a/aws_client/lib/sns.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'dart:async'; - -import 'package:http_client/http_client.dart' as http; -import 'package:meta/meta.dart'; -import 'package:xml/xml.dart'; - -import 'src/credentials.dart'; -import 'src/request.dart'; - -typedef RequestExecutor = Future Function( - Map parameter); - -/// AWS SQS (Simple Queue Service). -class Sns { - /// AWS SQS - Sns({Credentials credentials, http.Client httpClient, String region}) - : _credentials = credentials, - _httpClient = httpClient, - _region = region { - assert(_credentials != null); - assert(_httpClient != null); - assert(_region != null); - } - - final Credentials _credentials; - final http.Client _httpClient; - final String _region; - - /// execute real request - Future _sendRequest(Map parameters) async { - final endpoint = 'https://sns.$_region.amazonaws.com/'; - final response = await AwsRequestBuilder( - method: 'POST', - baseUrl: endpoint, - formParameters: parameters, - credentials: _credentials, - httpClient: _httpClient, - ).sendRequest(); - final respString = await response.readAsString(); - response.validateStatus(); - return respString; - } - - /// return an Endpoint of arn - SnsEndpoint endpoint(String arn) => SnsEndpoint(_sendRequest, arn); - - /// create an Endpoint with push token - /// implements of https://docs.aws.amazon.com/sns/latest/api/API_CreatePlatformEndpoint.html - Future createEndpoint( - {@required String applicationArn, - @required String pushToken, - String userData = ''}) async { - assert(applicationArn != ''); - assert(pushToken != ''); - final parameters = { - 'Action': 'CreatePlatformEndpoint', - 'PlatformApplicationArn': applicationArn, - 'Token': pushToken, - 'CustomUserData': userData, - 'Version': '2010-03-31' - }; - final xml = parse(await _sendRequest(parameters)); - final endpointArn = xml.findAllElements('EndpointArn').first.text; - return endpoint(endpointArn); - } - - SnsTopic topic(String arn) => SnsTopic(_sendRequest, arn); - - /// Create a Topic - /// implements of https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html - Future createTopic(String name) async { - final parameters = { - 'Action': 'CreateTopic', - 'Name': name, - 'Version': '2010-03-31' - }; - final xml = parse(await _sendRequest(parameters)); - final topicArn = xml.findAllElements('TopicArn').first.text; - return topic(topicArn); - } - - /// Get subscription with arn - SnsSubscription subscription(String arn) => - SnsSubscription(_sendRequest, arn); -} - -/// The device endpoint -class SnsEndpoint { - /// A new endpoint of device - SnsEndpoint(RequestExecutor sendRequest, String arn) - : _sendRequest = sendRequest, - _arn = arn { - assert(sendRequest != null); - assert(arn != null); - } - - final RequestExecutor _sendRequest; - final String _arn; - - /// The endpoint arg - String get arn => _arn; - - /// push message to this endpoint - /// implements of https://docs.aws.amazon.com/sns/latest/api/API_Publish.html - /// return MessageId type:String - Future pushNotification(String body) async { - final parameters = { - 'Action': 'Publish', - 'TargetArn': _arn, - 'Message': body, - 'Version': '2010-03-31' - }; - final xml = parse(await _sendRequest(parameters)); - final messageId = xml.findAllElements('MessageId').first.text; - return messageId; - } -} - -/// SNS's Topic -class SnsTopic { - /// The SNS Topic - SnsTopic(RequestExecutor sendRequest, String arn) - : _sendRequest = sendRequest, - _arn = arn { - assert(sendRequest != null); - assert(arn != null); - } - - final RequestExecutor _sendRequest; - final String _arn; - - /// push message to this Topic - /// implements of https://docs.aws.amazon.com/sns/latest/api/API_Publish.html - /// return MessageId type:String - Future pushNotification(String body) async { - final parameters = { - 'Action': 'Publish', - 'TargetArn': _arn, - 'Message': body, - 'Version': '2010-03-31' - }; - final xml = parse(await _sendRequest(parameters)); - final messageId = xml.findAllElements('MessageId').first.text; - return messageId; - } - - /// Subscribe this topic with given endpoint Arn - /// implements of https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html - /// return SubscriptionArn type:String - Future subscribe(String endpointArn) async { - final parameters = { - 'Action': 'Subscribe', - 'TopicArn': _arn, - 'Endpoint': endpointArn, - 'Protocol': 'application', - 'Version': '2010-03-31' - }; - final xml = parse(await _sendRequest(parameters)); - final subscriptionArn = xml.findAllElements('SubscriptionArn').first.text; - return SnsSubscription(_sendRequest, subscriptionArn); - } -} - -/// The SNS subscription -class SnsSubscription { - /// init subscription - SnsSubscription(RequestExecutor sendRequest, String arn) - : _sendRequest = sendRequest, - _arn = arn { - assert(sendRequest != null); - assert(arn != null); - } - - final RequestExecutor _sendRequest; - final String _arn; - - /// unsubcribe this subscription - Future unsubscribe() async { - final parameters = { - 'Action': 'Unsubscribe', - 'SubscriptionArn': _arn, - 'Version': '2010-03-31' - }; - await _sendRequest(parameters); - } -} diff --git a/aws_client/lib/sqs.dart b/aws_client/lib/sqs.dart deleted file mode 100644 index 501cd6407..000000000 --- a/aws_client/lib/sqs.dart +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2016, project contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:http_client/http_client.dart' as http; -import 'package:meta/meta.dart'; -import 'package:xml/xml.dart'; - -import 'src/credentials.dart'; -import 'src/request.dart'; - -/// AWS SQS (Simple Queue Service). -class Sqs { - final Credentials _credentials; - final http.Client _httpClient; - - /// AWS SQS - Sqs({Credentials credentials, http.Client httpClient}) - : _credentials = credentials, - _httpClient = httpClient { - assert(_credentials != null); - assert(_httpClient != null); - } - - /// Returns a new SQS queue, inheriting the properties of this instance. - SqsQueue queue(String queueUrl) => - SqsQueue(queueUrl, credentials: _credentials, httpClient: _httpClient); - - /// Create a new SQS queue - Future create( - {@required String region, - @required String queueName, - String maxSize = '1024', - String retentionPeriod = '345600'}) async { - assert(region != ''); - assert(queueName != ''); - final endpoint = 'https://sqs.$region.amazonaws.com/'; - final parameters = { - 'Action': 'CreateQueue', - 'QueueName': queueName, - 'Attribute.1.Name': 'MaximumMessageSize', - 'Attribute.1.Value': maxSize, - 'Attribute.2.Name': 'MessageRetentionPeriod', - 'Attribute.2.Value': retentionPeriod - }; - final response = await AwsRequestBuilder( - method: 'GET', - baseUrl: endpoint, - queryParameters: parameters, - credentials: _credentials, - httpClient: _httpClient, - ).sendRequest(); - response.validateStatus(); - final xml = parse(await response.readAsString()); - final queueUrl = xml.findAllElements('QueueUrl').first.text; - return queue(queueUrl); - } -} - -/// AWS SQS message. -class SqsMessage { - /// The message ID - final String messageId; - - /// The receipt handle that can be used to delete the message from the queue. - final String receiptHandle; - - /// The message body. - final String body; - - /// AWS SQS message. - SqsMessage(this.messageId, this.receiptHandle, this.body); - - @override - String toString() => '[$messageId, $receiptHandle, $body]'; -} - -/// AWS SQS Queue -class SqsQueue { - final String _queueUrl; - final Credentials _credentials; - final http.Client _httpClient; - - /// - SqsQueue( - String queueUrl, { - Credentials credentials, - http.Client httpClient, - }) : _credentials = credentials, - _httpClient = httpClient, - _queueUrl = queueUrl { - assert(_credentials != null); - assert(_httpClient != null); - assert(_queueUrl != null); - } - - /// Receives a single message from the queue. - Future receiveOne({int waitSeconds}) async { - final messages = await receiveMessage(1, waitSeconds: waitSeconds); - if (messages.isEmpty) return null; - return messages.first; - } - - /// Receives up to 10 (or up to [number], whichever is lower) messages from - /// the queue. - /// - /// The call will block up to [waitSeconds] if there are not enough messages - /// available immediately. - /// - /// http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html - Future> receiveMessage(int number, {int waitSeconds}) async { - assert(number > 0); - final parameters = { - 'Action': 'ReceiveMessage', - 'MaxNumberOfMessages': number.toString(), - 'Version': '2012-11-05', - }; - if (waitSeconds != null) { - parameters['WaitTimeSeconds'] = waitSeconds.toString(); - } - final response = await AwsRequestBuilder( - method: 'POST', - baseUrl: _queueUrl, - formParameters: parameters, - credentials: _credentials, - httpClient: _httpClient, - ).sendRequest(); - response.validateStatus(); - final xml = parse(await response.readAsString()); - return xml - .findAllElements('Message') - // LOW PRIORITY: check MD5 signature - .map((XmlElement elem) => SqsMessage( - elem.findElements('MessageId').first.text, - elem.findElements('ReceiptHandle').first.text, - elem.findElements('Body').first.text, - )) - .toList(); - } - - /// Delete a message from the queue by its [receiptHandle]. - /// - /// http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html - Future deleteMessage(String receiptHandle) async { - final parameters = { - 'Action': 'DeleteMessage', - 'ReceiptHandle': receiptHandle, - 'Version': '2012-11-05', - }; - final response = await AwsRequestBuilder( - method: 'POST', - baseUrl: _queueUrl, - formParameters: parameters, - credentials: _credentials, - httpClient: _httpClient, - ).sendRequest(); - response.validateStatus(); - } - - /// Sends a new message into the queue. - /// - /// http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html - Future sendMessage(String body, - {String messageGroupId, String messageDeduplicationId}) async { - final parameters = { - 'Action': 'SendMessage', - 'MessageBody': body, - 'Version': '2012-11-05' - }; - if (messageGroupId != null) { - parameters['MessageGroupId'] = messageGroupId; - } - if (messageDeduplicationId != null) { - parameters['MessageDeduplicationId'] = messageDeduplicationId; - } - final response = await AwsRequestBuilder( - method: 'POST', - baseUrl: _queueUrl, - formParameters: parameters, - credentials: _credentials, - httpClient: _httpClient, - ).sendRequest(); - response.validateStatus(); - } -} diff --git a/aws_client/lib/src/credentials.dart b/aws_client/lib/src/credentials.dart deleted file mode 100644 index 2aca11e6b..000000000 --- a/aws_client/lib/src/credentials.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2016, project contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -import 'package:meta/meta.dart'; - -/// AWS credentials. -class Credentials { - /// AWS access key - final String accessKey; - - /// AWS secret key - final String secretKey; - - /// AWS temporary credentials session token - final String sessionToken; - - /// AWS credentials. - Credentials( - {@required this.accessKey, @required this.secretKey, this.sessionToken}) { - assert(accessKey != null); - assert(secretKey != null); - } -} diff --git a/aws_client/lib/src/request.dart b/aws_client/lib/src/request.dart deleted file mode 100644 index a2ff25918..000000000 --- a/aws_client/lib/src/request.dart +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2016, project contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:crypto/crypto.dart'; -import 'package:http_client/http_client.dart'; - -import 'credentials.dart'; - -/// AWS response object. -class AwsResponse { - /// HTTP status code. - final int statusCode; - - /// HTTP status text. - final String statusText; - - /// HTTP headers. - final Map headers; - final Stream> _body; - - bool _bodyWasUsed = false; - - /// AWS response object. - AwsResponse( - this.statusCode, this.statusText, this.headers, Stream> body) - : _body = body; - - /// A very lousy way to validate some of the common status codes. - /// https://http.cat/ - void validateStatus() { - if (statusCode >= 200 && statusCode <= 207) return; - // TODO: check for different type of errors - // TODO: introduce transient exception for error handling - throw Exception( - 'Bad response code=$statusCode, statusText=$statusText, headers=$headers.'); - } - - /// Reads the entire response into a byte array. - Future> readAsBytes() async { - assert(_bodyWasUsed == false); - _bodyWasUsed = true; - final builder = BytesBuilder(copy: false); - await _body.forEach(builder.add); - return builder.toBytes(); - } - - /// Reads the entire response into a single String. - Future readAsString({Encoding encoding = utf8}) async { - return encoding.decode(await readAsBytes()); - } -} - -const _aws4HmacSha256 = 'AWS4-HMAC-SHA256'; - -String _queryComponent(String path) => - Uri.encodeQueryComponent(path).replaceAll('+', '%20'); - -String _extractRegion(Uri uri) { - final parts = uri.host.split('.'); - if (parts.length == 4 && parts[1].contains('-')) return parts[1]; - throw Exception('Unable to detect region in ${uri.host}.'); -} - -String _extractService(Uri uri) { - final parts = uri.host.split('.'); - if (parts.length == 4) return parts.first; - throw Exception('Unable to detect service in ${uri.host}.'); -} - -/// Builds an AWS request. -class AwsRequestBuilder { - /// HTTP method. - String method; - - /// Full URL. If set, [baseUrl] and [queryParameters] mustn't be set. - Uri uri; - - /// Base URL for easier [uri] construction. - String baseUrl; - - /// Query parameters for easier [uri] construction. - Map queryParameters; - - /// HTTP Headers - Map headers; - - /// request content - List body; - - /// Sets the body with the given parameters in a form-url-encoded format. - Map formParameters; - - /// AWS region - String region; - - /// AWS service - String service; - - /// AWS credentials - Credentials credentials; - - /// HTTP client - Client httpClient; - - /// Builds an AWS request. - AwsRequestBuilder({ - this.method = 'GET', - this.uri, - this.headers, - this.body, - this.formParameters, - this.region, - this.service, - this.credentials, - this.httpClient, - this.baseUrl, - this.queryParameters, - }); - - /// Initializes and signs a request. - Request buildRequest() { - assert(credentials != null); - assert(httpClient != null); - _initDefaults(); - _sign(); - return Request(method, uri, headers: headers, body: body); - } - - /// Initializes, signs and send the request. - Future sendRequest() async { - final rq = buildRequest(); - final rs = await httpClient.send(rq); - return AwsResponse(rs.statusCode, rs.reasonPhrase, rs.headers.toSimpleMap(), - rs.bodyAsStream); - } - - void _initDefaults() { - if (uri != null) { - assert(baseUrl == null); - assert(queryParameters == null); - } else { - assert(baseUrl != null); - var url = baseUrl; - if (queryParameters != null) { - url = '$url${Uri(queryParameters: queryParameters)}'; - } - uri = Uri.parse(url); - } - headers ??= {}; - headers.putIfAbsent('Host', () => uri.host); - if (body == null && formParameters != null && formParameters.isNotEmpty) { - body = utf8.encode(formParameters.keys - .map((key) => '${Uri.encodeQueryComponent(key)}=' - '${Uri.encodeQueryComponent(formParameters[key])}') - .join('&')); - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } - body ??= const []; - headers.putIfAbsent('X-Amz-Date', () { - final date = DateTime.now() - .toUtc() - .toIso8601String() - .replaceAll('-', '') - .replaceAll(':', '') - .split('.') - .first; - return '${date}Z'; - }); - region ??= _extractRegion(uri); - service ??= _extractService(uri); - } - - void _sign() { - final queryKeys = uri.queryParameters.keys.toList()..sort(); - final canonicalQuery = queryKeys - .map((s) => - '${_queryComponent(s)}=${_queryComponent(uri.queryParameters[s])}') - .join('&'); - final canonicalHeaders = headers.keys - .map((key) => '${key.toLowerCase()}:${headers[key].trim()}') - .toList() - ..sort(); - final signedHeaders = - (headers.keys.toList()..sort()).map((s) => s.toLowerCase()).join(';'); - - final payloadHash = - headers['X-Amz-Content-Sha256'] ?? sha256.convert(body).toString(); - - final canonical = [ - method.toUpperCase(), - Uri.encodeFull(uri.path), - canonicalQuery, - ...canonicalHeaders, - '', - signedHeaders, - payloadHash, - ].join('\n'); - - final date = headers['X-Amz-Date']; - final credentialList = [ - date.substring(0, 8), - region, - service, - 'aws4_request', - ]; - final canonicalHash = sha256.convert(utf8.encode(canonical)).toString(); - final toSign = [ - _aws4HmacSha256, - date, - credentialList.join('/'), - canonicalHash, - ].join('\n'); - final signingKey = credentialList.fold( - utf8.encode('AWS4${credentials.secretKey}'), (List key, String s) { - final hmac = Hmac(sha256, key); - return hmac.convert(utf8.encode(s)).bytes; - }); - final signature = - Hmac(sha256, signingKey).convert(utf8.encode(toSign)).toString(); - if (credentials.sessionToken != null) { - headers['X-Amz-Security-Token'] = credentials.sessionToken; - } - - final auth = '$_aws4HmacSha256 ' - 'Credential=${credentials.accessKey}/${credentialList.join('/')}, ' - 'SignedHeaders=$signedHeaders, ' - 'Signature=$signature'; - headers['Authorization'] = auth; - } -} diff --git a/aws_client/lib/src/shared/src/protocol/endpoint_config_data.dart b/aws_client/lib/src/shared/src/protocol/endpoint_config_data.dart new file mode 100644 index 000000000..8a1235b0f --- /dev/null +++ b/aws_client/lib/src/shared/src/protocol/endpoint_config_data.dart @@ -0,0 +1,112 @@ +// AUTO-GENERATED: This file is generated by the `generator` package + +import 'endpoint.dart'; + +final rules = { + '*/*': RegionConfig( + endpoint: '{service}.{region}.amazonaws.com', + ), + 'cn-*/*': RegionConfig( + endpoint: '{service}.{region}.amazonaws.com.cn', + ), + 'us-iso-*/*': _usIso, + 'us-isob-*/*': _usIsob, + '*/budgets': _globalSSL, + '*/cloudfront': _globalSSL, + '*/sts': _globalSSL, + '*/importexport': RegionConfig( + endpoint: '{service}.amazonaws.com', + globalEndpoint: true, + signatureVersion: 'v2', + ), + '*/route53': _globalSSL, + 'cn-*/route53': RegionConfig( + endpoint: '{service}.amazonaws.com.cn', + globalEndpoint: true, + signingRegion: 'cn-northwest-1', + ), + 'us-gov-*/route53': _globalGovCloud, + 'us-iso-*/route53': RegionConfig( + endpoint: '{service}.c2s.ic.gov', + globalEndpoint: true, + signingRegion: 'us-iso-east-1', + ), + 'us-isob-*/route53': RegionConfig( + endpoint: '{service}.sc2s.sgov.gov', + globalEndpoint: true, + signingRegion: 'us-isob-east-1', + ), + '*/waf': _globalSSL, + '*/iam': _globalSSL, + 'cn-*/iam': RegionConfig( + endpoint: '{service}.cn-north-1.amazonaws.com.cn', + globalEndpoint: true, + signingRegion: 'cn-north-1', + ), + 'us-iso-*/iam': RegionConfig( + endpoint: '{service}.us-iso-east-1.c2s.ic.gov', + globalEndpoint: true, + signingRegion: 'us-iso-east-1', + ), + 'us-gov-*/iam': _globalGovCloud, + 'us-gov-*/sts': RegionConfig( + endpoint: '{service}.{region}.amazonaws.com', + ), + 'us-gov-west-1/s3': _s3Signature, + 'us-west-1/s3': _s3Signature, + 'us-west-2/s3': _s3Signature, + 'eu-west-1/s3': _s3Signature, + 'ap-southeast-1/s3': _s3Signature, + 'ap-southeast-2/s3': _s3Signature, + 'ap-northeast-1/s3': _s3Signature, + 'sa-east-1/s3': _s3Signature, + 'us-east-1/s3': RegionConfig( + endpoint: '{service}.amazonaws.com', + signatureVersion: 's3', + ), + 'us-east-1/sdb': RegionConfig( + endpoint: '{service}.amazonaws.com', + signatureVersion: 'v2', + ), + '*/sdb': RegionConfig( + endpoint: '{service}.{region}.amazonaws.com', + signatureVersion: 'v2', + ), + '*/resource-explorer-2': _dualstackByDefault, + '*/kendra-ranking': _dualstackByDefault, + '*/internetmonitor': _dualstackByDefault, + '*/codecatalyst': _globalDualstackByDefault, +}; + +final _globalSSL = RegionConfig( + endpoint: 'https://{service}.amazonaws.com', + globalEndpoint: true, + signingRegion: 'us-east-1', +); + +final _globalGovCloud = RegionConfig( + endpoint: '{service}.us-gov.amazonaws.com', + globalEndpoint: true, + signingRegion: 'us-gov-west-1', +); + +final _s3Signature = RegionConfig( + endpoint: '{service}.{region}.amazonaws.com', + signatureVersion: 's3', +); + +final _usIso = RegionConfig( + endpoint: '{service}.{region}.c2s.ic.gov', +); + +final _usIsob = RegionConfig( + endpoint: '{service}.{region}.sc2s.sgov.gov', +); + +final _dualstackByDefault = RegionConfig( + endpoint: '{service}.{region}.api.aws', +); + +final _globalDualstackByDefault = RegionConfig( + endpoint: '{service}.global.api.aws', +); diff --git a/aws_client/pubspec.yaml b/aws_client/pubspec.yaml index 0e6660bbe..7cd184c1e 100644 --- a/aws_client/pubspec.yaml +++ b/aws_client/pubspec.yaml @@ -1,23 +1,21 @@ name: aws_client description: High-level APIs for Amazon Web Services (AWS) -version: 0.3.0-dev -author: Istvan Soos +version: 0.4.0 homepage: https://github.com/agilord/aws_client environment: - sdk: '>=2.6.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: - crypto: ^2.1.3 - http_client: '>=0.5.0 <2.0.0' - meta: ^1.1.8 - xml: ^3.5.0 - json_annotation: ^3.0.0 + crypto: ^3.0.1 + http: ^0.13.1 + meta: ^1.3.0 + xml: '>=6.0.0 <7.0.0' + intl: '>=0.17.0 <0.19.0' + uuid: ^3.0.3 + collection: ^1.15.0 dev_dependencies: - pedantic: ^1.8.0+1 - test: ^1.9.4 - archive: ^2.0.11 - build_runner: ^1.7.2 - json_serializable: ^3.2.3 + lints: + test: diff --git a/aws_client/test/impl_test.dart b/aws_client/test/impl_test.dart deleted file mode 100644 index cbad40adf..000000000 --- a/aws_client/test/impl_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -library aws_client.test.impl_test; - -import 'dart:io'; - -import 'package:aws_client/aws_client.dart'; -import 'package:aws_client/src/credentials.dart'; -import 'package:http_client/console.dart'; -import 'package:test/test.dart'; - -void main() { - final env = Platform.environment; - - final accessKey = env['AWS_ACCESS_KEY_ID']; - final accessSecret = env['AWS_SECRET_ACCESS_KEY']; - final region = env['AWS_DEFAULT_REGION']; - final appArn = env['AWS_TEST_APP_ARN']; - - group('SQS-queue', () { - test('create-queue', () async { - final httpClient = ConsoleClient(); - final credentials = - Credentials(accessKey: accessKey, secretKey: accessSecret); - final aws = Aws(credentials: credentials, httpClient: httpClient); - final queue = await aws.sqs - .create(region: region, queueName: '[set your queue name]'); - await queue.sendMessage('test message'); - expect(true, equals(true)); - }); - - test('Queue-send', () async { - final httpClient = ConsoleClient(); - final credentials = - Credentials(accessKey: accessKey, secretKey: accessSecret); - final aws = Aws(credentials: credentials, httpClient: httpClient); - final queue = aws.sqs.queue('[set your own]'); - await queue.sendMessage('test test test'); - expect(true, equals(true)); - }); - - test('SNS-createEndpoint', () async { - final httpClient = ConsoleClient(); - final credentials = - Credentials(accessKey: accessKey, secretKey: accessSecret); - final aws = Aws(credentials: credentials, httpClient: httpClient); - final sns = aws.sns(region); - final endpoint = await sns.createEndpoint( - applicationArn: appArn, pushToken: 'your device push token'); - print('endpoint: ${endpoint.arn}'); - expect(true, equals(true)); - }); - }); -} diff --git a/generator/bin/generate.dart b/generator/bin/generate.dart index 7abe7824c..29a1ec8e8 100644 --- a/generator/bin/generate.dart +++ b/generator/bin/generate.dart @@ -1,6 +1,7 @@ import 'package:args/command_runner.dart'; import 'package:aws_client_generator/download_command.dart'; import 'package:aws_client_generator/generate_command.dart'; +import 'package:aws_client_generator/generate_single_package_command.dart'; import 'package:aws_client_generator/package_command.dart'; void main(List arguments) async { @@ -10,6 +11,7 @@ void main(List arguments) async { ) ..addCommand(DownloadCommand()) ..addCommand(GenerateCommand()) + ..addCommand(GenerateSinglePackageCommand()) ..addCommand(PackageCommand()); await runner.run(arguments); } diff --git a/generator/lib/builders/library_builder.dart b/generator/lib/builders/library_builder.dart index a3f551f90..6964f1d58 100644 --- a/generator/lib/builders/library_builder.dart +++ b/generator/lib/builders/library_builder.dart @@ -1,4 +1,6 @@ import 'dart:math'; +import 'package:source_helper/source_helper.dart'; + import '../model/api.dart'; import '../model/dart_type.dart'; import '../model/operation.dart'; @@ -14,7 +16,8 @@ import 'protocols/rest_json_builder.dart'; import 'protocols/rest_xml_builder.dart'; import 'protocols/service_builder.dart'; -String buildService(Api api) { +String buildService(Api api, + {String sharedLibraryPath = 'package:shared_aws_api'}) { api.initReferences(); ServiceBuilder builder; @@ -44,13 +47,13 @@ String buildService(Api api) { import 'dart:convert'; import 'dart:typed_data'; -import 'package:shared_aws_api/shared.dart' as _s; -import 'package:shared_aws_api/shared.dart' +import '$sharedLibraryPath/shared.dart' as _s; +import '$sharedLibraryPath/shared.dart' show rfc822ToJson, iso8601ToJson, unixTimestampToJson, nonNullableTimeStampFromJson, timeStampFromJson; """); buf.writeln(builder.imports()); buf.writeln( - "export 'package:shared_aws_api/shared.dart' show AwsClientCredentials;\n"); + "export '$sharedLibraryPath/shared.dart' show AwsClientCredentials;\n"); final body = StringBuffer() ..putMainClass(api, builder) @@ -115,7 +118,7 @@ ${builder.constructor()} } if (operation.deprecated) { - writeln("@Deprecated('Deprecated')"); + _writeDeprecated(operation.deprecatedMessage); } operation.output?.shapeClass?.markUsed(false); @@ -196,7 +199,7 @@ ${builder.constructor()} if (shape.enumeration != null) { writeln(dartdocComment(shape.documentation ?? '')); if (shape.deprecated) { - writeln(r"@Deprecated('Deprecated')"); + _writeDeprecated(shape.deprecatedMessage); } writeln('enum $name {'); @@ -233,11 +236,14 @@ ${builder.constructor()} } else if (shape.type == 'structure') { writeln(dartdocComment(shape.documentation ?? '')); if (shape.deprecated) { - writeln(r'@deprecated'); + _writeDeprecated(shape.deprecatedMessage); } final extendsBlock = shape.exception ? 'implements _s.AwsException ' : ''; + if (name.contains('_')) { + writeln('// ignore: camel_case_types'); + } writeln('class $name $extendsBlock{'); for (final member in shape.members) { if (member.documentation != null) { @@ -307,9 +313,9 @@ ${builder.constructor()} writeln(' }'); } - if (shape.generateToJson) { - writeln('\n Map toJson() {'); - for (var member in shape.members.where((m) => m.isBody)) { + if (shape.generateToJson || Api.isGeneratingSinglePackage) { + writeln('\n\n Map toJson() {'); + for (var member in shape.members) { writeln('final ${member.fieldName} = this.${member.fieldName};'); } writeln('return {'); @@ -409,6 +415,10 @@ ${builder.constructor()} } writeln('};'); } + + void _writeDeprecated(String? message) { + writeln("@Deprecated(${escapeDartString(message ?? 'Deprecated')})"); + } } String calculateDateTimeToJson(Member member) { diff --git a/generator/lib/builders/protocols/rest_json_builder.dart b/generator/lib/builders/protocols/rest_json_builder.dart index 8e8bed17b..10cf7831c 100644 --- a/generator/lib/builders/protocols/rest_json_builder.dart +++ b/generator/lib/builders/protocols/rest_json_builder.dart @@ -130,8 +130,14 @@ class RestJsonServiceBuilder extends ServiceBuilder { } } for (var member in outputShape.members.where((m) => m.isHeader)) { - buf.writeln( - "${member.fieldName}: ${extractHeaderCode(member, 'response.headers')}${member.isRequired ? '!' : ''},"); + var headerCode = extractHeaderCode(member, 'response.headers'); + if (member.isRequired) { + if (headerCode.contains('?.to')) { + headerCode = '($headerCode)'; + } + headerCode += '!'; + } + buf.writeln('${member.fieldName}: $headerCode,'); } for (var member in outputShape.members.where((m) => m.isStatusCode)) { buf.writeln('${member.fieldName}: response.statusCode,'); diff --git a/generator/lib/generate_single_package_command.dart b/generator/lib/generate_single_package_command.dart new file mode 100644 index 000000000..61bd8d520 --- /dev/null +++ b/generator/lib/generate_single_package_command.dart @@ -0,0 +1,240 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:path/path.dart' as p; + +import 'builders/endpoint_config_builder.dart'; +import 'builders/library_builder.dart'; +import 'generate_command.dart'; +import 'model/api.dart'; +import 'model/region_config.dart'; +import 'model_thin/api.dart' as thin; +import 'utils/fix_absolute_import.dart'; + +class GenerateSinglePackageCommand extends Command { + final _formatter = DartFormatter(fixes: StyleFix.all); + + @override + String get name => 'generate-single-package'; + + @override + String get description => + '''Generate a single package containing all the AWS APIs.'''; + + GenerateSinglePackageCommand(); + + @override + Future run() async { + final stopwatch = Stopwatch()..start(); + + await _generateClasses(); + await _generateConfigFiles(); + + print('Generator finished in ${stopwatch.elapsed}'); + } + + Future _generateClasses() async { + print('Generating Dart classes...'); + + Api.isGeneratingSinglePackage = true; + final dir = Directory('./apis'); + final files = dir.listSync().whereType().toList(); + files.sort((a, b) => a.path.compareTo(b.path)); + final services = {}; + final readmeDescriptions = {}; + + for (var ent in files) { + final parts = ent.uri.pathSegments.last.split('.') + ..removeLast() + ..removeLast(); + services.add(parts.join('.')); + } + + final generatedApis = {}; + + final packageDir = '../aws_client'; + final libDir = p.join(packageDir, 'lib'); + final generatedDir = '$libDir/src/generated'; + + _clearDir(libDir); + + _copyPackages(); + + for (var i = 0; i < services.length; i++) { + final service = services.elementAt(i); + final def = File('./apis/$service.normal.json'); + + final defJson = + jsonDecode(def.readAsStringSync()) as Map; + + try { + final api = Api.fromJson(defJson); + final thinApi = thin.Api.fromJson(defJson); + + final percentage = i * 100 ~/ services.length; + + printPercentageInPlace( + percentage, 'Generating API ${api.metadata.serviceFullName}'); + + readmeDescriptions.add( + '${api.metadata.serviceFullName} (`package:aws_client/${api.directoryName}/`)'); + + // create directories + final baseDir = '$generatedDir/${api.directoryName}'; + final serviceFile = File('$baseDir/${api.fileBasename}.dart'); + final entryFile = File( + '$libDir/${api.directoryName}_${api.fileBasename.substring(1)}.dart'); + + serviceFile.parent.createSync(recursive: true); + entryFile.parent.createSync(recursive: true); + + var metaContents = ''' +// ignore_for_file: prefer_single_quotes +const Map> shapesJson = ${jsonEncode(thinApi.toJson()['shapes'])};'''; + + var entryContent = ''' +export '../src/generated/${api.directoryName}/${api.fileBasename}.dart'; +'''; + + var serviceText = buildService(api, sharedLibraryPath: '../../shared'); + serviceText = _formatter.format(serviceText, uri: serviceFile.uri); + metaContents = _formatter.format(metaContents); + entryContent = _formatter.format(entryContent); + + if (api.usesQueryProtocol) { + File('$baseDir/${api.fileBasename}.meta.dart') + .writeAsStringSync(metaContents); + } + + serviceFile.writeAsStringSync(serviceText); + entryFile.writeAsStringSync(entryContent); + + generatedApis[api.directoryName] = api.metadata.serviceFullName; + } on UnrecognizedKeysException catch (e) { + print('Error deserializing $service'); + print(e.message); + rethrow; + } catch (e) { + print('Error "${e.runtimeType}" deserializing $service'); + rethrow; + } + } + + File(p.join(libDir, 'dynamo_document.dart')).writeAsStringSync(''' +export 'src/dynamo_document/document_client.dart'; +export 'src/dynamo_document/src/translator.dart'; +'''); + + var readmeTemplate = + File(p.join(packageDir, 'README.template.md')).readAsStringSync(); + readmeTemplate = readmeTemplate.replaceAll('', + readmeDescriptions.map((d) => '- $d').join('\n')); + File(p.join(packageDir, 'README.md')).writeAsStringSync(readmeTemplate); + + printPercentageInPlace(100, 'Done'); + print('\n'); + + print('\nGenerated APIs:'); + + for (var e in (generatedApis.entries.toList() + ..sort((a, b) => a.value.compareTo(b.value)))) { + print('- ${e.value}'); + } + } + + void _clearDir(String path) { + final directory = Directory(path); + if (directory.existsSync()) { + directory.deleteSync(recursive: true); + } + } + + final _configDataFile = File('./apis/config/region_config_data.json'); + Future _generateConfigFiles() async { + final jsonContent = jsonDecode(await _configDataFile.readAsString()) + as Map; + final configData = RegionConfigData.fromJson(jsonContent); + final endpointConfigCode = + _formatter.format(buildEndpointConfig(configData)); + + File('../aws_client/lib/src/shared/src/protocol/endpoint_config_data.dart') + ..createSync(recursive: true) + ..writeAsStringSync(endpointConfigCode); + + print('Generated endpoint_config_data file'); + } + + void _copyPackages() { + final packagePath = '../aws_client'; + + _copy('../shared_aws_api/lib', '$packagePath/lib/src/shared'); + _copy('../document_client/lib', '$packagePath/lib/src/dynamo_document'); + _copy('../aws_credential_providers/lib', + '$packagePath/lib/src/credential_providers'); + + final replaceRoot = '$packagePath/lib/src'; + _searchAndReplace(replaceRoot, { + 'package:aws_dynamodb_api/dynamodb-2012-08-10.dart': + 'package:aws_client/dynamo_db_2012_08_10.dart', + 'package:aws_sts_api/sts-2011-06-15.dart': + 'package:aws_client/sts_2011_06_15.dart', + 'package:shared_aws_api/shared.dart': + 'package:aws_client/src/shared/shared.dart', + }); + _replaceInFile( + File('$packagePath/lib/src/credential_providers/src/ini/ini_io.dart'), + {'STS(': 'Sts('}); + + for (var file in Directory(replaceRoot) + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart'))) { + final path = p.relative(file.path, from: '../aws_client'); + final fileContent = replaceAbsoluteImports(file.readAsStringSync(), + filePath: path, packageName: 'aws_client'); + file.writeAsStringSync(fileContent); + } + } + + void _copy(String source, String destination) { + _clearDir(destination); + _copyDirectory(Directory(source), Directory(destination)); + } +} + +void _copyDirectory(Directory source, Directory destination) { + for (var entity in source.listSync(recursive: false)) { + if (entity is Directory) { + final newDirectory = + Directory(p.join(destination.absolute.path, p.basename(entity.path))); + newDirectory.createSync(recursive: true); + + _copyDirectory(entity.absolute, newDirectory); + } else if (entity is File) { + final destPath = p.join(destination.path, p.basename(entity.path)); + File(destPath).parent.createSync(recursive: true); + entity.copySync(destPath); + } + } +} + +void _searchAndReplace(String directory, Map terms) { + for (var file in Directory(directory) + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart'))) { + _replaceInFile(file, terms); + } +} + +void _replaceInFile(File file, Map terms) { + var content = file.readAsStringSync(); + for (var term in terms.entries) { + content = content.replaceAll(term.key, term.value); + } + file.writeAsStringSync(content); +} diff --git a/generator/lib/model/api.dart b/generator/lib/model/api.dart index 7c9bd45e1..face0dd55 100644 --- a/generator/lib/model/api.dart +++ b/generator/lib/model/api.dart @@ -2,14 +2,16 @@ import 'package:json_annotation/json_annotation.dart'; import '../utils/aws_names.dart'; +import '../utils/case.dart'; import 'descriptor.dart'; import 'operation.dart'; import 'shape.dart'; - part 'api.g.dart'; @JsonSerializable(createToJson: false) class Api { + static bool isGeneratingSinglePackage = false; + final String? version; final Metadata metadata; final Map operations; @@ -72,10 +74,16 @@ class Api { } String get fileBasename { + if (isGeneratingSinglePackage) { + return _singlePackageFileBasename; + } // TODO: lowercase file name return metadata.uid ?? '${metadata.endpointPrefix}-${metadata.apiVersion}'; } + String get _singlePackageFileBasename => + 'v${metadata.apiVersion.replaceAll('-', '_')}'; + bool get isRecognized => packageBaseName != null; String get packageName { @@ -135,6 +143,14 @@ class Api { 'sts', 'waf', }.contains(metadata.endpointPrefix); + + String get directoryName { + final name = metadata.serviceId ?? + metadata.serviceAbbreviation ?? + metadata.uid?.split('-20').first.toLowerCase() ?? + metadata.serviceFullName; + return snakeCase(splitWords(name)); + } } @JsonSerializable(createToJson: false, disallowUnrecognizedKeys: true) @@ -184,11 +200,33 @@ class Metadata { ); String get className { + if (Api.isGeneratingSinglePackage) { + return _singlePackageClassName; + } + final name = (serviceAbbreviation ?? serviceFullName) .replaceAll(RegExp(r'^Amazon|AWS\s*|\(.*|\s+|\W+'), ''); return name.substring(0, 1).toUpperCase() + name.substring(1); } + String get _singlePackageClassName { + final baseName = (serviceAbbreviation ?? serviceFullName) + .replaceAll(RegExp(r'^Amazon|AWS\s*'), ''); + + // Try to follow Effective Dart: DO capitalize acronyms and abbreviations longer than two letters like words. + // https://dart.dev/guides/language/effective-dart/style#do-capitalize-acronyms-and-abbreviations-longer-than-two-letters-like-words + final words = splitWords(baseName).map((w) { + if (const ['IoT'].contains(w) || w.length < 3) { + return w; + } + return w.toLowerCase(); + }).toList(); + if (words.last == 'service' && words.first != 'config') { + words.removeLast(); + } + return upperCamel(words); + } + factory Metadata.fromJson(Map json) => _$MetadataFromJson(json); } diff --git a/generator/lib/utils/case.dart b/generator/lib/utils/case.dart index bd303a716..f6d913460 100644 --- a/generator/lib/utils/case.dart +++ b/generator/lib/utils/case.dart @@ -26,6 +26,10 @@ String lowerCamel(Iterable input) { .join(''); } +String snakeCase(Iterable input) { + return input.map((i) => i.toLowerCase()).join('_'); +} + String upperCamel(Iterable input) { return input.map(capitalize).join(''); } diff --git a/generator/lib/utils/fix_absolute_import.dart b/generator/lib/utils/fix_absolute_import.dart new file mode 100644 index 000000000..7d39aedbe --- /dev/null +++ b/generator/lib/utils/fix_absolute_import.dart @@ -0,0 +1,33 @@ +import 'package:analyzer/dart/analysis/utilities.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:path/path.dart' as p; + +String replaceAbsoluteImports(String content, + {required String filePath, required String packageName}) { + filePath = filePath.replaceAll(r'\', '/'); + assert(filePath.startsWith('lib/')); + filePath = filePath.substring('lib/'.length); + var newContent = content; + + final unit = parseString(content: content).unit; + + for (var directive + in unit.directives.reversed.whereType()) { + final uriValue = directive.uri.stringValue!; + final absolutePrefix = 'package:$packageName/'; + if (uriValue.startsWith(absolutePrefix)) { + final absoluteImportFromLib = uriValue.replaceAll(absolutePrefix, ''); + final relativePath = p + .relative(absoluteImportFromLib, from: p.dirname(filePath)) + .replaceAll(r'\', '/'); + + final directiveContent = + directive.uri.toString().replaceAll(uriValue, relativePath); + + newContent = newContent.replaceRange(directive.uri.offset, + directive.uri.offset + directive.uri.length, directiveContent); + } + } + + return newContent; +} diff --git a/generator/pubspec.yaml b/generator/pubspec.yaml index d5e49431b..5faad99f7 100644 --- a/generator/pubspec.yaml +++ b/generator/pubspec.yaml @@ -7,8 +7,10 @@ environment: sdk: '>=2.15.0 <3.0.0' dependencies: + analyzer: ^5.13.0 archive: ^3.0.0 args: ^2.2.0 + collection: ^1.17.2 dart_style: ^2.0.0 html: ^0.15.0 http: ^0.13.3 @@ -16,6 +18,7 @@ dependencies: path: ^1.7.0 pool: ^1.4.0 process_runner: ^4.0.0 + source_helper: ^1.3.3 version: ^2.0.0 yaml: ^3.0.0