Make the code structure more modular

This commit is contained in:
Sander van der Burg 2017-09-22 22:24:57 +02:00
parent 4c20068b41
commit adf0a9c460
11 changed files with 519 additions and 266 deletions

View file

@ -0,0 +1,67 @@
<?php
namespace Composer2Nix;
use Exception;
class ComposerConfig
{
public $packageName;
public $packages;
public $devPackages;
public $values;
public function __construct($configFile, $lockFile, $packageName, $noDev)
{
/* Open the composer.json file and decode it */
$composerJSONStr = file_get_contents($configFile);
if($composerJSONStr === false)
throw new Exception("Cannot open contents of: ".$configFile);
$this->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();
}
}
}
?>

View file

@ -0,0 +1,73 @@
<?php
namespace Composer2Nix\Dependencies;
use Composer2Nix\NixASTNode;
use Exception;
abstract class Dependency extends NixASTNode
{
public $package;
protected $sourceObj;
protected function __construct(array $package, array $sourceObj)
{
$this->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;
}
}
?>

View file

@ -0,0 +1,38 @@
<?php
namespace Composer2Nix\Dependencies;
use PNDP\NixGenerator;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFunInvocation;
class GitDependency extends Dependency
{
public function __construct(array $package, array $sourceObj)
{
parent::__construct($package, $sourceObj);
}
public function toNixAST()
{
$dependency = parent::toNixAST();
$outputStr = shell_exec('nix-prefetch-git "'.$this->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;
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
namespace Composer2Nix\Dependencies;
use PNDP\NixGenerator;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFunInvocation;
class HgDependency extends Dependency
{
public function __construct(array $package, array $sourceObj)
{
parent::__construct($package, $sourceObj);
}
public function toNixAST()
{
$dependency = parent::toNixAST();
$hash = shell_exec('nix-prefetch-hg "'.$this->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;
}
}
?>

View file

@ -0,0 +1,20 @@
<?php
namespace Composer2Nix\Dependencies;
use PNDP\NixGenerator;
use PNDP\AST\NixFile;
class PathDependency extends Dependency
{
public function __construct(array $package, array $sourceObj)
{
parent::__construct($package, $sourceObj);
}
public function toNixAST()
{
$dependency = parent::toNixAST();
$dependency["src"] = new NixFile($sourceObj['url']);
return $dependency;
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
namespace Composer2Nix\Dependencies;
use PNDP\NixGenerator;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFunInvocation;
class SVNDependency extends Dependency
{
public function __construct(array $package, array $sourceObj)
{
parent::__construct($package, $sourceObj);
}
public function toNixAST()
{
$dependency = parent::toNixAST();
$hash = shell_exec('nix-prefetch-svn "'.$sourceObj['url'].'" '.$sourceObj["reference"]);
if($hash === false)
throw new Exception("Error while invoking nix-prefetch-svn");
else
{
$dependency["src"] = new NixFunInvocation(new NixExpression("fetchsvn"), array(
"name" => strtr($package["name"], "/", "-").'-'.$sourceObj["reference"],
"url" => $sourceObj["url"],
"rev" => $sourceObj["reference"],
"sha256" => $hash
));
}
return $dependency;
}
}
?>

View file

@ -0,0 +1,55 @@
<?php
namespace Composer2Nix\Dependencies;
use PNDP\NixGenerator;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFile;
use PNDP\AST\NixFunInvocation;
use PNDP\AST\NixURL;
class ZipDependency extends Dependency
{
public function __construct(array $package, array $sourceObj)
{
parent::__construct($package, $sourceObj);
}
public function toNixAST()
{
$dependency = parent::toNixAST();
if($this->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);
}
}
?>

View file

@ -0,0 +1,57 @@
<?php
namespace Composer2Nix\Expressions;
use PNDP\NixGenerator;
use PNDP\AST\NixAttrReference;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFunction;
use PNDP\AST\NixFunInvocation;
use PNDP\AST\NixFile;
use PNDP\AST\NixImport;
use PNDP\AST\NixInherit;
use PNDP\AST\NixLet;
use PNDP\AST\NixObject;
use Composer2Nix\NixASTNode;
class CompositionExpression extends NixASTNode
{
public function __construct($outputFile, $composerEnvFile)
{
$this->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("<nixpkgs>")), 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")
))));
}
}
?>

View file

@ -0,0 +1,102 @@
<?php
namespace Composer2Nix\Expressions;
use Composer2Nix\ComposerConfig;
use Composer2Nix\Dependencies\Dependency;
use PNDP\NixGenerator;
use PNDP\AST\NixAttrSet;
use PNDP\AST\NixExpression;
use PNDP\AST\NixFile;
use PNDP\AST\NixFunction;
use PNDP\AST\NixFunInvocation;
use PNDP\AST\NixInherit;
use PNDP\AST\NixLet;
use PNDP\AST\NixNoDefault;
use PNDP\AST\NixObject;
use PNDP\AST\NixURL;
use Composer2Nix\NixASTNode;
class PackagesExpression extends NixASTNode
{
public $executable;
public $symlinkDependencies;
public $config;
public $preferredInstall;
public function __construct(ComposerConfig $config, $executable, $symlinkDependencies, $preferredInstall)
{
$this->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()));
}
}
?>

View file

@ -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("<nixpkgs>")), 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);
}
}
?>

View file

@ -0,0 +1,17 @@
<?php
// TODO: move to PNDP
namespace Composer2Nix;
use PNDP\NixGenerator;
use PNDP\AST\NixObject;
abstract class NixASTNode extends NixObject
{
abstract public function toNixAST();
public function toNixExpr($indentLevel, $format)
{
return NixGenerator::phpToIndentedNix($this->toNixAST(), $indentLevel, $format);
}
}
?>