Browse Source

Merge pull request #2188 from Danack/GetRootComposerJson

Find root composer.json in zip artifact more reliably.
Jordi Boggiano 11 years ago
parent
commit
eb3384445b

+ 43 - 1
src/Composer/Repository/ArtifactRepository.php

@@ -74,6 +74,48 @@ class ArtifactRepository extends ArrayRepository
         }
     }
 
+    /**
+     * Find a file by name, returning the one that has the shortest path. 
+     * 
+     * @param \ZipArchive $zip
+     * @param $filename
+     * @return bool|int
+     */
+    private function locateFile(\ZipArchive $zip, $filename) {
+        $indexOfShortestMatch = false;
+        $lengthOfShortestMatch = -1;
+
+        for ($i = 0; $i < $zip->numFiles; $i++ ){
+            $stat = $zip->statIndex($i);
+            if (strcmp(basename($stat['name']), $filename) === 0){
+                $directoryName = dirname($stat['name']);
+                if ($directoryName == '.') {
+                    //if composer.json is in root directory 
+                    //it has to be the one to use.
+                    return $i;
+                }
+
+                if(strpos($directoryName, '\\') !== false ||
+                   strpos($directoryName, '/') !== false) {
+                    //composer.json files below first directory are rejected
+                    continue;
+                }
+                
+                $length = strlen($stat['name']);
+                if ($indexOfShortestMatch == false || $length < $lengthOfShortestMatch) {
+                    //Check it's not a directory.
+                    $contents = $zip->getFromIndex($i);
+                    if ($contents !== false) {
+                        $indexOfShortestMatch = $i;
+                        $lengthOfShortestMatch = $length;
+                    }
+                }
+            }
+        }
+
+        return $indexOfShortestMatch;
+    }
+    
     private function getComposerInformation(\SplFileInfo $file)
     {
         $zip = new \ZipArchive();
@@ -83,7 +125,7 @@ class ArtifactRepository extends ArrayRepository
             return false;
         }
 
-        $foundFileIndex = $zip->locateName('composer.json', \ZipArchive::FL_NODIR);
+        $foundFileIndex = $this->locateFile($zip, 'composer.json');
         if (false === $foundFileIndex) {
             return false;
         }

+ 43 - 0
tests/Composer/Test/Repository/ArtifactRepositoryTest.php

@@ -26,6 +26,10 @@ class ArtifactRepositoryTest extends TestCase
             'composer/composer-1.0.0-alpha6',
             'vendor1/package2-4.3.2',
             'vendor3/package1-5.4.3',
+            'test/jsonInRoot-1.0.0',
+            'test/jsonInFirstLevel-1.0.0',
+            //The files not-an-artifact.zip and jsonSecondLevel are not valid 
+            //artifacts and do not get detected.
         );
 
         $coordinates = array('type' => 'artifact', 'url' => __DIR__ . '/Fixtures/artifacts');
@@ -41,3 +45,42 @@ class ArtifactRepositoryTest extends TestCase
         $this->assertSame($expectedPackages, $foundPackages);
     }
 }
+
+//Files jsonInFirstLevel.zip, jsonInRoot.zip and jsonInSecondLevel.zip were generated with:
+//
+//$archivesToCreate = array(
+//    'jsonInRoot' => array(
+//        "extra.txt"     => "Testing testing testing",
+//        "composer.json" => '{  "name": "test/jsonInRoot", "version": "1.0.0" }',
+//        "subdir/extra.txt"     => "Testing testing testing",
+//        "subdir/extra2.txt"     => "Testing testing testing",
+//    ),
+//
+//    'jsonInFirstLevel' => array(
+//        "extra.txt"     => "Testing testing testing",
+//        "subdir/composer.json" => '{  "name": "test/jsonInFirstLevel", "version": "1.0.0" }',
+//        "subdir/extra.txt"     => "Testing testing testing",
+//        "subdir/extra2.txt"     => "Testing testing testing",
+//    ),
+//
+//    'jsonInSecondLevel' => array(
+//        "extra.txt"     => "Testing testing testing",
+//        "subdir/extra1.txt"     => "Testing testing testing",
+//        "subdir/foo/composer.json" => '{  "name": "test/jsonInSecondLevel", "version": "1.0.0" }',
+//        "subdir/foo/extra1.txt"     => "Testing testing testing",
+//        "subdir/extra2.txt"     => "Testing testing testing",
+//        "subdir/extra3.txt"     => "Testing testing testing",
+//    ),
+//);
+//
+//foreach($archivesToCreate as $archiveName => $fileDetails) {
+//    $zipFile = new ZipArchive();
+//    $zipFile->open("$archiveName.zip", ZIPARCHIVE::CREATE);
+//
+//    foreach ($fileDetails as $filename => $fileContents) {
+//        $zipFile->addFromString($filename, $fileContents);
+//    }
+//
+//    $zipFile->close();
+//}
+

BIN
tests/Composer/Test/Repository/Fixtures/artifacts/jsonInFirstLevel.zip


BIN
tests/Composer/Test/Repository/Fixtures/artifacts/jsonInRoot.zip


BIN
tests/Composer/Test/Repository/Fixtures/artifacts/jsonInSecondLevel.zip