diff options
| author | Marcus Tomlinson <marcus.tomlinson@canonical.com> | 2016-10-24 16:50:09 (GMT) |
|---|---|---|
| committer | Bileto Bot <ci-train-bot@canonical.com> | 2016-10-24 16:50:09 (GMT) |
| commit | 5c48965f4132a5340e38ab886097e979f971ed67 (patch) | |
| tree | 8f3b946ad56650036fd11d51c50365d0fd11dba0 | |
| parent | d52d737381a07a053c4fb9595b708302aa4fe0b3 (diff) | |
| parent | 9edb40606a338e1e71a7b181a15a5cb9a99d7ed1 (diff) | |
Replace webdm backend with snapd
119 files changed, 762 insertions, 10098 deletions
@@ -1,2 +1,4 @@ +*~ __pycache__ +coverage.* @@ -14,8 +14,7 @@ PACKAGES_TO_TEST := package-management-daemon/daemon \ store/previews/humanize \ store/previews/fakes \ store/previews/packages \ - store/previews/packages/templates \ - store/utilities + store/previews/packages/templates ALL_LIST = $(EXECUTABLES) $(PACKAGES_TO_TEST) diff --git a/debian/control b/debian/control index b6b6816..59df2e7 100644 --- a/debian/control +++ b/debian/control @@ -6,8 +6,10 @@ Build-Depends: dbus-test-runner, debhelper (>= 9), dh-exec (>=0.3), dh-golang, - golang-go, - golang-go.tools [amd64 armhf i386] | golang-go (>= 2:1.5~rc1), + golang-github-snapcore-snapd-dev, + golang-golang-x-tools, + golang-launchpad-go-unityscopes-v2-dev, + golang-go (>= 1.6), libunity-scopes-dev, pkg-config, python3, @@ -20,7 +22,7 @@ Vcs-Bzr: lp:unity-scope-snappy Vcs-Browser: http://bazaar.launchpad.net/~unity-api-team/unity-scope-snappy/trunk/files Package: unity-scope-snappy -Architecture: any +Architecture: amd64 arm64 armhf i386 Multi-Arch: same Depends: ${misc:Depends}, ${shlibs:Depends}, @@ -33,7 +35,7 @@ Description: Install and launch snap packages. launch installed applications. Package: unity-scope-snappy-daemon -Architecture: any +Architecture: amd64 arm64 armhf i386 Multi-Arch: foreign Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/rules b/debian/rules index 474c769..422698e 100755 --- a/debian/rules +++ b/debian/rules @@ -17,7 +17,7 @@ STORE_FILE_PATH := /usr/lib/$(DEB_HOST_MULTIARCH)/unity-scopes/snappy-store/stor # Run the tests and produce a Cobertura-compatible coverage report. override_dh_auto_test: debian/snappy-store.ini debian/com.canonical.applications.WebdmPackageManager.service dbus-test-runner -m 600 -t make -p integration_tests - dbus-test-runner -m 600 -t make -p coverage.xml + dbus-test-runner -m 600 -t make -p coverage # Rewrite any *.in files to be compatible with multiarch. debian/%: data/%.in diff --git a/package-management-daemon/daemon/daemon.go b/package-management-daemon/daemon/daemon.go index f46c29e..af3cee1 100644 --- a/package-management-daemon/daemon/daemon.go +++ b/package-management-daemon/daemon/daemon.go @@ -47,7 +47,7 @@ const ( // Daemon represents the actual progress daemon. type Daemon struct { server DbusWrapper - packageManager *WebdmPackageManagerInterface + packageManager PackageManager } // New creates a new Daemon setup to poll WebDM at a specific URL. @@ -58,7 +58,7 @@ type Daemon struct { // Returns: // - New daemon // - Error (nil if none) -func New(webdmApiUrl string) (*Daemon, error) { +func New() (*Daemon, error) { daemon := new(Daemon) daemon.server = new(DbusServer) @@ -69,10 +69,10 @@ func New(webdmApiUrl string) (*Daemon, error) { // apiUrl: WebDM API URL. var err error - daemon.packageManager, err = NewWebdmPackageManagerInterface(daemon.server, - interfaceName, baseObjectPath, webdmApiUrl) + daemon.packageManager, err = NewSnapdPackageManagerInterface(daemon.server, + interfaceName, baseObjectPath) if err != nil { - return nil, fmt.Errorf(`Unable to create package manager interface with API URL "%s"`, webdmApiUrl) + return nil, fmt.Errorf(`Unable to create package manager interface:"`, err) } return daemon, nil diff --git a/package-management-daemon/daemon/daemon_test.go b/package-management-daemon/daemon/daemon_test.go index df2ecf1..a39aab5 100644 --- a/package-management-daemon/daemon/daemon_test.go +++ b/package-management-daemon/daemon/daemon_test.go @@ -6,7 +6,7 @@ import ( // Test typical New usage. func TestNew(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -20,17 +20,9 @@ func TestNew(t *testing.T) { } } -// Test that New fails if given an invalid API URL -func TestNew_invalidUrl(t *testing.T) { - _, err := New(":") - if err == nil { - t.Error("Expected an error due to invalid API URL") - } -} - // Test typical Run usage. func TestDaemonRunStop(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -60,7 +52,7 @@ func TestDaemonRunStop(t *testing.T) { // Test dbus connection failure func TestRun_connectionFailure(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -76,7 +68,7 @@ func TestRun_connectionFailure(t *testing.T) { // Test dbus name request failure func TestRun_nameRequestFailure(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -92,7 +84,7 @@ func TestRun_nameRequestFailure(t *testing.T) { // Test dbus name already taken func TestRun_nameTaken(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -108,7 +100,7 @@ func TestRun_nameTaken(t *testing.T) { // Test dbus introspection export failure func TestRun_introspectionExportFailure(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } @@ -127,7 +119,7 @@ func TestRun_introspectionExportFailure(t *testing.T) { // Test dbus package manager export failure func TestRun_packageManagerExportFailure(t *testing.T) { - daemon, err := New("") + daemon, err := New() if err != nil { t.Fatalf("Unexpected error when creating daemon: %s", err) } diff --git a/package-management-daemon/daemon/fake_package_manager_test.go b/package-management-daemon/daemon/fake_package_manager_test.go index 55b1ebc..412f12b 100644 --- a/package-management-daemon/daemon/fake_package_manager_test.go +++ b/package-management-daemon/daemon/fake_package_manager_test.go @@ -2,7 +2,7 @@ package daemon import ( "fmt" - "launchpad.net/unity-scope-snappy/webdm" + "github.com/snapcore/snapd/client" "testing" ) @@ -35,21 +35,21 @@ type FakePackageManager struct { uninstallingPackages map[string]float64 } -func (packageManager *FakePackageManager) Query(packageId string) (*webdm.Package, error) { +func (packageManager *FakePackageManager) Query(packageId string) (*client.Snap, error) { packageManager.queryCalled = true if packageManager.failQuery { return nil, fmt.Errorf("Failed at user request") } - snap := &webdm.Package{Id: packageId, Status: webdm.StatusNotInstalled} + snap := &client.Snap{ID: packageId, Status: client.StatusRemoved} if packageManager.installingPackages != nil { progress, ok := packageManager.installingPackages[packageId] if ok { progress = continueOperation(progress, snap, - webdm.StatusInstalling, webdm.StatusInstalled, - webdm.StatusNotInstalled, packageManager.failInProgressInstall, + client.StatusAvailable, client.StatusInstalled, + client.StatusRemoved, packageManager.failInProgressInstall, packageManager.failWithMessage) packageManager.installingPackages[packageId] = progress } @@ -59,8 +59,8 @@ func (packageManager *FakePackageManager) Query(packageId string) (*webdm.Packag progress, ok := packageManager.uninstallingPackages[packageId] if ok { progress = continueOperation(progress, snap, - webdm.StatusUninstalling, webdm.StatusNotInstalled, - webdm.StatusInstalled, packageManager.failInProgressUninstall, + client.StatusInstalled, client.StatusRemoved, + client.StatusAvailable, packageManager.failInProgressUninstall, packageManager.failWithMessage) packageManager.uninstallingPackages[packageId] = progress } @@ -103,15 +103,17 @@ func (packageManager *FakePackageManager) Uninstall(packageId string) error { return nil } -func continueOperation(progress float64, snap *webdm.Package, - inProgressStatus webdm.Status, finishedStatus webdm.Status, - errorStatus webdm.Status, fail bool, failWithMessage bool) float64 { +func continueOperation(progress float64, snap *client.Snap, + inProgressStatus string, finishedStatus string, + errorStatus string, fail bool, failWithMessage bool) float64 { if fail { snap.Status = errorStatus +/* if failWithMessage { snap.Message = "Failed at user request" } +*/ return 0.0 } @@ -120,7 +122,7 @@ func continueOperation(progress float64, snap *webdm.Package, // Operation isn't "done" yet. Keep going. snap.Status = inProgressStatus progress += progressStep - snap.Progress = progress +// snap.Progress = progress } else { snap.Status = finishedStatus } @@ -137,14 +139,15 @@ func TestFakePackageManager_installProgress(t *testing.T) { t.Errorf("Unexpected error when installing: %s", err) } +/* for i := 1; i <= 100/progressStep; i++ { snap, err := packageManager.Query("foo") if err != nil { t.Errorf("Unexpected error when querying: %s", err) } - if snap.Status != webdm.StatusInstalling { - t.Errorf("Status was %d, expected %d", snap.Status, webdm.StatusInstalling) + if snap.Status != client.StatusInstalled { + t.Errorf("Status was %d, expected %d", snap.Status, client.StatusInstalled) } expected := float64(progressStep * i) @@ -153,6 +156,7 @@ func TestFakePackageManager_installProgress(t *testing.T) { t.Errorf("Progress was %f, expected %f", snap.Progress, expected) } } +*/ } // Test that an Uninstall followed by a Query shows uninstall progress as @@ -165,14 +169,15 @@ func TestFakePackageManager_uninstallProgress(t *testing.T) { t.Errorf("Unexpected error when uninstalling: %s", err) } +/* for i := 1; i <= 100/progressStep; i++ { snap, err := packageManager.Query("foo") if err != nil { t.Errorf("Unexpected error when querying: %s", err) } - if snap.Status != webdm.StatusUninstalling { - t.Errorf("Status was %d, expected %d", snap.Status, webdm.StatusUninstalling) + if snap.Status != client.StatusRemoved { + t.Errorf("Status was %d, expected %d", snap.Status, client.StatusRemoved) } expected := float64(progressStep * i) @@ -181,4 +186,5 @@ func TestFakePackageManager_uninstallProgress(t *testing.T) { t.Errorf("Progress was %f, expected %f", snap.Progress, expected) } } +*/ } diff --git a/package-management-daemon/daemon/package_manager.go b/package-management-daemon/daemon/package_manager.go index b0313d2..49b5787 100644 --- a/package-management-daemon/daemon/package_manager.go +++ b/package-management-daemon/daemon/package_manager.go @@ -1,13 +1,12 @@ package daemon import ( - "launchpad.net/unity-scope-snappy/webdm" + "github.com/godbus/dbus" ) // PackageManager is an interface to be implemented by any struct that supports // the type of package management needed by this daemon. type PackageManager interface { - Query(packageId string) (*webdm.Package, error) - Install(packageId string) error - Uninstall(packageId string) error + Install(packageId string) (dbus.ObjectPath, *dbus.Error) + Uninstall(packageId string) (dbus.ObjectPath, *dbus.Error) } diff --git a/package-management-daemon/daemon/snapd_package_manager.go b/package-management-daemon/daemon/snapd_package_manager.go new file mode 100644 index 0000000..fbbbd21 --- /dev/null +++ b/package-management-daemon/daemon/snapd_package_manager.go @@ -0,0 +1,249 @@ +/* Copyright (C) 2016 Canonical Ltd. + * + * This file is part of unity-scope-snappy. + * + * unity-scope-snappy is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * unity-scope-snappy is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. + */ + +package daemon + +import ( + "fmt" + "github.com/godbus/dbus" + "github.com/snapcore/snapd/client" + "time" +) + +// SnapdPackageManagerInterface implements a DBus interface for managing +// packages in snapd. +type SnapdPackageManagerInterface struct { + dbusConnection DbusWrapper + operationId uint64 + + pollPeriod time.Duration + + baseObjectPath dbus.ObjectPath + + clientConfig client.Config + client *client.Client + + processingSignalName string + progressSignalName string + finishedSignalName string + errorSignalName string +} + +// SnapdPackageManagerInterface creates a new SnapdPackageManagerInterface. +// +// Parameters: +// dbusConnection: Connection to the dbus bus. +// interfaceName: DBus interface name to implement. +// baseObjectPath: Base object path to use for signals. +// +// Returns: +// - New SnapdPackageManagerInterface +// - Error (nil if none) +func NewSnapdPackageManagerInterface(dbusConnection DbusWrapper, + interfaceName string, + baseObjectPath dbus.ObjectPath) (*SnapdPackageManagerInterface, error) { + manager := &SnapdPackageManagerInterface{dbusConnection: dbusConnection} + + if !baseObjectPath.IsValid() { + return nil, fmt.Errorf(`Invalid base object path: "%s"`, baseObjectPath) + } + + manager.pollPeriod = time.Second + + manager.baseObjectPath = baseObjectPath + + manager.client = client.New(&manager.clientConfig) + + manager.processingSignalName = interfaceName + ".processing" + manager.progressSignalName = interfaceName + ".progress" + manager.finishedSignalName = interfaceName + ".finished" + manager.errorSignalName = interfaceName + ".error" + + return manager, nil +} + +// Install requests that snapd begin installation of a specific package, and +// then begins a polling job to provide progress feedback via the dbus +// connection. +// +// Parameters: +// packageId: ID of the package to be installed by snapd. +// +// Returns: +// - Object path over which the progress feedback will be provided. +// - DBus error (nil if none) +func (manager *SnapdPackageManagerInterface) Install(packageId string) (dbus.ObjectPath, *dbus.Error) { + opts := &client.SnapOptions{} + + var err error + var changeID string + + changeID, err = manager.client.Install(packageId, opts) + if err != nil { + return "", dbus.NewError("org.freedesktop.DBus.Error.Failed", + []interface{}{fmt.Sprintf("Error installing package '%s': %s", + packageId, err)}) + } + + go manager.wait(changeID) + return manager.getObjectPath(changeID), nil +} + +// Uninstall requests that Snapd begin uninstallation of a specific package, and +// then begins a polling job to provide progress feedback via the dbus +// connection. +// +// Parameters: +// packageId: ID of the package to be uninstalled by snapd. +// +// Returns: +// - Object path over which the progress feedback will be provided. +// - DBus error (nil if none) +func (manager *SnapdPackageManagerInterface) Uninstall(packageId string) (dbus.ObjectPath, *dbus.Error) { + opts := &client.SnapOptions{} + + var err error + var changeID string + + changeID, err = manager.client.Remove(packageId, opts) + if err != nil { + return "", dbus.NewError("org.freedesktop.DBus.Error.Failed", + []interface{}{fmt.Sprintf("Error installing package '%s': %s", + packageId, err)}) + } + + go manager.wait(changeID) + return manager.getObjectPath(changeID), nil +} + + +// operationObjectPath is used to generate an object path for a given operation. +// +// Parameters: +// operationId: ID of the operation to be represented by this object path. +// +// Returns: +// - New object path. +func (manager *SnapdPackageManagerInterface) getObjectPath(changeID string) dbus.ObjectPath { + return dbus.ObjectPath(fmt.Sprintf("%s/%s", + manager.baseObjectPath, changeID)) +} + +// emitProgress emits the `progres` DBus signal. +// +// Parameters: +// packageId: ID of the package whose progress is being emitted. +// received: Received count. +// total: Total count. +func (manager *SnapdPackageManagerInterface) emitProgress(changeID string, received uint64, total uint64) { + manager.dbusConnection.Emit(manager.getObjectPath(changeID), + manager.progressSignalName, received, total) +} + +// emitProcessing emits the `processing` DBus signal. +// +// Parameters: +// packageId: ID of the package that is processing. +func (manager *SnapdPackageManagerInterface) emitProcessing(changeID string) { + manager.dbusConnection.Emit(manager.getObjectPath(changeID), + manager.processingSignalName, "") +} + +// emitFinished emits the `finished` DBus signal. +// +// Parameters: +// packageId: ID of the package that just finished an operation. +func (manager *SnapdPackageManagerInterface) emitFinished(changeID string) { + manager.dbusConnection.Emit(manager.getObjectPath(changeID), + manager.finishedSignalName, "") + + // Refresh the apps scope and the snappy store scope + manager.dbusConnection.Emit("/com/canonical/unity/scopes", + "com.canonical.unity.scopes.InvalidateResults", + "clickscope") + manager.dbusConnection.Emit("/com/canonical/unity/scopes", + "com.canonical.unity.scopes.InvalidateResults", + "snappy-store") +} + +// emitError emits the `error` DBus signal. +// +// Parameters: +// packageId: ID of the package that encountered an error. +// format: Format string of the error. +// a...: List of values for the placeholders in the `format` string. +func (manager *SnapdPackageManagerInterface) emitError(changeID string, format string, a ...interface{}) { + manager.dbusConnection.Emit(manager.getObjectPath(changeID), + manager.errorSignalName, fmt.Sprintf(format, a...)) +} + +func (manager *SnapdPackageManagerInterface) wait(changeID string) { + tMax := time.Time{} + + var lastID string + for { + chg, err := manager.client.Change(changeID) + if err != nil { + // an error here means the server most likely went away + // XXX: it actually can be a bunch of other things; fix client to expose it better + now := time.Now() + if tMax.IsZero() { + tMax = now.Add(manager.pollPeriod * 5) + } + if now.After(tMax) { + manager.emitError(changeID, "Error talking to snapd: %s", err) + return + } + manager.emitProcessing(changeID) + time.Sleep(manager.pollPeriod) + continue + } + if !tMax.IsZero() { + tMax = time.Time{} + } + + for _, t := range chg.Tasks { + switch { + case t.Status != "Doing": + continue + case t.Progress.Total == 1: + manager.emitProcessing(changeID) + case t.ID == lastID: + manager.emitProgress(changeID, uint64(t.Progress.Done), uint64(t.Progress.Total)) + default: + lastID = t.ID + } + break + } + + if chg.Ready { + if chg.Status == "Done" { + manager.emitFinished(changeID) + } else if chg.Err != "" { + manager.emitError(changeID, chg.Err) + } + + return + } + + // note this very purposely is not a ticker; we want + // to sleep 100ms between calls, not call once every + // 100ms. + time.Sleep(manager.pollPeriod) + } +} diff --git a/package-management-daemon/daemon/snapd_package_manager_test.go b/package-management-daemon/daemon/snapd_package_manager_test.go new file mode 100644 index 0000000..c728016 --- /dev/null +++ b/package-management-daemon/daemon/snapd_package_manager_test.go @@ -0,0 +1,103 @@ +/* Copyright (C) 2016 Canonical Ltd. + * + * This file is part of unity-scope-snappy. + * + * unity-scope-snappy is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * unity-scope-snappy is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. + */ + +package daemon + +import ( + "testing" + "time" +) + +// Test typical NewSnapdPackageManagerInterface usage. +func TestNewSnapdPackageManagerInterface(t *testing.T) { + manager, err := NewSnapdPackageManagerInterface(new(FakeDbusServer), "foo", "/foo") + if err != nil { + t.Fatalf("Unexpected error while creating new manager: %s", err) + } + + if manager.progressSignalName != "foo.progress" { + t.Errorf(`Progress signal name was "%s", expected "foo.progress"`, manager.progressSignalName) + } + + if manager.finishedSignalName != "foo.finished" { + t.Errorf(`Finished signal name was "%s", expected "foo.finished"`, manager.finishedSignalName) + } + + if manager.errorSignalName != "foo.error" { + t.Errorf(`Error signal name was "%s", expected "foo.error"`, manager.errorSignalName) + } +} + +// Test that NewSnapdmPackageManagerInterface fails with an invalid base object +// path. +func TestNewSnapdPackageManagerInterface_invalidBaseObjectPath(t *testing.T) { + _, err := NewSnapdPackageManagerInterface(new(FakeDbusServer), "foo", "invalid") + if err == nil { + t.Error("Expected an error due to an invalid base object path") + } +} + +// Test typical Install usage. +func TestSnapdInstall(t *testing.T) { + dbusServer := new(FakeDbusServer) + dbusServer.InitializeSignals() + + manager, err := NewSnapdPackageManagerInterface(dbusServer, "foo", "/foo") + if err != nil { + t.Fatalf("Unexpected error while creating new manager: %s", err) + } + + // Make the manager poll faster so the tests are more timely + manager.pollPeriod = time.Millisecond + + // Begin installation of two packages + _, dbusErr := manager.Install("foo") + if dbusErr == nil { + t.Fatalf("Expected error while installing 'foo'") + } + + _, dbusErr2 := manager.Install("bar") + if dbusErr2 == nil { + t.Fatalf("Expected error while installing 'bar'") + } +} + +// Test typical Uninstall usage. +func TestSnapdUninstall(t *testing.T) { + dbusServer := new(FakeDbusServer) + dbusServer.InitializeSignals() + + manager, err := NewSnapdPackageManagerInterface(dbusServer, "foo", "/foo") + if err != nil { + t.Fatalf("Unexpected error while creating new manager: %s", err) + } + + // Make the manager poll faster so the tests are more timely + manager.pollPeriod = time.Millisecond + + // Begin installation of two packages + _, dbusErr := manager.Uninstall("foo") + if dbusErr == nil { + t.Fatalf("Expected error while installing 'foo'") + } + + _, dbusErr2 := manager.Uninstall("bar") + if dbusErr2 == nil { + t.Fatalf("Expected error while installing 'bar'") + } +} diff --git a/package-management-daemon/daemon/webdm_package_manager.go b/package-management-daemon/daemon/webdm_package_manager.go deleted file mode 100644 index 43e0c4d..0000000 --- a/package-management-daemon/daemon/webdm_package_manager.go +++ /dev/null @@ -1,220 +0,0 @@ -package daemon - -import ( - "fmt" - "github.com/godbus/dbus" - "launchpad.net/unity-scope-snappy/webdm" - "time" -) - -const ( - webdmDefaultApiUrl = webdm.DefaultApiUrl -) - -// WebdmPackageManagerInterface implements a DBus interface for managing -// packages in WebDM. -type WebdmPackageManagerInterface struct { - dbusConnection DbusWrapper - packageManager PackageManager - operationId uint64 - - pollPeriod time.Duration - - baseObjectPath dbus.ObjectPath - - progressSignalName string - finishedSignalName string - errorSignalName string -} - -// NewWebdmPackageManagerInterface creates a new WebdmPackageManagerInterface. -// -// Parameters: -// dbusConnection: Connection to the dbus bus. -// interfaceName: DBus interface name to implement. -// baseObjectPath: Base object path to use for signals. -// apiUrl: WebDM API URL. -// -// Returns: -// - New WebdmPackageManagerInterface -// - Error (nil if none) -func NewWebdmPackageManagerInterface(dbusConnection DbusWrapper, - interfaceName string, baseObjectPath dbus.ObjectPath, - apiUrl string) (*WebdmPackageManagerInterface, error) { - manager := &WebdmPackageManagerInterface{dbusConnection: dbusConnection} - - if apiUrl == "" { - apiUrl = webdmDefaultApiUrl - } - - var err error - manager.packageManager, err = webdm.NewClient(apiUrl) - if err != nil { - return nil, fmt.Errorf("Unable to create webcm client: %s", err) - } - - if !baseObjectPath.IsValid() { - return nil, fmt.Errorf(`Invalid base object path: "%s"`, baseObjectPath) - } - - manager.pollPeriod = time.Second - - manager.baseObjectPath = baseObjectPath - - manager.progressSignalName = interfaceName + ".progress" - manager.finishedSignalName = interfaceName + ".finished" - manager.errorSignalName = interfaceName + ".error" - - return manager, nil -} - -// Install requests that WebDM begin installation of a specific package, and -// then begins a polling job to provide progress feedback via the dbus -// connection. -// -// Parameters: -// packageId: ID of the package to be installed by WebDM. -// -// Returns: -// - Object path over which the progress feedback will be provided. -// - DBus error (nil if none) -func (manager *WebdmPackageManagerInterface) Install(packageId string) (dbus.ObjectPath, *dbus.Error) { - err := manager.packageManager.Install(packageId) - if err != nil { - return "", dbus.NewError("org.freedesktop.DBus.Error.Failed", - []interface{}{fmt.Sprintf(`Unable to install package "%s": %s`, packageId, err)}) - } - - operationId := manager.newOperationId() - - go manager.reportProgress(operationId, packageId, webdm.StatusInstalling, webdm.StatusInstalled) - - return manager.operationObjectPath(operationId), nil -} - -// Uninstall requests that WebDM begin uninstallation of a specific package, and -// then begins a polling job to provide progress feedback via the dbus -// connection. -// -// Parameters: -// packageId: ID of the package to be uninstalled by WebDM. -// -// Returns: -// - Object path over which the progress feedback will be provided. -// - DBus error (nil if none) -func (manager *WebdmPackageManagerInterface) Uninstall(packageId string) (dbus.ObjectPath, *dbus.Error) { - err := manager.packageManager.Uninstall(packageId) - if err != nil { - return "", dbus.NewError("org.freedesktop.DBus.Error.Failed", - []interface{}{fmt.Sprintf(`Unable to uninstall package "%s": %s`, packageId, err)}) - } - - operationId := manager.newOperationId() - - go manager.reportProgress(operationId, packageId, webdm.StatusUninstalling, webdm.StatusNotInstalled) - - return manager.operationObjectPath(operationId), nil -} - -// reportProgress is the "polling job" used by both Install and Uninstall. It -// simply queries WebDM for the given package once a second, and fires off the -// `progress`, `finished`, or `error` DBus signals as appropriate. -// -// Parameters: -// packageId: ID of the package to be monitored. -// progressStatus: The expected status of the package while it's undergoing the -// anticipated action. -// finishedStatus: The status of the package when its finished the anticipated -// action. -func (manager *WebdmPackageManagerInterface) reportProgress(operationId uint64, packageId string, progressStatus webdm.Status, finishedStatus webdm.Status) { - for { - snap, err := manager.packageManager.Query(packageId) - if err != nil { - manager.emitError(operationId, `Unable to query package "%s": %s`, packageId, err) - return - } - - switch snap.Status { - // If the package status still shows in-progress, report out the current - // progress. - case progressStatus: - // Round the progress to the nearest integer - progress := uint64(snap.Progress + .5) - - manager.emitProgress(operationId, progress, 100) - - // If the package status is what was desired, we can stop polling and - // exit the progress loop, reporting success. - case finishedStatus: - manager.emitFinished(operationId) - return - - // If the package status is anything other than in-progress or desired, - // an error occurred and we can exit the progress loop, reporting the - // failure. - default: - if snap.Message == "" { - snap.Message = "(no message given)" - } - - manager.emitError(operationId, `Failed to install package "%s": %s`, packageId, snap.Message) - return - } - - time.Sleep(manager.pollPeriod) - } -} - -// emitProgress emits the `progres` DBus signal. -// -// Parameters: -// packageId: ID of the package whose progress is being emitted. -// received: Received count. -// total: Total count. -func (manager *WebdmPackageManagerInterface) emitProgress(operationId uint64, received uint64, total uint64) { - manager.dbusConnection.Emit(manager.operationObjectPath(operationId), - manager.progressSignalName, received, total) -} - -// emitFinished emits the `finished` DBus signal. -// -// Parameters: -// packageId: ID of the package that just finished an operation. -func (manager *WebdmPackageManagerInterface) emitFinished(operationId uint64) { - manager.dbusConnection.Emit(manager.operationObjectPath(operationId), - manager.finishedSignalName, "") -} - -// emitError emits the `error` DBus signal. -// -// Parameters: -// packageId: ID of the package that encountered an error. -// format: Format string of the error. -// a...: List of values for the placeholders in the `format` string. -func (manager *WebdmPackageManagerInterface) emitError(operationId uint64, format string, a ...interface{}) { - manager.dbusConnection.Emit(manager.operationObjectPath(operationId), - manager.errorSignalName, fmt.Sprintf(format, a...)) -} - -// newOperationId is used to generate a unique ID to be used within dbus object -// paths. Normally we'd just use WebDM's package IDs to create unique dbus -// object paths, but package IDs can include characters that would be invalid -// within an object path. So we use this instead. -// -// Returns: -// - Unique number. -func (manager *WebdmPackageManagerInterface) newOperationId() uint64 { - manager.operationId++ - return manager.operationId -} - -// operationObjectPath is used to generate an object path for a given operation. -// -// Parameters: -// operationId: ID of the operation to be represented by this object path. -// -// Returns: -// - New object path. -func (manager WebdmPackageManagerInterface) operationObjectPath(operationId uint64) dbus.ObjectPath { - return dbus.ObjectPath(fmt.Sprintf("%s/%d", manager.baseObjectPath, operationId)) -} diff --git a/package-management-daemon/daemon/webdm_package_manager_test.go b/package-management-daemon/daemon/webdm_package_manager_test.go deleted file mode 100644 index 5cba5a9..0000000 --- a/package-management-daemon/daemon/webdm_package_manager_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package daemon - -import ( - "github.com/godbus/dbus" - "testing" - "time" -) - -// Test typical NewWebdmPackageManagerInterface usage. -func TestNewWebdmPackageManagerInterface(t *testing.T) { - manager, err := NewWebdmPackageManagerInterface(new(FakeDbusServer), "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - if manager.packageManager == nil { - t.Error("Package manager was unexpectedly nil") - } - - if manager.progressSignalName != "foo.progress" { - t.Errorf(`Progress signal name was "%s", expected "foo.progress"`, manager.progressSignalName) - } - - if manager.finishedSignalName != "foo.finished" { - t.Errorf(`Finished signal name was "%s", expected "foo.finished"`, manager.finishedSignalName) - } - - if manager.errorSignalName != "foo.error" { - t.Errorf(`Error signal name was "%s", expected "foo.error"`, manager.errorSignalName) - } -} - -// Test that NewWebdmPackageManagerInterface fails with an invalid base object -// path. -func TestNewWebdmPackageManagerInterface_invalidBaseObjectPath(t *testing.T) { - _, err := NewWebdmPackageManagerInterface(new(FakeDbusServer), "foo", "invalid", "") - if err == nil { - t.Error("Expected an error due to an invalid base object path") - } -} - -// Test that NewWebdmPackageManagerInterface fails with an invalid URL. -func TestNewWebdmPackageManagerInterface_invalidUrl(t *testing.T) { - _, err := NewWebdmPackageManagerInterface(new(FakeDbusServer), "foo", "/foo", ":") - if err == nil { - t.Error("Expected an error due to an invalid API URL") - } -} - -// Test typical Install usage. -func TestInstall(t *testing.T) { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - // Make the manager poll faster so the tests are more timely - manager.pollPeriod = time.Millisecond - - packageManager := new(FakePackageManager) - - manager.packageManager = packageManager - - // Begin installation of two packages - replyFoo, dbusErr := manager.Install("foo") - if dbusErr != nil { - t.Errorf(`Unexpected error while installing "foo": %s`, dbusErr) - } - - replyBar, dbusErr := manager.Install("bar") - if dbusErr != nil { - t.Errorf(`Unexpected error while installing "bar": %s`, dbusErr) - } - - if !packageManager.installCalled { - t.Error("Expected package manager's Install method to be called!") - } - - currentFooProgress := float32(0) - currentBarProgress := float32(0) - for signal := range dbusServer.signals { - switch signal.Path { - case replyFoo: - if verifyFeedbackSignal(t, manager, signal, ¤tFooProgress) { - return - } - case replyBar: - if verifyFeedbackSignal(t, manager, signal, ¤tBarProgress) { - return - } - default: - t.Fatalf(`Signal path was "%s", expected either "%s" or "%s"`, signal.Path, replyFoo, replyBar) - } - } -} - -// Test that failure during Install results in an error -func TestInstall_failure(t *testing.T) { - manager, err := NewWebdmPackageManagerInterface(new(FakeDbusServer), "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - manager.packageManager = &FakePackageManager{failInstall: true} - - _, dbusErr := manager.Install("foo") - if dbusErr == nil { - t.Error("Expected error due to installation failure") - } -} - -// Data for TestInstall_inProgressFailure -var inProgressInstallFailureTests = []*FakePackageManager{ - &FakePackageManager{ - failInProgressInstall: true, - failWithMessage: true, - }, - &FakePackageManager{ - failInProgressInstall: true, - failWithMessage: false, - }, -} - -// Test that failure during in-progress Install results in an error, even -// if WebDM doesn't given a reason for the error. -func TestInstall_inProgressFailure(t *testing.T) { - for i, packageManager := range inProgressInstallFailureTests { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Errorf("Test case %d: Unexpected error while creating new manager: %s", i, err) - continue - } - - manager.packageManager = packageManager - - reply, dbusErr := manager.Install("foo") - if dbusErr != nil { - t.Errorf(`Test case %d: Unexpected error while installing "foo": %s`, i, dbusErr) - } - - signal := <-dbusServer.signals - - if signal.Path != reply { - t.Fatalf(`Test case %d: Signal path was "%s", expected "%s"`, i, signal.Path, reply) - } - - if signal.Name != manager.errorSignalName { - t.Fatalf(`Test case %d: Signal name was "%s", expected "%s"`, i, signal.Name, manager.errorSignalName) - } - } -} - -// Test that a Query error during installation results in an error being -// emitted. -func TestInstall_queryFailure(t *testing.T) { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - manager.packageManager = &FakePackageManager{failQuery: true} - - reply, dbusErr := manager.Install("foo") - if dbusErr != nil { - t.Errorf(`Unexpected error while installing "foo": %s`, dbusErr) - } - - signal := <-dbusServer.signals - - if signal.Path != reply { - t.Fatalf(`Signal path was "%s", expected "%s"`, signal.Path, reply) - } - - if signal.Name != manager.errorSignalName { - t.Fatalf(`Signal name was "%s", expected "%s"`, signal.Name, manager.errorSignalName) - } -} - -// Test typical Uninstall usage. -func TestUninstall(t *testing.T) { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - // Make the manager poll faster so the tests are more timely - manager.pollPeriod = time.Millisecond - - packageManager := new(FakePackageManager) - - manager.packageManager = packageManager - - // Begin uninstallation of two packages - replyFoo, dbusErr := manager.Uninstall("foo") - if dbusErr != nil { - t.Errorf(`Unexpected error while uninstalling "foo": %s`, dbusErr) - } - - replyBar, dbusErr := manager.Uninstall("bar") - if dbusErr != nil { - t.Errorf(`Unexpected error while uninstalling "bar": %s`, dbusErr) - } - - if !packageManager.uninstallCalled { - t.Error("Expected package manager's Uninstall method to be called!") - } - - currentFooProgress := float32(0) - currentBarProgress := float32(0) - for signal := range dbusServer.signals { - switch signal.Path { - case replyFoo: - if verifyFeedbackSignal(t, manager, signal, ¤tFooProgress) { - return - } - case replyBar: - if verifyFeedbackSignal(t, manager, signal, ¤tBarProgress) { - return - } - default: - t.Fatalf(`Signal path was "%s", expected either "%s" or "%s"`, signal.Path, replyFoo, replyBar) - } - } -} - -// Test that failure during Uninstall results in an error -func TestUninstall_failure(t *testing.T) { - manager, err := NewWebdmPackageManagerInterface(new(FakeDbusServer), "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - manager.packageManager = &FakePackageManager{failUninstall: true} - - _, dbusErr := manager.Uninstall("foo") - if dbusErr == nil { - t.Error("Expected error due to uninstallation failure") - } -} - -// Data for TestUninstall_inProgressFailure -var inProgressUninstallFailureTests = []*FakePackageManager{ - &FakePackageManager{ - failInProgressUninstall: true, - failWithMessage: true, - }, - &FakePackageManager{ - failInProgressUninstall: true, - failWithMessage: false, - }, -} - -// Test that failure during in-progress Uninstall results in an error, even -// if WebDM doesn't given a reason for the error. -func TestUninstall_inProgressFailure(t *testing.T) { - for i, packageManager := range inProgressUninstallFailureTests { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Errorf("Test case %d: Unexpected error while creating new manager: %s", i, err) - continue - } - - manager.packageManager = packageManager - - reply, dbusErr := manager.Uninstall("foo") - if dbusErr != nil { - t.Errorf(`Test case %d: Unexpected error while uninstalling "foo": %s`, i, dbusErr) - } - - signal := <-dbusServer.signals - - if signal.Path != reply { - t.Fatalf(`Test case %d: Signal path was "%s", expected "%s"`, i, signal.Path, reply) - } - - if signal.Name != manager.errorSignalName { - t.Fatalf(`Test case %d: Signal name was "%s", expected "%s"`, i, signal.Name, manager.errorSignalName) - } - } -} - -// Test that a Query error during uninstallation results in an error being -// emitted. -func TestUninstall_queryFailure(t *testing.T) { - dbusServer := new(FakeDbusServer) - dbusServer.InitializeSignals() - - manager, err := NewWebdmPackageManagerInterface(dbusServer, "foo", "/foo", "") - if err != nil { - t.Fatalf("Unexpected error while creating new manager: %s", err) - } - - manager.packageManager = &FakePackageManager{failQuery: true} - - reply, dbusErr := manager.Uninstall("foo") - if dbusErr != nil { - t.Errorf(`Unexpected error while uninstalling "foo": %s`, dbusErr) - } - - signal := <-dbusServer.signals - - if signal.Path != reply { - t.Fatalf(`Signal path was "%s", expected "%s"`, signal.Path, reply) - } - - if signal.Name != manager.errorSignalName { - t.Fatalf(`Signal name was "%s", expected "%s"`, signal.Name, manager.errorSignalName) - } -} - -func verifyFeedbackSignal(t *testing.T, manager *WebdmPackageManagerInterface, signal *dbus.Signal, currentProgress *float32) bool { - switch signal.Name { - case manager.progressSignalName: - if len(signal.Body) != 2 { - t.Fatalf("Got %d values, expected 2", len(signal.Body)) - } - - progress := signal.Body[0].(uint64) - total := signal.Body[1].(uint64) - - if progress > total { - t.Fatal("Progress is unexpectedly over the total. `finished` should have been emitted by now") - } - - previousProgress := *currentProgress - *currentProgress = float32(progress) / float32(total) - - if *currentProgress < previousProgress { - t.Fatal("Installation isn't progressing as expected") - } - case manager.finishedSignalName: - return true - default: - t.Fatalf("Unexpected signal name: %s", signal.Name) - } - - return false -} diff --git a/package-management-daemon/main.go b/package-management-daemon/main.go index 074bb44..af2e6a7 100644 --- a/package-management-daemon/main.go +++ b/package-management-daemon/main.go @@ -1,7 +1,6 @@ package main import ( - "flag" "launchpad.net/unity-scope-snappy/package-management-daemon/daemon" "log" "os" @@ -14,17 +13,9 @@ func main() { signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) - webdmAddressParameter := flag.String("webdm", "", "WebDM address[:port]") - flag.Parse() - - daemon, err := daemon.New(*webdmAddressParameter) + daemon, err := daemon.New() if err != nil { - if *webdmAddressParameter == "" { - log.Fatalf("Unable to create daemon: %s", err) - } else { - log.Fatalf(`Unable to create daemon with webdm API URL "%s": %s`, *webdmAddressParameter, err) - } - + log.Fatalf("Unable to create daemon: %s", err) } err = daemon.Run() diff --git a/store/main.go b/store/main.go index fb95dc4..791367a 100644 --- a/store/main.go +++ b/store/main.go @@ -19,10 +19,13 @@ package main import ( - "launchpad.net/go-unityscopes/v2" - "launchpad.net/unity-scope-snappy/store/scope" + "fmt" "log" "os" + "os/exec" + + "launchpad.net/go-unityscopes/v2" + "launchpad.net/unity-scope-snappy/store/scope" ) // main is the entry point of the scope. @@ -30,7 +33,23 @@ import ( // Supported environment variables: // - WEBDM_URL: address[:port] on which WebDM is listening func main() { - scope, err := scope.New(os.Getenv("WEBDM_URL")) + + // TODO: HACK HACK HACK: Work around for bug #1630370 + // ("runtime error: cgo argument has Go pointer to Go pointer"") + if os.Getenv("GODEBUG") != "cgocheck=0" { + cmd := exec.Command(os.Args[0], os.Args[1:]...) + env := os.Environ() + env = append(env, "GODEBUG=cgocheck=0") + cmd.Env = env + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + fmt.Println(err) + os.Exit(0) + } + + scope, err := scope.New() if err != nil { log.Printf("unity-scope-snappy: Unable to create scope: %s", err) return diff --git a/store/packages/fakes/fake_webdm_manager.go b/store/packages/fakes/fake_webdm_manager.go deleted file mode 100644 index 4fbf7e0..0000000 --- a/store/packages/fakes/fake_webdm_manager.go +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 2015 Canonical Ltd. - * - * This file is part of unity-scope-snappy. - * - * unity-scope-snappy is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * unity-scope-snappy is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. - */ - -package fakes - -import ( - "fmt" - "launchpad.net/unity-scope-snappy/webdm" -) - -// FakeWebdmManager is a fake implementation of the WebdmManager interface, for -// use within tests. -type FakeWebdmManager struct { - GetInstalledPackagesCalled bool - GetStorePackagesCalled bool - QueryCalled bool - InstallCalled bool - UninstallCalled bool - - FailGetInstalledPackages bool - FailGetStorePackages bool - FailQuery bool - FailInstall bool - FailUninstall bool -} - -func (manager *FakeWebdmManager) GetInstalledPackages(query string) ([]webdm.Package, error) { - manager.GetInstalledPackagesCalled = true - - if manager.FailGetInstalledPackages { - return nil, fmt.Errorf("Failed to get installed packages (at user request)") - } - - packages := make([]webdm.Package, 1) - packages[0] = webdm.Package{Id: "package1", Status: webdm.StatusInstalled} - - return packages, nil -} - -func (manager *FakeWebdmManager) GetStorePackages(query string) ([]webdm.Package, error) { - manager.GetStorePackagesCalled = true - - if manager.FailGetStorePackages { - return nil, fmt.Errorf("Failed to get store packages (at user request)") - } - - packages := make([]webdm.Package, 1) - packages[0] = webdm.Package{Id: "package1", Status: webdm.StatusNotInstalled} - - return packages, nil -} - -func (manager *FakeWebdmManager) Query(packageId string) (*webdm.Package, error) { - manager.QueryCalled = true - - if manager.FailQuery { - return nil, fmt.Errorf("Failed to query (at user request)") - } - - return &webdm.Package{Id: packageId, Status: webdm.StatusNotInstalled}, nil -} - -func (manager *FakeWebdmManager) Install(packageId string) error { - manager.InstallCalled = true - - if manager.FailInstall { - return fmt.Errorf("Failed to install (at user request)") - } - - return nil -} - -func (manager *FakeWebdmManager) Uninstall(packageId string) error { - manager.UninstallCalled = true - - if manager.FailUninstall { - return fmt.Errorf("Failed to uninstall (at user request)") - } - - return nil -} diff --git a/store/packages/fakes/fake_webdm_manager_test.go b/store/packages/fakes/fake_webdm_manager_test.go deleted file mode 100644 index 01eef65..0000000 --- a/store/packages/fakes/fake_webdm_manager_test.go +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (C) 2015 Canonical Ltd. - * - * This file is part of unity-scope-snappy. - * - * unity-scope-snappy is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * unity-scope-snappy is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. - */ - -package fakes - -import ( - "testing" -) - -// Test typical GetInstalledPackages usage. -func TestFakeWebdmManager_GetInstalledPackages(t *testing.T) { - manager := &FakeWebdmManager{} - - packages, err := manager.GetInstalledPackages("") - if err != nil { - t.Fatalf("Unexpected error while getting installed packages: %s", err) - } - - if len(packages) < 1 { - t.Errorf("Got %d packages, expected at least 1", len(packages)) - } - - if !manager.GetInstalledPackagesCalled { - t.Error("Expected GetInstalledPackagesCalled to have been set") - } -} - -// Test that requesting an error in GetInstalledPackages actually results in an -// error. -func TestFakeWebdmManager_GetInstalledPackages_failureRequest(t *testing.T) { - manager := &FakeWebdmManager{FailGetInstalledPackages: true} - - _, err := manager.GetInstalledPackages("") - if err == nil { - t.Error("Expected an error due to failure request") - } - - if !manager.GetInstalledPackagesCalled { - t.Error("Expected GetInstalledPackagesCalled to have been set") - } -} - -// Test typical GetStorePackages usage. -func TestFakeWebdmManager_GetStorePackages(t *testing.T) { - manager := &FakeWebdmManager{} - - packages, err := manager.GetStorePackages("") - if err != nil { - t.Fatalf("Unexpected error while getting store packages: %s", err) - } - - if len(packages) < 1 { - t.Errorf("Got %d packages, expected at least 1", len(packages)) - } - - if !manager.GetStorePackagesCalled { - t.Error("Expected GetStorePackagesCalled to have been set") - } -} - -// Test that requesting an error in GetStorePackages actually results in an -// error. -func TestFakeWebdmManager_GetStorePackages_failureRequest(t *testing.T) { - manager := &FakeWebdmManager{FailGetStorePackages: true} - - _, err := manager.GetStorePackages("") - if err == nil { - t.Error("Expected an error due to failure request") - } - - if !manager.GetStorePackagesCalled { - t.Error("Expected GetStorePackagesCalled to have been set") - } -} - -// Test typical Query usage. -func TestFakeWebdmManager_Query(t *testing.T) { - manager := &FakeWebdmManager{} - - snap, err := manager.Query("foo") - if err != nil { - t.Fatalf("Unexpected error while querying: %s", err) - } - - if snap == nil { - t.Error("Snap was unexpectedly nil") - } - - if !manager.QueryCalled { - t.Error("Expected QueryCalled to have been set") - } -} - -// Test that requesting an error in Query actually results in an error. -func TestFakeWebdmManager_Query_failureRequest(t *testing.T) { - manager := &FakeWebdmManager{FailQuery: true} - - _, err := manager.Query("foo") - if err == nil { - t.Error("Expected an error due to failure request") - } - - if !manager.QueryCalled { - t.Error("Expected QueryCalled to have been set") - } -} - -// Test typical Install usage. -func TestFakeWebdmManager_Install(t *testing.T) { - manager := &FakeWebdmManager{} - - err := manager.Install("foo") - if err != nil { - t.Fatalf("Unexpected error while installing: %s", err) - } - - if !manager.InstallCalled { - t.Error("Expected InstallCalled to have been set") - } -} - -// Test that requesting an error in Install actually results in an error. -func TestFakeWebdmManager_Install_failureRequest(t *testing.T) { - manager := &FakeWebdmManager{FailInstall: true} - - err := manager.Install("foo") - if err == nil { - t.Error("Expected an error due to failure request") - } - - if !manager.InstallCalled { - t.Error("Expected InstallCalled to have been set") - } -} - -// Test typical Uninstall usage. -func TestFakeWebdmManager_Uninstall(t *testing.T) { - manager := &FakeWebdmManager{} - - err := manager.Uninstall("foo") - if err != nil { - t.Fatalf("Unexpected error while uninstalling: %s", err) - } - - if !manager.UninstallCalled { - t.Error("Expected UninstallCalled to have been set") - } -} - -// Test that requesting an error in Uninstall actually results in an error. -func TestFakeWebdmManager_Uninstall_failureRequest(t *testing.T) { - manager := &FakeWebdmManager{FailUninstall: true} - - err := manager.Uninstall("foo") - if err == nil { - t.Error("Expected an error due to failure request") - } - - if !manager.UninstallCalled { - t.Error("Expected UninstallCalled to have been set") - } -} diff --git a/store/packages/mocks/mock_bus_object.go b/store/packages/mocks/mock_bus_object.go index 85aa2cf..2c0a6a6 100644 --- a/store/packages/mocks/mock_bus_object.go +++ b/store/packages/mocks/mock_bus_object.go @@ -25,14 +25,14 @@ import ( // MockBusObject is a mocked implementation of the dbus.BusObject interface, for // use within tests. type MockBusObject struct { - CallCalled bool - GoCalled bool + CallCalled bool + GoCalled bool GetPropertyCalled bool DestinationCalled bool - PathCalled bool + PathCalled bool Method string - Args []interface{} + Args []interface{} } func (mock *MockBusObject) Call(method string, flags dbus.Flags, args ...interface{}) *dbus.Call { diff --git a/store/packages/snapd_client.go b/store/packages/snapd_client.go new file mode 100644 index 0000000..8007725 --- /dev/null +++ b/store/packages/snapd_client.go @@ -0,0 +1,118 @@ +/* Copyright (C) 2016 Canonical Ltd. + * + * This file is part of unity-scope-snappy. + * + * unity-scope-snappy is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * unity-scope-snappy is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. + */ + +package packages + +import ( + "fmt" + + "github.com/snapcore/snapd/client" +) + +// Client is the main struct allowing for communication with the webdm API. +type SnapdClient struct { + snapdClientConfig client.Config + snapdClient *client.Client +} + +// NewClient creates a new client for communicating with the webdm API +// +// Parameters: +// apiUrl: URL where WebDM is listening (host[:port]) +// +// Returns: +// - Pointer to new client +// - Error (nil if none) +func NewSnapdClient() (*SnapdClient, error) { + snapd := &SnapdClient{} + snapd.snapdClient = client.New(&snapd.snapdClientConfig) + + return snapd, nil +} + +// GetInstalledPackages sends an API request for a list of installed packages. +// +// Parameters: +// query: Search query for list. +// +// Returns: +// - Slice of Packags structs +// - Error (nil of none) +func (snapd *SnapdClient) GetInstalledPackages() (map[string]struct{}) { + snaps, err := snapd.snapdClient.List(nil) + if err != nil { + fmt.Printf("snapd: Error getting installed packages: %s", err) + } + + packages := make(map[string]struct{}, 0) + for _, snap := range snaps { + packages[snap.Name] = struct{}{} + } + return packages +} + +// GetStorePackages sends an API request for a list of all packages in the +// store (including installed packages). +// +// Parameters: +// query: Search query for list. +// +// Returns: +// - Slice of Packags structs +// - Error (nil of none) +func (snapd *SnapdClient) GetStorePackages(query string) ([]client.Snap, error) { + if query == "" { + query = "." + } + snaps, _, err := snapd.snapdClient.Find(&client.FindOptions{ + Query: query, + }) + if err != nil { + return nil, fmt.Errorf("snapd: Error getting store packages: %s", err) + } + + packages := make([]client.Snap, 0) + for _, snap := range snaps { + if snap.Type != client.TypeApp { + continue + } + packages = append(packages, *snap) + } + return packages, nil +} + +func (snapd *SnapdClient) Query(snapName string) (*client.Snap, error) { + // Check first if the snap in question is already installed + pkg, _, err := snapd.snapdClient.Snap(snapName) + if err != nil { + pkg, _, err = snapd.snapdClient.FindOne(snapName) + if err != nil { + return nil, fmt.Errorf("snapd: Error getting package: %s", err) + } + } + + return pkg, nil +} + +func (snapd *SnapdClient) Install(packageId string) error { + return nil +} + +func (snapd *SnapdClient) Uninstall(packageId string) error { + return nil +} diff --git a/store/packages/webdm_manager.go b/store/packages/webdm_manager.go index 0c51bbd..9899f4f 100644 --- a/store/packages/webdm_manager.go +++ b/store/packages/webdm_manager.go @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Canonical Ltd. +/* Copyright (C) 2015-2016 Canonical Ltd. * * This file is part of unity-scope-snappy. * @@ -19,15 +19,15 @@ package packages import ( - "launchpad.net/unity-scope-snappy/webdm" + "github.com/snapcore/snapd/client" ) // WebdmManager is an interface to be implemented by any struct that supports // the type of package management needed by this scope. type WebdmManager interface { - GetInstalledPackages(query string) ([]webdm.Package, error) - GetStorePackages(query string) ([]webdm.Package, error) - Query(packageId string) (*webdm.Package, error) + GetInstalledPackages() (map[string]struct{}) + GetStorePackages(query string) ([]client.Snap, error) + Query(packageId string) (*client.Snap, error) Install(packageId string) error Uninstall(packageId string) error } diff --git a/store/previews/confirm_uninstall_preview.go b/store/previews/confirm_uninstall_preview.go index 68213a1..bbe4f59 100644 --- a/store/previews/confirm_uninstall_preview.go +++ b/store/previews/confirm_uninstall_preview.go @@ -20,23 +20,23 @@ package previews import ( "fmt" + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/actions" "launchpad.net/unity-scope-snappy/store/previews/interfaces" - "launchpad.net/unity-scope-snappy/webdm" ) // ConfirmUninstallPreview is a PreviewGenerator meant to have the user // confirm a request to uninstall a package. type ConfirmUninstallPreview struct { - snap webdm.Package + snap client.Snap } // NewConfirmUninstallPreview creates a new ConfirmUninstallPreview. // // Parameters: // snap: Package which we're being asked to uninstall. -func NewConfirmUninstallPreview(snap webdm.Package) *ConfirmUninstallPreview { +func NewConfirmUninstallPreview(snap client.Snap) *ConfirmUninstallPreview { return &ConfirmUninstallPreview{snap: snap} } diff --git a/store/previews/confirm_uninstall_preview_test.go b/store/previews/confirm_uninstall_preview_test.go index 26ec00e..d2c1b0d 100644 --- a/store/previews/confirm_uninstall_preview_test.go +++ b/store/previews/confirm_uninstall_preview_test.go @@ -20,15 +20,16 @@ package previews import ( "fmt" + + "github.com/snapcore/snapd/client" "launchpad.net/unity-scope-snappy/store/actions" "launchpad.net/unity-scope-snappy/store/previews/fakes" - "launchpad.net/unity-scope-snappy/webdm" "testing" ) // Test typical NewPackagePreview usage. func TestNewConfirmUninstallPreview(t *testing.T) { - snap := webdm.Package{Name: "package1"} + snap := client.Snap{Name: "package1"} preview := NewConfirmUninstallPreview(snap) if preview == nil { @@ -43,7 +44,7 @@ func TestNewConfirmUninstallPreview(t *testing.T) { // Test typical Generate usage, and verify that it conforms to store design. func TestConfirmUninstallPreview_generate(t *testing.T) { - snap := webdm.Package{Name: "package1"} + snap := client.Snap{Name: "package1"} preview := NewConfirmUninstallPreview(snap) receiver := new(fakes.FakeWidgetReceiver) diff --git a/store/previews/packages/preview.go b/store/previews/packages/preview.go index e59b074..70066e9 100644 --- a/store/previews/packages/preview.go +++ b/store/previews/packages/preview.go @@ -19,11 +19,11 @@ package packages import ( - "fmt" + "github.com/snapcore/snapd/client" + "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/operation" "launchpad.net/unity-scope-snappy/store/previews/interfaces" "launchpad.net/unity-scope-snappy/store/previews/packages/templates" - "launchpad.net/unity-scope-snappy/webdm" ) // Preview is a PreviewGenerator representing a given package. @@ -35,27 +35,24 @@ type Preview struct { // // Parameters: // snap: Package to be represented by the preview. -func NewPreview(snap webdm.Package, metadata operation.Metadata) (*Preview, error) { +func NewPreview(snap client.Snap, result *scopes.Result, metadata operation.Metadata) (*Preview, error) { preview := new(Preview) var err error - if metadata.InstallRequested && !snap.Installed() { - if snap.Uninstalling() { - return nil, fmt.Errorf("Install requested, but package is uninstalling") - } - - preview.template, err = templates.NewInstallingTemplate(snap, metadata.ObjectPath) - } else if metadata.UninstallConfirmed && !snap.NotInstalled() { - if snap.Installing() { - return nil, fmt.Errorf("Uninstall requested, but package is installing") - } - + installed := false + if (snap.Status == client.StatusInstalled || + snap.Status == client.StatusActive) { + installed = true + } + if metadata.InstallRequested && !installed { + preview.template, err = templates.NewInstallingTemplate(snap, result, metadata.ObjectPath) + } else if metadata.UninstallConfirmed && installed { preview.template, err = templates.NewUninstallingTemplate(snap, metadata.ObjectPath) } else { - if snap.Installed() { + if installed { preview.template, err = templates.NewInstalledTemplate(snap) } else { - preview.template, err = templates.NewStoreTemplate(snap) + preview.template, err = templates.NewStoreTemplate(snap, result) } } diff --git a/store/previews/packages/preview_test.go b/store/previews/packages/preview_test.go index b813be8..3e23608 100644 --- a/store/previews/packages/preview_test.go +++ b/store/previews/packages/preview_test.go @@ -19,10 +19,10 @@ package packages import ( + "github.com/snapcore/snapd/client" "launchpad.net/unity-scope-snappy/store/operation" "launchpad.net/unity-scope-snappy/store/previews/fakes" "launchpad.net/unity-scope-snappy/store/previews/packages/templates" - "launchpad.net/unity-scope-snappy/webdm" "reflect" "testing" ) @@ -33,59 +33,36 @@ var ( uninstallMetadata = operation.Metadata{UninstallConfirmed: true, ObjectPath: "/foo/1"} ) -// Data for both TestNewPreview_invalidMetadata -var invalidMetadataTests = []struct { - status webdm.Status - metadata operation.Metadata -}{ - {webdm.StatusUninstalling, installMetadata}, - {webdm.StatusInstalling, uninstallMetadata}, - {webdm.StatusUndefined, uninstallMetadata}, -} - -// Test that calling NewPreview with invalid metadata results in an error. -func TestNewPreview_invalidMetadata(t *testing.T) { - for i, test := range invalidMetadataTests { - snap := webdm.Package{Status: test.status} - - _, err := NewPreview(snap, test.metadata) - if err == nil { - t.Errorf("Test case %d: Expected an error due to invalid metadata", i) - } - } -} - // Data for both TestNewPreview and TestPreview_generate. var previewTests = []struct { - status webdm.Status + status string metadata operation.Metadata expectedTemplate interface{} }{ // No metadata - {webdm.StatusUndefined, emptyMetadata, &templates.StoreTemplate{}}, - {webdm.StatusInstalled, emptyMetadata, &templates.InstalledTemplate{}}, - {webdm.StatusNotInstalled, emptyMetadata, &templates.StoreTemplate{}}, - {webdm.StatusInstalling, emptyMetadata, &templates.StoreTemplate{}}, - {webdm.StatusUninstalling, emptyMetadata, &templates.StoreTemplate{}}, + {client.StatusInstalled, emptyMetadata, &templates.InstalledTemplate{}}, + {client.StatusAvailable, emptyMetadata, &templates.StoreTemplate{}}, + {client.StatusRemoved, emptyMetadata, &templates.StoreTemplate{}}, + {client.StatusActive, emptyMetadata, &templates.InstalledTemplate{}}, // Metadata requesting install - {webdm.StatusUndefined, installMetadata, &templates.InstallingTemplate{}}, - {webdm.StatusInstalled, installMetadata, &templates.InstalledTemplate{}}, - {webdm.StatusNotInstalled, installMetadata, &templates.InstallingTemplate{}}, - {webdm.StatusInstalling, installMetadata, &templates.InstallingTemplate{}}, + {client.StatusInstalled, installMetadata, &templates.InstalledTemplate{}}, + {client.StatusAvailable, installMetadata, &templates.InstallingTemplate{}}, + {client.StatusRemoved, installMetadata, &templates.InstallingTemplate{}}, // Metadata requesting uninstall - {webdm.StatusInstalled, uninstallMetadata, &templates.UninstallingTemplate{}}, - {webdm.StatusNotInstalled, uninstallMetadata, &templates.StoreTemplate{}}, - {webdm.StatusUninstalling, uninstallMetadata, &templates.UninstallingTemplate{}}, + {client.StatusInstalled, uninstallMetadata, &templates.UninstallingTemplate{}}, + {client.StatusActive, uninstallMetadata, &templates.UninstallingTemplate{}}, + {client.StatusAvailable, uninstallMetadata, &templates.StoreTemplate{}}, + {client.StatusRemoved, uninstallMetadata, &templates.StoreTemplate{}}, } // Test typical NewPreview usage. func TestNewPreview(t *testing.T) { for i, test := range previewTests { - snap := webdm.Package{Status: test.status} + snap := client.Snap{Status: test.status} - preview, err := NewPreview(snap, test.metadata) + preview, err := NewPreview(snap, nil, test.metadata) if err != nil { t.Errorf("Test case %d: Unexpected error: %s", i, err) continue @@ -102,18 +79,17 @@ func TestNewPreview(t *testing.T) { // Test typical Generate usage, and verify that it conforms to store design. func TestPreview_generate(t *testing.T) { for i, test := range previewTests { - preview, err := NewPreview(webdm.Package{ - Id: "package1", + preview, err := NewPreview(client.Snap{ + ID: "package1", Name: "package1", - Origin: "foo", Version: "0.1", - Vendor: "bar", + Developer: "bar", Description: "baz", - IconUrl: "http://fake", + Icon: "http://fake", Status: test.status, DownloadSize: 123456, - Type: "oem", - }, test.metadata) + Type: "app", + }, nil, test.metadata) if err != nil { t.Errorf("Test case %d: Unexpected error while creating package preview: %s", i, err) continue diff --git a/store/previews/packages/templates/generic_template.go b/store/previews/packages/templates/generic_template.go index 232f66b..47e3308 100644 --- a/store/previews/packages/templates/generic_template.go +++ b/store/previews/packages/templates/generic_template.go @@ -19,19 +19,19 @@ package templates import ( + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" - "launchpad.net/unity-scope-snappy/webdm" ) // GenericTemplate is a Template implementation that doesn't contain any // conditionals depending on package information. It's meant to be embedded in // other structs and further specialized. type GenericTemplate struct { - snap webdm.Package + snap client.Snap } // NewGenericTemplate creates a new GenericTemplate. -func NewGenericTemplate(snap webdm.Package) *GenericTemplate { +func NewGenericTemplate(snap client.Snap) *GenericTemplate { return &GenericTemplate{snap: snap} } diff --git a/store/previews/packages/templates/generic_template_test.go b/store/previews/packages/templates/generic_template_test.go index 3f01891..46d95bb 100644 --- a/store/previews/packages/templates/generic_template_test.go +++ b/store/previews/packages/templates/generic_template_test.go @@ -19,38 +19,37 @@ package templates import ( - "launchpad.net/unity-scope-snappy/webdm" + "github.com/snapcore/snapd/client" "testing" ) var ( - webdmPackage *webdm.Package - template *GenericTemplate + snap *client.Snap + template *GenericTemplate ) func setup() { - webdmPackage = &webdm.Package{ - Id: "package1", + snap = &client.Snap{ + ID: "package1", Name: "package1", - Origin: "foo", Version: "0.1", - Vendor: "bar", + Developer: "bar", Description: "baz", - IconUrl: "http://fake", - Status: webdm.StatusNotInstalled, + Icon: "http://fake", + Status: client.StatusAvailable, DownloadSize: 123456, - Type: "oem", + Type: "app", } - template = NewGenericTemplate(*webdmPackage) + template = NewGenericTemplate(*snap) } // Test typical NewGenericTemplate usage. func TestNewGenericTemplate(t *testing.T) { setup() - if template.snap.Id != "package1" { - t.Errorf(`Template snap's ID was "%s", expected "package1"`, template.snap.Id) + if template.snap.ID != "package1" { + t.Errorf(`Template snap's ID was "%s", expected "package1"`, template.snap.ID) } } @@ -137,8 +136,8 @@ func TestNewGenericTemplate_infoWidget(t *testing.T) { if !ok { t.Error("Expected info widget to include a description") } - if value != webdmPackage.Description { - t.Errorf(`Got "%s" as the description, expected "%s"`, value, webdmPackage.Description) + if value != snap.Description { + t.Errorf(`Got "%s" as the description, expected "%s"`, value, snap.Description) } } @@ -184,7 +183,7 @@ func TestNewGenericTemplate_updatesWidget(t *testing.T) { if versionRow[0] != "Version number" { t.Errorf(`First column was "%s", expected "Version number"`, versionRow[0]) } - if versionRow[1] != webdmPackage.Version { - t.Errorf(`Second column was "%s", expected "%s"`, versionRow[1], webdmPackage.Version) + if versionRow[1] != snap.Version { + t.Errorf(`Second column was "%s", expected "%s"`, versionRow[1], snap.Version) } } diff --git a/store/previews/packages/templates/installed_template.go b/store/previews/packages/templates/installed_template.go index e128427..fbed72b 100644 --- a/store/previews/packages/templates/installed_template.go +++ b/store/previews/packages/templates/installed_template.go @@ -20,15 +20,17 @@ package templates import ( "fmt" + + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/actions" "launchpad.net/unity-scope-snappy/store/previews/humanize" - "launchpad.net/unity-scope-snappy/webdm" ) // InstalledTemplate is a preview template for an installed package. type InstalledTemplate struct { *GenericTemplate + snap client.Snap } // NewInstalledTemplate creates a new InstalledTemplate. @@ -39,13 +41,10 @@ type InstalledTemplate struct { // Returns: // - Pointer to new InstalledTemplate (nil if error) // - Error (nil if none) -func NewInstalledTemplate(snap webdm.Package) (*InstalledTemplate, error) { - if !(snap.Installed() || snap.Uninstalling()) { - return nil, fmt.Errorf("Snap is not installed") - } - +func NewInstalledTemplate(snap client.Snap) (*InstalledTemplate, error) { template := new(InstalledTemplate) template.GenericTemplate = NewGenericTemplate(snap) + template.snap = snap return template, nil } @@ -59,7 +58,7 @@ func (preview InstalledTemplate) HeaderWidget() scopes.PreviewWidget { widget := preview.GenericTemplate.HeaderWidget() priceAttribute := make(map[string]interface{}) - priceAttribute["value"] = "✓ Installed" + priceAttribute["value"] = "✔ INSTALLED" widget.AddAttributeValue("attributes", []interface{}{priceAttribute}) return widget @@ -72,15 +71,26 @@ func (preview InstalledTemplate) HeaderWidget() scopes.PreviewWidget { func (preview InstalledTemplate) ActionsWidget() scopes.PreviewWidget { widget := preview.GenericTemplate.ActionsWidget() - openAction := make(map[string]interface{}) - openAction["id"] = actions.ActionOpen - openAction["label"] = "Open" + previewActions := make([]interface{}, 0) + + // Only show Open if we can get the URI + if len(preview.snap.Apps) != 0 { + uri := fmt.Sprintf("appid://%s/%s/current-user-version", + preview.snap.Name, preview.snap.Apps[0].Name) + + openAction := make(map[string]interface{}) + openAction["id"] = actions.ActionOpen + openAction["label"] = "Open" + openAction["uri"] = uri + previewActions = append(previewActions, openAction) + } uninstallAction := make(map[string]interface{}) uninstallAction["id"] = actions.ActionUninstall uninstallAction["label"] = "Uninstall" + previewActions = append(previewActions, uninstallAction) - widget.AddAttributeValue("actions", []interface{}{openAction, uninstallAction}) + widget.AddAttributeValue("actions", previewActions) return widget } diff --git a/store/previews/packages/templates/installed_template_test.go b/store/previews/packages/templates/installed_template_test.go index 9c468e4..367fb17 100644 --- a/store/previews/packages/templates/installed_template_test.go +++ b/store/previews/packages/templates/installed_template_test.go @@ -19,39 +19,17 @@ package templates import ( + "github.com/snapcore/snapd/client" "launchpad.net/unity-scope-snappy/store/actions" - "launchpad.net/unity-scope-snappy/webdm" "testing" ) -// Data for TestNewInstalledTemplate_notInstalled -var notInstalledTemplateTests = []struct { - status webdm.Status -}{ - {webdm.StatusUndefined}, - {webdm.StatusNotInstalled}, - {webdm.StatusInstalling}, -} - -// Make sure an error occurs if the package is not installed -func TestNewInstalledTemplate_notInstalled(t *testing.T) { - for i, test := range notInstalledTemplateTests { - _, err := NewInstalledTemplate(webdm.Package{ - Status: test.status, - }) - - if err == nil { - t.Errorf("Test case %d: Expected an error due to invalid status", i) - } - } -} - // Data for InstalledTemplate tests var installedTemplateTests = []struct { - snap webdm.Package + snap client.Snap }{ - {webdm.Package{Id: "package1", Status: webdm.StatusInstalled, Version: "0.1", InstalledSize: 123456}}, - {webdm.Package{Id: "package1", Status: webdm.StatusUninstalling, Version: "0.1", InstalledSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusInstalled, Version: "0.1", InstalledSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusActive, Version: "0.1", InstalledSize: 123456}}, } // Test typical NewInstalledTemplate usage. @@ -63,8 +41,8 @@ func TestNewInstalledTemplate(t *testing.T) { continue } - if template.snap.Id != test.snap.Id { - t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.Id, test.snap.Id) + if template.snap.ID != test.snap.ID { + t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.ID, test.snap.ID) } } } @@ -98,8 +76,8 @@ func TestInstalledTemplate_headerWidget(t *testing.T) { if !ok { t.Errorf(`Test case %d: Expected generic header attribute to have "value" key`, i) } - if value != "✓ Installed" { - t.Errorf(`Test case %d: Generic header attribute "value" was "%s", expected "✓ Installed"`, i, value) + if value != "✔ INSTALLED" { + t.Errorf(`Test case %d: Generic header attribute "value" was "%s", expected "✔ INSTALLED"`, i, value) } } } @@ -123,13 +101,16 @@ func TestInstalledTemplate_actionsWidget(t *testing.T) { actionsInterfaces := value.([]interface{}) - if len(actionsInterfaces) != 2 { + // Can only test for nil result, so no Open button + if len(actionsInterfaces) != 1 { t.Errorf("Test case %d: Actions widget has %d actions, expected 2", i, len(actionsInterfaces)) continue } // Verify the open action + // FIXME: Open action cannot currently be tested action := actionsInterfaces[0].(map[string]interface{}) +/* value, ok = action["id"] if !ok { t.Errorf("Test case %d: Expected open action to have an id", i) @@ -145,9 +126,10 @@ func TestInstalledTemplate_actionsWidget(t *testing.T) { if value != "Open" { t.Errorf(`Test case %d: Open action's label was "%s", expected "Open"`, i, value) } +*/ // Verify the uninstall action - action = actionsInterfaces[1].(map[string]interface{}) + // action = actionsInterfaces[1].(map[string]interface{}) value, ok = action["id"] if !ok { t.Errorf("Test case %d: Expected uninstall action to have an id", i) diff --git a/store/previews/packages/templates/installing_template.go b/store/previews/packages/templates/installing_template.go index a206264..6162858 100644 --- a/store/previews/packages/templates/installing_template.go +++ b/store/previews/packages/templates/installing_template.go @@ -21,8 +21,8 @@ package templates import ( "fmt" "github.com/godbus/dbus" + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" - "launchpad.net/unity-scope-snappy/webdm" ) // InstallingTemplate is a preview template for a package that is currently @@ -41,10 +41,7 @@ type InstallingTemplate struct { // Returns: // - Pointer to new InstallingTemplate (nil if error) // - Error (nil if none) -func NewInstallingTemplate(snap webdm.Package, objectPath dbus.ObjectPath) (*InstallingTemplate, error) { - if snap.Uninstalling() { - return nil, fmt.Errorf("Snap is currently being uninstalled") - } +func NewInstallingTemplate(snap client.Snap, result *scopes.Result, objectPath dbus.ObjectPath) (*InstallingTemplate, error) { if !objectPath.IsValid() { return nil, fmt.Errorf(`Invalid object path: "%s"`, objectPath) @@ -53,7 +50,7 @@ func NewInstallingTemplate(snap webdm.Package, objectPath dbus.ObjectPath) (*Ins template := &InstallingTemplate{objectPath: objectPath} var err error - template.StoreTemplate, err = NewStoreTemplate(snap) + template.StoreTemplate, err = NewStoreTemplate(snap, result) if err != nil { return nil, fmt.Errorf("Unable to create store template: %s", err) } diff --git a/store/previews/packages/templates/installing_template_test.go b/store/previews/packages/templates/installing_template_test.go index 24ad36f..106d14f 100644 --- a/store/previews/packages/templates/installing_template_test.go +++ b/store/previews/packages/templates/installing_template_test.go @@ -20,37 +20,29 @@ package templates import ( "github.com/godbus/dbus" - "launchpad.net/unity-scope-snappy/webdm" + "github.com/snapcore/snapd/client" "testing" ) // Data for InstallingTemplate tests var installingTemplateTests = []struct { - snap webdm.Package - expectError bool + snap client.Snap }{ - {webdm.Package{Id: "package1", Status: webdm.StatusUndefined, Version: "0.1", DownloadSize: 123456}, false}, - {webdm.Package{Id: "package1", Status: webdm.StatusInstalled, Version: "0.1", InstalledSize: 123456}, true}, - {webdm.Package{Id: "package1", Status: webdm.StatusNotInstalled, Version: "0.1", DownloadSize: 123456}, false}, - {webdm.Package{Id: "package1", Status: webdm.StatusInstalling, Version: "0.1", DownloadSize: 123456}, false}, - {webdm.Package{Id: "package1", Status: webdm.StatusUninstalling, Version: "0.1", DownloadSize: 123456}, true}, + {client.Snap{ID: "package1", Status: client.StatusAvailable, Version: "0.1", DownloadSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusRemoved, Version: "0.1", DownloadSize: 123456}}, } // Test typical NewInstallingTemplate usage. func TestNewInstallingTemplate(t *testing.T) { for i, test := range installingTemplateTests { - template, err := NewInstallingTemplate(test.snap, "/foo/1") - if err == nil && test.expectError { - t.Errorf("Test case %d: Expected error due to incorrect status", i) - } else if err != nil { - if !test.expectError { - t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) - } + template, err := NewInstallingTemplate(test.snap, nil, "/foo/1") + if err != nil { + t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue } - if template.snap.Id != test.snap.Id { - t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.Id, test.snap.Id) + if template.snap.ID != test.snap.ID { + t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.ID, test.snap.ID) } } } @@ -58,7 +50,7 @@ func TestNewInstallingTemplate(t *testing.T) { // Test that calling NewInstallingTemplate with an invalid object path results // in an error. func TestNewInstallingTemplate_invalidObjectPath(t *testing.T) { - _, err := NewInstallingTemplate(webdm.Package{}, "invalid") + _, err := NewInstallingTemplate(client.Snap{}, nil, "invalid") if err == nil { t.Error("Expected an error due to invalid object path") } @@ -67,13 +59,9 @@ func TestNewInstallingTemplate_invalidObjectPath(t *testing.T) { // Test that the actions widget conforms to the store design. func TestInstallingTemplate_actionsWidget(t *testing.T) { for i, test := range installingTemplateTests { - template, err := NewInstallingTemplate(test.snap, "/foo/1") - if err == nil && test.expectError { - t.Errorf("Test case %d: Expected error due to incorrect status", i) - } else if err != nil { - if !test.expectError { - t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) - } + template, err := NewInstallingTemplate(test.snap, nil, "/foo/1") + if err != nil { + t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue } diff --git a/store/previews/packages/templates/store_template.go b/store/previews/packages/templates/store_template.go index 4949673..95bbe8e 100644 --- a/store/previews/packages/templates/store_template.go +++ b/store/previews/packages/templates/store_template.go @@ -19,17 +19,17 @@ package templates import ( - "fmt" + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/actions" "launchpad.net/unity-scope-snappy/store/previews/humanize" - "launchpad.net/unity-scope-snappy/webdm" ) // StoreTemplate is a preview template for an in-store package // (i.e. not installed). type StoreTemplate struct { *GenericTemplate + result *scopes.Result } // NewStoreTemplate creates a new StoreTemplate. @@ -40,13 +40,10 @@ type StoreTemplate struct { // Returns: // - Pointer to new StoreTemplate (nil if error) // - Error (nil if none) -func NewStoreTemplate(snap webdm.Package) (*StoreTemplate, error) { - if snap.Installed() { - return nil, fmt.Errorf("Snap is installed") - } - +func NewStoreTemplate(snap client.Snap, result *scopes.Result) (*StoreTemplate, error) { template := new(StoreTemplate) template.GenericTemplate = NewGenericTemplate(snap) + template.result = result return template, nil } @@ -62,7 +59,11 @@ func (preview StoreTemplate) HeaderWidget() scopes.PreviewWidget { // WebDM doesn't provide any information about the cost of apps... so all // the snaps are free! priceAttribute := make(map[string]interface{}) - priceAttribute["value"] = "FREE" + if preview.result != nil { + var price_area string + preview.result.Get("price_area", &price_area) + priceAttribute["value"] = price_area + } widget.AddAttributeValue("attributes", []interface{}{priceAttribute}) return widget diff --git a/store/previews/packages/templates/store_template_test.go b/store/previews/packages/templates/store_template_test.go index 5d61ee4..91d0dfd 100644 --- a/store/previews/packages/templates/store_template_test.go +++ b/store/previews/packages/templates/store_template_test.go @@ -19,43 +19,31 @@ package templates import ( + "github.com/snapcore/snapd/client" "launchpad.net/unity-scope-snappy/store/actions" - "launchpad.net/unity-scope-snappy/webdm" "testing" ) -// Make sure an error occurs if the package is installed -func TestNewStoreTemplate_installed(t *testing.T) { - _, err := NewStoreTemplate(webdm.Package{ - Status: webdm.StatusInstalled, - }) - - if err == nil { - t.Error("Expected an error if the package is installed") - } -} - // Data for StoreTemplate tests var storeTemplateTests = []struct { - snap webdm.Package + snap client.Snap }{ - {webdm.Package{Id: "package1", Status: webdm.StatusUndefined, Version: "0.1", DownloadSize: 123456}}, - {webdm.Package{Id: "package1", Status: webdm.StatusNotInstalled, Version: "0.1", DownloadSize: 123456}}, - {webdm.Package{Id: "package1", Status: webdm.StatusInstalling, Version: "0.1", DownloadSize: 123456}}, - {webdm.Package{Id: "package1", Status: webdm.StatusUninstalling, Version: "0.1", DownloadSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusAvailable, Version: "0.1", DownloadSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusRemoved, Version: "0.1", DownloadSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusActive, Version: "0.1", DownloadSize: 123456}}, } // Test typical NewStoreTemplate usage. func TestNewStoreTemplate(t *testing.T) { for i, test := range storeTemplateTests { - template, err := NewStoreTemplate(test.snap) + template, err := NewStoreTemplate(test.snap, nil) if err != nil { t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue } - if template.snap.Id != test.snap.Id { - t.Errorf(`Template snap's ID is "%s", expected "%s"`, template.snap.Id, test.snap.Id) + if template.snap.ID != test.snap.ID { + t.Errorf(`Template snap's ID is "%s", expected "%s"`, template.snap.ID, test.snap.ID) } } } @@ -63,7 +51,7 @@ func TestNewStoreTemplate(t *testing.T) { // Test that the header widget conforms to the store design. func TestStoreTemplate_headerWidget(t *testing.T) { for i, test := range storeTemplateTests { - template, err := NewStoreTemplate(test.snap) + template, err := NewStoreTemplate(test.snap, nil) if err != nil { t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue @@ -84,6 +72,7 @@ func TestStoreTemplate_headerWidget(t *testing.T) { continue } +/* FIXME: Unable to test price attribute here as we get it from result attribute := attributes[0].(map[string]interface{}) value, ok = attribute["value"] if !ok { @@ -93,13 +82,14 @@ func TestStoreTemplate_headerWidget(t *testing.T) { if value != "FREE" { t.Errorf(`Test case %d: Generic header attribute was "%s", expected "FREE"`, i, value) } +*/ } } // Test that the actions widget conforms to the store design. func TestStoreTemplate_actionsWidget(t *testing.T) { for i, test := range storeTemplateTests { - template, err := NewStoreTemplate(test.snap) + template, err := NewStoreTemplate(test.snap, nil) if err != nil { t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue @@ -143,7 +133,7 @@ func TestStoreTemplate_actionsWidget(t *testing.T) { // Test that the updates widget conforms to the store design. func TestStoreTemplate_updatesWidget(t *testing.T) { for i, test := range storeTemplateTests { - template, err := NewStoreTemplate(test.snap) + template, err := NewStoreTemplate(test.snap, nil) if err != nil { t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue diff --git a/store/previews/packages/templates/uninstalling_template.go b/store/previews/packages/templates/uninstalling_template.go index f50e15a..68eea5f 100644 --- a/store/previews/packages/templates/uninstalling_template.go +++ b/store/previews/packages/templates/uninstalling_template.go @@ -21,8 +21,8 @@ package templates import ( "fmt" "github.com/godbus/dbus" + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" - "launchpad.net/unity-scope-snappy/webdm" ) // UninstallingTemplate is a preview template for a package that is currently @@ -41,10 +41,7 @@ type UninstallingTemplate struct { // Returns: // - Pointer to new UninstallingTemplate (nil if error) // - Error (nil if none) -func NewUninstallingTemplate(snap webdm.Package, objectPath dbus.ObjectPath) (*UninstallingTemplate, error) { - if snap.Installing() { - return nil, fmt.Errorf("Snap is currently being installed") - } +func NewUninstallingTemplate(snap client.Snap, objectPath dbus.ObjectPath) (*UninstallingTemplate, error) { if !objectPath.IsValid() { return nil, fmt.Errorf(`Invalid object path: "%s"`, objectPath) diff --git a/store/previews/packages/templates/uninstalling_template_test.go b/store/previews/packages/templates/uninstalling_template_test.go index 32b2993..4c016b5 100644 --- a/store/previews/packages/templates/uninstalling_template_test.go +++ b/store/previews/packages/templates/uninstalling_template_test.go @@ -20,37 +20,29 @@ package templates import ( "github.com/godbus/dbus" - "launchpad.net/unity-scope-snappy/webdm" + "github.com/snapcore/snapd/client" "testing" ) // Data for UninstallingTemplate tests var uninstallingTemplateTests = []struct { - snap webdm.Package - expectError bool + snap client.Snap }{ - {webdm.Package{Id: "package1", Status: webdm.StatusUndefined, Version: "0.1", DownloadSize: 123456}, true}, - {webdm.Package{Id: "package1", Status: webdm.StatusInstalled, Version: "0.1", InstalledSize: 123456}, false}, - {webdm.Package{Id: "package1", Status: webdm.StatusNotInstalled, Version: "0.1", DownloadSize: 123456}, true}, - {webdm.Package{Id: "package1", Status: webdm.StatusInstalling, Version: "0.1", DownloadSize: 123456}, true}, - {webdm.Package{Id: "package1", Status: webdm.StatusUninstalling, Version: "0.1", DownloadSize: 123456}, false}, + {client.Snap{ID: "package1", Status: client.StatusInstalled, Version: "0.1", InstalledSize: 123456}}, + {client.Snap{ID: "package1", Status: client.StatusActive, Version: "0.1", DownloadSize: 123456}}, } // Test typical NewUninstallingTemplate usage. func TestNewUninstallingTemplate(t *testing.T) { for i, test := range uninstallingTemplateTests { template, err := NewUninstallingTemplate(test.snap, "/foo/1") - if err == nil && test.expectError { - t.Errorf("Test case %d: Expected error due to incorrect status", i) - } else if err != nil { - if !test.expectError { - t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) - } + if err != nil { + t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue } - if template.snap.Id != test.snap.Id { - t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.Id, test.snap.Id) + if template.snap.ID != test.snap.ID { + t.Errorf(`Test case %d: Template snap's ID is "%s", expected "%s"`, i, template.snap.ID, test.snap.ID) } } } @@ -58,7 +50,7 @@ func TestNewUninstallingTemplate(t *testing.T) { // Test that calling NewUninstallingTemplate with an invalid object path results // in an error. func TestNewUninstallingTemplate_invalidObjectPath(t *testing.T) { - _, err := NewUninstallingTemplate(webdm.Package{}, "invalid") + _, err := NewUninstallingTemplate(client.Snap{}, "invalid") if err == nil { t.Error("Expected an error due to invalid object path") } @@ -68,12 +60,8 @@ func TestNewUninstallingTemplate_invalidObjectPath(t *testing.T) { func TestUninstallingTemplate_actionsWidget(t *testing.T) { for i, test := range uninstallingTemplateTests { template, err := NewUninstallingTemplate(test.snap, "/foo/1") - if err == nil && test.expectError { - t.Errorf("Test case %d: Expected error due to incorrect status", i) - } else if err != nil { - if !test.expectError { - t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) - } + if err != nil { + t.Errorf("Test case %d: Unexpected error creating template: %s", i, err) continue } diff --git a/store/previews/preview_generator.go b/store/previews/preview_generator.go index 1db89b1..3108b9b 100644 --- a/store/previews/preview_generator.go +++ b/store/previews/preview_generator.go @@ -19,11 +19,11 @@ package previews import ( + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/operation" "launchpad.net/unity-scope-snappy/store/previews/interfaces" "launchpad.net/unity-scope-snappy/store/previews/packages" - "launchpad.net/unity-scope-snappy/webdm" ) // NewPreview is a factory for getting the correct preview for a given package. @@ -31,7 +31,7 @@ import ( // Parameters: // snap: Snap to be represented by the preview. // metadata: Metadata to be used for informing the preview creation. -func NewPreview(snap webdm.Package, metadata *scopes.ActionMetadata) (interfaces.PreviewGenerator, error) { +func NewPreview(snap client.Snap, result *scopes.Result, metadata *scopes.ActionMetadata) (interfaces.PreviewGenerator, error) { var operationMetadata operation.Metadata // This may fail, but the zero-value of OperationMetadata is fine @@ -43,5 +43,5 @@ func NewPreview(snap webdm.Package, metadata *scopes.ActionMetadata) (interfaces return NewConfirmUninstallPreview(snap), nil } - return packages.NewPreview(snap, operationMetadata) + return packages.NewPreview(snap, result, operationMetadata) } diff --git a/store/previews/preview_generator_test.go b/store/previews/preview_generator_test.go index 78f96c4..f6fbf3b 100644 --- a/store/previews/preview_generator_test.go +++ b/store/previews/preview_generator_test.go @@ -19,40 +19,38 @@ package previews import ( + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/operation" "launchpad.net/unity-scope-snappy/store/previews/packages" - "launchpad.net/unity-scope-snappy/webdm" "reflect" "testing" ) // Data for TestNewPreview. var newPreviewTests = []struct { - status webdm.Status + status string scopeData *operation.Metadata expected interface{} }{ - {webdm.StatusUndefined, nil, &packages.Preview{}}, - {webdm.StatusInstalled, nil, &packages.Preview{}}, - {webdm.StatusNotInstalled, nil, &packages.Preview{}}, - {webdm.StatusInstalling, nil, &packages.Preview{}}, - {webdm.StatusUninstalling, nil, &packages.Preview{}}, + {client.StatusInstalled, nil, &packages.Preview{}}, + {client.StatusAvailable, nil, &packages.Preview{}}, + {client.StatusActive, nil, &packages.Preview{}}, + {client.StatusRemoved, nil, &packages.Preview{}}, // Uninstallation confirmation test cases - {webdm.StatusUndefined, &operation.Metadata{UninstallRequested: true}, &ConfirmUninstallPreview{}}, - {webdm.StatusInstalled, &operation.Metadata{UninstallRequested: true}, &ConfirmUninstallPreview{}}, + {client.StatusInstalled, &operation.Metadata{UninstallRequested: true}, &ConfirmUninstallPreview{}}, } // Test typical NewPreview usage. func TestNewPreview(t *testing.T) { for i, test := range newPreviewTests { - snap := webdm.Package{Status: test.status} + snap := client.Snap{Status: test.status} metadata := scopes.NewActionMetadata("us", "phone") metadata.SetScopeData(test.scopeData) - preview, err := NewPreview(snap, metadata) + preview, err := NewPreview(snap, nil, metadata) if err != nil { t.Errorf("Test case %d: Unexpected error: %s", i, err) } diff --git a/store/scope/scope.go b/store/scope/scope.go index 1a07d4e..b64a89e 100644 --- a/store/scope/scope.go +++ b/store/scope/scope.go @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Canonical Ltd. +/* Copyright (C) 2015-2016 Canonical Ltd. * * This file is part of unity-scope-snappy. * @@ -20,13 +20,13 @@ package scope import ( "fmt" + "log" + + "github.com/snapcore/snapd/client" "launchpad.net/go-unityscopes/v2" "launchpad.net/unity-scope-snappy/store/actions" "launchpad.net/unity-scope-snappy/store/packages" "launchpad.net/unity-scope-snappy/store/previews" - "launchpad.net/unity-scope-snappy/store/utilities" - "launchpad.net/unity-scope-snappy/webdm" - "log" ) // template for the grid layout of the search results. @@ -38,31 +38,33 @@ const layout = `{ }, "components": { "title": "title", + "subtitle": "subtitle", + "attributes": { "field": "attributes", "max-count": 4 }, "art" : { - "field": "art" - }, - "subtitle": "subtitle" - } + "field": "art", + "aspect-ratio": 1.13, + "fallback": "image://theme/placeholder-app-icon" + } + } }` // Scope is the struct representing the scope itself. type Scope struct { - webdmClient *webdm.Client + webdmClient packages.WebdmManager dbusClient *packages.DbusManagerClient } // New creates a new Scope using a specific WebDM API URL. // // Parameters: -// webdmApiUrl: URL where WebDM is listening. // // Returns: // - Pointer to scope (nil if error). // - Error (nil if none). -func New(webdmApiUrl string) (*Scope, error) { +func New() (*Scope, error) { scope := new(Scope) var err error - scope.webdmClient, err = webdm.NewClient(webdmApiUrl) + scope.webdmClient, err = packages.NewSnapdClient() if err != nil { return nil, fmt.Errorf("Unable to create WebDM client: %s", err) } @@ -81,22 +83,18 @@ func (scope Scope) SetScopeBase(base *scopes.ScopeBase) { } func (scope Scope) Search(query *scopes.CannedQuery, metadata *scopes.SearchMetadata, reply *scopes.SearchReply, cancelled <-chan bool) error { - createDepartments(query, reply) - - packages, err := utilities.GetPackageList(scope.webdmClient, query.DepartmentID(), query.QueryString()) + installedApps := scope.webdmClient.GetInstalledPackages() + available, err := scope.webdmClient.GetStorePackages(query.QueryString()) if err != nil { return scopeError("unity-scope-snappy: Unable to get package list: %s", err) } var category *scopes.Category - if query.DepartmentID() == "installed" { - category = reply.RegisterCategory("installed_packages", "Installed Packages", "", layout) - } else { - category = reply.RegisterCategory("store_packages", "Store Packages", "", layout) - } + category = reply.RegisterCategory("store_packages", "Store Packages", "", layout) - for _, thisPackage := range packages { - result := packageResult(category, thisPackage) + for _, thisPackage := range available { + _, ok := installedApps[thisPackage.Name] + result := packageResult(category, thisPackage, ok) if reply.Push(result) != nil { // If the push fails, the query was cancelled. No need to continue. @@ -108,8 +106,8 @@ func (scope Scope) Search(query *scopes.CannedQuery, metadata *scopes.SearchMeta } func (scope Scope) Preview(result *scopes.Result, metadata *scopes.ActionMetadata, reply *scopes.PreviewReply, cancelled <-chan bool) error { - var snapId string - err := result.Get("id", &snapId) + var snapName string + err := result.Get("name", &snapName) if err != nil { return scopeError(`unity-scope-snappy: Unable to retrieve ID for package "%s": %s`, result.Title(), err) } @@ -117,12 +115,13 @@ func (scope Scope) Preview(result *scopes.Result, metadata *scopes.ActionMetadat // Need to query the API to make sure we have an up-to-date status, // otherwise we can't refresh the state of the buttons after an install or // uninstall action. - snap, err := scope.webdmClient.Query(snapId) + snap, err := scope.webdmClient.Query(snapName) + if err != nil { return scopeError(`unity-scope-snappy: Unable to query API for package "%s": %s`, result.Title(), err) } - preview, err := previews.NewPreview(*snap, metadata) + preview, err := previews.NewPreview(*snap, result, metadata) if err != nil { return scopeError(`unity-scope-snappy: Unable to create preview for package "%s": %s`, result.Title(), err) } @@ -138,7 +137,7 @@ func (scope Scope) Preview(result *scopes.Result, metadata *scopes.ActionMetadat func (scope *Scope) PerformAction(result *scopes.Result, metadata *scopes.ActionMetadata, widgetId, actionId string) (*scopes.ActivationResponse, error) { // Obtain the ID for the specific package var snapId string - err := result.Get("id", &snapId) + err := result.Get("name", &snapId) if err != nil { return nil, scopeError(`unity-scope-snappy: Unable to retrieve ID for package "%s": %s`, result.Title(), err) } @@ -157,49 +156,44 @@ func (scope *Scope) PerformAction(result *scopes.Result, metadata *scopes.Action return response, err } -// createDepartments is used to create a set of static departments for the scope. -// -// Parameters: -// query: Query to be executed when the department is selected. -// reply: Reply onto which the departments will be registered -// -// Returns: -// - Error (nil if none) -func createDepartments(query *scopes.CannedQuery, reply *scopes.SearchReply) error { - rootDepartment, err := scopes.NewDepartment("", query, "All Categories") - if err != nil { - return fmt.Errorf(`Unable to create "All Categories" department: %s`, err) - } - - installedDepartment, err := scopes.NewDepartment("installed", query, "My Snaps") - if err != nil { - return fmt.Errorf(`Unable to create "My Snaps" department: %s`, err) - } - - rootDepartment.SetSubdepartments([]*scopes.Department{installedDepartment}) - reply.RegisterDepartments(rootDepartment) - - return nil -} - // packageResult is used to create a scopes.CategorisedResult from a -// webdm.Package. +// client.Snap. // // Parameters: // category: Category in which the result will be created. -// snap: webdm.Package representing snap. +// snap: client.Snap representing snap. // // Returns: // - Pointer to scopes.CategorisedResult -func packageResult(category *scopes.Category, snap webdm.Package) *scopes.CategorisedResult { +func packageResult(category *scopes.Category, snap client.Snap, installed bool) *scopes.CategorisedResult { result := scopes.NewCategorisedResult(category) + // NOTE: Title really needs to be title, not name, but snapd doesn't expose result.SetTitle(snap.Name) - result.Set("subtitle", snap.Vendor) - result.SetURI("snappy:" + snap.Id) - result.SetArt(snap.IconUrl) - result.Set("id", snap.Id) - + result.SetArt(snap.Icon) + result.SetURI("snappy:" + snap.Name) + result.Set("subtitle", snap.Developer) + result.Set("name", snap.Name) + result.Set("id", snap.ID) + result.Set("installed", installed) + var price string + if installed == true { + price = "✔ INSTALLED" + } else { + price = "FREE" + } + result.Set("price_area", price) + // This is a bit of a mess at the moment, need a better way to do this + attributes := make([]map[string]string, 0) + emptyValue := make(map[string]string, 0) + emptyValue["value"] = "" + priceValue := make(map[string]string, 0) + priceValue["value"] = price + attributes = append(attributes, priceValue) + attributes = append(attributes, emptyValue) + attributes = append(attributes, emptyValue) + attributes = append(attributes, emptyValue) + result.Set("attributes", attributes) return result } diff --git a/store/snappy-store.ini b/store/snappy-store.ini index b8d91bb..8bc42cd 100644 --- a/store/snappy-store.ini +++ b/store/snappy-store.ini @@ -3,4 +3,4 @@ DisplayName = Snappy Scope Description = A scope for the snappy store Author = Canonical Icon = /usr/share/unity/scopes/snappy-store/snappy-store.png -ScopeRunner = GODEBUG=cgocheck=0 $GOPATH/bin/store --runtime %R --scope %S +ScopeRunner = $GOPATH/bin/store --runtime %R --scope %S diff --git a/store/utilities/utilities.go b/store/utilities/utilities.go deleted file mode 100644 index 8e45505..0000000 --- a/store/utilities/utilities.go +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2015 Canonical Ltd. - * - * This file is part of unity-scope-snappy. - * - * unity-scope-snappy is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * unity-scope-snappy is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. - */ - -package utilities - -import ( - "fmt" - "launchpad.net/unity-scope-snappy/store/packages" - "launchpad.net/unity-scope-snappy/webdm" -) - -// GetPackageList is used to obtain a package list for a specific department. -// -// Parameters: -// packageManager: Package manager to use to obtain package list. -// department: The department whose packages should be listed. -// query: Search query from the scope. -// -// Returns: -// - List of WebDM Package structs -// - Error (nil if none) -func GetPackageList(packageManager packages.WebdmManager, department string, query string) ([]webdm.Package, error) { - var packages []webdm.Package - var err error - - switch department { - case "installed": - packages, err = packageManager.GetInstalledPackages(query) - if err != nil { - return nil, fmt.Errorf("Unable to retrieve installed packages: %s", err) - } - - default: - packages, err = packageManager.GetStorePackages(query) - if err != nil { - return nil, fmt.Errorf("Unable to retrieve store packages: %s", err) - } - } - - return packages, nil -} diff --git a/store/utilities/utilities_test.go b/store/utilities/utilities_test.go deleted file mode 100644 index 6f90065..0000000 --- a/store/utilities/utilities_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2015 Canonical Ltd. - * - * This file is part of unity-scope-snappy. - * - * unity-scope-snappy is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * unity-scope-snappy is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * unity-scope-snappy. If not, see <http://www.gnu.org/licenses/>. - */ - -package utilities - -import ( - "launchpad.net/unity-scope-snappy/store/packages/fakes" - "testing" -) - -// Test getPackageList for installed packages -func TestGetPackageList_installed(t *testing.T) { - packageManager := &fakes.FakeWebdmManager{} - - _, err := GetPackageList(packageManager, "installed", "") - if err != nil { - t.Error("Unexpected error while getting installed package list") - } - - if !packageManager.GetInstalledPackagesCalled { - t.Error("Expected GetInstalledPackages() to be called") - } -} - -// Test getPackageList failure getting installed packages -func TestGetPackageList_installed_failure(t *testing.T) { - packageManager := &fakes.FakeWebdmManager{FailGetInstalledPackages: true} - - packages, err := GetPackageList(packageManager, "installed", "") - if err == nil { - t.Error("Expected an error getting installed package list") - } - - if packages != nil { - t.Error("Expected no packages to be returned") - } -} - -// Test getPackageList for store packages -func TestGetPackageList_store(t *testing.T) { - packageManager := &fakes.FakeWebdmManager{} - - _, err := GetPackageList(packageManager, "", "") - if err != nil { - t.Error("Unexpected error while getting store package list") - } - - if !packageManager.GetStorePackagesCalled { - t.Error("Expected GetStorePackages() to be called") - } -} - -// Test getPackageList failure getting store packages -func TestGetPackageList_store_failure(t *testing.T) { - packageManager := &fakes.FakeWebdmManager{FailGetStorePackages: true} - - packages, err := GetPackageList(packageManager, "", "") - if err == nil { - t.Error("Expected an error getting store package list") - } - - if packages != nil { - t.Error("Expected no packages to be returned") - } -} diff --git a/vendor/github.com/AlekSi/gocov-xml/LICENSE b/vendor/github.com/AlekSi/gocov-xml/LICENSE deleted file mode 100644 index 39424b4..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Alexey Palazhchenko - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/AlekSi/gocov-xml/Makefile b/vendor/github.com/AlekSi/gocov-xml/Makefile deleted file mode 100644 index 862ace0..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: fvb - -prepare: - go get -u github.com/axw/gocov/... - go get -u github.com/gorilla/mux/... - gocov test -v github.com/gorilla/mux > mux.json - -fvb: - gofmt -e -s -w . - go vet . - go run ./gocov-xml.go < mux.json > coverage.xml - xmllint --valid --noout coverage.xml diff --git a/vendor/github.com/AlekSi/gocov-xml/README.md b/vendor/github.com/AlekSi/gocov-xml/README.md deleted file mode 100644 index 703032f..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/README.md +++ /dev/null @@ -1,27 +0,0 @@ -gocov XML (Cobertura) export -============================ - -This is a simple helper tool for generating XML output in [Cobertura](http://cobertura.sourceforge.net/) format -for CIs like [Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin) and others -from [github.com/axw/gocov](https://github.com/axw/gocov) output. - -Installation ------------- - -Just type the following to install the program and its dependencies: - - $ go get github.com/axw/gocov/... - $ go get github.com/AlekSi/gocov-xml - -Usage ------ - -`gocov-xml` reads from the standard input: - - $ gocov test github.com/gorilla/mux | gocov-xml > coverage.xml - -Authors -------- - -* [Alexey Palazhchenko (AlekSi)](https://github.com/AlekSi) -* [Yukinari Toyota (t-yuki)](https://github.com/t-yuki) diff --git a/vendor/github.com/AlekSi/gocov-xml/coverage-03.dtd b/vendor/github.com/AlekSi/gocov-xml/coverage-03.dtd deleted file mode 100644 index 8a3f8c2..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/coverage-03.dtd +++ /dev/null @@ -1,55 +0,0 @@ -<!-- Portions (C) International Organization for Standardization 1986: - Permission to copy in any form is granted for use with - conforming SGML systems and applications as defined in - ISO 8879, provided this notice is included in all copies. ---> - -<!ELEMENT coverage (sources?,packages)> -<!ATTLIST coverage line-rate CDATA #REQUIRED> -<!ATTLIST coverage branch-rate CDATA #REQUIRED> -<!ATTLIST coverage version CDATA #REQUIRED> -<!ATTLIST coverage timestamp CDATA #REQUIRED> - -<!ELEMENT sources (source*)> - -<!ELEMENT source (#PCDATA)> - -<!ELEMENT packages (package*)> - -<!ELEMENT package (classes)> -<!ATTLIST package name CDATA #REQUIRED> -<!ATTLIST package line-rate CDATA #REQUIRED> -<!ATTLIST package branch-rate CDATA #REQUIRED> -<!ATTLIST package complexity CDATA #REQUIRED> - -<!ELEMENT classes (class*)> - -<!ELEMENT class (methods,lines)> -<!ATTLIST class name CDATA #REQUIRED> -<!ATTLIST class filename CDATA #REQUIRED> -<!ATTLIST class line-rate CDATA #REQUIRED> -<!ATTLIST class branch-rate CDATA #REQUIRED> -<!ATTLIST class complexity CDATA #REQUIRED> - -<!ELEMENT methods (method*)> - -<!ELEMENT method (lines)> -<!ATTLIST method name CDATA #REQUIRED> -<!ATTLIST method signature CDATA #REQUIRED> -<!ATTLIST method line-rate CDATA #REQUIRED> -<!ATTLIST method branch-rate CDATA #REQUIRED> - -<!ELEMENT lines (line*)> - -<!ELEMENT line (conditions*)> -<!ATTLIST line number CDATA #REQUIRED> -<!ATTLIST line hits CDATA #REQUIRED> -<!ATTLIST line branch CDATA "false"> -<!ATTLIST line condition-coverage CDATA "100%"> - -<!ELEMENT conditions (condition*)> - -<!ELEMENT condition EMPTY> -<!ATTLIST condition number CDATA #REQUIRED> -<!ATTLIST condition type CDATA #REQUIRED> -<!ATTLIST condition coverage CDATA #REQUIRED> diff --git a/vendor/github.com/AlekSi/gocov-xml/coverage-with-data.xml b/vendor/github.com/AlekSi/gocov-xml/coverage-with-data.xml deleted file mode 100644 index c7c6f21..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/coverage-with-data.xml +++ /dev/null @@ -1,179 +0,0 @@ -<?xml version="1.0"?> -<!--DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-03.dtd"--> - -<coverage line-rate="0.9" branch-rate="0.75" version="1.9" timestamp="1187350905008"> - <sources> - <source>C:/local/mvn-coverage-example/src/main/java</source> - <source>--source</source> - </sources> - <packages> - <package name="" line-rate="1.0" branch-rate="1.0" complexity="1.0"> - <classes> - <class name="Main" filename="Main.java" line-rate="1.0" branch-rate="1.0" complexity="1.0"> - <methods> - <method name="<init>" signature="()V" line-rate="1.0" branch-rate="1.0"> - <lines> - <line number="10" hits="3" branch="false"/> - </lines> - </method> - <method name="doSearch" signature="()V" line-rate="1.0" branch-rate="1.0"> - <lines> - <line number="23" hits="3" branch="false"/> - <line number="25" hits="3" branch="false"/> - <line number="26" hits="3" branch="false"/> - <line number="28" hits="3" branch="false"/> - <line number="29" hits="3" branch="false"/> - <line number="30" hits="3" branch="false"/> - </lines> - </method> - <method name="main" signature="([Ljava/lang/String;)V" line-rate="1.0" branch-rate="1.0"> - <lines> - <line number="16" hits="3" branch="false"/> - <line number="17" hits="3" branch="false"/> - <line number="18" hits="3" branch="false"/> - <line number="19" hits="3" branch="false"/> - </lines> - </method> - </methods> - <lines> - <line number="10" hits="3" branch="false"/> - <line number="16" hits="3" branch="false"/> - <line number="17" hits="3" branch="false"/> - <line number="18" hits="3" branch="false"/> - <line number="19" hits="3" branch="false"/> - <line number="23" hits="3" branch="false"/> - <line number="25" hits="3" branch="false"/> - <line number="26" hits="3" branch="false"/> - <line number="28" hits="3" branch="false"/> - <line number="29" hits="3" branch="false"/> - <line number="30" hits="3" branch="false"/> - </lines> - </class> - </classes> - </package> - <package name="search" line-rate="0.8421052631578947" branch-rate="0.75" complexity="3.25"> - <classes> - <class name="search.BinarySearch" filename="search/BinarySearch.java" line-rate="0.9166666666666666" branch-rate="0.8333333333333334" complexity="3.0"> - <methods> - <method name="<init>" signature="()V" line-rate="1.0" branch-rate="1.0"> - <lines> - <line number="12" hits="3" branch="false"/> - </lines> - </method> - <method name="find" signature="([II)I" line-rate="0.9090909090909091" branch-rate="0.8333333333333334"> - <lines> - <line number="16" hits="3" branch="false"/> - <line number="18" hits="12" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="20" hits="9" branch="false"/> - <line number="21" hits="9" branch="false"/> - <line number="23" hits="9" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="24" hits="0" branch="false"/> - <line number="25" hits="9" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="26" hits="6" branch="false"/> - <line number="28" hits="3" branch="false"/> - <line number="29" hits="9" branch="false"/> - <line number="31" hits="3" branch="false"/> - </lines> - </method> - </methods> - <lines> - <line number="12" hits="3" branch="false"/> - <line number="16" hits="3" branch="false"/> - <line number="18" hits="12" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="20" hits="9" branch="false"/> - <line number="21" hits="9" branch="false"/> - <line number="23" hits="9" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="24" hits="0" branch="false"/> - <line number="25" hits="9" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="26" hits="6" branch="false"/> - <line number="28" hits="3" branch="false"/> - <line number="29" hits="9" branch="false"/> - <line number="31" hits="3" branch="false"/> - </lines> - </class> - <class name="search.ISortedArraySearch" filename="search/ISortedArraySearch.java" line-rate="1.0" branch-rate="1.0" complexity="1.0"> - <methods> - </methods> - <lines> - </lines> - </class> - <class name="search.LinearSearch" filename="search/LinearSearch.java" line-rate="0.7142857142857143" branch-rate="0.6666666666666666" complexity="6.0"> - <methods> - <method name="<init>" signature="()V" line-rate="1.0" branch-rate="1.0"> - <lines> - <line number="9" hits="3" branch="false"/> - </lines> - </method> - <method name="find" signature="([II)I" line-rate="0.6666666666666666" branch-rate="0.6666666666666666"> - <lines> - <line number="13" hits="9" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="15" hits="9" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="16" hits="3" branch="false"/> - <line number="17" hits="6" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="19" hits="0" branch="false"/> - <line number="24" hits="0" branch="false"/> - </lines> - </method> - </methods> - <lines> - <line number="9" hits="3" branch="false"/> - <line number="13" hits="9" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="15" hits="9" branch="true" condition-coverage="100% (2/2)"> - <conditions> - <condition number="0" type="jump" coverage="100%"/> - </conditions> - </line> - <line number="16" hits="3" branch="false"/> - <line number="17" hits="6" branch="true" condition-coverage="50% (1/2)"> - <conditions> - <condition number="0" type="jump" coverage="50%"/> - </conditions> - </line> - <line number="19" hits="0" branch="false"/> - <line number="24" hits="0" branch="false"/> - </lines> - </class> - </classes> - </package> - </packages> -</coverage> diff --git a/vendor/github.com/AlekSi/gocov-xml/gocov-xml.go b/vendor/github.com/AlekSi/gocov-xml/gocov-xml.go deleted file mode 100644 index 578e3bb..0000000 --- a/vendor/github.com/AlekSi/gocov-xml/gocov-xml.go +++ /dev/null @@ -1,145 +0,0 @@ -package main - -import ( - "encoding/json" - "encoding/xml" - "fmt" - "go/token" - "io/ioutil" - "os" - "strings" - "time" - - "github.com/axw/gocov" -) - -type Coverage struct { - XMLName xml.Name `xml:"coverage"` - LineRate float32 `xml:"line-rate,attr"` - BranchRate float32 `xml:"branch-rate,attr"` - Version string `xml:"version,attr"` - Timestamp int64 `xml:"timestamp,attr"` - Packages []Package `xml:"packages>package"` -} - -type Package struct { - Name string `xml:"name,attr"` - LineRate float32 `xml:"line-rate,attr"` - BranchRate float32 `xml:"branch-rate,attr"` - Complexity float32 `xml:"complexity,attr"` - Classes []Class `xml:"classes>class"` -} - -type Class struct { - Name string `xml:"name,attr"` - Filename string `xml:"filename,attr"` - LineRate float32 `xml:"line-rate,attr"` - BranchRate float32 `xml:"branch-rate,attr"` - Complexity float32 `xml:"complexity,attr"` - Methods []Method `xml:"methods>method"` - Lines []Line `xml:"lines>line"` -} - -type Method struct { - Name string `xml:"name,attr"` - Signature string `xml:"signature,attr"` - LineRate float32 `xml:"line-rate,attr"` - BranchRate float32 `xml:"branch-rate,attr"` - Lines []Line `xml:"lines>line"` -} - -type Line struct { - Number int `xml:"number,attr"` - Hits int64 `xml:"hits,attr"` -} - -func main() { - var r struct{ Packages []gocov.Package } - err := json.NewDecoder(os.Stdin).Decode(&r) - if err != nil { - panic(err) - } - - fset := token.NewFileSet() - tokenFiles := make(map[string]*token.File) - - // convert packages - packages := make([]Package, len(r.Packages)) - for i, gPackage := range r.Packages { - // group functions by filename and "class" (type) - files := make(map[string]map[string]*Class) - for _, gFunction := range gPackage.Functions { - classes := files[gFunction.File] - if classes == nil { - // group functions by "class" (type) in a File - classes = make(map[string]*Class) - files[gFunction.File] = classes - } - - s := strings.Split("-."+gFunction.Name, ".") // className is "-" for package-level functions - className, methodName := s[len(s)-2], s[len(s)-1] - class := classes[className] - if class == nil { - class = &Class{Name: className, Filename: gFunction.File, Methods: []Method{}, Lines: []Line{}} - classes[className] = class - } - - // from github.com/axw/gocov /gocov/annotate.go#printFunctionSource - // Load the file for line information. Probably overkill, maybe - // just compute the lines from offsets in here. - setContent := false - tokenFile := tokenFiles[gFunction.File] - if tokenFile == nil { - info, err := os.Stat(gFunction.File) - if err != nil { - panic(err) - } - tokenFile = fset.AddFile(gFunction.File, fset.Base(), int(info.Size())) - setContent = true - } - - tokenData, err := ioutil.ReadFile(gFunction.File) - if err != nil { - panic(err) - } - if setContent { - // This processes the content and records line number info. - tokenFile.SetLinesForContent(tokenData) - } - - // convert statements to lines - lines := make([]Line, len(gFunction.Statements)) - for i, s := range gFunction.Statements { - lineno := tokenFile.Line(tokenFile.Pos(s.Start)) - line := Line{Number: lineno, Hits: s.Reached} - lines[i] = line - class.Lines = append(class.Lines, line) - } - - class.Methods = append(class.Methods, Method{Name: methodName, Lines: lines}) - } - - // fill package with "classes" - p := Package{Name: gPackage.Name, Classes: []Class{}} - for _, classes := range files { - for _, class := range classes { - p.Classes = append(p.Classes, *class) - } - } - packages[i] = p - } - - coverage := Coverage{Packages: packages, Timestamp: time.Now().UnixNano() / int64(time.Millisecond)} - - fmt.Printf(xml.Header) - fmt.Printf("<!DOCTYPE coverage SYSTEM \"http://cobertura.sourceforge.net/xml/coverage-03.dtd\">\n") - - encoder := xml.NewEncoder(os.Stdout) - encoder.Indent("", "\t") - err = encoder.Encode(coverage) - if err != nil { - panic(err) - } - - fmt.Println() -} diff --git a/vendor/github.com/axw/gocov/AUTHORS b/vendor/github.com/axw/gocov/AUTHORS deleted file mode 100644 index 998341c..0000000 --- a/vendor/github.com/axw/gocov/AUTHORS +++ /dev/null @@ -1,5 +0,0 @@ -# List of gocov authors. - -Andrew Wilkins <axwalk@gmail.com> -Dave Cheney <dave@cheney.net> -Greg Ward <greg@gerg.ca> diff --git a/vendor/github.com/axw/gocov/LICENSE b/vendor/github.com/axw/gocov/LICENSE deleted file mode 100644 index 10b716c..0000000 --- a/vendor/github.com/axw/gocov/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 The Gocov Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/axw/gocov/README.md b/vendor/github.com/axw/gocov/README.md deleted file mode 100644 index 8b2e3ef..0000000 --- a/vendor/github.com/axw/gocov/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# gocov - -Coverage reporting tool for The Go Programming Language - -[](https://drone.io/github.com/axw/gocov/latest) - -## Installation - -```go get github.com/axw/gocov/gocov``` - -## Usage - -There are currently four gocov commands: ```test```, ```convert```, ```report``` and ```annotate```. - -#### gocov test - -Running `gocov test [args...]` will run `go test [args...]` with -an implicit `-coverprofile` added, and then output the result of -`gocov convert` with the profile. - -#### gocov convert - -Running `gocov convert <coverprofile>` will convert a coverage -profile generated by `go tool cover` to gocov's JSON interchange -format. For example: - - go test -coverprofile=c.out - gocov convert c.out | gocov annotate - - -#### gocov report - -Running `gocov report <coverage.json>` will generate a textual -report from the coverage data output by `gocov convert`. It is -assumed that the source code has not changed in between. - -Output from ```gocov test``` is printed to stdout so users can -pipe the output to ```gocov report``` to view a summary of the test -coverage, for example: - - - gocov test | gocov report - -#### gocov annotate - -Running `gocov annotate <coverage.json> <package[.receiver].function>` -will generate a source listing of the specified function, annotating -it with coverage information, such as which lines have been missed. - -## Related tools - -[GoCovGUI](http://github.com/nsf/gocovgui/): -A simple GUI wrapper for the gocov coverage analysis tool. - -[gocov-html](https://github.com/matm/gocov-html): -A simple helper tool for generating HTML output from gocov. - -[gocov-xml](https://github.com/AlekSi/gocov-xml): -A simple helper tool for generating XML output in Cobertura format for CIs like Jenkins and others from gocov. - -[goveralls](https://github.com/mattn/goveralls): -Go integration for Coveralls.io continuous code coverage tracking system. diff --git a/vendor/github.com/axw/gocov/gocov.go b/vendor/github.com/axw/gocov/gocov.go deleted file mode 100644 index 6e94ca7..0000000 --- a/vendor/github.com/axw/gocov/gocov.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -// Package gocov is a code coverage analysis tool for Go. -package gocov - -import ( - "fmt" -) - -type Package struct { - // Name is the canonical path of the package. - Name string - - // Functions is a list of functions registered with this package. - Functions []*Function -} - -type Function struct { - // Name is the name of the function. If the function has a receiver, the - // name will be of the form T.N, where T is the type and N is the name. - Name string - - // File is the full path to the file in which the function is defined. - File string - - // Start is the start offset of the function's signature. - Start int - - // End is the end offset of the function. - End int - - // statements registered with this function. - Statements []*Statement -} - -type Statement struct { - // Start is the start offset of the statement. - Start int - - // End is the end offset of the statement. - End int - - // Reached is the number of times the statement was reached. - Reached int64 -} - -// Accumulate will accumulate the coverage information from the provided -// Package into this Package. -func (p *Package) Accumulate(p2 *Package) error { - if p.Name != p2.Name { - return fmt.Errorf("Names do not match: %q != %q", p.Name, p2.Name) - } - if len(p.Functions) != len(p2.Functions) { - return fmt.Errorf("Function counts do not match: %d != %d", len(p.Functions), len(p2.Functions)) - } - for i, f := range p.Functions { - err := f.Accumulate(p2.Functions[i]) - if err != nil { - return err - } - } - return nil -} - -// Accumulate will accumulate the coverage information from the provided -// Function into this Function. -func (f *Function) Accumulate(f2 *Function) error { - if f.Name != f2.Name { - return fmt.Errorf("Names do not match: %q != %q", f.Name, f2.Name) - } - if f.File != f2.File { - return fmt.Errorf("Files do not match: %q != %q", f.File, f2.File) - } - if f.Start != f2.Start || f.End != f2.End { - return fmt.Errorf("Source ranges do not match: %d-%d != %d-%d", f.Start, f.End, f2.Start, f2.End) - } - if len(f.Statements) != len(f2.Statements) { - return fmt.Errorf("Number of statements do not match: %d != %d", len(f.Statements), len(f2.Statements)) - } - for i, s := range f.Statements { - err := s.Accumulate(f2.Statements[i]) - if err != nil { - return err - } - } - return nil -} - -// Accumulate will accumulate the coverage information from the provided -// Statement into this Statement. -func (s *Statement) Accumulate(s2 *Statement) error { - if s.Start != s2.Start || s.End != s2.End { - return fmt.Errorf("Source ranges do not match: %d-%d != %d-%d", s.Start, s.End, s2.Start, s2.End) - } - s.Reached += s2.Reached - return nil -} diff --git a/vendor/github.com/axw/gocov/gocov/annotate.go b/vendor/github.com/axw/gocov/gocov/annotate.go deleted file mode 100644 index a0c612e..0000000 --- a/vendor/github.com/axw/gocov/gocov/annotate.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2012 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package main - -import ( - "flag" - "fmt" - "go/token" - "io/ioutil" - "math" - "os" - "regexp" - "sort" - "strings" - - "github.com/axw/gocov" -) - -const ( - hitPrefix = " " - missPrefix = "MISS" - RED = "\x1b[31;1m" - GREEN = "\x1b[32;1m" - NONE = "\x1b[0m" -) - -var ( - annotateFlags = flag.NewFlagSet("annotate", flag.ExitOnError) - annotateCeilingFlag = annotateFlags.Float64( - "ceiling", 101, - "Annotate only functions whose coverage is less than the specified percentage") - annotateColorFlag = annotateFlags.Bool( - "color", false, - "Differentiate coverage with color") -) - -type packageList []*gocov.Package -type functionList []*gocov.Function - -func (l packageList) Len() int { - return len(l) -} - -func (l packageList) Less(i, j int) bool { - return l[i].Name < l[j].Name -} - -func (l packageList) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -func (l functionList) Len() int { - return len(l) -} - -func (l functionList) Less(i, j int) bool { - return l[i].Name < l[j].Name -} - -func (l functionList) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -type annotator struct { - fset *token.FileSet - files map[string]*token.File -} - -func percentReached(fn *gocov.Function) float64 { - if len(fn.Statements) == 0 { - return 0 - } - var reached int - for _, stmt := range fn.Statements { - if stmt.Reached > 0 { - reached++ - } - } - return float64(reached) / float64(len(fn.Statements)) * 100 -} - -func annotateSource() (rc int) { - annotateFlags.Parse(os.Args[2:]) - if annotateFlags.NArg() == 0 { - fmt.Fprintf(os.Stderr, "missing coverage file\n") - return 1 - } - - var data []byte - var err error - if filename := annotateFlags.Arg(0); filename == "-" { - data, err = ioutil.ReadAll(os.Stdin) - } else { - data, err = ioutil.ReadFile(filename) - } - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read coverage file: %s\n", err) - return 1 - } - - packages, err := unmarshalJson(data) - if err != nil { - fmt.Fprintf( - os.Stderr, "failed to unmarshal coverage data: %s\n", err) - return 1 - } - - // Sort packages, functions by name. - sort.Sort(packageList(packages)) - for _, pkg := range packages { - sort.Sort(functionList(pkg.Functions)) - } - - a := &annotator{} - a.fset = token.NewFileSet() - a.files = make(map[string]*token.File) - - var regexps []*regexp.Regexp - for _, arg := range annotateFlags.Args()[1:] { - re, err := regexp.Compile(arg) - if err != nil { - fmt.Fprintf(os.Stderr, "warning: failed to compile %q as a regular expression, ignoring\n", arg) - } else { - regexps = append(regexps, re) - } - } - if len(regexps) == 0 { - regexps = append(regexps, regexp.MustCompile(".")) - } - for _, pkg := range packages { - for _, fn := range pkg.Functions { - if percentReached(fn) >= *annotateCeilingFlag { - continue - } - name := pkg.Name + "/" + fn.Name - for _, regexp := range regexps { - if regexp.FindStringIndex(name) != nil { - err := a.printFunctionSource(fn) - if err != nil { - fmt.Fprintf(os.Stderr, "warning: failed to annotate function %q\n", name) - } - break - } - } - } - } - return -} - -func (a *annotator) printFunctionSource(fn *gocov.Function) error { - // Load the file for line information. Probably overkill, maybe - // just compute the lines from offsets in here. - setContent := false - file := a.files[fn.File] - if file == nil { - info, err := os.Stat(fn.File) - if err != nil { - return err - } - file = a.fset.AddFile(fn.File, a.fset.Base(), int(info.Size())) - setContent = true - } - - data, err := ioutil.ReadFile(fn.File) - if err != nil { - return err - } - if setContent { - // This processes the content and records line number info. - file.SetLinesForContent(data) - } - - statements := fn.Statements[:] - lineno := file.Line(file.Pos(fn.Start)) - lines := strings.Split(string(data)[fn.Start:fn.End], "\n") - linenoWidth := int(math.Log10(float64(lineno+len(lines)))) + 1 - fmt.Println() - for i, line := range lines { - // Go through statements one at a time, seeing if we've hit - // them or not. - // - // The prefix approach isn't perfect, as it doesn't - // distinguish multiple statements per line. It'll have to - // do for now. We could do fancy ANSI colouring later. - lineno := lineno + i - statementFound := false - hit := false - for j := 0; j < len(statements); j++ { - start := file.Line(file.Pos(statements[j].Start)) - // FIXME instrumentation no longer records statements - // in line order, as function literals are processed - // after the body of a function. If/when that's changed, - // we can go back to checking just the first statement - // in each loop. - if start == lineno { - statementFound = true - if !hit && statements[j].Reached > 0 { - hit = true - } - statements = append(statements[:j], statements[j+1:]...) - } - } - if *annotateColorFlag { - color := NONE - if statementFound && !hit { - color = RED - } - fmt.Printf("%s%*d \t%s%s\n", color, linenoWidth, lineno, line, NONE) - } else { - hitmiss := hitPrefix - if statementFound && !hit { - hitmiss = missPrefix - } - fmt.Printf("%*d %s\t%s\n", linenoWidth, lineno, hitmiss, line) - } - } - fmt.Println() - - return nil -} diff --git a/vendor/github.com/axw/gocov/gocov/convert.go b/vendor/github.com/axw/gocov/gocov/convert.go deleted file mode 100644 index 0eaadab..0000000 --- a/vendor/github.com/axw/gocov/gocov/convert.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2013 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package main - -import ( - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - "path/filepath" - - "golang.org/x/tools/cover" - - "github.com/axw/gocov" - "github.com/axw/gocov/gocovutil" -) - -func convertProfiles(filenames ...string) error { - var ps gocovutil.Packages - for i := range filenames { - converter := converter{ - packages: make(map[string]*gocov.Package), - } - profiles, err := cover.ParseProfiles(filenames[i]) - if err != nil { - return err - } - for _, p := range profiles { - if err := converter.convertProfile(p); err != nil { - return err - } - } - - for _, pkg := range converter.packages { - ps.AddPackage(pkg) - } - } - bytes, err := marshalJson(ps) - if err != nil { - return err - } - fmt.Println(string(bytes)) - return nil -} - -type converter struct { - packages map[string]*gocov.Package -} - -// wrapper for gocov.Statement -type statement struct { - *gocov.Statement - *StmtExtent -} - -func (c *converter) convertProfile(p *cover.Profile) error { - file, pkgpath, err := findFile(p.FileName) - if err != nil { - return err - } - pkg := c.packages[pkgpath] - if pkg == nil { - pkg = &gocov.Package{Name: pkgpath} - c.packages[pkgpath] = pkg - } - // Find function and statement extents; create corresponding - // gocov.Functions and gocov.Statements, and keep a separate - // slice of gocov.Statements so we can match them with profile - // blocks. - extents, err := findFuncs(file) - if err != nil { - return err - } - var stmts []statement - for _, fe := range extents { - f := &gocov.Function{ - Name: fe.name, - File: file, - Start: fe.startOffset, - End: fe.endOffset, - } - for _, se := range fe.stmts { - s := statement{ - Statement: &gocov.Statement{Start: se.startOffset, End: se.endOffset}, - StmtExtent: se, - } - f.Statements = append(f.Statements, s.Statement) - stmts = append(stmts, s) - } - pkg.Functions = append(pkg.Functions, f) - } - // For each profile block in the file, find the statement(s) it - // covers and increment the Reached field(s). - blocks := p.Blocks - for len(stmts) > 0 { - s := stmts[0] - for i, b := range blocks { - if b.StartLine > s.endLine || (b.StartLine == s.endLine && b.StartCol >= s.endCol) { - // Past the end of the statement - stmts = stmts[1:] - blocks = blocks[i:] - break - } - if b.EndLine < s.startLine || (b.EndLine == s.startLine && b.EndCol <= s.startCol) { - // Before the beginning of the statement - continue - } - s.Reached += int64(b.Count) - stmts = stmts[1:] - break - } - } - return nil -} - -// findFile finds the location of the named file in GOROOT, GOPATH etc. -func findFile(file string) (filename string, pkgpath string, err error) { - dir, file := filepath.Split(file) - if dir != "" { - dir = dir[:len(dir)-1] // drop trailing '/' - } - pkg, err := build.Import(dir, ".", build.FindOnly) - if err != nil { - return "", "", fmt.Errorf("can't find %q: %v", file, err) - } - return filepath.Join(pkg.Dir, file), pkg.ImportPath, nil -} - -// findFuncs parses the file and returns a slice of FuncExtent descriptors. -func findFuncs(name string) ([]*FuncExtent, error) { - fset := token.NewFileSet() - parsedFile, err := parser.ParseFile(fset, name, nil, 0) - if err != nil { - return nil, err - } - visitor := &FuncVisitor{fset: fset} - ast.Walk(visitor, parsedFile) - return visitor.funcs, nil -} - -type extent struct { - startOffset int - startLine int - startCol int - endOffset int - endLine int - endCol int -} - -// FuncExtent describes a function's extent in the source by file and position. -type FuncExtent struct { - extent - name string - stmts []*StmtExtent -} - -// StmtExtent describes a statements's extent in the source by file and position. -type StmtExtent extent - -// FuncVisitor implements the visitor that builds the function position list for a file. -type FuncVisitor struct { - fset *token.FileSet - funcs []*FuncExtent -} - -// Visit implements the ast.Visitor interface. -func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor { - var body *ast.BlockStmt - var name string - switch n := node.(type) { - case *ast.FuncLit: - body = n.Body - case *ast.FuncDecl: - body = n.Body - name = n.Name.Name - // Function name is prepended with "T." if there is a receiver, where - // T is the type of the receiver, dereferenced if it is a pointer. - if n.Recv != nil { - field := n.Recv.List[0] - switch recv := field.Type.(type) { - case *ast.StarExpr: - name = recv.X.(*ast.Ident).Name + "." + name - case *ast.Ident: - name = recv.Name + "." + name - } - } - } - if body != nil { - start := v.fset.Position(node.Pos()) - end := v.fset.Position(node.End()) - if name == "" { - name = fmt.Sprintf("@%d:%d", start.Line, start.Column) - } - fe := &FuncExtent{ - name: name, - extent: extent{ - startOffset: start.Offset, - startLine: start.Line, - startCol: start.Column, - endOffset: end.Offset, - endLine: end.Line, - endCol: end.Column, - }, - } - v.funcs = append(v.funcs, fe) - sv := StmtVisitor{fset: v.fset, function: fe} - sv.VisitStmt(body) - } - return v -} - -type StmtVisitor struct { - fset *token.FileSet - function *FuncExtent -} - -func (v *StmtVisitor) VisitStmt(s ast.Stmt) { - var statements *[]ast.Stmt - switch s := s.(type) { - case *ast.BlockStmt: - statements = &s.List - case *ast.CaseClause: - statements = &s.Body - case *ast.CommClause: - statements = &s.Body - case *ast.ForStmt: - if s.Init != nil { - v.VisitStmt(s.Init) - } - if s.Post != nil { - v.VisitStmt(s.Post) - } - v.VisitStmt(s.Body) - case *ast.IfStmt: - if s.Init != nil { - v.VisitStmt(s.Init) - } - v.VisitStmt(s.Body) - if s.Else != nil { - // Code copied from go.tools/cmd/cover, to deal with "if x {} else if y {}" - const backupToElse = token.Pos(len("else ")) // The AST doesn't remember the else location. We can make an accurate guess. - switch stmt := s.Else.(type) { - case *ast.IfStmt: - block := &ast.BlockStmt{ - Lbrace: stmt.If - backupToElse, // So the covered part looks like it starts at the "else". - List: []ast.Stmt{stmt}, - Rbrace: stmt.End(), - } - s.Else = block - case *ast.BlockStmt: - stmt.Lbrace -= backupToElse // So the block looks like it starts at the "else". - default: - panic("unexpected node type in if") - } - v.VisitStmt(s.Else) - } - case *ast.LabeledStmt: - v.VisitStmt(s.Stmt) - case *ast.RangeStmt: - v.VisitStmt(s.Body) - case *ast.SelectStmt: - v.VisitStmt(s.Body) - case *ast.SwitchStmt: - if s.Init != nil { - v.VisitStmt(s.Init) - } - v.VisitStmt(s.Body) - case *ast.TypeSwitchStmt: - if s.Init != nil { - v.VisitStmt(s.Init) - } - v.VisitStmt(s.Assign) - v.VisitStmt(s.Body) - } - if statements == nil { - return - } - for i := 0; i < len(*statements); i++ { - s := (*statements)[i] - switch s.(type) { - case *ast.CaseClause, *ast.CommClause, *ast.BlockStmt: - break - default: - start, end := v.fset.Position(s.Pos()), v.fset.Position(s.End()) - se := &StmtExtent{ - startOffset: start.Offset, - startLine: start.Line, - startCol: start.Column, - endOffset: end.Offset, - endLine: end.Line, - endCol: end.Column, - } - v.function.stmts = append(v.function.stmts, se) - } - v.VisitStmt(s) - } -} diff --git a/vendor/github.com/axw/gocov/gocov/main.go b/vendor/github.com/axw/gocov/gocov/main.go deleted file mode 100644 index d9be6a2..0000000 --- a/vendor/github.com/axw/gocov/gocov/main.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package main - -import ( - "encoding/json" - "flag" - "fmt" - "os" - - "github.com/axw/gocov" -) - -func usage() { - fmt.Fprintf(os.Stderr, "Usage:\n\n\tgocov command [arguments]\n\n") - fmt.Fprintf(os.Stderr, "The commands are:\n\n") - fmt.Fprintf(os.Stderr, "\tannotate\n") - fmt.Fprintf(os.Stderr, "\tconvert\n") - fmt.Fprintf(os.Stderr, "\treport\n") - fmt.Fprintf(os.Stderr, "\ttest\n") - fmt.Fprintf(os.Stderr, "\n") - flag.PrintDefaults() - os.Exit(2) -} - -func marshalJson(packages []*gocov.Package) ([]byte, error) { - return json.Marshal(struct{ Packages []*gocov.Package }{packages}) -} - -func unmarshalJson(data []byte) (packages []*gocov.Package, err error) { - result := &struct{ Packages []*gocov.Package }{} - err = json.Unmarshal(data, result) - if err == nil { - packages = result.Packages - } - return -} - -func main() { - flag.Usage = usage - flag.Parse() - - command := "" - if flag.NArg() > 0 { - command = flag.Arg(0) - switch command { - case "convert": - if flag.NArg() <= 1 { - fmt.Fprintln(os.Stderr, "missing cover profile") - os.Exit(1) - } - if err := convertProfiles(flag.Args()[1:]...); err != nil { - fmt.Fprintln(os.Stderr, "error:", err) - os.Exit(1) - } - case "annotate": - os.Exit(annotateSource()) - case "report": - os.Exit(reportCoverage()) - case "test": - if err := runTests(flag.Args()[1:]); err != nil { - fmt.Fprintln(os.Stderr, "error:", err) - os.Exit(1) - } - default: - fmt.Fprintf(os.Stderr, "Unknown command: %#q\n\n", command) - usage() - } - } else { - usage() - } -} diff --git a/vendor/github.com/axw/gocov/gocov/report.go b/vendor/github.com/axw/gocov/gocov/report.go deleted file mode 100644 index 6f633d4..0000000 --- a/vendor/github.com/axw/gocov/gocov/report.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2012 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package main - -import ( - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - "text/tabwriter" - - "github.com/axw/gocov" -) - -type report struct { - packages []*gocov.Package -} - -type reportFunction struct { - *gocov.Function - statementsReached int -} - -type reportFunctionList []reportFunction - -func (l reportFunctionList) Len() int { - return len(l) -} - -// TODO make sort method configurable? -func (l reportFunctionList) Less(i, j int) bool { - var left, right float64 - if len(l[i].Statements) > 0 { - left = float64(l[i].statementsReached) / float64(len(l[i].Statements)) - } - if len(l[j].Statements) > 0 { - right = float64(l[j].statementsReached) / float64(len(l[j].Statements)) - } - if left < right { - return true - } - return left == right && len(l[i].Statements) < len(l[j].Statements) -} - -func (l reportFunctionList) Swap(i, j int) { - l[i], l[j] = l[j], l[i] -} - -type reverse struct { - sort.Interface -} - -func (r reverse) Less(i, j int) bool { - return r.Interface.Less(j, i) -} - -// NewReport creates a new report. -func newReport() (r *report) { - r = &report{} - return -} - -// AddPackage adds a package's coverage information to the report. -func (r *report) addPackage(p *gocov.Package) { - i := sort.Search(len(r.packages), func(i int) bool { - return r.packages[i].Name >= p.Name - }) - if i < len(r.packages) && r.packages[i].Name == p.Name { - r.packages[i].Accumulate(p) - } else { - head := r.packages[:i] - tail := append([]*gocov.Package{p}, r.packages[i:]...) - r.packages = append(head, tail...) - } -} - -// Clear clears the coverage information from the report. -func (r *report) clear() { - r.packages = nil -} - -// PrintReport prints a coverage report to the given writer. -func printReport(w io.Writer, r *report) { - w = tabwriter.NewWriter(w, 0, 8, 0, '\t', 0) - //fmt.Fprintln(w, "Package\tFunction\tStatements\t") - //fmt.Fprintln(w, "-------\t--------\t---------\t") - for _, pkg := range r.packages { - printPackage(w, pkg) - fmt.Fprintln(w) - } -} - -func printPackage(w io.Writer, pkg *gocov.Package) { - functions := make(reportFunctionList, len(pkg.Functions)) - for i, fn := range pkg.Functions { - reached := 0 - for _, stmt := range fn.Statements { - if stmt.Reached > 0 { - reached++ - } - } - functions[i] = reportFunction{fn, reached} - } - sort.Sort(reverse{functions}) - - var longestFunctionName int - var totalStatements, totalReached int - for _, fn := range functions { - reached := fn.statementsReached - totalStatements += len(fn.Statements) - totalReached += reached - var stmtPercent float64 = 0 - if len(fn.Statements) > 0 { - stmtPercent = float64(reached) / float64(len(fn.Statements)) * 100 - } - if len(fn.Name) > longestFunctionName { - longestFunctionName = len(fn.Name) - } - fmt.Fprintf(w, "%s/%s\t %s\t %.2f%% (%d/%d)\n", - pkg.Name, filepath.Base(fn.File), fn.Name, stmtPercent, - reached, len(fn.Statements)) - } - - var funcPercent float64 - if totalStatements > 0 { - funcPercent = float64(totalReached) / float64(totalStatements) * 100 - } - summaryLine := strings.Repeat("-", longestFunctionName) - fmt.Fprintf(w, "%s\t %s\t %.2f%% (%d/%d)\n", - pkg.Name, summaryLine, funcPercent, - totalReached, totalStatements) -} - -func reportCoverage() (rc int) { - files := make([]*os.File, 0, 1) - if flag.NArg() > 1 { - for _, name := range flag.Args()[1:] { - file, err := os.Open(name) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to open file (%s): %s\n", name, err) - } else { - files = append(files, file) - } - } - } else { - files = append(files, os.Stdin) - } - report := newReport() - for _, file := range files { - data, err := ioutil.ReadAll(file) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read coverage file: %s\n", err) - return 1 - } - packages, err := unmarshalJson(data) - if err != nil { - fmt.Fprintf( - os.Stderr, "failed to unmarshal coverage data: %s\n", err) - return 1 - } - for _, pkg := range packages { - report.addPackage(pkg) - } - if file != os.Stdin { - file.Close() - } - } - fmt.Println() - printReport(os.Stdout, report) - return 0 -} diff --git a/vendor/github.com/axw/gocov/gocov/test.go b/vendor/github.com/axw/gocov/gocov/test.go deleted file mode 100644 index d723078..0000000 --- a/vendor/github.com/axw/gocov/gocov/test.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2013 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package main - -import ( - "io/ioutil" - "os" - "os/exec" -) - -func runTests(args []string) error { - coverprofile, err := ioutil.TempFile("", "gocov") - if err != nil { - return err - } - coverprofile.Close() - defer os.Remove(coverprofile.Name()) - args = append([]string{ - "test", "-coverprofile", coverprofile.Name(), - }, args...) - cmd := exec.Command("go", args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stderr - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return err - } - return convertProfiles(coverprofile.Name()) -} diff --git a/vendor/github.com/axw/gocov/gocov_test.go b/vendor/github.com/axw/gocov/gocov_test.go deleted file mode 100644 index 021bfc6..0000000 --- a/vendor/github.com/axw/gocov/gocov_test.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2012 The Gocov Authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -package gocov - -import "testing" - -func registerPackage(name string) *Package { - return &Package{Name: name} -} - -func registerFunction(p *Package, name, file string, startOffset, endOffset int) *Function { - f := &Function{Name: name, File: file, Start: startOffset, End: endOffset} - p.Functions = append(p.Functions, f) - return f -} - -func registerStatement(f *Function, startOffset, endOffset int) *Statement { - s := &Statement{Start: startOffset, End: endOffset} - f.Statements = append(f.Statements, s) - return s -} - -func TestAccumulatePackage(t *testing.T) { - p1_1 := registerPackage("p1") - p1_2 := registerPackage("p1") - p2 := registerPackage("p2") - p3 := registerPackage("p1") - registerFunction(p3, "f", "file.go", 0, 1) - p4 := registerPackage("p1") - registerFunction(p4, "f", "file.go", 1, 2) - - var tests = [...]struct { - a, b *Package - expectPass bool - }{ - // Should work: everything is the same. - {p1_1, p1_2, true}, - // Should fail: name is different. - {p1_1, p2, false}, - // Should fail: numbers of functions are different. - {p1_1, p3, false}, - // Should fail: functions are different. - {p3, p4, false}, - } - - for _, test := range tests { - err := test.a.Accumulate(test.b) - if test.expectPass { - if err != nil { - t.Error(err) - } - } else { - if err == nil { - t.Error("Expected an error") - } - } - } -} - -func TestAccumulateFunction(t *testing.T) { - p := registerPackage("p1") - f1_1 := registerFunction(p, "f1", "file.go", 0, 1) - f1_2 := registerFunction(p, "f1", "file.go", 0, 1) - f2 := registerFunction(p, "f2", "file.go", 0, 1) - f3 := registerFunction(p, "f1", "file2.go", 0, 1) - f4 := registerFunction(p, "f1", "file.go", 2, 3) - f5 := registerFunction(p, "f1", "file.go", 0, 1) - registerStatement(f5, 0, 1) - f6 := registerFunction(p, "f1", "file.go", 0, 1) - registerStatement(f6, 2, 3) - - var tests = [...]struct { - a, b *Function - expectPass bool - }{ - // Should work: everything is the same. - {f1_1, f1_2, true}, - // Should fail: names are different. - {f1_1, f2, false}, - // Should fail: files are different. - {f1_1, f3, false}, - // Should fail: ranges are different. - {f1_1, f4, false}, - // Should fail: numbers of statements are different. - {f1_1, f5, false}, - // Should fail: all the same, except statement values. - {f5, f6, false}, - } - - for _, test := range tests { - err := test.a.Accumulate(test.b) - if test.expectPass { - if err != nil { - t.Error(err) - } - } else { - if err == nil { - t.Error("Expected an error") - } - } - } -} - -func TestAccumulateStatement(t *testing.T) { - p := registerPackage("p1") - f := registerFunction(p, "f1", "file.go", 0, 1) - s1_1 := registerStatement(f, 0, 1) - s1_2 := registerStatement(f, 0, 1) - s2 := registerStatement(f, 2, 3) - - // Should work: ranges are the same. - if err := s1_1.Accumulate(s1_2); err != nil { - t.Error(err) - } - - // Should fail: ranges are not the same. - if err := s1_1.Accumulate(s2); err == nil { - t.Errorf("Expected an error") - } -} diff --git a/vendor/github.com/axw/gocov/gocovutil/packages.go b/vendor/github.com/axw/gocov/gocovutil/packages.go deleted file mode 100644 index 9b407c6..0000000 --- a/vendor/github.com/axw/gocov/gocovutil/packages.go +++ /dev/null @@ -1,82 +0,0 @@ -package gocovutil - -import ( - "encoding/json" - "github.com/axw/gocov" - "io/ioutil" - "os" - "sort" -) - -// Packages represents a set of gocov.Package structures. -// The "AddPackage" method may be used to merge package -// coverage results into the set. -type Packages []*gocov.Package - -// AddPackage adds a package's coverage information to the -func (ps *Packages) AddPackage(p *gocov.Package) { - i := sort.Search(len(*ps), func(i int) bool { - return (*ps)[i].Name >= p.Name - }) - if i < len(*ps) && (*ps)[i].Name == p.Name { - (*ps)[i].Accumulate(p) - } else { - head := (*ps)[:i] - tail := append([]*gocov.Package{p}, (*ps)[i:]...) - *ps = append(head, tail...) - } -} - -// ReadPackages takes a list of filenames and parses their -// contents as a Packages object. -// -// The special filename "-" may be used to indicate standard input. -// Duplicate filenames are ignored. -func ReadPackages(filenames []string) (ps Packages, err error) { - copy_ := make([]string, len(filenames)) - copy(copy_, filenames) - filenames = copy_ - sort.Strings(filenames) - - // Eliminate duplicates. - unique := []string{filenames[0]} - if len(filenames) > 1 { - for _, f := range filenames[1:] { - if f != unique[len(unique)-1] { - unique = append(unique, f) - } - } - } - - // Open files. - var files []*os.File - for _, f := range filenames { - if f == "-" { - files = append(files, os.Stdin) - } else { - file, err := os.Open(f) - if err != nil { - return nil, err - } - defer file.Close() - files = append(files, os.Stdin) - } - } - - // Parse the files, accumulate Packages. - for _, file := range files { - data, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - result := &struct{ Packages []*gocov.Package }{} - err = json.Unmarshal(data, result) - if err != nil { - return nil, err - } - for _, p := range result.Packages { - ps.AddPackage(p) - } - } - return ps, nil -} diff --git a/vendor/golang.org/x/tools/LICENSE b/vendor/golang.org/x/tools/LICENSE deleted file mode 100644 index 6a66aea..0000000 --- a/vendor/golang.org/x/tools/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/tools/PATENTS b/vendor/golang.org/x/tools/PATENTS deleted file mode 100644 index 7330990..0000000 --- a/vendor/golang.org/x/tools/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/tools/cover/profile.go b/vendor/golang.org/x/tools/cover/profile.go deleted file mode 100644 index a53bf4e..0000000 --- a/vendor/golang.org/x/tools/cover/profile.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cover provides support for parsing coverage profiles -// generated by "go test -coverprofile=cover.out". -package cover // import "golang.org/x/tools/cover" - -import ( - "bufio" - "fmt" - "math" - "os" - "regexp" - "sort" - "strconv" - "strings" -) - -// Profile represents the profiling data for a specific file. -type Profile struct { - FileName string - Mode string - Blocks []ProfileBlock -} - -// ProfileBlock represents a single block of profiling data. -type ProfileBlock struct { - StartLine, StartCol int - EndLine, EndCol int - NumStmt, Count int -} - -type byFileName []*Profile - -func (p byFileName) Len() int { return len(p) } -func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName } -func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -// ParseProfiles parses profile data in the specified file and returns a -// Profile for each source file described therein. -func ParseProfiles(fileName string) ([]*Profile, error) { - pf, err := os.Open(fileName) - if err != nil { - return nil, err - } - defer pf.Close() - - files := make(map[string]*Profile) - buf := bufio.NewReader(pf) - // First line is "mode: foo", where foo is "set", "count", or "atomic". - // Rest of file is in the format - // encoding/base64/base64.go:34.44,37.40 3 1 - // where the fields are: name.go:line.column,line.column numberOfStatements count - s := bufio.NewScanner(buf) - mode := "" - for s.Scan() { - line := s.Text() - if mode == "" { - const p = "mode: " - if !strings.HasPrefix(line, p) || line == p { - return nil, fmt.Errorf("bad mode line: %v", line) - } - mode = line[len(p):] - continue - } - m := lineRe.FindStringSubmatch(line) - if m == nil { - return nil, fmt.Errorf("line %q doesn't match expected format: %v", m, lineRe) - } - fn := m[1] - p := files[fn] - if p == nil { - p = &Profile{ - FileName: fn, - Mode: mode, - } - files[fn] = p - } - p.Blocks = append(p.Blocks, ProfileBlock{ - StartLine: toInt(m[2]), - StartCol: toInt(m[3]), - EndLine: toInt(m[4]), - EndCol: toInt(m[5]), - NumStmt: toInt(m[6]), - Count: toInt(m[7]), - }) - } - if err := s.Err(); err != nil { - return nil, err - } - for _, p := range files { - sort.Sort(blocksByStart(p.Blocks)) - } - // Generate a sorted slice. - profiles := make([]*Profile, 0, len(files)) - for _, profile := range files { - profiles = append(profiles, profile) - } - sort.Sort(byFileName(profiles)) - return profiles, nil -} - -type blocksByStart []ProfileBlock - -func (b blocksByStart) Len() int { return len(b) } -func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] } -func (b blocksByStart) Less(i, j int) bool { - bi, bj := b[i], b[j] - return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol -} - -var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`) - -func toInt(s string) int { - i, err := strconv.Atoi(s) - if err != nil { - panic(err) - } - return i -} - -// Boundary represents the position in a source file of the beginning or end of a -// block as reported by the coverage profile. In HTML mode, it will correspond to -// the opening or closing of a <span> tag and will be used to colorize the source -type Boundary struct { - Offset int // Location as a byte offset in the source file. - Start bool // Is this the start of a block? - Count int // Event count from the cover profile. - Norm float64 // Count normalized to [0..1]. -} - -// Boundaries returns a Profile as a set of Boundary objects within the provided src. -func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { - // Find maximum count. - max := 0 - for _, b := range p.Blocks { - if b.Count > max { - max = b.Count - } - } - // Divisor for normalization. - divisor := math.Log(float64(max)) - - // boundary returns a Boundary, populating the Norm field with a normalized Count. - boundary := func(offset int, start bool, count int) Boundary { - b := Boundary{Offset: offset, Start: start, Count: count} - if !start || count == 0 { - return b - } - if max <= 1 { - b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. - } else if count > 0 { - b.Norm = math.Log(float64(count)) / divisor - } - return b - } - - line, col := 1, 2 // TODO: Why is this 2? - for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); { - b := p.Blocks[bi] - if b.StartLine == line && b.StartCol == col { - boundaries = append(boundaries, boundary(si, true, b.Count)) - } - if b.EndLine == line && b.EndCol == col || line > b.EndLine { - boundaries = append(boundaries, boundary(si, false, 0)) - bi++ - continue // Don't advance through src; maybe the next block starts here. - } - if src[si] == '\n' { - line++ - col = 0 - } - col++ - si++ - } - sort.Sort(boundariesByPos(boundaries)) - return -} - -type boundariesByPos []Boundary - -func (b boundariesByPos) Len() int { return len(b) } -func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } -func (b boundariesByPos) Less(i, j int) bool { - if b[i].Offset == b[j].Offset { - return !b[i].Start && b[j].Start - } - return b[i].Offset < b[j].Offset -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/accounts.go b/vendor/launchpad.net/go-unityscopes/v2/accounts.go deleted file mode 100644 index 29ad7c9..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/accounts.go +++ /dev/null @@ -1,41 +0,0 @@ -package scopes - -type PostLoginAction int - -const ( - _ = PostLoginAction(iota) - PostLoginDoNothing - PostLoginInvalidateResults - PostLoginContinueActivation -) - -type accountDetails struct { - ScopeID string `json:"scope_id"` - ServiceName string `json:"service_name"` - ServiceType string `json:"service_type"` - ProviderName string `json:"provider_name"` - LoginPassedAction PostLoginAction `json:"login_passed_action"` - LoginFailedAction PostLoginAction `json:"login_failed_action"` -} - -// RegisterAccountLoginResult configures a result such that the dash -// will attempt to log in to the account identified by (serviceName, -// serviceType, providerName). -// -// On success, the dash will perform the action specified by -// passedAction. On failure, it will use failedAction. -func RegisterAccountLoginResult(result *CategorisedResult, query *CannedQuery, serviceName, serviceType, providerName string, passedAction, failedAction PostLoginAction) error { - if result.URI() == "" { - if err := result.SetURI(query.ToURI()); err != nil { - return err - } - } - return result.Set("online_account_details", accountDetails{ - ScopeID: query.ScopeID(), - ServiceName: serviceName, - ServiceType: serviceType, - ProviderName: providerName, - LoginPassedAction: passedAction, - LoginFailedAction: failedAction, - }) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/activationresponse.cpp b/vendor/launchpad.net/go-unityscopes/v2/activationresponse.cpp deleted file mode 100644 index 134ff05..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/activationresponse.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include <stdexcept> -#include <cstring> - -#include <unity/scopes/ActivationResponse.h> -#include <unity/scopes/CannedQuery.h> -#include <unity/scopes/PreviewWidget.h> -#include <unity/scopes/Result.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -void activation_response_init_status(_ActivationResponse *response, int status) { - *reinterpret_cast<ActivationResponse*>(response) = - ActivationResponse(static_cast<ActivationResponse::Status>(status)); -} - -void activation_response_init_query(_ActivationResponse *response, _CannedQuery *query) { - *reinterpret_cast<ActivationResponse*>(response) = - ActivationResponse(*reinterpret_cast<CannedQuery*>(query)); -} - -void activation_response_init_update_result(_ActivationResponse *response, _Result *result) { - *reinterpret_cast<ActivationResponse*>(response) = - ActivationResponse(*reinterpret_cast<Result*>(result)); -} - -void activation_response_init_update_preview(_ActivationResponse *response, const StrData widget_list, char **error) { - try { - PreviewWidgetList widgets; - for (const auto &data : split_strings(widget_list)) { - widgets.push_back(PreviewWidget(data)); - } - *reinterpret_cast<ActivationResponse*>(response) = - ActivationResponse(widgets); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void activation_response_set_scope_data(_ActivationResponse *response, char *json_data, int json_data_length, char **error) { - try { - Variant v = Variant::deserialize_json(std::string(json_data, json_data_length)); - reinterpret_cast<ActivationResponse*>(response)->set_scope_data(v); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/activationresponse.go b/vendor/launchpad.net/go-unityscopes/v2/activationresponse.go deleted file mode 100644 index acece15..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/activationresponse.go +++ /dev/null @@ -1,118 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "unsafe" -) - -type ActivationStatus int - -const ( - ActivationNotHandled ActivationStatus = iota - ActivationShowDash - ActivationHideDash - ActivationShowPreview - ActivationPerformQuery - ActivationUpdateResult - ActivationUpdatePreview -) - -// ActivationResponse is used as the result of a Activate() or -// PerformAction() call on the scope to instruct the dash on what to -// do next. -type ActivationResponse struct { - Status ActivationStatus - Query *CannedQuery - Result *Result - Widgets []PreviewWidget - ScopeData interface{} -} - -// NewActivationResponse creates an ActivationResponse with the given status -// -// This function should not be used to create an -// ActivationPerformQuery response: use NewActivationResponseForQuery -// instead. -func NewActivationResponse(status ActivationStatus) *ActivationResponse { - switch status { - case ActivationPerformQuery: - panic("Use NewActivationResponseFromQuery for PerformQuery responses") - case ActivationUpdateResult: - panic("Use NewActivationResponseUpdateResult for UpdateResult responses") - case ActivationUpdatePreview: - panic("Use NewActivationResponseUpdatePreview for UpdatePreview responses") - } - return &ActivationResponse{ - Status: status, - Query: nil, - } -} - -// NewActivationResponseForQuery creates an ActivationResponse that -// performs the given query. -func NewActivationResponseForQuery(query *CannedQuery) *ActivationResponse { - return &ActivationResponse{ - Status: ActivationPerformQuery, - Query: query, - } -} - -func NewActivationResponseUpdateResult(result *Result) *ActivationResponse { - return &ActivationResponse{ - Status: ActivationUpdateResult, - Result: result, - } -} - -func NewActivationResponseUpdatePreview(widgets ...PreviewWidget) *ActivationResponse { - return &ActivationResponse{ - Status: ActivationUpdatePreview, - Widgets: widgets, - } -} - -func (r *ActivationResponse) update(responsePtr *C._ActivationResponse) error { - switch r.Status { - case ActivationPerformQuery: - C.activation_response_init_query(responsePtr, r.Query.q) - case ActivationUpdateResult: - C.activation_response_init_update_result(responsePtr, r.Result.result) - case ActivationUpdatePreview: - widgetData := make([]string, len(r.Widgets)) - for i, w := range r.Widgets { - data, err := w.data() - if err != nil { - return err - } - widgetData[i] = string(data) - } - var errorString *C.char - C.activation_response_init_update_preview(responsePtr, joinedStrData(widgetData), &errorString) - if err := checkError(errorString); err != nil { - return err - } - default: - C.activation_response_init_status(responsePtr, C.int(r.Status)) - } - if r.ScopeData != nil { - data, err := json.Marshal(r.ScopeData) - if err != nil { - return err - } - var errorString *C.char - C.activation_response_set_scope_data(responsePtr, (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)), &errorString) - if err = checkError(errorString); err != nil { - return err - } - } - return nil -} - -// SetScopeData stores data that will be passed through to the preview -// for ActivationShowPreview type responses. -func (r *ActivationResponse) SetScopeData(v interface{}) { - r.ScopeData = v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/activationresponse_test.go b/vendor/launchpad.net/go-unityscopes/v2/activationresponse_test.go deleted file mode 100644 index 3c7f2ac..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/activationresponse_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestActivationResponse(c *C) { - // check all different status - response := scopes.NewActivationResponse(scopes.ActivationNotHandled) - c.Check(response.Status, Equals, scopes.ActivationNotHandled) - c.Check(response.Query, IsNil) - c.Check(response.ScopeData, IsNil) - - response = scopes.NewActivationResponse(scopes.ActivationShowDash) - c.Check(response.Status, Equals, scopes.ActivationShowDash) - c.Check(response.Query, IsNil) - c.Check(response.ScopeData, IsNil) - - response = scopes.NewActivationResponse(scopes.ActivationShowDash) - c.Check(response.Status, Equals, scopes.ActivationShowDash) - c.Check(response.Query, IsNil) - c.Check(response.ScopeData, IsNil) - - // we should get panic with ActivationPerformQuery - c.Check(func() { scopes.NewActivationResponse(scopes.ActivationPerformQuery) }, PanicMatches, "Use NewActivationResponseFromQuery for PerformQuery responses") - - // test SetScopeData - response.SetScopeData("test_string") - c.Check(response.ScopeData, Equals, "test_string") - - response.SetScopeData(1999) - c.Check(response.ScopeData, Equals, 1999) - - response.SetScopeData(1.999) - c.Check(response.ScopeData, Equals, 1.999) - - response.SetScopeData([]string{"test1", "test2"}) - c.Check(response.ScopeData, DeepEquals, []string{"test1", "test2"}) - - // test activation response for query - query := scopes.NewCannedQuery("scope", "query_string", "department_string") - response_query := scopes.NewActivationResponseForQuery(query) - - c.Check(response_query.Status, Equals, scopes.ActivationPerformQuery) - c.Check(response_query.Query, Equals, query) - c.Check(response_query.ScopeData, IsNil) - - // test activation response for reply - result := scopes.NewTestingResult() - response = scopes.NewActivationResponseUpdateResult(result) - c.Check(response.Status, Equals, scopes.ActivationUpdateResult) - c.Check(response.Result, Equals, result) - - // test activation response for a preview update - widget1 := scopes.NewPreviewWidget("id1", "text") - widget2 := scopes.NewPreviewWidget("id2", "image") - response = scopes.NewActivationResponseUpdatePreview(widget1, widget2) - c.Check(response.Status, Equals, scopes.ActivationUpdatePreview) - c.Check(response.Widgets, DeepEquals, []scopes.PreviewWidget{widget1, widget2}) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/childscope.cpp b/vendor/launchpad.net/go-unityscopes/v2/childscope.cpp deleted file mode 100644 index 246b933..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/childscope.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include <cstring> - -#include <unity/scopes/ChildScope.h> -#include <unity/scopes/ScopeMetadata.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -_ChildScope *new_child_scope(const StrData id, _ScopeMetadata *metadata, int enabled, const StrData keyword_list) { - ScopeMetadata *api_metadata = reinterpret_cast<ScopeMetadata *>(metadata); - - std::set<std::string> keywords; - for (auto &k : split_strings(keyword_list)) { - keywords.emplace(std::move(k)); - } - - return reinterpret_cast<_ChildScope *>(new ChildScope(from_gostring(id), *api_metadata, enabled, keywords)); -} - -void destroy_child_scope(_ChildScope *childscope) { - delete reinterpret_cast<ChildScope*>(childscope); -} - -char *child_scope_get_id(_ChildScope *childscope) { - return strdup(reinterpret_cast<ChildScope*>(childscope)->id.c_str()); -} - -void set_child_scopes_list(void *child_scopes_list, _ChildScope **source_child_scopes, int length) { - ChildScopeList *c_child_scopes_list = reinterpret_cast<ChildScopeList*>(child_scopes_list); - for (int i=0; i < length; ++i) { - ChildScope *pItem = reinterpret_cast<ChildScope*>(source_child_scopes[i]); - c_child_scopes_list->push_back(*pItem); - } -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/childscope.go b/vendor/launchpad.net/go-unityscopes/v2/childscope.go deleted file mode 100644 index 22b8db3..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/childscope.go +++ /dev/null @@ -1,48 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "runtime" - "unsafe" -) - -type ChildScope struct { - c *C._ChildScope -} - -func finalizeChildScope(childscope *ChildScope) { - if childscope.c != nil { - C.destroy_child_scope((*C._ChildScope)(childscope.c)) - } - childscope.c = nil -} - -func makeChildScope(c *C._ChildScope) *ChildScope { - childscope := new(ChildScope) - runtime.SetFinalizer(childscope, finalizeChildScope) - childscope.c = (*C._ChildScope)(c) - return childscope -} - -// NewChildScope creates a new ChildScope with the given id, metadata, enabled state and keywords -func NewChildScope(id string, metadata *ScopeMetadata, enabled bool, keywords []string) *ChildScope { - var cEnabled C.int - if enabled { - cEnabled = 1 - } else { - cEnabled = 0 - } - return makeChildScope(C.new_child_scope(strData(id), - (*C._ScopeMetadata)(metadata.m), - cEnabled, - joinedStrData(keywords))) -} - -// Id returns the identifier of the child scope -func (childscope *ChildScope) Id() string { - s := C.child_scope_get_id(childscope.c) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/column_layout.cpp b/vendor/launchpad.net/go-unityscopes/v2/column_layout.cpp deleted file mode 100644 index e736d2e..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/column_layout.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include <unity/scopes/ColumnLayout.h> -#include <unity/scopes/Variant.h> - -#include <unity/UnityExceptions.h> - -extern "C" { -#include "_cgo_export.h" -} - -#include <cstring> - -#include "helpers.h" -#include "smartptr_helper.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -void destroy_column_layout(_ColumnLayout *layout) { - delete reinterpret_cast<ColumnLayout*>(layout); -} - -_ColumnLayout *new_column_layout(int num_columns) { - return reinterpret_cast<_ColumnLayout*>(new ColumnLayout(num_columns)); -} - -void column_layout_add_column(_ColumnLayout *layout, const StrData widget_list, char **error) { - std::vector<std::string> widgets = split_strings(widget_list); - try { - reinterpret_cast<ColumnLayout*>(layout)->add_column(widgets); - } catch(unity::LogicException & e) { - *error = strdup(e.what()); - } -} - -int column_layout_number_of_columns(_ColumnLayout *layout) { - return reinterpret_cast<ColumnLayout*>(layout)->number_of_columns(); -} - -int column_layout_size(_ColumnLayout *layout) { - return reinterpret_cast<ColumnLayout*>(layout)->size(); -} - -void *column_layout_column(_ColumnLayout *layout, int column, int *length, char **error) { - try { - auto columns = reinterpret_cast<ColumnLayout*>(layout)->column(column); - VariantArray var_array; - for (auto item: columns) { - var_array.push_back(Variant(item)); - } - std::string json_data = Variant(var_array).serialize_json(); - return as_bytes(json_data, length); - - } catch(const std::exception & e) { - *error = strdup(e.what()); - return nullptr; - } -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/column_layout.go b/vendor/launchpad.net/go-unityscopes/v2/column_layout.go deleted file mode 100644 index 6eee63f..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/column_layout.go +++ /dev/null @@ -1,75 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "runtime" -) - -// ColumnLayout is used represent different representations of a widget. -// Depending on the device your applications runs you can have several predefined -// column layouts in order to represent your view in the way it fits better the -// aspect ratio. -type ColumnLayout struct { - c *C._ColumnLayout -} - -func finalizeColumnLayout(layout *ColumnLayout) { - if layout.c != nil { - C.destroy_column_layout(layout.c) - } - layout.c = nil -} - -func makeColumnLayout(c *C._ColumnLayout) *ColumnLayout { - layout := new(ColumnLayout) - runtime.SetFinalizer(layout, finalizeColumnLayout) - layout.c = c - return layout -} - -// NewColumnLayout Creates a layout definition that expects num_of_columns columns to be added with ColumnLayout.AddColumn. -func NewColumnLayout(num_columns int) *ColumnLayout { - return makeColumnLayout(C.new_column_layout(C.int(num_columns))) -} - -// AddColumn adds a new column and assigns widgets to it. -// ColumnLayout expects exactly the number of columns passed to the constructor to be created with the -// AddColumn method. -func (layout *ColumnLayout) AddColumn(widgetIds ...string) error { - var errorString *C.char - C.column_layout_add_column(layout.c, joinedStrData(widgetIds), &errorString) - - return checkError(errorString) -} - -// NumberOfColumns gets the number of columns expected by this layout as specified in the constructor. -func (layout *ColumnLayout) NumberOfColumns() int { - return int(C.column_layout_number_of_columns(layout.c)) -} - -// Size gets the current number of columns in this layout. -func (layout *ColumnLayout) Size() int { - return int(C.column_layout_size(layout.c)) -} - -// Column retrieves the list of widgets for given column. -func (layout *ColumnLayout) Column(column int) ([]string, error) { - var ( - length C.int - errorString *C.char - ) - - data := C.column_layout_column(layout.c, C.int(column), &length, &errorString) - if err := checkError(errorString); err != nil { - return nil, err - } - defer C.free(data) - - var value []string - err := json.Unmarshal(C.GoBytes(data, length), &value) - - return value, err -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/column_layout_test.go b/vendor/launchpad.net/go-unityscopes/v2/column_layout_test.go deleted file mode 100644 index 6ec2f05..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/column_layout_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestColumnLayout(c *C) { - layout := scopes.NewColumnLayout(3) - - c.Check(layout.Size(), Equals, 0) - c.Check(layout.NumberOfColumns(), Equals, 3) - - err := layout.AddColumn("widget_1", "widget_2") - c.Assert(err, IsNil) - - c.Check(layout.Size(), Equals, 1) - c.Check(layout.NumberOfColumns(), Equals, 3) - - col, err := layout.Column(0) - c.Assert(err, IsNil) - - c.Check(len(col), Equals, 2) - c.Check(col, DeepEquals, []string{"widget_1", "widget_2"}) - - // add another column - err = layout.AddColumn("widget_3", "widget_4", "widget_5") - c.Assert(err, IsNil) - - col, err = layout.Column(1) - c.Assert(err, IsNil) - - c.Check(len(col), Equals, 3) - c.Check(col, DeepEquals, []string{"widget_3", "widget_4", "widget_5"}) - - // check for a bad column - _, err = layout.Column(2) - c.Assert(err, Not(Equals), nil) - - // now add the last column - err = layout.AddColumn("widget_6") - c.Assert(err, IsNil) - - col, err = layout.Column(2) - c.Assert(err, IsNil) - - c.Check(len(col), Equals, 1) - c.Check(col[0], Equals, "widget_6") - - // try to add more columns ... should obtain an error - err = layout.AddColumn("widget_3", "widget_4", "widget_5") - c.Assert(err, Not(Equals), nil) - - // check size again - c.Check(layout.Size(), Equals, 3) - c.Check(layout.NumberOfColumns(), Equals, 3) - - // check empty list - layout1col := scopes.NewColumnLayout(1) - err = layout1col.AddColumn() - c.Check(err, IsNil) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/department.cpp b/vendor/launchpad.net/go-unityscopes/v2/department.cpp deleted file mode 100644 index 2ee0b7e..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/department.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include <stdexcept> -#include <cstring> - -#include <unity/scopes/Department.h> -#include <unity/scopes/CannedQuery.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" -#include "smartptr_helper.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -/* Department objects */ -void init_department_ptr(SharedPtrData dest, SharedPtrData src) { - std::shared_ptr<Department> dept = get_ptr<Department>(src); - init_ptr<Department>(dest, dept); -} - -void new_department(const StrData dept_id, _CannedQuery *query, const StrData label, SharedPtrData dept, char **error) { - try { - auto d = Department::create(from_gostring(dept_id), - *reinterpret_cast<CannedQuery*>(query), - from_gostring(label)); - init_ptr<Department>(dept, std::move(d)); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void destroy_department_ptr(SharedPtrData data) { - destroy_ptr<Department>(data); -} - -void department_add_subdepartment(SharedPtrData dept, SharedPtrData child) { - get_ptr<Department>(dept)->add_subdepartment(get_ptr<Department>(child)); -} - -void department_set_alternate_label(SharedPtrData dept, const StrData label) { - get_ptr<Department>(dept)->set_alternate_label(from_gostring(label)); -} - -char *department_get_alternate_label(SharedPtrData dept) { - return strdup(get_ptr<Department>(dept)->alternate_label().c_str()); -} - -char *department_get_id(SharedPtrData dept) { - return strdup(get_ptr<Department>(dept)->id().c_str()); -} - -char *department_get_label(SharedPtrData dept) { - return strdup(get_ptr<Department>(dept)->label().c_str()); -} - -void department_set_has_subdepartments(SharedPtrData dept, int subdepartments) { - get_ptr<Department>(dept)->set_has_subdepartments(subdepartments); -} - -int department_has_subdepartments(SharedPtrData dept) { - return static_cast<int>(get_ptr<Department>(dept)->has_subdepartments()); -} - -SharedPtrData * department_get_subdepartments(SharedPtrData dept, int *n_subdepts) { - auto subdepts = get_ptr<Department>(dept)->subdepartments(); - *n_subdepts = subdepts.size(); - SharedPtrData* ret_data = - reinterpret_cast<SharedPtrData*>(calloc(*n_subdepts, sizeof(SharedPtrData))); - int i = 0; - for(auto item: subdepts) { - init_ptr<Department const>(ret_data[i++], item); - } - return ret_data; -} - -void department_set_subdepartments(SharedPtrData dept, SharedPtrData *subdepartments, int nb_subdepartments) { - DepartmentList api_depts; - for(auto i = 0; i < nb_subdepartments; i++) { - api_depts.push_back(get_ptr<Department>(subdepartments[i])); - } - get_ptr<Department>(dept)->set_subdepartments(api_depts); -} - -_CannedQuery * department_get_query(SharedPtrData dept) { - return reinterpret_cast<_CannedQuery*>(new CannedQuery(get_ptr<Department>(dept)->query())); -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/department.go b/vendor/launchpad.net/go-unityscopes/v2/department.go deleted file mode 100644 index 4fe1ca5..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/department.go +++ /dev/null @@ -1,146 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "runtime" - "unsafe" -) - -// Department represents a section of the a scope's results. A -// department can have sub-departments. -type Department struct { - d C.SharedPtrData -} - -func makeDepartment() *Department { - dept := new(Department) - runtime.SetFinalizer(dept, finalizeDepartment) - return dept -} - -// NewDepartment creates a new department using the given canned query. -func NewDepartment(departmentID string, query *CannedQuery, label string) (*Department, error) { - dept := makeDepartment() - var errorString *C.char - C.new_department(strData(departmentID), query.q, strData(label), &dept.d[0], &errorString) - - if err := checkError(errorString); err != nil { - return nil, err - } - return dept, nil -} - -func finalizeDepartment(dept *Department) { - C.destroy_department_ptr(&dept.d[0]) -} - -// AddSubdepartment adds a new child department to this department. -func (dept *Department) AddSubdepartment(child *Department) { - C.department_add_subdepartment(&dept.d[0], &child.d[0]) -} - -// Id gets the identifier of this department. -func (dept *Department) Id() string { - s := C.department_get_id(&dept.d[0]) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// Label gets the label of this department. -func (dept *Department) Label() string { - s := C.department_get_label(&dept.d[0]) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// Query gets the canned query associated with this department. -func (dept *Department) Query() *CannedQuery { - c_query := C.department_get_query(&dept.d[0]) - return makeCannedQuery(c_query) -} - -// SetAlternateLabel sets the alternate label for this department. -// -// This should express the plural form of the normal label. For -// example, if the normal label is "Books", then the alternate label -// should be "All Books". -// -// The alternate label only needs to be provided for the current -// department. -func (dept *Department) SetAlternateLabel(label string) { - C.department_set_alternate_label(&dept.d[0], strData(label)) -} - -// AlternateLabel gets the alternate label for this department. -// -// This should express the plural form of the normal label. For -// example, if the normal label is "Books", then the alternate label -// should be "All Books". -func (dept *Department) AlternateLabel() string { - s := C.department_get_alternate_label(&dept.d[0]) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// SetHasSubdepartments sets whether this department has subdepartments. -// -// It is not necessary to call this if AddSubdepartment has been -// called. It intended for cases where subdepartments have not been -// specified but the shell should still act as if it has them. -func (dept *Department) SetHasSubdepartments(subdepartments bool) { - var cSubdepts C.int - if subdepartments { - cSubdepts = 1 - } else { - cSubdepts = 0 - } - C.department_set_has_subdepartments(&dept.d[0], cSubdepts) -} - -// HasSubdepartments checks if this department has subdepartments or has_subdepartments flag is set -func (dept *Department) HasSubdepartments() bool { - if C.department_has_subdepartments(&dept.d[0]) == 1 { - return true - } else { - return false - } -} - -// Subdepartments gets list of sub-departments of this department. -func (dept *Department) Subdepartments() []*Department { - var nb_subdepartments C.int - var theCArray *C.SharedPtrData = C.department_get_subdepartments(&dept.d[0], &nb_subdepartments) - defer C.free(unsafe.Pointer(theCArray)) - length := int(nb_subdepartments) - // create a very big slice and then slice it to the number of subdepartments - slice := (*[1 << 27]C.SharedPtrData)(unsafe.Pointer(theCArray))[:length:length] - ptr_depts := make([]*Department, length) - for i := 0; i < length; i++ { - ptr_depts[i] = makeDepartment() - ptr_depts[i].d = slice[i] - } - return ptr_depts -} - -// SetSubdepartments sets sub-departments of this department. -func (dept *Department) SetSubdepartments(subdepartments []*Department) { - // This technically breaks C++ shared_ptr rules because we are - // making a copy of the shared_ptr that doesn't own a - // reference. - // - // However, we know the copy won't be destroyed on the C++ - // side, and we hold references to the underlying Deparment - // objects, preventing them from being cleaned up while the - // shared_ptr copies are in scope. - api_depts := make([]C.SharedPtrData, len(subdepartments)) - for i := 0; i < len(subdepartments); i++ { - api_depts[i] = subdepartments[i].d - } - if len(subdepartments) > 0 { - C.department_set_subdepartments(&dept.d[0], &api_depts[0], C.int(len(subdepartments))) - } else { - C.department_set_subdepartments(&dept.d[0], nil, C.int(len(subdepartments))) - } -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/department_test.go b/vendor/launchpad.net/go-unityscopes/v2/department_test.go deleted file mode 100644 index 4439d00..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/department_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestDepartment(c *C) { - query := scopes.NewCannedQuery("scope", "query_string", "department_string") - department, err := scopes.NewDepartment("department_string2", query, "TEST_DEPARTMENT") - c.Assert(err, IsNil) - - department.SetAlternateLabel("test_alternate_label") - c.Check(department.AlternateLabel(), Equals, "test_alternate_label") - c.Check(department.Id(), Equals, "department_string2") - c.Check(department.Label(), Equals, "TEST_DEPARTMENT") - - department.SetHasSubdepartments(true) - c.Check(department.HasSubdepartments(), Equals, true) - - department.SetHasSubdepartments(false) - c.Check(department.HasSubdepartments(), Equals, false) - - department2, err := scopes.NewDepartment("sub_department_string", query, "TEST_SUB_DEPARTMENT") - c.Assert(err, IsNil) - department2.SetAlternateLabel("test_alternate_label_2") - - department3, err := scopes.NewDepartment("sub_department_2_string", query, "TEST_SUB_DEPARTMENT_2") - c.Assert(err, IsNil) - department3.SetAlternateLabel("test_alternate_label_3") - - subdepartments := department.Subdepartments() - c.Check(len(subdepartments), Equals, 0) - c.Check(department.HasSubdepartments(), Equals, false) - - department.SetSubdepartments([]*scopes.Department{department2, department3}) - subdepartments = department.Subdepartments() - - c.Check(len(subdepartments), Equals, 2) - c.Check(department.HasSubdepartments(), Equals, true) - - // verify that the values are correct in all subdepartments - c.Check(subdepartments[0].Id(), Equals, department2.Id()) - c.Check(subdepartments[0].Label(), Equals, department2.Label()) - c.Check(subdepartments[0].AlternateLabel(), Equals, department2.AlternateLabel()) - c.Check(subdepartments[1].Id(), Equals, department3.Id()) - c.Check(subdepartments[1].Label(), Equals, department3.Label()) - c.Check(subdepartments[1].AlternateLabel(), Equals, department3.AlternateLabel()) - - sub_depts := make([]*scopes.Department, 0) - department.SetSubdepartments(sub_depts) - - subdepartments = department.Subdepartments() - c.Check(len(subdepartments), Equals, 0) - c.Check(department.HasSubdepartments(), Equals, false) - - department.SetSubdepartments([]*scopes.Department{department2, department3}) - - subdepartments = department.Subdepartments() - c.Check(len(subdepartments), Equals, 2) - c.Check(department.HasSubdepartments(), Equals, true) - - c.Check(subdepartments[0].Id(), Equals, department2.Id()) - c.Check(subdepartments[0].Label(), Equals, department2.Label()) - c.Check(subdepartments[0].AlternateLabel(), Equals, department2.AlternateLabel()) - c.Check(subdepartments[1].Id(), Equals, department3.Id()) - c.Check(subdepartments[1].Label(), Equals, department3.Label()) - c.Check(subdepartments[1].AlternateLabel(), Equals, department3.AlternateLabel()) - - stored_query := department.Query() - c.Check(stored_query.ScopeID(), Equals, "scope") - c.Check(stored_query.DepartmentID(), Equals, "department_string2") - c.Check(stored_query.QueryString(), Equals, "query_string") -} - -func (s *S) TestDepartmentDifferentCreation(c *C) { - query := scopes.NewCannedQuery("scope", "query_string", "department_string") - department, err := scopes.NewDepartment("", query, "TEST_DEPARTMENT") - - c.Assert(err, IsNil) - c.Check(department.Id(), Equals, "") - c.Check(department.Label(), Equals, "TEST_DEPARTMENT") -} - -func (s *S) TestDepartmentEmptyLabel(c *C) { - query := scopes.NewCannedQuery("scope", "query_string", "department_string") - department, err := scopes.NewDepartment("", query, "") - c.Check(err, Not(Equals), nil) - c.Check(department, IsNil) - - department, err = scopes.NewDepartment("dept_id", query, "") - c.Check(err, Not(Equals), nil) - c.Check(department, IsNil) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/doc.go b/vendor/launchpad.net/go-unityscopes/v2/doc.go deleted file mode 100644 index 1e97534..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/doc.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Package scopes is used to write Unity scopes in Go. - -Scopes are implemented through types that conform to the Scope interface. - - type MyScope struct {} - -The scope has access to a ScopeBase instance, which can be used to access -various pieces of information about the scope, such as its settings: - - func (s *MyScope) SetScopeBase(base *scopes.ScopeBase) { - } - -If the scope needs access to this information, it should save the -provided instance for later use. Otherwise, it the method body can be -left blank. - -The shell may ask the scope for search results, which will cause the -Search method to be invoked: - - func (s *MyScope) Search(query *scopes.CannedQuery, metadata *scopes.SearchMetadata, reply *scopes.SearchReply, cancelled <-chan bool) error { - category := reply.RegisterCategory("cat_id", "category", "", "") - result := scopes.NewCategorisedResult(category) - result.SetTitle("Result for " + query.QueryString()) - reply.Push(result) - return nil - } - -In general, scopes will: - -* Register result categories via reply.RegisterCategory() - -* Create new results via NewCategorisedResult(), and push them with reply.Push(result) - -* Check for cancellation requests via the provided channel. - -The Search method will be invoked with an empty query when surfacing -results are wanted. - -The shell may ask the scope to provide a preview of a result, which causes the Preview method to be invoked: - - func (s *MyScope) Preview(result *scopes.Result, metadata *scopes.ActionMetadata, reply *scopes.PreviewReply, cancelled <-chan bool) error { - widget := scopes.NewPreviewWidget("foo", "text") - widget.AddAttributeValue("text", "Hello") - reply.PushWidgets(widget) - return nil - } - -The scope should push one or more slices of PreviewWidgets using reply.PushWidgets. PreviewWidgets can be created with NewPreviewWidget. - -Additional data for the preview can be pushed with reply.PushAttr. - -If any of the preview widgets perform actions that the scope should -respond to, the scope should implement the PerformAction method: - - func (s *MyScope) PerformAction(result *Result, metadata *ActionMetadata, widgetId, actionId string) (*ActivationResponse, error) { - // handle the action and then tell the dash what to do next - // through an ActivationResponse. - resp := NewActivationResponse(ActivationHideDash) return resp, nil - } - -The PerformAction method is not part of the main Scope interface, so -the feature need only be implemented for scopes that use the feature. - -Finally, the scope can be exported in the main function: - - func main() { - if err := scopes.Run(&MyScope{}); err != nil { - log.Fatalln(err) - } - } - -The scope executable can be deployed to a scope directory named like: - - /usr/lib/${arch}/unity-scopes/${scope_name} - -In addition to the scope executable, a scope configuration file named -${scope_name}.ini should be placed in the directory. Its contents -should look something like: - - [ScopeConfig] - DisplayName = Short name for the scope - Description = Long description of scope - Author = - ScopeRunner = ${scope_executable} --runtime %R --scope %S -*/ -package scopes diff --git a/vendor/launchpad.net/go-unityscopes/v2/export_test.go b/vendor/launchpad.net/go-unityscopes/v2/export_test.go deleted file mode 100644 index 55f2011..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/export_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package scopes - -import ( - "encoding/json" -) - -// This file exports certain private functions for use by tests. - -func NewTestingResult() *Result { - return newTestingResult() -} - -func NewTestingScopeMetadata(json_data string) ScopeMetadata { - var scopeMetadata ScopeMetadata - if err := json.Unmarshal([]byte(json_data), &scopeMetadata); err != nil { - panic(err) - } - - return scopeMetadata -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/filters_base.go b/vendor/launchpad.net/go-unityscopes/v2/filters_base.go deleted file mode 100644 index 01b4e4c..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/filters_base.go +++ /dev/null @@ -1,95 +0,0 @@ -package scopes - -// Filter is implemented by all scope filter types. -type Filter interface { - serializeFilter() map[string]interface{} -} - -type FilterDisplayHints int - -const ( - FilterDisplayDefault FilterDisplayHints = 0 - FilterDisplayPrimary FilterDisplayHints = 1 << iota -) - -// FilterState represents the current state of a set of filters. -type FilterState map[string]interface{} - -type filterBase struct { - Id string - DisplayHints FilterDisplayHints - FilterType string - Title string -} - -func (f *filterBase) serializeFilter() map[string]interface{} { - v := map[string]interface{}{ - "filter_type": f.FilterType, - "id": f.Id, - "display_hints": f.DisplayHints, - } - if f.Title != "" { - v["title"] = f.Title - } - return v -} - -type filterWithOptions struct { - filterBase - Options []FilterOption -} - -// AddOption adds a new option to the filter. -func (f *filterWithOptions) AddOption(id, label string, defaultValue bool) { - f.Options = append(f.Options, FilterOption{ - Id: id, - Label: label, - Default: defaultValue, - }) -} - -func (f *filterWithOptions) isValidOption(optionId interface{}) bool { - for _, o := range f.Options { - if o.Id == optionId { - return true - } - } - return false -} - -// HasActiveOption returns true if any of the filters options are active. -func (f *filterWithOptions) HasActiveOption(state FilterState) bool { - for _, optionId := range f.ActiveOptions(state) { - if f.isValidOption(optionId) { - return true - } - } - return false -} - -// ActiveOptions returns the filter's active options from the filter state. -func (f *filterWithOptions) ActiveOptions(state FilterState) []string { - var ret []string - if state[f.Id] != nil { - options := state[f.Id].([]interface{}) - ret = make([]string, len(options)) - for i, opt := range options { - ret[i] = opt.(string) - } - } else { - // We don't have this filter in the state object, so - // give defaults back. - for _, o := range f.Options { - if o.Default { - ret = append(ret, o.Id) - } - } - } - return ret -} - -type FilterOption struct { - Id string `json:"id"` - Label string `json:"label"` - Default bool `json:"default"` -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/helpers.cpp b/vendor/launchpad.net/go-unityscopes/v2/helpers.cpp deleted file mode 100644 index 446fde3..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/helpers.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "helpers.h" - -#include <cstdlib> -#include <cstring> - -extern "C" { -#include "_cgo_export.h" -} - -namespace gounityscopes { -namespace internal { - -std::string from_gostring(const StrData str) { - return std::string(str.data, str.length); -} - -std::vector<std::string> split_strings(const StrData str) { - std::vector<std::string> list; - const char *s = str.data; - // str contains a sequence of nul-terminated strings concatenated together. - for (const char *p = str.data; p != str.data + str.length; ++p) { - if (*p == '\0') { - list.push_back(s); - s = p + 1; - } - } - return list; -} - -void *as_bytes(const std::string &str, int *length) { - *length = str.size(); - void *data = malloc(str.size()); - if (data == nullptr) { - return nullptr; - } - memcpy(data, str.data(), str.size()); - return data; -} - -} -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/helpers.go b/vendor/launchpad.net/go-unityscopes/v2/helpers.go deleted file mode 100644 index 9cb9d5c..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/helpers.go +++ /dev/null @@ -1,49 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "reflect" - "unsafe" -) - -// strData transforms a string to a form that can be passed to cgo -// without copying data. -func strData(s string) C.StrData { - h := (*reflect.StringHeader)(unsafe.Pointer(&s)) - return C.StrData{ - data: (*C.char)(unsafe.Pointer(h.Data)), - length: C.long(len(s)), - } -} - -// byteData transforms a byte array into the same format strData() produces. -func byteData(b []byte) C.StrData { - if len(b) == 0 { - return C.StrData{ - data: nil, - length: 0, - } - } - return C.StrData{ - data: (*C.char)(unsafe.Pointer(&b[0])), - length: C.long(len(b)), - } -} - - -func joinedStrData(a []string) C.StrData { - total := 0 - for _, s := range a { - total += len(s) + 1 - } - buf := make([]byte, total) - i := 0 - for _, s := range a { - copy(buf[i:i+len(s)], s) - buf[i+len(s)] = 0 - i += len(s) + 1 - } - return byteData(buf) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/helpers.h b/vendor/launchpad.net/go-unityscopes/v2/helpers.h deleted file mode 100644 index 5412f21..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/helpers.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef UNITYSCOPE_HELPERS_H -#define UNITYSCOPE_HELPERS_H - -#include <string> -#include <vector> - -typedef struct StrData StrData; - -namespace gounityscopes { -namespace internal { - -std::string from_gostring(const StrData str); -std::vector<std::string> split_strings(const StrData str); -void *as_bytes(const std::string &str, int *length); - -} -} - -#endif diff --git a/vendor/launchpad.net/go-unityscopes/v2/metadata.cpp b/vendor/launchpad.net/go-unityscopes/v2/metadata.cpp deleted file mode 100644 index 0a5451c..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/metadata.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include <stdexcept> -#include <cmath> -#include <cstring> - -#include <unity/scopes/ActionMetadata.h> -#include <unity/scopes/SearchMetadata.h> -#include <unity/scopes/ScopeMetadata.h> -#include <unity/scopes/ScopeExceptions.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -/* SearchMetadata objects */ -_SearchMetadata *new_search_metadata(int cardinality, const StrData locale, const StrData form_factor) { - return reinterpret_cast<_SearchMetadata*>(new SearchMetadata(cardinality, - from_gostring(locale), - from_gostring(form_factor))); -} - -void destroy_search_metadata(_SearchMetadata *metadata) { - delete reinterpret_cast<SearchMetadata*>(metadata); -} - -char *query_metadata_get_locale(_QueryMetadata *metadata) { - auto m = reinterpret_cast<QueryMetadata*>(metadata); - try { - return strdup(m->locale().c_str()); - } catch (const NotFoundException &) { - return nullptr; - } -} - -char *query_metadata_get_form_factor(_QueryMetadata *metadata) { - auto m = reinterpret_cast<QueryMetadata*>(metadata); - try { - return strdup(m->form_factor().c_str()); - } catch (const NotFoundException &) { - return nullptr; - } -} - -void query_metadata_set_internet_connectivity(_QueryMetadata *metadata, int status) { - reinterpret_cast<QueryMetadata*>(metadata)->set_internet_connectivity(static_cast<QueryMetadata::ConnectivityStatus>(status)); -} - -int query_metadata_get_internet_connectivity(_QueryMetadata *metadata) { - return static_cast<int>(reinterpret_cast<QueryMetadata*>(metadata)->internet_connectivity()); -} - -int search_metadata_get_cardinality(_SearchMetadata *metadata) { - return reinterpret_cast<SearchMetadata*>(metadata)->cardinality(); -} - -void *search_metadata_get_location(_SearchMetadata *metadata, int *length) { - auto m = reinterpret_cast<SearchMetadata*>(metadata); - VariantMap location; - try { - location = m->location().serialize(); - } catch (const NotFoundException &) { - return nullptr; - } - // libjsoncpp generates invalid JSON for NaN or Inf values, so - // filter them out here. - for (auto &pair : location) { - if (pair.second.which() == Variant::Double) { - double value = pair.second.get_double(); - if (!std::isfinite(value)) { - pair.second = Variant(); - } - } - } - return as_bytes(Variant(location).serialize_json(), length); -} - -void search_metadata_set_location(_SearchMetadata *metadata, char *json_data, int json_data_length, char **error) { - - try { - Variant value = Variant::deserialize_json(std::string(json_data, json_data_length)); - Location location(value.get_dict()); - reinterpret_cast<SearchMetadata*>(metadata)->set_location(location); - } catch (const std::exception & e) { - *error = strdup(e.what()); - } -} - -void search_metadata_set_aggregated_keywords(_SearchMetadata *metadata, const StrData keyword_list, char **error) { - try { - std::set<std::string> keywords; - for (auto &k : split_strings(keyword_list)) { - keywords.emplace(std::move(k)); - } - reinterpret_cast<SearchMetadata*>(metadata)->set_aggregated_keywords(keywords); - } catch (const std::exception & e) { - *error = strdup(e.what()); - } -} - -void *search_metadata_get_aggregated_keywords(_SearchMetadata *metadata, int *length) { - std::set<std::string> keywords = reinterpret_cast<SearchMetadata*>(metadata)->aggregated_keywords(); - // Marshal via JSON for now. This is probably faster than calling - // C.free() on each of a list of strings. - VariantArray array(keywords.begin(), keywords.end()); - return as_bytes(Variant(array).serialize_json(), length); -} - -int search_metadata_is_aggregated(_SearchMetadata *metadata) { - return reinterpret_cast<SearchMetadata*>(metadata)->is_aggregated(); -} - - -/* ActionMetadata objects */ -_ActionMetadata *new_action_metadata(const StrData locale, const StrData form_factor) { - return reinterpret_cast<_ActionMetadata*>(new ActionMetadata(from_gostring(locale), - from_gostring(form_factor))); -} - -void destroy_action_metadata(_ActionMetadata *metadata) { - delete reinterpret_cast<ActionMetadata*>(metadata); -} - -void *action_metadata_get_scope_data(_ActionMetadata *metadata, int *data_length) { - const std::string data = reinterpret_cast<ActionMetadata*>(metadata)->scope_data().serialize_json(); - return as_bytes(data, data_length); -} - -void action_metadata_set_scope_data(_ActionMetadata *metadata, char *json_data, int json_data_length, char **error) { - try { - Variant value = Variant::deserialize_json(std::string(json_data, json_data_length)); - reinterpret_cast<ActionMetadata*>(metadata)->set_scope_data(value); - } catch (const std::exception & e) { - *error = strdup(e.what()); - } -} - -void action_metadata_set_hint(_ActionMetadata *metadata, const StrData key, char *json_data, int json_data_length, char **error) { - try { - Variant value = Variant::deserialize_json(std::string(json_data, json_data_length)); - reinterpret_cast<ActionMetadata*>(metadata)->set_hint(from_gostring(key), value); - } catch (const std::exception & e) { - *error = strdup(e.what()); - } -} - -void *action_metadata_get_hint(_ActionMetadata *metadata, const StrData key, int *data_length, char **error) { - try { - ActionMetadata const*api_metadata = reinterpret_cast<ActionMetadata const*>(metadata); - Variant value = (*api_metadata)[from_gostring(key)]; - const std::string data = value.serialize_json(); - return as_bytes(data, data_length); - } catch (const std::exception & e) { - *data_length = 0; - *error = strdup(e.what()); - return 0; - } -} - -void *action_metadata_get_hints(_ActionMetadata *metadata, int *length) { - VariantMap hints = reinterpret_cast<ActionMetadata const*>(metadata)->hints(); - // libjsoncpp generates invalid JSON for NaN or Inf values, so - // filter them out here. - for (auto &pair : hints) { - if (pair.second.which() == Variant::Double) { - double value = pair.second.get_double(); - if (!std::isfinite(value)) { - pair.second = Variant(); - } - } - } - return as_bytes(Variant(hints).serialize_json(), length); -} - -char *get_scope_metadata_serialized(_ScopeMetadata *metadata) { - ScopeMetadata const*api_metadata = reinterpret_cast<ScopeMetadata const*>(metadata); - return strdup(Variant(api_metadata->serialize()).serialize_json().c_str()); -} - -void destroy_scope_metadata_ptr(_ScopeMetadata *metadata) { - delete reinterpret_cast<ScopeMetadata*>(metadata); -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/metadata.go b/vendor/launchpad.net/go-unityscopes/v2/metadata.go deleted file mode 100644 index 1da9b7c..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/metadata.go +++ /dev/null @@ -1,309 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "fmt" - "runtime" - "unsafe" -) - -type ConnectivityStatus int - -const ( - ConnectivityStatusUnknown ConnectivityStatus = 0 - ConnectivityStatusConnected ConnectivityStatus = 1 - ConnectivityStatusDisconnected ConnectivityStatus = 2 -) - -// queryMetadata is the base class for extra metadata passed to scopes as a part of a request. -// This base class is not exported -type queryMetadata struct { - m *C._QueryMetadata -} - -// Locale returns the expected locale for the search request. -func (metadata *queryMetadata) Locale() string { - locale := C.query_metadata_get_locale(metadata.m) - defer C.free(unsafe.Pointer(locale)) - return C.GoString(locale) -} - -// FormFactor returns the form factor for the search request. -func (metadata *queryMetadata) FormFactor() string { - formFactor := C.query_metadata_get_form_factor(metadata.m) - defer C.free(unsafe.Pointer(formFactor)) - return C.GoString(formFactor) -} - -// SetInternetConnectivity indicates the internet connectivity status. -func (metadata *queryMetadata) SetInternetConnectivity(status ConnectivityStatus) { - C.query_metadata_set_internet_connectivity(metadata.m, C.int(status)) -} - -// InternetConnectivity gets internet connectivity status. -func (metadata *queryMetadata) InternetConnectivity() ConnectivityStatus { - return ConnectivityStatus(C.query_metadata_get_internet_connectivity(metadata.m)) -} - -// SearchMetadata holds additional metadata about the search request. -type SearchMetadata struct { - queryMetadata -} - -func finalizeSearchMetadata(metadata *SearchMetadata) { - if metadata.m != nil { - C.destroy_search_metadata((*C._SearchMetadata)(metadata.m)) - } - metadata.m = nil -} - -func makeSearchMetadata(m *C._SearchMetadata) *SearchMetadata { - metadata := new(SearchMetadata) - runtime.SetFinalizer(metadata, finalizeSearchMetadata) - metadata.m = (*C._QueryMetadata)(m) - return metadata -} - -// NewSearchMetadata creates a new SearchMetadata with the given locale and -// form_factor -func NewSearchMetadata(cardinality int, locale, form_factor string) *SearchMetadata { - return makeSearchMetadata(C.new_search_metadata(C.int(cardinality), - strData(locale), - strData(form_factor))) -} - -// Cardinality returns the desired number of results for the search request. -func (metadata *SearchMetadata) Cardinality() int { - return int(C.search_metadata_get_cardinality((*C._SearchMetadata)(metadata.m))) -} - -type Location struct { - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - Altitude float64 `json:"altitude"` - AreaCode string `json:"area_code"` - City string `json:"city"` - CountryCode string `json:"country_code"` - CountryName string `json:"country_name"` - HorizontalAccuracy float64 `json:"horizontal_accuracy"` - VerticalAccuracy float64 `json:"vertical_accuracy"` - RegionCode string `json:"region_code"` - RegionName string `json:"region_name"` - ZipPostalCode string `json:"zip_postal_code"` -} - -func (metadata *SearchMetadata) Location() *Location { - var length C.int - locData := C.search_metadata_get_location((*C._SearchMetadata)(metadata.m), &length) - if locData == nil { - return nil - } - defer C.free(locData) - var location Location - if err := json.Unmarshal(C.GoBytes(locData, length), &location); err != nil { - panic(err) - } - return &location -} - -// SetLocation sets the location -func (metadata *SearchMetadata) SetLocation(l *Location) error { - location := locationMarshal{marshalFloat(l.Latitude), - marshalFloat(l.Longitude), - marshalFloat(l.Altitude), - l.AreaCode, - l.City, - l.CountryCode, - l.CountryName, - marshalFloat(l.HorizontalAccuracy), - marshalFloat(l.VerticalAccuracy), - l.RegionCode, - l.RegionName, - l.ZipPostalCode} - data, err := json.Marshal(location) - if err != nil { - return err - } - var errorString *C.char - C.search_metadata_set_location((*C._SearchMetadata)(metadata.m), (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)), &errorString) - return checkError(errorString) -} - -func (metadata *SearchMetadata) SetAggregatedKeywords(keywords []string) error { - var errorString *C.char - C.search_metadata_set_aggregated_keywords((*C._SearchMetadata)(metadata.m), joinedStrData(keywords), &errorString) - return checkError(errorString) -} - -func (metadata *SearchMetadata) AggregatedKeywords() []string { - var length C.int - keywordData := C.search_metadata_get_aggregated_keywords((*C._SearchMetadata)(metadata.m), &length) - var keywords []string - if err := json.Unmarshal(C.GoBytes(keywordData, length), &keywords); err != nil { - panic(err) - } - return keywords -} - -func (metadata *SearchMetadata) IsAggregated() bool { - if C.search_metadata_is_aggregated((*C._SearchMetadata)(metadata.m)) == 0 { - return false - } - return true -} - -// ActionMetadata holds additional metadata about the preview request -// or result activation. -type ActionMetadata struct { - queryMetadata -} - -func finalizeActionMetadata(metadata *ActionMetadata) { - if metadata.m != nil { - C.destroy_action_metadata((*C._ActionMetadata)(metadata.m)) - } - metadata.m = nil -} - -// NewActionMetadata creates a new ActionMetadata with the given locale and -// form_factor -func NewActionMetadata(locale, form_factor string) *ActionMetadata { - return makeActionMetadata(C.new_action_metadata(strData(locale), - strData(form_factor))) -} - -func makeActionMetadata(m *C._ActionMetadata) *ActionMetadata { - metadata := new(ActionMetadata) - runtime.SetFinalizer(metadata, finalizeActionMetadata) - metadata.m = (*C._QueryMetadata)(m) - return metadata -} - -// ScopeData decodes the stored scope data into the given variable. -// -// Scope data is either set by the shell when calling a preview -// action, or set by the scope through an ActivationResponse object. -func (metadata *ActionMetadata) ScopeData(v interface{}) error { - var dataLength C.int - scopeData := C.action_metadata_get_scope_data((*C._ActionMetadata)(metadata.m), &dataLength) - defer C.free(scopeData) - return json.Unmarshal(C.GoBytes(scopeData, dataLength), v) -} - -// SetScopeData attaches arbitrary data to this ActionMetadata. -func (metadata *ActionMetadata) SetScopeData(v interface{}) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - var errorString *C.char - C.action_metadata_set_scope_data((*C._ActionMetadata)(metadata.m), (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)), &errorString) - return checkError(errorString) -} - -// SetHint sets a hint. -func (metadata *ActionMetadata) SetHint(key string, value interface{}) error { - data, err := json.Marshal(value) - if err != nil { - return err - } - var errorString *C.char - C.action_metadata_set_hint((*C._ActionMetadata)(metadata.m), strData(key), (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)), &errorString) - return checkError(errorString) -} - -// Hint returns a hint. -// Returns error if the hint does not exist or if we got an error unmarshaling -func (metadata *ActionMetadata) Hint(key string, value interface{}) error { - var dataLength C.int - var errorString *C.char - scopeData := C.action_metadata_get_hint((*C._ActionMetadata)(metadata.m), strData(key), &dataLength, &errorString) - if dataLength > 0 && errorString == nil { - defer C.free(scopeData) - return json.Unmarshal(C.GoBytes(scopeData, dataLength), value) - } else { - return checkError(errorString) - } -} - -// Hints gets all hints. -func (metadata *ActionMetadata) Hints(value interface{}) error { - var length C.int - data := C.action_metadata_get_hints((*C._ActionMetadata)(metadata.m), &length) - if data == nil { - return nil - } - defer C.free(data) - return json.Unmarshal(C.GoBytes(data, length), value) -} - -// we use this type to reimplement the marshaller interface in order to make values -// like 1.0 not being converted as 1 (integer). -type marshalFloat float64 - -func (n marshalFloat) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf("%f", n)), nil -} - -// the following structure is only used to control how the float64 types are -// marshaled. It is not exported. -type locationMarshal struct { - Latitude marshalFloat `json:"latitude"` - Longitude marshalFloat `json:"longitude"` - Altitude marshalFloat `json:"altitude"` - AreaCode string `json:"area_code"` - City string `json:"city"` - CountryCode string `json:"country_code"` - CountryName string `json:"country_name"` - HorizontalAccuracy marshalFloat `json:"horizontal_accuracy"` - VerticalAccuracy marshalFloat `json:"vertical_accuracy"` - RegionCode string `json:"region_code"` - RegionName string `json:"region_name"` - ZipPostalCode string `json:"zip_postal_code"` -} - -type ProxyScopeMetadata struct { - Identity string `json:"identity"` - EndPoint string `json:"endpoint"` -} - -// ScopeMetadata holds scope attributes such as name, description, icon etc. -// -// The information stored by ScopeMetadata comes from the .ini file for the given scope (for local scopes) -// or is fetched from the remote server (for scopes running on Smart Scopes Server). -// Use ListRegistryScopes from ScopeBase to get the metadata for all scopes. -type ScopeMetadata struct { - m *C._ScopeMetadata - Art string `json:"art"` - Author string `json:"author"` - Description string `json:"description"` - DisplayName string `json:"display_name"` - Icon string `json:"icon"` - Invisible bool `json:"invisible"` - IsAggregator bool `json:"is_aggregator"` - LocationDataNeeded bool `json:"location_data_needed"` - ScopeDir string `json:"scope_dir"` - ScopeId string `json:"scope_id"` - Version int `json:"version"` - Proxy ProxyScopeMetadata `json:"proxy"` - AppearanceAttributes map[string]interface{} `json:"appearance_attributes"` - SettingsDefinitions []interface{} `json:"settings_definitions"` - Keywords []string `json:"keywords"` -} - -func finalizeScopeMetadata(metadata *ScopeMetadata) { - C.destroy_scope_metadata_ptr(metadata.m) -} - -func makeScopeMetadata(m *C._ScopeMetadata, json_data string) *ScopeMetadata { - metadata := new(ScopeMetadata) - if err := json.Unmarshal([]byte(json_data), &metadata); err != nil { - panic(err) - } - metadata.m = m - runtime.SetFinalizer(metadata, finalizeScopeMetadata) - return metadata -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/metadata_test.go b/vendor/launchpad.net/go-unityscopes/v2/metadata_test.go deleted file mode 100644 index 3e7f9d2..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/metadata_test.go +++ /dev/null @@ -1,175 +0,0 @@ -package scopes_test - -import ( - "sort" - - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestMetadataBasic(c *C) { - metadata := scopes.NewSearchMetadata(2, "us", "phone") - - // basic check - c.Check(metadata.Locale(), Equals, "us") - c.Check(metadata.FormFactor(), Equals, "phone") - c.Check(metadata.Cardinality(), Equals, 2) - c.Check(metadata.Location(), IsNil) - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusUnknown) - metadata.SetInternetConnectivity(scopes.ConnectivityStatusConnected) - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusConnected) - metadata.SetInternetConnectivity(scopes.ConnectivityStatusDisconnected) - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusDisconnected) -} - -func (s *S) TestSetLocation(c *C) { - metadata := scopes.NewSearchMetadata(2, "us", "phone") - location := scopes.Location{1.1, 2.1, 0.0, "EU", "Barcelona", "es", "Spain", 1.1, 1.1, "BCN", "BCN", "08080"} - - // basic check - c.Check(metadata.Location(), IsNil) - - // set the location - err := metadata.SetLocation(&location) - c.Check(err, IsNil) - - stored_location := metadata.Location() - c.Assert(stored_location, Not(Equals), nil) - // this test need version 0.6.15 of libunity-scopes - //c.Check(stored_location, DeepEquals, &location) -} - -func (s *S) TestSearchMetadataAgregatorKeywords(c *C) { - metadata := scopes.NewSearchMetadata(2, "us", "phone") - - c.Check(metadata.AggregatedKeywords(), DeepEquals, []string{}) - c.Check(metadata.IsAggregated(), Equals, false) - - c.Check(metadata.SetAggregatedKeywords([]string{"one", "two"}), IsNil) - keywords := metadata.AggregatedKeywords() - sort.Strings(keywords) - c.Check(keywords, DeepEquals, []string{"one", "two"}) - c.Check(metadata.IsAggregated(), Equals, true) -} - -func (s *S) TestActionMetadata(c *C) { - metadata := scopes.NewActionMetadata("us", "phone") - - // basic check - c.Check(metadata.Locale(), Equals, "us") - c.Check(metadata.FormFactor(), Equals, "phone") - - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusUnknown) - metadata.SetInternetConnectivity(scopes.ConnectivityStatusConnected) - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusConnected) - metadata.SetInternetConnectivity(scopes.ConnectivityStatusDisconnected) - c.Check(metadata.InternetConnectivity(), Equals, scopes.ConnectivityStatusDisconnected) - - var scope_data interface{} - metadata.ScopeData(&scope_data) - c.Check(scope_data, IsNil) - - err := metadata.SetScopeData([]string{"test1", "test2", "test3"}) - c.Check(err, IsNil) - - err = metadata.ScopeData(&scope_data) - c.Check(err, IsNil) - c.Check(scope_data, DeepEquals, []interface{}{"test1", "test2", "test3"}) - - // try to pass a non-pointer object - var errorJsonUnserialize unserializable - err = metadata.ScopeData(errorJsonUnserialize) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "json: Unmarshal(non-pointer scopes_test.unserializable)") - - // try to use an unserializable object - // We should get an error - err = metadata.ScopeData(&errorJsonUnserialize) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "Can not unmarshal from JSON") -} - -func (s *S) TestActionMetadataHints(c *C) { - metadata := scopes.NewActionMetadata("us", "phone") - - var value interface{} - - // we still have no hints - err := metadata.Hints(&value) - c.Check(err, IsNil) - c.Check(value, DeepEquals, map[string]interface{}{}) - - err = metadata.SetHint("test_1", "value_1") - c.Check(err, IsNil) - - err = metadata.Hint("test_1", &value) - c.Check(err, IsNil) - c.Check(value, Equals, "value_1") - - err = metadata.Hint("test_1_not_exists", &value) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "unity::LogicException: QueryMetadataImpl::hint(): requested key test_1_not_exists doesn't exist") - - err = metadata.Hints(&value) - expected_results := make(map[string]interface{}) - expected_results["test_1"] = "value_1" - c.Check(expected_results, DeepEquals, value) - - err = metadata.SetHint("test_2", "value_2") - c.Check(err, IsNil) - - expected_results["test_2"] = "value_2" - err = metadata.Hints(&value) - c.Check(err, IsNil) - c.Check(expected_results, DeepEquals, value) - - err = metadata.SetHint("test_3", []interface{}{"value_3_1", "value_3_2"}) - c.Check(err, IsNil) - - expected_results["test_3"] = []interface{}{"value_3_1", "value_3_2"} - err = metadata.Hints(&value) - c.Check(err, IsNil) - c.Check(expected_results, DeepEquals, value) - - // pass non-pointer - var errorJsonUnserialize unserializable - err = metadata.Hints(errorJsonUnserialize) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "json: Unmarshal(non-pointer scopes_test.unserializable)") - - // pass non-serializable object - err = metadata.Hints(&errorJsonUnserialize) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "Can not unmarshal from JSON") - - err = metadata.SetHint("bad_hint", &errorJsonUnserialize) - c.Assert(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "json: error calling MarshalJSON for type *scopes_test.unserializable: Can not marshal to JSON") -} - -func (s *S) TestScopeMetadataCreation(c *C) { - json_data := "{\"appearance_attributes\":{\"page-header\":{\"background\":\"color:///#ffffff\",\"divider-color\":\"#b31217\",\"logo\":\"unity-scope-youtube/build/src/logo.png\"}},\"art\":\"unity-scope-youtube/build/src/screenshot.jpg\",\"author\":\"Canonical Ltd.\",\"description\":\"Search YouTube for videos and browse channels\",\"display_name\":\"YouTube\",\"icon\":\"unity-scope-youtube/build/src/icon.png\",\"invisible\":false,\"is_aggregator\":false,\"location_data_needed\":true,\"proxy\":{\"endpoint\":\"ipc:///tmp/scope-dev-endpoints.V4gbrE/priv/com.ubuntu.scopes.youtube_youtube\",\"identity\":\"com.ubuntu.scopes.youtube_youtube\"},\"scope_dir\":\"unity-scope-youtube/build/src\",\"scope_id\":\"com.ubuntu.scopes.youtube_youtube\",\"settings_definitions\":[{\"defaultValue\":true,\"displayName\":\"Enable location data\",\"id\":\"internal.location\",\"type\":\"boolean\"}],\"version\":0,\"keywords\":[\"music\",\"video\"]}" - - scopeMetadata := scopes.NewTestingScopeMetadata(json_data) - c.Assert(scopeMetadata, Not(Equals), nil) - - c.Check(scopeMetadata.Art, Equals, "unity-scope-youtube/build/src/screenshot.jpg") - c.Check(scopeMetadata.Author, Equals, "Canonical Ltd.") - c.Check(scopeMetadata.Description, Equals, "Search YouTube for videos and browse channels") - c.Check(scopeMetadata.DisplayName, Equals, "YouTube") - c.Check(scopeMetadata.Icon, Equals, "unity-scope-youtube/build/src/icon.png") - c.Check(scopeMetadata.Invisible, Equals, false) - c.Check(scopeMetadata.IsAggregator, Equals, false) - c.Check(scopeMetadata.LocationDataNeeded, Equals, true) - c.Check(scopeMetadata.ScopeDir, Equals, "unity-scope-youtube/build/src") - c.Check(scopeMetadata.ScopeId, Equals, "com.ubuntu.scopes.youtube_youtube") - c.Check(scopeMetadata.Version, Equals, 0) - c.Check(scopeMetadata.Proxy, Equals, scopes.ProxyScopeMetadata{"com.ubuntu.scopes.youtube_youtube", "ipc:///tmp/scope-dev-endpoints.V4gbrE/priv/com.ubuntu.scopes.youtube_youtube"}) - pageHeader, ok := scopeMetadata.AppearanceAttributes["page-header"].(map[string]interface{}) - c.Check(ok, Equals, true) - c.Check(pageHeader["background"], Equals, "color:///#ffffff") - c.Check(pageHeader["divider-color"], Equals, "#b31217") - c.Check(pageHeader["logo"], Equals, "unity-scope-youtube/build/src/logo.png") - - c.Check(scopeMetadata.Keywords, DeepEquals, []string{"music", "video"}) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter.go b/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter.go deleted file mode 100644 index 37f28d1..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter.go +++ /dev/null @@ -1,79 +0,0 @@ -package scopes - -import ( - "sort" -) - -// OptionSelectorFilter is used to implement single-select or multi-select filters. -type OptionSelectorFilter struct { - filterWithOptions - Label string - MultiSelect bool -} - -// NewOptionSelectorFilter creates a new option filter. -func NewOptionSelectorFilter(id, label string, multiSelect bool) *OptionSelectorFilter { - return &OptionSelectorFilter{ - filterWithOptions: filterWithOptions{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "option_selector", - }, - }, - Label: label, - MultiSelect: multiSelect, - } -} - -type optionSort struct { - Options []interface{} -} - -func (s optionSort) Len() int { - return len(s.Options) -} - -func (s optionSort) Less(i, j int) bool { - return s.Options[i].(string) < s.Options[j].(string) -} - -func (s optionSort) Swap(i, j int) { - s.Options[i], s.Options[j] = s.Options[j], s.Options[i] -} - -// UpdateState updates the value of a particular option in the filter state. -func (f *OptionSelectorFilter) UpdateState(state FilterState, optionId string, active bool) { - if !f.isValidOption(optionId) { - panic("invalid option ID") - } - // For single-select filters, clear the previous state when - // setting a new active option. - if active && !f.MultiSelect { - delete(state, f.Id) - } - // If the state isn't in a form we expect, treat it as empty - selected, _ := state[f.Id].([]interface{}) - sort.Sort(optionSort{selected}) - pos := sort.Search(len(selected), func(i int) bool { return selected[i].(string) >= optionId }) - if active { - if pos == len(selected) { - selected = append(selected, optionId) - } else if pos < len(selected) && selected[pos] != optionId { - selected = append(selected[:pos], append([]interface{}{optionId}, selected[pos:]...)...) - } - } else { - if pos < len(selected) { - selected = append(selected[:pos], selected[pos+1:]...) - } - } - state[f.Id] = selected -} - -func (f *OptionSelectorFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["label"] = f.Label - v["multi_select"] = f.MultiSelect - v["options"] = f.Options - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter_test.go deleted file mode 100644 index 55b11ec..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/option_selector_filter_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestOptionSelectorFilter(c *C) { - filter1 := scopes.NewOptionSelectorFilter("f1", "Options", false) - c.Check("f1", Equals, filter1.Id) - c.Check("Options", Equals, filter1.Label) - c.Check(filter1.MultiSelect, Equals, false) - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayDefault) - - filter1.DisplayHints = scopes.FilterDisplayPrimary - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayPrimary) - c.Check(2, Equals, len(filter1.Options)) - c.Check("1", Equals, filter1.Options[0].Id) - c.Check("Option 1", Equals, filter1.Options[0].Label) - c.Check("2", Equals, filter1.Options[1].Id) - c.Check("Option 2", Equals, filter1.Options[1].Label) - - // verify the list of options - c.Check(len(filter1.Options), Equals, 2) - c.Check(filter1.Options, DeepEquals, []scopes.FilterOption{scopes.FilterOption{"1", "Option 1", false}, scopes.FilterOption{"2", "Option 2", false}}) -} - -func (s *S) TestOptionSelectorFilterSingleSelection(c *C) { - filter1 := scopes.NewOptionSelectorFilter("f1", "Options", false) - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - - fstate := make(scopes.FilterState) - _, ok := fstate["f1"] - c.Check(ok, Equals, false) - c.Check(filter1.HasActiveOption(fstate), Equals, false) - - // enable option1 - filter1.UpdateState(fstate, "1", true) - _, ok = fstate["f1"] - c.Check(ok, Equals, true) - c.Check(filter1.HasActiveOption(fstate), Equals, true) - - active := filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active, DeepEquals, []string{"1"}) - - // enable option2, option1 get disabled - filter1.UpdateState(fstate, "2", true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active, DeepEquals, []string{"2"}) - - // disable option1; filter state remains in the FilterState, just no options are selected - filter1.UpdateState(fstate, "2", false) - _, ok = fstate["f1"] - c.Check(ok, Equals, true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 0) -} - -func (s *S) TestOptionSelectorFilterMultiSelection(c *C) { - filter1 := scopes.NewOptionSelectorFilter("f1", "Options", true) - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - - // enable option1 & option2 - filter1.UpdateState(fstate, "1", true) - filter1.UpdateState(fstate, "2", true) - _, ok := fstate["f1"] - c.Check(ok, Equals, true) - - c.Check(filter1.HasActiveOption(fstate), Equals, true) - active := filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"1", "2"}) - - // disable option1 - filter1.UpdateState(fstate, "1", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active[0], Equals, "2") - - // disable option2 - filter1.UpdateState(fstate, "2", false) - c.Check(0, Equals, len(filter1.ActiveOptions(fstate))) - - filter1.UpdateState(fstate, "3", true) - filter1.UpdateState(fstate, "1", true) - - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"1", "3"}) - - // add existing item - filter1.UpdateState(fstate, "1", true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"1", "3"}) - - // add in the middle - filter1.UpdateState(fstate, "2", true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 3) - c.Check(active, DeepEquals, []string{"1", "2", "3"}) - - // erase in the middle - filter1.UpdateState(fstate, "2", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"1", "3"}) - - filter1.UpdateState(fstate, "2", true) - - // erase at the beginning - filter1.UpdateState(fstate, "1", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"2", "3"}) - - filter1.UpdateState(fstate, "1", true) - - // erase at the end - filter1.UpdateState(fstate, "3", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 2) - c.Check(active, DeepEquals, []string{"1", "2"}) - - filter1.UpdateState(fstate, "1", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active, DeepEquals, []string{"2"}) - - filter1.UpdateState(fstate, "2", false) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 0) -} - -func (s *S) TestOptionSelectorFilterBadOption(c *C) { - filter1 := scopes.NewOptionSelectorFilter("f1", "Options", true) - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - - c.Assert(func() { filter1.UpdateState(fstate, "5", true) }, PanicMatches, "invalid option ID") - c.Assert(func() { filter1.UpdateState(fstate, "5", false) }, PanicMatches, "invalid option ID") -} - -func (s *S) TestOptionSelectorFilterDefaultValue(c *C) { - filter := scopes.NewOptionSelectorFilter("f1", "Options", true) - filter.AddOption("1", "Option 1", false) - filter.AddOption("2", "Option 2", true) - filter.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - c.Check(filter.HasActiveOption(fstate), Equals, true) - c.Check(filter.ActiveOptions(fstate), DeepEquals, []string{"2"}) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/previewwidget.go b/vendor/launchpad.net/go-unityscopes/v2/previewwidget.go deleted file mode 100644 index 96e0afe..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/previewwidget.go +++ /dev/null @@ -1,64 +0,0 @@ -package scopes - -import ( - "encoding/json" -) - -type PreviewWidget map[string]interface{} - -/* -NewPreviewWidget creates a preview widget with the given name and type. - -Widget type specific attributes can be set directly with -AddAttributeValue(), or mapped to result attributes with -AddAttributeMapping(). - -A list of available widget types and their associated attributes is -available here: - -http://developer.ubuntu.com/api/scopes/sdk-14.10/previewwidgets/ -*/ -func NewPreviewWidget(id, widgetType string) PreviewWidget { - return PreviewWidget{"id": id, "type": widgetType} -} - -// Id returns the name of this widget. -func (widget PreviewWidget) Id() string { - return widget["id"].(string) -} - -// WidgetType returns the type of this widget. -func (widget PreviewWidget) WidgetType() string { - return widget["type"].(string) -} - -// AddAttributeValue sets a widget attribute to a particular value. -func (widget PreviewWidget) AddAttributeValue(key string, value interface{}) { - widget[key] = value -} - -// AddAttributeMapping maps a widget attribute to a named result attribute. -func (widget PreviewWidget) AddAttributeMapping(key, fieldName string) { - var components map[string]interface{} - if comp, ok := widget["components"]; ok { - components = comp.(map[string]interface{}) - } else { - components = make(map[string]interface{}) - widget["components"] = components - } - components[key] = fieldName -} - -// AddWidget adds a child widget to this widget. -// This only makes sense for expandable type widgets. -func (widget PreviewWidget) AddWidget(child PreviewWidget) { - if widget.WidgetType() != "expandable" { - panic("Can only add widgets to expandable type widgets") - } - subwidgets, _ := widget["widgets"].([]PreviewWidget) - widget["widgets"] = append(subwidgets, child) -} - -func (widget PreviewWidget) data() ([]byte, error) { - return json.Marshal(widget) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/previewwidget_test.go b/vendor/launchpad.net/go-unityscopes/v2/previewwidget_test.go deleted file mode 100644 index 4783893..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/previewwidget_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestPreviewWidget(c *C) { - widget := scopes.NewPreviewWidget("widget_id", "widget_type") - c.Check(widget.Id(), Equals, "widget_id") - c.Check(widget.WidgetType(), Equals, "widget_type") - - _, ok := widget["attr_id"] - c.Check(ok, Equals, false) - widget.AddAttributeValue("attr_id", "attr_value") - - value, ok := widget["attr_id"] - c.Check(ok, Equals, true) - c.Check(value, Equals, "attr_value") - - // set complex value - widget.AddAttributeValue("attr_slice", []string{"test1", "test2", "test3"}) - value, ok = widget["attr_slice"] - c.Check(ok, Equals, true) - c.Check(value, DeepEquals, []string{"test1", "test2", "test3"}) - - // attribute mapping - - _, ok = widget["components"] - c.Check(ok, Equals, false) - widget.AddAttributeMapping("map_key", "mapping_value") - - value, ok = widget["components"] - c.Check(ok, Equals, true) - - components := value.(map[string]interface{}) - - _, ok = components["map_key_error"] - c.Check(ok, Equals, false) - - value, ok = components["map_key"] - c.Check(ok, Equals, true) - c.Check(value, Equals, "mapping_value") - - // add nother mapping - widget.AddAttributeMapping("map_key_2", "mapping_value_2") - value, ok = widget["components"] - c.Check(ok, Equals, true) - components = value.(map[string]interface{}) - - value, ok = components["map_key"] - c.Check(ok, Equals, true) - c.Check(value, Equals, "mapping_value") - - value, ok = components["map_key_2"] - c.Check(ok, Equals, true) - c.Check(value, Equals, "mapping_value_2") -} - -func (s *S) TestPreviewWidgetAddWidgets(c *C) { - widget := scopes.NewPreviewWidget("widget_id", "widget_type") - c.Check(widget.Id(), Equals, "widget_id") - c.Check(widget.WidgetType(), Equals, "widget_type") - - sub_widget_1 := scopes.NewPreviewWidget("widget1", "expandable") - - // check panic error when adding widget to non expandable - c.Assert(func() { widget.AddWidget(sub_widget_1) }, PanicMatches, "Can only add widgets to expandable type widgets") - - // check it does not have subwidgets - _, ok := sub_widget_1["widgets"] - c.Check(ok, Equals, false) - - sub_widget_11 := scopes.NewPreviewWidget("widget11", "audio") - sub_widget_12 := scopes.NewPreviewWidget("widget12", "video") - - sub_widget_1.AddWidget(sub_widget_11) - // now it does have widgets - widgets, ok := sub_widget_1["widgets"] - c.Check(ok, Equals, true) - c.Check(widgets, DeepEquals, []scopes.PreviewWidget{sub_widget_11}) - - sub_widget_1.AddWidget(sub_widget_12) - widgets, ok = sub_widget_1["widgets"] - c.Check(ok, Equals, true) - c.Check(widgets, DeepEquals, []scopes.PreviewWidget{sub_widget_11, sub_widget_12}) - - main_widget := scopes.NewPreviewWidget("main_widget_id", "expandable") - // check it does not have subwidgets - _, ok = main_widget["widgets"] - c.Check(ok, Equals, false) - - main_widget.AddWidget(sub_widget_1) - widgets, ok = main_widget["widgets"] - c.Check(ok, Equals, true) - c.Check(widgets, DeepEquals, []scopes.PreviewWidget{sub_widget_1}) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/query.cpp b/vendor/launchpad.net/go-unityscopes/v2/query.cpp deleted file mode 100644 index 1083d45..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/query.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include <stdexcept> -#include <cstring> - -#include <unity/scopes/CannedQuery.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -void destroy_canned_query(_CannedQuery *query) { - delete reinterpret_cast<CannedQuery*>(query); -} - -_CannedQuery *new_canned_query(const StrData scope_id, const StrData query_str, const StrData department_id) { - return reinterpret_cast<_CannedQuery*>( - new CannedQuery(from_gostring(scope_id), - from_gostring(query_str), - from_gostring(department_id))); -} - -char *canned_query_get_scope_id(_CannedQuery *query) { - return strdup(reinterpret_cast<CannedQuery*>(query)->scope_id().c_str()); -} - -char *canned_query_get_department_id(_CannedQuery *query) { - return strdup(reinterpret_cast<CannedQuery*>(query)->department_id().c_str()); -} - -void *canned_query_get_filter_state(_CannedQuery *query, int *length) { - std::string json_data; - try { - Variant v(reinterpret_cast<CannedQuery*>(query)->filter_state().serialize()); - json_data = v.serialize_json(); - } catch (...) { - return nullptr; - } - return as_bytes(json_data, length); -} - -char *canned_query_get_query_string(_CannedQuery *query) { - return strdup(reinterpret_cast<CannedQuery*>(query)->query_string().c_str()); -} - -void canned_query_set_department_id(_CannedQuery *query, const StrData department_id) { - reinterpret_cast<CannedQuery*>(query)->set_department_id(from_gostring(department_id)); -} - -void canned_query_set_query_string(_CannedQuery *query, const StrData query_str) { - reinterpret_cast<CannedQuery*>(query)->set_query_string(from_gostring(query_str)); -} - -char *canned_query_to_uri(_CannedQuery *query) { - return strdup(reinterpret_cast<CannedQuery*>(query)->to_uri().c_str()); -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/query.go b/vendor/launchpad.net/go-unityscopes/v2/query.go deleted file mode 100644 index c66161e..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/query.go +++ /dev/null @@ -1,88 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "runtime" - "unsafe" -) - -// CannedQuery represents a search query from the user. -type CannedQuery struct { - q *C._CannedQuery -} - -func finalizeCannedQuery(query *CannedQuery) { - if query.q != nil { - C.destroy_canned_query(query.q) - } - query.q = nil -} - -func makeCannedQuery(q *C._CannedQuery) *CannedQuery { - query := new(CannedQuery) - runtime.SetFinalizer(query, finalizeCannedQuery) - query.q = q - return query -} - -// NewCannedQuery creates a new CannedQuery with the given scope ID, -// query string and department ID. -func NewCannedQuery(scopeID, queryString, departmentID string) *CannedQuery { - return makeCannedQuery(C.new_canned_query( - strData(scopeID), - strData(queryString), - strData(departmentID))) -} - -// ScopeID returns the scope ID for this canned query. -func (query *CannedQuery) ScopeID() string { - s := C.canned_query_get_scope_id(query.q) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// DepartmentID returns the department ID for this canned query. -func (query *CannedQuery) DepartmentID() string { - s := C.canned_query_get_department_id(query.q) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// QueryString returns the query string for this canned query. -func (query *CannedQuery) QueryString() string { - s := C.canned_query_get_query_string(query.q) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} - -// FilterState returns the state of the filters for this canned query. -func (query *CannedQuery) FilterState() FilterState { - var length C.int - s := C.canned_query_get_filter_state(query.q, &length) - defer C.free(s) - var state FilterState - if err := json.Unmarshal(C.GoBytes(s, length), &state); err != nil { - panic(err) - } - return state -} - -// SetDepartmentID changes the department ID for this canned query. -func (query *CannedQuery) SetDepartmentID(departmentID string) { - C.canned_query_set_department_id(query.q, strData(departmentID)) -} - -// SetQueryString changes the query string for this canned query. -func (query *CannedQuery) SetQueryString(queryString string) { - C.canned_query_set_query_string(query.q, strData(queryString)) -} - -// ToURI formats the canned query as a URI. -func (query *CannedQuery) ToURI() string { - s := C.canned_query_to_uri(query.q) - defer C.free(unsafe.Pointer(s)) - return C.GoString(s) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/query_test.go b/vendor/launchpad.net/go-unityscopes/v2/query_test.go deleted file mode 100644 index bee6622..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/query_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestQuery(c *C) { - query := scopes.NewCannedQuery("scope", "query_string", "department_string") - - // basic check - c.Check(query.ScopeID(), Equals, "scope") - c.Check(query.DepartmentID(), Equals, "department_string") - c.Check(query.QueryString(), Equals, "query_string") - - // verify uri - c.Check(query.ToURI(), Equals, "scope://scope?q=query%5Fstring&dep=department%5Fstring") - - // check setters - query.SetDepartmentID("department_id") - c.Check(query.DepartmentID(), Equals, "department_id") - - query.SetQueryString("new_query_value") - c.Check(query.QueryString(), Equals, "new_query_value") - - // TODO FilterState setter -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter.go b/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter.go deleted file mode 100644 index d1773c1..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter.go +++ /dev/null @@ -1,54 +0,0 @@ -package scopes - -// RadioButtonsFilter is a filter that displays mutually exclusive list of options -type RadioButtonsFilter struct { - filterWithOptions - Label string -} - -// NewRadioButtonsFilter creates a new radio button filter. -func NewRadioButtonsFilter(id, label string) *RadioButtonsFilter { - return &RadioButtonsFilter{ - filterWithOptions: filterWithOptions{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "radio_buttons", - }, - }, - Label: label, - } -} - -// UpdateState updates the value of a particular option in the filter state. -func (f *RadioButtonsFilter) UpdateState(state FilterState, optionId string, active bool) { - if !f.isValidOption(optionId) { - panic("invalid option ID") - } - // If the state isn't in a form we expect, treat it as empty - selected, _ := state[f.Id].([]interface{}) - - if active { - if len(selected) == 0 { - // just add the optionId - selected = append(selected, optionId) - } else if len(selected) > 0 && selected[0] != optionId { - // we have another option selected, just select the current one - selected[0] = optionId - } - } else { - if len(selected) > 0 && selected[0] == optionId { - // we have 1 option selected and it's the current one. - // clear the state - selected = make([]interface{}, 0) - } - } - state[f.Id] = selected -} - -func (f *RadioButtonsFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["label"] = f.Label - v["options"] = f.Options - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter_test.go deleted file mode 100644 index 4363dbc..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/radio_buttons_filter_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestRadioButtonsFilter(c *C) { - filter1 := scopes.NewRadioButtonsFilter("f1", "Options") - c.Check("f1", Equals, filter1.Id) - c.Check("Options", Equals, filter1.Label) - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayDefault) - - filter1.DisplayHints = scopes.FilterDisplayPrimary - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayPrimary) - - // verify the list of options - c.Check(len(filter1.Options), Equals, 3) - c.Check(filter1.Options, DeepEquals, []scopes.FilterOption{scopes.FilterOption{"1", "Option 1", false}, - scopes.FilterOption{"2", "Option 2", false}, - scopes.FilterOption{"3", "Option 3", false}}) - - // check the selection - fstate := make(scopes.FilterState) - c.Check(filter1.HasActiveOption(fstate), Equals, false) -} - -func (s *S) TestRadioButtonsFilterSingleSelection(c *C) { - filter1 := scopes.NewRadioButtonsFilter("f1", "Options") - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 2", false) - - fstate := make(scopes.FilterState) - _, ok := fstate["route"] - c.Check(ok, Equals, false) - c.Check(filter1.HasActiveOption(fstate), Equals, false) - - // enable option1 - filter1.UpdateState(fstate, "1", true) - _, ok = fstate["f1"] - c.Check(ok, Equals, true) - c.Check(filter1.HasActiveOption(fstate), Equals, true) - - active := filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active, DeepEquals, []string{"1"}) - - // enable option2, option1 get disabled - filter1.UpdateState(fstate, "2", true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 1) - c.Check(active, DeepEquals, []string{"2"}) - - // disable option1; filter state remains in the FilterState, just no options are selected - filter1.UpdateState(fstate, "2", false) - _, ok = fstate["f1"] - c.Check(ok, Equals, true) - active = filter1.ActiveOptions(fstate) - c.Check(len(active), Equals, 0) -} - -func (s *S) TestRadioButtonsFilterBadOption(c *C) { - filter1 := scopes.NewRadioButtonsFilter("f1", "Options") - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - - c.Assert(func() { filter1.UpdateState(fstate, "5", true) }, PanicMatches, "invalid option ID") - c.Assert(func() { filter1.UpdateState(fstate, "5", false) }, PanicMatches, "invalid option ID") -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/range_input_filter.go b/vendor/launchpad.net/go-unityscopes/v2/range_input_filter.go deleted file mode 100644 index 553e5ea..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/range_input_filter.go +++ /dev/null @@ -1,178 +0,0 @@ -package scopes - -import ( - "errors" - "fmt" -) - -// RangeInputFilter is a range filter which allows a start and end value to be entered by user, and any of them is optional. -type RangeInputFilter struct { - filterBase - DefaultStartValue interface{} - DefaultEndValue interface{} - StartPrefixLabel string - StartPostfixLabel string - EndPrefixLabel string - EndPostfixLabel string - CentralLabel string -} - -func checkRangeValidType(value interface{}) bool { - switch value.(type) { - case int, float64, nil: - return true - default: - return false - } -} - -// NewRangeInputFilter creates a new range input filter. -func NewRangeInputFilter(id string, defaultStartValue, defaultEndValue interface{}, startPrefixLabel, startPostfixLabel, endPrefixLabel, endPostfixLabel, centralLabel string) *RangeInputFilter { - if !checkRangeValidType(defaultStartValue) { - panic("bad type for defaultStartValue") - } - if !checkRangeValidType(defaultEndValue) { - panic("bad type for defaultEndValue") - } - return &RangeInputFilter{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "range_input", - }, - DefaultStartValue: defaultStartValue, - DefaultEndValue: defaultEndValue, - StartPrefixLabel: startPrefixLabel, - StartPostfixLabel: startPostfixLabel, - EndPrefixLabel: endPrefixLabel, - EndPostfixLabel: endPostfixLabel, - CentralLabel: centralLabel, - } -} - -// StartValue gets the start value of this filter from filter state object. -// If the value is not set for the filter it returns false as the second return statement, -// it returns true otherwise -func (f *RangeInputFilter) StartValue(state FilterState) (float64, bool) { - var start float64 - var ok bool - slice_interface, ok := state[f.Id].([]interface{}) - if ok { - if len(slice_interface) != 2 { - // something went really bad. - // we should have just 2 values - panic("RangeInputFilter:StartValue unexpected number of values found.") - } - - switch v := slice_interface[0].(type) { - case float64: - return v, true - case int: - return float64(v), true - case nil: - return 0, false - default: - panic("RangeInputFilter:StartValue Unknown value type") - } - } else { - switch v := f.DefaultStartValue.(type) { - case float64: - return v, true - case int: - return float64(v), true - case nil: - return 0, false - } - } - return start, ok -} - -// EndValue gets the end value of this filter from filter state object. -// If the value is not set for the filter it returns false as the second return statement, -// it returns true otherwise -func (f *RangeInputFilter) EndValue(state FilterState) (float64, bool) { - var end float64 - var ok bool - slice_interface, ok := state[f.Id].([]interface{}) - if ok { - if len(slice_interface) != 2 { - // something went really bad. - // we should have just 2 values - panic("RangeInputFilter:EndValue unexpected number of values found.") - } - - switch v := slice_interface[1].(type) { - case float64: - return v, true - case int: - return float64(v), true - case nil: - return 0, false - default: - panic("RangeInputFilter:EndValue Unknown value type") - } - } else { - switch v := f.DefaultEndValue.(type) { - case float64: - return v, true - case int: - return float64(v), true - case nil: - return 0, false - } - } - return end, ok -} - -func convertToFloat(value interface{}) float64 { - if value != nil { - fVal, ok := value.(float64) - if !ok { - iVal, ok := value.(int) - if !ok { - panic(fmt.Sprint("RangeInputFilter:convertToFloat unexpected type for given value %v", value)) - } - return float64(iVal) - } - return fVal - } else { - panic("RangeInputFilter:convertToFloat nil values are not accepted") - } -} - -// UpdateState updates the value of the filter -func (f *RangeInputFilter) UpdateState(state FilterState, start, end interface{}) error { - if !checkRangeValidType(start) { - return errors.New("RangeInputFilter:UpdateState: Bad type for start value. Valid types are int float64 and nil") - } - if !checkRangeValidType(end) { - return errors.New("RangeInputFilter:UpdateState: Bad type for end value. Valid types are int float64 and nil") - } - - if start == nil && end == nil { - // remove the state - delete(state, f.Id) - return nil - } - if start != nil && end != nil { - fStart := convertToFloat(start) - fEnd := convertToFloat(end) - if fStart >= fEnd { - return errors.New(fmt.Sprintf("RangeInputFilter::UpdateState(): start_value %v is greater or equal to end_value %v for filter %s", start, end, f.Id)) - } - } - state[f.Id] = []interface{}{start, end} - return nil -} - -func (f *RangeInputFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["default_start_value"] = f.DefaultStartValue - v["default_end_value"] = f.DefaultEndValue - v["start_prefix_label"] = f.StartPrefixLabel - v["start_postfix_label"] = f.StartPostfixLabel - v["end_prefix_label"] = f.EndPrefixLabel - v["end_postfix_label"] = f.EndPostfixLabel - v["central_label"] = f.CentralLabel - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/range_input_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/range_input_filter_test.go deleted file mode 100644 index e98e06a..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/range_input_filter_test.go +++ /dev/null @@ -1,172 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestRangeInputFilter(c *C) { - filter1 := scopes.NewRangeInputFilter("f1", nil, nil, "start_prefix", "start_postfix", "end_prefix", "end_postfix", "central") - c.Check("f1", Equals, filter1.Id) - c.Check(nil, Equals, filter1.DefaultStartValue) - c.Check(nil, Equals, filter1.DefaultEndValue) - c.Check("start_prefix", Equals, filter1.StartPrefixLabel) - c.Check("start_postfix", Equals, filter1.StartPostfixLabel) - c.Check("end_prefix", Equals, filter1.EndPrefixLabel) - c.Check("end_postfix", Equals, filter1.EndPostfixLabel) - c.Check("central", Equals, filter1.CentralLabel) - - // check the selection - fstate := make(scopes.FilterState) - start, found := filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found := filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // test setting floats - err := filter1.UpdateState(fstate, 10.2, 100.4) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, 10.2) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, 100.4) - c.Check(found, Equals, true) - - // test setting floats with no decimals - err = filter1.UpdateState(fstate, 10.0, 100.0) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, 10.0) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, 100.0) - c.Check(found, Equals, true) - - // test setting mixed floats and integers - err = filter1.UpdateState(fstate, 10, 100.0) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, float64(10)) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, 100.0) - c.Check(found, Equals, true) - - // test integers - err = filter1.UpdateState(fstate, 10, 100) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, float64(10)) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, float64(100)) - c.Check(found, Equals, true) - - // test integer and nil - err = filter1.UpdateState(fstate, nil, 100) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, float64(100)) - c.Check(found, Equals, true) - - // test float and nil - err = filter1.UpdateState(fstate, 10.4, nil) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, 10.4) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // test both nil - err = filter1.UpdateState(fstate, nil, nil) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found = filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // start greater then end - err = filter1.UpdateState(fstate, 10, 0.6) - c.Check(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "RangeInputFilter::UpdateState(): start_value 10 is greater or equal to end_value 0.6 for filter f1") - - start, found = filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found = filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // start equals end - err = filter1.UpdateState(fstate, 10, 10.0) - c.Check(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "RangeInputFilter::UpdateState(): start_value 10 is greater or equal to end_value 10 for filter f1") - - start, found = filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found = filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // bad values - err = filter1.UpdateState(fstate, "", 10.0) - c.Check(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "RangeInputFilter:UpdateState: Bad type for start value. Valid types are int float64 and nil") - - err = filter1.UpdateState(fstate, 1, "") - c.Check(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "RangeInputFilter:UpdateState: Bad type for end value. Valid types are int float64 and nil") - - err = filter1.UpdateState(fstate, 1, []int{1, 2}) - c.Check(err, Not(Equals), nil) - c.Check(err.Error(), Equals, "RangeInputFilter:UpdateState: Bad type for end value. Valid types are int float64 and nil") - - start, found = filter1.StartValue(fstate) - c.Check(found, Equals, false) - - end, found = filter1.EndValue(fstate) - c.Check(found, Equals, false) - - // try to set values again - err = filter1.UpdateState(fstate, 10, 100) - c.Check(err, IsNil) - - start, found = filter1.StartValue(fstate) - c.Check(start, Equals, float64(10)) - c.Check(found, Equals, true) - - end, found = filter1.EndValue(fstate) - c.Check(end, Equals, float64(100)) - c.Check(found, Equals, true) -} - -func (s *S) TestRangeInputFilterDefaults(c *C) { - filter := scopes.NewRangeInputFilter("f1", 0, 100, "start_prefix", "start_postfix", "end_prefix", "end_postfix", "central") - - fstate := make(scopes.FilterState) - start, ok := filter.StartValue(fstate) - c.Check(ok, Equals, true) - c.Check(start, Equals, 0.0) - - end, ok := filter.EndValue(fstate) - c.Check(ok, Equals, true) - c.Check(end, Equals, 100.0) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/rating_filter.go b/vendor/launchpad.net/go-unityscopes/v2/rating_filter.go deleted file mode 100644 index c1b8ae4..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/rating_filter.go +++ /dev/null @@ -1,56 +0,0 @@ -package scopes - -import ( -// "sort" -) - -// RatingFilter is a filter that allows for rating-based selection -type RatingFilter struct { - filterWithOptions - Label string - OnIcon string - OffIcon string -} - -// NewRatingFilter creates a new rating filter. -func NewRatingFilter(id, label string) *RatingFilter { - return &RatingFilter{ - filterWithOptions: filterWithOptions{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "rating", - }, - }, - Label: label, - } -} - -// ActiveRating gets active option from an instance of FilterState for this filter. -func (f *RatingFilter) ActiveRating(state FilterState) (string, bool) { - rating, ok := state[f.Id].(string) - return rating, ok -} - -// UpdateState updates the value of a particular option in the filter state. -func (f *RatingFilter) UpdateState(state FilterState, optionId string, active bool) { - if !f.isValidOption(optionId) { - panic("invalid option ID") - } - // If the state isn't in a form we expect, treat it as empty - selected, ok := state[f.Id].(string) - if ok && selected == optionId && active == false { - delete(state, f.Id) - } else { - if active { - state[f.Id] = optionId - } - } -} - -func (f *RatingFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["label"] = f.Label - v["options"] = f.Options - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/rating_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/rating_filter_test.go deleted file mode 100644 index 60f184e..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/rating_filter_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestRatingFilter(c *C) { - filter1 := scopes.NewRatingFilter("f1", "Options") - c.Check("f1", Equals, filter1.Id) - c.Check("Options", Equals, filter1.Label) - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayDefault) - - filter1.DisplayHints = scopes.FilterDisplayPrimary - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayPrimary) - c.Check(2, Equals, len(filter1.Options)) - c.Check("1", Equals, filter1.Options[0].Id) - c.Check("Option 1", Equals, filter1.Options[0].Label) - c.Check("2", Equals, filter1.Options[1].Id) - c.Check("Option 2", Equals, filter1.Options[1].Label) - - // verify the list of options - c.Check(len(filter1.Options), Equals, 2) - c.Check(filter1.Options, DeepEquals, []scopes.FilterOption{scopes.FilterOption{"1", "Option 1", false}, scopes.FilterOption{"2", "Option 2", false}}) -} - -func (s *S) TestRatingFilterMultiSelection(c *C) { - filter1 := scopes.NewRatingFilter("f1", "Options") - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - - // enable option1 & option2 - filter1.UpdateState(fstate, "1", true) - _, ok := fstate["f1"] - c.Check(ok, Equals, true) - - active, ok := filter1.ActiveRating(fstate) - c.Check(active, Equals, "1") - c.Check(ok, Equals, true) - - // disable option1 - filter1.UpdateState(fstate, "1", false) - active, ok = filter1.ActiveRating(fstate) - c.Check(active, Equals, "") - c.Check(ok, Equals, false) - - filter1.UpdateState(fstate, "3", true) - - active, ok = filter1.ActiveRating(fstate) - c.Check(active, Equals, "3") - c.Check(ok, Equals, true) - - // select another one - filter1.UpdateState(fstate, "1", true) - active, ok = filter1.ActiveRating(fstate) - c.Check(active, Equals, "1") - c.Check(ok, Equals, true) - - // select another one - filter1.UpdateState(fstate, "2", true) - - // erase not selected - filter1.UpdateState(fstate, "1", false) - active, ok = filter1.ActiveRating(fstate) - c.Check(active, Equals, "2") - c.Check(ok, Equals, true) - - // erase the active one - filter1.UpdateState(fstate, "2", false) - active, ok = filter1.ActiveRating(fstate) - c.Check(ok, Equals, false) - c.Check(active, Equals, "") -} - -func (s *S) TestRatingFilterBadOption(c *C) { - filter1 := scopes.NewRatingFilter("f1", "Options") - filter1.AddOption("1", "Option 1", false) - filter1.AddOption("2", "Option 2", false) - filter1.AddOption("3", "Option 3", false) - - fstate := make(scopes.FilterState) - - c.Assert(func() { filter1.UpdateState(fstate, "5", true) }, PanicMatches, "invalid option ID") - c.Assert(func() { filter1.UpdateState(fstate, "5", false) }, PanicMatches, "invalid option ID") - c.Assert(func() { filter1.UpdateState(fstate, "", false) }, PanicMatches, "invalid option ID") -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/reply.cpp b/vendor/launchpad.net/go-unityscopes/v2/reply.cpp deleted file mode 100644 index 51f2009..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/reply.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include <stdexcept> -#include <cstring> -#include <iostream> - -#include <unity/scopes/PreviewReply.h> -#include <unity/scopes/SearchReply.h> -#include <unity/scopes/Version.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" -#include "smartptr_helper.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -void init_search_reply_ptr(SharedPtrData dest, SharedPtrData src) { - std::shared_ptr<SearchReply> reply = get_ptr<SearchReply>(src); - init_ptr<SearchReply>(dest, reply); -} - -void destroy_search_reply_ptr(SharedPtrData data) { - destroy_ptr<SearchReply>(data); -} - -void search_reply_finished(SharedPtrData reply) { - get_ptr<SearchReply>(reply)->finished(); -} - -void search_reply_error(SharedPtrData reply, const StrData err_string) { - get_ptr<SearchReply>(reply)->error(std::make_exception_ptr( - std::runtime_error(from_gostring(err_string)))); -} - -void search_reply_register_category(SharedPtrData reply, const StrData id, const StrData title, const StrData icon, const StrData cat_template, SharedPtrData category) { - CategoryRenderer renderer; - std::string renderer_template = from_gostring(cat_template); - if (!renderer_template.empty()) { - renderer = CategoryRenderer(renderer_template); - } - auto cat = get_ptr<SearchReply>(reply)->register_category(from_gostring(id), from_gostring(title), from_gostring(icon), renderer); - init_ptr<const Category>(category, cat); -} - -void search_reply_register_departments(SharedPtrData reply, SharedPtrData dept) { - get_ptr<SearchReply>(reply)->register_departments(get_ptr<Department>(dept)); -} - -void search_reply_push(SharedPtrData reply, _CategorisedResult *result, char **error) { - try { - get_ptr<SearchReply>(reply)->push(*reinterpret_cast<CategorisedResult*>(result)); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void search_reply_push_filters(SharedPtrData reply, const StrData filters_json, const StrData filter_state_json, char **error) { -#if UNITY_SCOPES_VERSION_MAJOR == 0 && (UNITY_SCOPES_VERSION_MINOR < 6 || (UNITY_SCOPES_VERSION_MINOR == 6 && UNITY_SCOPES_VERSION_MICRO < 10)) - std::string errorMessage = "SearchReply.PushFilters() is only available when compiled against libunity-scopes >= 0.6.10"; - *error = strdup(errorMessage.c_str()); - std::cerr << errorMessage << std::endl; -#else - try { - Variant filters_var = Variant::deserialize_json(from_gostring(filters_json)); - Variant filter_state_var = Variant::deserialize_json(from_gostring(filter_state_json)); - Filters filters; - for (const auto &f : filters_var.get_array()) { - filters.emplace_back(FilterBase::deserialize(f.get_dict())); - } - auto filter_state = FilterState::deserialize(filter_state_var.get_dict()); - get_ptr<SearchReply>(reply)->push(filters, filter_state); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -#endif -} - -void init_preview_reply_ptr(SharedPtrData dest, SharedPtrData src) { - std::shared_ptr<PreviewReply> reply = get_ptr<PreviewReply>(src); - init_ptr<PreviewReply>(dest, reply); -} - -void destroy_preview_reply_ptr(SharedPtrData data) { - destroy_ptr<PreviewReply>(data); -} - -void preview_reply_finished(SharedPtrData reply) { - get_ptr<PreviewReply>(reply)->finished(); -} - -void preview_reply_error(SharedPtrData reply, const StrData err_string) { - get_ptr<PreviewReply>(reply)->error(std::make_exception_ptr( - std::runtime_error(from_gostring(err_string)))); -} - -void preview_reply_push_widgets(SharedPtrData reply, const StrData widget_list, char **error) { - try { - PreviewWidgetList widgets; - for (const auto &w : split_strings(widget_list)) { - widgets.push_back(PreviewWidget(w)); - } - get_ptr<PreviewReply>(reply)->push(widgets); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void preview_reply_push_attr(SharedPtrData reply, const StrData key, const StrData json_value, char **error) { - try { - Variant value = Variant::deserialize_json(from_gostring(json_value)); - get_ptr<PreviewReply>(reply)->push(from_gostring(key), value); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void preview_reply_register_layout(SharedPtrData reply, _ColumnLayout **layout, int n_items, char **error) { - try { - ColumnLayoutList api_layout_list; - for(auto i = 0; i < n_items; ++i) { - ColumnLayout api_layout(*(reinterpret_cast<ColumnLayout*>(layout[i]))); - api_layout_list.push_back(api_layout); - } - get_ptr<PreviewReply>(reply)->register_layout(api_layout_list); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/reply.go b/vendor/launchpad.net/go-unityscopes/v2/reply.go deleted file mode 100644 index 10a28ab..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/reply.go +++ /dev/null @@ -1,181 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "runtime" -) - -// SearchReply is used to send results of search queries to the client. -type SearchReply struct { - r C.SharedPtrData -} - -func makeSearchReply(replyData *C.uintptr_t) *SearchReply { - reply := new(SearchReply) - runtime.SetFinalizer(reply, finalizeSearchReply) - C.init_search_reply_ptr(&reply.r[0], replyData) - return reply -} - -func finalizeSearchReply(reply *SearchReply) { - C.destroy_search_reply_ptr(&reply.r[0]) -} - -// Finished is called to indicate that no further results will be -// pushed to this reply. -// -// This is called automatically if a scope's Search method completes -// without error. -func (reply *SearchReply) Finished() { - C.search_reply_finished(&reply.r[0]) -} - -// Error is called to indicate that search query could not be -// completed successfully. -// -// This is called automatically if a scope's Search method completes -// with an error. -func (reply *SearchReply) Error(err error) { - errString := err.Error() - C.search_reply_error(&reply.r[0], strData(errString)) -} - -// RegisterCategory registers a new results category with the client. -// -// The template parameter should either be empty (to use the default -// rendering template), or contain a JSON template as described here: -// -// http://developer.ubuntu.com/api/scopes/sdk-14.10/unity.scopes.CategoryRenderer/#details -// -// Categories can be passed to NewCategorisedResult in order to -// construct search results. -func (reply *SearchReply) RegisterCategory(id, title, icon, template string) *Category { - cat := new(Category) - runtime.SetFinalizer(cat, finalizeCategory) - C.search_reply_register_category(&reply.r[0], strData(id), strData(title), strData(icon), strData(template), &cat.c[0]) - return cat -} - -// RegisterDepartments registers the department set to display with -// the search results. -// -// The parent department of the current search should be provided -// here, with the current department identified among its children by -// a matching department ID. -func (reply *SearchReply) RegisterDepartments(parent *Department) { - C.search_reply_register_departments(&reply.r[0], &parent.d[0]) -} - -// Push sends a search result to the client. -func (reply *SearchReply) Push(result *CategorisedResult) error { - var errorString *C.char - C.search_reply_push(&reply.r[0], result.result, &errorString) - return checkError(errorString) -} - -// PushFilters sends the set of filters and their state to the client. -func (reply *SearchReply) PushFilters(filters []Filter, state FilterState) error { - var filtersJson, stateJson string - filterData := make([]interface{}, len(filters)) - for i, f := range filters { - filterData[i] = f.serializeFilter() - } - if data, err := json.Marshal(filterData); err == nil { - filtersJson = string(data) - } else { - return err - } - if data, err := json.Marshal(state); err == nil { - stateJson = string(data) - } else { - return err - } - var errorString *C.char - C.search_reply_push_filters(&reply.r[0], strData(filtersJson), strData(stateJson), &errorString) - return checkError(errorString) -} - -// PreviewReply is used to send result previews to the client. -type PreviewReply struct { - r C.SharedPtrData -} - -func makePreviewReply(replyData *C.uintptr_t) *PreviewReply { - reply := new(PreviewReply) - runtime.SetFinalizer(reply, finalizePreviewReply) - C.init_preview_reply_ptr(&reply.r[0], replyData) - return reply -} - -func finalizePreviewReply(reply *PreviewReply) { - C.destroy_search_reply_ptr(&reply.r[0]) -} - -// Finished is called to indicate that no further widgets or -// attributes will be pushed to this reply. -// -// This is called automatically if a scope's Preview method completes -// without error. -func (reply *PreviewReply) Finished() { - C.preview_reply_finished(&reply.r[0]) -} - -// Error is called to indicate that the preview generation could not -// be completed successfully. -// -// This is called automatically if a scope's Preview method completes -// with an error. -func (reply *PreviewReply) Error(err error) { - errString := err.Error() - C.preview_reply_error(&reply.r[0], strData(errString)) -} - -// PushWidgets sends one or more preview widgets to the client. -func (reply *PreviewReply) PushWidgets(widgets ...PreviewWidget) error { - widget_data := make([]string, len(widgets)) - for i, w := range widgets { - data, err := w.data() - if err != nil { - return err - } - widget_data[i] = string(data) - } - var errorString *C.char - C.preview_reply_push_widgets(&reply.r[0], joinedStrData(widget_data), &errorString) - return checkError(errorString) -} - -// PushAttr pushes a preview attribute to the client. -// -// This will augment the set of attributes in the result available to -// be mapped by preview widgets. This allows a widget to be sent to -// the client early, and then fill it in later when the information is -// available. -func (reply *PreviewReply) PushAttr(attr string, value interface{}) error { - data, err := json.Marshal(value) - if err != nil { - return err - } - json_value := string(data) - var errorString *C.char - C.preview_reply_push_attr(&reply.r[0], strData(attr), strData(json_value), &errorString) - return checkError(errorString) -} - -// RegisterLayout registers a list of column layouts for the current preview. -// -// Layouts must be registered before pushing a unity::scopes::PreviewWidgetList, and must be -// registered only once. -// Returns an error if RegisterLayout() is called more than once. -func (reply *PreviewReply) RegisterLayout(layout ...*ColumnLayout) error { - api_layout := make([]*C._ColumnLayout, len(layout)) - for i, l := range layout { - api_layout[i] = l.c - } - var errorString *C.char - C.preview_reply_register_layout(&reply.r[0], &api_layout[0], C.int(len(api_layout)), &errorString) - return checkError(errorString) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/result.cpp b/vendor/launchpad.net/go-unityscopes/v2/result.cpp deleted file mode 100644 index 766f830..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/result.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <stdexcept> -#include <cstring> - -#include <unity/scopes/Category.h> -#include <unity/scopes/CategorisedResult.h> -#include <unity/scopes/Result.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" -#include "smartptr_helper.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -_Result *new_categorised_result(SharedPtrData category) { - auto cat = get_ptr<Category>(category); - return reinterpret_cast<_CategorisedResult*>(static_cast<Result*>(new CategorisedResult(cat))); -} - -void destroy_result(_Result *res) { - delete reinterpret_cast<Result*>(res); -} - -void *result_get_attr(_Result *res, const StrData attr, int *length, char **error) { - std::string json_data; - try { - Variant v = reinterpret_cast<Result*>(res)->value(from_gostring(attr)); - json_data = v.serialize_json(); - } catch (const std::exception &e) { - *error = strdup(e.what()); - return nullptr; - } - return as_bytes(json_data, length); -} - -void result_set_attr(_Result *res, const StrData attr, const StrData json_value, char **error) { - try { - Variant v = Variant::deserialize_json(from_gostring(json_value)); - (*reinterpret_cast<Result*>(res))[from_gostring(attr)] = v; - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -void result_set_intercept_activation(_Result *res) { - reinterpret_cast<Result*>(res)->set_intercept_activation(); -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/result.go b/vendor/launchpad.net/go-unityscopes/v2/result.go deleted file mode 100644 index 1637cb4..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/result.go +++ /dev/null @@ -1,143 +0,0 @@ -package scopes - -// #include <stdlib.h> -// #include "shim.h" -import "C" -import ( - "encoding/json" - "runtime" -) - -// Result represents a result from the scope -type Result struct { - result *C._Result -} - -func makeResult(res *C._Result) *Result { - result := new(Result) - runtime.SetFinalizer(result, finalizeResult) - result.result = res - return result -} - -func finalizeResult(res *Result) { - if res.result != nil { - C.destroy_result(res.result) - } - res.result = nil -} - -// Get returns the named result attribute. -// -// The value is decoded into the variable pointed to by the second -// argument. If the types do not match, an error will be returned. -// -// If the attribute does not exist, an error is returned. -func (res *Result) Get(attr string, value interface{}) error { - var ( - length C.int - errorString *C.char - ) - data := C.result_get_attr(res.result, strData(attr), &length, &errorString) - if err := checkError(errorString); err != nil { - return err - } - defer C.free(data) - return json.Unmarshal(C.GoBytes(data, length), value) -} - -// Set sets the named result attribute. -// -// An error may be returned if the value can not be stored, or if -// there is any other problems updating the result. -func (res *Result) Set(attr string, value interface{}) error { - data, err := json.Marshal(value) - if err != nil { - return err - } - stringValue := string(data) - - var errorString *C.char - C.result_set_attr(res.result, strData(attr), strData(stringValue), &errorString) - return checkError(errorString) -} - -// SetInterceptActivation marks this result as needing custom activation handling. -// -// By default, results are activated by the client directly (e.g. by -// running the application associated with the result URI). For -// results with this flag set though, the scope will be asked to -// perform activation and should implement the Activate method. -func (res *Result) SetInterceptActivation() { - C.result_set_intercept_activation(res.result) -} - -// SetURI sets the "uri" attribute of the result. -func (res *Result) SetURI(uri string) error { - return res.Set("uri", uri) -} - -// SetTitle sets the "title" attribute of the result. -func (res *Result) SetTitle(title string) error { - return res.Set("title", title) -} - -// SetArt sets the "art" attribute of the result. -func (res *Result) SetArt(art string) error { - return res.Set("art", art) -} - -// SetDndURI sets the "dnd_uri" attribute of the result. -func (res *Result) SetDndURI(uri string) error { - return res.Set("dnd_uri", uri) -} - -func (res *Result) getString(attr string) string { - var value string - if err := res.Get(attr, &value); err != nil { - return "" - } - return value -} - -// URI returns the "uri" attribute of the result if set, or an empty string. -func (res *Result) URI() string { - return res.getString("uri") -} - -// Title returns the "title" attribute of the result if set, or an empty string. -func (res *Result) Title() string { - return res.getString("title") -} - -// Art returns the "art" attribute of the result if set, or an empty string. -func (res *Result) Art() string { - return res.getString("art") -} - -// DndURI returns the "dnd_uri" attribute of the result if set, or an -// empty string. -func (res *Result) DndURI() string { - return res.getString("dnd_uri") -} - -// CategorisedResult represents a result linked to a particular category. -// -// CategorisedResult embeds Result, so all of its attribute -// manipulation methods can be used on variables of this type. -type CategorisedResult struct { - Result -} - -// NewCategorisedResult creates a new empty result linked to the given -// category. -func NewCategorisedResult(category *Category) *CategorisedResult { - res := new(CategorisedResult) - runtime.SetFinalizer(res, finalizeCategorisedResult) - res.result = C.new_categorised_result(&category.c[0]) - return res -} - -func finalizeCategorisedResult(res *CategorisedResult) { - finalizeResult(&res.Result) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/result_test.go b/vendor/launchpad.net/go-unityscopes/v2/result_test.go deleted file mode 100644 index 57f15cb..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/result_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestResultSetURI(c *C) { - r := scopes.NewTestingResult() - c.Check(r.SetURI("http://example.com"), IsNil) - c.Check(r.URI(), Equals, "http://example.com") - - var uri string - c.Check(r.Get("uri", &uri), IsNil) - c.Check(uri, Equals, "http://example.com") -} - -func (s *S) TestResultSetTitle(c *C) { - r := scopes.NewTestingResult() - c.Check(r.SetTitle("The title"), IsNil) - c.Check(r.Title(), Equals, "The title") - - var title string - c.Check(r.Get("title", &title), IsNil) - c.Check(title, Equals, "The title") -} - -func (s *S) TestResultSetArt(c *C) { - r := scopes.NewTestingResult() - c.Check(r.SetArt("http://example.com/foo.png"), IsNil) - c.Check(r.Art(), Equals, "http://example.com/foo.png") - - var uri string - c.Check(r.Get("art", &uri), IsNil) - c.Check(uri, Equals, "http://example.com/foo.png") -} - -func (s *S) TestResultSetDndURI(c *C) { - r := scopes.NewTestingResult() - c.Check(r.SetDndURI("http://example.com"), IsNil) - c.Check(r.DndURI(), Equals, "http://example.com") - - var uri string - c.Check(r.Get("dnd_uri", &uri), IsNil) - c.Check(uri, Equals, "http://example.com") -} - -func (s *S) TestResultSetComplexValue(c *C) { - type Attr struct { - Value string `json:"value"` - } - - r := scopes.NewTestingResult() - c.Check(r.Set("attributes", []Attr{ - Attr{"one"}, - Attr{"two"}, - }), IsNil) - - // Check that the value has been encoded as expeected: - var v interface{} - c.Check(r.Get("attributes", &v), IsNil) - c.Check(v, DeepEquals, []interface{}{ - map[string]interface{}{"value": "one"}, - map[string]interface{}{"value": "two"}, - }) - - // The value can also be decoded into the complex structure too - var v2 []Attr - c.Check(r.Get("attributes", &v2), IsNil) - c.Check(v2, DeepEquals, []Attr{ - Attr{"one"}, - Attr{"two"}, - }) -} - -func testMarshallingThisFunction(i int) int { - return i -} - -func (s *S) TestResultSetBadValue(c *C) { - type Attr struct { - value int - value2 float64 - } - - r := scopes.NewTestingResult() - c.Check(r.Set("attributes", testMarshallingThisFunction), Not(Equals), nil) -} - -func (s *S) TestResultGetBadValue(c *C) { - type Attr struct { - value int - value2 float64 - } - - r := scopes.NewTestingResult() - var attr string - c.Check(r.Get("bad_attribute", &attr), Not(Equals), nil) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/scope.cpp b/vendor/launchpad.net/go-unityscopes/v2/scope.cpp deleted file mode 100644 index b3f0824..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/scope.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include <unity/scopes/Category.h> -extern "C" { -#include "_cgo_export.h" -} -#include "scope.h" -#include "smartptr_helper.h" - -using namespace unity::scopes; - -ScopeAdapter::ScopeAdapter(GoInterface goscope) : goscope(goscope) { -} - -void ScopeAdapter::start(std::string const &) { - setScopeBase(goscope, reinterpret_cast<_ScopeBase*>(this)); -} - -void ScopeAdapter::stop() { - setScopeBase(goscope, nullptr); -} - -SearchQueryBase::UPtr ScopeAdapter::search(CannedQuery const &q, - SearchMetadata const &metadata) { - SearchQueryBase::UPtr query(new QueryAdapter(q, metadata, *this)); - return query; -} - -PreviewQueryBase::UPtr ScopeAdapter::preview(Result const& result, ActionMetadata const& metadata) { - PreviewQueryBase::UPtr query(new PreviewAdapter(result, metadata, *this)); - return query; -} - -ActivationQueryBase::UPtr ScopeAdapter::activate(Result const& result, ActionMetadata const &metadata) { - ActivationQueryBase::UPtr activation(new ActivationAdapter(result, metadata, *this)); - return activation; -} - -ActivationQueryBase::UPtr ScopeAdapter::perform_action(Result const& result, ActionMetadata const &metadata, std::string const &widget_id, std::string const &action_id) { - ActivationQueryBase::UPtr activation(new ActivationAdapter(result, metadata, widget_id, action_id, *this)); - return activation; -} - -ChildScopeList ScopeAdapter::find_child_scopes() const { - ChildScopeList child_scopes; - callFindChildScopes(goscope, &child_scopes); - return child_scopes; -} - -QueryAdapter::QueryAdapter(CannedQuery const &query, - SearchMetadata const &metadata, - ScopeAdapter &scope) - : SearchQueryBase(query, metadata), scope(scope), - cancel_channel(makeCancelChannel(), releaseCancelChannel) { -} - -void QueryAdapter::cancelled() { - sendCancelChannel(cancel_channel.get()); -} - -void QueryAdapter::run(SearchReplyProxy const &reply) { - callScopeSearch( - scope.goscope, - reinterpret_cast<_CannedQuery*>(new CannedQuery(query())), - reinterpret_cast<_SearchMetadata*>(new SearchMetadata(search_metadata())), - const_cast<uintptr_t*>(reinterpret_cast<const uintptr_t*>(&reply)), - cancel_channel.get()); -} - -PreviewAdapter::PreviewAdapter(Result const &result, - ActionMetadata const &metadata, - ScopeAdapter &scope) - : PreviewQueryBase(result, metadata), scope(scope), - cancel_channel(makeCancelChannel(), releaseCancelChannel) { -} - -void PreviewAdapter::cancelled() { - sendCancelChannel(cancel_channel.get()); -} - -void PreviewAdapter::run(PreviewReplyProxy const &reply) { - callScopePreview( - scope.goscope, - reinterpret_cast<_Result*>(new Result(result())), - reinterpret_cast<_ActionMetadata*>(new ActionMetadata(action_metadata())), - const_cast<uintptr_t*>(reinterpret_cast<const uintptr_t*>(&reply)), - cancel_channel.get()); -} - -ActivationAdapter::ActivationAdapter(Result const &result, - ActionMetadata const &metadata, - ScopeAdapter &scope) - : ActivationQueryBase(result, metadata), scope(scope), - is_action(false) { -} - -ActivationAdapter::ActivationAdapter(Result const &result, - ActionMetadata const &metadata, - std::string const &widget_id, - std::string const &action_id, - ScopeAdapter &scope) - : ActivationQueryBase(result, metadata, widget_id, action_id), - scope(scope), is_action(true) { -} - -ActivationResponse ActivationAdapter::activate() { - ActivationResponse response(ActivationResponse::NotHandled); - char *error = nullptr; - if (is_action) { - callScopePerformAction( - scope.goscope, - reinterpret_cast<_Result*>(new Result(result())), - reinterpret_cast<_ActionMetadata*>(new ActionMetadata(action_metadata())), - const_cast<char*>(widget_id().c_str()), - const_cast<char*>(action_id().c_str()), - reinterpret_cast<_ActivationResponse*>(&response), - &error); - } else { - callScopeActivate( - scope.goscope, - reinterpret_cast<_Result*>(new Result(result())), - reinterpret_cast<_ActionMetadata*>(new ActionMetadata(action_metadata())), - reinterpret_cast<_ActivationResponse*>(&response), - &error); - } - if (error != nullptr) { - const std::string message(error); - free(error); - throw std::runtime_error(message); - } - return response; -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/scope.h b/vendor/launchpad.net/go-unityscopes/v2/scope.h deleted file mode 100644 index 360738d..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/scope.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef UNITYSCOPE_SCOPE_H -#define UNITYSCOPE_SCOPE_H - -#include <memory> -#include <string> - -#include <unity/scopes/ScopeBase.h> - -class ScopeAdapter : public unity::scopes::ScopeBase -{ - friend class QueryAdapter; - friend class PreviewAdapter; - friend class ActivationAdapter; -public: - ScopeAdapter(GoInterface goscope); - virtual void start(std::string const&) override; - virtual void stop() override; - virtual unity::scopes::SearchQueryBase::UPtr search(unity::scopes::CannedQuery const &query, unity::scopes::SearchMetadata const &metadata) override; - - virtual unity::scopes::PreviewQueryBase::UPtr preview(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata) override; - virtual unity::scopes::ActivationQueryBase::UPtr activate(unity::scopes::Result const& result, unity::scopes::ActionMetadata const &metadata) override; - virtual unity::scopes::ActivationQueryBase::UPtr perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const &metadata, std::string const &widget_id, std::string const &action_id) override; - - virtual unity::scopes::ChildScopeList find_child_scopes() const override; - -private: - GoInterface goscope; -}; - -class QueryAdapter : public unity::scopes::SearchQueryBase -{ -public: - QueryAdapter(unity::scopes::CannedQuery const &query, - unity::scopes::SearchMetadata const &metadata, - ScopeAdapter &scope); - virtual void cancelled() override; - virtual void run(unity::scopes::SearchReplyProxy const &reply) override; -private: - const ScopeAdapter &scope; - std::unique_ptr<void, void(*)(GoChan)> cancel_channel; -}; - -class PreviewAdapter : public unity::scopes::PreviewQueryBase -{ -public: - PreviewAdapter(unity::scopes::Result const &result, - unity::scopes::ActionMetadata const &metadata, - ScopeAdapter &scope); - virtual void cancelled() override; - virtual void run(unity::scopes::PreviewReplyProxy const &reply) override; -private: - const ScopeAdapter &scope; - std::unique_ptr<void, void(*)(GoChan)> cancel_channel; -}; - -class ActivationAdapter : public unity::scopes::ActivationQueryBase -{ -public: - ActivationAdapter(unity::scopes::Result const &result, - unity::scopes::ActionMetadata const &metadata, - ScopeAdapter &scope); - ActivationAdapter(unity::scopes::Result const &result, - unity::scopes::ActionMetadata const &metadata, - std::string const &widget_id, - std::string const &action_id, - ScopeAdapter &scope); - virtual unity::scopes::ActivationResponse activate() override; -private: - const ScopeAdapter &scope; - bool is_action; -}; - -#endif diff --git a/vendor/launchpad.net/go-unityscopes/v2/shim.cpp b/vendor/launchpad.net/go-unityscopes/v2/shim.cpp deleted file mode 100644 index d5d6d9f..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/shim.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include <cstring> - -#include <unity/scopes/Category.h> -#include <unity/scopes/Runtime.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "version.h" -#include "helpers.h" -#include "smartptr_helper.h" -#include "scope.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -void run_scope(const StrData scope_name, const StrData runtime_config, - const StrData scope_config, void *pointer_to_iface, - char **error) { - try { - auto runtime = Runtime::create_scope_runtime( - from_gostring(scope_name), from_gostring(runtime_config)); - ScopeAdapter scope(*reinterpret_cast<GoInterface*>(pointer_to_iface)); - runtime->run_scope(&scope, from_gostring(scope_config)); - } catch (const std::exception &e) { - *error = strdup(e.what()); - } -} - -char *scope_base_scope_directory(_ScopeBase *scope) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - return strdup(s->scope_directory().c_str()); -} - -char *scope_base_cache_directory(_ScopeBase *scope) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - return strdup(s->cache_directory().c_str()); -} - -char *scope_base_tmp_directory(_ScopeBase *scope) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - return strdup(s->tmp_directory().c_str()); -} - -void *scope_base_settings(_ScopeBase *scope, int *length) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - Variant settings(s->settings()); - return as_bytes(settings.serialize_json(), length); -} - -void destroy_category_ptr(SharedPtrData data) { - destroy_ptr<const Category>(data); -} - -_ScopeMetadata** list_registry_scopes_metadata(_ScopeBase *scope, int *n_scopes) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - auto registry = s->registry(); - auto scopes = registry->list(); - - *n_scopes = scopes.size(); - - _ScopeMetadata** ret_data = reinterpret_cast<_ScopeMetadata**>(calloc(*n_scopes, sizeof(_ScopeMetadata*))); - int i = 0; - for( auto item: scopes ) { - ret_data[i++] = reinterpret_cast<_ScopeMetadata*>(new ScopeMetadata(item.second)); - } - - return ret_data; -} - -_ChildScope **list_child_scopes(_ScopeBase *scope, int *n_scopes) { - ScopeBase *s = reinterpret_cast<ScopeBase*>(scope); - auto child_scopes = s->child_scopes(); - - *n_scopes = child_scopes.size(); - _ChildScope** ret_data = reinterpret_cast<_ChildScope**>(calloc(*n_scopes, sizeof(_ChildScope*))); - int i = 0; - for (auto item: child_scopes) { - ret_data[i++] = reinterpret_cast<_ChildScope*>(new ChildScope(item.id, item.metadata, item.enabled, item.keywords)); - } - - return ret_data; -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/shim.h b/vendor/launchpad.net/go-unityscopes/v2/shim.h deleted file mode 100644 index 82b9ce3..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/shim.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef UNITYSCOPE_SHIM_H -#define UNITYSCOPE_SHIM_H - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* A typedef that can be used to represent a std::shared_ptr */ - -typedef uintptr_t SharedPtrData[2]; - -typedef struct StrData { - char *data; - long length; -} StrData; - -typedef struct _CannedQuery _CannedQuery; -typedef struct _Result _Result; -typedef struct _Result _CategorisedResult; -typedef struct _SearchMetadata _SearchMetadata; -typedef struct _ActionMetadata _ActionMetadata; -typedef struct _ScopeMetadata _ScopeMetadata; -typedef struct _QueryMetadata _QueryMetadata; -typedef struct _ColumnLayout _ColumnLayout; -typedef struct _ChildScope _ChildScope; -typedef void _ScopeBase; -typedef struct _GoString _GoString; - -typedef struct _ActivationResponse _ActivationResponse; - -void run_scope(const StrData scope_name, const StrData runtime_config, - const StrData scope_config, void *pointer_to_iface, - char **error); - -/* ScopeBase objects */ -char *scope_base_scope_directory(_ScopeBase *scope); -char *scope_base_cache_directory(_ScopeBase *scope); -char *scope_base_tmp_directory(_ScopeBase *scope); -void *scope_base_settings(_ScopeBase *scope, int *length); -_ScopeMetadata **list_registry_scopes_metadata(_ScopeBase *scope, int *n_scopes); -_ChildScope **list_child_scopes(_ScopeBase *scope, int *n_scopes); - -/* ChildScope objects */ -_ChildScope *new_child_scope(const StrData id, _ScopeMetadata *metadata, int enabled, const StrData keyword_list); -void destroy_child_scope(_ChildScope *childscope); -char *child_scope_get_id(_ChildScope *childscope); -void set_child_scopes_list(void *child_scopes_list, _ChildScope **source_child_scopes, int length); - -/* SearchReply objects */ -void init_search_reply_ptr(SharedPtrData dest, SharedPtrData src); -void destroy_search_reply_ptr(SharedPtrData data); - -void search_reply_finished(SharedPtrData reply); -void search_reply_error(SharedPtrData reply, const StrData err_string); -void search_reply_register_category(SharedPtrData reply, const StrData id, const StrData title, const StrData icon, const StrData cat_template, SharedPtrData category); -void search_reply_register_departments(SharedPtrData reply, SharedPtrData dept); -void search_reply_push(SharedPtrData reply, _CategorisedResult *result, char **error); -void search_reply_push_filters(SharedPtrData reply, const StrData filters_json, const StrData filter_state_json, char **error); - -/* PreviewReply objects */ -void init_preview_reply_ptr(SharedPtrData dest, SharedPtrData src); -void destroy_preview_reply_ptr(SharedPtrData data); - -void preview_reply_finished(SharedPtrData reply); -void preview_reply_error(SharedPtrData reply, const StrData err_string); -void preview_reply_push_widgets(SharedPtrData reply, const StrData widget_list, char **error); -void preview_reply_push_attr(SharedPtrData reply, const StrData key, const StrData json_value, char **error); -void preview_reply_register_layout(SharedPtrData reply, _ColumnLayout **layout, int n_items, char **error); - -/* CannedQuery objects */ -void destroy_canned_query(_CannedQuery *query); -_CannedQuery *new_canned_query(const StrData scope_id, const StrData query_str, const StrData department_id); -char *canned_query_get_scope_id(_CannedQuery *query); -char *canned_query_get_department_id(_CannedQuery *query); -char *canned_query_get_query_string(_CannedQuery *query); -void *canned_query_get_filter_state(_CannedQuery *query, int *length); -void canned_query_set_department_id(_CannedQuery *query, const StrData department_id); -void canned_query_set_query_string(_CannedQuery *query, const StrData query_str); -char *canned_query_to_uri(_CannedQuery *query); - -/* Category objects */ -void destroy_category_ptr(SharedPtrData data); - -/* CategorisedResult objects */ -_Result *new_categorised_result(SharedPtrData category); -void destroy_result(_Result *res); - -/* Result objects */ -void *result_get_attr(_Result *res, const StrData attr, int *length, char **error); -void result_set_attr(_Result *res, const StrData attr, const StrData json_value, char **error); -void result_set_intercept_activation(_Result *res); - -/* Department objects */ -void init_department_ptr(SharedPtrData dest, SharedPtrData src); -void new_department(const StrData deptt_id, _CannedQuery *query, const StrData label, SharedPtrData dept, char **error); -void destroy_department_ptr(SharedPtrData data); -void department_add_subdepartment(SharedPtrData dept, SharedPtrData child); -void department_set_alternate_label(SharedPtrData dept, const StrData label); -char *department_get_alternate_label(SharedPtrData dept); -char *department_get_id(SharedPtrData dept); -char *department_get_label(SharedPtrData dept); -void department_set_has_subdepartments(SharedPtrData dept, int subdepartments); -int department_has_subdepartments(SharedPtrData dept); -//void department_get_subdepartments(SharedPtrData dept, SharedPtrData **ret_data); -SharedPtrData * department_get_subdepartments(SharedPtrData dept, int *n_subdepts); -void department_set_subdepartments(SharedPtrData dept, SharedPtrData *subdepartments, int nb_subdepartments); -_CannedQuery * department_get_query(SharedPtrData dept); - -/* QueryMetadata objects */ -char *query_metadata_get_locale(_QueryMetadata *metadata); -char *query_metadata_get_form_factor(_QueryMetadata *metadata); -void query_metadata_set_internet_connectivity(_QueryMetadata *metadata, int status); -int query_metadata_get_internet_connectivity(_QueryMetadata *metadata); - -/* SearchMetadata objects */ -_SearchMetadata *new_search_metadata(int cardinality, const StrData locale, const StrData form_factor); -void destroy_search_metadata(_SearchMetadata *metadata); -int search_metadata_get_cardinality(_SearchMetadata *metadata); -void *search_metadata_get_location(_SearchMetadata *metadata, int *length); -void search_metadata_set_location(_SearchMetadata *metadata, char *json_data, int json_data_length, char **error); -void search_metadata_set_aggregated_keywords(_SearchMetadata *metadata, const StrData keyword_list, char **error); -void *search_metadata_get_aggregated_keywords(_SearchMetadata *metadata, int *length); -int search_metadata_is_aggregated(_SearchMetadata *metadata); - -/* ActionMetadata objects */ -_ActionMetadata *new_action_metadata(const StrData locale, const StrData form_factor); -void destroy_action_metadata(_ActionMetadata *metadata); -void *action_metadata_get_scope_data(_ActionMetadata *metadata, int *data_length); -void action_metadata_set_scope_data(_ActionMetadata *metadata, char *json_data, int json_data_length, char **error); -void action_metadata_set_hint(_ActionMetadata *metadata, const StrData key, char *json_data, int json_data_length, char **error); -void *action_metadata_get_hint(_ActionMetadata *metadata, const StrData key, int *data_length, char **error); -void *action_metadata_get_hints(_ActionMetadata *metadata, int *length); - -/* ScopeMetadata objects */ -void destroy_scope_metadata_ptr(_ScopeMetadata *metadata); -char *get_scope_metadata_serialized(_ScopeMetadata *metadata); - -/* ActivationResponse objects */ -void activation_response_init_status(_ActivationResponse *response, int status); -void activation_response_init_query(_ActivationResponse *response, _CannedQuery *query); -void activation_response_init_update_result(_ActivationResponse *response, _Result *result); -void activation_response_init_update_preview(_ActivationResponse *response, const StrData widget_list, char **error); -void activation_response_set_scope_data(_ActivationResponse *response, char *json_data, int json_data_length, char **error); - -/* ColumnLayout objects */ -_ColumnLayout *new_column_layout(int num_columns); -void destroy_column_layout(_ColumnLayout *layout); -void column_layout_add_column(_ColumnLayout *layout, const StrData widget_list, char **error); -int column_layout_number_of_columns(_ColumnLayout *layout); -int column_layout_size(_ColumnLayout *layout); -void *column_layout_column(_ColumnLayout *layout, int column, int *n_items, char **error); - - -/* Helpers for tests */ -_Result *new_testing_result(void); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/vendor/launchpad.net/go-unityscopes/v2/smartptr_helper.h b/vendor/launchpad.net/go-unityscopes/v2/smartptr_helper.h deleted file mode 100644 index fde2198..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/smartptr_helper.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef UNITYSCOPE_SMARTPTR_HELPER_H -#define UNITYSCOPE_SMARTPTR_HELPER_H - -#include <memory> - -#include "shim.h" - -namespace gounityscopes { -namespace internal { - -template<typename T> inline void init_const_ptr(SharedPtrData data, std::shared_ptr<T const> v) { - typedef std::shared_ptr<T const> Ptr; - static_assert(sizeof(SharedPtrData) >= sizeof(Ptr), - "std::shared_ptr is larger than expected"); - Ptr *ptr = new(reinterpret_cast<void*>(data)) Ptr(); - *ptr = v; -} - -template<typename T> inline void init_ptr(SharedPtrData data, std::shared_ptr<T> v) { - typedef std::shared_ptr<T> Ptr; - static_assert(sizeof(SharedPtrData) >= sizeof(Ptr), - "std::shared_ptr is larger than expected"); - Ptr *ptr = new(reinterpret_cast<void*>(data)) Ptr(); - *ptr = v; -} - -template<typename T> inline std::shared_ptr<T> get_ptr(SharedPtrData data) { - typedef std::shared_ptr<T> Ptr; - Ptr *ptr = reinterpret_cast<Ptr*>(data); - return *ptr; -} - -template<typename T> inline void destroy_ptr(SharedPtrData data) { - typedef std::shared_ptr<T> Ptr; - if (!(data[0] == 0 && data[1] == 0)) { - Ptr *ptr = reinterpret_cast<Ptr*>(data); - ptr->~Ptr(); - } - data[0] = data[1] = 0; -} - -template<typename T> inline void copy_ptr(SharedPtrData dest_data, SharedPtrData src_data) { - typedef std::shared_ptr<T> Ptr; - Ptr *dest = reinterpret_cast<Ptr*>(dest_data); - Ptr *src = reinterpret_cast<Ptr*>(src_data); - *dest = *src; -} - -} -} - -#endif diff --git a/vendor/launchpad.net/go-unityscopes/v2/suite_test.go b/vendor/launchpad.net/go-unityscopes/v2/suite_test.go deleted file mode 100644 index 764ec83..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/suite_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package scopes_test - -import ( - "errors" - . "gopkg.in/check.v1" - "testing" -) - -// The following type is used only for testing unserializable cases -type unserializable struct{} - -func (u unserializable) MarshalJSON() ([]byte, error) { - return nil, errors.New("Can not marshal to JSON") -} - -func (u *unserializable) UnmarshalJSON(data []byte) error { - return errors.New("Can not unmarshal from JSON") -} - -type S struct{} - -func init() { - Suite(&S{}) -} - -func TestAll(t *testing.T) { - TestingT(t) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/switch_filter.go b/vendor/launchpad.net/go-unityscopes/v2/switch_filter.go deleted file mode 100644 index d9f7bec..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/switch_filter.go +++ /dev/null @@ -1,40 +0,0 @@ -package scopes - -// SwitchFilter is a simple on/off switch filter. -type SwitchFilter struct { - filterBase - Label string -} - -// NewSwitchFilter creates a new switch filter. -func NewSwitchFilter(id, label string) *SwitchFilter { - return &SwitchFilter{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "switch", - }, - Label: label, - } -} - -func (f *SwitchFilter) IsOn(state FilterState) bool { - value, ok := state[f.Id] - if ok { - return value.(bool) - } else { - return false - } - return true -} - -// UpdateState updates the value of the filter to on/off -func (f *SwitchFilter) UpdateState(state FilterState, value bool) { - state[f.Id] = value -} - -func (f *SwitchFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["label"] = f.Label - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/switch_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/switch_filter_test.go deleted file mode 100644 index 6778878..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/switch_filter_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestSwitchFilter(c *C) { - filter1 := scopes.NewSwitchFilter("f1", "Options") - c.Check("f1", Equals, filter1.Id) - c.Check("Options", Equals, filter1.Label) - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayDefault) - - fstate := make(scopes.FilterState) - c.Check(filter1.IsOn(fstate), Equals, false) - - // set on - filter1.UpdateState(fstate, true) - c.Check(filter1.IsOn(fstate), Equals, true) - - filter1.UpdateState(fstate, true) - filter1.UpdateState(fstate, false) - filter1.UpdateState(fstate, true) - c.Check(filter1.IsOn(fstate), Equals, true) - - filter1.UpdateState(fstate, false) - filter1.UpdateState(fstate, true) - filter1.UpdateState(fstate, false) - c.Check(filter1.IsOn(fstate), Equals, false) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/testing.cpp b/vendor/launchpad.net/go-unityscopes/v2/testing.cpp deleted file mode 100644 index 733a914..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/testing.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include <stdexcept> -#include <cstring> - -#include <unity/scopes/testing/Result.h> - -extern "C" { -#include "_cgo_export.h" -} -#include "helpers.h" - -using namespace unity::scopes; -using namespace gounityscopes::internal; - -_Result *new_testing_result() { - return reinterpret_cast<_Result*>(static_cast<Result*>(new testing::Result)); -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/testing.go b/vendor/launchpad.net/go-unityscopes/v2/testing.go deleted file mode 100644 index b08b82f..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/testing.go +++ /dev/null @@ -1,11 +0,0 @@ -package scopes - -// #include "shim.h" -import "C" - -// These functions are used by tests. They are not part of a -// *_test.go file because they make use of cgo. - -func newTestingResult() *Result { - return makeResult(C.new_testing_result()) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/unityscope.go b/vendor/launchpad.net/go-unityscopes/v2/unityscope.go deleted file mode 100644 index d75ac84..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/unityscope.go +++ /dev/null @@ -1,285 +0,0 @@ -package scopes - -/* -#cgo CXXFLAGS: -std=c++11 -Wall -#cgo pkg-config: libunity-scopes -#include <stdlib.h> -#include "shim.h" -*/ -import "C" -import ( - "encoding/json" - "errors" - "flag" - "path" - "strings" - "sync" - "unsafe" -) - -func checkError(errorString *C.char) (err error) { - if errorString != nil { - err = errors.New(C.GoString(errorString)) - C.free(unsafe.Pointer(errorString)) - } - return -} - -// Category represents a search result category. -type Category struct { - c C.SharedPtrData -} - -func finalizeCategory(cat *Category) { - C.destroy_category_ptr(&cat.c[0]) -} - -// Scope defines the interface that scope implementations must implement -type Scope interface { - SetScopeBase(base *ScopeBase) - Search(query *CannedQuery, metadata *SearchMetadata, reply *SearchReply, cancelled <-chan bool) error - Preview(result *Result, metadata *ActionMetadata, reply *PreviewReply, cancelled <-chan bool) error -} - -type AggregatedScope interface { - Scope - FindChildScopes() []*ChildScope -} - -// Activator is an interface that should be implemented by scopes that -// need to handle result activation directly. -type Activator interface { - Scope - Activate(result *Result, metadata *ActionMetadata) (*ActivationResponse, error) -} - -// PerformActioner is an interface that should be implemented by -// scopes that need to handle preview actions directly. -type PerformActioner interface { - Scope - PerformAction(result *Result, metadata *ActionMetadata, widgetId, actionId string) (*ActivationResponse, error) -} - -//export callScopeSearch -func callScopeSearch(scope Scope, queryPtr, metadataPtr unsafe.Pointer, replyData *C.uintptr_t, cancel <-chan bool) { - query := makeCannedQuery((*C._CannedQuery)(queryPtr)) - metadata := makeSearchMetadata((*C._SearchMetadata)(metadataPtr)) - reply := makeSearchReply(replyData) - - go func() { - err := scope.Search(query, metadata, reply, cancel) - if err != nil { - reply.Error(err) - return - } - reply.Finished() - }() -} - -//export callScopePreview -func callScopePreview(scope Scope, resultPtr, metadataPtr unsafe.Pointer, replyData *C.uintptr_t, cancel <-chan bool) { - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - reply := makePreviewReply(replyData) - - go func() { - err := scope.Preview(result, metadata, reply, cancel) - if err != nil { - reply.Error(err) - return - } - reply.Finished() - }() -} - -//export callScopeActivate -func callScopeActivate(scope Scope, resultPtr, metadataPtr, responsePtr unsafe.Pointer, errorPtr **C.char) { - switch s := scope.(type) { - case Activator: - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - response, err := s.Activate(result, metadata) - if err == nil { - err = response.update((*C._ActivationResponse)(responsePtr)) - } - if err != nil { - *errorPtr = C.CString(err.Error()) - } - default: - // nothing - } -} - -//export callFindChildScopes -func callFindChildScopes(scope Scope, childScopeList unsafe.Pointer) { - switch s := scope.(type) { - case AggregatedScope: - go_child_scopes := s.FindChildScopes() - child_scopes := make([]*C._ChildScope, len(go_child_scopes)) - for index, child_scope := range go_child_scopes { - child_scopes[index] = child_scope.c - } - C.set_child_scopes_list(childScopeList, &child_scopes[0], (C.int)(len(go_child_scopes))) - default: - // nothing - } -} - -//export callScopePerformAction -func callScopePerformAction(scope Scope, resultPtr, metadataPtr unsafe.Pointer, widgetId, actionId *C.char, responsePtr unsafe.Pointer, errorPtr **C.char) { - switch s := scope.(type) { - case PerformActioner: - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - response, err := s.PerformAction(result, metadata, C.GoString(widgetId), C.GoString(actionId)) - if err == nil { - err = response.update((*C._ActivationResponse)(responsePtr)) - } - if err != nil { - *errorPtr = C.CString(err.Error()) - } - default: - // nothing - } -} - -var ( - runtimeConfig = flag.String("runtime", "", "The runtime configuration file for the Unity Scopes library") - scopeConfig = flag.String("scope", "", "The scope configuration file for the Unity Scopes library") -) - -// ScopeBase exposes information about the scope including settings -// and various directories available for use. -type ScopeBase struct { - b unsafe.Pointer -} - -//export setScopeBase -func setScopeBase(scope Scope, b unsafe.Pointer) { - if b == nil { - scope.SetScopeBase(nil) - } else { - scope.SetScopeBase(&ScopeBase{b}) - } -} - -// ScopeDirectory returns the directory where the scope has been installed -func (b *ScopeBase) ScopeDirectory() string { - dir := C.scope_base_scope_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// CacheDirectory returns a directory the scope can use to store cache files -func (b *ScopeBase) CacheDirectory() string { - dir := C.scope_base_cache_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// TmpDirectory returns a directory the scope can use to store temporary files -func (b *ScopeBase) TmpDirectory() string { - dir := C.scope_base_tmp_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// ListRegistryScopes lists all the scopes existing in the registry -func (b *ScopeBase) ListRegistryScopes() map[string]*ScopeMetadata { - var nb_scopes C.int - var c_array **C._ScopeMetadata = C.list_registry_scopes_metadata(b.b, &nb_scopes) - defer C.free(unsafe.Pointer(c_array)) - - length := int(nb_scopes) - // create a very big slice and then slice it to the number of scopes metadata - slice := (*[1 << 27]*C._ScopeMetadata)(unsafe.Pointer(c_array))[:length:length] - var scopesList = make(map[string]*ScopeMetadata) - - for i := 0; i < length; i++ { - json_data := C.get_scope_metadata_serialized(slice[i]) - defer C.free(unsafe.Pointer(json_data)) - - metadata := makeScopeMetadata(slice[i], C.GoString(json_data)) - scopesList[metadata.ScopeId] = metadata - } - - return scopesList -} - -// ChildScopes list all the child scopes -func (b *ScopeBase) ChildScopes() []*ChildScope { - var nb_scopes C.int - var c_array **C._ChildScope = C.list_child_scopes(b.b, &nb_scopes) - defer C.free(unsafe.Pointer(c_array)) - - length := int(nb_scopes) - // create a very big slice and then slice it to the number of scopes metadata - slice := (*[1 << 27]*C._ChildScope)(unsafe.Pointer(c_array))[:length:length] - child_scopes := make([]*ChildScope, length) - - for i := 0; i < length; i++ { - child_scope := makeChildScope(slice[i]) - child_scopes[i] = child_scope - } - - return child_scopes -} - -// Settings returns the scope's settings. The settings will be -// decoded into the given value according to the same rules used by -// json.Unmarshal(). -func (b *ScopeBase) Settings(value interface{}) error { - var length C.int - data := C.scope_base_settings(b.b, &length) - defer C.free(data) - return json.Unmarshal(C.GoBytes(data, length), value) -} - -/* -Run will initialise the scope runtime and make a scope availble. It -is intended to be called from the program's main function, and will -run until the program exits. -*/ -func Run(scope Scope) error { - if !flag.Parsed() { - flag.Parse() - } - if *scopeConfig == "" { - return errors.New("Scope configuration file not set on command line") - } - base := path.Base(*scopeConfig) - if !strings.HasSuffix(base, ".ini") { - return errors.New("Scope configuration file does not end in '.ini'") - } - scopeId := base[:len(base)-len(".ini")] - - var errorString *C.char - C.run_scope(strData(scopeId), strData(*runtimeConfig), strData(*scopeConfig), unsafe.Pointer(&scope), &errorString) - return checkError(errorString) -} - -var ( - cancelChannels = make(map[chan bool]bool) - cancelChannelsLock sync.Mutex -) - -//export makeCancelChannel -func makeCancelChannel() chan bool { - ch := make(chan bool, 1) - cancelChannelsLock.Lock() - cancelChannels[ch] = true - cancelChannelsLock.Unlock() - return ch -} - -//export sendCancelChannel -func sendCancelChannel(ch chan bool) { - ch <- true -} - -//export releaseCancelChannel -func releaseCancelChannel(ch chan bool) { - cancelChannelsLock.Lock() - delete(cancelChannels, ch) - cancelChannelsLock.Unlock() -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/unityscope.go~ b/vendor/launchpad.net/go-unityscopes/v2/unityscope.go~ deleted file mode 100644 index d75ac84..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/unityscope.go~ +++ /dev/null @@ -1,285 +0,0 @@ -package scopes - -/* -#cgo CXXFLAGS: -std=c++11 -Wall -#cgo pkg-config: libunity-scopes -#include <stdlib.h> -#include "shim.h" -*/ -import "C" -import ( - "encoding/json" - "errors" - "flag" - "path" - "strings" - "sync" - "unsafe" -) - -func checkError(errorString *C.char) (err error) { - if errorString != nil { - err = errors.New(C.GoString(errorString)) - C.free(unsafe.Pointer(errorString)) - } - return -} - -// Category represents a search result category. -type Category struct { - c C.SharedPtrData -} - -func finalizeCategory(cat *Category) { - C.destroy_category_ptr(&cat.c[0]) -} - -// Scope defines the interface that scope implementations must implement -type Scope interface { - SetScopeBase(base *ScopeBase) - Search(query *CannedQuery, metadata *SearchMetadata, reply *SearchReply, cancelled <-chan bool) error - Preview(result *Result, metadata *ActionMetadata, reply *PreviewReply, cancelled <-chan bool) error -} - -type AggregatedScope interface { - Scope - FindChildScopes() []*ChildScope -} - -// Activator is an interface that should be implemented by scopes that -// need to handle result activation directly. -type Activator interface { - Scope - Activate(result *Result, metadata *ActionMetadata) (*ActivationResponse, error) -} - -// PerformActioner is an interface that should be implemented by -// scopes that need to handle preview actions directly. -type PerformActioner interface { - Scope - PerformAction(result *Result, metadata *ActionMetadata, widgetId, actionId string) (*ActivationResponse, error) -} - -//export callScopeSearch -func callScopeSearch(scope Scope, queryPtr, metadataPtr unsafe.Pointer, replyData *C.uintptr_t, cancel <-chan bool) { - query := makeCannedQuery((*C._CannedQuery)(queryPtr)) - metadata := makeSearchMetadata((*C._SearchMetadata)(metadataPtr)) - reply := makeSearchReply(replyData) - - go func() { - err := scope.Search(query, metadata, reply, cancel) - if err != nil { - reply.Error(err) - return - } - reply.Finished() - }() -} - -//export callScopePreview -func callScopePreview(scope Scope, resultPtr, metadataPtr unsafe.Pointer, replyData *C.uintptr_t, cancel <-chan bool) { - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - reply := makePreviewReply(replyData) - - go func() { - err := scope.Preview(result, metadata, reply, cancel) - if err != nil { - reply.Error(err) - return - } - reply.Finished() - }() -} - -//export callScopeActivate -func callScopeActivate(scope Scope, resultPtr, metadataPtr, responsePtr unsafe.Pointer, errorPtr **C.char) { - switch s := scope.(type) { - case Activator: - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - response, err := s.Activate(result, metadata) - if err == nil { - err = response.update((*C._ActivationResponse)(responsePtr)) - } - if err != nil { - *errorPtr = C.CString(err.Error()) - } - default: - // nothing - } -} - -//export callFindChildScopes -func callFindChildScopes(scope Scope, childScopeList unsafe.Pointer) { - switch s := scope.(type) { - case AggregatedScope: - go_child_scopes := s.FindChildScopes() - child_scopes := make([]*C._ChildScope, len(go_child_scopes)) - for index, child_scope := range go_child_scopes { - child_scopes[index] = child_scope.c - } - C.set_child_scopes_list(childScopeList, &child_scopes[0], (C.int)(len(go_child_scopes))) - default: - // nothing - } -} - -//export callScopePerformAction -func callScopePerformAction(scope Scope, resultPtr, metadataPtr unsafe.Pointer, widgetId, actionId *C.char, responsePtr unsafe.Pointer, errorPtr **C.char) { - switch s := scope.(type) { - case PerformActioner: - result := makeResult((*C._Result)(resultPtr)) - metadata := makeActionMetadata((*C._ActionMetadata)(metadataPtr)) - response, err := s.PerformAction(result, metadata, C.GoString(widgetId), C.GoString(actionId)) - if err == nil { - err = response.update((*C._ActivationResponse)(responsePtr)) - } - if err != nil { - *errorPtr = C.CString(err.Error()) - } - default: - // nothing - } -} - -var ( - runtimeConfig = flag.String("runtime", "", "The runtime configuration file for the Unity Scopes library") - scopeConfig = flag.String("scope", "", "The scope configuration file for the Unity Scopes library") -) - -// ScopeBase exposes information about the scope including settings -// and various directories available for use. -type ScopeBase struct { - b unsafe.Pointer -} - -//export setScopeBase -func setScopeBase(scope Scope, b unsafe.Pointer) { - if b == nil { - scope.SetScopeBase(nil) - } else { - scope.SetScopeBase(&ScopeBase{b}) - } -} - -// ScopeDirectory returns the directory where the scope has been installed -func (b *ScopeBase) ScopeDirectory() string { - dir := C.scope_base_scope_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// CacheDirectory returns a directory the scope can use to store cache files -func (b *ScopeBase) CacheDirectory() string { - dir := C.scope_base_cache_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// TmpDirectory returns a directory the scope can use to store temporary files -func (b *ScopeBase) TmpDirectory() string { - dir := C.scope_base_tmp_directory(b.b) - defer C.free(unsafe.Pointer(dir)) - return C.GoString(dir) -} - -// ListRegistryScopes lists all the scopes existing in the registry -func (b *ScopeBase) ListRegistryScopes() map[string]*ScopeMetadata { - var nb_scopes C.int - var c_array **C._ScopeMetadata = C.list_registry_scopes_metadata(b.b, &nb_scopes) - defer C.free(unsafe.Pointer(c_array)) - - length := int(nb_scopes) - // create a very big slice and then slice it to the number of scopes metadata - slice := (*[1 << 27]*C._ScopeMetadata)(unsafe.Pointer(c_array))[:length:length] - var scopesList = make(map[string]*ScopeMetadata) - - for i := 0; i < length; i++ { - json_data := C.get_scope_metadata_serialized(slice[i]) - defer C.free(unsafe.Pointer(json_data)) - - metadata := makeScopeMetadata(slice[i], C.GoString(json_data)) - scopesList[metadata.ScopeId] = metadata - } - - return scopesList -} - -// ChildScopes list all the child scopes -func (b *ScopeBase) ChildScopes() []*ChildScope { - var nb_scopes C.int - var c_array **C._ChildScope = C.list_child_scopes(b.b, &nb_scopes) - defer C.free(unsafe.Pointer(c_array)) - - length := int(nb_scopes) - // create a very big slice and then slice it to the number of scopes metadata - slice := (*[1 << 27]*C._ChildScope)(unsafe.Pointer(c_array))[:length:length] - child_scopes := make([]*ChildScope, length) - - for i := 0; i < length; i++ { - child_scope := makeChildScope(slice[i]) - child_scopes[i] = child_scope - } - - return child_scopes -} - -// Settings returns the scope's settings. The settings will be -// decoded into the given value according to the same rules used by -// json.Unmarshal(). -func (b *ScopeBase) Settings(value interface{}) error { - var length C.int - data := C.scope_base_settings(b.b, &length) - defer C.free(data) - return json.Unmarshal(C.GoBytes(data, length), value) -} - -/* -Run will initialise the scope runtime and make a scope availble. It -is intended to be called from the program's main function, and will -run until the program exits. -*/ -func Run(scope Scope) error { - if !flag.Parsed() { - flag.Parse() - } - if *scopeConfig == "" { - return errors.New("Scope configuration file not set on command line") - } - base := path.Base(*scopeConfig) - if !strings.HasSuffix(base, ".ini") { - return errors.New("Scope configuration file does not end in '.ini'") - } - scopeId := base[:len(base)-len(".ini")] - - var errorString *C.char - C.run_scope(strData(scopeId), strData(*runtimeConfig), strData(*scopeConfig), unsafe.Pointer(&scope), &errorString) - return checkError(errorString) -} - -var ( - cancelChannels = make(map[chan bool]bool) - cancelChannelsLock sync.Mutex -) - -//export makeCancelChannel -func makeCancelChannel() chan bool { - ch := make(chan bool, 1) - cancelChannelsLock.Lock() - cancelChannels[ch] = true - cancelChannelsLock.Unlock() - return ch -} - -//export sendCancelChannel -func sendCancelChannel(ch chan bool) { - ch <- true -} - -//export releaseCancelChannel -func releaseCancelChannel(ch chan bool) { - cancelChannelsLock.Lock() - delete(cancelChannels, ch) - cancelChannelsLock.Unlock() -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter.go b/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter.go deleted file mode 100644 index 01a5582..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter.go +++ /dev/null @@ -1,108 +0,0 @@ -package scopes - -import ( - "errors" - "fmt" -) - -// ValueSliderFilter is a value slider filter that allows for selecting a value within a given range. -type ValueSliderFilter struct { - filterBase - DefaultValue float64 - Min float64 - Max float64 - Labels ValueSliderLabels -} - -type ValueSliderLabels struct { - MinLabel string - MaxLabel string - ExtraLabels []ValueSliderExtraLabel -} - -type ValueSliderExtraLabel struct { - Value float64 - Label string -} - -// NewValueSliderFilter creates a new value slider filter. -func NewValueSliderFilter(id string, min, max, defaultValue float64, labels ValueSliderLabels) *ValueSliderFilter { - filter := &ValueSliderFilter{ - filterBase: filterBase{ - Id: id, - DisplayHints: FilterDisplayDefault, - FilterType: "value_slider", - }, - Min: min, - Max: max, - DefaultValue: defaultValue, - Labels: labels, - } - filter.validate() - return filter -} - -func (f *ValueSliderFilter) validate() { - if f.Min >= f.Max { - panic("Invalid range for value slider filter") - } - last := f.Min - labels := map[string]bool{ - f.Labels.MinLabel: true, - f.Labels.MaxLabel: true, - } - // check that values of extra labels grow, i.e. v1 < v2 < v3 ... - // and labels are unique and not empty - for _, l := range f.Labels.ExtraLabels { - if l.Value <= last { - panic("Extra label for value slider filter out of sequence") - } - last = l.Value - if l.Label == "" { - panic("Extra labels cannot be empty") - } - if labels[l.Label] { - panic("Multiple definitions for extra label") - } - labels[l.Label] = true - } - if f.Max <= last { - panic("Last extra label value greater than maximum value") - } -} - -// Value gets value of this filter from filter state object. -// If the value is not set for the filter it returns false as the second return statement, -// it returns true otherwise -func (f *ValueSliderFilter) Value(state FilterState) float64 { - if value, ok := state[f.Id].(float64); ok { - return value - } - return f.DefaultValue -} - -// UpdateState updates the value of the filter to the given value -func (f *ValueSliderFilter) UpdateState(state FilterState, value float64) error { - if value < f.Min || value > f.Max { - return errors.New(fmt.Sprintf("ValueSliderFilter:UpdateState: value %f outside of allowed range (%f,%f)", value, f.Min, f.Max)) - } - state[f.Id] = value - return nil -} - -func (f *ValueSliderFilter) serializeFilter() map[string]interface{} { - v := f.filterBase.serializeFilter() - v["min"] = marshalFloat(f.Min) - v["max"] = marshalFloat(f.Max) - v["default"] = marshalFloat(f.DefaultValue) - extra := make([]interface{}, 0, 2*len(f.Labels.ExtraLabels)) - for _, l := range f.Labels.ExtraLabels { - extra = append(extra, marshalFloat(l.Value), l.Label) - } - v["labels"] = map[string]interface{}{ - "min_label": f.Labels.MinLabel, - "max_label": f.Labels.MaxLabel, - "extra_labels": extra, - } - return v -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter_test.go b/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter_test.go deleted file mode 100644 index 0247e32..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/value_slider_filter_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package scopes_test - -import ( - . "gopkg.in/check.v1" - "launchpad.net/go-unityscopes/v2" -) - -func (s *S) TestValueSliderFilter(c *C) { - labels := scopes.ValueSliderLabels{ - MinLabel: "min", - MaxLabel: "max", - ExtraLabels: []scopes.ValueSliderExtraLabel{ - {50, "middle"}, - }, - } - filter1 := scopes.NewValueSliderFilter("f1", 10.0, 100.0, 50, labels) - c.Check("f1", Equals, filter1.Id) - c.Check(filter1.DisplayHints, Equals, scopes.FilterDisplayDefault) - c.Check(filter1.DefaultValue, Equals, 50.0) - c.Check(filter1.Min, Equals, 10.0) - c.Check(filter1.Max, Equals, 100.0) - c.Check(filter1.Labels, DeepEquals, labels) - - fstate := make(scopes.FilterState) - value := filter1.Value(fstate) - c.Check(value, Equals, 50.0) - - err := filter1.UpdateState(fstate, 30.5) - c.Check(err, IsNil) - value = filter1.Value(fstate) - c.Check(value, Equals, 30.5) - - err = filter1.UpdateState(fstate, 44.5) - c.Check(err, IsNil) - value = filter1.Value(fstate) - c.Check(value, Equals, 44.5) - - err = filter1.UpdateState(fstate, 3545.33) - c.Check(err, Not(Equals), nil) - value = filter1.Value(fstate) - c.Check(value, Equals, 44.5) -} diff --git a/vendor/launchpad.net/go-unityscopes/v2/version.h b/vendor/launchpad.net/go-unityscopes/v2/version.h deleted file mode 100644 index e53454f..0000000 --- a/vendor/launchpad.net/go-unityscopes/v2/version.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef UNITYSCOPE_GO_VERSION_H -#define UNITYSCOPE_GO_VERSION_H - -#include <unity/scopes/Version.h> - -// check that we have a compatible version of lib-unityscopes installed -static_assert(UNITY_SCOPES_VERSION_MAJOR > 0 || - (UNITY_SCOPES_VERSION_MAJOR == 0 && (UNITY_SCOPES_VERSION_MINOR > 6 || (UNITY_SCOPES_VERSION_MINOR == 6 && UNITY_SCOPES_VERSION_MICRO >= 15))), - "Version of Unity scopes API mismatch. Minimum required version is 0.6.15."); - -#endif diff --git a/vendor/vendor.json b/vendor/vendor.json index 0a42b88..1ebe499 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,30 +3,6 @@ "ignore": "", "package": [ { - "checksumSHA1": "irOVQufDH3nJExsYR7Sbg3iDj7U=", - "path": "github.com/AlekSi/gocov-xml", - "revision": "d2f6da892a0d5e0b587526abf51349ad654ade51", - "revisionTime": "2013-09-03T17:40:06+04:00" - }, - { - "checksumSHA1": "/XfMgYsMs7fv94SFD6rKtj7uR+M=", - "path": "github.com/axw/gocov", - "revision": "3b045e0eb61013ff134e6752184febc47d119f3a", - "revisionTime": "2014-11-11T18:30:33+08:00" - }, - { - "checksumSHA1": "JFCAqWbFArgsOEontAAV+JnsBeY=", - "path": "github.com/axw/gocov/gocov", - "revision": "3b045e0eb61013ff134e6752184febc47d119f3a", - "revisionTime": "2014-11-11T18:30:33+08:00" - }, - { - "checksumSHA1": "ms9JKYBjHnxRYsJRRkR8M/Zm81o=", - "path": "github.com/axw/gocov/gocovutil", - "revision": "3b045e0eb61013ff134e6752184febc47d119f3a", - "revisionTime": "2014-11-11T18:30:33+08:00" - }, - { "checksumSHA1": "wVSf1UQTGka3kJLXGuJgc1FciCc=", "path": "github.com/dustin/go-humanize", "revision": "c128122e0b9b93799aef8181a537e5d8fd7081d6", @@ -43,18 +19,6 @@ "path": "github.com/godbus/dbus/introspect", "revision": "25c3068a42a0b50b877953fb249dbcffc6bd1bca", "revisionTime": "2015-07-29T16:15:27-07:00" - }, - { - "checksumSHA1": "D6kd4vJPfoBDgNvV+Tw79pxLUq4=", - "path": "golang.org/x/tools/cover", - "revision": "af817890aa7b628234075a6cb01a3a435fb8317d", - "revisionTime": "2015-06-17T17:25:35-07:00" - }, - { - "checksumSHA1": "wRxu5fLESE73JcO4A5B9BXaRBl8=", - "path": "launchpad.net/go-unityscopes/v2", - "revision": "74", - "revisionTime": "2016-10-03T20:26:39Z" } ], "rootPath": "launchpad.net/unity-scope-snappy" diff --git a/webdm/client.go b/webdm/client.go deleted file mode 100644 index 4d54fa6..0000000 --- a/webdm/client.go +++ /dev/null @@ -1,325 +0,0 @@ -package webdm - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "net/url" -) - -const ( - // Where webdm is listening - DefaultApiUrl = "http://localhost:4200" - - // User-agent to use when communicating with webdm API - defaultUserAgent = "unity-scope-snappy" - - // webdm default icon path - apiDefaultIconPath = "/public/images/default-package-icon.svg" - - // webdm API path to use for package-specific requests (e.g. list, query, - // install, etc.) - apiPackagesPath = "/api/v2/packages/" -) - -// Client is the main struct allowing for communication with the webdm API. -type Client struct { - // Actual HTTP client for communicating with the webdm API - client *http.Client - - // Base URL for API requests - BaseUrl *url.URL - - // User agent used when communicating with the API - UserAgent string -} - -// NewClient creates a new client for communicating with the webdm API -// -// Parameters: -// apiUrl: URL where WebDM is listening (host[:port]) -// -// Returns: -// - Pointer to new client -// - Error (nil if none) -func NewClient(apiUrl string) (*Client, error) { - client := new(Client) - client.client = http.DefaultClient - client.UserAgent = defaultUserAgent - - if apiUrl == "" { - apiUrl = DefaultApiUrl - } - - var err error - client.BaseUrl, err = url.Parse(apiUrl) - if err != nil { - return nil, fmt.Errorf("webdm: Error parsing URL \"%s\": %s", apiUrl, err) - } - - return client, nil -} - -// GetInstalledPackages sends an API request for a list of installed packages. -// -// Parameters: -// query: Search query for list. -// -// Returns: -// - Slice of Packags structs -// - Error (nil of none) -func (client *Client) GetInstalledPackages(query string) ([]Package, error) { - packages, err := client.getPackages(query, true) - if err != nil { - return nil, fmt.Errorf("webdm: Error getting installed packages: %s", err) - } - - return packages, nil -} - -// GetStorePackages sends an API request for a list of all packages in the -// store (including installed packages). -// -// Parameters: -// query: Search query for list. -// -// Returns: -// - Slice of Packags structs -// - Error (nil of none) -func (client *Client) GetStorePackages(query string) ([]Package, error) { - packages, err := client.getPackages(query, false) - if err != nil { - return nil, fmt.Errorf("webdm: Error getting store packages: %s", err) - } - - return packages, nil -} - -// Query sends an API request for information on a given snappy package. -// -// Parameters: -// packageId: ID of the package of interest (NOT the name). -// -// Returns: -// - Pointer to resulting Package struct. -// - Error (nil if none) -func (client *Client) Query(packageId string) (*Package, error) { - request, err := client.newRequest("GET", apiPackagesPath+packageId, nil) - if err != nil { - return nil, fmt.Errorf("webdm: Error creating API request: %s", err) - } - - snap := new(Package) - _, err = client.do(request, snap) - if err != nil { - return nil, fmt.Errorf("webdm: Error making API request: %s", err) - } - - snap.IconUrl = client.fixIconUrl(snap.IconUrl) - - return snap, nil -} - -// Install sends an API request for a specific snappy package to be installed. -// -// Parameters: -// packageId: ID of the package to install (NOT the name). -// -// Returns: -// - Error (nil if none). Note that installing a package that is already -// installed is not considered an error. -func (client *Client) Install(packageId string) error { - request, err := client.newRequest("PUT", apiPackagesPath+packageId, nil) - if err != nil { - return fmt.Errorf("webdm: Error creating API request: %s", err) - } - - response, err := client.do(request, nil) - if err != nil { - // This could possibly return a 400, which just means that the package - // is essentially already installed but hasn't yet been refreshed. No - // need to error out if that's the case. - if response == nil || (response.StatusCode != http.StatusBadRequest) { - return fmt.Errorf("webdm: Error making API request: %s", err) - } - } - - return nil -} - -// Uninstall sends an API request for a specific snappy package to be uninstalled. -// -// Parameters: -// packageId: ID of the package to uninstall (NOT the name). -// -// Returns: -// - Error (nil if none). Note that uninstalling a package that is not installed -// is not considered an error. -func (client *Client) Uninstall(packageId string) error { - request, err := client.newRequest("DELETE", apiPackagesPath+packageId, nil) - if err != nil { - return fmt.Errorf("webdm: Error creating API request: %s", err) - } - - response, err := client.do(request, nil) - if err != nil { - // This could possibly return a 400, which just means that the package - // is essentially already uninstalled but hasn't yet been refreshed. No - // need to error out if that's the case. - if response == nil || (response.StatusCode != http.StatusBadRequest) { - return fmt.Errorf("webdm: Error making API request: %s", err) - } - } - - return nil -} - -// getPackages sends a request to the API for a package list. -// -// Parameters: -// query: Search query for list. -// installedOnly: Whether the list should only contain installed packages. -// -// Returns: -// - Slice of Package structs -// - Error (nil if none) -func (client *Client) getPackages(query string, installedOnly bool) ([]Package, error) { - data := url.Values{} - data.Set("q", query) - - if installedOnly { - data.Set("installed_only", "true") - } - - request, err := client.newRequest("GET", apiPackagesPath, data) - if err != nil { - return nil, fmt.Errorf("Error creating API request: %s", err) - } - - var packages []Package - _, err = client.do(request, &packages) - if err != nil { - return nil, fmt.Errorf("Error making API request: %s", err) - } - - for i, thisPackage := range packages { - packages[i].IconUrl = client.fixIconUrl(thisPackage.IconUrl) - } - - return packages, nil -} - -// newRequest creates an API request. -// -// Parameters: -// method: HTTP method (e.g. GET, POST, etc.) -// path: API path relative to BaseUrl -// query: key-values which will be included in the request URL as a query -// -// Returns: -// - Pointer to created HTTP request -// - Error (nil if none) -func (client *Client) newRequest(method string, path string, query url.Values) (*http.Request, error) { - relativeUrl, err := url.Parse(path) - if err != nil { - return nil, fmt.Errorf("Eror parsing path %s: %s", path, err) - } - - requestUrl := client.BaseUrl.ResolveReference(relativeUrl) - - // Create the request. The current webdm API doesn't support bodies - request, err := http.NewRequest(method, requestUrl.String(), nil) - if err != nil { - return nil, fmt.Errorf("Error creating request: %s", err) - } - - request.URL.RawQuery = query.Encode() // Add the desired URL query - - // Add the configured user agent to the request - request.Header.Add("User-Agent", client.UserAgent) - - return request, nil -} - -// do sends an API request. The response is decoded and marshalled into `value`. -// -// Parameters: -// request: HTTP request representing the API call. -// value: Destination of the decoded API response (if the response does not -// successfully decode into this type, it will cause an error). -// -// Returns: -// - Pointer to resulting HTTP response (even upon error) -// - Error (nil if none) -func (client *Client) do(request *http.Request, value interface{}) (*http.Response, error) { - response, err := client.client.Do(request) - if err != nil { - return nil, err - } - - defer response.Body.Close() - - err = checkResponse(response) - if err != nil { - // Return the response in case the caller wants to investigate futher - return response, fmt.Errorf("Error in API response: %s", err) - } - - // Assuming we were given a value, decode into it - if value != nil { - err = json.NewDecoder(response.Body).Decode(value) - if err != nil { - // Still return the response in case the caller is interested - return response, fmt.Errorf("Error decoding response: %s", err) - } - } - - return response, nil -} - -// fixIconUrl checks an icon URL to ensure it's pointing to a valid icon. -// -// Invalid icon URLs can occur in two cases: -// -// 1) The app is installed, in which case the API provides an icon URL -// that is relative to webdm's base URL. -// 2) The icon URL is actually invalid in the store database. -// -// If (1), we can turn it into a valid URL using webdm's base URL. If -// (2), we'll need to use a default icon. -// -// Parameters: -// iconUrlString: Icon URL to be (potentially) fixed. -// -// Returns: -// - Fixed icon URL. Note that if the original didn't need to be fixed, the -// original is returned. -func (client Client) fixIconUrl(iconUrlString string) string { - iconUrl, err := url.Parse(iconUrlString) - if err != nil || (!iconUrl.IsAbs() && iconUrl.Path == "") { - log.Printf("Invalid icon URL: \"%s\", using default", iconUrlString) - - iconUrl, _ = url.Parse(apiDefaultIconPath) - } - - // Note that if the icon URL is already absolute, ResolveReference() won't - // change it. - return client.BaseUrl.ResolveReference(iconUrl).String() -} - -// checkResponse ensures the server response means it's okay to continue. -// -// Parameters: -// response: Response from the server that will be checked. -// -// Returns: -// - Error (nil if none) -func checkResponse(response *http.Response) error { - code := response.StatusCode - if code < 200 || code > 299 { - return fmt.Errorf("Response was %d", code) - } - - return nil -} diff --git a/webdm/client_server_test.go b/webdm/client_server_test.go deleted file mode 100644 index b61c99a..0000000 --- a/webdm/client_server_test.go +++ /dev/null @@ -1,516 +0,0 @@ -package webdm - -import ( - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" -) - -// FakeResponse holds the response from the server -type FakeResponse struct { - Package string // Package name - Message string // The message associated with the package -} - -var ( - // mux is the HTTP request multiplexer used with the test server. - mux *http.ServeMux - - // client is the webdm client being tested. - client *Client - - // server is a test HTTP server used to provide fake API responses. - server *httptest.Server - - // storePackages holds all the packages available in the store - storePackages []Package -) - -// fakeSetup simply sets up a test HTTP server along with a webdm.Client that is -// configured to talk to it. -func fakeSetup() { - // Test server - mux = http.NewServeMux() - server = httptest.NewServer(mux) - - // webdm client configured to use test server - client, _ = NewClient(server.URL) -} - -// setup sets up a test HTTP server along with a webdm.Client that is configured -// to talk to that test server. It then initializes the store and configures -// handlers for the fake API. -func setup(t *testing.T) { - fakeSetup() - - // Setup fake API - initializeStore() - setupHandlers(t) -} - -// setup sets up a test HTTP server along with a webdm.Client that is configured -// to talk to that test server. It then registers a handler for the packages -// API that simply returns a server error (500). -func setupBroken() { - fakeSetup() - - // Handle anything in the packages API, and return a 500. - mux.HandleFunc(apiPackagesPath, - func(writer http.ResponseWriter, request *http.Request) { - http.Error(writer, "Internal Server Error", 500) - }) -} - -// teardown closes the test HTTP server. -func teardown() { - server.Close() -} - -// initializeStore sets up the fake package store to hold a few packages -func initializeStore() { - storePackages = []Package{ - Package{ - Id: "package1", - Name: "package1", - Origin: "foo", - Version: "0.1", - Vendor: "bar", - Description: "baz", - IconUrl: "http://fake", - Status: StatusNotInstalled, - DownloadSize: 123456, - Type: "oem", - }, - Package{ - Id: "package2", - Name: "package2", - Origin: "foo", - Version: "0.1", - Vendor: "bar", - Description: "baz", - IconUrl: "http://fake", - Status: StatusNotInstalled, - DownloadSize: 123456, - Type: "app", - }, - } -} - -// setupHandlers sets up handlers for listing, querying, installing, and -// uninstalling packages. -func setupHandlers(t *testing.T) { - mux.HandleFunc(apiPackagesPath, - func(writer http.ResponseWriter, request *http.Request) { - packageName := request.URL.Path[len(apiPackagesPath):] - - // If no package name was supplied, then list all packages - if packageName == "" { - testMethod(t, request, "GET") - - installedOnly := (request.FormValue("installed_only") == "true") - query := request.FormValue("q") - handlePackageListRequest(t, installedOnly, query, writer) - return - } - - // Try to emulate what WebDM does if the ID is actually another - // resource path: return a 404 - if strings.Contains(packageName, "/") { - http.Error(writer, "404 page not found", http.StatusNotFound) - return - } - - switch request.Method { - case "GET": - handleQueryRequest(t, writer, packageName) - case "PUT": - handleInstallRequest(t, writer, packageName) - case "DELETE": - handleUninstallRequest(t, writer, packageName) - default: // Anything else is an error - t.Error("Unexpected HTTP method: %s", request.Method) - } - }) -} - -// handlePackageListRequest writes the package list into the response as JSON. -// -// Parameters: -// t: Testing handle for any errors that occur. -// installedOnly: Whether the list should only contain installed packages. -// query: Search string. -// writer: Response writer into which the response will be written. -func handlePackageListRequest(t *testing.T, installedOnly bool, query string, writer http.ResponseWriter) { - finishOperations() - - // This is pretty inefficient, but fine for these small sets - packages := make([]Package, 0) - for _, thisPackage := range storePackages { - // This is really poor search support, but we'll only check the query - // against the package IDs for these tests. - if (!installedOnly || thisPackage.Installed()) && - (query == "" || query == thisPackage.Id) { - packages = append(packages, thisPackage) - } - } - - writer.WriteHeader(http.StatusOK) - encoder := json.NewEncoder(writer) - encoder.Encode(packages) - - clearMessages() -} - -// handleQueryRequest writes the information for a specific package into the -// response as JSON. -// -// Parameters: -// t: Testing handle for any errors that occur. -// writer: Response writer into which the response will be written. -// packageId: ID of the package whose information is being requested. -func handleQueryRequest(t *testing.T, writer http.ResponseWriter, packageId string) { - packageAvailable := false - var thisPackage Package - var index int - for index, thisPackage = range storePackages { - if thisPackage.Id == packageId { - packageAvailable = true - break - } - } - - encoder := json.NewEncoder(writer) - - if !packageAvailable { - writer.WriteHeader(http.StatusNotFound) - encoder.Encode(fmt.Sprintf("snappy package not found %s\n", packageId)) - return - } - - storePackages[index].Status = finishedOperation(thisPackage.Status) - - writer.WriteHeader(http.StatusOK) - encoder.Encode(storePackages[index]) - - // Clear this package's message (if any) and resolve any pending operations - storePackages[index].Message = "" -} - -// handleInstallRequest sets a given package as installed and always returns -// a 202. The body will contain different things depending on the status of -// the install. -// -// Parameters: -// t: Testing handle for any errors that occur. -// writer: Response writer into which the response will be written. -// packageId: ID of the package to install -func handleInstallRequest(t *testing.T, writer http.ResponseWriter, packageId string) { - // The real WebDM doesn't seem to care whether or not the package is even - // available. The API always response with either a 202 or a 400, depending - // on whether an install request has already come in for this package. - encoder := json.NewEncoder(writer) - - for index, thisPackage := range storePackages { - if thisPackage.Id == packageId { - message := "Accepted" - if operationPending(thisPackage) { - message = "Operation in progress" - writer.WriteHeader(http.StatusBadRequest) - } else { - writer.WriteHeader(http.StatusAccepted) - } - - fakeResponse := &FakeResponse{ - Package: packageId, - Message: message, - } - - encoder.Encode(fakeResponse) - - storePackages[index].Status = StatusInstalling - break - } - } -} - -// handleUninstallRequest sets a given package as uninstalled -func handleUninstallRequest(t *testing.T, writer http.ResponseWriter, packageId string) { - // The real WebDM doesn't seem to care whether or not the package is even - // available. The API always response with either a 202 or a 400, depending - // on whether an install request has already come in for this package. - encoder := json.NewEncoder(writer) - - for index, thisPackage := range storePackages { - if thisPackage.Id == packageId { - message := "Accepted" - if operationPending(thisPackage) { - message = "Operation in progress" - writer.WriteHeader(http.StatusBadRequest) - } else { - writer.WriteHeader(http.StatusAccepted) - } - - fakeResponse := &FakeResponse{ - Package: packageId, - Message: message, - } - - encoder.Encode(fakeResponse) - - storePackages[index].Status = StatusUninstalling - break - } - } -} - -// testMethod ensures the HTTP method used is the one expected -func testMethod(t *testing.T, request *http.Request, expected string) { - if expected != request.Method { - t.Errorf("Request method was %s, expected %s", request.Method, expected) - } -} - -// operationPending determines if an operation is currently pending on a given -// package. -// -// Parameters: -// snap: The package that will be checked for pending operations. -func operationPending(snap Package) bool { - return snap.Installing() || snap.Uninstalling() -} - -// clearMessages iterates through the store packages, clearing any package -// messages. -func clearMessages() { - for index, _ := range storePackages { - storePackages[index].Message = "" - } -} - -// finishOperations iterates through the store packaging, resolving any pending -// operations. -func finishOperations() { - for index, snap := range storePackages { - storePackages[index].Status = finishedOperation(snap.Status) - } -} - -// finishedOperation converts a given "pending" status into its resolved state. -// -// Parameters: -// status: Status to convert into a resolved state. -// -// Returns: -// - Resolved status. Note that this is just a copy if the `status` parameter -// was not in a pending state. -func finishedOperation(status Status) Status { - switch status { - case StatusInstalling: - return StatusInstalled - case StatusUninstalling: - return StatusNotInstalled - default: - return status - } -} - -// runApiRequest runs the desired API request and decodes the JSON response -// into an interface. -// -// Parameters: -// method: HTTP method to use in request -// path: Path to use for request (relative to server.URL) -// value: Interface into which the response will be decoded. -// -// Returns: -// - Error (nil if none) -func runApiRequest(method string, path string, value interface{}) error { - baseUrl, err := url.Parse(server.URL) - if err != nil { - return fmt.Errorf("Error parsing server URL: %s", err) - } - - relativeUrl, err := url.Parse(path) - if err != nil { - return fmt.Errorf("Error parsing relative path: %s", err) - } - - requestUrl := baseUrl.ResolveReference(relativeUrl).String() - - request, err := http.NewRequest(method, requestUrl, nil) - if err != nil { - return fmt.Errorf("Error creating request: %s", err) - } - - response, err := http.DefaultClient.Do(request) - if err != nil { - return fmt.Errorf("Error making request: %s", err) - } - - defer response.Body.Close() - - if value != nil { - err = json.NewDecoder(response.Body).Decode(value) - if err != nil { - return fmt.Errorf("Error decoding response: %s", err) - } - } - - return nil -} - -// Test that the fake server's search functionality works. -func TestFakeServer_search(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - var packages []Package - err := runApiRequest("GET", apiPackagesPath+"?q=package1", &packages) - if err != nil { - t.Fatalf("Unexpected error searching: %s", err) - } - - if len(packages) != 1 { - t.Fatalf("Got %d results, expected 1", len(packages)) - } - - if packages[0].Id != "package1" { - t.Errorf(`Got package with ID "%s", expected package with id "package1"`, - packages[0].Id) - } -} - -// Test that the fake server clears pending operations upon a query like the -// real server -func TestFakeServer_pendingOperationsQuery(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - response := new(FakeResponse) - - // Request installation of "package1" - err := runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - if response.Message != "Accepted" { - t.Errorf(`Response message was "%s", expected "Accepted"`, response.Message) - } - - // Query "package1." Don't care about the response. - err = runApiRequest("GET", apiPackagesPath+"package1", nil) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - // Request installation of "package1" again - err = runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - // Should be "Accepted" again, since we cleared the pending operation - // with the query. - if response.Message != "Accepted" { - t.Errorf(`Response message was "%s", expected "Accepted"`, response.Message) - } -} - -// Test that the fake server clears pending operations upon a package list like -// the real server -func TestFakeServer_pendingOperationsList(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - response := new(FakeResponse) - - // Request installation of "package1" - err := runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - if response.Message != "Accepted" { - t.Errorf(`Response message was "%s", expected "Accepted"`, response.Message) - } - - // Request package list. Don't care about the response. - err = runApiRequest("GET", apiPackagesPath, nil) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - // Request installation of "package1" again - err = runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - // Should be "Accepted" again, since we cleared the pending operation - // with the package list request. - if response.Message != "Accepted" { - t.Errorf(`Response message was "%s", expected "Accepted"`, response.Message) - } -} - -// Test that the fake server can deal with two requests to install the same -// package. -func TestFakeServer_twoInstallRequests(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - response := new(FakeResponse) - - // Request installation of "package1" - err := runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - if response.Message != "Accepted" { - t.Errorf(`Response message was "%s", expected "Accepted"`, response.Message) - } - - // Request installation of "package1" again - err = runApiRequest("PUT", apiPackagesPath+"package1", response) - if err != nil { - t.Errorf("Unexpected error running API request: %s", err) - } - - if response.Package != "package1" { - t.Errorf(`Response was for package "%s", expected "package1"`, response.Package) - } - - if response.Message != "Operation in progress" { - t.Errorf(`Response message was "%s", expected "Operation in progress"`, response.Message) - } -} diff --git a/webdm/client_test.go b/webdm/client_test.go deleted file mode 100644 index d48b4fc..0000000 --- a/webdm/client_test.go +++ /dev/null @@ -1,660 +0,0 @@ -package webdm - -import ( - "fmt" - "net/http" - "net/url" - "reflect" - "testing" -) - -// Test typical NewClient() usage. -func TestNewClient(t *testing.T) { - client, _ := NewClient("") - - expectedUrl, _ := url.Parse(DefaultApiUrl) - - if client.BaseUrl.Scheme != expectedUrl.Scheme { - t.Errorf("NewClient BaseUrl.Scheme was %s, expected %s", - client.BaseUrl.Scheme, - expectedUrl.Scheme) - } - - if client.BaseUrl.Host != expectedUrl.Host { - t.Errorf("NewClient BaseUrl.Host was %s, expected %s", - client.BaseUrl.Host, - expectedUrl.Host) - } - - if client.UserAgent != defaultUserAgent { - t.Errorf("NewClient UserAgent was %s, expected %s", client.UserAgent, - defaultUserAgent) - } -} - -// Test NewClient() with an invalid API URL. -func TestNewClient_invalidApiUrl(t *testing.T) { - _, err := NewClient(":") - if err == nil { - t.Error("Expected an error to be returned due to invalid URL") - } -} - -// Test typical newRequest() usage. -func TestNewRequest(t *testing.T) { - client, _ := NewClient("") - - data := url.Values{} - data.Set("foo", "bar") - - path := "foo" - - expectedUrl, _ := url.Parse(DefaultApiUrl) - expectedUrl.Path = path - expectedUrl.RawQuery = data.Encode() - - request, _ := client.newRequest("GET", path, data) - - // Ensure URL was expanded correctly, including query data - if request.URL.String() != expectedUrl.String() { - t.Errorf("NewRequest URL was %s, expected %s", request.URL.String(), - expectedUrl.String()) - } - - // Ensure form can access query data - if request.FormValue("foo") != "bar" { - t.Errorf("NewRequest form should include \"foo\"") - } - - // Ensure the user agent is correct - if request.Header.Get("User-Agent") != client.UserAgent { - t.Errorf("NewRequest User-Agent was %s, expected %s", - request.Header.Get("User-Agent"), - client.UserAgent) - } -} - -// Test handling of a bad URL -func TestNewRequest_badUrl(t *testing.T) { - client, _ := NewClient("") - - // Test a bad relative URL first-- ":" is obviously invalid - _, err := client.newRequest("GET", ":", nil) - if err == nil { - t.Error("Expected an error to be returned due to invalid relative URL") - } - - // Now test a bad base URL - client.BaseUrl.Host = "%20" - _, err = client.newRequest("GET", "foo", nil) - if err == nil { - t.Error("Expected an error to be returned due to invalid base URL") - } -} - -// Test typical do() usage. -func TestDo(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - type Body struct { - Foo string - } - - // Setup a handler function to respond to requests to the root url - mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { - testMethod(t, request, "GET") - fmt.Fprint(writer, `{"Foo":"bar"}`) - }) - - request, _ := client.newRequest("GET", "/", nil) - body := new(Body) - client.do(request, body) - - expected := &Body{Foo: "bar"} - if !reflect.DeepEqual(body, expected) { - t.Errorf("Response body was %v, expected %v", body, expected) - } -} - -// Test decoding into incorrect JSON -func TestDo_incorrectJson(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Expect an int, even though the server responds with a string - type BadBody struct { - Foo int - } - - // Setup a handler function to respond to requests to the root url - mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { - testMethod(t, request, "GET") - fmt.Fprint(writer, `{"Foo":"bar"}`) // Respond with a string - }) - - request, _ := client.newRequest("GET", "/", nil) - body := new(BadBody) - _, err := client.do(request, body) - - if err == nil { - t.Errorf("Expected an error due to parsing a string into a int") - } -} - -// Test handling of an HTTP 404 error. -func TestDo_httpError(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Setup a handler function to respond to requests to the root url - mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { - http.Error(writer, "Not Found", 404) - }) - - request, _ := client.newRequest("GET", "/", nil) - _, err := client.do(request, nil) - - if err == nil { - t.Error("Expected an HTTP 404 error") - } -} - -// Test handling of an infinite redirect loop. -func TestDo_redirectLoop(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Setup a handler function to respond to requests to the root url - mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { - http.Redirect(writer, request, "/", http.StatusFound) - }) - - req, _ := client.newRequest("GET", "/", nil) - _, err := client.do(req, nil) - - if err == nil { - t.Error("Expected error to be returned due to redirect loop.") - } -} - -// Test getting packages with an invalid URL -func TestGetPackages_invalidUrl(t *testing.T) { - client.BaseUrl.Host = "%20" - _, err := client.getPackages("", false) - if err == nil { - t.Error("Expected error to be returned due to invalid URL") - } -} - -// Test getting packages from an API that returns an error -func TestGetPackages_invalidResponse(t *testing.T) { - // Run test server - setupBroken() - defer teardown() - - _, err := client.getPackages("", false) - if err == nil { - t.Error("Expected error to be returned due to broken server") - } -} - -// Test querying for only installed packages -func TestGetInstalledPackages(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Set package1 as "installed" - for index, snap := range storePackages { - if snap.Id == "package1" { - storePackages[index].Status = StatusInstalled - } - } - - packages, err := client.GetInstalledPackages("") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - // Expect that only one package will be returned, since only one is - // installed. - if len(packages) != 1 { - // Get out now so we don't use a potentially invalid index later - t.Fatalf("Number of packages: %d, expected: 1", len(packages)) - } - - if packages[0].Id != "package1" { - t.Error("\"package1\" should have been the only package in response") - } -} - -// Test querying for only installed packages with a search parameter -func TestGetInstalledPackages_search(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Set all packages as "installed" - for index, _ := range storePackages { - storePackages[index].Status = StatusInstalled - } - - packages, err := client.GetInstalledPackages("package1") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - // Expect that only one package will be returned, since only one is - // installed. - if len(packages) != 1 { - // Get out now so we don't use a potentially invalid index later - t.Fatalf("Number of packages: %d, expected: 1", len(packages)) - } - - if packages[0].Id != "package1" { - t.Error("\"package1\" should have been the only package in response") - } -} - -// Test querying for only installed packages with a search parameter that can't -// be fulfilled. -func TestGetInstalledPackages_searchFailure(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Set package1 as "installed" - for index, snap := range storePackages { - if snap.Id == "package1" { - storePackages[index].Status = StatusInstalled - } - } - - packages, err := client.GetInstalledPackages("package2") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - if len(packages) > 0 { - t.Errorf("Got %d packages, expected none due to no search results", len(packages)) - } -} - -// Test querying for only installed packages with a server that returns an error -func TestGetInstalledPackages_brokenServer(t *testing.T) { - // Run test server - setupBroken() - defer teardown() - - _, err := client.GetInstalledPackages("") - if err == nil { - t.Error("Expected error to be returned due to broken server") - } -} - -// Test querying for all packages -func TestGetStorePackages(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - packages, err := client.GetStorePackages("") - if err != nil { - t.Error("Error: ", err) - } - - if len(packages) != 2 { - t.Errorf("Number of packages: %d, expected: 2", len(packages)) - } - - foundPackage1 := false - foundPackage2 := false - - // Order is not enforced on the result, so we need to iterate through the - // slice checking each item. - for _, thisPackage := range packages { - if thisPackage.Id == "package1" { - foundPackage1 = true - } - - if thisPackage.Id == "package2" { - foundPackage2 = true - } - } - - if !foundPackage1 { - t.Error("\"package1\" not found within response") - } - - if !foundPackage2 { - t.Error("\"package2\" not found within response") - } -} - -// Test querying for store packages with a search parameter -func TestGetStorePackages_search(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - packages, err := client.GetStorePackages("package1") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - // Expect that only one package will be returned due to query - if len(packages) != 1 { - // Get out now so we don't use a potentially invalid index later - t.Fatalf("Number of packages: %d, expected: 1", len(packages)) - } - - if packages[0].Id != "package1" { - t.Error("\"package1\" should have been the only package in response") - } -} - -// Test querying for store packages with a search parameter that can't be -// fulfilled. -func TestGetStorePackages_searchFailure(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - packages, err := client.GetInstalledPackages("invalid") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - if len(packages) > 0 { - t.Errorf("Got %d packages, expected none due to no search results", len(packages)) - } -} - -// Test querying for all packages with a server that returns an error -func TestGetStorePackages_brokenServer(t *testing.T) { - // Run test server - setupBroken() - defer teardown() - - _, err := client.GetStorePackages("") - if err == nil { - t.Error("Expected error to be returned due to broken server") - } -} - -// Test typical query usage -func TestQuery(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - snap, err := client.Query("package1") - if err != nil { - t.Errorf("Unexpected error: %s", err) - } - - if snap.Id != "package1" { - t.Error("Expected the response to contain \"package1\"") - } -} - -// Testing querying with an invalid URL -func TestQuery_invalidUrl(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - client.BaseUrl.Host = "%20" - _, err := client.Query("foo") - if err == nil { - t.Error("Expected an error due to invalid URL") - } -} - -// Test querying for a non-existing package -func TestQuery_notFound(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - _, err := client.Query("package_not_found") - if err == nil { - t.Error("Expected an error due to unavailable package.") - } -} - -// Test typical package installation -func TestInstall(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Request installation of package "package1" - err := client.Install("package1") - if err != nil { - t.Errorf("Unexpected error while installing: %s", err) - } - - snap, err := client.Query("package1") - if err != nil { - // Make this fatal so we don't dereference NULL later - t.Fatalf("Unexpected error while querying: %s", err) - } - - if !snap.Installed() { - t.Error("Expected package to be installed") - } -} - -// Test installing with an invalid URL -func TestInstall_invalidUrl(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - client.BaseUrl.Host = "%20" - err := client.Install("foo") - if err == nil { - t.Error("Expected an error due to invalid URL") - } -} - -// Test installing with a valid, but incorrect, URL -func TestInstall_incorrectUrl(t *testing.T) { - defer func() { - if recover() != nil { - t.Error("Unexpected panic when attempting install") - } - }() - - // Run test server - setup(t) - defer teardown() - - client.BaseUrl.Host = "foo" - err := client.Install("foo") - if err == nil { - t.Error("Expected an error due to incorrect URL") - } -} - -// Unfortunately we can't test installing a non-existing package, since not -// even WebDM seems to care about that. So we'll test trying to install a -// a package with an invalid ID instead. -func TestInstall_notFound(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // The forward slash should invalidate this request - err := client.Install("foo/bar") - if err == nil { - t.Error("Expected an error due to invalid package ID") - } -} - -// Test that our API doesn't complain if asked to install a package that is -// already installed. -func TestInstall_redundantInstall(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Request installation of package "package1" - err := client.Install("package1") - if err != nil { - t.Errorf("Unexpected error while installing: %s", err) - } - - // Request installation of "package1" again. The WebDM API will complain, - // but ours should handle it. - err = client.Install("package1") - if err != nil { - t.Errorf("Unexpected error while installing again: %s", err) - } -} - -// Test typical package uninstallation -func TestUninstall(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // Set package1 as "installed" - for index, snap := range storePackages { - if snap.Id == "package1" { - storePackages[index].Status = StatusInstalled - } - } - - // Verify that package1 is actually installed - snap, err := client.Query("package1") - if err != nil { - t.Errorf("Unexpected error while querying: %s", err) - } - - if !snap.Installed() { - t.Errorf(`Expected "package1" to be installed`) - } - - // Request that the package be uninstalled - err = client.Uninstall("package1") - if err != nil { - t.Errorf("Unexpected error while uninstalling: %s", err) - } - - snap, err = client.Query("package1") - if err != nil { - t.Errorf("Unexpected error while querying: %s", err) - } - - if !snap.NotInstalled() { - t.Error(`Expected "package1" to be uninstalled`) - } -} - -// Test uninstalling with an invalid URL -func TestUninstall_invalidUrl(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - client.BaseUrl.Host = "%20" - err := client.Uninstall("foo") - if err == nil { - t.Error("Expected an error due to invalid URL") - } -} - -// Test uninstalling with a valid, but incorrect, URL -func TestUninstall_incorrectUrl(t *testing.T) { - defer func() { - if recover() != nil { - t.Error("Unexpected panic when attempting uninstall") - } - }() - - // Run test server - setup(t) - defer teardown() - - client.BaseUrl.Host = "foo" - err := client.Uninstall("foo") - if err == nil { - t.Error("Expected an error due to incorrect URL") - } -} - -// Unfortunately we can't test uninstalling a non-existing package, since not -// even WebDM seems to care about that. So we'll test trying to uninstall a -// a package with an invalid ID instead. -func TestUninstall_notFound(t *testing.T) { - // Run test server - setup(t) - defer teardown() - - // The forward slash should invalidate this request - err := client.Uninstall("foo/bar") - if err == nil { - t.Error("Expected an error due to invalid package ID") - } -} - -// Data for TestFixIconUrl -var fixIconUrlTests = []struct { - baseUrl string - iconUrl string - expectedIconUrl string -}{ - {"http://example.com", "http://icon.com/icon", "http://icon.com/icon"}, - {"http://example.com", "/icon", "http://example.com/icon"}, - {"http://example.com", "", "http://example.com" + apiDefaultIconPath}, -} - -// Test that the icon URL fixer works for our cases -func TestFixIconUrl(t *testing.T) { - for i, test := range fixIconUrlTests { - client, _ = NewClient(test.baseUrl) - fixedUrl := client.fixIconUrl(test.iconUrl) - - if fixedUrl != test.expectedIconUrl { - t.Errorf("Test case %d: Fixed url was %s, expected %s", i, - fixedUrl, test.expectedIconUrl) - } - } -} - -// Data for TestCheckResponse -var checkResponseTests = []struct { - shouldAccept bool - responseCode int -}{ - {true, 200}, // OK - {true, 226}, // Fulfilled request - {false, 122}, // URI too long - {false, 300}, // Redirection -} - -// Test the response checker is only good with 2xx values -func TestCheckResponse(t *testing.T) { - for i, test := range checkResponseTests { - response := &http.Response{StatusCode: test.responseCode} - checkError := checkResponse(response) - if test.shouldAccept { - if checkError != nil { - t.Errorf("Test case %d: Expected %d to be acceptable, got \"%s\"", - i, test.responseCode, checkError) - } - } else { - if checkError == nil { - t.Errorf("Test case %d: Expected %d to cause an error", i, - test.responseCode) - } - } - } -} diff --git a/webdm/package.go b/webdm/package.go deleted file mode 100644 index 22a0dc2..0000000 --- a/webdm/package.go +++ /dev/null @@ -1,99 +0,0 @@ -package webdm - -import ( - "fmt" -) - -type Status int - -const ( - StatusUndefined Status = iota - StatusNotInstalled - StatusInstalled - StatusInstalling - StatusUninstalling -) - -// Package contains information about a given package available from the store -// or already installed. -type Package struct { - Id string - Name string - Origin string - Version string - Vendor string - Description string - IconUrl string `json:"icon"` - Type string - - Progress float64 - Status Status - - // WebDM uses this field to report errors, etc. It's not always filled. - Message string - - // InstalledSize will be filled if the package is installed, otherwise - // DownloadSize will be filled. - InstalledSize int64 `json:"installed_size"` - DownloadSize int64 `json:"download_size"` -} - -// UnmarshalJSON exists to decode the Status field from JSON to our enum. -func (status *Status) UnmarshalJSON(data []byte) error { - if status == nil { - return fmt.Errorf("UnmarshalJSON: Called on nil pointer") - } - - dataString := string(data) - switch dataString { - case `"uninstalled"`: - *status = StatusNotInstalled - case `"installed"`: - *status = StatusInstalled - case `"installing"`: - *status = StatusInstalling - case `"uninstalling"`: - *status = StatusUninstalling - default: - *status = StatusUndefined - return fmt.Errorf("UnmarshalJSON: Unhandled Status type: %s", dataString) - } - - return nil -} - -// MarshalJSON exists to encode the Status enum to JSON. -func (status Status) MarshalJSON() ([]byte, error) { - switch status { - case StatusNotInstalled: - return []byte(`"uninstalled"`), nil - case StatusInstalled: - return []byte(`"installed"`), nil - case StatusInstalling: - return []byte(`"installing"`), nil - case StatusUninstalling: - return []byte(`"uninstalling"`), nil - default: - return nil, fmt.Errorf("MarshalJSON: Unhandled Status type: %d", status) - } -} - -// Installed is used to check whether or not the package is installed. -func (snap Package) Installed() bool { - return snap.Status == StatusInstalled -} - -// Installing is used to check whether or not the package is being installed. -func (snap Package) Installing() bool { - return snap.Status == StatusInstalling -} - -// NotInstalled is used to check whether or not the package not installed. -func (snap Package) NotInstalled() bool { - return snap.Status == StatusNotInstalled -} - -// Uninstalling is used to check whether or not the package is being uninstalled. -func (snap Package) Uninstalling() bool { - return snap.Status == StatusUninstalling -} diff --git a/webdm/package_test.go b/webdm/package_test.go deleted file mode 100644 index 94d366b..0000000 --- a/webdm/package_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package webdm - -import ( - "testing" -) - -// Data for TestMarshalJSON -var marshalJSONTests = []struct { - status Status - expected string - shouldError bool -}{ - {StatusUndefined, "", true}, - {StatusNotInstalled, `"uninstalled"`, false}, - {StatusInstalled, `"installed"`, false}, - {StatusInstalling, `"installing"`, false}, - {StatusUninstalling, `"uninstalling"`, false}, -} - -// Test typical MarshalJSON usage -func TestMarshalJSON(t *testing.T) { - for i, test := range marshalJSONTests { - json, err := test.status.MarshalJSON() - - if test.shouldError && err == nil { - t.Errorf("Test case %d: Expected an error", i) - } - - if !test.shouldError && err != nil { - t.Errorf("Test case %d: Unexpected error: %s", i, err) - } - - if !test.shouldError && string(json) != test.expected { - t.Errorf("Test case %d: Got %s, expected %s", i, string(json), test.expected) - } - } -} - -// Data for TestUnmarshalJSON -var unmarshalJSONTests = []struct { - json string - expected Status - shouldError bool -}{ - {`"uninstalled"`, StatusNotInstalled, false}, - {`"installed"`, StatusInstalled, false}, - {`"installing"`, StatusInstalling, false}, - {`"uninstalling"`, StatusUninstalling, false}, - {`"foo"`, StatusUndefined, true}, -} - -// Test typical UnmarshalJSON usage -func TestUnmarshalJSON(t *testing.T) { - for i, test := range unmarshalJSONTests { - var status Status - err := status.UnmarshalJSON([]byte(test.json)) - if status != test.expected { - t.Errorf("Test case %d: Status was %d, expected %d", i, status, test.expected) - } - - if test.shouldError && err == nil { - t.Errorf("Test case %d: Expected an error", i) - } - - if !test.shouldError && err != nil { - t.Errorf("Test case %d: Unexpected error: %s", i, err) - } - } -} - -// Test that UnmarshalJSON dies when called on nil Status -func TestUnmarshalJSON_nilStatus(t *testing.T) { - var nilStatus *Status = nil - err := nilStatus.UnmarshalJSON([]byte("this is fake json")) - if err == nil { - t.Error("Expected error when Status is nil") - } -} - -// Test typical Installed usage. -func TestPackage_installed(t *testing.T) { - snap := Package{Status: StatusInstalled} - if !snap.Installed() { - t.Error("Expected package to be installed") - } -} - -// Test typical Installing usage. -func TestPackage_installing(t *testing.T) { - snap := Package{Status: StatusInstalling} - if !snap.Installing() { - t.Error("Expected package to be installing") - } -} - -// Test typical NotInstalled usage. -func TestPackage_notInstalled(t *testing.T) { - snap := Package{Status: StatusNotInstalled} - if !snap.NotInstalled() { - t.Error("Expected package to not be installed") - } -} - -// Test typical Uninstalling usage. -func TestPackage_uninstalling(t *testing.T) { - snap := Package{Status: StatusUninstalling} - if !snap.Uninstalling() { - t.Error("Expected package to be uninstalling") - } -} |
