<commit_before>    function format_date(datestring) {
        //parse and format the date timestamps - seconds since epoch into date object
        var date = new Date(datestring * 1000);
        // hours part from the timestamp
        var hours = date.getHours();
        // minutes part from the timestamp
        var minutes = date.getMinutes();
        // seconds part from the timestamp
        var seconds = date.getSeconds();
        if (seconds < 10) {
            var second_str = "0"+ seconds;
        } else {
            var second_str = seconds;
        }

        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var day = date.getDate();

        return  year + '/' + month + '/' + day + ' ' + hours + ':' + minutes + ':' +  second_str;

    }

    function number_fix(num) {
        if (num !== null) {
            if (num.toFixed) {
                return num.toFixed(2)
            }
            if (num.toPrecision) {
                return num.toPrecision(2);
            }
            return num;
        }
    }

    function RefreshableViewModel(url, model, interval, sort_by) {
        var self = this;
        self.error = ko.observable();
        self.models = ko.observableArray();
        self.autoRefresh = ko.observable(false);
        self.loading = ko.observable(false);
        self.timer = null;
        self.interval = interval;

        self.autoRefresh.subscribe(function (newVal) {
            if (newVal) {
                self.refresh();
            } else {
                self.clearTimer();
            }
        });

        self.clearTimer = function () {
            if (self.timer) {
                clearTimeout(self.timer);
                self.timer = null;
            }
        };

        self.refresh = function () {
            self.clearTimer();
            self.loading(true);
            $.getJSON(url, function (data) {
                self.error(null);
                var objects = _(data).map(function (item) {
                    return new model(item);
                });
                if (sort_by) {
                    objects = _(objects).sortBy(function (x) { return x[sort_by]; })
                }
                self.models(objects);
                if (self.autoRefresh()) {
                    self.timer = setTimeout(self.refresh, self.interval);
                }
            })
            .fail(function (jqxhr, textStatus, error) {
                var err = 'Unknown server error';
                try {
                    err = JSON.parse(jqxhr.responseText).error;
                } catch (e) {}
                self.error("Error: " + err);
                self.autoRefresh(false);
                self.timer = null;
            })
            .always(function (){
                self.loading(false);
            });
        };
    }

    function ActiveTaskModel(data) {

        this.pid = ko.observable(data.pid);
        this.type = ko.observable(data.type);
        this.database = ko.observable(data.database);
        this.progress = ko.observable(data.progress + "%");
        this.design_document = ko.observable(data.design_document);
        this.started_on = ko.observable(format_date(data.started_on));
        this.updated_on = ko.observable(format_date(data.updated_on));
        this.total_changes = ko.observable(data.total_changes);
        this.changes_done = ko.observable(data.changes_done);
        this.progress_contribution = ko.observable(data.progress_contribution);
    }

    function DesignDocModel(data) {
        var self = this;
        self.design_document = ko.observable(data.design_document);
        self.details_id = self.design_document() + '_details';
        var tasks = _(data.tasks).map(function (task) {
            return new ActiveTaskModel(task);
        });
        self.tasks = ko.observableArray(tasks);

        self.showDetails = function () {
            $('#' + self.details_id).toggle();
        };
    }

    function CeleryTaskModel(data) {
        var self = this;
        this.name = ko.observable(data.name);
        this.uuid = ko.observable(data.uuid);
        this.state = ko.observable(data.state);
        this.received = ko.observable(format_date(data.received));
        this.started = ko.observable(format_date(data.started));
        this.timestamp = ko.observable(format_date(data.timestamp));
        this.succeeded = ko.observable(format_date(data.succeeded));
        this.retries = ko.observable(data.retries);
        this.args = ko.observable(data.args);
        this.kwargs = ko.observable(data.kwargs);
        this.runtime = ko.observable(number_fix(data.runtime));

        this.toggleArgs = function () {
            $('#' + self.uuid()).toggle();
        }
    }

    function PillowOperationViewModel(pillow_model, operation) {
        var self = this;
        self.pillow_model = pillow_model;
        self.operation = operation;
        self.title = operation + ' for ' + pillow_model.name();

        self.go = function () {
            self.pillow_model.perform_operation(operation);
        }
    }

    function PillowProgress(name, db_offset, seq) {
        var self = this;
        self.name = name;
        self.db_offset = db_offset;
        self.seq = seq;

        self.width = function() {
            return (self.seq * 100) / self.db_offset;
        };

        self.status = function() {
            if (self.width() > 98) {
                return 'progress-bar-success';
            } else if (self.width() < 50) {
                return 'progress-bar-danger';
            } else if (self.width() < 75) {
                return 'progress-bar-warning';
            }
        };
    }

    function PillowModel(pillow) {
        var self = this;
        self.name = ko.observable();
        self.seq_format = ko.observable();
        self.seq = ko.observable();
        self.offsets = ko.observable();
        self.time_since_last = ko.observable();
        self.show_supervisor_info = ko.observable();
        self.supervisor_state = ko.observable();
        self.supervisor_message = ko.observable();
        self.operation_in_progress = ko.observable(false);
        self.progress = ko.observableArray();

        self.update = function (data) {
            self.name(data.name);
            self.seq_format(data.seq_format);
            self.seq(data.seq);
            self.offsets(data.offsets);
            self.time_since_last(data.time_since_last);
            self.show_supervisor_info(!!data.supervisor_state);
            self.supervisor_state(data.supervisor_state||'(unavailable)');
            self.supervisor_message(data.supervisor_message);

            self.progress([]);
            if (self.seq_format() === 'json') {
                _.each(self.offsets(), function(db_offset, key) {
                    var value;
                    if (self.seq() === null || !self.seq().hasOwnProperty(key)) {
                        value = 0;
                    } else {
                        value = self.seq()[key];
                    }
                    self.progress.push(new PillowProgress(key, db_offset, value));
                })
            } else {
                var key = _.keys(self.offsets())[0];
                self.progress.push(new PillowProgress(key, self.offsets()[key], self.seq()));
            }
        };

        self.update(pillow);

        self.process_running = ko.computed(function () {
            return self.supervisor_state() === 'RUNNING';
        });

        self.start_stop_text = ko.computed(function () {
            return self.process_running() ? gettext("Stop") : gettext("Start");
        });

        self.disabled = ko.computed(function() {
            return self.operation_in_progress() || (self.supervisor_state() !== 'RUNNING' && self.supervisor_state() !== 'STOPPED');
        });

        self.supervisor_state_css = ko.computed(function() {
            switch (self.supervisor_state()) {
                case ('(unavailable)'):
                    return '';
                case ('RUNNING'):
                    return 'label-success';
                case ('STOPPED'):
                    return 'label-warning';
                default:
                    return 'label-danger';
            }
        });

        self.checkpoint_status_css = ko.computed(function() {
            var hours = pillow.hours_since_last;
            switch (true) {
                case (hours <= 1):
                    return 'label-success';
                case (hours <= 6):
                    return 'label-info';
                case (hours <= 12):
                    return 'label-warning';
                default:
                    return 'label-danger';
            }
        });

        self.overall_status = ko.computed(function() {
            var status_combined = self.checkpoint_status_css() + self.supervisor_state_css();
            if (status_combined.indexOf('important') !== -1) {
                return 'error';
            } else if (status_combined.indexOf('warning') !== -1) {
                return 'warning';
            } else if (status_combined.indexOf('info') !== -1) {
                return 'info';
            } else if (status_combined.indexOf('success') !== -1) {
                return 'success';
            }
        });

        self.show_pillow_dialog = function (operation) {
            var element = $('#pillow_operation_modal').get(0);
            ko.cleanNode(element);
            $(element).koApplyBindings(new PillowOperationViewModel(self, operation));
            $('#pillow_operation_modal').modal({
                backdrop: 'static',
                keyboard: false,
                show: true
            });
        };

        self.reset_checkpoint = function () {
            self.show_pillow_dialog('reset_checkpoint');
        };

        self.start_stop = function () {
            self.show_pillow_dialog(self.process_running() ? 'stop' : 'start');
        };

        self.refresh = function () {
            self.perform_operation('refresh');
        };

        self.perform_operation = function(operation) {
            self.operation_in_progress(true);
            $.post(hqImport("hqwebapp/js/urllib.js").reverse("pillow_operation_api"), {
                'pillow_name': self.name,
                'operation': operation
            }, function( data ) {
                self.operation_in_progress(false);
                self.update(data);

                if (!data.success) {
                    alert_user("Operation failed: " + data.operation + " on "
                            + data.pillow_name + ', ' + data.message, 'error');
                }
            }, "json")
            .fail(function (jqxhr, textStatus, error) {
                var err = 'Unknown server error';
                try {
                    err = JSON.parse(jqxhr.responseText).error;
                } catch (e) {}
                self.operation_in_progress(false);
                self.supervisor_state('(unavailable)');
                self.supervisor_message(err);
            }).always(function() {
                $('#pillow_operation_modal').modal('hide');
                $("#" + self.name() +" td").fadeTo( "fast" , 0.5).fadeTo( "fast" , 1);
            });
        }
    }

    function DbComparisons(data) {
        var self = this;
        self.description = data.description;
        self.es_docs = data.es_docs;
        self.couch_docs = data.couch_docs;
        self.sql_rows = data.sql_rows;
    }

    $(function () {
        var initial_page_data = hqImport("hqwebapp/js/initial_page_data.js").get,
            celery_update = initial_page_data("celery_update"),
            couch_update = initial_page_data("couch_update"),
            system_ajax_url = hqImport("hqwebapp/js/urllib.js").reverse("system_ajax");
        var celeryViewModel = new RefreshableViewModel(system_ajax_url + "?api=flower_poll", CeleryTaskModel, celery_update);
        var couchViewModel;
        if (initial_page_data("is_bigcouch")) {
            var couchViewModel = new RefreshableViewModel(system_ajax_url + "?api=_active_tasks", DesignDocModel, couch_update, 'design_document');
        } else {
            var couchViewModel = new RefreshableViewModel(system_ajax_url + "?api=_active_tasks", ActiveTaskModel, couch_update);
        }
        var pillowtopViewModel = new RefreshableViewModel(system_ajax_url + "?api=pillowtop", PillowModel, couch_update, 'name');

        var AutoRefreshModel = function () {
            var self = this;
            self.refreshStatus = ko.observable(false);
            self.refreshStatusText = ko.observable('off');
            self.models = [];

            self.addModel = function (model) {
                self.models.push(model);
            };

            self.toggleRefresh = function () {
                self.refreshStatus(!self.refreshStatus());
                self.refreshStatusText(self.refreshStatus() ? 'on' : 'off');
                $.each(self.models, function (index, model) {
                    model.autoRefresh(self.refreshStatus());
                });
            };

            self.refreshAll = function () {
                $.each(self.models, function (index, model) {
                    model.refresh();
                });
            };
        };

        var autoRefresh = new AutoRefreshModel();
        $("#celeryblock").koApplyBindings(celeryViewModel);
        $("#couchblock").koApplyBindings(couchViewModel);
        $('#pillowtop-status').koApplyBindings(pillowtopViewModel);
        autoRefresh.addModel(celeryViewModel);
        autoRefresh.addModel(couchViewModel);
        autoRefresh.addModel(pillowtopViewModel);

        autoRefresh.refreshAll();
        $('#autorefresh').koApplyBindings(autoRefresh);
    });
<commit_msg>[ci skip] whitespace only<commit_after>function format_date(datestring) {
    //parse and format the date timestamps - seconds since epoch into date object
    var date = new Date(datestring * 1000);
    // hours part from the timestamp
    var hours = date.getHours();
    // minutes part from the timestamp
    var minutes = date.getMinutes();
    // seconds part from the timestamp
    var seconds = date.getSeconds();
    if (seconds < 10) {
        var second_str = "0"+ seconds;
    } else {
        var second_str = seconds;
    }

    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var day = date.getDate();

    return  year + '/' + month + '/' + day + ' ' + hours + ':' + minutes + ':' +  second_str;

}

function number_fix(num) {
    if (num !== null) {
        if (num.toFixed) {
            return num.toFixed(2)
        }
        if (num.toPrecision) {
            return num.toPrecision(2);
        }
        return num;
    }
}

function RefreshableViewModel(url, model, interval, sort_by) {
    var self = this;
    self.error = ko.observable();
    self.models = ko.observableArray();
    self.autoRefresh = ko.observable(false);
    self.loading = ko.observable(false);
    self.timer = null;
    self.interval = interval;

    self.autoRefresh.subscribe(function (newVal) {
        if (newVal) {
            self.refresh();
        } else {
            self.clearTimer();
        }
    });

    self.clearTimer = function () {
        if (self.timer) {
            clearTimeout(self.timer);
            self.timer = null;
        }
    };

    self.refresh = function () {
        self.clearTimer();
        self.loading(true);
        $.getJSON(url, function (data) {
            self.error(null);
            var objects = _(data).map(function (item) {
                return new model(item);
            });
            if (sort_by) {
                objects = _(objects).sortBy(function (x) { return x[sort_by]; })
            }
            self.models(objects);
            if (self.autoRefresh()) {
                self.timer = setTimeout(self.refresh, self.interval);
            }
        })
        .fail(function (jqxhr, textStatus, error) {
            var err = 'Unknown server error';
            try {
                err = JSON.parse(jqxhr.responseText).error;
            } catch (e) {}
            self.error("Error: " + err);
            self.autoRefresh(false);
            self.timer = null;
        })
        .always(function (){
            self.loading(false);
        });
    };
}

function ActiveTaskModel(data) {

    this.pid = ko.observable(data.pid);
    this.type = ko.observable(data.type);
    this.database = ko.observable(data.database);
    this.progress = ko.observable(data.progress + "%");
    this.design_document = ko.observable(data.design_document);
    this.started_on = ko.observable(format_date(data.started_on));
    this.updated_on = ko.observable(format_date(data.updated_on));
    this.total_changes = ko.observable(data.total_changes);
    this.changes_done = ko.observable(data.changes_done);
    this.progress_contribution = ko.observable(data.progress_contribution);
}

function DesignDocModel(data) {
    var self = this;
    self.design_document = ko.observable(data.design_document);
    self.details_id = self.design_document() + '_details';
    var tasks = _(data.tasks).map(function (task) {
        return new ActiveTaskModel(task);
    });
    self.tasks = ko.observableArray(tasks);

    self.showDetails = function () {
        $('#' + self.details_id).toggle();
    };
}

function CeleryTaskModel(data) {
    var self = this;
    this.name = ko.observable(data.name);
    this.uuid = ko.observable(data.uuid);
    this.state = ko.observable(data.state);
    this.received = ko.observable(format_date(data.received));
    this.started = ko.observable(format_date(data.started));
    this.timestamp = ko.observable(format_date(data.timestamp));
    this.succeeded = ko.observable(format_date(data.succeeded));
    this.retries = ko.observable(data.retries);
    this.args = ko.observable(data.args);
    this.kwargs = ko.observable(data.kwargs);
    this.runtime = ko.observable(number_fix(data.runtime));

    this.toggleArgs = function () {
        $('#' + self.uuid()).toggle();
    }
}

function PillowOperationViewModel(pillow_model, operation) {
    var self = this;
    self.pillow_model = pillow_model;
    self.operation = operation;
    self.title = operation + ' for ' + pillow_model.name();

    self.go = function () {
        self.pillow_model.perform_operation(operation);
    }
}

function PillowProgress(name, db_offset, seq) {
    var self = this;
    self.name = name;
    self.db_offset = db_offset;
    self.seq = seq;

    self.width = function() {
        return (self.seq * 100) / self.db_offset;
    };

    self.status = function() {
        if (self.width() > 98) {
            return 'progress-bar-success';
        } else if (self.width() < 50) {
            return 'progress-bar-danger';
        } else if (self.width() < 75) {
            return 'progress-bar-warning';
        }
    };
}

function PillowModel(pillow) {
    var self = this;
    self.name = ko.observable();
    self.seq_format = ko.observable();
    self.seq = ko.observable();
    self.offsets = ko.observable();
    self.time_since_last = ko.observable();
    self.show_supervisor_info = ko.observable();
    self.supervisor_state = ko.observable();
    self.supervisor_message = ko.observable();
    self.operation_in_progress = ko.observable(false);
    self.progress = ko.observableArray();

    self.update = function (data) {
        self.name(data.name);
        self.seq_format(data.seq_format);
        self.seq(data.seq);
        self.offsets(data.offsets);
        self.time_since_last(data.time_since_last);
        self.show_supervisor_info(!!data.supervisor_state);
        self.supervisor_state(data.supervisor_state||'(unavailable)');
        self.supervisor_message(data.supervisor_message);

        self.progress([]);
        if (self.seq_format() === 'json') {
            _.each(self.offsets(), function(db_offset, key) {
                var value;
                if (self.seq() === null || !self.seq().hasOwnProperty(key)) {
                    value = 0;
                } else {
                    value = self.seq()[key];
                }
                self.progress.push(new PillowProgress(key, db_offset, value));
            })
        } else {
            var key = _.keys(self.offsets())[0];
            self.progress.push(new PillowProgress(key, self.offsets()[key], self.seq()));
        }
    };

    self.update(pillow);

    self.process_running = ko.computed(function () {
        return self.supervisor_state() === 'RUNNING';
    });

    self.start_stop_text = ko.computed(function () {
        return self.process_running() ? gettext("Stop") : gettext("Start");
    });

    self.disabled = ko.computed(function() {
        return self.operation_in_progress() || (self.supervisor_state() !== 'RUNNING' && self.supervisor_state() !== 'STOPPED');
    });

    self.supervisor_state_css = ko.computed(function() {
        switch (self.supervisor_state()) {
            case ('(unavailable)'):
                return '';
            case ('RUNNING'):
                return 'label-success';
            case ('STOPPED'):
                return 'label-warning';
            default:
                return 'label-danger';
        }
    });

    self.checkpoint_status_css = ko.computed(function() {
        var hours = pillow.hours_since_last;
        switch (true) {
            case (hours <= 1):
                return 'label-success';
            case (hours <= 6):
                return 'label-info';
            case (hours <= 12):
                return 'label-warning';
            default:
                return 'label-danger';
        }
    });

    self.overall_status = ko.computed(function() {
        var status_combined = self.checkpoint_status_css() + self.supervisor_state_css();
        if (status_combined.indexOf('important') !== -1) {
            return 'error';
        } else if (status_combined.indexOf('warning') !== -1) {
            return 'warning';
        } else if (status_combined.indexOf('info') !== -1) {
            return 'info';
        } else if (status_combined.indexOf('success') !== -1) {
            return 'success';
        }
    });

    self.show_pillow_dialog = function (operation) {
        var element = $('#pillow_operation_modal').get(0);
        ko.cleanNode(element);
        $(element).koApplyBindings(new PillowOperationViewModel(self, operation));
        $('#pillow_operation_modal').modal({
            backdrop: 'static',
            keyboard: false,
            show: true
        });
    };

    self.reset_checkpoint = function () {
        self.show_pillow_dialog('reset_checkpoint');
    };

    self.start_stop = function () {
        self.show_pillow_dialog(self.process_running() ? 'stop' : 'start');
    };

    self.refresh = function () {
        self.perform_operation('refresh');
    };

    self.perform_operation = function(operation) {
        self.operation_in_progress(true);
        $.post(hqImport("hqwebapp/js/urllib.js").reverse("pillow_operation_api"), {
            'pillow_name': self.name,
            'operation': operation
        }, function( data ) {
            self.operation_in_progress(false);
            self.update(data);

            if (!data.success) {
                alert_user("Operation failed: " + data.operation + " on "
                        + data.pillow_name + ', ' + data.message, 'error');
            }
        }, "json")
        .fail(function (jqxhr, textStatus, error) {
            var err = 'Unknown server error';
            try {
                err = JSON.parse(jqxhr.responseText).error;
            } catch (e) {}
            self.operation_in_progress(false);
            self.supervisor_state('(unavailable)');
            self.supervisor_message(err);
        }).always(function() {
            $('#pillow_operation_modal').modal('hide');
            $("#" + self.name() +" td").fadeTo( "fast" , 0.5).fadeTo( "fast" , 1);
        });
    }
}

function DbComparisons(data) {
    var self = this;
    self.description = data.description;
    self.es_docs = data.es_docs;
    self.couch_docs = data.couch_docs;
    self.sql_rows = data.sql_rows;
}

$(function () {
    var initial_page_data = hqImport("hqwebapp/js/initial_page_data.js").get,
        celery_update = initial_page_data("celery_update"),
        couch_update = initial_page_data("couch_update"),
        system_ajax_url = hqImport("hqwebapp/js/urllib.js").reverse("system_ajax");
    var celeryViewModel = new RefreshableViewModel(system_ajax_url + "?api=flower_poll", CeleryTaskModel, celery_update);
    var couchViewModel;
    if (initial_page_data("is_bigcouch")) {
        var couchViewModel = new RefreshableViewModel(system_ajax_url + "?api=_active_tasks", DesignDocModel, couch_update, 'design_document');
    } else {
        var couchViewModel = new RefreshableViewModel(system_ajax_url + "?api=_active_tasks", ActiveTaskModel, couch_update);
    }
    var pillowtopViewModel = new RefreshableViewModel(system_ajax_url + "?api=pillowtop", PillowModel, couch_update, 'name');

    var AutoRefreshModel = function () {
        var self = this;
        self.refreshStatus = ko.observable(false);
        self.refreshStatusText = ko.observable('off');
        self.models = [];

        self.addModel = function (model) {
            self.models.push(model);
        };

        self.toggleRefresh = function () {
            self.refreshStatus(!self.refreshStatus());
            self.refreshStatusText(self.refreshStatus() ? 'on' : 'off');
            $.each(self.models, function (index, model) {
                model.autoRefresh(self.refreshStatus());
            });
        };

        self.refreshAll = function () {
            $.each(self.models, function (index, model) {
                model.refresh();
            });
        };
    };

    var autoRefresh = new AutoRefreshModel();
    $("#celeryblock").koApplyBindings(celeryViewModel);
    $("#couchblock").koApplyBindings(couchViewModel);
    $('#pillowtop-status').koApplyBindings(pillowtopViewModel);
    autoRefresh.addModel(celeryViewModel);
    autoRefresh.addModel(couchViewModel);
    autoRefresh.addModel(pillowtopViewModel);

    autoRefresh.refreshAll();
    $('#autorefresh').koApplyBindings(autoRefresh);
});
<|endoftext|>


<commit_before>(function() {

  var view;

  module("Backbone.View", {

    setup: function() {
      view = new Backbone.View({
        id        : 'test-view',
        className : 'test-view',
        other     : 'non-special-option'
      });
    }

  });

  test("constructor", 3, function() {
    equal(view.el.id, 'test-view');
    equal(view.el.className, 'test-view');
    equal(view.el.other, void 0);
  });

  test("$", 2, function() {
    var view = new Backbone.View;
    view.setElement('
test
');
    var result = view.$('a b');

    strictEqual(result[0].innerHTML, 'test');
    ok(result.length === +result.length);
  });

  test("$el", 3, function() {
    var view = new Backbone.View;
    view.setElement('
test
');
    strictEqual(view.el.nodeType, 1);

    ok(view.$el instanceof Backbone.$);
    strictEqual(view.$el[0], view.el);
  });

  test("initialize", 1, function() {
    var View = Backbone.View.extend({
      initialize: function() {
        this.one = 1;
      }
    });

    strictEqual(new View().one, 1);
  });

  test("render", 1, function() {
    var view = new Backbone.View;
    equal(view.render(), view, '#render returns the view instance');
  });

  test("delegateEvents", 6, function() {
    var counter1 = 0, counter2 = 0;

    var view = new Backbone.View({el: '#testElement'});
    view.increment = function(){ counter1++; };
    view.$el.on('click', function(){ counter2++; });

    var events = {'click h1': 'increment'};

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 1);

    view.$('h1').trigger('click');
    equal(counter1, 2);
    equal(counter2, 2);

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 3);
    equal(counter2, 3);
  });

  test("delegate", 3, function() {
    var view = new Backbone.View({el: '#testElement'});
    view.delegate('click', 'h1', function() {
      ok(true);
    });
    view.delegate('click', function() {
      ok(true);
    });
    view.$('h1').trigger('click');

    equal(view.delegate(), view, '#delegate returns the view instance');
  });

  test("delegateEvents allows functions for callbacks", 3, function() {
    var view = new Backbone.View({el: '

'});
    view.counter = 0;

    var events = {
      click: function() {
        this.counter++;
      }
    };

    view.delegateEvents(events);
    view.$el.trigger('click');
    equal(view.counter, 1);

    view.$el.trigger('click');
    equal(view.counter, 2);

    view.delegateEvents(events);
    view.$el.trigger('click');
    equal(view.counter, 3);
  });

  test("delegateEvents ignore undefined methods", 0, function() {
    var view = new Backbone.View({el: '

'});
    view.delegateEvents({'click': 'undefinedMethod'});
    view.$el.trigger('click');
  });

  test("undelegateEvents", 7, function() {
    var counter1 = 0, counter2 = 0;

    var view = new Backbone.View({el: '#testElement'});
    view.increment = function(){ counter1++; };
    view.$el.on('click', function(){ counter2++; });

    var events = {'click h1': 'increment'};

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 1);

    view.undelegateEvents();
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 2);

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 2);
    equal(counter2, 3);

    equal(view.undelegateEvents(), view, '#undelegateEvents returns the view instance');
  });

  test("undelegate", 1, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(false); });
    view.delegate('click', 'h1', function() { ok(false); });

    view.undelegate('click');

    view.$('h1').trigger('click');
    view.$el.trigger('click');

    equal(view.undelegate(), view, '#undelegate returns the view instance');
  });

  test("undelegate with passed handler", 1, function() {
    view = new Backbone.View({el: '#testElement'});
    var listener = function() { ok(false); };
    view.delegate('click', listener);
    view.delegate('click', function() { ok(true); });
    view.undelegate('click', listener);
    view.$el.trigger('click');
  });

  test("undelegate with selector", 2, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(true); });
    view.delegate('click', 'h1', function() { ok(false); });
    view.undelegate('click', 'h1');
    view.$('h1').trigger('click');
    view.$el.trigger('click');
  });

  test("undelegate with handler and selector", 2, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(true); });
    var handler = function(){ ok(false); };
    view.delegate('click', 'h1', handler);
    view.undelegate('click', 'h1', handler);
    view.$('h1').trigger('click');
    view.$el.trigger('click');
  });

  test("tagName can be provided as a string", 1, function() {
    var View = Backbone.View.extend({
      tagName: 'span'
    });

    equal(new View().el.tagName, 'SPAN');
  });

  test("tagName can be provided as a function", 1, function() {
    var View = Backbone.View.extend({
      tagName: function() {
        return 'p';
      }
    });

    ok(new View().$el.is('p'));
  });

  test("_ensureElement with DOM node el", 1, function() {
    var View = Backbone.View.extend({
      el: document.body
    });

    equal(new View().el, document.body);
  });

  test("_ensureElement with string el", 3, function() {
    var View = Backbone.View.extend({
      el: "body"
    });
    strictEqual(new View().el, document.body);

    View = Backbone.View.extend({
      el: "#testElement > h1"
    });
    strictEqual(new View().el, $("#testElement > h1").get(0));

    View = Backbone.View.extend({
      el: "#nonexistent"
    });
    ok(!new View().el);
  });

  test("with className and id functions", 2, function() {
    var View = Backbone.View.extend({
      className: function() {
        return 'className';
      },
      id: function() {
        return 'id';
      }
    });

    strictEqual(new View().el.className, 'className');
    strictEqual(new View().el.id, 'id');
  });

  test("with attributes", 2, function() {
    var View = Backbone.View.extend({
      attributes: {
        id: 'id',
        'class': 'class'
      }
    });

    strictEqual(new View().el.className, 'class');
    strictEqual(new View().el.id, 'id');
  });

  test("with attributes as a function", 1, function() {
    var View = Backbone.View.extend({
      attributes: function() {
        return {'class': 'dynamic'};
      }
    });

    strictEqual(new View().el.className, 'dynamic');
  });

  test("multiple views per element", 3, function() {
    var count = 0;
    var $el = $('

');

    var View = Backbone.View.extend({
      el: $el,
      events: {
        click: function() {
          count++;
        }
      }
    });

    var view1 = new View;
    $el.trigger("click");
    equal(1, count);

    var view2 = new View;
    $el.trigger("click");
    equal(3, count);

    view1.delegateEvents();
    $el.trigger("click");
    equal(5, count);
  });

  test("custom events", 2, function() {
    var View = Backbone.View.extend({
      el: $('body'),
      events: {
        "fake$event": function() { ok(true); }
      }
    });

    var view = new View;
    $('body').trigger('fake$event').trigger('fake$event');

    $('body').off('fake$event');
    $('body').trigger('fake$event');
  });

  test("#1048 - setElement uses provided object.", 2, function() {
    var $el = $('body');

    var view = new Backbone.View({el: $el});
    ok(view.$el === $el);

    view.setElement($el = $($el));
    ok(view.$el === $el);
  });

  test("#986 - Undelegate before changing element.", 1, function() {
    var button1 = $('<button></button>');
    var button2 = $('<button></button>');

    var View = Backbone.View.extend({
      events: {
        click: function(e) {
          ok(view.el === e.target);
        }
      }
    });

    var view = new View({el: button1});
    view.setElement(button2);

    button1.trigger('click');
    button2.trigger('click');
  });

  test("#1172 - Clone attributes object", 2, function() {
    var View = Backbone.View.extend({
      attributes: {foo: 'bar'}
    });

    var view1 = new View({id: 'foo'});
    strictEqual(view1.el.id, 'foo');

    var view2 = new View();
    ok(!view2.el.id);
  });

  test("views stopListening", 0, function() {
    var View = Backbone.View.extend({
      initialize: function() {
        this.listenTo(this.model, 'all x', function(){ ok(false); });
        this.listenTo(this.collection, 'all x', function(){ ok(false); });
      }
    });

    var view = new View({
      model: new Backbone.Model,
      collection: new Backbone.Collection
    });

    view.stopListening();
    view.model.trigger('x');
    view.collection.trigger('x');
  });

  test("Provide function for el.", 2, function() {
    var View = Backbone.View.extend({
      el: function() {
        return "

";
      }
    });

    var view = new View;
    ok(view.$el.is('p'));
    ok(view.$el.has('a'));
  });

  test("events passed in options", 1, function() {
    var counter = 0;

    var View = Backbone.View.extend({
      el: '#testElement',
      increment: function() {
        counter++;
      }
    });

    var view = new View({
      events: {
        'click h1': 'increment'
      }
    });

    view.$('h1').trigger('click').trigger('click');
    equal(counter, 2);
  });

  test("remove", 2, function() {
    var view = new Backbone.View;
    document.body.appendChild(view.el);

    view.delegate('click', function() { ok(false); });
    view.listenTo(view, 'all x', function() { ok(false); });

    equal(view.remove(), view, '#remove returns the view instance');
    view.$el.trigger('click');
    view.trigger('x');

    // In IE8 and below, parentNode still exists but is not document.body.
    notEqual(view.el.parentNode, document.body);
  });

})();
<commit_msg>Test #setElement<commit_after>(function() {

  var view;

  module("Backbone.View", {

    setup: function() {
      view = new Backbone.View({
        id        : 'test-view',
        className : 'test-view',
        other     : 'non-special-option'
      });
    }

  });

  test("constructor", 3, function() {
    equal(view.el.id, 'test-view');
    equal(view.el.className, 'test-view');
    equal(view.el.other, void 0);
  });

  test("$", 2, function() {
    var view = new Backbone.View;
    view.setElement('
test
');
    var result = view.$('a b');

    strictEqual(result[0].innerHTML, 'test');
    ok(result.length === +result.length);
  });

  test("$el", 3, function() {
    var view = new Backbone.View;
    view.setElement('
test
');
    strictEqual(view.el.nodeType, 1);

    ok(view.$el instanceof Backbone.$);
    strictEqual(view.$el[0], view.el);
  });

  test("initialize", 1, function() {
    var View = Backbone.View.extend({
      initialize: function() {
        this.one = 1;
      }
    });

    strictEqual(new View().one, 1);
  });

  test("render", 1, function() {
    var view = new Backbone.View;
    equal(view.render(), view, '#render returns the view instance');
  });

  test("delegateEvents", 6, function() {
    var counter1 = 0, counter2 = 0;

    var view = new Backbone.View({el: '#testElement'});
    view.increment = function(){ counter1++; };
    view.$el.on('click', function(){ counter2++; });

    var events = {'click h1': 'increment'};

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 1);

    view.$('h1').trigger('click');
    equal(counter1, 2);
    equal(counter2, 2);

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 3);
    equal(counter2, 3);
  });

  test("delegate", 3, function() {
    var view = new Backbone.View({el: '#testElement'});
    view.delegate('click', 'h1', function() {
      ok(true);
    });
    view.delegate('click', function() {
      ok(true);
    });
    view.$('h1').trigger('click');

    equal(view.delegate(), view, '#delegate returns the view instance');
  });

  test("delegateEvents allows functions for callbacks", 3, function() {
    var view = new Backbone.View({el: '

'});
    view.counter = 0;

    var events = {
      click: function() {
        this.counter++;
      }
    };

    view.delegateEvents(events);
    view.$el.trigger('click');
    equal(view.counter, 1);

    view.$el.trigger('click');
    equal(view.counter, 2);

    view.delegateEvents(events);
    view.$el.trigger('click');
    equal(view.counter, 3);
  });

  test("delegateEvents ignore undefined methods", 0, function() {
    var view = new Backbone.View({el: '

'});
    view.delegateEvents({'click': 'undefinedMethod'});
    view.$el.trigger('click');
  });

  test("undelegateEvents", 7, function() {
    var counter1 = 0, counter2 = 0;

    var view = new Backbone.View({el: '#testElement'});
    view.increment = function(){ counter1++; };
    view.$el.on('click', function(){ counter2++; });

    var events = {'click h1': 'increment'};

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 1);

    view.undelegateEvents();
    view.$('h1').trigger('click');
    equal(counter1, 1);
    equal(counter2, 2);

    view.delegateEvents(events);
    view.$('h1').trigger('click');
    equal(counter1, 2);
    equal(counter2, 3);

    equal(view.undelegateEvents(), view, '#undelegateEvents returns the view instance');
  });

  test("undelegate", 1, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(false); });
    view.delegate('click', 'h1', function() { ok(false); });

    view.undelegate('click');

    view.$('h1').trigger('click');
    view.$el.trigger('click');

    equal(view.undelegate(), view, '#undelegate returns the view instance');
  });

  test("undelegate with passed handler", 1, function() {
    view = new Backbone.View({el: '#testElement'});
    var listener = function() { ok(false); };
    view.delegate('click', listener);
    view.delegate('click', function() { ok(true); });
    view.undelegate('click', listener);
    view.$el.trigger('click');
  });

  test("undelegate with selector", 2, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(true); });
    view.delegate('click', 'h1', function() { ok(false); });
    view.undelegate('click', 'h1');
    view.$('h1').trigger('click');
    view.$el.trigger('click');
  });

  test("undelegate with handler and selector", 2, function() {
    view = new Backbone.View({el: '#testElement'});
    view.delegate('click', function() { ok(true); });
    var handler = function(){ ok(false); };
    view.delegate('click', 'h1', handler);
    view.undelegate('click', 'h1', handler);
    view.$('h1').trigger('click');
    view.$el.trigger('click');
  });

  test("tagName can be provided as a string", 1, function() {
    var View = Backbone.View.extend({
      tagName: 'span'
    });

    equal(new View().el.tagName, 'SPAN');
  });

  test("tagName can be provided as a function", 1, function() {
    var View = Backbone.View.extend({
      tagName: function() {
        return 'p';
      }
    });

    ok(new View().$el.is('p'));
  });

  test("_ensureElement with DOM node el", 1, function() {
    var View = Backbone.View.extend({
      el: document.body
    });

    equal(new View().el, document.body);
  });

  test("_ensureElement with string el", 3, function() {
    var View = Backbone.View.extend({
      el: "body"
    });
    strictEqual(new View().el, document.body);

    View = Backbone.View.extend({
      el: "#testElement > h1"
    });
    strictEqual(new View().el, $("#testElement > h1").get(0));

    View = Backbone.View.extend({
      el: "#nonexistent"
    });
    ok(!new View().el);
  });

  test("with className and id functions", 2, function() {
    var View = Backbone.View.extend({
      className: function() {
        return 'className';
      },
      id: function() {
        return 'id';
      }
    });

    strictEqual(new View().el.className, 'className');
    strictEqual(new View().el.id, 'id');
  });

  test("with attributes", 2, function() {
    var View = Backbone.View.extend({
      attributes: {
        id: 'id',
        'class': 'class'
      }
    });

    strictEqual(new View().el.className, 'class');
    strictEqual(new View().el.id, 'id');
  });

  test("with attributes as a function", 1, function() {
    var View = Backbone.View.extend({
      attributes: function() {
        return {'class': 'dynamic'};
      }
    });

    strictEqual(new View().el.className, 'dynamic');
  });

  test("multiple views per element", 3, function() {
    var count = 0;
    var $el = $('

');

    var View = Backbone.View.extend({
      el: $el,
      events: {
        click: function() {
          count++;
        }
      }
    });

    var view1 = new View;
    $el.trigger("click");
    equal(1, count);

    var view2 = new View;
    $el.trigger("click");
    equal(3, count);

    view1.delegateEvents();
    $el.trigger("click");
    equal(5, count);
  });

  test("custom events", 2, function() {
    var View = Backbone.View.extend({
      el: $('body'),
      events: {
        "fake$event": function() { ok(true); }
      }
    });

    var view = new View;
    $('body').trigger('fake$event').trigger('fake$event');

    $('body').off('fake$event');
    $('body').trigger('fake$event');
  });

  test("#1048 - setElement uses provided object.", 2, function() {
    var $el = $('body');

    var view = new Backbone.View({el: $el});
    ok(view.$el === $el);

    view.setElement($el = $($el));
    ok(view.$el === $el);
  });

  test("#986 - Undelegate before changing element.", 1, function() {
    var button1 = $('<button></button>');
    var button2 = $('<button></button>');

    var View = Backbone.View.extend({
      events: {
        click: function(e) {
          ok(view.el === e.target);
        }
      }
    });

    var view = new View({el: button1});
    view.setElement(button2);

    button1.trigger('click');
    button2.trigger('click');
  });

  test("#1172 - Clone attributes object", 2, function() {
    var View = Backbone.View.extend({
      attributes: {foo: 'bar'}
    });

    var view1 = new View({id: 'foo'});
    strictEqual(view1.el.id, 'foo');

    var view2 = new View();
    ok(!view2.el.id);
  });

  test("views stopListening", 0, function() {
    var View = Backbone.View.extend({
      initialize: function() {
        this.listenTo(this.model, 'all x', function(){ ok(false); });
        this.listenTo(this.collection, 'all x', function(){ ok(false); });
      }
    });

    var view = new View({
      model: new Backbone.Model,
      collection: new Backbone.Collection
    });

    view.stopListening();
    view.model.trigger('x');
    view.collection.trigger('x');
  });

  test("Provide function for el.", 2, function() {
    var View = Backbone.View.extend({
      el: function() {
        return "

";
      }
    });

    var view = new View;
    ok(view.$el.is('p'));
    ok(view.$el.has('a'));
  });

  test("events passed in options", 1, function() {
    var counter = 0;

    var View = Backbone.View.extend({
      el: '#testElement',
      increment: function() {
        counter++;
      }
    });

    var view = new View({
      events: {
        'click h1': 'increment'
      }
    });

    view.$('h1').trigger('click').trigger('click');
    equal(counter, 2);
  });

  test("remove", 2, function() {
    var view = new Backbone.View;
    document.body.appendChild(view.el);

    view.delegate('click', function() { ok(false); });
    view.listenTo(view, 'all x', function() { ok(false); });

    equal(view.remove(), view, '#remove returns the view instance');
    view.$el.trigger('click');
    view.trigger('x');

    // In IE8 and below, parentNode still exists but is not document.body.
    notEqual(view.el.parentNode, document.body);
  });

  test("setElement", 3, function() {
    var view = new Backbone.View({
      events: {
        click: function() { ok(false); }
      }
    });
    view.events = {
      click: function() { ok(true); }
    };
    var oldEl = view.el;
    var $oldEl = view.$el;

    view.setElement(document.createElement('div'));

    $oldEl.click();
    view.$el.click();

    notEqual(oldEl, view.el);
    notEqual($oldEl, view.$el);
  });

})();
<|endoftext|>


<commit_before>// npm install command

var npm = require("../npm"),
  utils = require("./utils"),
  rm = require("./utils/rm-rf"),
  exec = require("./utils/exec"),
  chain = require("./utils/chain"),
  log = utils.log,
  fail = utils.fail,
  succeed = utils.succeed,
  bind = utils.bind,
  fetch = require("./utils/fetch"),
  sys = require("sys"),
  fs = require("fs"),
  path = require("path"),
  semver = require("./utils/semver"),
  mkdir = require("./utils/mkdir-p"),
  lifecycle = require("./utils/lifecycle"),
  readJson = require("./utils/read-json");

module.exports = install;

// cb called with (er, ok) args.
function install (tarball, cb) {

  // fetch the tarball
  if (tarball.match(/^https?:\/\//)) {
    log(tarball, "install");
    return fetchAndInstall(tarball, cb);
  }

  // install from a file.
  if (tarball.indexOf("file://") === 0) tarball = tarball.substr("file://".length);

  log(tarball, "install");

  var ROOT = npm.root,
    npmdir = npm.dir,
    tmp = npm.tmp,
    unpackTargetDir = path.join(
      // todo: use a sha1 of the url, and don't fetch if it's there already
      tmp, path.basename(tarball, ".tgz")),
    unpackTargetTgz = path.join(
      unpackTargetDir, "package.tgz"),
    pkg = {};

  // at this point, presumably the filesystem knows how to open it.
  chain(
    [fs, "stat", tarball],
    [mkdir, unpackTargetDir],
    [unpackTar, tarball, unpackTargetDir],

    // read the json and then save it
    [function (cb) {
      readJson(path.join(unpackTargetDir, "package.json"), function (er, data) {
        if (er) return cb(er, data);
        // save this just for this install
        npm.set(data._npmKey, data);
        pkg.data = data;
        cb(null, data);
      });
    }],

    // move to ROOT/.npm/{name}/{version}/package
    [moveIntoPlace, unpackTargetDir, pkg],

    // link deps into ROOT/.npm/{name}/{version}/dependencies
    // this is then added to require.paths, but ONLY for this package's main module.
    // of course, they could do require(".npm/foo/1.0.3/dependencies/bar") to import
    // whichever version of bar is currently satisfying foo-1.0.3's need.
    // For now, all dependencies must already be installed, or the install fails.
    [resolveDependencies, pkg],

    // generate ROOT/.npm/{name}/{version}/main.js
    [createMain, pkg],

    // symlink ROOT/{name}-{version}.js to ROOT/.npm/{name}/{version}/main.js
    [linkMain, pkg],

    // run the "make", if there is one.
    // [runMake, pkg],

    // run the "install" lifecycle script
    [lifecycle, pkg, "install"],

    // symlink ROOT/{name}-{version}/ to ROOT/.npm/{name}/{version}/{lib}
    [linkLib, pkg],

    // success!
    [function (cb) {
      log("Successfully installed "+pkg.data._npmKey, "WIN!");
      cb();
    }],

    cb
  );
};

// make sure that all the dependencies have been installed.
// todo: if they're not, then install them, and come back here.
function resolveDependencies (pkg, topCb) {
  log("starting...", "resolveDependencies");
  pkg = pkg && pkg.data;
  if (!pkg) return cb(new Error("Package not found to resolve dependencies"));
  // link foo-1.0.3 to ROOT/.npm/{pkg}/{ver}/dependencies/foo

  var found = [];
  chain(
    [mkdir, path.join(npm.dir, pkg.name, pkg.version, "dependencies")],
    [function (cb) {
      if (!pkg.dependencies) return topCb();
      // don't create anything until they're all verified.
      var reqs = [];
      for (var i in pkg.dependencies) reqs.push({name:i, ver:pkg.dependencies[i]});
      if (!reqs.length) return topCb();

      (function R (req) {
        if (!req) return cb();
        log(req.name+" "+req.ver, "required");
        // see if we have this thing installed.
        fs.readdir(path.join(npm.dir, req.name), function (er, versions) {
          if (er) return cb(new Error(
            "Required package: "+req.name+"("+req.ver+") not found."));
          // TODO: Get the "stable" version if there is one.
          // Look that up from the registry.
          versions.sort(semver.compare);
          var i = versions.length;
          while (i--) {
            if (semver.satisfies(versions[i], req.ver)) {
              found.push({name:req.name, ver:versions[i]});
              return R(reqs.pop());
            }
          }
          return cb(new Error(
            "Required package: "+req.name+"("+req.ver+") not found. "+
            "(Found: "+JSON.stringify(versions)+")"));
        });
      })(reqs.pop());
    }],
    // for all the found ones, make a note that this package depends on it
    // this is important for safe uninstallation
    [function (cb) {
      var deps = found.slice(0);
      (function L (dep) {
        if (!dep) return cb();
        // link from ROOT/.npm/{dep.name}/{dep.version}/dependents/{pkg}-{ver}
        // to the package folder being installed.
        var dependents = path.join(npm.dir, dep.name, dep.version, "dependents"),
          to = path.join(dependents, pkg.name + "-" + pkg.version),
          from = path.join(npm.dir, pkg.name, pkg.version);
        chain(
          [mkdir, dependents],
          [fs, "symlink", from, to],
          cb
        );
      })(deps.pop());
    }],
    [function (cb) {
      // link in all the found reqs.
      (function L (req) {
        if (!req) return cb();

        log(req.name+ "-" +req.ver, "found");

        // link ROOT/.npm/{pkg}/{ver}/dependencies/{req.name} to
        // ROOT/{req.name}-{req.version}
        // both the JS and the folder, if they're there
        // then try again with the next req.
        pkg.link = pkg.link || {};
        var to = path.join(npm.dir, pkg.name, pkg.version, "dependencies", req.name),
          linkDepTo = (req.name in pkg.link)
            ? path.join(npm.dir, pkg.name, pkg.version, "package", pkg.link[req.name])
            : null,
          from = path.join(npm.root, req.name + "-" + req.ver);
        function link (cb) {
          fs.stat(from, function (er, stat) {
            if (er) return cb();
            fs.symlink(from, to, function (er) {
              if (er) return cb(er);
              if (linkDepTo) {
                mkdir(path.dirname(linkDepTo), function (er) {
                  if (er) return cb(er);
                  fs.symlink(from, linkDepTo, cb);
                });
              }
              else cb();
            });
          });
        };

        chain([link], [function (cb) {
          from += ".js";
          to += ".js";
          if (linkDepTo) linkDepTo += ".js";
          cb();
        }], [link],
        function (er) { if (er) return topCb(er); L(found.pop()) });
      })(found.pop());
    }],
    topCb
  );
}

// move to ROOT/.npm/{name}/{version}/package
function moveIntoPlace (dir, pkg, cb) {
  pkg = pkg.data;
  if (!pkg.name || !pkg.version) {
    return cb(new Error("Name or version not found in package info."));
  }
  var target = path.join(npm.dir, pkg.name, pkg.version);

  log("to: "+pkg.name+"-"+pkg.version+" from: "+dir, "moveIntoPlace");
  chain(
    [function (cb) {
      path.exists(target, function (e) {
        log((e?"remove":"creating") + " " +target, "moveIntoPlace");
        if (e) rm(target, function (er, ok) {
          if (er) {
            log("could not remove " + target, "moveIntoPlace");
            cb(new Error(target+" exists, and can't be removed"));
          } else {
            log("unlinked "+target,"moveIntoPlace");
            cb();
          };
        });
        else cb();
      });
    }],
    [mkdir, target],
    [function (cb) { pkg._npmPackage = target = path.join(target, "package"); cb() }],
    [function (cb) { fs.rename(dir, target, cb) }],
    [function (cb) { log("done", "moveIntoPlace"); cb() }],
    cb
  );
};

function fetchAndInstall (tarball, cb) {
  mkdir(npm.tmp, function (er, ok) {
    if (er) return cb(er, ok);
    var target = path.join(npm.tmp, tarball.replace(/[^a-zA-Z0-9]/g, "-")+"-"+
                           Date.now()+"-"+Math.random()+".tgz");

    fetch(tarball, target, function (er, ok) {
      if (er) return cb(er, ok);
      chain(
        [install, target],
        // clean up
        [function (cb) { log(target, "deleting"); cb() }],
        [fs, "unlink", target],
        cb
      );
    });
  });
};

function unpackTar (tarball, unpackTarget, cb) {
  exec("tar", ["xzvf", tarball, "--strip", "1", "-C", unpackTarget], cb);
};

function createMain (pkg,cb) {
  pkg = pkg.data;
  if (!pkg.main) return cb();

  var code =
      "// generated by npm, please don't touch!\n"+
      "require.paths.unshift("+
        JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "dependencies"))+
      ");"+
      "module.exports = require("+
        JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "package", pkg.main)) +
      ");"+
      "require.paths.shift();"+
      "\n",
    proxyFile = path.join(npm.dir, pkg.name, pkg.version, "main.js");

  fs.writeFile(proxyFile, code, "ascii", cb);
};

// symlink ROOT/{name}-{version}/ to ROOT/.npm/{name}/{version}/{lib}
function linkLib (pkg, cb) {
  pkg = pkg.data;
  var lib = pkg.directories && pkg.directories.lib || pkg.lib || false;
    defLib = (lib === false);
  if (defLib) lib = "lib";

  var from = path.join(npm.dir, pkg.name, pkg.version, "package", lib),
    toInternal = path.join(npm.dir, pkg.name, pkg.version, "lib"),
    to = path.join(npm.root, pkg.name+"-"+pkg.version);

  log("from: "+from, "linkLib");
  log("to: "+to, "linkLib");

  function doLink (er) {
    if (er) return cb(er);
    fs.symlink(from, toInternal, function (er) {
      if (er) return cb(er);
      fs.symlink(toInternal, to, cb);
    });
  }

  fs.stat(from, function (er, s) {
    if (er) return (!defLib) ? cb(new Error("Libs dir not found "+from)) : cb();
    if (!s.isDirectory()) {
      if (!defLib) cb(new Error("Libs dir not a dir: "+lib));
      else cb();
    } else {
      // make sure that it doesn't already exist.  If so, rm it.
      fs.lstat(to, function (er, s) {
        if (!er) fs.unlink(to, doLink);
        else doLink();
      })
    }
  });
};

function linkMain (pkg, cb) {
  pkg = pkg.data;
  if (!pkg.main) return;
  var
    from = path.join(npm.dir, pkg.name, pkg.version, "main.js"),
    to = path.join(npm.root, pkg.name+"-"+pkg.version+".js");
  path.exists(to, function (e) {
    if (e) cb();
    else fs.symlink(from, to, cb);
  });
};

function runMake (pkg, cb) {
  pkg = pkg.data;
  if (!pkg.make) return cb();
  log(pkg.make+" (wd: "+pkg._npmPackage+")", "runMake");
  process.chdir(pkg._npmPackage);
  sys.exec(pkg.make, function (er, ok, stderr) {
    if (er) cb(er, ok, stderr);
    else {
      ok && log(ok, "runMake");
      stderr && log(stderr, "runMake");
      cb(null, ok, stderr);
    }
  });
};
<commit_msg>Remove the dependent link if it's already present.<commit_after>// npm install command

var npm = require("../npm"),
  utils = require("./utils"),
  rm = require("./utils/rm-rf"),
  exec = require("./utils/exec"),
  chain = require("./utils/chain"),
  log = utils.log,
  fail = utils.fail,
  succeed = utils.succeed,
  bind = utils.bind,
  fetch = require("./utils/fetch"),
  sys = require("sys"),
  fs = require("fs"),
  path = require("path"),
  semver = require("./utils/semver"),
  mkdir = require("./utils/mkdir-p"),
  lifecycle = require("./utils/lifecycle"),
  readJson = require("./utils/read-json");

module.exports = install;

// cb called with (er, ok) args.
function install (tarball, cb) {

  // fetch the tarball
  if (tarball.match(/^https?:\/\//)) {
    log(tarball, "install");
    return fetchAndInstall(tarball, cb);
  }

  // install from a file.
  if (tarball.indexOf("file://") === 0) tarball = tarball.substr("file://".length);

  log(tarball, "install");

  var ROOT = npm.root,
    npmdir = npm.dir,
    tmp = npm.tmp,
    unpackTargetDir = path.join(
      // todo: use a sha1 of the url, and don't fetch if it's there already
      tmp, path.basename(tarball, ".tgz")),
    unpackTargetTgz = path.join(
      unpackTargetDir, "package.tgz"),
    pkg = {};

  // at this point, presumably the filesystem knows how to open it.
  chain(
    [fs, "stat", tarball],
    [mkdir, unpackTargetDir],
    [unpackTar, tarball, unpackTargetDir],

    // read the json and then save it
    [function (cb) {
      readJson(path.join(unpackTargetDir, "package.json"), function (er, data) {
        if (er) return cb(er, data);
        // save this just for this install
        npm.set(data._npmKey, data);
        pkg.data = data;
        cb(null, data);
      });
    }],

    // move to ROOT/.npm/{name}/{version}/package
    [moveIntoPlace, unpackTargetDir, pkg],

    // link deps into ROOT/.npm/{name}/{version}/dependencies
    // this is then added to require.paths, but ONLY for this package's main module.
    // of course, they could do require(".npm/foo/1.0.3/dependencies/bar") to import
    // whichever version of bar is currently satisfying foo-1.0.3's need.
    // For now, all dependencies must already be installed, or the install fails.
    [resolveDependencies, pkg],

    // generate ROOT/.npm/{name}/{version}/main.js
    [createMain, pkg],

    // symlink ROOT/{name}-{version}.js to ROOT/.npm/{name}/{version}/main.js
    [linkMain, pkg],

    // run the "make", if there is one.
    // [runMake, pkg],

    // run the "install" lifecycle script
    [lifecycle, pkg, "install"],

    // symlink ROOT/{name}-{version}/ to ROOT/.npm/{name}/{version}/{lib}
    [linkLib, pkg],

    // success!
    [function (cb) {
      log("Successfully installed "+pkg.data._npmKey, "WIN!");
      cb();
    }],

    cb
  );
};

// make sure that all the dependencies have been installed.
// todo: if they're not, then install them, and come back here.
function resolveDependencies (pkg, topCb) {
  log("starting...", "resolveDependencies");
  pkg = pkg && pkg.data;
  if (!pkg) return cb(new Error("Package not found to resolve dependencies"));
  // link foo-1.0.3 to ROOT/.npm/{pkg}/{ver}/dependencies/foo

  var found = [];
  chain(
    [mkdir, path.join(npm.dir, pkg.name, pkg.version, "dependencies")],
    [function (cb) {
      if (!pkg.dependencies) return topCb();
      // don't create anything until they're all verified.
      var reqs = [];
      for (var i in pkg.dependencies) reqs.push({name:i, ver:pkg.dependencies[i]});
      if (!reqs.length) return topCb();

      (function R (req) {
        if (!req) return cb();
        log(req.name+" "+req.ver, "required");
        // see if we have this thing installed.
        fs.readdir(path.join(npm.dir, req.name), function (er, versions) {
          if (er) return cb(new Error(
            "Required package: "+req.name+"("+req.ver+") not found."));
          // TODO: Get the "stable" version if there is one.
          // Look that up from the registry.
          versions.sort(semver.compare);
          var i = versions.length;
          while (i--) {
            if (semver.satisfies(versions[i], req.ver)) {
              found.push({name:req.name, ver:versions[i]});
              return R(reqs.pop());
            }
          }
          return cb(new Error(
            "Required package: "+req.name+"("+req.ver+") not found. "+
            "(Found: "+JSON.stringify(versions)+")"));
        });
      })(reqs.pop());
    }],
    // for all the found ones, make a note that this package depends on it
    // this is important for safe uninstallation
    [function (cb) {
      var deps = found.slice(0);
      (function L (dep) {
        if (!dep) return cb();
        // link from ROOT/.npm/{dep.name}/{dep.version}/dependents/{pkg}-{ver}
        // to the package folder being installed.
        var dependents = path.join(npm.dir, dep.name, dep.version, "dependents"),
          to = path.join(dependents, pkg.name + "-" + pkg.version),
          from = path.join(npm.dir, pkg.name, pkg.version);
        chain(
          [mkdir, dependents],
          [rm, to], // should be rare
          [fs, "symlink", from, to],
          cb
        );
      })(deps.pop());
    }],
    [function (cb) {
      // link in all the found reqs.
      (function L (req) {
        if (!req) return cb();

        log(req.name+ "-" +req.ver, "found");

        // link ROOT/.npm/{pkg}/{ver}/dependencies/{req.name} to
        // ROOT/{req.name}-{req.version}
        // both the JS and the folder, if they're there
        // then try again with the next req.
        pkg.link = pkg.link || {};
        var to = path.join(npm.dir, pkg.name, pkg.version, "dependencies", req.name),
          linkDepTo = (req.name in pkg.link)
            ? path.join(npm.dir, pkg.name, pkg.version, "package", pkg.link[req.name])
            : null,
          from = path.join(npm.root, req.name + "-" + req.ver);
        function link (cb) {
          fs.stat(from, function (er, stat) {
            if (er) return cb();
            fs.symlink(from, to, function (er) {
              if (er) return cb(er);
              if (linkDepTo) {
                mkdir(path.dirname(linkDepTo), function (er) {
                  if (er) return cb(er);
                  fs.symlink(from, linkDepTo, cb);
                });
              }
              else cb();
            });
          });
        };

        chain([link], [function (cb) {
          from += ".js";
          to += ".js";
          if (linkDepTo) linkDepTo += ".js";
          cb();
        }], [link],
        function (er) { if (er) return topCb(er); L(found.pop()) });
      })(found.pop());
    }],
    topCb
  );
}

// move to ROOT/.npm/{name}/{version}/package
function moveIntoPlace (dir, pkg, cb) {
  pkg = pkg.data;
  if (!pkg.name || !pkg.version) {
    return cb(new Error("Name or version not found in package info."));
  }
  var target = path.join(npm.dir, pkg.name, pkg.version);

  log("to: "+pkg.name+"-"+pkg.version+" from: "+dir, "moveIntoPlace");
  chain(
    [function (cb) {
      path.exists(target, function (e) {
        log((e?"remove":"creating") + " " +target, "moveIntoPlace");
        if (e) rm(target, function (er, ok) {
          if (er) {
            log("could not remove " + target, "moveIntoPlace");
            cb(new Error(target+" exists, and can't be removed"));
          } else {
            log("unlinked "+target,"moveIntoPlace");
            cb();
          };
        });
        else cb();
      });
    }],
    [mkdir, target],
    [function (cb) { pkg._npmPackage = target = path.join(target, "package"); cb() }],
    [function (cb) { fs.rename(dir, target, cb) }],
    [function (cb) { log("done", "moveIntoPlace"); cb() }],
    cb
  );
};

function fetchAndInstall (tarball, cb) {
  mkdir(npm.tmp, function (er, ok) {
    if (er) return cb(er, ok);
    var target = path.join(npm.tmp, tarball.replace(/[^a-zA-Z0-9]/g, "-")+"-"+
                           Date.now()+"-"+Math.random()+".tgz");

    fetch(tarball, target, function (er, ok) {
      if (er) return cb(er, ok);
      chain(
        [install, target],
        // clean up
        [function (cb) { log(target, "deleting"); cb() }],
        [fs, "unlink", target],
        cb
      );
    });
  });
};

function unpackTar (tarball, unpackTarget, cb) {
  exec("tar", ["xzvf", tarball, "--strip", "1", "-C", unpackTarget], cb);
};

function createMain (pkg,cb) {
  pkg = pkg.data;
  if (!pkg.main) return cb();

  var code =
      "// generated by npm, please don't touch!\n"+
      "require.paths.unshift("+
        JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "dependencies"))+
      ");"+
      "module.exports = require("+
        JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "package", pkg.main)) +
      ");"+
      "require.paths.shift();"+
      "\n",
    proxyFile = path.join(npm.dir, pkg.name, pkg.version, "main.js");

  fs.writeFile(proxyFile, code, "ascii", cb);
};

// symlink ROOT/{name}-{version}/ to ROOT/.npm/{name}/{version}/{lib}
function linkLib (pkg, cb) {
  pkg = pkg.data;
  var lib = pkg.directories && pkg.directories.lib || pkg.lib || false;
    defLib = (lib === false);
  if (defLib) lib = "lib";

  var from = path.join(npm.dir, pkg.name, pkg.version, "package", lib),
    toInternal = path.join(npm.dir, pkg.name, pkg.version, "lib"),
    to = path.join(npm.root, pkg.name+"-"+pkg.version);

  log("from: "+from, "linkLib");
  log("to: "+to, "linkLib");

  function doLink (er) {
    if (er) return cb(er);
    fs.symlink(from, toInternal, function (er) {
      if (er) return cb(er);
      fs.symlink(toInternal, to, cb);
    });
  }

  fs.stat(from, function (er, s) {
    if (er) return (!defLib) ? cb(new Error("Libs dir not found "+from)) : cb();
    if (!s.isDirectory()) {
      if (!defLib) cb(new Error("Libs dir not a dir: "+lib));
      else cb();
    } else {
      // make sure that it doesn't already exist.  If so, rm it.
      fs.lstat(to, function (er, s) {
        if (!er) fs.unlink(to, doLink);
        else doLink();
      })
    }
  });
};

function linkMain (pkg, cb) {
  pkg = pkg.data;
  if (!pkg.main) return;
  var
    from = path.join(npm.dir, pkg.name, pkg.version, "main.js"),
    to = path.join(npm.root, pkg.name+"-"+pkg.version+".js");
  path.exists(to, function (e) {
    if (e) cb();
    else fs.symlink(from, to, cb);
  });
};

function runMake (pkg, cb) {
  pkg = pkg.data;
  if (!pkg.make) return cb();
  log(pkg.make+" (wd: "+pkg._npmPackage+")", "runMake");
  process.chdir(pkg._npmPackage);
  sys.exec(pkg.make, function (er, ok, stderr) {
    if (er) cb(er, ok, stderr);
    else {
      ok && log(ok, "runMake");
      stderr && log(stderr, "runMake");
      cb(null, ok, stderr);
    }
  });
};
<|endoftext|>


<commit_before>
// npm install <pkg> <pkg> <pkg>
// npm install <pkg@version> <pkg@"1.0.0 - 1.99.99"> <pkg[@latest]> <pkg@tagname>

// 1. fetch the data for that package/tag into the cache
// 2. if it has any dependents, which are not yet installed,
// then add those to the list, and fetch their data.
// 3. when all the pkgs are fetched to the cache, and we have a set
// of packages that are either installed or fetched which
// will satisfy everyone's dependencies, then untar into the
// target directories for each of them.
// 4. build each of the packages that aren't already installed

module.exports = install

install.usage = "npm install <tarball file>"
              + "\nnpm install <tarball url>"
              + "\nnpm install <folder>"
              + "\nnpm install <pkg>"
              + "\nnpm install <pkg>@<tag>"
              + "\nnpm install <pkg>@<version>"
              + "\nnpm install <pkg>@<version range>"
              + "\n\nCan specify one or more: npm install ./foo.tgz bar@stable /some/folder"
              + "\nInstalls '.' if no argument supplied"

install.completion = function (args, index, cb) {
  var remotePkgs = require("./utils/completion/remote-packages")
  remotePkgs(args, index, true, true, true, cb)
}

var registry = require("./utils/registry")
  , npm = require("../npm")
  , readInstalled = require("./utils/read-installed")
  , installedPackages
  , semver = require("semver")
  , url = require("url")
  , fetch = require("./utils/fetch")
  , readJson = require("./utils/read-json")
  , log = require("./utils/log")
  , path = require("path")
  , fs = require("./utils/graceful-fs")
  , cache = require("./cache")
  , asyncMap = require("./utils/async-map")
  , chain = require("./utils/chain")

function install (pkglist, cb) {
  log.verbose(pkglist, "install")
  if (pkglist.length === 0) pkglist = ["."]
  // it's helpful to know what we have already
  if (!installedPackages) return readInstalled([], function (er, data) {
    if (er) return cb(er)
    installedPackages = data || {}
    install(pkglist, cb)
  })

  log.verbose(pkglist, "install pkglist")
  var mustInstall = npm.config.get("must-install") ? pkglist.slice(0) : []

  // three lists: "pkglist", "next", and "reg"
  // asyncMap over the "left" list: for each "it"
  //   find out what it is
  //   if it's version/range installed or on "reg" list, continue.
  //   if it's a url, fetch to cache and add the name/version to "next"
  //   if it's a tag, fetch the json, add the version to "next"
  //   if it's a version(range) not installed, then fetch the json,
  //     add url to "next"
  //   if it's a specific version in cache, then unpack, add to "reg"
  //     list, add its deps to "next"
  // if the "next" list is not empty, then pkglist=next,next=[], and repeat.
  // if it is, then build all the "reg" folders.

  var reg = Object.create(installedPackages)
    , seen = {}
    , bundles = {}
  log.verbose(mustInstall, "must install")
  asyncMap(pkglist, function (pkg, cb) {
    install_(pkg, reg, seen, mustInstall.indexOf(pkg) !== -1,
             pkglist, bundles, cb)
  }, function (er) {
    if (er) return cb(er)
    buildAll(reg, bundles, cb)
  })
}

// call the cb with the "next" thing(s) to look up for this one, or nothing
function install_ (pkg, reg, seen, mustHave, pkglist, bundles, cb) {
  log.verbose(pkg, "install_")
  if (seen[pkg]) return cb() // repeat, skip it
  seen[pkg] = true

  // it's a local thing or a url if it has a / in it.
  if (pkg.indexOf("/") !== -1 || pkg === ".") {
    log.silly(pkg, "install local")
    return cache.add(pkg, finisher(pkg, reg, pkglist, bundles, cb))
  }

  // now we know it's not a URL or file,
  // so handle it like a tag, version, or range.
  pkg = pkg.split("@")
  var name = pkg[0]
    , defTag = npm.config.get("tag")
    , ver = pkg.slice(1).join("@").trim() || defTag
    , range = semver.validRange(ver)
    , exact = semver.valid(ver)
    , tag = !exact && !range && range !== "" && ver
  log.verbose([pkg, mustHave], "must install?")
  pkg = pkg.join("@")
  seen[name+"@"+ver] = true

  // if there is a satisfying version already, then simply move on.
  if (!tag && findSatisfying(pkg, name, range, mustHave, reg)) {
    return cb()
  }

  // at this point, assume that it has to be installed.
  if (exact) {
    log.verbose("exact", pkg)
    // just pull the data out of the cache to ensure it's there
    return cache.read(name, exact, finisher(pkg, reg, pkglist, bundles, cb))
  }

  getData(name, function (er, data) {
    if (er) return cb(er)
    log.silly(data, pkg)
    if (tag) {
      log.verbose(tag, pkg+" tag")
      var tags = data["dist-tags"]
      if (!tags[tag]) cb(new Error(
        "Tag not found: "+data.name+"@"+tag
        +"\nValid install targets for "+data.name+": "
        +installTargets(data)))
      install_(data.name+"@"+tags[tag], reg, seen, mustHave
              , pkglist, bundles, cb)
    } else {
      log(pkg, "range")
      // prefer the default tag version.
      var defTag = npm.config.get("tag")
        , satis
      defTag = defTag && data["dist-tags"] && data["dist-tags"][defTag]
      if (semver.satisfies(defTag, range)) satis = defTag
      else satis = semver.maxSatisfying(Object.keys(data.versions), range)

      if (!satis) return cb(new Error(
        "No satisfying version found for '"+data.name+"'@'"+range+"'"
        +"\nValid install targets for "+data.name+": "
        +installTargets(data)))
      install_(data.name+"@"+satis, reg, seen, mustHave
              , pkglist, bundles, cb)
    }
  })
}
function installTargets (data) {
  return Object.keys(data["dist-tags"] || {})
    .concat(Object.keys(data.versions))
    .map(JSON.stringify)
    .join(", ") || "(none)"
}

function getData (name, cb) {
  var data = npm.get(name)
  if (data && data["dist-tags"]) return cb(null, data)
  registry.get(name, function (er, data) {
    if (er) return cb(er)
    if (!data._id) data._id = name
    for (var ver in data.versions) {
      try {
        readJson.processJson(data.versions[ver])
      } catch (ex) {
        log(data.name+"@"+ver, "ignoring invalid version")
        delete data.versions[ver]
      }
    }
    if (!data["dist-tags"]) return cb(new Error(
      (data._id || data.name) +
      " Invalid package data. Lacking 'dist-tags' hash."))
    filterNodeVersion(data)
    npm.set(data)
    cb(null, data)
  })
}
// see if there is a satisfying version already
function findSatisfying (pkg, name, range, mustHave, reg) {
  if (mustHave) return null
  return semver.maxSatisfying
         ( Object.keys(reg[name] || {})
           .concat(Object.keys(Object.getPrototypeOf(reg[name] || {})))
         , range
         )
}

function finisher (pkg, reg, pkglist, bundles, cb) {
    return function (er, data) {
  if (!cb) throw new Error("no cb in finisher")
  if (er) return log.er(cb, "Error installing "+pkg)(er)
  if (!data._engineSupported) return cb(
    data.name+"@"+data.version+" not compatible with your version of node\n"+
    "Requires: node@"+data.engines.node+"\n"+
    "You have: node@"+process.version)

  if (!reg.hasOwnProperty(data.name)) {
    reg[data.name] = Object.create(reg[data.name] || Object.prototype)
  }
  reg[data.name][data.version] = data

  // also add the dependencies.
  // any dependencies that are URLs get added to a bundle list
  if (!pkglist) pkglist = []
  getDeps(data, function (er, deps) {
    if (er) return cb(er)
    if (!Array.isArray(pkglist)) pkglist = [pkglist]
    pkglist.push.apply(pkglist, Object.keys(deps).map(function (dep) {
      var v = deps[dep].trim()
        , d = dep.trim()
        , u = url.parse(v)
      log.silly(u, "url.parse "+v)
      if (u && u.protocol && u.host) {
        bundles[data._id] = bundles[data._id] || []
        bundles[data._id].push(u.href)
        return false
      }
      return v ? d + "@" + v : d
    }).filter(function (dep) { return dep }))
    cb()
  })
}}

function getDeps (data, cb) {
  var deps = data.dependencies || {}
    , devDeps = data.devDependencies || {}
  if (npm.config.get("dev")) {
    Object.keys(devDeps).forEach(function (d) { deps[d] = devDeps[d] })
  }
  // now see if any of them are already bundled.
  // if so, omit them from the list.
  var bundle = path.join( npm.cache, data.name, data.version
                        , "package", "node_modules" )
  fs.readdir(bundle, function (er, bundles) {
    bundles = bundles || []
    bundles.forEach(function (b) { delete deps[b] })
    cb(null, deps)
  })
}

function filterNodeVersion (data) {
  var supported = []
  Object.keys(data.versions).forEach(function (v) {
    if (!data.versions[v]._engineSupported) {
      log.verbose(data.versions[v]._id, "not supported on node@"+process.version)
      delete data.versions[v]
    } else supported.push(data.versions[v]._id)
  })
  if (!supported.length) {
    log.warn(data._id, "Not supported on node@"+process.version)
  } else log.verbose(supported, "Supported versions")
  // might have deleted the special "latest" tag.  if so, replace it.
  var v = data["dist-tags"].latest
  if (v && !data.versions[v] && supported.length) {
    data["dist-tags"].latest = Object.keys(data.versions)
      .sort(semver.compare).pop()
    log("not supported by node@"+process.version,
        "latest = "+data.name+"@"+v)
  }
}

function buildAll (installed, bundles, cb) {
  var list = []
  Object.keys(installed).forEach(function (i) {
    Object.keys(installed[i]).forEach(function (v) {
      list.push([i, v])
    })
  })
  log.verbose(list, "install list")
  cb = rollbackFailure(list, cb)
  if (!list.length) return log.info("Nothing to do", "install", cb)
  var buildList = []

  asyncMap(list, function (i, cb) {
    var target = path.join(npm.dir, i[0], i[1])
    cache.unpack( i[0], i[1], target
                , null, null // don't chmod anything here.  just as-is.
                , npm.config.get("user")
                , npm.config.get("group"), function (er) {
      if (!er) buildList.push(target)
      cb(er)
    })
  }, function (er) {
    if (er) return cb(er)
    log.verbose(list.join("\n"), "unpacked, building")
    // now everything's been unpacked.
    // install any bundles that were requested with a url dep.
    // MUST install ALL bundles before building anything
    log.silly(bundles, "installing bundles")
    chain( [installBundles, bundles]
         , [npm.commands.build, buildList]
         , cb )
  })
}

function installBundles (bundles, cb) {
  // bundles is {name:[some, pkg, urls],...}
  // bundle install each of them one at at time.
  // This global config state thing sucks a lot. Need
  // a more clean FP-style approach to the whole bundle thing.
  var bundlePkgs = Object.keys(bundles)
  if (!bundlePkgs.length) return cb()
  chain(bundlePkgs.map(function (host) { return function (cb) {
    var urls = bundles[host]
      , _ = host.split("@")
      , name = _.shift()
      , ver = _.join("@")
      , pkgDir = path.join(npm.dir, name, ver, "package")
    log.info(urls, "bundling for "+host)
    npm.commands.bundle(["install"].concat(urls), pkgDir, cb)
  }}).concat(cb))
}

function rollbackFailure (installList, cb) { return function (er) {
  if (!er) return log.verbose(installList.map(function (i) {
    return i.join("@")
  }).join("\n"), "installed", cb)
  // error happened, roll back
  installList = installList.map(function (p) {
    return p.join('@')
  })
  npm.ROLLBACK = true
  log.error(er, "install failed")
  log("rollback", "install failed")
  log(installList, "uninstall")
  return npm.commands.uninstall
    ( installList
    , function (er_) {
        if (er_) log.error(er_, "rollback failed")
        else log("rolled back", "install failed")
        cb(er)
      }
    )
}}
<commit_msg>Closes GH-449 Better message when npm version conflicts<commit_after>
// npm install <pkg> <pkg> <pkg>
// npm install <pkg@version> <pkg@"1.0.0 - 1.99.99"> <pkg[@latest]> <pkg@tagname>

// 1. fetch the data for that package/tag into the cache
// 2. if it has any dependents, which are not yet installed,
// then add those to the list, and fetch their data.
// 3. when all the pkgs are fetched to the cache, and we have a set
// of packages that are either installed or fetched which
// will satisfy everyone's dependencies, then untar into the
// target directories for each of them.
// 4. build each of the packages that aren't already installed

module.exports = install

install.usage = "npm install <tarball file>"
              + "\nnpm install <tarball url>"
              + "\nnpm install <folder>"
              + "\nnpm install <pkg>"
              + "\nnpm install <pkg>@<tag>"
              + "\nnpm install <pkg>@<version>"
              + "\nnpm install <pkg>@<version range>"
              + "\n\nCan specify one or more: npm install ./foo.tgz bar@stable /some/folder"
              + "\nInstalls '.' if no argument supplied"

install.completion = function (args, index, cb) {
  var remotePkgs = require("./utils/completion/remote-packages")
  remotePkgs(args, index, true, true, true, cb)
}

var registry = require("./utils/registry")
  , npm = require("../npm")
  , readInstalled = require("./utils/read-installed")
  , installedPackages
  , semver = require("semver")
  , url = require("url")
  , fetch = require("./utils/fetch")
  , readJson = require("./utils/read-json")
  , log = require("./utils/log")
  , path = require("path")
  , fs = require("./utils/graceful-fs")
  , cache = require("./cache")
  , asyncMap = require("./utils/async-map")
  , chain = require("./utils/chain")

function install (pkglist, cb) {
  log.verbose(pkglist, "install")
  if (pkglist.length === 0) pkglist = ["."]
  // it's helpful to know what we have already
  if (!installedPackages) return readInstalled([], function (er, data) {
    if (er) return cb(er)
    installedPackages = data || {}
    install(pkglist, cb)
  })

  log.verbose(pkglist, "install pkglist")
  var mustInstall = npm.config.get("must-install") ? pkglist.slice(0) : []

  // three lists: "pkglist", "next", and "reg"
  // asyncMap over the "left" list: for each "it"
  //   find out what it is
  //   if it's version/range installed or on "reg" list, continue.
  //   if it's a url, fetch to cache and add the name/version to "next"
  //   if it's a tag, fetch the json, add the version to "next"
  //   if it's a version(range) not installed, then fetch the json,
  //     add url to "next"
  //   if it's a specific version in cache, then unpack, add to "reg"
  //     list, add its deps to "next"
  // if the "next" list is not empty, then pkglist=next,next=[], and repeat.
  // if it is, then build all the "reg" folders.

  var reg = Object.create(installedPackages)
    , seen = {}
    , bundles = {}
  log.verbose(mustInstall, "must install")
  asyncMap(pkglist, function (pkg, cb) {
    install_(pkg, reg, seen, mustInstall.indexOf(pkg) !== -1,
             pkglist, bundles, cb)
  }, function (er) {
    if (er) return cb(er)
    buildAll(reg, bundles, cb)
  })
}

// call the cb with the "next" thing(s) to look up for this one, or nothing
function install_ (pkg, reg, seen, mustHave, pkglist, bundles, cb) {
  log.verbose(pkg, "install_")
  if (seen[pkg]) return cb() // repeat, skip it
  seen[pkg] = true

  // it's a local thing or a url if it has a / in it.
  if (pkg.indexOf("/") !== -1 || pkg === ".") {
    log.silly(pkg, "install local")
    return cache.add(pkg, finisher(pkg, reg, pkglist, bundles, cb))
  }

  // now we know it's not a URL or file,
  // so handle it like a tag, version, or range.
  pkg = pkg.split("@")
  var name = pkg[0]
    , defTag = npm.config.get("tag")
    , ver = pkg.slice(1).join("@").trim() || defTag
    , range = semver.validRange(ver)
    , exact = semver.valid(ver)
    , tag = !exact && !range && range !== "" && ver
  log.verbose([pkg, mustHave], "must install?")
  pkg = pkg.join("@")
  seen[name+"@"+ver] = true

  // if there is a satisfying version already, then simply move on.
  if (!tag && findSatisfying(pkg, name, range, mustHave, reg)) {
    return cb()
  }

  // at this point, assume that it has to be installed.
  if (exact) {
    log.verbose("exact", pkg)
    // just pull the data out of the cache to ensure it's there
    return cache.read(name, exact, finisher(pkg, reg, pkglist, bundles, cb))
  }

  getData(name, function (er, data) {
    if (er) return cb(er)
    log.silly(data, pkg)
    if (tag) {
      log.verbose(tag, pkg+" tag")
      var tags = data["dist-tags"]
      if (!tags[tag]) cb(new Error(
        "Tag not found: "+data.name+"@"+tag
        +"\nValid install targets for "+data.name+": "
        +installTargets(data)))
      install_(data.name+"@"+tags[tag], reg, seen, mustHave
              , pkglist, bundles, cb)
    } else {
      log(pkg, "range")
      // prefer the default tag version.
      var defTag = npm.config.get("tag")
        , satis
      defTag = defTag && data["dist-tags"] && data["dist-tags"][defTag]
      if (semver.satisfies(defTag, range)) satis = defTag
      else satis = semver.maxSatisfying(Object.keys(data.versions), range)

      if (!satis) return cb(new Error(
        "No satisfying version found for '"+data.name+"'@'"+range+"'"
        +"\nValid install targets for "+data.name+": "
        +installTargets(data)))
      install_(data.name+"@"+satis, reg, seen, mustHave
              , pkglist, bundles, cb)
    }
  })
}
function installTargets (data) {
  return Object.keys(data["dist-tags"] || {})
    .concat(Object.keys(data.versions))
    .map(JSON.stringify)
    .join(", ") || "(none)"
}

function getData (name, cb) {
  var data = npm.get(name)
  if (data && data["dist-tags"]) return cb(null, data)
  registry.get(name, function (er, data) {
    if (er) return cb(er)
    if (!data._id) data._id = name
    for (var ver in data.versions) {
      try {
        readJson.processJson(data.versions[ver])
      } catch (ex) {
        log(data.name+"@"+ver, "ignoring invalid version")
        delete data.versions[ver]
      }
    }
    if (!data["dist-tags"]) return cb(new Error(
      (data._id || data.name) +
      " Invalid package data. Lacking 'dist-tags' hash."))
    filterNodeVersion(data)
    npm.set(data)
    cb(null, data)
  })
}
// see if there is a satisfying version already
function findSatisfying (pkg, name, range, mustHave, reg) {
  if (mustHave) return null
  return semver.maxSatisfying
         ( Object.keys(reg[name] || {})
           .concat(Object.keys(Object.getPrototypeOf(reg[name] || {})))
         , range
         )
}

function finisher (pkg, reg, pkglist, bundles, cb) {
    return function (er, data) {
  if (!cb) throw new Error("no cb in finisher")
  if (er) return log.er(cb, "Error installing "+pkg)(er)
  if (!data._engineSupported) return cb(
    data.name+"@"+data.version
    +" not compatible with this version of node/npm\n"
    +"Requires: "+JSON.stringify(data.engines)+"\n"
    +"You have: "+JSON.stringify({node:process.version, npm:npm.version}))

  if (!reg.hasOwnProperty(data.name)) {
    reg[data.name] = Object.create(reg[data.name] || Object.prototype)
  }
  reg[data.name][data.version] = data

  // also add the dependencies.
  // any dependencies that are URLs get added to a bundle list
  if (!pkglist) pkglist = []
  getDeps(data, function (er, deps) {
    if (er) return cb(er)
    if (!Array.isArray(pkglist)) pkglist = [pkglist]
    pkglist.push.apply(pkglist, Object.keys(deps).map(function (dep) {
      var v = deps[dep].trim()
        , d = dep.trim()
        , u = url.parse(v)
      log.silly(u, "url.parse "+v)
      if (u && u.protocol && u.host) {
        bundles[data._id] = bundles[data._id] || []
        bundles[data._id].push(u.href)
        return false
      }
      return v ? d + "@" + v : d
    }).filter(function (dep) { return dep }))
    cb()
  })
}}

function getDeps (data, cb) {
  var deps = data.dependencies || {}
    , devDeps = data.devDependencies || {}
  if (npm.config.get("dev")) {
    Object.keys(devDeps).forEach(function (d) { deps[d] = devDeps[d] })
  }
  // now see if any of them are already bundled.
  // if so, omit them from the list.
  var bundle = path.join( npm.cache, data.name, data.version
                        , "package", "node_modules" )
  fs.readdir(bundle, function (er, bundles) {
    bundles = bundles || []
    bundles.forEach(function (b) { delete deps[b] })
    cb(null, deps)
  })
}

function filterNodeVersion (data) {
  var supported = []
  Object.keys(data.versions).forEach(function (v) {
    if (!data.versions[v]._engineSupported) {
      log.verbose(data.versions[v]._id, "not supported on node@"+process.version)
      delete data.versions[v]
    } else supported.push(data.versions[v]._id)
  })
  if (!supported.length) {
    log.warn(data._id, "Not supported on node@"+process.version)
  } else log.verbose(supported, "Supported versions")
  // might have deleted the special "latest" tag.  if so, replace it.
  var v = data["dist-tags"].latest
  if (v && !data.versions[v] && supported.length) {
    data["dist-tags"].latest = Object.keys(data.versions)
      .sort(semver.compare).pop()
    log("not supported by node@"+process.version,
        "latest = "+data.name+"@"+v)
  }
}

function buildAll (installed, bundles, cb) {
  var list = []
  Object.keys(installed).forEach(function (i) {
    Object.keys(installed[i]).forEach(function (v) {
      list.push([i, v])
    })
  })
  log.verbose(list, "install list")
  cb = rollbackFailure(list, cb)
  if (!list.length) return log.info("Nothing to do", "install", cb)
  var buildList = []

  asyncMap(list, function (i, cb) {
    var target = path.join(npm.dir, i[0], i[1])
    cache.unpack( i[0], i[1], target
                , null, null // don't chmod anything here.  just as-is.
                , npm.config.get("user")
                , npm.config.get("group"), function (er) {
      if (!er) buildList.push(target)
      cb(er)
    })
  }, function (er) {
    if (er) return cb(er)
    log.verbose(list.join("\n"), "unpacked, building")
    // now everything's been unpacked.
    // install any bundles that were requested with a url dep.
    // MUST install ALL bundles before building anything
    log.silly(bundles, "installing bundles")
    chain( [installBundles, bundles]
         , [npm.commands.build, buildList]
         , cb )
  })
}

function installBundles (bundles, cb) {
  // bundles is {name:[some, pkg, urls],...}
  // bundle install each of them one at at time.
  // This global config state thing sucks a lot. Need
  // a more clean FP-style approach to the whole bundle thing.
  var bundlePkgs = Object.keys(bundles)
  if (!bundlePkgs.length) return cb()
  chain(bundlePkgs.map(function (host) { return function (cb) {
    var urls = bundles[host]
      , _ = host.split("@")
      , name = _.shift()
      , ver = _.join("@")
      , pkgDir = path.join(npm.dir, name, ver, "package")
    log.info(urls, "bundling for "+host)
    npm.commands.bundle(["install"].concat(urls), pkgDir, cb)
  }}).concat(cb))
}

function rollbackFailure (installList, cb) { return function (er) {
  if (!er) return log.verbose(installList.map(function (i) {
    return i.join("@")
  }).join("\n"), "installed", cb)
  // error happened, roll back
  installList = installList.map(function (p) {
    return p.join('@')
  })
  npm.ROLLBACK = true
  log.error(er, "install failed")
  log("rollback", "install failed")
  log(installList, "uninstall")
  return npm.commands.uninstall
    ( installList
    , function (er_) {
        if (er_) log.error(er_, "rollback failed")
        else log("rolled back", "install failed")
        cb(er)
      }
    )
}}
<|endoftext|>


<commit_before>"use strict";function _typeof(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e}!function(e){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.GitHubCalendar=e()}}(function(){return function e(t,n,r){function o(i,f){if(!n[i]){if(!t[i]){var d="function"==typeof require&&require;if(!f&&d)return d(i,!0);if(u)return u(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var p=n[i]={exports:{}};t[i][0].call(p.exports,function(e){var n=t[i][1][e];return o(n?n:e)},p,p.exports,e,t,n,r)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}({1:[function(e,t,n){t.exports=function(e,t,n){return"string"==typeof e&&(e=document.querySelector(e)),n=n||{},n.summary_text=n.summary_text||'Summary of pull requests, issues opened, and commits made by @'+t+"",n.proxy=n.proxy||function(e){return"https://urlreq.appspot.com/req?method=GET&url="+e},fetch(n.proxy("https://github.com/"+t)).then(function(e){return e.text()}).then(function(t){var r=document.createElement("div");r.innerHTML=t;var o=r.querySelector("#contributions-calendar");o.querySelector(".left.text-muted").innerHTML=n.summary_text,e.innerHTML=o.innerHTML})}},{}]},{},[1])(1)});<commit_msg>build new minified js<commit_after>"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(e){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.GitHubCalendar=e()}}(function(){return function e(t,n,r){function o(f,i){if(!n[f]){if(!t[f]){var c="function"==typeof require&&require;if(!i&&c)return c(f,!0);if(u)return u(f,!0);var p=new Error("Cannot find module '"+f+"'");throw p.code="MODULE_NOT_FOUND",p}var d=n[f]={exports:{}};t[f][0].call(d.exports,function(e){var n=t[f][1][e];return o(n?n:e)},d,d.exports,e,t,n,r)}return n[f].exports}for(var u="function"==typeof require&&require,f=0;f<r.length;f++)o(r[f]);return o}({1:[function(e,t,n){t.exports=function(e,t,n){function r(){return fetch(n.proxy("https://github.com/"+t)).then(function(e){return e.text()}).then(function(t){var o=document.createElement("div");o.innerHTML=t;var u=o.querySelector("#contributions-calendar");u.querySelector(".left.text-muted").innerHTML=n.summary_text,u.querySelector("include-fragment")?setTimeout(r,500):e.innerHTML=u.innerHTML})}return"string"==typeof e&&(e=document.querySelector(e)),n=n||{},n.summary_text=n.summary_text||'Summary of pull requests, issues opened, and commits made by @'+t+"",n.proxy=n.proxy||function(e){return"https://urlreq.appspot.com/req?method=GET&url="+e},r()}},{}]},{},[1])(1)});<|endoftext|>