diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -86,9 +86,11 @@ 'PhutilAWSException' => 'future/aws/PhutilAWSException.php', 'PhutilAWSFuture' => 'future/aws/PhutilAWSFuture.php', 'PhutilAWSManagementWorkflow' => 'future/aws/management/PhutilAWSManagementWorkflow.php', + 'PhutilAWSS3DeleteManagementWorkflow' => 'future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php', 'PhutilAWSS3Future' => 'future/aws/PhutilAWSS3Future.php', 'PhutilAWSS3GetManagementWorkflow' => 'future/aws/management/PhutilAWSS3GetManagementWorkflow.php', 'PhutilAWSS3ManagementWorkflow' => 'future/aws/management/PhutilAWSS3ManagementWorkflow.php', + 'PhutilAWSS3PutManagementWorkflow' => 'future/aws/management/PhutilAWSS3PutManagementWorkflow.php', 'PhutilAWSv4Signature' => 'future/aws/PhutilAWSv4Signature.php', 'PhutilAWSv4SignatureTestCase' => 'future/aws/__tests__/PhutilAWSv4SignatureTestCase.php', 'PhutilAggregateException' => 'error/PhutilAggregateException.php', @@ -607,9 +609,11 @@ 'PhutilAWSException' => 'Exception', 'PhutilAWSFuture' => 'FutureProxy', 'PhutilAWSManagementWorkflow' => 'PhutilArgumentWorkflow', + 'PhutilAWSS3DeleteManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSS3Future' => 'PhutilAWSFuture', 'PhutilAWSS3GetManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSS3ManagementWorkflow' => 'PhutilAWSManagementWorkflow', + 'PhutilAWSS3PutManagementWorkflow' => 'PhutilAWSS3ManagementWorkflow', 'PhutilAWSv4Signature' => 'Phobject', 'PhutilAWSv4SignatureTestCase' => 'PhutilTestCase', 'PhutilAggregateException' => 'Exception', diff --git a/src/future/aws/PhutilAWSFuture.php b/src/future/aws/PhutilAWSFuture.php --- a/src/future/aws/PhutilAWSFuture.php +++ b/src/future/aws/PhutilAWSFuture.php @@ -10,6 +10,8 @@ private $path = '/'; private $params = array(); private $endpoint; + private $data = ''; + private $headers = array(); abstract public function getServiceName(); @@ -71,25 +73,45 @@ return $this->path; } + public function setData($data) { + $this->data = $data; + return $this; + } + + public function getData() { + return $this->data; + } + protected function getParameters() { $params = $this->params; return $params; } + public function addHeader($key, $value) { + $this->headers[] = array($key, $value); + return $this; + } + protected function getProxiedFuture() { if (!$this->future) { $params = $this->getParameters(); $method = $this->getHTTPMethod(); $host = $this->getEndpoint(); $path = $this->getPath(); + $data = $this->getData(); $uri = id(new PhutilURI("https://{$host}/")) ->setPath($path) ->setQueryParams($params); - $future = id(new HTTPSFuture($uri)) + $future = id(new HTTPSFuture($uri, $data)) ->setMethod($method); + foreach ($this->headers as $header) { + list($key, $value) = $header; + $future->addHeader($key, $value); + } + $this->signRequest($future); $this->future = $future; diff --git a/src/future/aws/PhutilAWSS3Future.php b/src/future/aws/PhutilAWSS3Future.php --- a/src/future/aws/PhutilAWSS3Future.php +++ b/src/future/aws/PhutilAWSS3Future.php @@ -26,6 +26,29 @@ return $this; } + public function setParametersForPutObject($key, $value) { + $bucket = $this->getBucket(); + + $this->setHTTPMethod('PUT'); + $this->setPath($bucket.'/'.$key); + + $this->addHeader('X-Amz-ACL', 'private'); + $this->addHeader('Content-Type', 'application/octet-stream'); + + $this->setData($value); + + return $this; + } + + public function setParametersForDeleteObject($key) { + $bucket = $this->getBucket(); + + $this->setHTTPMethod('DELETE'); + $this->setPath($bucket.'/'.$key); + + return $this; + } + protected function didReceiveResult($result) { list($status, $body, $headers) = $result; diff --git a/src/future/aws/management/PhutilAWSManagementWorkflow.php b/src/future/aws/management/PhutilAWSManagementWorkflow.php --- a/src/future/aws/management/PhutilAWSManagementWorkflow.php +++ b/src/future/aws/management/PhutilAWSManagementWorkflow.php @@ -43,6 +43,15 @@ $template->setRegion($region); + $endpoint = $argv->getArg('endpoint'); + if (!strlen($endpoint)) { + throw new PhutilArgumentUsageException( + pht( + 'You must specify an AWS endpoint with --endpoint.')); + } + + $template->setEndpoint($endpoint); + return $template; } @@ -63,6 +72,11 @@ 'param' => 'region', 'help' => pht('AWS region.'), ), + array( + 'name' => 'endpoint', + 'param' => 'endpoint', + 'help' => pht('Name of the AWS region to access.'), + ), ); } diff --git a/src/future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php b/src/future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php new file mode 100644 --- /dev/null +++ b/src/future/aws/management/PhutilAWSS3DeleteManagementWorkflow.php @@ -0,0 +1,45 @@ +setName('delete') + ->setExamples( + '**delete** --key __key__') + ->setSynopsis(pht('Delete an object from S3.')) + ->setArguments( + array_merge( + $this->getAWSArguments(), + $this->getAWSS3BucketArguments(), + array( + array( + 'name' => 'key', + 'param' => 'key', + 'help' => pht('Specify a key to delete.'), + ), + ))); + } + + public function execute(PhutilArgumentParser $args) { + $key = $args->getArg('key'); + if (!strlen($key)) { + throw new PhutilArgumentUsageException( + pht( + 'Specify an AWS S3 object key to access with --key.')); + } + + $future = $this->newAWSFuture(new PhutilAWSS3Future()) + ->setParametersForDeleteObject($key); + + $future->resolve(); + + echo tsprintf( + "%s\n", + pht('Deleted "%s".', $key)); + + return 0; + } + +} diff --git a/src/future/aws/management/PhutilAWSS3ManagementWorkflow.php b/src/future/aws/management/PhutilAWSS3ManagementWorkflow.php --- a/src/future/aws/management/PhutilAWSS3ManagementWorkflow.php +++ b/src/future/aws/management/PhutilAWSS3ManagementWorkflow.php @@ -10,12 +10,18 @@ 'param' => 'bucket', 'help' => pht('Name of the S3 bucket to access.'), ), - array( - 'name' => 'endpoint', - 'param' => 'endpoint', - 'help' => pht('Name of the AWS region to access.'), - ), ); } + protected function newAWSFuture($future) { + $future = parent::newAWSFuture($future); + + $argv = $this->getArgv(); + $bucket = $argv->getArg('bucket'); + + $future->setBucket($bucket); + + return $future; + } + } diff --git a/src/future/aws/management/PhutilAWSS3PutManagementWorkflow.php b/src/future/aws/management/PhutilAWSS3PutManagementWorkflow.php new file mode 100644 --- /dev/null +++ b/src/future/aws/management/PhutilAWSS3PutManagementWorkflow.php @@ -0,0 +1,52 @@ +setName('put') + ->setExamples( + '**put** --key __key__') + ->setSynopsis(pht('Upload content to S3.')) + ->setArguments( + array_merge( + $this->getAWSArguments(), + $this->getAWSS3BucketArguments(), + array( + array( + 'name' => 'key', + 'param' => 'key', + 'help' => pht('Specify a key to upload.'), + ), + ))); + } + + public function execute(PhutilArgumentParser $args) { + $key = $args->getArg('key'); + if (!strlen($key)) { + throw new PhutilArgumentUsageException( + pht( + 'Specify an AWS S3 object key to access with --key.')); + } + + $future = $this->newAWSFuture(new PhutilAWSS3Future()); + + echo tsprintf( + "%s\n", + pht('Reading data from stdin...')); + + $data = file_get_contents('php://stdin'); + + $future->setParametersForPutObject($key, $data); + + $result = $future->resolve(); + + echo tsprintf( + "%s\n", + pht('Uploaded "%s".', $key)); + + return 0; + } + +}