Skip to content

Commit

Permalink
Refactored npm step to command:npm
Browse files Browse the repository at this point in the history
Added text:replace step
Fixed cwd on steps running
  • Loading branch information
fantoine committed Jul 13, 2016
1 parent 509e410 commit bfdfbff
Show file tree
Hide file tree
Showing 15 changed files with 434 additions and 90 deletions.
5 changes: 2 additions & 3 deletions src/hxextern/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ class Main
// Prepare injector
var injector = new Injector();
injector.mapValue(Injector, injector);
injector.mapValue(String, cwd, 'cwd'); // current working directory
injector.mapValue(String, Sys.getCwd(), 'hwd'); // hxextern working directory
injector.mapSingleton(Console);
injector.mapSingleton(Haxelib);
injector.mapSingleton(Process);
injector.mapSingleton(Repository);
Macro.listSteps(injector);

// Update cwd
Sys.setCwd(cwd);

// Run
var cli = injector.instantiate(Cli);
cli.run(args);
Expand Down
9 changes: 9 additions & 0 deletions src/hxextern/Tools.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hxextern;

class Tools
{
public static function escapeEReg(value : String) : String
{
return ~/([-[\]{}()*+?.,\\^$|#\s])/g.replace(value, '\\$1');
}
}
67 changes: 44 additions & 23 deletions src/hxextern/command/GenerateCommand.hx
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
package hxextern.command;

import haxe.io.Path;
import hxextern.service.Console;
import hxextern.service.Haxelib;
import hxextern.step.*;
import hxextern.step.IStep;
import hxextern.step.StepContext;
import minject.Injector;
import sys.FileSystem;

using StringTools;

class GenerateCommand implements ICommand
{
@inject
public var injector(default, null) : Injector;

@inject
public var haxelib(default, null) : Haxelib;

@inject
public var console(default, null) : Console;

@inject('cwd')
public var cwd(default, null) : String;

public function new()
{
/*
this.path = path;
this.steps = new Map();
var types : Array<Class<IStep>> = [ScriptStep, NpmStep];
for (type in types) {
var instance = Type.createInstance(type, []);
this.steps[instance.type] = instance;
}
*/

}

public function run(args : Array<Dynamic>) : Void
Expand All @@ -33,30 +36,48 @@ class GenerateCommand implements ICommand
// Find haxelib file
var file = (null != path ?
this.haxelib.findFile(path) :
this.haxelib.findFromPath(Sys.getCwd())
this.haxelib.findFromPath(this.cwd)
);

// Extract datas
var data = this.haxelib.extract(file);
this.executeSteps(data.steps);
var context = new StepContext();

// Update to haxelib.json file
Sys.setCwd(Path.directory(file));

// Run steps
this.executeSteps(context, data.steps);
this.generateCode(context);
}

private function executeSteps(steps : Array<HaxelibHxExternStep>) : Void
private function executeSteps(context : StepContext, steps : Array<HaxelibHxExternStep>) : Void
{
/*
var definitions = new TypeDefinitionMap();
for (step in steps) {
// Run steps
for (i in 0...steps.length) {
var step = steps[i];

// Get step name
var name = step.type.trim().toLowerCase();
if (!this.steps.exists(name)) {
throw 'Step "${step.type}" has not been found';

// Get step
var instance = try this.injector.getInstance(IStep, name) catch(e : Dynamic) null;
if (null == instance) {
throw 'Step ${step.type} has not been found';
}

// Prepare context
context.setup(name);

// Run step
var instance = this.steps[name];
definitions = instance.run(definitions, step.options);
this.console.info('(${i + 1}) Running step "${name}"');
instance.initialize(step.options);
instance.run(context);
}
trace(definitions);
*/
}

private function generateCode(context : StepContext) : Void
{

}
}
17 changes: 15 additions & 2 deletions src/hxextern/service/Haxelib.hx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,21 @@ class Haxelib
// Return validated object
return {
steps: [ for (step in (steps : Array<DynamicAccess<Dynamic>>)) {
type: this.extractField(step, 'type'),
options: (step.exists('options') ? step['options'] : null),
var type = this.extractField(step, 'type');
var options = null;
for (field in step.keys()) {
if ('type' == field) {
continue;
}
if (null == options) {
options = {};
}
Reflect.setField(options, field, step[field]);
}
{
type: type,
options: options,
};
} ],
};
}
Expand Down
9 changes: 9 additions & 0 deletions src/hxextern/service/Process.hx
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ class Process

return result;
}

public function checkCommand(command : String) : Void
{
// Check if command exists
var result = this.execute('which', [command]);
if (0 != result.code) {
throw 'Command "${command}" not available';
}
}
}
6 changes: 3 additions & 3 deletions src/hxextern/service/Repository.hx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import haxe.Json;
import hxextern.service.Process;
import hxextern.Target;

using hxextern.Tools;

typedef RepositoryInfo = {
var name : String;
var target : Target;
Expand Down Expand Up @@ -89,9 +91,7 @@ class Repository
{
this.preload();

var escapedName = ~/([-[\]{}()*+?.,\\^$|#\s])/g.replace(name, '\\$1');
var ereg = new EReg(escapedName, 'ig');

var ereg = new EReg(name.escapeEReg(), 'ig');
return [
for (info in this.repositories)
if (ereg.match(info.name) && (null == target || info.target == target))
Expand Down
19 changes: 14 additions & 5 deletions src/hxextern/step/AbstractCommandStep.hx
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package hxextern.step;

import hxextern.service.Process;
import hxextern.step.IStep;

@:skip
class AbstractCommandStep extends AbstractStep
{
public function new(type : String)
@inject
public var process(default, null) : Process;

public function new()
{
super();
}

public override function run(context : StepContext) : Void
{
super(type);
super.run(context);
}

public override function run(definitions : TypeDefinitionMap, options : Null<Dynamic>) : TypeDefinitionMap
private function exec(command : String, ?args : Array<String>) : ProcessOutput
{
return definitions;
this.process.checkCommand(command);
return this.process.execute(command, args);
}
}
35 changes: 28 additions & 7 deletions src/hxextern/step/AbstractStep.hx
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
package hxextern.step;

import haxe.DynamicAccess;
import hxextern.service.Console;
import hxextern.step.IStep;

@:skip
class AbstractStep implements IStep
{
public var type(default, null) : String;
@inject
public var console(default, null) : Console;

public function new(type : String)
public function new()
{
this.type = type;
// ...
}

public function run(definitions : TypeDefinitionMap, options : Null<Dynamic>) : TypeDefinitionMap
public function initialize(options : DynamicAccess<Dynamic>) : Void
{
throw 'Must be overriden';
// ...
}

public function run(context : StepContext) : Void
{
// ...
}

private function getOption(options : DynamicAccess<Dynamic>, field : String, type : Dynamic, ?defaultValue : Dynamic) : Dynamic
{
if (!options.exists(field)) {
if (null != defaultValue) {
return defaultValue;
}
throw 'Missing field "${field}" in step options';
}

return definitions;
var value = options[field];
if (!Std.is(value, type)) {
throw 'Invalid type for field "${field}". Expected ${type}, but got ${Type.typeof(value)}';
}
return value;
}
}
58 changes: 58 additions & 0 deletions src/hxextern/step/AbstractTextStep.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package hxextern.step;

import haxe.DynamicAccess;
import hxextern.step.IStep;
import sys.FileSystem;
import sys.io.File;

class AbstractTextStep extends AbstractStep
{
private var file : String;

public function new()
{
super();
}

public override function initialize(options : DynamicAccess<Dynamic>) : Void
{
super.initialize(options);

this.file = FileSystem.absolutePath(this.getOption(options, 'file', String));
}

public override function run(context : StepContext) : Void
{
super.run(context);

// Ensure that file exists
if (!FileSystem.exists(this.file)) {
throw 'Cannot find file "${this.file}"';
}
}

private function getLines() : Array<String>
{
var input = File.read(this.file);
var lines = [];
try {
while (true) {
lines.push(input.readLine());
}
} catch (e : haxe.io.Eof) {}
input.close();

return lines;
}

private function setLines(lines : Array<String>) : Void
{
var output = File.write(this.file);
for (line in lines) {
output.writeString(line);
output.writeString('\n');
}
output.flush();
output.close();
}
}
61 changes: 61 additions & 0 deletions src/hxextern/step/CommandNpmStep.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package hxextern.step;

import haxe.DynamicAccess;
import hxextern.service.Process;
import hxextern.step.IStep;

using hxextern.Tools;
using StringTools;

@:step('command:npm')
class CommandNpmStep extends AbstractCommandStep
{
private var module : String;
private var version : String;

public function new()
{
super();
}

public override function initialize(options : DynamicAccess<Dynamic>) : Void
{
super.initialize(options);

this.module = this.getOption(options, 'module', String);
this.version = this.getOption(options, 'version', String, '');
}

public override function run(context : StepContext) : Void
{
super.run(context);

// Prepare package name
var packageName = this.module;
if (this.version.length > 0) {
packageName += '@${this.version}';
}

// Install module
var result = this.exec('npm', ['install', packageName, '--silent']);
if (0 == result.code) {
this.console.success('NPM module "${packageName}" installed');

// Extract installed npm module version
var ereg = new EReg('${this.module.escapeEReg()}@([0-9.]+)', 'ig');
if (ereg.match(result.output)) {
context.registerVariable('npm', {
module: {
name: this.module,
version: ereg.matched(1),
},
});
}
} else {
this.console
.error('NPM module "${this.module}" has not been installed')
.error(result.error)
;
}
}
}
Loading

0 comments on commit bfdfbff

Please sign in to comment.