<commit_before>/*
 * Mathoid worker.
 *
 * Configure in storoid.config.json.
 */
// global includes
var express = require('express'),
	cluster = require('cluster'),
	http = require('http'),
	fs = require('fs'),
	child_process = require('child_process'),
	request = require('request'),
	querystring = require('querystring');
var mjAPI = require("./MathJaxNode/lib/mj-single.js");

var format = "TeX";
var font = "TeX";

var config;

// Get the config
try {
	config = JSON.parse(fs.readFileSync('./mathoid.config.json', 'utf8'));
} catch ( e ) {
	// Build a skeleton localSettings to prevent errors later.
	console.error("Please set up your mathoid.config.json from the example " +
			"storoid.config.json.example");
	process.exit(1);
}

mjAPI.config({MathJax: {SVG: {font: font}}, displayError: true});
mjAPI.start();

/**
 * The name of this instance.
 * @property {string}
 */
var instanceName = cluster.isWorker ? 'worker(' + process.pid + ')' : 'master';

console.log( ' - ' + instanceName + ' loading...' );

/* -------------------- Web service --------------------- */

var app = express.createServer();

// Increase the form field size limit from the 2M default.
app.use(express.bodyParser({maxFieldsSize: 25 * 1024 * 1024}));
app.use( express.limit( '25mb' ) );

app.get('/', function(req, res){
	res.write('\n');
	res.write('Welcome to Mathoid. POST to / with var tex');
	res.write('<form action="/" method="POST"><input type="text" name="q"></form>');
	res.end('');
});

// robots.txt: no indexing.
app.get(/^\/robots.txt$/, function ( req, res ) {
	res.end( "User-agent: *\nDisallow: /\n" );
});

function handleRequest(req, res, q, type) {
	var mml = true;
	//Keep format variables constant
	if (type === "tex") {
		type = "TeX";
	}
	if (type === "mml" || type === "MathML") {
		type = "MathML";
		mml = false;
	}
	if (type === "ascii" || type === "asciimath") {
		type = "AsciiMath";
	}
	mjAPI.typeset({math: q, format: type, svg: true, img: true, mml: mml}, function (data) {
		if (data.errors) {
			data.success = false;
			data.log = "Error:" + JSON.stringify(data.errors);
		} else {
			data.success = true;
			data.log = "success";
		}

		// Temporary work-around for a duplicate attribute (invalid XML)
		// returned by MathJax.
		if (data.mml) {
			data.mml = data.mml.replace(/displaystyle="true" (?=displaystyle)/, '');
		}

		// Strip some styling returned by MathJax
		if (data.svg) {
			data.svg = data.svg.replace(/(style="[^"]*)(?:margin|position):[^;]+;/, '$1');
		}

		res.writeHead(200,
			{
				'Content-Type': 'application/json'
			});
		res.end(JSON.stringify(data));
	});
}

app.post(/^\/$/, function ( req, res ) {
	// First some rudimentary input validation
	if (!(req.body.q)) {
		res.writeHead(400);
		return res.end(JSON.stringify({error: "q (query) post parameter is missing!"}));
	}
	var q = req.body.q;
    var type = req.body.type;
    if (!(req.body.type) ){
        type = 'tex';
    }
	handleRequest(req, res, q, type);

});

console.log( ' - ' + instanceName + ' ready' );

module.exports = app;

<commit_msg>Strip margins too<commit_after>/*
 * Mathoid worker.
 *
 * Configure in storoid.config.json.
 */
// global includes
var express = require('express'),
	cluster = require('cluster'),
	http = require('http'),
	fs = require('fs'),
	child_process = require('child_process'),
	request = require('request'),
	querystring = require('querystring');
var mjAPI = require("./MathJaxNode/lib/mj-single.js");

var format = "TeX";
var font = "TeX";

var config;

// Get the config
try {
	config = JSON.parse(fs.readFileSync('./mathoid.config.json', 'utf8'));
} catch ( e ) {
	// Build a skeleton localSettings to prevent errors later.
	console.error("Please set up your mathoid.config.json from the example " +
			"storoid.config.json.example");
	process.exit(1);
}

mjAPI.config({MathJax: {SVG: {font: font}}, displayError: true});
mjAPI.start();

/**
 * The name of this instance.
 * @property {string}
 */
var instanceName = cluster.isWorker ? 'worker(' + process.pid + ')' : 'master';

console.log( ' - ' + instanceName + ' loading...' );

/* -------------------- Web service --------------------- */

var app = express.createServer();

// Increase the form field size limit from the 2M default.
app.use(express.bodyParser({maxFieldsSize: 25 * 1024 * 1024}));
app.use( express.limit( '25mb' ) );

app.get('/', function(req, res){
	res.write('\n');
	res.write('Welcome to Mathoid. POST to / with var tex');
	res.write('<form action="/" method="POST"><input type="text" name="q"></form>');
	res.end('');
});

// robots.txt: no indexing.
app.get(/^\/robots.txt$/, function ( req, res ) {
	res.end( "User-agent: *\nDisallow: /\n" );
});

function handleRequest(req, res, q, type) {
	var mml = true;
	//Keep format variables constant
	if (type === "tex") {
		type = "TeX";
	}
	if (type === "mml" || type === "MathML") {
		type = "MathML";
		mml = false;
	}
	if (type === "ascii" || type === "asciimath") {
		type = "AsciiMath";
	}
	mjAPI.typeset({math: q, format: type, svg: true, img: true, mml: mml}, function (data) {
		if (data.errors) {
			data.success = false;
			data.log = "Error:" + JSON.stringify(data.errors);
		} else {
			data.success = true;
			data.log = "success";
		}

		// Temporary work-around for a duplicate attribute (invalid XML)
		// returned by MathJax.
		if (data.mml) {
			data.mml = data.mml.replace(/displaystyle="true" (?=displaystyle)/, '');
		}

		// Strip some styling returned by MathJax
		if (data.svg) {
			data.svg = data.svg.replace(/style="([^"]+)"/, function(match, style) {
					return 'style="'
						+ style.replace(/(?:margin(?:-[a-z]+)?|position):[^;]+; */g, '')
						+ '"';
			});
		}

		res.writeHead(200,
			{
				'Content-Type': 'application/json'
			});
		res.end(JSON.stringify(data));
	});
}

app.post(/^\/$/, function ( req, res ) {
	// First some rudimentary input validation
	if (!(req.body.q)) {
		res.writeHead(400);
		return res.end(JSON.stringify({error: "q (query) post parameter is missing!"}));
	}
	var q = req.body.q;
    var type = req.body.type;
    if (!(req.body.type) ){
        type = 'tex';
    }
	handleRequest(req, res, q, type);

});

console.log( ' - ' + instanceName + ' ready' );

module.exports = app;

<|endoftext|>


<commit_before>
var path = require('path')
  , fm = require('front-matter')
  , marked = require('marked')
  , hogan = require('hogan.js')
  , beardo = require('beardo')
  , mkdirp = require('mkdirp')
  , fs = require('graceful-fs')
  , extensions = { '.md': '.html'
    , '.markdown': '.html'
    , '.mdown': ".html"
    , '.mustache': '.html'
    , '.mkdn': '.html'
    , '.mkd': '.html'
    }

module.exports = function(file, haiku){
  var page = typeof file === 'string' ? { filename: file } : file

  // extends the passed in object and returns it
  Object.defineProperty(page, 'haiku', { value: haiku })
  Object.defineProperty(page, 'name', { get: name })
  Object.defineProperty(page, 'destination', { get: destination })
  Object.defineProperty(page, 'collection', { get: collection })
  Object.defineProperty(page, 'dirname', { get: dirname })
  Object.defineProperty(page, 'url', { get: url })
  Object.defineProperty(page, 'context', { get: context })

  Object.defineProperty(page, 'build', { value: build })
  Object.defineProperty(page, 'render', { value: render })
  Object.defineProperty(page, 'render', { value: render })

  Object.defineProperty(page, 'body', { get: body })
  Object.defineProperty(page, 'meta', { get: meta })

  Object.defineProperty(page, 'logger', {
    value: haiku.logger.child({ page: page.name })
  })

  //   , stats: { value: {}, writable: true }
  //   , data: { value: '', writable: true }
  //   }
  // , page = Object.create({ read: read
  //   , write: write
  //   , render: render
  //   }, props)

  return page
}

function name(){
  var page = this
    , haiku = page.haiku

  return page.filename
  .replace(haiku.opt('content-dir'), '')
  .replace(new RegExp('^' + path.sep), '') // trims leading slash
}

function destination(){
  var page = this
    , haiku = page.haiku

  return path.join(haiku.opt('build-dir'), page.url)
}

function dirname(){
  var page = this
    , haiku = page.haiku

  return path
  .relative(haiku.opt('src'), path.dirname(page.filename))
}

function collection(){
  var page = this
    , haiku = page.haiku

  return path
  .relative(haiku.opt('src'), path.dirname(page.filename))
  .replace(path.sep, '.')
}

function url(){
  var page = this
    , haiku = page.haiku
    , uri = page.filename.replace(haiku.opt('content-dir'), '')

  var mime = require('mime')
    , ct = mime.lookup(page.filename)
    , ext = path.extname(page.filename)
    , wants = page.meta['content-type']

  if (ct === 'text/x-markdown') {
    if (ct === wants) return uri
    else return uri.replace(ext, '.html')
  }

  return uri
}

function build(callback){
  var page = this
    , haiku = page.haiku

  page.render(function(err, out){
    if (err) return callback(err)

    mkdirp(path.dirname(page.destination), function(err, made){
      if (err) return callback(err)

      if (made) page.logger.info('created dir: %s', page.dirname)

      fs.writeFile(page.destination, out, function(err){
        if (err) return callback(err)

        page.logger.info('built')

        callback()
      })
    })

  })
}

function render(ctx, callback){
  var page = this
    , haiku = page.haiku

  if (typeof ctx === 'function') {
    callback = ctx
    ctx = {}
  }

  // adds haiku.ctx to the ctx argument
  for (var key in haiku.context) ctx[key] = haiku.context[key]

  ctx.page = page.context

  // This might be pulled into beardo, also an expensive operation
  // think about caching it
  // NOTE: this has to happen after everything has been read
  var compiled = hogan.compile(page.body)
    , mustached = compiled.render(ctx)
    , mime = require('mime')
    , wantsMD = mime.lookup(page.filename) === 'text/x-markdown'
      && ctx.page['content-type'] !== 'text/x-markdown'
    , MD = wantsMD ? marked(mustached) : mustached

  var template = beardo.add(page.filename, MD)

  // TODO: only apply default layout to html
  ctx.layout = ctx.page.layout

  // tell beardo wheres what
  beardo.directory = path.join(haiku.opt('src'), 'templates')

  // ???: beardo needs a way to distinguish templates that need reading
  // vs ones that were added manually
  beardo.render(page.filename, ctx, function(err, out){
    page.logger.info('rendered page')
    page.logger.info(out)

    if (err) return callback(err)
    else return callback(null, out)
  })
}

// TODO: throw a meaningful error when page.data is missing
function body(){
  return fm(this.data).body
}

// TODO: throw a meaningful error when page.data is missing
function meta(){
  return fm(this.data).attributes
}

function context(){
  var page = this
    , haiku = page.haiku
    , defaults = { title: page.name }

  page._context = page._context || {}

  // Build the context with the defaults
  for (var key in defaults) page._context[key] = defaults[key]

  // apply overrides
  for (var key in page.meta) {
    var value = page.meta[key]
      , isString = typeof value === 'string'
      , matches = isString ? value.match('haiku:content/') : null

    // Deal with keys that expand other pages
    if (matches) {
      // removes the "haiku:content/"
      var name = value.replace(matches[0], '')
        , expanded = haiku.find(name)

      // NOTE: this should throw in a menaingful way if your trying to
      // expand a page that doesn't exitst
      if (! expanded) {
        console.error('haiku.pages', haiku.pages)
        throw new Error( name + ' does not exist')
      }

      page._context[key] = expanded.context
    } else page._context[key] = value
  }

  // Apply the tings we don't want overidden
  page._context.body = page.body
  page._context.url = page.url
  page._context.name = page.name

  // Helpers / lambdas
  page._context.next = function(){
    var keys = page.collection.split('.')
      , parent = page.haiku.context

    keys.forEach(function(key){
      parent = parent[key]
    })

    return parent[parent.indexOf(page._context) + 1]
  }

  page._context.previous = function(){
    var keys = page.collection.split('.')
      , parent = page.haiku.context

    keys.forEach(function(key){
      parent = parent[key]
    })

    return parent[parent.indexOf(page._context) - 1]
  }

  return page._context
}
<commit_msg>Adds minimal debugging info to yaml parser errors, fixes #67<commit_after>
var path = require('path')
  , fm = require('front-matter')
  , marked = require('marked')
  , hogan = require('hogan.js')
  , beardo = require('beardo')
  , mkdirp = require('mkdirp')
  , fs = require('graceful-fs')
  , extensions = { '.md': '.html'
    , '.markdown': '.html'
    , '.mdown': ".html"
    , '.mustache': '.html'
    , '.mkdn': '.html'
    , '.mkd': '.html'
    }

module.exports = function(file, haiku){
  var page = typeof file === 'string' ? { filename: file } : file

  // extends the passed in object and returns it
  Object.defineProperty(page, 'haiku', { value: haiku })
  Object.defineProperty(page, 'name', { get: name })
  Object.defineProperty(page, 'destination', { get: destination })
  Object.defineProperty(page, 'collection', { get: collection })
  Object.defineProperty(page, 'dirname', { get: dirname })
  Object.defineProperty(page, 'url', { get: url })
  Object.defineProperty(page, 'context', { get: context })

  Object.defineProperty(page, 'build', { value: build })
  Object.defineProperty(page, 'render', { value: render })
  Object.defineProperty(page, 'render', { value: render })

  Object.defineProperty(page, 'body', { get: body })
  Object.defineProperty(page, 'meta', { get: meta })

  Object.defineProperty(page, 'logger', {
    value: haiku.logger.child({ page: page.name })
  })

  //   , stats: { value: {}, writable: true }
  //   , data: { value: '', writable: true }
  //   }
  // , page = Object.create({ read: read
  //   , write: write
  //   , render: render
  //   }, props)

  return page
}

function name(){
  var page = this
    , haiku = page.haiku

  return page.filename
  .replace(haiku.opt('content-dir'), '')
  .replace(new RegExp('^' + path.sep), '') // trims leading slash
}

function destination(){
  var page = this
    , haiku = page.haiku

  return path.join(haiku.opt('build-dir'), page.url)
}

function dirname(){
  var page = this
    , haiku = page.haiku

  return path
  .relative(haiku.opt('src'), path.dirname(page.filename))
}

function collection(){
  var page = this
    , haiku = page.haiku

  return path
  .relative(haiku.opt('src'), path.dirname(page.filename))
  .replace(path.sep, '.')
}

function url(){
  var page = this
    , haiku = page.haiku
    , uri = page.filename.replace(haiku.opt('content-dir'), '')

  var mime = require('mime')
    , ct = mime.lookup(page.filename)
    , ext = path.extname(page.filename)
    , wants = page.meta['content-type']

  if (ct === 'text/x-markdown') {
    if (ct === wants) return uri
    else return uri.replace(ext, '.html')
  }

  return uri
}

function build(callback){
  var page = this
    , haiku = page.haiku

  page.render(function(err, out){
    if (err) return callback(err)

    mkdirp(path.dirname(page.destination), function(err, made){
      if (err) return callback(err)

      if (made) page.logger.info('created dir: %s', page.dirname)

      fs.writeFile(page.destination, out, function(err){
        if (err) return callback(err)

        page.logger.info('built')

        callback()
      })
    })

  })
}

function render(ctx, callback){
  var page = this
    , haiku = page.haiku

  if (typeof ctx === 'function') {
    callback = ctx
    ctx = {}
  }

  // adds haiku.ctx to the ctx argument
  for (var key in haiku.context) ctx[key] = haiku.context[key]

  ctx.page = page.context

  // This might be pulled into beardo, also an expensive operation
  // think about caching it
  // NOTE: this has to happen after everything has been read
  var compiled = hogan.compile(page.body)
    , mustached = compiled.render(ctx)
    , mime = require('mime')
    , wantsMD = mime.lookup(page.filename) === 'text/x-markdown'
      && ctx.page['content-type'] !== 'text/x-markdown'
    , MD = wantsMD ? marked(mustached) : mustached

  var template = beardo.add(page.filename, MD)

  // TODO: only apply default layout to html
  ctx.layout = ctx.page.layout

  // tell beardo wheres what
  beardo.directory = path.join(haiku.opt('src'), 'templates')

  // ???: beardo needs a way to distinguish templates that need reading
  // vs ones that were added manually
  beardo.render(page.filename, ctx, function(err, out){
    page.logger.info('rendered page')
    page.logger.info(out)

    if (err) return callback(err)
    else return callback(null, out)
  })
}

// TODO: throw a meaningful error when page.data is missing
function body(){
  return fm(this.data).body
}

// TODO: throw a meaningful error when page.data is missing
function meta(){
  try {
    var _meta = fm(this.data).attributes
  } catch(e) {
    var error = new Error('Bad front-matter - '
    + e.problem
    + ' - '
    + this.filename
    + ':'
    + e.problem_mark.line)

    this.haiku.emit('error', error)

    // throw error
  }

  return _meta
}

function context(){
  var page = this
    , haiku = page.haiku
    , defaults = { title: page.name }

  page._context = page._context || {}

  // Build the context with the defaults
  for (var key in defaults) page._context[key] = defaults[key]

  // apply overrides
  for (var key in page.meta) {
    var value = page.meta[key]
      , isString = typeof value === 'string'
      , matches = isString ? value.match('haiku:content/') : null

    // Deal with keys that expand other pages
    if (matches) {
      // removes the "haiku:content/"
      var name = value.replace(matches[0], '')
        , expanded = haiku.find(name)

      // NOTE: this should throw in a menaingful way if your trying to
      // expand a page that doesn't exitst
      if (! expanded) {
        console.error('haiku.pages', haiku.pages)
        throw new Error( name + ' does not exist')
      }

      page._context[key] = expanded.context
    } else page._context[key] = value
  }

  // Apply the tings we don't want overidden
  page._context.body = page.body
  page._context.url = page.url
  page._context.name = page.name

  // Helpers / lambdas
  page._context.next = function(){
    var keys = page.collection.split('.')
      , parent = page.haiku.context

    keys.forEach(function(key){
      parent = parent[key]
    })

    return parent[parent.indexOf(page._context) + 1]
  }

  page._context.previous = function(){
    var keys = page.collection.split('.')
      , parent = page.haiku.context

    keys.forEach(function(key){
      parent = parent[key]
    })

    return parent[parent.indexOf(page._context) - 1]
  }

  return page._context
}
<|endoftext|>


<commit_before>/** Represents a single project in the work carousel */
import Parallax3D from '../parallax';

export class CarouselCard {
  constructor(elem, tags) {
    this.elem = elem;
    this.elem.classList.add('carousel-card');
    // Move elem into a wrapper div
    this.wrapper = document.createElement('div');
    this.wrapper.className = 'carousel-card-wrapper';
    this.elem.parentNode.insertBefore(this.wrapper, this.elem);
    this.wrapper.appendChild(this.elem);

    this.tags = tags || elem.dataset.tags.split(',').map(t => t.trim());
    this.titleElem = elem.getElementsByTagName('h1')[0];

    this.parallax = new Parallax3D(this.elem);

    // Title manipulation interface

    const _this2 = this;
    /**
     * Interface for updating styles on the title.
     * Examples:
     *   this.title.translate = '-10px'
     *   this.title.opacity = 0.5
     */
    this.title = {
      _apply() {
        _this2.titleElem.style.transform = `translateZ(25px) translateX(${this._translate})`;
        _this2.titleElem.style.opacity = this._opacity;
      },
      get translate() { return this._translate; },
      set translate(t) { this._translate = t; this._apply(); },
      get opacity() { return this._opacity; },
      set opacity(o) { this._opacity = o; this._apply(); },
    };
  }

  /**
   * Update the card wrapper's CSS in order to reflect changes that were made to its JS
   * representation.
   */
  _applyTransform() {
    this.wrapper.style.transform = [
      'translate(-50%, -50%)',
      `translateX(${this._translate})`,
    ].join(' ');
  }

  // Translation

  get translate() { return this._translate; }
  set translate(val) { this._translate = val; this._applyTransform(); }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.titleElem.style.transition = `transform ${secs}s, opacity ${secs}s`;
  }
}

/** Collects and orchestrates multiple CarouselCards */
export class Carousel {
  constructor(cards) {
    this.cards = cards;
    this._position = 0;
  }

  get position() { return this._position; }
  set position(pos) {
    // Move
    this._position = pos;
  }
}
<commit_msg>Set default transitionTime<commit_after>/** Represents a single project in the work carousel */
import Parallax3D from '../parallax';

export class CarouselCard {
  constructor(elem, tags) {
    this.elem = elem;
    this.elem.classList.add('carousel-card');
    // Move elem into a wrapper div
    this.wrapper = document.createElement('div');
    this.wrapper.className = 'carousel-card-wrapper';
    this.elem.parentNode.insertBefore(this.wrapper, this.elem);
    this.wrapper.appendChild(this.elem);

    this.tags = tags || elem.dataset.tags.split(',').map(t => t.trim());
    this.titleElem = elem.getElementsByTagName('h1')[0];

    this.transitionTime = this.baseTransitionTime = 0.3;
    this.parallax = new Parallax3D(this.elem);

    // Title manipulation interface

    const _this2 = this;
    /**
     * Interface for updating styles on the title.
     * Examples:
     *   this.title.translate = '-10px'
     *   this.title.opacity = 0.5
     */
    this.title = {
      _apply() {
        _this2.titleElem.style.transform = `translateZ(25px) translateX(${this._translate})`;
        _this2.titleElem.style.opacity = this._opacity;
      },
      get translate() { return this._translate; },
      set translate(t) { this._translate = t; this._apply(); },
      get opacity() { return this._opacity; },
      set opacity(o) { this._opacity = o; this._apply(); },
    };
  }

  /**
   * Update the card wrapper's CSS in order to reflect changes that were made to its JS
   * representation.
   */
  _applyTransform() {
    this.wrapper.style.transform = [
      'translate(-50%, -50%)',
      `translateX(${this._translate})`,
    ].join(' ');
  }

  // Translation

  get translate() { return this._translate; }
  set translate(val) { this._translate = val; this._applyTransform(); }

  // Transition time

  get transitionTime() { return this._transitionTime; }
  set transitionTime(secs) {
    this._transitionTime = secs;
    this.wrapper.style.transition = `transform ${secs}s`;
    this.titleElem.style.transition = `transform ${secs}s, opacity ${secs}s`;
  }
}

/** Collects and orchestrates multiple CarouselCards */
export class Carousel {
  constructor(cards) {
    this.cards = cards;
    this._position = 0;
  }

  get position() { return this._position; }
  set position(pos) {
    // Move
    this._position = pos;
  }
}
<|endoftext|>


<commit_before>import {
  SEARCH_PENDING,
  SEARCH_SUCCESS,
  SEARCH_RESET,
  SEARCH_FAILURE
} from "./actionTypes";
import { GraphQLClient } from "../core";
import { queries } from "./graphql";

const search = terms => {
  return (dispatch, getStore) => {
    dispatch({
      type: SEARCH_PENDING
    });

    const searchRegEx = new RegExp(`${terms}`, "i");
    const { movies } = getStore();

    const matches = movies.items.filter(movie => searchRegEx.test(movie.title));
    const ids = matches.map(movie => movie.id);

    GraphQLClient.query({
      query: queries.SEARCH,
      variables: {
        terms
      }
    })
      .then(response => {
        const {
          data: { search: results }
        } = response;

        dispatch({
          type: SEARCH_SUCCESS,
          payload: {
            matches: results.filter(result => !ids.includes(result.id))
          }
        });
      })
      .catch(error => {
        dispatch({
          type: SEARCH_FAILURE,
          payload: {
            error
          }
        });
      });
  };
};

const reset = () => {
  return dispatch => {
    dispatch({
      type: SEARCH_RESET
    });
  };
};

export { search, reset };
<commit_msg>process search exclusively on client side<commit_after>import { SEARCH_SUCCESS, SEARCH_RESET } from "./actionTypes";

const search = terms => {
  return (dispatch, getStore) => {
    const searchRegEx = new RegExp(`${terms}`, "i");
    const { movies } = getStore();

    const matches = movies.items.filter(movie => searchRegEx.test(movie.title));

    dispatch({
      type: SEARCH_SUCCESS,
      payload: {
        matches
      }
    });
  };
};

const reset = () => {
  return dispatch => {
    dispatch({
      type: SEARCH_RESET
    });
  };
};

export { search, reset };
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn;

module.exports = pdc;

// pdc(src, from, to[, opt], cb)
function pdc(src, from, to, opt, cb) {
  if (typeof cb == 'undefined')
    cb = opt;

  var args = [ '-f', from, '-t', to ];

  if (typeof opt == 'object')
    args = args.concat(opt);

  var pandoc = spawn('pandoc', args);

  var result = '';
  var error = '';

  pandoc.stdout.on('data', function (data) {
    result += data;
  });
  pandoc.stderr.on('data', function (data) {
    error += data;
  });

  pandoc.on('exit', function (code) {
    var msg = '';
    if (code !== 0)
      msg += 'pandoc exited with code '+code+(error ? ': ' : '.');
    if (error)
      msg += error;

    if (msg)
      return cb(new Error(msg));

    cb(null, result);
  });

  pandoc.stdin.end(src, 'utf8');
}
<commit_msg>Added pdc.path to change path to pandoc runner<commit_after>var spawn = require('child_process').spawn;

module.exports = pdc;

// pdc(src, from, to[, opt], cb)
function pdc(src, from, to, opt, cb) {
  if (typeof cb == 'undefined')
    cb = opt;

  var args = [ '-f', from, '-t', to ];

  if (typeof opt == 'object')
    args = args.concat(opt);

  var pandoc = spawn(pdc.path, args);

  var result = '';
  var error = '';

  pandoc.stdout.on('data', function (data) {
    result += data;
  });
  pandoc.stderr.on('data', function (data) {
    error += data;
  });

  pandoc.on('exit', function (code) {
    var msg = '';
    if (code !== 0)
      msg += 'pandoc exited with code '+code+(error ? ': ' : '.');
    if (error)
      msg += error;

    if (msg)
      return cb(new Error(msg));

    cb(null, result);
  });

  pandoc.stdin.end(src, 'utf8');
}

// Path to pandoc runner in your system
pdc.path = 'pandoc';
<|endoftext|>


<commit_before>import Ember from 'ember';
import { initialize } from '../../../initializers/tour';
import { module, test } from 'qunit';

var container, application;

module('TourInitializer', {
  beforeEach: function() {
    Ember.run(function() {
      application = Ember.Application.create();
      container = application.__container__;
      application.deferReadiness();
    });
  }
});

// Replace this with your real tests.
test('it works', function(assert) {
  initialize(container, application);

  // you would normally confirm the results of the initializer here
  assert.ok(true);
});
<commit_msg>Add test for initializer<commit_after>import Ember from 'ember';
// See comment below about Ember CLI bug
// This should be fixed with the next CLI release
import initializer from '../../../initializers/tour';
import { module, test } from 'qunit';

var container, application, mockTourService, mockApplicationController;

module('TourInitializer', {
  beforeEach: function() {
    Ember.run(function() {
      application = Ember.Application.create();
      container = application.__container__;
      application.deferReadiness();

      mockTourService = Ember.Object.create({});
      mockApplicationController = Ember.Object.create({});

      application.register('service:tour', mockTourService, {instantiate: false});
      application.register('controller:application', mockApplicationController, {instantiate: false});
    });
  }
});

// Replace this with your real tests.
test('it injects the application controller into the tour service', function(assert) {
  // NOTE: this is needed due to a bug in the Ember CLI testing of
  // addon-provided initializers.  See link for more details
  // https://github.com/ember-cli/ember-cli/pull/3891
  initializer.initialize(container, application);
  assert.equal(mockTourService.get('_applicationController'), mockApplicationController, 'Initializer injects the application controller');
});
<|endoftext|>


<commit_before>/**
 * Game Controller
 */
function GameController(io)
{
    this.io    = io;
    this.games = new Collection([], 'name');

    this.onDie         = this.onDie.bind(this);
    this.onAngle       = this.onAngle.bind(this);
    this.onPosition    = this.onPosition.bind(this);
    this.onPrinting    = this.onPrinting.bind(this);
    this.onPoint       = this.onPoint.bind(this);
    this.onScore       = this.onScore.bind(this);
    this.onTrailClear  = this.onTrailClear.bind(this);
    this.onRoundNew    = this.onRoundNew.bind(this);
    this.onRoundEnd    = this.onRoundEnd.bind(this);
    this.onRoundWinner = this.onRoundWinner.bind(this);
}

/**
 * Add game
 *
 * @param {Game} game
 */
GameController.prototype.addGame = function(game)
{
    if (this.games.add(game)) {
        game.on('round:new', this.onRoundNew);
        game.on('round:end', this.onRoundEnd);
        game.on('round:winner', this.onRoundWinner);

        game.on('bonus:pop', this.onBonusPop);
        game.on('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.attach(game.clients.items[i], game);
        }
    }
};

/**
 * Remove game
 *
 * @param {Game} game
 */
GameController.prototype.removeGame = function(game)
{
    if (this.games.remove(game)) {
        game.removeListener('round:new', this.onRoundNew);
        game.removeListener('round:end', this.onRoundEnd);
        game.removeListener('round:winner', this.onRoundWinner);
        game.removeListener('bonus:pop', this.onBonusPop);
        game.removeListener('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.detach(game.clients.items[i], game);
        }
    }
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attach = function(client, game)
{
    this.attachEvents(client);
    client.joinChannel('game:' + game.name);
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detach = function(client)
{
    this.detachEvents(client);

    var avatar;

    if (client.room.game) {
        for (var i = client.players.items.length - 1; i >= 0; i--) {
            avatar = client.players.items[i].avatar;
            this.io.sockets.in(client.room.game.channel).emit('game:leave', {avatar: avatar.name});
            client.room.game.removeAvatar(avatar);
        }
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attachEvents = function(client)
{
    var controller = this,
        avatar;

    client.socket.on('loaded', function () { controller.onGameLoaded(client); });
    client.socket.on('player:move', function (data) { controller.onMove(client, data); });

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.on('die', this.onDie);
        avatar.on('angle', this.onAngle);
        avatar.on('position', this.onPosition);
        avatar.on('printing', this.onPrinting);
        avatar.on('point', this.onPoint);
        avatar.on('score', this.onScore);
        avatar.trail.on('clear', this.onTrailClear);
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detachEvents = function(client)
{
    var avatar;

    client.socket.removeAllListeners('loaded');
    client.socket.removeAllListeners('channel');
    client.socket.removeAllListeners('player:move');

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.removeAllListeners('die');
        avatar.removeAllListeners('position');
        avatar.removeAllListeners('printing');
        avatar.removeAllListeners('point');
        avatar.removeAllListeners('score');
        avatar.trail.removeAllListeners('clear');
    }
};

/**
 * On game loaded
 *
 * @param {SocketClient} client
 */
GameController.prototype.onGameLoaded = function(client)
{
    var game = client.room.game,
        avatar;

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;
        avatar.ready = true;
    }

    if (game.isReady()) {
        game.newRound();
    }
};

/**
 * On move
 *
 * @param {SocketClient} client
 * @param {Number} move
 */
GameController.prototype.onMove = function(client, data)
{
    var player = client.players.getById(data.avatar);

    if (player && player.avatar) {
        player.avatar.setAngularVelocity(data.move);
    }
};

/**
 * On position
 *
 * @param {Object} data
 */
GameController.prototype.onPosition = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        point = data.point;

    this.io.sockets.in(channel).emit('position', {avatar: avatar.name, point: point});
};

/**
 * On printing
 *
 * @param {Object} data
 */
GameController.prototype.onPrinting = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        printing = data.printing;

    this.io.sockets.in(channel).emit('printing', {avatar: avatar.name, printing: printing});
};

/**
 * On angle
 *
 * @param {Object} data
 */
GameController.prototype.onAngle = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        angle = data.angle;

    if(!avatar.player.client.room.game.isPlaying()) {
        this.io.sockets.in(channel).emit('angle', {avatar: avatar.name, angle: angle});
    }
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onPoint = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        point = data.point;

    if (data.important) {
        this.io.sockets.in(channel).emit('point', {avatar: avatar.name, point: point});
    }
};

/**
 * On die
 *
 * @param {Object} data
 */
GameController.prototype.onDie = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    this.io.sockets.in(channel).emit('die', {avatar: avatar.name});
};

/**
 * On bonus pop
 *
 * @param {SocketClient} game
 */
GameController.prototype.onBonusPop = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    this.io.sockets.in(channel).emit('bonus:pop', data.bonus);
};

/**
 * On bonus clear
 *
 * @param {SocketClient}client
 * @param data
 */
GameController.prototype.onBonusClear = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    this.io.sockets.in(channel).emit('bonus:clear', data.bonus);
};

/**
 * On score
 *
 * @param {Object} data
 */
GameController.prototype.onScore = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        score = data.score;

    this.io.sockets.in(channel).emit('score', {avatar: avatar.name, score: score});
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onTrailClear = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    this.io.sockets.in(channel).emit('trail:clear', {avatar: avatar.name});
};

// Game events:

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundNew = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:new');
};

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundEnd = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:end');
};

/**
 * On round winner
 *
 * @param {Object} data
 */
GameController.prototype.onRoundWinner = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:winner', {winner: data.winner.name});
};
<commit_msg>fix methods binding for bonus and velocity changes<commit_after>/**
 * Game Controller
 */
function GameController(io)
{
    this.io    = io;
    this.games = new Collection([], 'name');

    this.onDie         = this.onDie.bind(this);
    this.onAngle       = this.onAngle.bind(this);
    this.onPosition    = this.onPosition.bind(this);
    this.onPrinting    = this.onPrinting.bind(this);
    this.onPoint       = this.onPoint.bind(this);
    this.onScore       = this.onScore.bind(this);
    this.onTrailClear  = this.onTrailClear.bind(this);
    this.onRoundNew    = this.onRoundNew.bind(this);
    this.onRoundEnd    = this.onRoundEnd.bind(this);
    this.onRoundWinner = this.onRoundWinner.bind(this);
    this.onBonusPop    = this.onBonusPop.bind(this);
    this.onBonusClear  = this.onBonusClear.bind(this);
}

/**
 * Add game
 *
 * @param {Game} game
 */
GameController.prototype.addGame = function(game)
{
    if (this.games.add(game)) {
        game.on('round:new', this.onRoundNew);
        game.on('round:end', this.onRoundEnd);
        game.on('round:winner', this.onRoundWinner);

        game.on('bonus:pop', this.onBonusPop);
        game.on('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.attach(game.clients.items[i], game);
        }
    }
};

/**
 * Remove game
 *
 * @param {Game} game
 */
GameController.prototype.removeGame = function(game)
{
    if (this.games.remove(game)) {
        game.removeListener('round:new', this.onRoundNew);
        game.removeListener('round:end', this.onRoundEnd);
        game.removeListener('round:winner', this.onRoundWinner);
        game.removeListener('bonus:pop', this.onBonusPop);
        game.removeListener('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.detach(game.clients.items[i], game);
        }
    }
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attach = function(client, game)
{
    this.attachEvents(client);
    client.joinChannel('game:' + game.name);
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detach = function(client)
{
    this.detachEvents(client);

    var avatar;

    if (client.room.game) {
        for (var i = client.players.items.length - 1; i >= 0; i--) {
            avatar = client.players.items[i].avatar;
            this.io.sockets.in(client.room.game.channel).emit('game:leave', {avatar: avatar.name});
            client.room.game.removeAvatar(avatar);
        }
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attachEvents = function(client)
{
    var controller = this,
        avatar;

    client.socket.on('loaded', function () { controller.onGameLoaded(client); });
    client.socket.on('player:move', function (data) { controller.onMove(client, data); });

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.on('die', this.onDie);
        avatar.on('angle', this.onAngle);
        avatar.on('position', this.onPosition);
        avatar.on('printing', this.onPrinting);
        avatar.on('point', this.onPoint);
        avatar.on('score', this.onScore);
        avatar.trail.on('clear', this.onTrailClear);
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detachEvents = function(client)
{
    var avatar;

    client.socket.removeAllListeners('loaded');
    client.socket.removeAllListeners('channel');
    client.socket.removeAllListeners('player:move');

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.removeAllListeners('die');
        avatar.removeAllListeners('position');
        avatar.removeAllListeners('printing');
        avatar.removeAllListeners('point');
        avatar.removeAllListeners('score');
        avatar.trail.removeAllListeners('clear');
    }
};

/**
 * On game loaded
 *
 * @param {SocketClient} client
 */
GameController.prototype.onGameLoaded = function(client)
{
    var game = client.room.game,
        avatar;

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;
        avatar.ready = true;
    }

    if (game.isReady()) {
        game.newRound();
    }
};

/**
 * On move
 *
 * @param {SocketClient} client
 * @param {Number} move
 */
GameController.prototype.onMove = function(client, data)
{
    var player = client.players.getById(data.avatar);

    if (player && player.avatar) {
        player.avatar.setAngularVelocity(data.move);
    }
};

/**
 * On position
 *
 * @param {Object} data
 */
GameController.prototype.onPosition = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        point = data.point;

    this.io.sockets.in(channel).emit('position', {avatar: avatar.name, point: point});
};

/**
 * On printing
 *
 * @param {Object} data
 */
GameController.prototype.onPrinting = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        printing = data.printing;

    this.io.sockets.in(channel).emit('printing', {avatar: avatar.name, printing: printing});
};

/**
 * On angle
 *
 * @param {Object} data
 */
GameController.prototype.onAngle = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        angle = data.angle;

    if(!avatar.player.client.room.game.isPlaying()) {
        this.io.sockets.in(channel).emit('angle', {avatar: avatar.name, angle: angle});
    }
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onPoint = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        point = data.point;

    if (data.important) {
        this.io.sockets.in(channel).emit('point', {avatar: avatar.name, point: point});
    }
};

/**
 * On die
 *
 * @param {Object} data
 */
GameController.prototype.onDie = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    this.io.sockets.in(channel).emit('die', {avatar: avatar.name});
};

/**
 * On bonus pop
 *
 * @param {SocketClient} game
 */
GameController.prototype.onBonusPop = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    this.io.sockets.in(channel).emit('bonus:pop', data.bonus);
};

/**
 * On bonus clear
 *
 * @param {SocketClient}client
 * @param data
 */
GameController.prototype.onBonusClear = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    this.io.sockets.in(channel).emit('bonus:clear', data.bonus);
};

/**
 * On score
 *
 * @param {Object} data
 */
GameController.prototype.onScore = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel,
        score = data.score;

    this.io.sockets.in(channel).emit('score', {avatar: avatar.name, score: score});
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onTrailClear = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    this.io.sockets.in(channel).emit('trail:clear', {avatar: avatar.name});
};

// Game events:

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundNew = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:new');
};

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundEnd = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:end');
};

/**
 * On round winner
 *
 * @param {Object} data
 */
GameController.prototype.onRoundWinner = function(data)
{
    this.io.sockets.in(data.game.channel).emit('round:winner', {winner: data.winner.name});
};
<|endoftext|>


<commit_before>'use strict';

//
// The MIT License (MIT)
//
// Copyright (c) 2016 Justin Unterreiner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// this code was adapted from
// https://github.com/Justin-Credible/cordova-plugin-braintree/blob/master/hooks/after_plugin_install.js
//
//
//  Copyright (C) Microsoft. All rights reserved. Licensed under the MIT
//  license. See LICENSE.txt file in the project root for full license
//  information.
//

var exec = require('child-process-promise').exec;
var fs = require('fs-extra-promise');
var path = require('path');
var Promise = require('lie');
var xcode = require('xcode');

function updateProjectBuildProperties(xcodeProject, buildWithTests) {
  console.log('Adding Build Properties');

  // Tell to Xcode project that we use Swift in our framework
  // I believe that this line of code will be removed in the future
  xcodeProject.removeBuildProperty(
    'EMBEDDED_CONTENT_CONTAINS_SWIFT');

  xcodeProject.removeBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES');
  xcodeProject.addBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES');

  xcodeProject.removeBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET');
  xcodeProject.addBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET', '10.0');

  xcodeProject.removeBuildProperty(
    'SWIFT_VERSION');
  xcodeProject.addBuildProperty(
    'SWIFT_VERSION', '3.0');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND');
  xcodeProject.addBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_TESTABILITY');
  xcodeProject.addBuildProperty(
    'ENABLE_TESTABILITY', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_NO_COMMON_BLOCKS');
  xcodeProject.addBuildProperty(
    'GCC_NO_COMMON_BLOCKS', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION');
  xcodeProject.addBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL');
  xcodeProject.addBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL', '-Owholemodule');

  if (buildWithTests) {
    xcodeProject.removeBuildProperty(
      'OTHER_SWIFT_FLAGS');
    xcodeProject.addBuildProperty('OTHER_SWIFT_FLAGS', '\"-DTEST\"');

    xcodeProject.removeBuildProperty('GCC_PREPROCESSOR_DEFINITIONS');
    xcodeProject.updateBuildProperty(
      'GCC_PREPROCESSOR_DEFINITIONS',
      ['\"$(inherited)\"', '\"TEST=1\"']);
  }
}

function updateProjectFrameworks(
  xcodeProject, frameworkOutputDir, buildWithTests) {
  // Project should not have more that one target.
  var targetUUID = xcodeProject.getFirstTarget().uuid;

  // First check to see if the Embed Framework node exists, if not, add
  // it. This is all we need to do as they are added to the embedded
  // section by default.
  if (!xcodeProject.pbxEmbedFrameworksBuildPhaseObj(targetUUID)) {
    var buildPhaseResult = xcodeProject.addBuildPhase(
      [],
      'PBXCopyFilesBuildPhase',
      'Embed Frameworks',
      targetUUID,
      'framework');
    // No idea why,
    // but "Framework" (value 10) is not available in node-xcode,
    // set it here manually so libraries
    // embed correctly.
    // If we don't set it, the folder type defaults to "Shared
    // Frameworks".
    buildPhaseResult.buildPhase.dstSubfolderSpec = 10;
    console.log('Adding Embedded Build Phase');
  } else {
    console.log('Embedded Build Phase already added');
  }

  // This is critical to include,
  // otherwise the library loader cannot find libs at runtime
  // on a device.
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Debug');
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Release');

  // Add the frameworks again.
  // This time they will have the code-sign option set
  // so they get code signed when being deployed to devices.
  console.log('Adding ThaliCore.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'ThaliCore.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'SwiftXCTest.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'CocoaAsyncSocket.framework'),
    {customFramework: true, embed: true, link: true, sign: true});
}

function updateProjectTestingInfrastructure(
  xcodeProject, testingInfrastructureDir, buildWithTests) {
  if (buildWithTests) {
    var testingFiles =
      fs.readdirSync(testingInfrastructureDir)
        .filter(function (file) {
          return file.endsWith('.swift');
        })
        .map(function (file) {
          return path.join(testingInfrastructureDir, file);
        });

    testingFiles
      .forEach(function (file) {
        xcodeProject.addSourceFile(file);
      });
  }
}

function addFramework(
  projectPath, frameworkProjectDir, frameworkOutputDir,
  buildWithTests, testingInfrastructureDir) {

  checkoutThaliCoreViaCarthage(
    frameworkOutputDir, frameworkProjectDir, buildWithTests)
    .then(function () {
      console.log('Checkouting done!');

      var checkoutDir = path.join(frameworkOutputDir, 'Carthage', 'Checkouts');
      var buildDir = path.join(checkoutDir, 'thali-ios', 'Carthage', 'Build');

      console.log('Building CocoaAsyncSocket.framework');
      return biuldCocoaAsyncSocket(checkoutDir, buildDir, buildWithTests)
    })
    .then (function () {
      console.log('Building CocoaAsyncSocket.framework has been finished');

      var checkoutDir = path.join(frameworkOutputDir, 'Carthage', 'Checkouts');
      var buildDir = path.join(checkoutDir, 'thali-ios', 'Carthage', 'Build');

      return biuldSwiftXCTest(checkoutDir, buildDir, buildWithTests)
    })
    .then (function () {
      // We need to build ThaliCore.framework before embedding it into the project
      return buildFramework(
        frameworkProjectDir, frameworkOutputDir, buildWithTests)
        .then(function () {
          var pbxProjectPath = path.join(projectPath, 'project.pbxproj');
          var xcodeProject = xcode.project(pbxProjectPath);

          return new Promise(function (resolve, reject) {

            xcodeProject.parse(function (error) {

              // If we couldn't parse the project, bail out.
              if (error) {
                var message =
                  'Cannot parse Xcode project: ' + JSON.stringify(error);
                reject(new Error(message));
                return;
              }

              updateProjectBuildProperties(xcodeProject, buildWithTests);

              updateProjectFrameworks(
                xcodeProject, frameworkOutputDir, buildWithTests);

              updateProjectTestingInfrastructure(
                xcodeProject, testingInfrastructureDir, buildWithTests);

              resolve(xcodeProject);
            });
          })
          .then(function (xcodeProject) {
            // Save the project file back to disk.
            return fs.writeFileAsync(
              pbxProjectPath, xcodeProject.writeSync(), 'utf-8');
          });
        });
    })
};

function checkoutThaliCoreViaCarthage(cartfileDir, outputDir, buildWithTests) {
  var changeDirCmd = 'cd ' + cartfileDir;
  var carthageCmd = 'carthage checkout';
  var checkoutCmd = changeDirCmd + ' && ' + carthageCmd;

  console.log('Checkouting ThaliCore-iOS and its dependencies');

  return exec(checkoutCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(outputDir);
    })
}

function biuldCocoaAsyncSocket(checkoutDir, buildDir, buildWithTests) {
  var projectDir = 'CocoaAsyncSocket';
  var projectName = 'CocoaAsyncSocket';
  var projectScheme = 'iOS Framework';

  var projectConfiguration = 'Release';

  if (buildWithTests) {
    console.log('Building in debug mode');
    projectConfiguration = 'Debug';
  }

  var sdk = 'iphoneos';
  var projectPath = path.join(checkoutDir, projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(buildDir, projectName);

  var changeDirCmd = 'cd ' + checkoutDir + '/' + projectName;
  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  var changeDirAndBuildCmd = changeDirCmd + ' && ' + buildCmd;

  return exec(changeDirAndBuildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(buildDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        buildDir, 'Release' + '-' + sdk, projectName + '.framework');

      return fs.copy(frameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var thaliCoreFrameworkOutputDir = path.join(
        checkoutDir, '..', '..', projectName + '.framework');

      return fs.copy(frameworkBuildDir, thaliCoreFrameworkOutputDir, { clobber: false });
    });
}

function biuldSwiftXCTest(checkoutDir, buildDir, buildWithTests) {
  var projectDir = 'swift-corelibs-xctest';
  var projectName = 'XCTest'
  var projectScheme = 'SwiftXCTest-iOS';
  var frameworkName = 'SwiftXCTest';

  var projectConfiguration = 'Release';
  var sdk = 'iphoneos';
  var projectPath = path.join(checkoutDir, projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(buildDir, projectName);

  var changeDirCmd = 'cd ' + checkoutDir + '/' + projectDir;
  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  var changeDirAndBuildCmd = changeDirCmd + ' && ' + buildCmd;

  return exec(changeDirAndBuildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(buildDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, frameworkName + '.framework');
      var thaliCoreFrameworkOutputDir = path.join(
        checkoutDir, '..', '..', frameworkName + '.framework');

      console.log('from: ', frameworkBuildDir);
      console.log('to : ', thaliCoreFrameworkOutputDir);

      return fs.copy(frameworkBuildDir, thaliCoreFrameworkOutputDir, { clobber: false });
    });
}

/**
 * @param {string} projectDir Xcode project directory
 * @param {string} outputDir Framework output directory
 * @param {boolean} buildWithTests
 * @returns {Promise} Output of exec
 */
function buildFramework(projectDir, outputDir, buildWithTests) {
  var projectName = 'ThaliCore';
  var projectScheme = 'ThaliCore';
  var projectConfiguration = 'Release';

  if (buildWithTests) {
    console.log('Building in debug mode');
    projectScheme = 'ThaliCoreCITests';
    projectConfiguration = 'Debug';
  }

  var sdk = 'iphoneos';
  var projectPath = path.join(projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(projectDir, 'build');

  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' IPHONEOS_DEPLOYMENT_TARGET=10.0' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  console.log('Building ThaliCore.framework');
  console.log('Build command:\n' + buildCmd);

  // todo: fixed buffer size should be fixed with streaming in #1001
  return exec(buildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      console.log('Building ThaliCore.framework has been finished');
      return fs.ensureDir(outputDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, projectName + '.framework');

      return fs.copy(frameworkBuildDir, frameworkOutputDir, { clobber: false });
    });
}

module.exports = {
  addFramework: addFramework
};
<commit_msg>Fixed some typos in nativeInstaller.js.<commit_after>'use strict';

//
// The MIT License (MIT)
//
// Copyright (c) 2016 Justin Unterreiner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// this code was adapted from
// https://github.com/Justin-Credible/cordova-plugin-braintree/blob/master/hooks/after_plugin_install.js
//
//
//  Copyright (C) Microsoft. All rights reserved. Licensed under the MIT
//  license. See LICENSE.txt file in the project root for full license
//  information.
//

var exec = require('child-process-promise').exec;
var fs = require('fs-extra-promise');
var path = require('path');
var Promise = require('lie');
var xcode = require('xcode');

function updateProjectBuildProperties(xcodeProject, buildWithTests) {
  console.log('Adding Build Properties');

  // Tell to Xcode project that we use Swift in our framework
  // I believe that this line of code will be removed in the future
  xcodeProject.removeBuildProperty(
    'EMBEDDED_CONTENT_CONTAINS_SWIFT');

  xcodeProject.removeBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES');
  xcodeProject.addBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES');

  xcodeProject.removeBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET');
  xcodeProject.addBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET', '10.0');

  xcodeProject.removeBuildProperty(
    'SWIFT_VERSION');
  xcodeProject.addBuildProperty(
    'SWIFT_VERSION', '3.0');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND');
  xcodeProject.addBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_TESTABILITY');
  xcodeProject.addBuildProperty(
    'ENABLE_TESTABILITY', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_NO_COMMON_BLOCKS');
  xcodeProject.addBuildProperty(
    'GCC_NO_COMMON_BLOCKS', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION');
  xcodeProject.addBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL');
  xcodeProject.addBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL', '-Owholemodule');

  if (buildWithTests) {
    xcodeProject.removeBuildProperty(
      'OTHER_SWIFT_FLAGS');
    xcodeProject.addBuildProperty('OTHER_SWIFT_FLAGS', '\"-DTEST\"');

    xcodeProject.removeBuildProperty('GCC_PREPROCESSOR_DEFINITIONS');
    xcodeProject.updateBuildProperty(
      'GCC_PREPROCESSOR_DEFINITIONS',
      ['\"$(inherited)\"', '\"TEST=1\"']);
  }
}

function updateProjectFrameworks(
  xcodeProject, frameworkOutputDir, buildWithTests) {
  // Project should not have more that one target.
  var targetUUID = xcodeProject.getFirstTarget().uuid;

  // First check to see if the Embed Framework node exists, if not, add
  // it. This is all we need to do as they are added to the embedded
  // section by default.
  if (!xcodeProject.pbxEmbedFrameworksBuildPhaseObj(targetUUID)) {
    var buildPhaseResult = xcodeProject.addBuildPhase(
      [],
      'PBXCopyFilesBuildPhase',
      'Embed Frameworks',
      targetUUID,
      'framework');
    // No idea why,
    // but "Framework" (value 10) is not available in node-xcode,
    // set it here manually so libraries
    // embed correctly.
    // If we don't set it, the folder type defaults to "Shared
    // Frameworks".
    buildPhaseResult.buildPhase.dstSubfolderSpec = 10;
    console.log('Adding Embedded Build Phase');
  } else {
    console.log('Embedded Build Phase already added');
  }

  // This is critical to include,
  // otherwise the library loader cannot find libs at runtime
  // on a device.
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Debug');
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Release');

  // Add the frameworks again.
  // This time they will have the code-sign option set
  // so they get code signed when being deployed to devices.
  console.log('Adding ThaliCore.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'ThaliCore.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'SwiftXCTest.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'CocoaAsyncSocket.framework'),
    {customFramework: true, embed: true, link: true, sign: true});
}

function updateProjectTestingInfrastructure(
  xcodeProject, testingInfrastructureDir, buildWithTests) {
  if (buildWithTests) {
    var testingFiles =
      fs.readdirSync(testingInfrastructureDir)
        .filter(function (file) {
          return file.endsWith('.swift');
        })
        .map(function (file) {
          return path.join(testingInfrastructureDir, file);
        });

    testingFiles
      .forEach(function (file) {
        xcodeProject.addSourceFile(file);
      });
  }
}

function addFramework(
  projectPath, frameworkProjectDir, frameworkOutputDir,
  buildWithTests, testingInfrastructureDir) {

  checkoutThaliCoreViaCarthage(
    frameworkOutputDir, frameworkProjectDir, buildWithTests)
    .then(function () {
      console.log('Checkouting done!');

      var checkoutDir = path.join(frameworkOutputDir, 'Carthage', 'Checkouts');
      var buildDir = path.join(checkoutDir, 'thali-ios', 'Carthage', 'Build');

      console.log('Building CocoaAsyncSocket.framework');
      return buildCocoaAsyncSocket(checkoutDir, buildDir, buildWithTests)
    })
    .then (function () {
      console.log('Building CocoaAsyncSocket.framework has been finished');

      var checkoutDir = path.join(frameworkOutputDir, 'Carthage', 'Checkouts');
      var buildDir = path.join(checkoutDir, 'thali-ios', 'Carthage', 'Build');

      return buildSwiftXCTest(checkoutDir, buildDir, buildWithTests)
    })
    .then (function () {
      // We need to build ThaliCore.framework before embedding it into the project
      return buildFramework(
        frameworkProjectDir, frameworkOutputDir, buildWithTests)
        .then(function () {
          var pbxProjectPath = path.join(projectPath, 'project.pbxproj');
          var xcodeProject = xcode.project(pbxProjectPath);

          return new Promise(function (resolve, reject) {

            xcodeProject.parse(function (error) {

              // If we couldn't parse the project, bail out.
              if (error) {
                var message =
                  'Cannot parse Xcode project: ' + JSON.stringify(error);
                reject(new Error(message));
                return;
              }

              updateProjectBuildProperties(xcodeProject, buildWithTests);

              updateProjectFrameworks(
                xcodeProject, frameworkOutputDir, buildWithTests);

              updateProjectTestingInfrastructure(
                xcodeProject, testingInfrastructureDir, buildWithTests);

              resolve(xcodeProject);
            });
          })
          .then(function (xcodeProject) {
            // Save the project file back to disk.
            return fs.writeFileAsync(
              pbxProjectPath, xcodeProject.writeSync(), 'utf-8');
          });
        });
    })
};

function checkoutThaliCoreViaCarthage(cartfileDir, outputDir, buildWithTests) {
  var changeDirCmd = 'cd ' + cartfileDir;
  var carthageCmd = 'carthage checkout';
  var checkoutCmd = changeDirCmd + ' && ' + carthageCmd;

  console.log('Checkouting ThaliCore-iOS and its dependencies');

  return exec(checkoutCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(outputDir);
    })
}

function buildCocoaAsyncSocket(checkoutDir, buildDir, buildWithTests) {
  var projectDir = 'CocoaAsyncSocket';
  var projectName = 'CocoaAsyncSocket';
  var projectScheme = 'iOS Framework';

  var projectConfiguration = 'Release';

  if (buildWithTests) {
    console.log('Building in debug mode');
    projectConfiguration = 'Debug';
  }

  var sdk = 'iphoneos';
  var projectPath = path.join(checkoutDir, projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(buildDir, projectName);

  var changeDirCmd = 'cd ' + checkoutDir + '/' + projectName;
  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  var changeDirAndBuildCmd = changeDirCmd + ' && ' + buildCmd;

  return exec(changeDirAndBuildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(buildDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        buildDir, 'Release' + '-' + sdk, projectName + '.framework');

      return fs.copy(frameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var thaliCoreFrameworkOutputDir = path.join(
        checkoutDir, '..', '..', projectName + '.framework');

      return fs.copy(frameworkBuildDir, thaliCoreFrameworkOutputDir, { clobber: false });
    });
}

function buildSwiftXCTest(checkoutDir, buildDir, buildWithTests) {
  var projectDir = 'swift-corelibs-xctest';
  var projectName = 'XCTest'
  var projectScheme = 'SwiftXCTest-iOS';
  var frameworkName = 'SwiftXCTest';

  var projectConfiguration = 'Release';
  var sdk = 'iphoneos';
  var projectPath = path.join(checkoutDir, projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(buildDir, projectName);

  var changeDirCmd = 'cd ' + checkoutDir + '/' + projectDir;
  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  var changeDirAndBuildCmd = changeDirCmd + ' && ' + buildCmd;

  return exec(changeDirAndBuildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(buildDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, frameworkName + '.framework');
      var thaliCoreFrameworkOutputDir = path.join(
        checkoutDir, '..', '..', frameworkName + '.framework');

      console.log('from: ', frameworkBuildDir);
      console.log('to : ', thaliCoreFrameworkOutputDir);

      return fs.copy(frameworkBuildDir, thaliCoreFrameworkOutputDir, { clobber: false });
    });
}

/**
 * @param {string} projectDir Xcode project directory
 * @param {string} outputDir Framework output directory
 * @param {boolean} buildWithTests
 * @returns {Promise} Output of exec
 */
function buildFramework(projectDir, outputDir, buildWithTests) {
  var projectName = 'ThaliCore';
  var projectScheme = 'ThaliCore';
  var projectConfiguration = 'Release';

  if (buildWithTests) {
    console.log('Building in debug mode');
    projectScheme = 'ThaliCoreCITests';
    projectConfiguration = 'Debug';
  }

  var sdk = 'iphoneos';
  var projectPath = path.join(projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(projectDir, 'build');

  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' IPHONEOS_DEPLOYMENT_TARGET=10.0' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  console.log('Building ThaliCore.framework');
  console.log('Build command:\n' + buildCmd);

  // todo: fixed buffer size should be fixed with streaming in #1001
  return exec(buildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      console.log('Building ThaliCore.framework has been finished');
      return fs.ensureDir(outputDir);
    })
    .then(function () {
      var frameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, projectName + '.framework');

      return fs.copy(frameworkBuildDir, frameworkOutputDir, { clobber: false });
    });
}

module.exports = {
  addFramework: addFramework
};
<|endoftext|>


<commit_before>'use strict';

//
// The MIT License (MIT)
//
// Copyright (c) 2016 Justin Unterreiner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// this code was adapted from
// https://github.com/Justin-Credible/cordova-plugin-braintree/blob/master/hooks/after_plugin_install.js
//
//
//  Copyright (C) Microsoft. All rights reserved. Licensed under the MIT
//  license. See LICENSE.txt file in the project root for full license
//  information.
//

var exec = require('child-process-promise').exec;
var fs = require('fs-extra-promise');
var path = require('path');
var Promise = require('lie');
var xcode = require('xcode');

function updateProjectBuildProperties(xcodeProject, buildWithTests) {
  console.log('Adding Build Properties');

  // Tell to Xcode project that we use Swift in our framework
  // I believe that this line of code will be removed in the future
  xcodeProject.removeBuildProperty(
    'EMBEDDED_CONTENT_CONTAINS_SWIFT');

  xcodeProject.removeBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES');
  xcodeProject.addBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES');

  xcodeProject.removeBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET');
  xcodeProject.addBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET', '10.0');

  xcodeProject.removeBuildProperty(
    'SWIFT_VERSION');
  xcodeProject.addBuildProperty(
    'SWIFT_VERSION', '3.0');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND');
  xcodeProject.addBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_TESTABILITY');
  xcodeProject.addBuildProperty(
    'ENABLE_TESTABILITY', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_NO_COMMON_BLOCKS');
  xcodeProject.addBuildProperty(
    'GCC_NO_COMMON_BLOCKS', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION');
  xcodeProject.addBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL');
  xcodeProject.addBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL', '-Owholemodule');

  if (buildWithTests) {
    xcodeProject.removeBuildProperty(
      'OTHER_SWIFT_FLAGS');
    xcodeProject.addBuildProperty('OTHER_SWIFT_FLAGS', '\"-DTEST\"');

    xcodeProject.removeBuildProperty('GCC_PREPROCESSOR_DEFINITIONS');
    xcodeProject.updateBuildProperty(
      'GCC_PREPROCESSOR_DEFINITIONS',
      ['\"$(inherited)\"', '\"TEST=1\"']);
  }
}

function updateProjectFrameworks(
  xcodeProject, frameworkOutputDir, buildWithTests) {
  // Project should not have more that one target.
  var targetUUID = xcodeProject.getFirstTarget().uuid;

  // First check to see if the Embed Framework node exists, if not, add
  // it. This is all we need to do as they are added to the embedded
  // section by default.
  if (!xcodeProject.pbxEmbedFrameworksBuildPhaseObj(targetUUID)) {
    var buildPhaseResult = xcodeProject.addBuildPhase(
      [],
      'PBXCopyFilesBuildPhase',
      'Embed Frameworks',
      targetUUID,
      'framework');
    // No idea why,
    // but "Framework" (value 10) is not available in node-xcode,
    // set it here manually so libraries
    // embed correctly.
    // If we don't set it, the folder type defaults to "Shared
    // Frameworks".
    buildPhaseResult.buildPhase.dstSubfolderSpec = 10;
    console.log('Adding Embedded Build Phase');
  } else {
    console.log('Embedded Build Phase already added');
  }

  // This is critical to include,
  // otherwise the library loader cannot find libs at runtime
  // on a device.
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Debug');
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Release');

  // Add the frameworks again.
  // This time they will have the code-sign option set
  // so they get code signed when being deployed to devices.
  console.log('Adding ThaliCore.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'ThaliCore.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  console.log('Adding CocoaAsyncSocket.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'CocoaAsyncSocket.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  if (buildWithTests) {
    console.log('Adding SwiftXCTest.framework');
    xcodeProject.addFramework(
      path.join(frameworkOutputDir, 'SwiftXCTest.framework'),
      {customFramework: true, embed: true, link: true, sign: true});
  }
}

function updateProjectTestingInfrastructure(
  xcodeProject, testingInfrastructureDir, buildWithTests) {
  if (buildWithTests) {
    var testingFiles =
      fs.readdirSync(testingInfrastructureDir)
        .filter(function (file) {
          return file.endsWith('.swift');
        })
        .map(function (file) {
          return path.join(testingInfrastructureDir, file);
        });

    testingFiles
      .forEach(function (file) {
        xcodeProject.addSourceFile(file);
      });
  }
}

function addFramework(
  projectPath, frameworkProjectDir, frameworkOutputDir,
  buildWithTests, testingInfrastructureDir) {

  checkoutThaliCoreViaCarthage(
    frameworkOutputDir, frameworkProjectDir, buildWithTests)
    .then (function () {
      console.log('Checkouting is successfully done.\n' +
                  'Results were put into ' + frameworkProjectDir);

      // We need to build ThaliCore.framework before embedding it into the project
      return buildFramework(
        frameworkProjectDir, frameworkOutputDir, buildWithTests)
        .then(function () {
          console.log('Building framework is done.');
          console.log('frameworkProjectDir: ' + frameworkProjectDir);
          console.log('frameworkOutputDir: ' + frameworkOutputDir);
          console.log('buildWithTests: ' + buildWithTests);

          var pbxProjectPath = path.join(projectPath, 'project.pbxproj');
          var xcodeProject = xcode.project(pbxProjectPath);

          return new Promise(function (resolve, reject) {

            xcodeProject.parse(function (error) {

              // If we couldn't parse the project, bail out.
              if (error) {
                var message =
                  'Cannot parse Xcode project: ' + JSON.stringify(error);
                reject(new Error(message));
                return;
              }

              updateProjectBuildProperties(xcodeProject, buildWithTests);

              updateProjectFrameworks(
                xcodeProject, frameworkOutputDir, buildWithTests);

              updateProjectTestingInfrastructure(
                xcodeProject, testingInfrastructureDir, buildWithTests);

              resolve(xcodeProject);
            });
          })
          .then(function (xcodeProject) {
            // Save the project file back to disk.
            return fs.writeFileAsync(
              pbxProjectPath, xcodeProject.writeSync(), 'utf-8');
          });
        });
    })
};

function checkoutThaliCoreViaCarthage(cartfileDir, outputDir, buildWithTests) {
  var cdToCartfileDirCmd = 'cd ' + cartfileDir;
  var removeCarthageDirCmd = 'rm -rf Carthage/';
  var carthageCmd = 'carthage update --no-build';
  var checkoutCmd = cdToCartfileDirCmd + ' && ' +
                    removeCarthageDirCmd + ' && ' +
                    carthageCmd;

  console.log('Checkouting ThaliCore and its dependencies via carthage.\n' +
              'Cartfile in: ' + cartfileDir + '\n' +
              'Results will be put into ' + outputDir);

  return exec(checkoutCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(outputDir);
    })
}

/**
 * @param {string} projectDir Xcode project directory
 * @param {string} outputDir Framework output directory
 * @param {boolean} buildWithTests
 * @returns {Promise} Output of exec
 */
function buildFramework(projectDir, outputDir, buildWithTests) {

  var cocoaAsyncSocketFrameworkName = 'CocoaAsyncSocket';
  var XCTestFrameworkName = 'SwiftXCTest';

  var projectName = 'ThaliCore';
  var projectScheme = 'ThaliCore';
  var projectConfiguration = 'Release';

  if (buildWithTests) {
    projectScheme = 'ThaliCoreCITests';
    projectConfiguration = 'Debug';
  }

  console.log('Building ' + projectName + ' in ' + projectConfiguration + ' mode\n' +
              'Xcode project dir: ' + projectDir + '\n' +
              'Framework output dir: ' + outputDir);

  var sdk = 'iphoneos';
  var projectPath = path.join(projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(projectDir, 'build');

  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' IPHONEOS_DEPLOYMENT_TARGET=10.0' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  console.log('Building ' + projectName + ' framework');
  console.log('Build command:\n' + buildCmd);

  // todo: fixed buffer size should be fixed with streaming in #1001
  return exec(buildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      console.log('Building ThaliCore.framework has been finished');
      return fs.ensureDir(outputDir);
    })
    .then(function () {
      var thaliCoreFrameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, projectName + '.framework');

      console.log('Copying:\n' +
                  'from: ' + thaliCoreFrameworkBuildDir + '\n' +
                  'to:   ' + frameworkOutputDir);

      return fs.copy(thaliCoreFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      var cocoaAsyncSocketFrameworkBuildDir = path.join(
        projectDir, 'build', projectConfiguration + '-' + sdk,
        cocoaAsyncSocketFrameworkName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, cocoaAsyncSocketFrameworkName + '.framework');

        console.log('Copying:\n' +
                    'from: ' + cocoaAsyncSocketFrameworkBuildDir + '\n' +
                    'to:   ' + frameworkOutputDir);

      return fs.copy(cocoaAsyncSocketFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      if (!buildWithTests) {
        // Don't cope SwiftXCTest framework
        // if the plugin was built without tests (release mode).
        return new Promise(function (resolve) {
          resolve();
        })
      }

      var swiftXCTestFrameworkBuildDir = path.join(
        projectDir, 'build', projectConfiguration + '-' + sdk,
        XCTestFrameworkName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, XCTestFrameworkName + '.framework');

        console.log('Copying:\n' +
                    'from: ' + swiftXCTestFrameworkBuildDir + '\n' +
                    'to:   ' + frameworkOutputDir);

      return fs.copy(swiftXCTestFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    });
}

module.exports = {
  addFramework: addFramework
};
<commit_msg>Fix typo in the comment.<commit_after>'use strict';

//
// The MIT License (MIT)
//
// Copyright (c) 2016 Justin Unterreiner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// this code was adapted from
// https://github.com/Justin-Credible/cordova-plugin-braintree/blob/master/hooks/after_plugin_install.js
//
//
//  Copyright (C) Microsoft. All rights reserved. Licensed under the MIT
//  license. See LICENSE.txt file in the project root for full license
//  information.
//

var exec = require('child-process-promise').exec;
var fs = require('fs-extra-promise');
var path = require('path');
var Promise = require('lie');
var xcode = require('xcode');

function updateProjectBuildProperties(xcodeProject, buildWithTests) {
  console.log('Adding Build Properties');

  // Tell to Xcode project that we use Swift in our framework
  // I believe that this line of code will be removed in the future
  xcodeProject.removeBuildProperty(
    'EMBEDDED_CONTENT_CONTAINS_SWIFT');

  xcodeProject.removeBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES');
  xcodeProject.addBuildProperty(
    'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES');

  xcodeProject.removeBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET');
  xcodeProject.addBuildProperty(
    'IPHONEOS_DEPLOYMENT_TARGET', '10.0');

  xcodeProject.removeBuildProperty(
    'SWIFT_VERSION');
  xcodeProject.addBuildProperty(
    'SWIFT_VERSION', '3.0');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_ENUM_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_INFINITE_RECURSION', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_SUSPICIOUS_MOVE', 'YES');

  xcodeProject.removeBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE');
  xcodeProject.addBuildProperty(
    'CLANG_WARN_UNREACHABLE_CODE', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND');
  xcodeProject.addBuildProperty(
    'ENABLE_STRICT_OBJC_MSGSEND', 'YES');

  xcodeProject.removeBuildProperty(
    'ENABLE_TESTABILITY');
  xcodeProject.addBuildProperty(
    'ENABLE_TESTABILITY', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_NO_COMMON_BLOCKS');
  xcodeProject.addBuildProperty(
    'GCC_NO_COMMON_BLOCKS', 'YES');

  xcodeProject.removeBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION');
  xcodeProject.addBuildProperty(
    'GCC_WARN_64_TO_32_BIT_CONVERSION', 'YES');

  xcodeProject.removeBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL');
  xcodeProject.addBuildProperty(
    'SWIFT_OPTIMIZATION_LEVEL', '-Owholemodule');

  if (buildWithTests) {
    xcodeProject.removeBuildProperty(
      'OTHER_SWIFT_FLAGS');
    xcodeProject.addBuildProperty('OTHER_SWIFT_FLAGS', '\"-DTEST\"');

    xcodeProject.removeBuildProperty('GCC_PREPROCESSOR_DEFINITIONS');
    xcodeProject.updateBuildProperty(
      'GCC_PREPROCESSOR_DEFINITIONS',
      ['\"$(inherited)\"', '\"TEST=1\"']);
  }
}

function updateProjectFrameworks(
  xcodeProject, frameworkOutputDir, buildWithTests) {
  // Project should not have more that one target.
  var targetUUID = xcodeProject.getFirstTarget().uuid;

  // First check to see if the Embed Framework node exists, if not, add
  // it. This is all we need to do as they are added to the embedded
  // section by default.
  if (!xcodeProject.pbxEmbedFrameworksBuildPhaseObj(targetUUID)) {
    var buildPhaseResult = xcodeProject.addBuildPhase(
      [],
      'PBXCopyFilesBuildPhase',
      'Embed Frameworks',
      targetUUID,
      'framework');
    // No idea why,
    // but "Framework" (value 10) is not available in node-xcode,
    // set it here manually so libraries
    // embed correctly.
    // If we don't set it, the folder type defaults to "Shared
    // Frameworks".
    buildPhaseResult.buildPhase.dstSubfolderSpec = 10;
    console.log('Adding Embedded Build Phase');
  } else {
    console.log('Embedded Build Phase already added');
  }

  // This is critical to include,
  // otherwise the library loader cannot find libs at runtime
  // on a device.
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Debug');
  xcodeProject.addBuildProperty(
    'LD_RUNPATH_SEARCH_PATHS',
    '\"$(inherited) @executable_path/Frameworks\"', 'Release');

  // Add the frameworks again.
  // This time they will have the code-sign option set
  // so they get code signed when being deployed to devices.
  console.log('Adding ThaliCore.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'ThaliCore.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  console.log('Adding CocoaAsyncSocket.framework');
  xcodeProject.addFramework(
    path.join(frameworkOutputDir, 'CocoaAsyncSocket.framework'),
    {customFramework: true, embed: true, link: true, sign: true});

  if (buildWithTests) {
    console.log('Adding SwiftXCTest.framework');
    xcodeProject.addFramework(
      path.join(frameworkOutputDir, 'SwiftXCTest.framework'),
      {customFramework: true, embed: true, link: true, sign: true});
  }
}

function updateProjectTestingInfrastructure(
  xcodeProject, testingInfrastructureDir, buildWithTests) {
  if (buildWithTests) {
    var testingFiles =
      fs.readdirSync(testingInfrastructureDir)
        .filter(function (file) {
          return file.endsWith('.swift');
        })
        .map(function (file) {
          return path.join(testingInfrastructureDir, file);
        });

    testingFiles
      .forEach(function (file) {
        xcodeProject.addSourceFile(file);
      });
  }
}

function addFramework(
  projectPath, frameworkProjectDir, frameworkOutputDir,
  buildWithTests, testingInfrastructureDir) {

  checkoutThaliCoreViaCarthage(
    frameworkOutputDir, frameworkProjectDir, buildWithTests)
    .then (function () {
      console.log('Checkouting is successfully done.\n' +
                  'Results were put into ' + frameworkProjectDir);

      // We need to build ThaliCore.framework before embedding it into the project
      return buildFramework(
        frameworkProjectDir, frameworkOutputDir, buildWithTests)
        .then(function () {
          console.log('Building framework is done.');
          console.log('frameworkProjectDir: ' + frameworkProjectDir);
          console.log('frameworkOutputDir: ' + frameworkOutputDir);
          console.log('buildWithTests: ' + buildWithTests);

          var pbxProjectPath = path.join(projectPath, 'project.pbxproj');
          var xcodeProject = xcode.project(pbxProjectPath);

          return new Promise(function (resolve, reject) {

            xcodeProject.parse(function (error) {

              // If we couldn't parse the project, bail out.
              if (error) {
                var message =
                  'Cannot parse Xcode project: ' + JSON.stringify(error);
                reject(new Error(message));
                return;
              }

              updateProjectBuildProperties(xcodeProject, buildWithTests);

              updateProjectFrameworks(
                xcodeProject, frameworkOutputDir, buildWithTests);

              updateProjectTestingInfrastructure(
                xcodeProject, testingInfrastructureDir, buildWithTests);

              resolve(xcodeProject);
            });
          })
          .then(function (xcodeProject) {
            // Save the project file back to disk.
            return fs.writeFileAsync(
              pbxProjectPath, xcodeProject.writeSync(), 'utf-8');
          });
        });
    })
};

function checkoutThaliCoreViaCarthage(cartfileDir, outputDir, buildWithTests) {
  var cdToCartfileDirCmd = 'cd ' + cartfileDir;
  var removeCarthageDirCmd = 'rm -rf Carthage/';
  var carthageCmd = 'carthage update --no-build';
  var checkoutCmd = cdToCartfileDirCmd + ' && ' +
                    removeCarthageDirCmd + ' && ' +
                    carthageCmd;

  console.log('Checkouting ThaliCore and its dependencies via carthage.\n' +
              'Cartfile in: ' + cartfileDir + '\n' +
              'Results will be put into ' + outputDir);

  return exec(checkoutCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      return fs.ensureDir(outputDir);
    })
}

/**
 * @param {string} projectDir Xcode project directory
 * @param {string} outputDir Framework output directory
 * @param {boolean} buildWithTests
 * @returns {Promise} Output of exec
 */
function buildFramework(projectDir, outputDir, buildWithTests) {

  var cocoaAsyncSocketFrameworkName = 'CocoaAsyncSocket';
  var XCTestFrameworkName = 'SwiftXCTest';

  var projectName = 'ThaliCore';
  var projectScheme = 'ThaliCore';
  var projectConfiguration = 'Release';

  if (buildWithTests) {
    projectScheme = 'ThaliCoreCITests';
    projectConfiguration = 'Debug';
  }

  console.log('Building ' + projectName + ' in ' + projectConfiguration + ' mode\n' +
              'Xcode project dir: ' + projectDir + '\n' +
              'Framework output dir: ' + outputDir);

  var sdk = 'iphoneos';
  var projectPath = path.join(projectDir, projectName + '.xcodeproj');
  var buildDir = path.join(projectDir, 'build');

  var buildCmd = 'set -o pipefail && ' +
    'xcodebuild -project' +
    ' \"' + projectPath + '\"' +
    ' -scheme ' + '\"' + projectScheme + '\"' +
    ' -configuration ' + projectConfiguration +
    ' -sdk ' + sdk +
    ' ONLY_ACTIVE_ARCH=NO ' +
    ' IPHONEOS_DEPLOYMENT_TARGET=10.0' +
    ' BUILD_DIR=' + '\"' + buildDir + '\"' +
    ' clean build';

  console.log('Building ' + projectName + ' framework');
  console.log('Build command:\n' + buildCmd);

  // todo: fixed buffer size should be fixed with streaming in #1001
  return exec(buildCmd, { maxBuffer: 10*1024*1024 } )
    .then(function () {
      console.log('Building ThaliCore.framework has been finished');
      return fs.ensureDir(outputDir);
    })
    .then(function () {
      var thaliCoreFrameworkBuildDir = path.join(
        buildDir, projectConfiguration + '-' + sdk, projectName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, projectName + '.framework');

      console.log('Copying:\n' +
                  'from: ' + thaliCoreFrameworkBuildDir + '\n' +
                  'to:   ' + frameworkOutputDir);

      return fs.copy(thaliCoreFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      var cocoaAsyncSocketFrameworkBuildDir = path.join(
        projectDir, 'build', projectConfiguration + '-' + sdk,
        cocoaAsyncSocketFrameworkName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, cocoaAsyncSocketFrameworkName + '.framework');

        console.log('Copying:\n' +
                    'from: ' + cocoaAsyncSocketFrameworkBuildDir + '\n' +
                    'to:   ' + frameworkOutputDir);

      return fs.copy(cocoaAsyncSocketFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    })
    .then(function () {
      if (!buildWithTests) {
        // Don't copy SwiftXCTest framework
        // if the plugin was built without tests (release mode).
        return new Promise(function (resolve) {
          resolve();
        })
      }

      var swiftXCTestFrameworkBuildDir = path.join(
        projectDir, 'build', projectConfiguration + '-' + sdk,
        XCTestFrameworkName + '.framework');
      var frameworkOutputDir = path.join(
        outputDir, XCTestFrameworkName + '.framework');

        console.log('Copying:\n' +
                    'from: ' + swiftXCTestFrameworkBuildDir + '\n' +
                    'to:   ' + frameworkOutputDir);

      return fs.copy(swiftXCTestFrameworkBuildDir, frameworkOutputDir, { clobber: false });
    });
}

module.exports = {
  addFramework: addFramework
};
<|endoftext|>