Skip to content

Commit bb2309b

Browse files
author
Jamie Hannaford
committed
Merge pull request rackspace#609 from jamiehannaford/upload-dir-path
Adds ability for uploadDir to be nested in pseudo-directories
2 parents 29e1f27 + 360abf3 commit bb2309b

File tree

5 files changed

+108
-16
lines changed

5 files changed

+108
-16
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
},
3434
"require-dev" : {
3535
"phpunit/phpunit": "4.3.*",
36+
"phpspec/prophecy": "~1.4",
3637
"satooshi/php-coveralls": "0.6.*@dev",
3738
"jakub-onderka/php-parallel-lint": "0.*",
3839
"fabpot/php-cs-fixer": "1.0.*@dev",

lib/OpenCloud/ObjectStore/Resource/Container.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,11 +570,12 @@ public function setupObjectTransfer(array $options = array())
570570
/**
571571
* Upload the contents of a local directory to a remote container, effectively syncing them.
572572
*
573-
* @param $path The local path to the directory.
573+
* @param string $path The local path to the directory.
574+
* @param string $targetDir The path (or pseudo-directory) that all files will be nested in.
574575
*/
575-
public function uploadDirectory($path)
576+
public function uploadDirectory($path, $targetDir = null)
576577
{
577-
$sync = DirectorySync::factory($path, $this);
578+
$sync = DirectorySync::factory($path, $this, $targetDir);
578579
$sync->execute();
579580
}
580581

lib/OpenCloud/ObjectStore/Upload/DirectorySync.php

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,34 @@
3131
*/
3232
class DirectorySync
3333
{
34-
/**
35-
* @var string The path to the directory you're syncing.
36-
*/
34+
/** @var string The path to the directory you're syncing. */
3735
private $basePath;
38-
/**
39-
* @var ResourceIterator A collection of remote files in Swift.
40-
*/
36+
37+
/** @var ResourceIterator A collection of remote files in Swift. */
4138
private $remoteFiles;
42-
/**
43-
* @var AbstractContainer The Container object you are syncing.
44-
*/
39+
40+
/** @var AbstractContainer The Container object you are syncing. */
4541
private $container;
4642

43+
/** @var string */
44+
private $targetDir;
45+
4746
/**
4847
* Basic factory method to instantiate a new DirectorySync object with all the appropriate properties.
4948
*
50-
* @param $path The local path
49+
* @param string $path The local path
5150
* @param Container $container The container you're syncing
51+
* @param string $targetDir The path (or pseudo-directory) that the files will be nested in
52+
*
5253
* @return DirectorySync
5354
*/
54-
public static function factory($path, Container $container)
55+
public static function factory($path, Container $container, $targetDir = null)
5556
{
5657
$transfer = new self();
5758
$transfer->setBasePath($path);
5859
$transfer->setContainer($container);
5960
$transfer->setRemoteFiles($container->objectList());
61+
$transfer->setTargetDir($targetDir);
6062

6163
return $transfer;
6264
}
@@ -90,6 +92,14 @@ public function setContainer(Container $container)
9092
$this->container = $container;
9193
}
9294

95+
/**
96+
* @param string $dir The target path that all files will be nested in. By default, the files will not be nested.
97+
*/
98+
public function setTargetDir($dir)
99+
{
100+
$this->targetDir = rtrim($dir, '/');
101+
}
102+
93103
/**
94104
* Execute the sync process. This will collect all the remote files from the API and do a comparison. There are
95105
* four scenarios that need to be dealt with:
@@ -112,7 +122,9 @@ public function execute()
112122

113123
// Handle PUT requests (create/update files)
114124
foreach ($localFiles as $filename) {
115-
$callback = $this->getCallback($filename);
125+
$remoteFilename = $this->targetDir ? $this->targetDir . '/' . $filename : $filename;
126+
127+
$callback = $this->getCallback($remoteFilename);
116128
$filePath = rtrim($this->basePath, '/') . '/' . $filename;
117129

118130
if (!is_readable($filePath)) {
@@ -133,7 +145,7 @@ public function execute()
133145
} else {
134146
// upload new file
135147
$url = clone $this->container->getUrl();
136-
$url->addPath($filename);
148+
$url->addPath($remoteFilename);
137149

138150
$requests[] = $this->container->getClient()->put($url, array(), $entityBody);
139151
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace OpenCloud\Tests\ObjectStore\Upload;
4+
5+
use Guzzle\Http\Url;
6+
use OpenCloud\ObjectStore\Upload\DirectorySync;
7+
use OpenCloud\Tests\OpenCloudTestCase;
8+
use Prophecy\Argument;
9+
use Prophecy\Prophet;
10+
11+
class DirectorySyncTest extends OpenCloudTestCase
12+
{
13+
private $prophet;
14+
15+
public function setUp()
16+
{
17+
$this->prophet = new Prophet();
18+
}
19+
20+
public function test_it_uploads_to_a_container()
21+
{
22+
$baseUrl = 'foo.com/bar';
23+
24+
$containerMock = $this->prophet->prophesize('OpenCloud\ObjectStore\Resource\Container');
25+
$iteratorMock = $this->prophet->prophesize('OpenCloud\Common\Collection\PaginatedIterator');
26+
27+
$iteratorMock->rewind()->shouldBeCalled();
28+
$iteratorMock->populateAll()->shouldBeCalled();
29+
$iteratorMock->valid()->willReturn(false);
30+
$iteratorMock->search(Argument::type('callable'))->willReturn(false);
31+
32+
$containerMock->getUrl()->willReturn(Url::factory($baseUrl));
33+
34+
$guzzleMock = $this->prophet->prophesize('Guzzle\Http\Client');
35+
36+
$guzzleMock->put($baseUrl . '/test1', [], Argument::type('Guzzle\Http\EntityBody'))->shouldBeCalled();
37+
$guzzleMock->send(Argument::that(function ($array) { return count($array) === 1; }))->shouldBeCalled();
38+
39+
$containerMock->getClient()->willReturn($guzzleMock->reveal());
40+
41+
$sync = new DirectorySync();
42+
$sync->setBasePath(__DIR__ . '/fixtures');
43+
$sync->setContainer($containerMock->reveal());
44+
$sync->setRemoteFiles($iteratorMock->reveal());
45+
46+
$sync->execute();
47+
}
48+
49+
public function test_it_uploads_to_a_nested_sub_dir_in_a_container()
50+
{
51+
$baseUrl = 'foo.com/bar';
52+
53+
$containerMock = $this->prophet->prophesize('OpenCloud\ObjectStore\Resource\Container');
54+
$iteratorMock = $this->prophet->prophesize('OpenCloud\Common\Collection\PaginatedIterator');
55+
56+
$iteratorMock->rewind()->shouldBeCalled();
57+
$iteratorMock->populateAll()->shouldBeCalled();
58+
$iteratorMock->valid()->willReturn(false);
59+
$iteratorMock->search(Argument::type('callable'))->willReturn(false);
60+
61+
$containerMock->getUrl()->willReturn(Url::factory($baseUrl));
62+
63+
$guzzleMock = $this->prophet->prophesize('Guzzle\Http\Client');
64+
65+
$guzzleMock->put($baseUrl . '/sub-dir/test1', [], Argument::type('Guzzle\Http\EntityBody'))->shouldBeCalled();
66+
$guzzleMock->send(Argument::that(function ($array) { return count($array) === 1; }))->shouldBeCalled();
67+
68+
$containerMock->getClient()->willReturn($guzzleMock->reveal());
69+
70+
$sync = new DirectorySync();
71+
$sync->setBasePath(__DIR__ . '/fixtures');
72+
$sync->setContainer($containerMock->reveal());
73+
$sync->setRemoteFiles($iteratorMock->reveal());
74+
$sync->setTargetDir('sub-dir');
75+
76+
$sync->execute();
77+
}
78+
}

tests/OpenCloud/Tests/ObjectStore/Upload/fixtures/test1

Whitespace-only changes.

0 commit comments

Comments
 (0)