From adf0a9c46003a8fc3f7cb9f75103bcbdf92bc345 Mon Sep 17 00:00:00 2001 From: Sander van der Burg Date: Fri, 22 Sep 2017 22:24:57 +0200 Subject: [PATCH] Make the code structure more modular --- src/Composer2Nix/ComposerConfig.php | 67 ++++ src/Composer2Nix/Dependencies/Dependency.php | 73 +++++ .../Dependencies/GitDependency.php | 38 +++ .../Dependencies/HgDependency.php | 35 +++ .../Dependencies/PathDependency.php | 20 ++ .../Dependencies/SVNDependency.php | 35 +++ .../Dependencies/ZipDependency.php | 55 ++++ .../Expressions/CompositionExpression.php | 57 ++++ .../Expressions/PackagesExpression.php | 102 +++++++ src/Composer2Nix/Generator.php | 286 ++---------------- src/Composer2Nix/NixASTNode.php | 17 ++ 11 files changed, 519 insertions(+), 266 deletions(-) create mode 100644 src/Composer2Nix/ComposerConfig.php create mode 100644 src/Composer2Nix/Dependencies/Dependency.php create mode 100644 src/Composer2Nix/Dependencies/GitDependency.php create mode 100644 src/Composer2Nix/Dependencies/HgDependency.php create mode 100644 src/Composer2Nix/Dependencies/PathDependency.php create mode 100644 src/Composer2Nix/Dependencies/SVNDependency.php create mode 100644 src/Composer2Nix/Dependencies/ZipDependency.php create mode 100644 src/Composer2Nix/Expressions/CompositionExpression.php create mode 100644 src/Composer2Nix/Expressions/PackagesExpression.php create mode 100644 src/Composer2Nix/NixASTNode.php diff --git a/src/Composer2Nix/ComposerConfig.php b/src/Composer2Nix/ComposerConfig.php new file mode 100644 index 0000000..a134835 --- /dev/null +++ b/src/Composer2Nix/ComposerConfig.php @@ -0,0 +1,67 @@ +values = json_decode($composerJSONStr, true); + + /* If no package name has been provided, attempt to use the name in the composer config file */ + if($packageName === null) + { + if(array_key_exists("name", $this->values)) + $packageName = $this->values["name"]; + else + { + throw new Exception("Cannot determine a package name! Either add a name\n". + "property to the composer.json file or provide a --name parameter!"); + } + } + + $this->packageName = strtr($packageName, "/", "-"); // replace / by - since / is not allowed in Nix package names + + /* Open the lock file and decode it */ + + if(file_exists($lockFile)) + { + $composerLockStr = file_get_contents($lockFile); + + if($composerLockStr === false) + throw new Exception("Cannot open contents of: ".$lockFile); + + $lockConfig = json_decode($composerLockStr, true); + + if(array_key_exists("packages", $lockConfig)) + $this->packages = $lockConfig["packages"]; + else + $this->packages = array(); + + if(!$noDev && array_key_exists("packages-dev", $lockConfig)) + $this->devPackages = $lockConfig["packages-dev"]; + else + $this->devPackages = array(); + } + else + { + $this->packages = array(); + $this->devPackages = array(); + } + } +} +?> diff --git a/src/Composer2Nix/Dependencies/Dependency.php b/src/Composer2Nix/Dependencies/Dependency.php new file mode 100644 index 0000000..a8b4f51 --- /dev/null +++ b/src/Composer2Nix/Dependencies/Dependency.php @@ -0,0 +1,73 @@ +package = $package; + $this->sourceObj = $sourceObj; + } + + private static function selectSourceObject($preferredInstall, array $package) + { + if($preferredInstall === "source") + { + if(array_key_exists("source", $package)) + return $package["source"]; + else if(array_key_exists("dist", $package)) + return $package["dist"]; + else + throw new Exception("Encountered a dangling package reference"); + } + else + { + if(array_key_exists("dist", $package)) + return $package["dist"]; + else if(array_key_exists("source", $package)) + return $package["source"]; + else + throw new Exception("Encountered a dangling package reference"); + } + } + + public static function constructDependency(array $package, $preferredInstall) + { + $sourceObj = Dependency::selectSourceObject($preferredInstall, $package); + + switch($sourceObj["type"]) + { + case "path": + return new PathDependency($package, $sourceObj); + case "zip": + return new ZipDependency($package, $sourceObj); + case "git": + return new GitDependency($package, $sourceObj); + case "hg": + return new HgDependency($package, $sourceObj); + case "svn": + return new SVNDependency($package, $sourceObj); + default: + throw new Exception("Cannot convert dependency of type: ".$sourceObj["type"]); + } + } + + public function toNixAST() + { + $dependency = array(); + + if(array_key_exists("target-dir", $this->package)) + $dependency["targetDir"] = $this->package["target-dir"]; + else + $dependency["targetDir"] = ""; + + return $dependency; + } +} +?> diff --git a/src/Composer2Nix/Dependencies/GitDependency.php b/src/Composer2Nix/Dependencies/GitDependency.php new file mode 100644 index 0000000..1972d3d --- /dev/null +++ b/src/Composer2Nix/Dependencies/GitDependency.php @@ -0,0 +1,38 @@ +sourceObj['url'].'" '.$this->sourceObj["reference"]); + + if($outputStr === false) + throw new Exception("Error while invoking nix-prefetch-git"); + else + { + $output = json_decode($outputStr, true); + $hash = $output["sha256"]; + + $dependency["src"] = new NixFunInvocation(new NixExpression("fetchgit"), array( + "name" => strtr($this->package["name"], "/", "-").'-'.$this->sourceObj["reference"], + "url" => $this->sourceObj["url"], + "rev" => $this->sourceObj["reference"], + "sha256" => $hash + )); + } + + return $dependency; + } +} +?> diff --git a/src/Composer2Nix/Dependencies/HgDependency.php b/src/Composer2Nix/Dependencies/HgDependency.php new file mode 100644 index 0000000..d4e4a1c --- /dev/null +++ b/src/Composer2Nix/Dependencies/HgDependency.php @@ -0,0 +1,35 @@ +sourceObj['url'].'" '.$this->sourceObj["reference"]); + + if($hash === false) + throw new Exception("Error while invoking nix-prefetch-hg"); + else + { + $dependency["src"] = new NixFunInvocation(new NixExpression("fetchhg"), array( + "name" => strtr($package["name"], "/", "-").'-'.$this->sourceObj["reference"], + "url" => $this->sourceObj["url"], + "rev" => $this->sourceObj["reference"], + "sha256" => $hash + )); + } + + return $dependency; + } +} +?> diff --git a/src/Composer2Nix/Dependencies/PathDependency.php b/src/Composer2Nix/Dependencies/PathDependency.php new file mode 100644 index 0000000..e945438 --- /dev/null +++ b/src/Composer2Nix/Dependencies/PathDependency.php @@ -0,0 +1,20 @@ + diff --git a/src/Composer2Nix/Dependencies/SVNDependency.php b/src/Composer2Nix/Dependencies/SVNDependency.php new file mode 100644 index 0000000..7f7628e --- /dev/null +++ b/src/Composer2Nix/Dependencies/SVNDependency.php @@ -0,0 +1,35 @@ + strtr($package["name"], "/", "-").'-'.$sourceObj["reference"], + "url" => $sourceObj["url"], + "rev" => $sourceObj["reference"], + "sha256" => $hash + )); + } + + return $dependency; + } +} +?> diff --git a/src/Composer2Nix/Dependencies/ZipDependency.php b/src/Composer2Nix/Dependencies/ZipDependency.php new file mode 100644 index 0000000..1a6405b --- /dev/null +++ b/src/Composer2Nix/Dependencies/ZipDependency.php @@ -0,0 +1,55 @@ +sourceObj["reference"] == "") + $reference = ""; + else + $reference = "-".$this->sourceObj["reference"]; + + if(substr($this->sourceObj["url"], 0, 7) === "http://" || substr($this->sourceObj["url"], 0, 8) === "https://") + { + $hash = shell_exec('nix-prefetch-url "'.$this->sourceObj['url'].'"'); + + if($hash === null) + throw new Exception("Error while invoking nix-prefetch-url"); + else + { + $src = new NixFunInvocation(new NixFile("fetchurl"), array( + "url" => new NixURL($this->sourceObj["url"]), + "sha256" => substr($hash, 0, -1) + )); + } + } + else + $src = new NixFile($this->sourceObj['url']); + + $dependency["src"] = new NixFunInvocation(new NixExpression("composerEnv.buildZipPackage"), array( + "name" => strtr($this->package["name"], "/", "-").$reference, + "src" => $src + )); + + return $dependency; + } + + public function toNixExpr($indentLevel, $format) + { + return NixGenerator::phpToIndentedNix($this->toNixAST(), $indentLevel, $format); + } +} +?> diff --git a/src/Composer2Nix/Expressions/CompositionExpression.php b/src/Composer2Nix/Expressions/CompositionExpression.php new file mode 100644 index 0000000..f7e1e71 --- /dev/null +++ b/src/Composer2Nix/Expressions/CompositionExpression.php @@ -0,0 +1,57 @@ +outputFile = $outputFile; + $this->composerEnvFile = $composerEnvFile; + } + + private function prefixRelativePath($target) + { + if(substr($target, 0, 1) == "/" || substr($target, 0, 2) == "./" || substr($target, 0, 3) == "../") + return $target; + else + return "./".$target; + } + + public function toNixAST() + { + return new NixFunction(array( + "pkgs" => new NixFunInvocation(new NixImport(new NixExpression("")), array( + "system" => new NixInherit() + )), + "system" => new NixAttrReference(new NixExpression("builtins"), new NixExpression("currentSystem")), + "noDev" => false + ), new NixLet(array( + "composerEnv" => new NixFunInvocation(new NixImport(new NixFile($this->prefixRelativePath($this->composerEnvFile))), array( + "stdenv" => new NixInherit("pkgs"), + "writeTextFile" => new NixInherit("pkgs"), + "fetchurl" => new NixInherit("pkgs"), + "php" => new NixInherit("pkgs"), + "unzip" => new NixInherit("pkgs") + )) + ), new NixFunInvocation(new NixImport(new NixFile($this->prefixRelativePath($this->outputFile))), array( + "composerEnv" => new NixInherit(), + "noDev" => new NixInherit(), + "fetchurl" => new NixInherit("pkgs"), + "fetchgit" => new NixInherit("pkgs"), + "fetchhg" => new NixInherit("pkgs"), + "fetchsvn" => new NixInherit("pkgs") + )))); + } +} +?> diff --git a/src/Composer2Nix/Expressions/PackagesExpression.php b/src/Composer2Nix/Expressions/PackagesExpression.php new file mode 100644 index 0000000..6c19185 --- /dev/null +++ b/src/Composer2Nix/Expressions/PackagesExpression.php @@ -0,0 +1,102 @@ +executable = $executable; + $this->symlinkDependencies = $symlinkDependencies; + $this->config = $config; + $this->preferredInstall = $preferredInstall; + } + + private function generateDependenciesExpr(array $packages) + { + $dependencies = array(); + + foreach($packages as $package) + { + $dependency = Dependency::constructDependency($package, $this->preferredInstall); + $dependencies[$package["name"]] = $dependency; + } + + return new NixAttrSet($dependencies); + } + + private function generatePackageMetaDataExpr() + { + $meta = array(); + + if(array_key_exists("homepage", $this->config->values)) + $meta["homepage"] = new NixURL($this->config->values["homepage"]); + + if(array_key_exists("license", $this->config->values)) + { + if(is_string($this->config->values["license"])) // If the license is a string, just take it + $meta["license"] = $this->config->values["license"]; + else if(is_array($this->config->values["license"])) // If the license is an array, compose a comma , separated string from it + { + if(count($this->config->values["license"]) > 0) + $meta["license"] = $this->config->values["license"][0]; + + for($i = 1; $i < count($this->config->values["license"]); $i++) + $meta["license"] .= ", ".$this->config->values["license"][$i]; + } + } + + return new NixAttrSet($meta); + } + + private function generatePackageBuild() + { + return new NixFunInvocation(new NixExpression("composerEnv.buildPackage"), array( + "name" => $this->config->packageName, + "src" => new NixFile("./."), + "executable" => $this->executable, + "packages" => new NixInherit(), + "devPackages" => new NixInherit(), + "noDev" => new NixInherit(), + "symlinkDependencies" => $this->symlinkDependencies, + "meta" => $this->generatePackageMetaDataExpr() + )); + } + + public function toNixAST() + { + return new NixFunction(array( + "composerEnv" => new NixNoDefault(), + "fetchurl" => new NixNoDefault(), + "fetchgit" => null, + "fetchhg" => null, + "fetchsvn" => null, + "noDev" => false + ), new NixLet(array( + "packages" => $this->generateDependenciesExpr($this->config->packages), + "devPackages" => $this->generateDependenciesExpr($this->config->devPackages) + ), $this->generatePackageBuild())); + } +} +?> diff --git a/src/Composer2Nix/Generator.php b/src/Composer2Nix/Generator.php index 9975c71..d2c3ef0 100644 --- a/src/Composer2Nix/Generator.php +++ b/src/Composer2Nix/Generator.php @@ -2,290 +2,44 @@ namespace Composer2Nix; use Exception; use PNDP\NixGenerator; -use PNDP\AST\NixAttrReference; -use PNDP\AST\NixAttrSet; -use PNDP\AST\NixExpression; -use PNDP\AST\NixFile; -use PNDP\AST\NixFunction; -use PNDP\AST\NixFunInvocation; -use PNDP\AST\NixImport; -use PNDP\AST\NixInherit; -use PNDP\AST\NixLet; -use PNDP\AST\NixNoDefault; -use PNDP\AST\NixURL; +use Composer2Nix\Expressions\CompositionExpression; +use Composer2Nix\Expressions\PackagesExpression; class Generator { - private static function selectSourceObject($preferredInstall, $package) + private static function writeExprToFile($filename, $expr) { - if($preferredInstall === "source") - { - if(array_key_exists("source", $package)) - return $package["source"]; - else if(array_key_exists("dist", $package)) - return $package["dist"]; - else - throw new Exception("Encountered a dangling package reference"); - } - else - { - if(array_key_exists("dist", $package)) - return $package["dist"]; - else if(array_key_exists("source", $package)) - return $package["source"]; - else - throw new Exception("Encountered a dangling package reference"); - } - } - - private static function prefixRelativePath($target) - { - if(substr($target, 0, 1) == "/" || substr($target, 0, 2) == "./" || substr($target, 0, 3) == "../") - return $target; - else - return "./".$target; - } - - private static function generatePackagesAttrSet(array $packages, $preferredInstall) - { - $dependencies = array(); - - foreach($packages as $package) - { - $dependency = array(); - - if(array_key_exists("target-dir", $package)) - $dependency["targetDir"] = $package["target-dir"]; - else - $dependency["targetDir"] = ""; - - $sourceObj = Generator::selectSourceObject($preferredInstall, $package); - - switch($sourceObj["type"]) - { - case "path": - $dependency["src"] = new NixFile($sourceObj['url']); - break; - - case "zip": - if($sourceObj["reference"] == "") - $reference = ""; - else - $reference = "-".$sourceObj["reference"]; - - if(substr($sourceObj["url"], 0, 7) === "http://" || substr($sourceObj["url"], 0, 8) === "https://") - { - $hash = shell_exec('nix-prefetch-url "'.$sourceObj['url'].'"'); - $src = new NixFunInvocation(new NixFile("fetchurl"), array( - "url" => new NixURL($sourceObj["url"]), - "sha256" => substr($hash, 0, -1) - )); - } - else - $src = new NixFile($sourceObj['url']); - - $dependency["src"] = new NixFunInvocation(new NixExpression("composerEnv.buildZipPackage"), array( - "name" => strtr($package["name"], "/", "-").$reference, - "src" => $src - )); - break; - - case "git": - $outputStr = shell_exec('nix-prefetch-git "'.$sourceObj['url'].'" '.$sourceObj["reference"]); - - $output = json_decode($outputStr, true); - $hash = $output["sha256"]; - - $dependency["src"] = new NixFunInvocation(new NixExpression("fetchgit"), array( - "name" => strtr($package["name"], "/", "-").'-'.$sourceObj["reference"], - "url" => $sourceObj["url"], - "rev" => $sourceObj["reference"], - "sha256" => $hash - )); - break; - - case "hg": - $hash = shell_exec('nix-prefetch-hg "'.$sourceObj['url'].'" '.$sourceObj["reference"]); - $dependency["src"] = new NixFunInvocation(new NixExpression("fetchhg"), array( - "name" => strtr($package["name"], "/", "-").'-'.$sourceObj["reference"], - "url" => $sourceObj["url"], - "rev" => $sourceObj["reference"], - "sha256" => $hash - )); - break; - - case "svn": - $hash = shell_exec('nix-prefetch-svn "'.$sourceObj['url'].'" '.$sourceObj["reference"]); - $dependency["src"] = new NixFunInvocation(new NixExpression("fetchsvn"), array( - "name" => strtr($package["name"], "/", "-").'-'.$sourceObj["reference"], - "url" => $sourceObj["url"], - "rev" => $sourceObj["reference"], - "sha256" => $hash - )); - break; - - default: - throw new Exception("Cannot convert dependency of type: ".$sourceObj["type"]); - } - - $dependencies[$package["name"]] = $dependency; - } - - return new NixAttrSet($dependencies); - } - - private static function generatePackagesExpression(array $config, $outputFile, $name, $preferredInstall, array $packages, array $devPackages, $executable, $symlinkDependencies) - { - $handle = fopen($outputFile, "w"); + $handle = fopen($filename, "w"); if($handle === false) - throw new Exception("Cannot write to: ".$outputFile); + throw new Exception("Cannot write to: ".$filename); - $packagesAttrSet = Generator::generatePackagesAttrSet($packages, $preferredInstall); - $devpackagesAttrSet = Generator::generatePackagesAttrSet($devPackages, $preferredInstall); - - /* Compose meta properties */ - $meta = array(); - - if(array_key_exists("homepage", $config)) - $meta["homepage"] = $config["homepage"]; - - if(array_key_exists("license", $config)) - { - if(is_string($config["license"])) - $meta["license"] = $config["license"]; - else if(is_array($config["license"])) - { - if(count($config["license"]) > 0) - $meta["license"] = $config["license"][0]; - - for($i = 1; $i < count($config["license"]); $i++) - $meta["license"] .= ", ".$config["license"][$i]; - } - } - - /* Compose package function invocation */ - $expr = new NixFunction(array( - "composerEnv" => new NixNoDefault(), - "fetchurl" => new NixNoDefault(), - "fetchgit" => null, - "fetchhg" => null, - "fetchsvn" => null, - "noDev" => false - ), new NixLet(array( - "packages" => $packagesAttrSet, - "devPackages" => $devpackagesAttrSet - ), new NixFunInvocation(new NixExpression("composerEnv.buildPackage"), array( - "name" => $name, - "src" => new NixFile("./."), - "executable" => $executable, - "packages" => new NixInherit(), - "devPackages" => new NixInherit(), - "noDev" => new NixInherit(), - "symlinkDependencies" => $symlinkDependencies, - "meta" => new NixAttrSet($meta) - )))); - - $exprStr = NixGenerator::phpToNix($expr, true); - fwrite($handle, $exprStr); + fwrite($handle, NixGenerator::phpToNix($expr, true)); fclose($handle); } + private static function generatePackagesExpression($outputFile, ComposerConfig $config, $executable, $symlinkDependencies, $preferredInstall) + { + Generator::writeExprToFile($outputFile, new PackagesExpression($config, $executable, $symlinkDependencies, $preferredInstall)); + } + private static function generateCompositionExpression($compositionFile, $outputFile, $composerEnvFile) { - $handle = fopen($compositionFile, "w"); + Generator::writeExprToFile($compositionFile, new CompositionExpression($outputFile, $composerEnvFile)); + } - if($handle === false) - throw new Exception("Cannot write to: ".$compositionFile); - - $expr = new NixFunction(array( - "pkgs" => new NixFunInvocation(new NixImport(new NixExpression("")), array( - "system" => new NixInherit() - )), - "system" => new NixAttrReference(new NixExpression("builtins"), new NixExpression("currentSystem")), - "noDev" => false - ), new NixLet(array( - "composerEnv" => new NixFunInvocation(new NixImport(new NixFile(Generator::prefixRelativePath($composerEnvFile))), array( - "stdenv" => new NixInherit("pkgs"), - "writeTextFile" => new NixInherit("pkgs"), - "fetchurl" => new NixInherit("pkgs"), - "php" => new NixInherit("pkgs"), - "unzip" => new NixInherit("pkgs") - )) - ), new NixFunInvocation(new NixImport(new NixFile(Generator::prefixRelativePath($outputFile))), array( - "composerEnv" => new NixInherit(), - "noDev" => new NixInherit(), - "fetchurl" => new NixInherit("pkgs"), - "fetchgit" => new NixInherit("pkgs"), - "fetchhg" => new NixInherit("pkgs"), - "fetchsvn" => new NixInherit("pkgs") - )))); - - $exprStr = NixGenerator::phpToNix($expr, true); - fwrite($handle, $exprStr); - fclose($handle); + private static function copyComposerEnv($composerEnvFile, $noCopyComposerEnv) + { + if(!$noCopyComposerEnv && !copy(dirname(__FILE__)."/composer-env.nix", $composerEnvFile)) + throw new Exception("Cannot copy composer-env.nix to".$composerEnvFile); } public static function generateNixExpressions($name, $executable, $preferredInstall, $noDev, $configFile, $lockFile, $outputFile, $compositionFile, $composerEnvFile, $noCopyComposerEnv, $symlinkDependencies) { - /* Open the composer.json file and decode it */ - $composerJSONStr = file_get_contents($configFile); - - if($composerJSONStr === false) - throw new Exception("Cannot open contents of: ".$configFile); - - $config = json_decode($composerJSONStr, true); - - /* If no package name has been provided, attempt to use the name in the composer config file */ - if($name === null) - { - if(array_key_exists("name", $config)) - $name = $config["name"]; - else - { - throw new Exception("Cannot determine a package name! Either add a name\n". - "property to the composer.json file or provide a --name parameter!"); - } - } - - $name = strtr($name, "/", "-"); // replace / by - since / is not allowed in Nix package names - - /* Open the lock file and decode it */ - - if(file_exists($lockFile)) - { - $composerLockStr = file_get_contents($lockFile); - - if($composerLockStr === false) - throw new Exception("Cannot open contents of: ".$lockFile); - - $lockConfig = json_decode($composerLockStr, true); - - if(array_key_exists("packages", $lockConfig)) - $packages = $lockConfig["packages"]; - else - $packages = array(); - - if(!$noDev && array_key_exists("packages-dev", $lockConfig)) - $devPackages = $lockConfig["packages-dev"]; - else - $devPackages = array(); - } - else - { - $packages = array(); - $devPackages = array(); - } - - /* Generate packages expression */ - Generator::generatePackagesExpression($config, $outputFile, $name, $preferredInstall, $packages, $devPackages, $executable, $symlinkDependencies); - - /* Generate composition expression */ + $config = new ComposerConfig($configFile, $lockFile, $name, $noDev); + Generator::generatePackagesExpression($outputFile, $config, $executable, $symlinkDependencies, $preferredInstall); Generator::generateCompositionExpression($compositionFile, $outputFile, $composerEnvFile); - - /* Copy composer-env.nix */ - if(!$noCopyComposerEnv && !copy(dirname(__FILE__)."/composer-env.nix", $composerEnvFile)) - throw new Exception("Cannot copy composer-env.nix!"); + Generator::copyComposerEnv($composerEnvFile, $noCopyComposerEnv); } } ?> diff --git a/src/Composer2Nix/NixASTNode.php b/src/Composer2Nix/NixASTNode.php new file mode 100644 index 0000000..241f695 --- /dev/null +++ b/src/Composer2Nix/NixASTNode.php @@ -0,0 +1,17 @@ +toNixAST(), $indentLevel, $format); + } +} +?>