Merge lp:~mvo/click/repository into lp:click/devel

Proposed by Michael Vogt
Status: Needs review
Proposed branch: lp:~mvo/click/repository
Merge into: lp:click/devel
Diff against target: 546 lines (+416/-16)
8 files modified
click/commands/__init__.py (+2/-0)
click/commands/info.py (+58/-5)
click/commands/search.py (+46/-0)
click/commands/update.py (+78/-0)
click/install.py (+7/-6)
click/repository.py (+220/-0)
click/tests/test_install.py (+2/-2)
debian/control (+3/-3)
To merge this branch: bzr merge lp:~mvo/click/repository
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Colin Watson Approve
Review via email: mp+237604@code.launchpad.net

Commit message

Add support for remote repositories to click.

Description of the change

This branch adds a new "repository" concept for packages coming from a remote location. It also adds "click search", "click update", "click info --remote" to query the repository.

At this point its mostly up for review to get feedback on the approach used and if the CLI interface fits the vision of click. But once the acquire branch lands and my sso branch gets into better shape this will allow managing clicks on a server image from the commandline easily.

Feedback welcome!

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:527
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/repository/+merge/237604/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/93/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/95/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/93/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/93/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/93/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:529
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/repository/+merge/237604/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/94/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/96/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/94/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/94/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/94/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:530
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/repository/+merge/237604/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/95/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/97/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/95/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/95/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/95/rebuild

review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
528. By Michael Vogt

debian/control: add python3-pycurl

529. By Michael Vogt

click/commands/update.py: add missing file

530. By Michael Vogt

pep8 fixes

531. By Michael Vogt

merge lp:click/devel

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:531
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/repository/+merge/237604/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/96/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/98
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/96
        deb: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/96/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/96

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/96/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Colin Watson (cjwatson) wrote :

I'm happy with the general direction, yes, thanks. Some specific comments / nitpicking below.

Presumably this could ultimately replace the current app updates handling on the phone as well, perhaps by way of exposing some of this via D-Bus?

review: Approve
lp:~mvo/click/repository updated
532. By Michael Vogt

use the bulk interface that click-update-manager is using to find available updates

533. By Michael Vogt

address review comments by Colin (thanks!)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Vogt (mvo) wrote :

> I'm happy with the general direction, yes, thanks. Some specific comments /
> nitpicking below.
>
> Presumably this could ultimately replace the current app updates handling on
> the phone as well, perhaps by way of exposing some of this via D-Bus?

Thanks a bunch! I replied to your comments inline, the ones I did not reply to are fixed in my branch now.

Revision history for this message
Michael Vogt (mvo) wrote :

See the inline replies.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mvo/click/repository updated
534. By Michael Vogt

click/repository.py: fix crash

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mvo/click/repository updated
535. By Michael Vogt

add docstrings/cleanup to ClickRepository

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
536. By Michael Vogt

click/commands/update.py. use prettytable to generate table output

537. By Michael Vogt

click/commands/update.py: add --machine-readable

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
538. By Michael Vogt

click/repository.py: add description property to a click repository

539. By Michael Vogt

click/commands/info.py: always search local/remote click names in click info

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
540. By Michael Vogt

merged from lp:click/devel

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
541. By Michael Vogt

click/repository.py: do not hit the network on update if nothing is installed

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
542. By Michael Vogt

add new Repository.credentails property

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
543. By Michael Vogt

click/commands/update.py: support "click update click1 click2" style invocation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
544. By Michael Vogt

click/commands/update.py: add --user/--all-users

545. By Michael Vogt

click/commands/info.py: fix pep8 failure

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
546. By Michael Vogt

add missing python3-prettytable build dependency

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
547. By Michael Vogt

set the right search headers

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mvo/click/repository updated
548. By Michael Vogt

fix tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mvo/click/repository updated
549. By Michael Vogt

click/repository.py: use application/hal+json instead of application/json

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mvo/click/repository updated
550. By Michael Vogt

click/repository.py: the ClickRepositoryAppsUbuntuCom.details() call needs to send framework info in the headers too)

551. By Michael Vogt

click/repository.py: fix headers in get_upgradable

552. By Michael Vogt

revert r551 - the myapps.developer.u.c API breaks with that

553. By Michael Vogt

merged lp:click/devel

554. By Michael Vogt

click/commands/info.py: add info -v to address Colins review comment

555. By Michael Vogt

click/repository.py: use the bulk uri

556. By Michael Vogt

click/repository.py: silly typo

Unmerged revisions

556. By Michael Vogt

click/repository.py: silly typo

555. By Michael Vogt

click/repository.py: use the bulk uri

554. By Michael Vogt

click/commands/info.py: add info -v to address Colins review comment

553. By Michael Vogt

merged lp:click/devel

552. By Michael Vogt

revert r551 - the myapps.developer.u.c API breaks with that

551. By Michael Vogt

click/repository.py: fix headers in get_upgradable

550. By Michael Vogt

click/repository.py: the ClickRepositoryAppsUbuntuCom.details() call needs to send framework info in the headers too)

549. By Michael Vogt

click/repository.py: use application/hal+json instead of application/json

548. By Michael Vogt

fix tests

547. By Michael Vogt

set the right search headers

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'click/commands/__init__.py'
--- click/commands/__init__.py 2014-05-20 09:03:05 +0000
+++ click/commands/__init__.py 2015-02-24 16:14:00 +0000
@@ -31,6 +31,8 @@
31 "list",31 "list",
32 "pkgdir",32 "pkgdir",
33 "register",33 "register",
34 "search",
35 "update",
34 "unregister",36 "unregister",
35 "verify",37 "verify",
36 )38 )
3739
=== modified file 'click/commands/info.py'
--- click/commands/info.py 2014-10-07 08:56:03 +0000
+++ click/commands/info.py 2015-02-24 16:14:00 +0000
@@ -28,6 +28,10 @@
2828
29from click.install import DebFile29from click.install import DebFile
30from click.json_helpers import json_object_to_python30from click.json_helpers import json_object_to_python
31from click.repository import (
32 get_repository,
33 ClickRepositoryError,
34)
3135
3236
33def _load_manifest(manifest_file):37def _load_manifest(manifest_file):
@@ -73,14 +77,63 @@
73 "--user", metavar="USER",77 "--user", metavar="USER",
74 help="look up PACKAGE-NAME for USER (if you have permission; "78 help="look up PACKAGE-NAME for USER (if you have permission; "
75 "default: current user)")79 "default: current user)")
80 parser.add_option(
81 "--repository", default=False, action="store_true",
82 help="Search in remote repository only")
83 parser.add_option(
84 "--no-repository", default=False, action="store_true",
85 help="Never search in a remote repository")
86 parser.add_option(
87 "-v", "--verbose", default=False, action="store_true",
88 help="Show verbose information")
76 options, args = parser.parse_args(argv)89 options, args = parser.parse_args(argv)
90 pkgname = args[0]
77 if len(args) < 1:91 if len(args) < 1:
78 parser.error("need file name")92 parser.error("need file name")
79 try:93
80 manifest = get_manifest(options, args[0])94 # see if its available locally: pkgname, click-path, path-to-unpacked-click
81 except Exception as e:95 manifest = None
82 print(e, file=sys.stderr)96 if not options.repository:
83 return 197 try:
98 manifest = get_manifest(options, pkgname)
99 except Exception as e:
100 pass
101
102 # now check remote
103 if manifest is None and not options.no_repository:
104 repo = get_repository()
105 try:
106 details = repo.details(pkgname)
107 if options.verbose:
108 # all information from the store, lots of stuff
109 manifest = details
110 else:
111 # by default show only a subset of all the store information
112 # by default, it contains a lot of additional info
113 # like hashes
114 manifest = {k: details.get(k)
115 for k in ('name',
116 'title',
117 'description',
118 'binary_filesize',
119 'publisher',
120 'framework',
121 'version',
122 'last_updated',
123 'architecture',
124 'department',
125 'changelog',
126 'ratings_average',
127 'price',
128 'keywords',
129 'license',
130 )}
131 manifest["_repository"] = repo.description
132 except ClickRepositoryError as e:
133 print(
134 "Can not get details for %s:%s" % (pkgname, e), file=sys.stderr)
135 return 1
136
84 json.dump(137 json.dump(
85 manifest, sys.stdout, ensure_ascii=False, sort_keys=True, indent=4,138 manifest, sys.stdout, ensure_ascii=False, sort_keys=True, indent=4,
86 separators=(",", ": "))139 separators=(",", ": "))
87140
=== added file 'click/commands/search.py'
--- click/commands/search.py 1970-01-01 00:00:00 +0000
+++ click/commands/search.py 2015-02-24 16:14:00 +0000
@@ -0,0 +1,46 @@
1# Copyright (C) 2014 Canonical Ltd.
2# Author: Michael Vogt
3
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; version 3 of the License.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16"""Search for Click packages"""
17
18from __future__ import print_function
19
20from optparse import OptionParser
21import sys
22from textwrap import dedent
23
24from click.repository import (
25 get_repository,
26 ClickRepositoryError,
27)
28
29
30def run(argv):
31 parser = OptionParser(dedent("""\
32 %prog search search-term(s)
33
34 """))
35 options, args = parser.parse_args(argv)
36 if len(args) < 1:
37 parser.error("need package file name")
38 repo = get_repository()
39 try:
40 result = repo.search(args[0])
41 except ClickRepositoryError as e:
42 print("Search failed %s" % e, file=sys.stderr)
43 return 1
44 for app in result:
45 print("%s - %s" % (app["name"], app["title"]))
46 return 0
047
=== added file 'click/commands/update.py'
--- click/commands/update.py 1970-01-01 00:00:00 +0000
+++ click/commands/update.py 2015-02-24 16:14:00 +0000
@@ -0,0 +1,78 @@
1# Copyright (C) 2014 Canonical Ltd.
2# Author: Michael Vogt
3
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; version 3 of the License.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16"""Update Click packages"""
17
18from __future__ import print_function
19
20from optparse import OptionParser
21import sys
22from textwrap import dedent
23
24from prettytable import PrettyTable, PLAIN_COLUMNS
25
26from click.repository import (
27 get_repository,
28 ClickRepositoryError,
29)
30
31
32def run(argv):
33 parser = OptionParser(dedent("""\
34 %prog update
35
36 """))
37 parser.add_option(
38 "--list", default=False, action="store_true",
39 help="Just list the update")
40 parser.add_option(
41 "--machine-readable", default=False, action="store_true",
42 help="output in machine readable form")
43 parser.add_option(
44 "--user", metavar="USER", help="register package for USER")
45 parser.add_option(
46 "--all-users", default=False, action="store_true",
47 help="register package for all users")
48 options, args = parser.parse_args(argv)
49 repo = get_repository()
50 try:
51 all_updates = repo.get_upgradable()
52 except ClickRepositoryError as e:
53 print("Update failed: %s" % e, file=sys.stderr)
54 return 1
55 if not all_updates:
56 return 0
57
58 if len(args) > 0:
59 updates = [up for up in all_updates if up[0]["name"] in args]
60 else:
61 updates = all_updates
62
63 if options.machine_readable:
64 for (current, new) in updates:
65 print("%s|%s|%s" % (
66 new["name"], current["version"], new["version"]))
67 elif options.list:
68 t = PrettyTable(["Part","Installed", "Available"])
69 t.set_style(PLAIN_COLUMNS)
70 t.align["Part"] = "l"
71 for (current, new) in updates:
72 t.add_row((new["name"], current["version"], new["version"]))
73 print(t)
74 else:
75 for (current, new) in updates:
76 print("downloading %s" % new["download_url"])
77
78 return 0
079
=== modified file 'click/install.py'
--- click/install.py 2014-12-03 12:42:21 +0000
+++ click/install.py 2015-02-24 16:14:00 +0000
@@ -76,6 +76,12 @@
76apt_pkg.init_system()76apt_pkg.init_system()
7777
7878
79def _dpkg_architecture():
80 return subprocess.check_output(
81 ["dpkg", "--print-architecture"],
82 universal_newlines=True).rstrip("\n")
83
84
79class DebsigVerifyError(Exception):85class DebsigVerifyError(Exception):
80 pass86 pass
8187
@@ -145,11 +151,6 @@
145 return os.path.abspath(preload)151 return os.path.abspath(preload)
146 return preload_path152 return preload_path
147153
148 def _dpkg_architecture(self):
149 return subprocess.check_output(
150 ["dpkg", "--print-architecture"],
151 universal_newlines=True).rstrip("\n")
152
153 def extract(self, path, target):154 def extract(self, path, target):
154 command = ["dpkg-deb", "-R", path, target]155 command = ["dpkg-deb", "-R", path, target]
155 with open(path, "rb") as fd:156 with open(path, "rb") as fd:
@@ -263,7 +264,7 @@
263 if check_arch:264 if check_arch:
264 architecture = manifest.get("architecture", "all")265 architecture = manifest.get("architecture", "all")
265 if architecture != "all":266 if architecture != "all":
266 dpkg_architecture = self._dpkg_architecture()267 dpkg_architecture = _dpkg_architecture()
267 if isinstance(architecture, list):268 if isinstance(architecture, list):
268 if dpkg_architecture not in architecture:269 if dpkg_architecture not in architecture:
269 raise ClickInstallerAuditError(270 raise ClickInstallerAuditError(
270271
=== added file 'click/repository.py'
--- click/repository.py 1970-01-01 00:00:00 +0000
+++ click/repository.py 2015-02-24 16:14:00 +0000
@@ -0,0 +1,220 @@
1# Copyright (C) 2014 Canonical Ltd.
2# Author: Michael Vogt
3
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; version 3 of the License.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16"""Search Click packages."""
17
18from __future__ import print_function
19
20__metaclass__ = type
21__all__ = [
22 'ClickRepository',
23 'ClickRepositoryError',
24 ]
25
26from io import BytesIO, StringIO
27import json
28import platform
29import os
30
31import apt_pkg
32from gi.repository import Click
33import pycurl
34
35from six.moves.urllib.parse import quote as url_quote
36
37from click.json_helpers import json_array_to_python
38import click.install
39
40class ClickRepositoryError(Exception):
41 pass
42
43
44class HttpResponse:
45 """Http Response with status and data members"""
46
47 def __init__(self, status, data):
48 self.status = status
49 self.data = data
50
51 def __str__(self):
52 return self.data
53
54
55# similar to httplib2.Http().request()
56def http_request(url, data=None, headers=None):
57 """Send a http request to the given url and return (response, data)
58
59 param url The url to send the request to
60 param data (Optional) data to POST to the url
61 param headers (Optional) headers to include with the request
62 return A tuple of (response, body)
63 rtype (HttpResponse, bytes)
64 """
65 def write_header(line):
66 header.write(line.decode("utf-8"))
67 return len(line)
68 def write_body(data):
69 body.write(data)
70 return len(data)
71 def post_data(num):
72 return data_stream.read(num)
73 header = StringIO()
74 body = BytesIO()
75 curl = pycurl.Curl()
76 curl.setopt(curl.URL, url)
77 if os.environ.get("CLICK_DEBUG_HTTP", ""):
78 curl.setopt(curl.VERBOSE, 1)
79 curl.setopt(pycurl.WRITEFUNCTION, write_body)
80 curl.setopt(pycurl.HEADERFUNCTION, write_header)
81 if data is not None:
82 data_stream = BytesIO(data)
83 curl.setopt(pycurl.READFUNCTION, post_data)
84 curl.setopt(pycurl.POSTFIELDSIZE, len(data))
85 curl.setopt(pycurl.POST, 1)
86 if headers is not None:
87 header_list = []
88 for k, v in headers.items():
89 header_list.append("%s: %s" % (k, v))
90 curl.setopt(pycurl.HTTPHEADER, header_list)
91 # ssl: no need to set extra options, pycurl has sensible defaults
92 curl.perform()
93 resp = HttpResponse(curl.getinfo(pycurl.HTTP_CODE), header.getvalue())
94 return resp, body.getvalue()
95
96
97def get_repository():
98 """Factory to get a click repository for the current distro"""
99 distro = platform.dist()[0]
100 if distro.startswith('Ubuntu'):
101 return ClickRepositoryAppsUbuntuCom()
102 raise ClickRepositoryError("No repository for distribution '%s'" % distro)
103
104
105class ClickRepository:
106
107 def search(self, search_string):
108 """Search the repository for the given search string
109
110 Returns a list of click manifest from the repository
111 """
112 raise NotImplementedError()
113
114 def get_upgradable(self):
115 """Get all click packages where a newer version is available
116
117 Returns a list of (old_manifest, new_manifest) pairs
118 """
119 raise NotImplementedError()
120
121 def details(self, name):
122 """Get the details for the given click name
123
124 Returns a click manifest
125 """
126 raise NotImplementedError()
127
128 @property
129 def description(self):
130 """The description of the repository as a URL"""
131 raise NotImplementedError()
132
133 @property
134 def credentials(self):
135 """The credentials for the repository (or None)"""
136 return None
137
138
139def get_store_headers():
140 frameworks = ["%s-%s" % (f.get_base_name(), f.get_base_version())
141 for f in Click.Framework.get_frameworks()]
142 headers = {
143 "Accept": "application/hal+json",
144 "X-Ubuntu-Frameworks": ",".join(frameworks),
145 "X-Ubuntu-Architecture": click.install._dpkg_architecture(),
146 }
147 return headers
148
149
150class ClickRepositoryAppsUbuntuCom(ClickRepository):
151 """Interface to click repository from apps.ubuntu.com"""
152
153 SEARCH_URI = "https://search.apps.ubuntu.com/api/v1/search?q=%s"
154 DETAILS_URI = "https://search.apps.ubuntu.com/api/v1/package/%s"
155 BULK_APPS_URI = "https://search.apps.ubuntu.com/api/v1/click-metadata"
156
157 @property
158 def credentials(self):
159 return None
160
161 @property
162 def description(self):
163 return "https://myapps.developer.ubuntu.com/dev/click-apps/"
164
165 def search(self, search_term):
166 result = []
167 url = self.SEARCH_URI % url_quote(search_term)
168 if not self.credentials:
169 url += ",allow_unauthenticated:True"
170 resp, raw_content = http_request(url, headers=get_store_headers())
171 content = raw_content.decode("utf-8")
172 if resp.status != 200:
173 raise ClickRepositoryError(content)
174 data = json.loads(content)
175 if not "_embedded" in data:
176 return result
177 for item in data["_embedded"]["clickindex:package"]:
178 result.append(item)
179 return result
180
181 def details(self, name):
182 resp, raw_content = http_request(
183 self.DETAILS_URI % url_quote(name), headers=get_store_headers())
184 content = raw_content.decode("utf-8")
185 if resp.status != 200:
186 raise ClickRepositoryError(content)
187 return json.loads(content)
188
189 def get_upgradable(self):
190 result = []
191 db = Click.DB()
192 db.read(db_dir=None)
193 registry = Click.User.for_user(db, name=None)
194 # build the dict of installed apps for the POST
195 current_apps = {}
196 for app in json_array_to_python(registry.get_manifests()):
197 current_apps[app["name"]] = app
198 # if we have nothing installed, do not query the server
199 if not current_apps:
200 return result
201 json_post_data = json.dumps({
202 "name": list(current_apps.keys()),
203 }).encode("utf-8")
204 # query the API
205 resp, raw_content = http_request(
206 self.BULK_APPS_URI,
207 json_post_data,
208 headers={"content-type": "application/json"})
209 content = raw_content.decode("utf-8")
210 if resp.status != 200:
211 raise ClickRepositoryError(
212 "Failed to get upgradable packages: %s" % resp.content)
213 # return a list of (old, new) pairs to the caller
214 server_apps = json.loads(content)
215 result = []
216 for new in server_apps:
217 current = current_apps[new["name"]]
218 if apt_pkg.version_compare(current["version"], new["version"]) < 0:
219 result.append( (current, new) )
220 return result
0221
=== modified file 'click/tests/test_install.py'
--- click/tests/test_install.py 2014-12-03 12:42:21 +0000
+++ click/tests/test_install.py 2015-02-24 16:14:00 +0000
@@ -605,7 +605,7 @@
605 os.path.exists(ClickInstaller(None)._preload_path()),605 os.path.exists(ClickInstaller(None)._preload_path()),
606 "preload bits not built; installing packages will fail")606 "preload bits not built; installing packages will fail")
607 @mock.patch("gi.repository.Click.package_install_hooks")607 @mock.patch("gi.repository.Click.package_install_hooks")
608 @mock.patch("click.install.ClickInstaller._dpkg_architecture")608 @mock.patch("click.install._dpkg_architecture")
609 def test_single_architecture(self, mock_dpkg_architecture,609 def test_single_architecture(self, mock_dpkg_architecture,
610 mock_package_install_hooks):610 mock_package_install_hooks):
611 with self.run_in_subprocess(611 with self.run_in_subprocess(
@@ -642,7 +642,7 @@
642 os.path.exists(ClickInstaller(None)._preload_path()),642 os.path.exists(ClickInstaller(None)._preload_path()),
643 "preload bits not built; installing packages will fail")643 "preload bits not built; installing packages will fail")
644 @mock.patch("gi.repository.Click.package_install_hooks")644 @mock.patch("gi.repository.Click.package_install_hooks")
645 @mock.patch("click.install.ClickInstaller._dpkg_architecture")645 @mock.patch("click.install._dpkg_architecture")
646 def test_multiple_architectures(self, mock_dpkg_architecture,646 def test_multiple_architectures(self, mock_dpkg_architecture,
647 mock_package_install_hooks):647 mock_package_install_hooks):
648 with self.run_in_subprocess(648 with self.run_in_subprocess(
649649
=== modified file 'debian/control'
--- debian/control 2014-10-10 07:10:23 +0000
+++ debian/control 2015-02-24 16:14:00 +0000
@@ -3,7 +3,7 @@
3Priority: optional3Priority: optional
4Maintainer: Colin Watson <cjwatson@ubuntu.com>4Maintainer: Colin Watson <cjwatson@ubuntu.com>
5Standards-Version: 3.9.55Standards-Version: 3.9.5
6Build-Depends: debhelper (>= 9~), dh-autoreconf, intltool, python3:any (>= 3.2), python3-all:any, python3-setuptools, python3-apt, python3-debian, python3-gi, python3:any (>= 3.3) | python3-mock, pep8, python3-pep8, pyflakes, python3-sphinx, pkg-config, valac, gobject-introspection (>= 0.6.7), libgirepository1.0-dev (>= 0.6.7), libglib2.0-dev (>= 2.34), gir1.2-glib-2.0, libjson-glib-dev (>= 0.10), libgee-0.8-dev, libpackagekit-glib2-dev (>= 0.7.2), python3-coverage, python3-six, dh-systemd (>= 1.3)6Build-Depends: debhelper (>= 9~), dh-autoreconf, intltool, python3:any (>= 3.2), python3-all:any, python3-setuptools, python3-apt, python3-debian, python3-gi, python3:any (>= 3.3) | python3-mock, pep8, python3-pep8, pyflakes, python3-sphinx, pkg-config, valac, gobject-introspection (>= 0.6.7), libgirepository1.0-dev (>= 0.6.7), libglib2.0-dev (>= 2.34), gir1.2-glib-2.0, libjson-glib-dev (>= 0.10), libgee-0.8-dev, libpackagekit-glib2-dev (>= 0.7.2), python3-coverage, python3-six, dh-systemd (>= 1.3), python3-pycurl, python3-prettytable
7Vcs-Bzr: https://code.launchpad.net/~ubuntu-managed-branches/click/click7Vcs-Bzr: https://code.launchpad.net/~ubuntu-managed-branches/click/click
8Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-managed-branches/click/click/files8Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-managed-branches/click/click/files
9X-Auto-Uploader: no-rewrite-version9X-Auto-Uploader: no-rewrite-version
@@ -14,7 +14,7 @@
14Package: click14Package: click
15Architecture: any15Architecture: any
16Pre-Depends: ${misc:Pre-Depends}16Pre-Depends: ${misc:Pre-Depends}
17Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, python3-click (= ${binary:Version}), adduser17Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, python3-click (= ${binary:Version}), adduser, python3-prettytable
18Recommends: click-apparmor18Recommends: click-apparmor
19Suggests: click-reviewers-tools (>= 0.9), ubuntu-app-launch-tools | upstart-app-launch-tools19Suggests: click-reviewers-tools (>= 0.9), ubuntu-app-launch-tools | upstart-app-launch-tools
20Conflicts: click-package20Conflicts: click-package
@@ -40,7 +40,7 @@
40Package: python3-click40Package: python3-click
41Section: python41Section: python
42Architecture: any42Architecture: any
43Depends: ${misc:Depends}, ${python3:Depends}, gir1.2-click-0.4 (= ${binary:Version}), gir1.2-glib-2.0, python3-apt, python3-debian, python3-gi43Depends: ${misc:Depends}, ${python3:Depends}, gir1.2-click-0.4 (= ${binary:Version}), gir1.2-glib-2.0, python3-apt, python3-debian, python3-gi, python3-pycurl
44Conflicts: python3-click-package44Conflicts: python3-click-package
45Replaces: python3-click-package45Replaces: python3-click-package
46Provides: python3-click-package46Provides: python3-click-package

Subscribers

People subscribed via source and target branches

to all changes: