github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/tasks/install.js (about)

     1  /*******************************
     2           Install Task
     3  *******************************/
     4  
     5  /*
     6     Install tasks
     7  
     8     For more notes
     9  
    10     * Runs automatically after npm update (hooks)
    11     * (NPM) Install - Will ask for where to put semantic (outside pm folder)
    12     * (NPM) Upgrade - Will look for semantic install, copy over files and update if new version
    13     * Standard installer runs asking for paths to site files etc
    14  
    15  */
    16  
    17  var
    18    gulp           = require('gulp'),
    19  
    20    // node dependencies
    21    console        = require('better-console'),
    22    extend         = require('extend'),
    23    fs             = require('fs'),
    24    mkdirp         = require('mkdirp'),
    25    path           = require('path'),
    26  
    27    // gulp dependencies
    28    chmod          = require('gulp-chmod'),
    29    del            = require('del'),
    30    jsonEditor     = require('gulp-json-editor'),
    31    plumber        = require('gulp-plumber'),
    32    prompt         = require('gulp-prompt'),
    33    rename         = require('gulp-rename'),
    34    replace        = require('gulp-replace'),
    35    requireDotFile = require('require-dot-file'),
    36    wrench         = require('wrench'),
    37  
    38    // install config
    39    install        = require('./config/project/install'),
    40  
    41    // user config
    42    config         = require('./config/user'),
    43  
    44    // release config (name/title/etc)
    45    release        = require('./config/project/release'),
    46  
    47    // shorthand
    48    questions      = install.questions,
    49    files          = install.files,
    50    folders        = install.folders,
    51    regExp         = install.regExp,
    52    settings       = install.settings,
    53    source         = install.source
    54  ;
    55  
    56  // Export install task
    57  module.exports = function () {
    58  
    59    var
    60      currentConfig = requireDotFile('semantic.json'),
    61      manager       = install.getPackageManager(),
    62      rootQuestions = questions.root
    63    ;
    64  
    65    console.clear();
    66  
    67    /* Test NPM
    68    manager = {
    69      name : 'NPM',
    70      root : path.normalize(__dirname + '/../')
    71    };
    72    */
    73  
    74    /*--------------
    75        PM Config
    76    ---------------*/
    77  
    78    /* Don't do end user config if SUI is a sub-module */
    79    if( install.isSubModule() ) {
    80      console.info('SUI is a sub-module, skipping end-user install');
    81      return;
    82    }
    83  
    84    // run update scripts if semantic.json exists
    85    if(currentConfig && manager.name === 'NPM') {
    86  
    87      var
    88        updateFolder = path.join(manager.root, currentConfig.base),
    89        updatePaths  = {
    90          config      : path.join(manager.root, files.config),
    91          tasks       : path.join(updateFolder, folders.tasks),
    92          themeImport : path.join(updateFolder, folders.themeImport),
    93          definition  : path.join(currentConfig.paths.source.definitions),
    94          site        : path.join(currentConfig.paths.source.site),
    95          theme       : path.join(currentConfig.paths.source.themes)
    96        }
    97      ;
    98  
    99      // duck-type if there is a project installed
   100      if( fs.existsSync(updatePaths.definition) ) {
   101  
   102        // perform update if new version
   103        if(currentConfig.version !== release.version) {
   104          console.log('Updating Semantic UI from ' + currentConfig.version + ' to ' + release.version);
   105  
   106          console.info('Updating ui definitions...');
   107          wrench.copyDirSyncRecursive(source.definitions, updatePaths.definition, settings.wrench.update);
   108  
   109          console.info('Updating default theme...');
   110          wrench.copyDirSyncRecursive(source.themes, updatePaths.theme, settings.wrench.update);
   111  
   112          console.info('Updating tasks...');
   113          wrench.copyDirSyncRecursive(source.tasks, updatePaths.tasks, settings.wrench.update);
   114  
   115          console.info('Updating gulpfile.js');
   116          gulp.src(source.userGulpFile)
   117            .pipe(plumber())
   118            .pipe(gulp.dest(updateFolder))
   119          ;
   120  
   121          // copy theme import
   122          console.info('Updating theme import file');
   123          gulp.src(source.themeImport)
   124            .pipe(plumber())
   125            .pipe(gulp.dest(updatePaths.themeImport))
   126          ;
   127  
   128          console.info('Adding new site theme files...');
   129          wrench.copyDirSyncRecursive(source.site, updatePaths.site, settings.wrench.site);
   130  
   131          console.info('Updating version...');
   132  
   133          // update version number in semantic.json
   134          gulp.src(updatePaths.config)
   135            .pipe(plumber())
   136            .pipe(rename(settings.rename.json)) // preserve file extension
   137            .pipe(jsonEditor({
   138              version: release.version
   139            }))
   140            .pipe(gulp.dest(manager.root))
   141          ;
   142  
   143          console.info('Update complete! Run "\033[92mgulp build\033[0m" to rebuild dist/ files.');
   144  
   145          return;
   146        }
   147        else {
   148          console.log('Current version of Semantic UI already installed');
   149          return;
   150        }
   151  
   152      }
   153      else {
   154        console.error('Cannot locate files to update at path: ', updatePaths.definition);
   155        console.log('Running installer');
   156      }
   157  
   158    }
   159  
   160    /*--------------
   161     Determine Root
   162    ---------------*/
   163  
   164    // PM that supports Build Tools (NPM Only Now)
   165    if(manager.name == 'NPM') {
   166      rootQuestions[0].message = rootQuestions[0].message
   167        .replace('{packageMessage}', 'We detected you are using \033[92m' + manager.name + '\033[0m. Nice! ')
   168        .replace('{root}', manager.root)
   169      ;
   170      // set default path to detected PM root
   171      rootQuestions[0].default = manager.root;
   172      rootQuestions[1].default = manager.root;
   173  
   174      // insert PM questions after "Install Type" question
   175      Array.prototype.splice.apply(questions.setup, [2, 0].concat(rootQuestions));
   176  
   177      // omit cleanup questions for managed install
   178      questions.cleanup = [];
   179    }
   180  
   181    /*--------------
   182         Set-up
   183    ---------------*/
   184  
   185    return gulp
   186      .src('gulpfile.js')
   187      .pipe(prompt.prompt(questions.setup, function(answers) {
   188  
   189        /*--------------
   190         Exit Conditions
   191        ---------------*/
   192  
   193        // if config exists and user specifies not to proceed
   194        if(answers.overwrite !== undefined && answers.overwrite == 'no') {
   195          return;
   196        }
   197  
   198        console.clear();
   199        console.log('Installing');
   200        console.log('------------------------------');
   201  
   202  
   203        /*--------------
   204              Paths
   205        ---------------*/
   206  
   207        var
   208          installPaths = {
   209            config            : files.config,
   210            configFolder      : folders.config,
   211            site              : answers.site || folders.site,
   212            themeConfig       : files.themeConfig,
   213            themeConfigFolder : folders.themeConfig
   214          },
   215          installFolder = false
   216        ;
   217  
   218        /*--------------
   219           PM Install
   220        ---------------*/
   221  
   222        // Check if PM install
   223        if(answers.useRoot || answers.customRoot) {
   224  
   225          // Set root to custom root path if set
   226          if(answers.customRoot) {
   227            if(answers.customRoot === '') {
   228              console.log('Unable to proceed, invalid project root');
   229              return;
   230            }
   231            manager.root = answers.customRoot;
   232          }
   233  
   234          // special install paths only for PM install
   235          installPaths = extend(false, {}, installPaths, {
   236            definition  : folders.definitions,
   237            lessImport  : folders.lessImport,
   238            tasks       : folders.tasks,
   239            theme       : folders.themes,
   240            themeImport : folders.themeImport
   241          });
   242  
   243          // add project root to semantic root
   244          installFolder = path.join(manager.root, answers.semanticRoot);
   245  
   246          // add install folder to all output paths
   247          for(var destination in installPaths) {
   248            if( installPaths.hasOwnProperty(destination) ) {
   249              // config goes in project root, rest in install folder
   250              installPaths[destination] = (destination == 'config' || destination == 'configFolder')
   251                ? path.normalize( path.join(manager.root, installPaths[destination]) )
   252                : path.normalize( path.join(installFolder, installPaths[destination]) )
   253              ;
   254            }
   255          }
   256  
   257          // create project folders
   258          try {
   259            mkdirp.sync(installFolder);
   260            mkdirp.sync(installPaths.definition);
   261            mkdirp.sync(installPaths.theme);
   262            mkdirp.sync(installPaths.tasks);
   263          }
   264          catch(error) {
   265            console.error('NPM does not have permissions to create folders at your specified path. Adjust your folders permissions and run "npm install" again');
   266          }
   267  
   268          console.log('Installing to \033[92m' + answers.semanticRoot + '\033[0m');
   269  
   270          console.info('Copying UI definitions');
   271          wrench.copyDirSyncRecursive(source.definitions, installPaths.definition, settings.wrench.install);
   272          wrench.copyDirSyncRecursive(source.themes, installPaths.theme, settings.wrench.install);
   273  
   274          console.info('Copying gulp tasks');
   275          wrench.copyDirSyncRecursive(source.tasks, installPaths.tasks, settings.wrench.install);
   276  
   277          // copy theme import
   278          console.info('Adding theme files');
   279          gulp.src(source.themeImport)
   280            .pipe(plumber())
   281            .pipe(gulp.dest(installPaths.themeImport))
   282          ;
   283          gulp.src(source.lessImport)
   284            .pipe(plumber())
   285            .pipe(gulp.dest(installPaths.lessImport))
   286          ;
   287  
   288          // create gulp file
   289          console.info('Creating gulpfile.js');
   290          gulp.src(source.userGulpFile)
   291            .pipe(plumber())
   292            .pipe(gulp.dest(installFolder))
   293          ;
   294  
   295        }
   296  
   297        /*--------------
   298           Site Theme
   299        ---------------*/
   300  
   301        // Copy _site templates folder to destination
   302        if( fs.existsSync(installPaths.site) ) {
   303          console.info('Site folder exists, merging files (no overwrite)', installPaths.site);
   304        }
   305        else {
   306          console.info('Creating site theme folder', installPaths.site);
   307        }
   308        wrench.copyDirSyncRecursive(source.site, installPaths.site, settings.wrench.site);
   309  
   310        /*--------------
   311          Theme Config
   312        ---------------*/
   313  
   314        var
   315          // determine path to site theme folder from theme config
   316          // force CSS path variable to use forward slashes for paths
   317          pathToSite   = path.relative(path.resolve(installPaths.themeConfigFolder), path.resolve(installPaths.site)).replace(/\\/g,'/'),
   318          siteVariable = "@siteFolder   : '" + pathToSite + "/';"
   319        ;
   320  
   321        // rewrite site variable in theme.less
   322        console.info('Adjusting @siteFolder to: ', pathToSite + '/');
   323  
   324        if(fs.existsSync(installPaths.themeConfig)) {
   325          console.info('Modifying src/theme.config (LESS config)', installPaths.themeConfig);
   326          gulp.src(installPaths.themeConfig)
   327            .pipe(plumber())
   328            .pipe(replace(regExp.siteVariable, siteVariable))
   329            .pipe(gulp.dest(installPaths.themeConfigFolder))
   330          ;
   331        }
   332        else {
   333          console.info('Creating src/theme.config (LESS config)', installPaths.themeConfig);
   334          gulp.src(source.themeConfig)
   335            .pipe(plumber())
   336            .pipe(rename({ extname : '' }))
   337            .pipe(replace(regExp.siteVariable, siteVariable))
   338            .pipe(gulp.dest(installPaths.themeConfigFolder))
   339          ;
   340        }
   341  
   342        /*--------------
   343          Semantic.json
   344        ---------------*/
   345  
   346        var
   347          jsonConfig = install.createJSON(answers)
   348        ;
   349  
   350        // adjust variables in theme.less
   351        if( fs.existsSync(files.config) ) {
   352          console.info('Extending config file (semantic.json)', installPaths.config);
   353          gulp.src(installPaths.config)
   354            .pipe(plumber())
   355            .pipe(rename(settings.rename.json)) // preserve file extension
   356            .pipe(jsonEditor(jsonConfig))
   357            .pipe(gulp.dest(installPaths.configFolder))
   358          ;
   359        }
   360        else {
   361          console.info('Creating config file (semantic.json)', installPaths.config);
   362          gulp.src(source.config)
   363            .pipe(plumber())
   364            .pipe(rename({ extname : '' })) // remove .template from ext
   365            .pipe(jsonEditor(jsonConfig))
   366            .pipe(gulp.dest(installPaths.configFolder))
   367          ;
   368        }
   369  
   370        // Completion Message
   371        if(installFolder) {
   372          console.log('Install complete! Navigate to \033[92m' + answers.semanticRoot + '\033[0m and run "\033[92mgulp build\033[0m" to build');
   373        }
   374        else {
   375          console.log('');
   376          console.log('');
   377        }
   378  
   379      }))
   380      .pipe(prompt.prompt(questions.cleanup, function(answers) {
   381        if(answers.cleanup == 'yes') {
   382          del(install.setupFiles);
   383        }
   384        if(answers.build == 'yes') {
   385          gulp.start('build');
   386        }
   387      }))
   388    ;
   389  
   390  
   391  };