#!/usr/bin/env php
<?php
# 将指定项目的assets目录和调用类库的的assets目录的文件进行合并，并输出保存到 wwwroot/assets/ 对应项目目录里

# 本脚本依赖 recess、sass 和 uglifyjs 分别处理css和js
# recess   https://github.com/twitter/recess
# sass     http://sass-lang.com/
# uglifyjs https://github.com/mishoo/UglifyJS
#
# 安装方法：
#
#  npm install recess -g
#  npm install uglify-js@1
#  gem install sass
#
# 其中，recess处理less后缀的css文件，sass处理scss和sass后缀的css文件


# 不自动执行，这样只初始化Bootstrap和Core类，而不执行Core::run()方法
$auto_run = false;
$done     = "[\x1b[35m未修改\x1b[39m]";
$success  = "\x1b[32m✔\x1b[39m";
$error    = "\x1b[31m✕\x1b[39m";

$argv = $_SERVER['argv'];

if (!isset($argv[1]) || !$argv[1])
{
    help();
}


function help()
{
    echo <<<EOF
使用方法: $ \x1b[36mmerge-assets\x1b[39m \x1b[33m[project]\x1b[39m [options]

OPTIONS:
  -r \x1b[32m全部重新生成\x1b[39m
  -a \x1b[32m全部项目\x1b[39m
  -c \x1b[32m先删除目标目录中所有文件后再重新生成全部assets\x1b[39m

EXAMPLE:
  生成全部项目assets文件:            \x1b[36mmerge-assets\x1b[39m \x1b[33m-a\x1b[39m
  全部项目重新生成文件  :            \x1b[36mmerge-assets\x1b[39m \x1b[33m-a -r\x1b[39m
  生成default项目文件   :            \x1b[36mmerge-assets\x1b[39m \x1b[33mdefault\x1b[39m
  生成default项目文件并清理多余文件: \x1b[36mmerge-assets\x1b[39m \x1b[33mdefault -c\x1b[39m

EOF;
    exit;
}

# 设置后台模式
if (in_array('--admin', $argv))
{
    $admin_mode = true;
}

if (in_array('-r', $argv))
{
    $key = array_search('-r', $argv);
    $recreate = true;
}
else
{
    $recreate = false;
}

if (in_array('-a', $argv))
{
    $_ = $_SERVER['_'];

    if ($_==$argv[0])
    {
        unset($argv[0]);
    }
    else
    {
        $_ .= ' ' . array_shift($argv);
    }

    # 全部项目
    $key = array_search('-a', $argv);
    unset($argv[$key]);

    $config = array();
    $adminmod = in_array('--admin', $argv);
    include (dirname(__FILE__).'/../config.php');

    if (isset($config['projects']) && is_array($config['projects']))foreach ($config['projects'] as $key => $project_config)
    {
        if (!$adminmod && (($project_config['url_admin'] && $project_config['url_admin']=='/') || (array)$project_config['url']===(array)$project_config['url_admin']))
        {
            // 直接调用admin模式
            $tmp_argv[] = '--admin';
            $tmpstr = "\n此项目为独立后台项目，无须生成前端assets文件\n直接生成项目后台assets文件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
        }
        else
        {
            $tmpstr = '';
            $tmp_argv = $argv;
        }

        $cmd = trim($_ . ' ' . $key . ' ' . implode(' ', $tmp_argv));

        echo "\n\n\n\n-------------------生成{$key}项目assets文件-------------------\n\n";
        echo $tmpstr;

        $handle = popen($cmd, 'r');
        while (($read = fread($handle, 128))!==false)
        {
            echo $read;
            if (feof($handle))break;
        }

        pclose($handle);
    }


    exit;
}

# 移除文件名
array_shift($argv);

# 调用项目
$project = $argv[0];

include (dirname(__FILE__).'/../index.php');

# 输出目录
$out_dir = DIR_ASSETS . $project .'/' . ($admin_mode?'~admin/':'');

# 清理css多余文件
if (in_array('-c', $argv))
{
    if (is_dir($out_dir))
    {
        echo "清理多余文件";
        File::remove_dir($out_dir);
        echo " {$success}\n";
    }
    $recreate = true;
}


echo "待合并目录：\n";
foreach (Core::include_path() as $path)
{
    echo "  => ".Core::debug_path($path, true)."\n";
}

$include_path = Core::include_path();
$include_path = array_reverse($include_path);

# 允许的后缀
$allow_suffix = Core::config('core.asset_allow_suffix');
if (!$allow_suffix)
{
    $allow_suffix = 'js|css|jpg|jpeg|png|gif|bmp|pdf|html|htm|mp4|swf';
}
$allow_suffix = explode('|', $allow_suffix);


# 循环获取所有文件列表
$file_paths = array();

# assets目录,经过 escapeshellarg 处理，用于sass，less处理时增加包含目录参数
$assets_path = array();

# 循环include path
foreach ($include_path as $path)
{
    $dir = $path ."assets/";

    if (is_dir($dir))
    {
        $assets_path[] = escapeshellarg($dir);
        glob_files($file_paths, $dir, strlen($dir));
    }
}

// print_r($file_paths);exit;

echo "\n修改数/文件数:\n";

# md5存放的文件
$cachefile = DIR_CACHE . 'asset_md5_by_proect_'.$project.($admin_mode?'~admin/':'');
if (is_file($cachefile))
{
    $old_md5 = (array)unserialize(file_get_contents($cachefile));
}
else
{
    $old_md5 = array();
}

# 修改的文件数
$changed_files = array();
# 输出信息
foreach (array('css'=>'css ', 'less'=>'less', 'sass'=>'sass', 'scss'=>'scss', 'js'=>'js  ', 'extends'=>'扩展', 'modules'=>'模块', 'other'=>'其它') as $type=>$name)
{
    if (isset($file_paths[$type]) && $file_paths[$type])
    {
        $all_count = 0;
        $changed_count = 0;
        foreach ($file_paths[$type] as $files)
        {
            if (true===$files)continue;
            $files = (array)$files;
            $all_count += count($files);
            foreach ($files as $file)
            {
                $new_md5 = $file_paths['file_md5'][$file];
                $file2 = Core::debug_path($file);
                if (!isset($old_md5[$file2]) || $old_md5[$file2]!=$new_md5)
                {
                    $changed_files[] = $file;
                    $changed_count += 1;
                }
            }
        }

        echo "  => {$name}: \x1b[33m".$changed_count."\x1b[39m/\x1b[36m".$all_count."\x1b[39m\n";
    }
}

echo "总修改数 : \x1b[33m".count($changed_files)."\x1b[39m/\x1b[36m".count($file_paths['file_md5'])."\x1b[39m\n";

echo "\n开始合并文件:";

$out_dir_path = Core::debug_path($out_dir, true);


function get_ext_contents($file, $type, $parent_file_list)
{
    # 避免 A include B，B include A 导致死循环
    if ($parent_file_list && in_array($file, $parent_file_list))return '';

    if ($parent_file_list)
    {
        $str = CRLF . CRLF . ($type=='js'?'//':'/*') . ' file: '. Core::debug_path($file) . ($type=='js'?'':' */') . CRLF;
    }
    else
    {
        $str = '';
    }

    if ($type=='js')
    {
        $content = file_get_contents($file);

        if (preg_match_all('#//(?:[ ]+)?@(?:codekit|myqee)\-(append|prepend|include) "(.*)";#', $content, $m))
        {
            foreach($m[0] as $k=>$v)
            {
                $tmpfile = Core::find_file('assets', trim(trim($m[2][$k]), './'), '');
                if (!$tmpfile)continue;

                $tmp_parent_file_list   = $parent_file_list;
                $tmp_parent_file_list[] = $file;

                if ($m[1][$k]=='prepend')
                {
                    # 加在文件头
                    $content = get_ext_contents($tmpfile, $type, $tmp_parent_file_list) . CRLF . $content;
                }
                else if ($m[1][$k]=='include')
                {
                    # 在当前位置插入
                    $content = str_replace($v, $v. CRLF .'//--include-begin--- '. CRLF . get_ext_contents($tmpfile, $type, $tmp_parent_file_list) . CRLF . '//---include-end--- ', $content);
                }
                else
                {
                    # 加在文件结尾
                    $content .= get_ext_contents($tmpfile, $type, $tmp_parent_file_list);
                }
            }
        }

        return $str . $content;
    }
    else
    {
        return $str . file_get_contents($file);
    }
}


# 记录需要压缩处理的文件列表
$todo_min_files = array();
foreach (array('css', 'less', 'scss', 'sass', 'js', 'other') as $type)
{
    if (!isset($file_paths[$type]) || !$file_paths[$type])
    {
        continue;
    }

    foreach ($file_paths[$type] as $tmpfile => $fullpath)
    {
        # 输出的文件名
        $out_file = $out_dir . $tmpfile;
        if (false!==strrpos($tmpfile, '/'))
        {
            $file_dir = substr($tmpfile, 0, strrpos($tmpfile, '/')+1);
        }
        else
        {
            $file_dir = '';
        }


        if ($recreate)
        {
            $need_renew = true;
        }
        else
        {
            if (is_file($out_file))
            {
                if (true!==$fullpath)
                {
                    $fulldebugpath = Core::debug_path($fullpath);
                }

                if (true!==$fullpath && (!isset($old_md5[$fulldebugpath]) || $old_md5[$fulldebugpath]!=$file_paths['file_md5'][$fullpath]))
                {
                    $need_renew = true;
                }
                else
                {
                    $need_renew = false;

                    # 获取所有依赖文件
                    if (isset($file_paths['extends'][$tmpfile]) && $file_paths['extends'][$tmpfile])
                    {
                        $tmpexfulldebugpath = Core::debug_path($file_paths['extends'][$tmpfile]);

                        if (!isset($old_md5[$tmpexfulldebugpath]) || $old_md5[$tmpexfulldebugpath]!=$file_paths['file_md5'][$file_paths['extends'][$tmpfile]])
                        {
                            $need_renew = true;
                        }
                    }

                    if ( false===$need_renew && isset($file_paths['modules'][$tmpfile]) && $file_paths['modules'][$tmpfile])foreach ($file_paths['modules'][$tmpfile] as $tmpfile2=>$tmpexfullpath)
                    {
                        $tmpexfulldebugpath = Core::debug_path($tmpexfullpath);
                        if (!isset($old_md5[$tmpexfulldebugpath]) || $old_md5[$tmpexfulldebugpath]!=$file_paths['file_md5'][$tmpexfullpath])
                        {
                            $need_renew = true;
                            break;
                        }
                        else
                        {
                            if (isset($file_paths['extends'][$tmpfile2]) && $file_paths['extends'][$tmpfile2])
                            {
                                $tmpexfulldebugpath = Core::debug_path($file_paths['extends'][$tmpfile2]);
                                if (!isset($old_md5[$tmpexfulldebugpath]) || $old_md5[$tmpexfulldebugpath]!=$file_paths['file_md5'][$file_paths['extends'][$tmpfile2]])
                                {
                                    $need_renew = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                $need_renew = true;
            }
        }

        # 无需修改
        if (!$need_renew)
        {
            // echo "\n  => {$out_dir_path}{$tmpfile} ".$done;
            continue;
        }

        # 内容
        if (true===$fullpath)
        {
            $content = '';
            $parent_file_list = array();
        }
        else
        {
            $content = get_ext_contents($fullpath, $type, array());
            $parent_file_list = array($fullpath);
        }

        if ($type=='css'||$type=='less'||$type=='scss'||$type=='sass'||$type=='js')
        {
            if (isset($file_paths['extends'][$tmpfile]) && $file_paths['extends'][$tmpfile])
            {
                # 读取扩展文件进行合并
                $content .= get_ext_contents($file_paths['extends'][$tmpfile], $type, $parent_file_list);
            }

            # JS的模块直接合并即可，CSS利用less处理@import的文件进行合并
            if ($type=='css' || $type=='js')
            {
                if (isset($file_paths['modules'][$tmpfile]) && $file_paths['modules'][$tmpfile])foreach($file_paths['modules'][$tmpfile] as $modfile => $tmpmfile)
                {
                    # 读取JS模块文件进行合并
                    $content .= get_ext_contents($tmpmfile, $type, $parent_file_list);

                    # 扩展
                    if (isset($file_paths['extends'][$modfile]) && $file_paths['extends'][$modfile])
                    {
                        $content .= get_ext_contents($file_paths['extends'][$modfile], $type, $parent_file_list);
                    }
                }
            }

            if (substr($out_file, -strlen($type)-5)!='.min.'.$type)
            {
                $todo_min_files[$type=='less'||$type=='scss'||$type=='sass'?'css':$type][$tmpfile] = $out_file;
            }
        }
        # 如果应该输出为文件的路径变成了文件夹，则先删除
        if (is_dir($out_file))
        {
            File::remove_dir($out_file);
        }

        # 写入文件
        $rs = File::create_file($out_file, trim($content));
        echo "\n  => {$out_dir_path}{$tmpfile} " . ($rs?$success:$error);

        # 对于LESS文件，如果有扩展模块，则先把扩展文件写入到文件中，再在后面由recess来处理
        if (($type=='less' || $type=='scss' || $type=='sass') && isset($file_paths['modules'][$tmpfile]) && $file_paths['modules'][$tmpfile])foreach ($file_paths['modules'][$tmpfile] as $modfile => $tmpmfile)
        {
            $outm_file = $out_dir . $modfile;
            $continue = file_get_contents($tmpmfile);
            if (isset($file_paths['extends'][$modfile]) && $file_paths['extends'][$modfile])
            {
                $content .= get_ext_contents($file_paths['extends'][$modfile], $type, array($tmpmfile));
            }
            $rs = File::create_file($outm_file, trim($continue));
            echo "\n     {$out_dir_path}{$modfile} " . ($rs?$success:$error);
        }
    }
}
echo "\n合并结束";


# 处理压缩
# ----------------------

# 读取nodejs配置
static $node_file = null;
static $node_modules_path = null;
if (null===$node_file)
{
    # 获取node的执行文件路径和node_modules的路径
    list($node_file, $node_modules_path) = get_node_set();
}

echo "\n\n准备压缩JS和CSS:\njs文件数:  \x1b[33m".count($todo_min_files['js'])."\x1b[39m\n";
# 压缩js
if (isset($todo_min_files['js']) && $todo_min_files['js'])foreach ($todo_min_files['js'] as $tmpname => $realfile)
{
    $output = '';

    $cmd = 'cd '.(escapeshellcmd($node_modules_path)).' && ' . escapeshellcmd($node_file).' '.escapeshellarg('./node_modules/uglify-js/bin/uglifyjs').' '.escapeshellarg($realfile).' -nc';

    exec($cmd, $output, $r);
    if (0===$r)
    {
        # 写入文件
        File::create_file(substr($realfile, 0, -3).'.min.js',implode('', $output));
        echo "  => ".$out_dir_path.substr($tmpname, 0, -3).".min.js " . ($rs?$success:$error)."\n";
    }
    elseif (1===$r)
    {
        echo "压缩 {$realfile} 文件失败，请检查js语法是否有误。";
    }
    else
    {
        echo "系统执行uglifyjs处理失败，请检查执行uglifyjs是否安装或模块路径是否配置正确\nnpm安装:\n\x1b[31m  npm install uglify-js@1 -g\x1b[39m\nuglifyjs安装详见 https://github.com/mishoo/UglifyJS \n执行的命令为：\n";
        echo $cmd ."\n";
        exit;
    }
}


echo "CSS文件数: \x1b[33m".count($todo_min_files['css'])."\x1b[39m\n";
# 压缩处理less和css
if (isset($todo_min_files['css']) && $todo_min_files['css'])foreach ($todo_min_files['css'] as $tmpname => $realfile)
{
    $type = substr($tmpname, strrpos($tmpname, '.')+1);
    if ($type=='less' || $type=='scss' || $type=='sass')
    {
        $n = 5;
        $gostr = '  ';
    }
    else
    {
        $n = 4;
        $gostr = '=>';
    }

    if ($type=='less' || $type=='scss' || $type=='sass')
    {
        # 处理LESS转换为CSS
        $output   = '';
        $path_str = '';

        if ($type=='less')
        {
            if ($assets_path)$path_str = ' --includePath=' . implode(' --includePath=', $assets_path);
            $cmd = 'cd '.(escapeshellcmd($node_modules_path)).' && ' . escapeshellcmd($node_file).' '.escapeshellarg('./node_modules/recess/bin/recess').' --compile'.$path_str.' '.escapeshellarg($realfile);
        }
        else
        {
            if ($assets_path)$path_str = ' --load-path=' . implode(' --load-path=', $assets_path);
            $cmd = 'sass -t expanded'.$path_str.' '.escapeshellarg($realfile);
        }

        exec($cmd, $output, $r);
        if (0===$r)
        {
            # 写入文件
            File::create_file(substr($realfile, 0, -$n).'.css', implode('', $output));
            echo "  => ".$out_dir_path.substr($tmpname, 0, -$n).".css " . ($rs?$success:$error)."\n";
        }
        else
        {
            if ($type=='less')
            {
                echo "系统执行less处理失败，请检查执行recess是否安装或模块路径是否配置正确\nnpm安装:\n\x1b[31m  npm install recess -g\x1b[39m\n详细见：https://github.com/twitter/recess \n执行的命令为：\n";
            }
            else
            {
                echo "系统执行{$type}处理失败，请检查sass是否安装或配置正确\ngem安装:\n\x1b[31m  gem install sass\x1b[39m\nsass的安装方法见 http://sass-lang.com/download.html\n执行的命令为：\n";
            }

            echo $cmd ."\n";
            exit;
        }
    }

    # 处理压缩
    $output   = '';
    $path_str = '';

    if ($type=='less' || $type=='css')
    {
        if ($assets_path)$path_str = ' --includePath=' . implode(' --includePath=', $assets_path);
        $cmd = 'cd '.(escapeshellcmd($node_modules_path)).' && ' . escapeshellcmd($node_file).' '.escapeshellarg('./node_modules/recess/bin/recess').' --compress'.$path_str.' '.escapeshellarg($realfile);
    }
    else
    {
        if ($assets_path)$path_str = ' --load-path=' . implode(' --load-path=', $assets_path);
        $cmd = 'sass -t compressed'.$path_str.' '. escapeshellarg($realfile);
    }

    exec($cmd, $output, $r);

    if (0===$r)
    {
        # 写入文件
        File::create_file(substr($realfile, 0, -$n).'.min.css', implode('', $output));
        echo "  {$gostr} ".$out_dir_path.substr($tmpname, 0, -$n).".min.css " . ($rs?$success:$error)."\n";
    }
    else
    {
        if (1===$r)
        {
            echo "\x1b[31m执行{$type}处理失败，请检查相关文件\x1b[39m\n";
            echo $cmd ."\n";
        }
        else
        {
            if ($type=='less')
            {
                echo "系统执行less处理失败，请检查执行recess是否安装或模块路径是否配置正确\nnpm安装:\n\x1b[31m  npm install recess -g\x1b[39m\n详细见：https://github.com/twitter/recess \n执行的命令为：\n";
            }
            else
            {
                echo "系统执行{$type}处理失败，请检查sass是否安装或配置正确\ngem安装:\n\x1b[31m  gem install sass\x1b[39m\nsass的安装方法见 http://sass-lang.com/download.html\n执行的命令为：\n";
            }
            echo $cmd ."\n";
            exit;
        }
    }
}

if (isset($file_paths['less']) && $file_paths['less'])
{
    echo "\n清理Less文件";
    foreach($file_paths['less'] as $tmpname=>$tmpfile)
    {
        File::unlink($out_dir.$tmpname);
    }
    echo " $success\n";
}

if (isset($file_paths['scss']) && $file_paths['scss'])
{
    echo "\n清理scss文件";
    foreach($file_paths['scss'] as $tmpname=>$tmpfile)
    {
        File::unlink($out_dir.$tmpname);
    }
    echo " $success\n";
}

if (isset($file_paths['sass']) && $file_paths['sass'])
{
    echo "\n清理sass文件";
    foreach($file_paths['sass'] as $tmpname=>$tmpfile)
    {
        File::unlink($out_dir.$tmpname);
    }
    echo " $success\n";
}


if (isset($file_paths['modules']) && $file_paths['modules'])foreach($file_paths['modules'] as $tmpparenname=>$tmpfiles)
{
    $type = substr($tmpparenname, strrpos($tmpparenname, '.')+1);
    if ($type=='less'||$type=='scss'||$type=='sass')
    {
        foreach ($tmpfiles as $tmpname => $tmpfile)
        {
            File::unlink($out_dir.$tmpname);
        }
    }
}

$file_md5 = array();
foreach ($file_paths['file_md5'] as $tmpfile=>$md5)
{
    $file_md5[Core::debug_path($tmpfile)] = $md5;
}
# 排序2次的用途是保证一些特殊情况下排序能得到纠正，比如有2个key分别是 test1.js 和 test.js 在排序时会有bug
asort($file_md5);
asort($file_md5);
$content = serialize($file_md5);
if (!is_file($cachefile) || md5($content)!=md5_file($cachefile))
{
    # 保存MD5列表
    File::create_file($cachefile,$content);
}

echo "\n\n操作完成\n";


if (!$admin_mode && Core::config('core.projects.'.$project.'.url_admin'))
{
    $_ = $_SERVER['_'];

    if ($_==$argv[0])
    {
        unset($argv[0]);
    }
    else
    {
        $_ .= ' ' . array_shift($argv);
    }

    $argv[] = '--admin';

    echo "\n\n生成{$project}项目后台assets文件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
    chdir(dirname(__FILE__));
    $cmd = trim($_ . ' ' . implode(' ', $argv));
    var_dump($cmd);

    $handle = popen($cmd, 'r');
    while (($read = fread($handle, 128))!==false)
    {
        echo $read;
        if (feof($handle))break;
    }
    pclose($handle);
}

exit;


/**
 * 递归的读取目录下所有文件到$file_paths中
 */
function glob_files(&$file_paths,$dir,$dir_len)
{
    global $allow_suffix;

    $files = glob($dir .'*', GLOB_NOSORT);

    if ($files)foreach ($files as $file)
    {
        if ($file==='.'||$file==='..'||substr($file,0,1)==='.')continue;

        # 文件夹
        if (is_dir($file))
        {
            glob_files($file_paths, $file.'/', $dir_len);
            continue;
        }

        # 将文件列表加入到all数组里
        $file_paths['file_md5'][$file] = md5_file($file);

        $file = str_replace('\\', '/', $file);
        $path_rpos = strrpos($file, '/');

        # 文件名
        $file_name = substr($file, $path_rpos+1);
        $file_path = substr($file, $dir_len, -strlen($file_name)).$file_name;

        $rpos = strrpos($file_name, '.');
        if ($rpos>0)
        {
            # 后缀
            $suffix = strtolower(substr($file_name, $rpos+1));

            if ($suffix=='css'||$suffix=='less'||$suffix=='sass'||$suffix=='scss'||$suffix=='js')
            {
                # 处理CSS，JS文件
                $file_name_arr = explode('.', $file_name);
                $count_file_name_arr = count($file_name_arr);

                if ($count_file_name_arr>=3)
                {
                    $type = strtolower($file_name_arr[1]);
                    if ('extend'==$type || 'mod'==$type)
                    {
                        if ('extend'==$type)
                        {
                            if ($count_file_name_arr==3)
                            {
                                unset($file_name_arr[1]);
                            }
                            else
                            {
                                $file_name_arr[1] = 'mod';
                            }
                        }
                        else
                        {
                            $file_name_arr = array($file_name_arr[0], $file_name_arr[count($file_name_arr)-1]);
                        }
                        $parent_file_name = implode('.',$file_name_arr);
                        $parent_file_path = substr($file,$dir_len,-strlen($file_name)).$parent_file_name;

                        if ($suffix=='less'||$suffix=='sass'||$suffix=='scss')
                        {
                            $parent_file_path = substr($file_path, 0, -strlen($type)).'.css';
                        }

                        if ('mod'==$type)
                        {
                            $file_paths['modules'][$parent_file_path][substr($file, $dir_len, -strlen($file_name)).$file_name] = $file;
                        }
                        else
                        {
                            $file_paths['extends'][$parent_file_path] = $file;
                        }

                        if ($count_file_name_arr==3 && !$file_paths[$suffix][$parent_file_path])
                        {
                            $file_paths[$suffix][$parent_file_path] = true;
                        }
                        continue;
                    }
                }

                $file_paths[$suffix][$file_path] = $file;
            }
            elseif (in_array($suffix, $allow_suffix))
            {
                $file_paths['other'][$file_path] = $file;
            }
        }
    }
}

/**
 * 获取node的设置
 *
 * @return array(exe_file_path,modules_path)
 */
function get_node_set()
{
    # 读取nodejs配置
    $node_config_file = dirname(__FILE__) . '/config.ini.php';

    if (is_file($node_config_file))
    {
        $config = array();
        include $node_config_file;
        $node_config = $config['nodejs'];
        unset($config);
    }
    else
    {
        $node_config = null;
    }

    # 执行程序
    if (is_array($node_config) && isset($node_config[0]) && $node_config[0])
    {
        $node_file = $node_config[0];
    }
    else
    {
        $node_file = IS_WIN?'c:\\Program Files\\nodejs\\node.exe':'/usr/local/bin/node';
    }

    # node_modules 路径
    if (is_array($node_config) && isset($node_config[1]) && $node_config[1])
    {
        $node_modules_path = $node_config[1];
    }
    else
    {
        $node_modules_path = IS_WIN?'c:\\Program Files\\nodejs\\node_modules\\' : '/usr/local/lib/node_modules/';
    }

    $node_modules_path = explode('/', str_replace('\\', '/', rtrim($node_modules_path,'/\\')));
    $i = count($node_modules_path)-1;
    if ($node_modules_path[$i]=='node_modules')
    {
        # 将node_modules移除
        unset($node_modules_path[$i]);
    }

    # 得到node_modules的父目录
    $node_modules_path = implode(DS, $node_modules_path) . DS;

    if (!is_dir($node_modules_path))
    {
        if (is_dir(DIR_SYSTEM.'node_modules'.DS))
        {
            $node_modules_path = DIR_SYSTEM . 'node_modules' . DS;
        }
        else
        {
            throw new Exception('node_modules目录不存在，请修改config'.EXT.'中$config[\'nodejs\']中配置');
        }
    }

    return array($node_file, $node_modules_path);
}
