From 0cb57f52de3f81894cc8eebe6953e94df3dfd296 Mon Sep 17 00:00:00 2001 From: woodsaj Date: Tue, 8 Mar 2016 15:03:34 +0800 Subject: [PATCH 01/16] refactor how template vars are updated. fixes #4283 Use promises to order the updates of variable options so that parents are always updated before children. This ensures that we only need to query the datasource once per variable as variables that depend on other variables will only be processed once their parent has been. This commit also ensures that variable options are refreshed if "refresh_on_load" is true even when query params are used to set the variable seltion. --- .../features/templating/templateValuesSrv.js | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 46d2f90bc03..5256c3e59b5 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -27,29 +27,72 @@ function (angular, _, kbn) { var queryParams = $location.search(); var promises = []; + //use promises to delay processing variables that + //depend on other variables. + this.variableLock = {}; + var self = this; + _.forEach(this.variables, function(variable) { + self.variableLock[variable.name] = $q.defer(); + }); + for (var i = 0; i < this.variables.length; i++) { var variable = this.variables[i]; - var urlValue = queryParams['var-' + variable.name]; - if (urlValue !== void 0) { - promises.push(this.setVariableFromUrl(variable, urlValue)); - } - else if (variable.refresh) { - promises.push(this.updateOptions(variable)); - } - else if (variable.type === 'interval') { - this.updateAutoInterval(variable); - } + promises.push(this.processVariable(variable, queryParams)); } return $q.all(promises); }; + this.processVariable = function(variable, queryParams) { + var dependencies = []; + var self = this; + // determine our dependencies. + if (variable.type === "query") { + _.forEach(this.variables, function(v) { + if (templateSrv.containsVariable(variable.query, v.name)) { + dependencies.push(self.variableLock[v.name].promise); + } + }); + } + return $q.all(dependencies).then(function() { + var variableName = variable.name; + var urlValue = queryParams['var-' + variable.name]; + if (urlValue !== void 0) { + return self.setVariableFromUrl(variable, urlValue).then(function() { + self.variableLock[variableName].resolve(); + }); + } + else if (variable.refresh) { + return self.updateOptions(variable).then(function() { + self.variableLock[variableName].resolve(); + }); + } + else if (variable.type === 'interval') { + self.updateAutoInterval(variable); + self.variableLock[variableName].resolve(); + } else { + self.variableLock[variableName].resolve(); + } + }); + }; + this.setVariableFromUrl = function(variable, urlValue) { + if (variable.refresh) { + var self = this; + //refresh the list of options before setting the value + return this.updateOptions(variable).then(function() { + var option = _.findWhere(variable.options, { text: urlValue }); + option = option || { text: urlValue, value: urlValue }; + + self.updateAutoInterval(variable); + return self.setVariableValue(variable, option, true); + }); + } var option = _.findWhere(variable.options, { text: urlValue }); option = option || { text: urlValue, value: urlValue }; this.updateAutoInterval(variable); - return this.setVariableValue(variable, option); + return this.setVariableValue(variable, option, true); }; this.updateAutoInterval = function(variable) { @@ -64,7 +107,7 @@ function (angular, _, kbn) { templateSrv.setGrafanaVariable('$__auto_interval', interval); }; - this.setVariableValue = function(variable, option) { + this.setVariableValue = function(variable, option, firstLoad) { variable.current = angular.copy(option); if (_.isArray(variable.current.value)) { @@ -74,6 +117,11 @@ function (angular, _, kbn) { self.selectOptionsForCurrentValue(variable); templateSrv.updateTemplateData(); + // on first load, variable loading is ordered to ensure + // that parents are updated before children. + if (firstLoad) { + return $q.when(); + } return self.updateOptionsInChildVariables(variable); }; @@ -119,8 +167,7 @@ function (angular, _, kbn) { return datasourceSrv.get(variable.datasource) .then(_.partial(this.updateOptionsFromMetricFindQuery, variable)) - .then(_.partial(this.updateTags, variable)) - .then(_.partial(this.validateVariableSelectionState, variable)); + .then(_.partial(this.updateTags, variable)); }; this.selectOptionsForCurrentValue = function(variable) { From dc4743a392e4a4494f967b8d27f758db7917309c Mon Sep 17 00:00:00 2001 From: woodsaj Date: Tue, 8 Mar 2016 15:41:24 +0800 Subject: [PATCH 02/16] ensure current template variable is set. - When distributing a dashboard it is often not practical to have "current" template variable option set. This commit ensures that for dashboards with no current, it is assigned when the dashboard loads (assuming refresh on load is set.) --- public/app/features/templating/templateValuesSrv.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 5256c3e59b5..7750bb34a19 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -64,6 +64,10 @@ function (angular, _, kbn) { } else if (variable.refresh) { return self.updateOptions(variable).then(function() { + if (_.isEmpty(variable.current) && variable.options.length) { + console.log("setting current for %s", variable.name); + self.setVariableValue(variable, variable.options[0], true); + } self.variableLock[variableName].resolve(); }); } From 2a18430a451fb7623360470a85390a7c1660ea7d Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 09:26:15 +0100 Subject: [PATCH 03/16] docs(plugin): add table reponse format for queries --- docs/sources/plugins/datasources.md | 41 ++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/sources/plugins/datasources.md b/docs/sources/plugins/datasources.md index 399d99b6292..97ef508b004 100644 --- a/docs/sources/plugins/datasources.md +++ b/docs/sources/plugins/datasources.md @@ -53,7 +53,10 @@ Request object passed to datasource.query function } ``` -Expected response from datasource.query +There are two different kind of results for datasources. +Time series and table. Time series is the most common format and is suppoert by all datasources and panels. Table format is only support by the Influxdb datasource and table panel. But we might se more of this in the future. + +Time series response from datasource.query An array of ```json [ @@ -74,6 +77,42 @@ An array of ] ``` +Table response from datasource.query +An array of +```json +[ + { + "columns": [ + { + "text": "Time", + "type": "time", + "sort": true, + "desc": true, + }, + { + "text": "mean", + }, + { + "text": "sum", + } + ], + "rows": [ + [ + 1457425380000, + null, + null + ], + [ + 1457425370000, + 1002.76215352, + 1002.76215352 + ], + ], + "type": "table" + } +] +``` + ### Annotation Query Request object passed to datasource.annotationsQuery function From 2475ca8f9a5f23263315dd3181b74c30f5b17050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 8 Mar 2016 09:32:54 +0100 Subject: [PATCH 04/16] fix(templaing): refactoring PR #4283 --- .../features/templating/templateValuesSrv.js | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 7750bb34a19..51895ff1ebf 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -27,10 +27,9 @@ function (angular, _, kbn) { var queryParams = $location.search(); var promises = []; - //use promises to delay processing variables that - //depend on other variables. + // use promises to delay processing variables that + // depend on other variables. this.variableLock = {}; - var self = this; _.forEach(this.variables, function(variable) { self.variableLock[variable.name] = $q.defer(); }); @@ -45,7 +44,8 @@ function (angular, _, kbn) { this.processVariable = function(variable, queryParams) { var dependencies = []; - var self = this; + var lock = self.variableLock[variable.name]; + // determine our dependencies. if (variable.type === "query") { _.forEach(this.variables, function(v) { @@ -54,49 +54,44 @@ function (angular, _, kbn) { } }); } + return $q.all(dependencies).then(function() { - var variableName = variable.name; var urlValue = queryParams['var-' + variable.name]; if (urlValue !== void 0) { - return self.setVariableFromUrl(variable, urlValue).then(function() { - self.variableLock[variableName].resolve(); - }); + return self.setVariableFromUrl(variable, urlValue).then(lock.resolve); } else if (variable.refresh) { return self.updateOptions(variable).then(function() { if (_.isEmpty(variable.current) && variable.options.length) { console.log("setting current for %s", variable.name); - self.setVariableValue(variable, variable.options[0], true); + self.setVariableValue(variable, variable.options[0]); } - self.variableLock[variableName].resolve(); + lock.resolve(); }); } else if (variable.type === 'interval') { self.updateAutoInterval(variable); - self.variableLock[variableName].resolve(); + lock.resolve(); } else { - self.variableLock[variableName].resolve(); + lock.resolve(); } }); }; this.setVariableFromUrl = function(variable, urlValue) { + var promise = $q.when(true); + if (variable.refresh) { - var self = this; - //refresh the list of options before setting the value - return this.updateOptions(variable).then(function() { - var option = _.findWhere(variable.options, { text: urlValue }); - option = option || { text: urlValue, value: urlValue }; - - self.updateAutoInterval(variable); - return self.setVariableValue(variable, option, true); - }); + promise = this.updateOptions(variable); } - var option = _.findWhere(variable.options, { text: urlValue }); - option = option || { text: urlValue, value: urlValue }; - this.updateAutoInterval(variable); - return this.setVariableValue(variable, option, true); + return promise.then(function() { + var option = _.findWhere(variable.options, { text: urlValue }); + option = option || { text: urlValue, value: urlValue }; + + self.updateAutoInterval(variable); + return self.setVariableValue(variable, option, true); + }); }; this.updateAutoInterval = function(variable) { @@ -111,7 +106,7 @@ function (angular, _, kbn) { templateSrv.setGrafanaVariable('$__auto_interval', interval); }; - this.setVariableValue = function(variable, option, firstLoad) { + this.setVariableValue = function(variable, option, initPhase) { variable.current = angular.copy(option); if (_.isArray(variable.current.value)) { @@ -119,13 +114,14 @@ function (angular, _, kbn) { } self.selectOptionsForCurrentValue(variable); - templateSrv.updateTemplateData(); + // on first load, variable loading is ordered to ensure // that parents are updated before children. - if (firstLoad) { + if (initPhase) { return $q.when(); } + return self.updateOptionsInChildVariables(variable); }; @@ -171,7 +167,8 @@ function (angular, _, kbn) { return datasourceSrv.get(variable.datasource) .then(_.partial(this.updateOptionsFromMetricFindQuery, variable)) - .then(_.partial(this.updateTags, variable)); + .then(_.partial(this.updateTags, variable)) + .then(_.partial(this.validateVariableSelectionState, variable)); }; this.selectOptionsForCurrentValue = function(variable) { @@ -196,7 +193,7 @@ function (angular, _, kbn) { this.validateVariableSelectionState = function(variable) { if (!variable.current) { if (!variable.options.length) { return; } - return self.setVariableValue(variable, variable.options[0]); + return self.setVariableValue(variable, variable.options[0], true); } if (_.isArray(variable.current.value)) { @@ -204,7 +201,7 @@ function (angular, _, kbn) { } else { var currentOption = _.findWhere(variable.options, { text: variable.current.text }); if (currentOption) { - return self.setVariableValue(variable, currentOption); + return self.setVariableValue(variable, currentOption, true); } else { if (!variable.options.length) { return; } return self.setVariableValue(variable, variable.options[0]); From 8e11f8dc21c265398aa9eef04a157db84d744431 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 10:30:38 +0100 Subject: [PATCH 05/16] feat(graph): add spacing above Series specific overrides --- public/app/plugins/panel/graph/module.ts | 2 +- .../graph/{seriesOverridesCtrl.js => series_overrides_ctrl.js} | 0 public/app/plugins/panel/graph/styleEditor.html | 2 +- public/test/specs/seriesOverridesCtrl-specs.js | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename public/app/plugins/panel/graph/{seriesOverridesCtrl.js => series_overrides_ctrl.js} (100%) diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 88c92ee320a..201d3f3e8c8 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -2,7 +2,7 @@ import './graph'; import './legend'; -import './seriesOverridesCtrl'; +import './series_overrides_ctrl'; import moment from 'moment'; import kbn from 'app/core/utils/kbn'; diff --git a/public/app/plugins/panel/graph/seriesOverridesCtrl.js b/public/app/plugins/panel/graph/series_overrides_ctrl.js similarity index 100% rename from public/app/plugins/panel/graph/seriesOverridesCtrl.js rename to public/app/plugins/panel/graph/series_overrides_ctrl.js diff --git a/public/app/plugins/panel/graph/styleEditor.html b/public/app/plugins/panel/graph/styleEditor.html index 82cf31dd0d1..9f7b7989d5c 100644 --- a/public/app/plugins/panel/graph/styleEditor.html +++ b/public/app/plugins/panel/graph/styleEditor.html @@ -1,4 +1,4 @@ -
+
Chart Options
diff --git a/public/test/specs/seriesOverridesCtrl-specs.js b/public/test/specs/seriesOverridesCtrl-specs.js index 75030bea077..f83a87d5977 100644 --- a/public/test/specs/seriesOverridesCtrl-specs.js +++ b/public/test/specs/seriesOverridesCtrl-specs.js @@ -1,6 +1,6 @@ define([ './helpers', - 'app/plugins/panel/graph/seriesOverridesCtrl' + 'app/plugins/panel/graph/series_overrides_ctrl' ], function(helpers) { 'use strict'; From 252568c91bd34af3ea06a6d2cf8b03a9b696dff0 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 10:33:38 +0100 Subject: [PATCH 06/16] fix(graph): type in html --- public/app/plugins/panel/graph/styleEditor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/panel/graph/styleEditor.html b/public/app/plugins/panel/graph/styleEditor.html index 9f7b7989d5c..b730b1d397a 100644 --- a/public/app/plugins/panel/graph/styleEditor.html +++ b/public/app/plugins/panel/graph/styleEditor.html @@ -1,4 +1,4 @@ -
+
Chart Options
From 6fac471415c15c5a19dbc06df2e1c91d8b73d6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 8 Mar 2016 10:41:20 +0100 Subject: [PATCH 07/16] feat(templating): fixed failing unit tests in PR #4287 --- public/test/specs/templateValuesSrv-specs.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/public/test/specs/templateValuesSrv-specs.js b/public/test/specs/templateValuesSrv-specs.js index 0eaa9d1d99f..d81ce4fd059 100644 --- a/public/test/specs/templateValuesSrv-specs.js +++ b/public/test/specs/templateValuesSrv-specs.js @@ -34,12 +34,13 @@ define([ options: [{text: "test", value: "test"}] }; - beforeEach(function() { + beforeEach(function(done) { var dashboard = { templating: { list: [variable] } }; var urlParams = {}; urlParams["var-apps"] = "new"; ctx.$location.search = sinon.stub().returns(urlParams); - ctx.service.init(dashboard); + ctx.service.init(dashboard).then(function() { done(); }); + ctx.$rootScope.$digest(); }); it('should update current value', function() { @@ -56,12 +57,13 @@ define([ options: [{text: "val1", value: "val1"}, {text: 'val2', value: 'val2'}, {text: 'val3', value: 'val3', selected: true}] }; - beforeEach(function() { + beforeEach(function(done) { var dashboard = { templating: { list: [variable] } }; var urlParams = {}; urlParams["var-apps"] = ["val2", "val1"]; ctx.$location.search = sinon.stub().returns(urlParams); - ctx.service.init(dashboard); + ctx.service.init(dashboard).then(function() { done(); }); + ctx.$rootScope.$digest(); }); it('should update current value', function() { From 1a39d93b4e0f4dae38637d1fb494fb94b64a64cd Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 7 Mar 2016 12:25:26 -0800 Subject: [PATCH 08/16] Implemented GetDataSourceByName API --- pkg/api/api.go | 4 ++++ pkg/api/datasources.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/pkg/api/api.go b/pkg/api/api.go index ed029a5171a..e15c08b770c 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -174,6 +174,10 @@ func Register(r *macaron.Macaron) { r.Get("/plugins", GetDataSourcePlugins) }, reqOrgAdmin) + r.Group("/datasources/name/:name", func() { + r.Get("/", wrap(GetDataSourceByName)) + }, reqOrgAdmin) + r.Get("/frontend/settings/", GetFrontendSettings) r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 54959840d03..2f0f1e3ad7c 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -132,3 +132,35 @@ func GetDataSourcePlugins(c *middleware.Context) { c.JSON(200, dsList) } } + +// Get /api/datasources/name/:name +func GetDataSourceByName(c *middleware.Context) Response { + query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId} + + if err := bus.Dispatch(&query); err != nil { + if err == m.ErrDataSourceNotFound { + return ApiError(404, "Data source not found", nil) + } + return ApiError(500, "Failed to query datasources", err) + } + + ds := query.Result + + return Json(200, &dtos.DataSource{ + Id: ds.Id, + OrgId: ds.OrgId, + Name: ds.Name, + Url: ds.Url, + Type: ds.Type, + Access: ds.Access, + Password: ds.Password, + Database: ds.Database, + User: ds.User, + BasicAuth: ds.BasicAuth, + BasicAuthUser: ds.BasicAuthUser, + BasicAuthPassword: ds.BasicAuthPassword, + WithCredentials: ds.WithCredentials, + IsDefault: ds.IsDefault, + JsonData: ds.JsonData, + }) +} From 453eebbac8e5d00a57eeb8a413b22a63e0e1d376 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 11:08:43 +0100 Subject: [PATCH 09/16] style(graph): convert query options to gf-form --- .../graphite/partials/query.options.html | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/public/app/plugins/datasource/graphite/partials/query.options.html b/public/app/plugins/datasource/graphite/partials/query.options.html index 35c95d03e88..b00028d0e05 100644 --- a/public/app/plugins/datasource/graphite/partials/query.options.html +++ b/public/app/plugins/datasource/graphite/partials/query.options.html @@ -1,74 +1,70 @@ -
-
-
    -
  • +
    +
    +
    + -
  • -
  • - Cache timeout -
  • -
  • - -
  • -
  • - Max data points -
  • -
  • - -
  • -
-
+ + Cache timeout + + +
+
+ Max data points + + +
-
- -
+ +
-
+
Shorter legend names
From e5d400ebb98bdae222464ff9a4b0dca8d88f6e70 Mon Sep 17 00:00:00 2001 From: Utkarsh Bhatnagar Date: Tue, 8 Mar 2016 02:19:52 -0800 Subject: [PATCH 10/16] Update data_source.md --- docs/sources/http_api/data_source.md | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/sources/http_api/data_source.md b/docs/sources/http_api/data_source.md index 57352161d31..f60c9cd7000 100644 --- a/docs/sources/http_api/data_source.md +++ b/docs/sources/http_api/data_source.md @@ -74,6 +74,39 @@ page_keywords: grafana, admin, http, api, documentation, datasource "jsonData":null } +## Get a single data sources by Name + +`GET /api/datasources/name/:name` + +**Example Request**: + + GET /api/datasources/name/test_datasource HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + + { + "id":1, + "orgId":1, + "name":"test_datasource", + "type":"graphite", + "access":"proxy", + "url":"http://mydatasource.com", + "password":"", + "user":"", + "database":"", + "basicAuth":false, + "basicAuthUser":"", + "basicAuthPassword":"", + "isDefault":false, + "jsonData":null + } + ## Create data source `POST /api/datasources` From f20f4d130baebdd1ffce841da8fb8614044e7a0a Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Tue, 8 Mar 2016 02:51:03 -0800 Subject: [PATCH 11/16] Pulled out the common code --- pkg/api/datasources.go | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 2f0f1e3ad7c..8c57438dfb5 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -52,24 +52,9 @@ func GetDataSourceById(c *middleware.Context) Response { } ds := query.Result + dtos := convertModelToDtos(ds) - return Json(200, &dtos.DataSource{ - Id: ds.Id, - OrgId: ds.OrgId, - Name: ds.Name, - Url: ds.Url, - Type: ds.Type, - Access: ds.Access, - Password: ds.Password, - Database: ds.Database, - User: ds.User, - BasicAuth: ds.BasicAuth, - BasicAuthUser: ds.BasicAuthUser, - BasicAuthPassword: ds.BasicAuthPassword, - WithCredentials: ds.WithCredentials, - IsDefault: ds.IsDefault, - JsonData: ds.JsonData, - }) + return Json(200, &dtos) } func DeleteDataSource(c *middleware.Context) { @@ -145,8 +130,13 @@ func GetDataSourceByName(c *middleware.Context) Response { } ds := query.Result + dtos := convertModelToDtos(ds) - return Json(200, &dtos.DataSource{ + return Json(200, &dtos) +} + +func convertModelToDtos(ds m.DataSource) dtos.DataSource { + return dtos.DataSource{ Id: ds.Id, OrgId: ds.OrgId, Name: ds.Name, @@ -162,5 +152,5 @@ func GetDataSourceByName(c *middleware.Context) Response { WithCredentials: ds.WithCredentials, IsDefault: ds.IsDefault, JsonData: ds.JsonData, - }) + } } From f397d0ddd7074c98589b97c9cdc06acc97b79220 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 13:16:04 +0100 Subject: [PATCH 12/16] fix(cli): retry download when panicing Will retry to download plugins once if the zip lib panics. closes #4068 --- .../grafana-cli/commands/install_command.go | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 773d5958f4c..070c0aa77c3 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -111,7 +111,21 @@ func RemoveGitBuildFromname(pluginname, filename string) string { return r.ReplaceAllString(filename, pluginname+"/") } +var retryCount = 0 + func downloadFile(pluginName, filepath, url string) (err error) { + defer func() { + if r := recover(); r != nil { + retryCount++ + if retryCount == 1 { + log.Debug("\nFailed downloading. Will retry once.\n") + downloadFile(pluginName, filepath, url) + } else { + panic(r) + } + } + }() + resp, err := http.Get(url) if err != nil { return err @@ -122,12 +136,6 @@ func downloadFile(pluginName, filepath, url string) (err error) { if err != nil { return err } - log.Infof("Got statuscode %s from %s\n", resp.Status, url) - - if resp.StatusCode == 302 || resp.StatusCode == 301 { - str, _ := ioutil.ReadAll(resp.Body) - log.Info("body %s\n\n", string(str)) - } r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength) if err != nil { From d7a72e30c0ebc2ef8644286d74a78abaff00f6b1 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 13:29:42 +0100 Subject: [PATCH 13/16] gofmt --- pkg/cmd/grafana-cli/commands/install_command.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 070c0aa77c3..62ec403d706 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -118,11 +118,11 @@ func downloadFile(pluginName, filepath, url string) (err error) { if r := recover(); r != nil { retryCount++ if retryCount == 1 { - log.Debug("\nFailed downloading. Will retry once.\n") + log.Debug("\nFailed downloading. Will retry once.\n") downloadFile(pluginName, filepath, url) } else { - panic(r) - } + panic(r) + } } }() From 2fcb8b849eaf8d21de19e76be6dd49f967642399 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 14:30:25 +0100 Subject: [PATCH 14/16] style(cli): fixed typos --- .../grafana-cli/commands/install_command.go | 18 +++++++++--------- .../commands/install_command_test.go | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 62ec403d706..2af6b71c878 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -26,8 +26,8 @@ func validateInput(c CommandLine, pluginFolder string) error { return errors.New("missing path flag") } - fileinfo, err := os.Stat(pluginDir) - if err != nil && !fileinfo.IsDir() { + fileInfo, err := os.Stat(pluginDir) + if err != nil && !fileInfo.IsDir() { return errors.New("path is not a directory") } @@ -106,20 +106,20 @@ func SelectVersion(plugin m.Plugin, version string) (m.Version, error) { return m.Version{}, errors.New("Could not find the version your looking for") } -func RemoveGitBuildFromname(pluginname, filename string) string { +func RemoveGitBuildFromName(pluginName, filename string) string { r := regexp.MustCompile("^[a-zA-Z0-9_.-]*/") - return r.ReplaceAllString(filename, pluginname+"/") + return r.ReplaceAllString(filename, pluginName+"/") } var retryCount = 0 -func downloadFile(pluginName, filepath, url string) (err error) { +func downloadFile(pluginName, filePath, url string) (err error) { defer func() { if r := recover(); r != nil { retryCount++ if retryCount == 1 { log.Debug("\nFailed downloading. Will retry once.\n") - downloadFile(pluginName, filepath, url) + downloadFile(pluginName, filePath, url) } else { panic(r) } @@ -142,12 +142,12 @@ func downloadFile(pluginName, filepath, url string) (err error) { return err } for _, zf := range r.File { - newfile := path.Join(filepath, RemoveGitBuildFromname(pluginName, zf.Name)) + newFile := path.Join(filePath, RemoveGitBuildFromName(pluginName, zf.Name)) if zf.FileInfo().IsDir() { - os.Mkdir(newfile, 0777) + os.Mkdir(newFile, 0777) } else { - dst, err := os.Create(newfile) + dst, err := os.Create(newFile) if err != nil { log.Errorf("%v", err) } diff --git a/pkg/cmd/grafana-cli/commands/install_command_test.go b/pkg/cmd/grafana-cli/commands/install_command_test.go index b88677cf614..52b329adf7f 100644 --- a/pkg/cmd/grafana-cli/commands/install_command_test.go +++ b/pkg/cmd/grafana-cli/commands/install_command_test.go @@ -19,7 +19,7 @@ func TestFoldernameReplacement(t *testing.T) { Convey("should be replaced with plugin name", func() { for k, v := range paths { - So(RemoveGitBuildFromname(pluginName, k), ShouldEqual, v) + So(RemoveGitBuildFromName(pluginName, k), ShouldEqual, v) } }) }) @@ -32,7 +32,7 @@ func TestFoldernameReplacement(t *testing.T) { Convey("should be replaced with plugin name", func() { for k, v := range paths { - So(RemoveGitBuildFromname(pluginName, k), ShouldEqual, v) + So(RemoveGitBuildFromName(pluginName, k), ShouldEqual, v) } }) }) From da2b65cd7ce4c92480326e1e41ef510d70e66324 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 14:31:31 +0100 Subject: [PATCH 15/16] feat(editorconfig): add config for go files --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.editorconfig b/.editorconfig index 5760be58369..831bb8696cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,13 @@ # http://editorconfig.org root = true +[*.go] +indent_style = tabs +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + [*] indent_style = space indent_size = 2 From 95f3e520644c6afae1b50e5167d73d1eb975acb4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 8 Mar 2016 14:53:27 +0100 Subject: [PATCH 16/16] feat(cli): use commandline object all the way --- pkg/cmd/grafana-cli/commands/install_command.go | 9 +++++---- pkg/cmd/grafana-cli/commands/upgrade_all_command.go | 2 +- pkg/cmd/grafana-cli/commands/upgrade_command.go | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 2af6b71c878..c58ed12668f 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -49,11 +49,12 @@ func installCommand(c CommandLine) error { log.Infof("version: %v\n", version) } - return InstallPlugin(pluginToInstall, pluginFolder, version, c.GlobalString("repo")) + return InstallPlugin(pluginToInstall, version, c) } -func InstallPlugin(pluginName, pluginFolder, version, repoUrl string) error { - plugin, err := s.GetPlugin(pluginName, repoUrl) +func InstallPlugin(pluginName, version string, c CommandLine) error { + plugin, err := s.GetPlugin(pluginName, c.GlobalString("repo")) + pluginFolder := c.GlobalString("path") if err != nil { return err } @@ -85,7 +86,7 @@ func InstallPlugin(pluginName, pluginFolder, version, repoUrl string) error { res, _ := s.ReadPlugin(pluginFolder, pluginName) for _, v := range res.Dependency.Plugins { - InstallPlugin(v.Id, pluginFolder, "", repoUrl) + InstallPlugin(v.Id, version, c) log.Infof("Installed Dependency: %v ✔\n", v.Id) } diff --git a/pkg/cmd/grafana-cli/commands/upgrade_all_command.go b/pkg/cmd/grafana-cli/commands/upgrade_all_command.go index 0bb89866fcd..d8594182a99 100644 --- a/pkg/cmd/grafana-cli/commands/upgrade_all_command.go +++ b/pkg/cmd/grafana-cli/commands/upgrade_all_command.go @@ -54,7 +54,7 @@ func upgradeAllCommand(c CommandLine) error { log.Infof("Upgrading %v \n", p.Id) s.RemoveInstalledPlugin(pluginDir, p.Id) - InstallPlugin(p.Id, pluginDir, "", c.GlobalString("repo")) + InstallPlugin(p.Id, "", c) } return nil diff --git a/pkg/cmd/grafana-cli/commands/upgrade_command.go b/pkg/cmd/grafana-cli/commands/upgrade_command.go index c3d2cf06aea..e4072e5ced9 100644 --- a/pkg/cmd/grafana-cli/commands/upgrade_command.go +++ b/pkg/cmd/grafana-cli/commands/upgrade_command.go @@ -24,7 +24,7 @@ func upgradeCommand(c CommandLine) error { if localPlugin.Id == v.Id { if ShouldUpgrade(localPlugin.Info.Version, v) { s.RemoveInstalledPlugin(pluginDir, pluginName) - return InstallPlugin(localPlugin.Id, pluginDir, "", c.GlobalString("repo")) + return InstallPlugin(localPlugin.Id, "", c) } } }