Skip to content

Commit

Permalink
Merge pull request #367 from Ulauncher/v4.4.0
Browse files Browse the repository at this point in the history
v4.4.0
  • Loading branch information
gornostal committed Apr 28, 2019
2 parents a1304f5 + 30d5114 commit 486e302
Show file tree
Hide file tree
Showing 12 changed files with 1,335 additions and 170 deletions.
3 changes: 3 additions & 0 deletions bin/ulauncher-toggle
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ dbus-send \
/net/launchpad/ulauncher \
net.launchpad.ulauncher.toggle_window

# dbus-send is asynchronous and sometimes it takes a bit of time for Ulauncher window to be presented
sleep 0.03

wmctrl -a "Ulauncher window title"
3 changes: 2 additions & 1 deletion build-utils/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,13 @@ launchpad_upload() {
xenial="PPA=$PPA GPGKEY=$GPGKEY RELEASE=xenial ./build-utils/build-deb.sh $VERSION --upload"
bionic="PPA=$PPA GPGKEY=$GPGKEY RELEASE=bionic ./build-utils/build-deb.sh $VERSION --upload"
cosmic="PPA=$PPA GPGKEY=$GPGKEY RELEASE=cosmic ./build-utils/build-deb.sh $VERSION --upload"
disco="PPA=$PPA GPGKEY=$GPGKEY RELEASE=disco ./build-utils/build-deb.sh $VERSION --upload"

docker run \
--rm \
-v $(pwd):/root/ulauncher \
$BUILD_IMAGE \
bash -c "./build-utils/extract-launchpad-ssh.sh && $xenial && $bionic && $cosmic"
bash -c "./build-utils/extract-launchpad-ssh.sh && $xenial && $bionic && $cosmic && $disco"
}

main
87 changes: 1 addition & 86 deletions tests/api/server/test_ExtensionDownloader.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import io
import mock
import pytest

from json import dumps
from urllib2 import HTTPError

from ulauncher.api.server.ExtensionDb import ExtensionDb
from ulauncher.api.server.ExtensionRunner import ExtensionRunner
from ulauncher.api.server.ExtensionDownloader import (ExtensionDownloader, ExtensionIsUpToDateError,
AlreadyDownloadedError)
from ulauncher.api.server.ExtensionDownloader import ExtensionDownloader


class TestExtensionDownloader:
Expand Down Expand Up @@ -48,83 +43,3 @@ def unzip(self, mocker):
@pytest.fixture(autouse=True)
def datetime(self, mocker):
return mocker.patch('ulauncher.api.server.ExtensionDownloader.datetime')

def test_download(self, downloader, ext_db, ext_runner, unzip, download_zip, datetime):
ext_db.find.return_value = None

assert downloader.download('https://github.com/Ulauncher/ulauncher-timer') == \
'com.github.ulauncher.ulauncher-timer'

unzip.assert_called_with(download_zip.return_value, mock.ANY)
ext_db.put.assert_called_with('com.github.ulauncher.ulauncher-timer', {
'id': 'com.github.ulauncher.ulauncher-timer',
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': datetime.now.return_value.isoformat.return_value,
'last_commit': '64e106c',
'last_commit_time': '2017-05-01T07:30:39Z'
})

def test_download_raises_AlreadyDownloadedError(self, downloader, ext_db, ext_runner, mocker):
ext_id = 'com.github.ulauncher.ulauncher-timer'
ext_db.find.return_value = {
'id': ext_id,
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': '2017-01-01',
'last_commit': 'aDbc',
'last_commit_time': '2017-01-01'
}
os = mocker.patch('ulauncher.api.server.ExtensionDownloader.os')
os.path.exists.return_value = True

with pytest.raises(AlreadyDownloadedError):
assert downloader.download('https://github.com/Ulauncher/ulauncher-timer')

def test_update(self, downloader, ext_db, ext_runner, gh_ext, download_zip, unzip, datetime):
ext_id = 'com.github.ulauncher.ulauncher-timer'
ext_db.find.return_value = {
'id': ext_id,
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': '2017-01-01',
'last_commit': 'aDbc',
'last_commit_time': '2017-01-01'
}
ext_runner.is_running.return_value = True

assert downloader.update(ext_id)

download_zip.assert_called_with(gh_ext.get_download_url.return_value)
unzip.assert_called_with(download_zip.return_value, mock.ANY)
ext_runner.stop.assert_called_with(ext_id)
ext_runner.run.assert_called_with(ext_id)
ext_db.put.assert_called_with(ext_id, {
'id': ext_id,
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': datetime.now.return_value.isoformat.return_value,
'last_commit': '64e106c',
'last_commit_time': '2017-05-01T07:30:39Z'
})

def test_get_new_version_raises_ExtensionIsUpToDateError(self, downloader, ext_db):
ext_id = 'com.github.ulauncher.ulauncher-timer'
ext_db.find.return_value = {
'id': ext_id,
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': '2017-01-01',
'last_commit': '64e106c',
'last_commit_time': '2017-05-01T07:30:39Z'
}

with pytest.raises(ExtensionIsUpToDateError):
downloader.get_new_version(ext_id)

def test_get_new_version_returns_new_version(self, downloader, ext_db, ext_runner, gh_ext):
ext_id = 'com.github.ulauncher.ulauncher-timer'
ext_db.find.return_value = {
'id': ext_id,
'url': 'https://github.com/Ulauncher/ulauncher-timer',
'updated_at': '2017-01-01',
'last_commit': 'a8827b723',
'last_commit_time': '2017-01-01'
}

assert downloader.get_new_version(ext_id) == gh_ext.get_last_commit.return_value
16 changes: 3 additions & 13 deletions tests/api/server/test_GithubExtension.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from json import dumps
from urllib2 import HTTPError

from ulauncher.api.server.GithubExtension import GithubExtension, InvalidGithubUrlError
from ulauncher.api.server.GithubExtension import GithubExtension, GithubExtensionError


class TestGithubExtension:
Expand All @@ -20,21 +20,11 @@ def test_get_ext_id(self, gh_ext):
def test_validate_url(self, gh_ext):
assert gh_ext.validate_url() is None

with pytest.raises(InvalidGithubUrlError):
with pytest.raises(GithubExtensionError):
GithubExtension('http://github.com/Ulauncher/ulauncher-timer').validate_url()

with pytest.raises(InvalidGithubUrlError):
with pytest.raises(GithubExtensionError):
GithubExtension('https://github.com/Ulauncher/ulauncher-timer/').validate_url()

def test_get_download_url(self, gh_ext):
assert gh_ext.get_download_url() == 'https://github.com/Ulauncher/ulauncher-timer/archive/master.zip'

def test_get_last_commit(self, gh_ext, mocker):
urlopen = mocker.patch('ulauncher.api.server.GithubExtension.urlopen')
urlopen.side_effect = [
io.StringIO(dumps({'object': {'url': 'url123'}}).decode('utf-8')),
io.StringIO(dumps({'sha': '64e106c', 'committer': {'date': '2017-05-01T07:30:39Z'}}).decode('utf-8'))
]
info = gh_ext.get_last_commit()
assert info['last_commit'] == '64e106c'
assert info['last_commit_time'] == '2017-05-01T07:30:39Z'
5 changes: 5 additions & 0 deletions tests/util/test_date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from ulauncher.util.date import iso_to_datetime


def test_iso_to_datetime():
assert str(iso_to_datetime('2017-05-01T07:30:39Z')) == '2017-05-01 07:30:39'
81 changes: 36 additions & 45 deletions ulauncher/api/server/ExtensionDownloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ulauncher.util.decorator.run_async import run_async
from ulauncher.util.decorator.singleton import singleton
from .ExtensionDb import ExtensionDb
from .GithubExtension import GithubExtension, InvalidGithubUrlError
from .GithubExtension import GithubExtension, GithubExtensionError
from .ExtensionRunner import ExtensionRunner, ExtensionIsNotRunningError
from .extension_finder import find_extensions

Expand All @@ -37,37 +37,37 @@ def download(self, url):
1. check if ext already exists
2. get last commit info
3. download & unzip
4. add to the db
5. start the ext
4. add it to the db
:rtype: str
:returns: Extension ID
:raises AlreadyDownloadedError:
:raises InvalidGithubUrlError:
"""
gh_ext = GithubExtension(url)
gh_ext.validate_url()

# 1. check if ext already exists
ext_id = gh_ext.get_ext_id()
ext_path = os.path.join(EXTENSIONS_DIR, ext_id)
if os.path.exists(ext_path):
raise AlreadyDownloadedError('Extension with given URL is already added')
# allow user to re-download an extension if it's not running
# most likely it has some problems with manifest file if it's not running
if os.path.exists(ext_path) and self.ext_runner.is_running(ext_id):
raise AlreadyDownloadedError('Extension with URL "%s" is already added' % url)

try:
gh_commit = gh_ext.get_last_commit()
except Exception as e:
logger.error('gh_ext.get_ext_meta() failed. %s: %s' % (type(e).__name__, e))
raise InvalidGithubUrlError('Project is not available on Github')
# 2. get last commit info
commit = gh_ext.find_compatible_version()

filename = download_zip(gh_ext.get_download_url(gh_commit['last_commit']))
# 3. download & unzip
filename = download_zip(gh_ext.get_download_url(commit['sha']))
unzip(filename, ext_path)

# 4. add to the db
self.ext_db.put(ext_id, {
'id': ext_id,
'url': url,
'updated_at': datetime.now().isoformat(),
'last_commit': gh_commit['last_commit'],
'last_commit_time': gh_commit['last_commit_time']
'last_commit': commit['sha'],
'last_commit_time': commit['time'].isoformat()
})
self.ext_db.commit()

Expand All @@ -80,12 +80,12 @@ def download_missing(self):
if id in already_downloaded:
continue

logger.info('Downloading missing extension %s' % id)
logger.info('Downloading missing extension %s', id)
try:
ext_id = self.download(ext['url'])
self.ext_runner.run(ext_id)
except Exception as e:
logger.error('%s: %s' % (type(e).__name__, e))
logger.error('%s: %s', type(e).__name__, e)

def remove(self, ext_id):
try:
Expand All @@ -99,38 +99,31 @@ def remove(self, ext_id):

def update(self, ext_id):
"""
:raises ExtensionNotFound:
:raises ExtensionDownloaderError:
:rtype: boolean
:returns: False if already up-to-date, True if was updated
"""
commit = self.get_new_version(ext_id)
ext = self.ext_db.find(ext_id)
if not ext:
raise ExtensionNotFound("Extension not found")

url = ext['url']
gh_ext = GithubExtension(url)

try:
gh_commit = self.get_new_version(ext_id)
except ExtensionIsUpToDateError:
return False
logger.info('Updating extension "" from commit to ', ext_id, ext['last_commit'][:8], commit['last_commit'][:8])

need_restart = self.ext_runner.is_running(ext_id)
if need_restart:
if self.ext_runner.is_running(ext_id):
self.ext_runner.stop(ext_id)

ext_path = os.path.join(EXTENSIONS_DIR, ext_id)

filename = download_zip(gh_ext.get_download_url(gh_commit['last_commit']))
gh_ext = GithubExtension(ext['url'])
filename = download_zip(gh_ext.get_download_url(commit['last_commit']))
unzip(filename, ext_path)

ext['updated_at'] = datetime.now().isoformat()
ext['last_commit'] = gh_commit['last_commit']
ext['last_commit_time'] = gh_commit['last_commit_time']
ext['last_commit'] = commit['last_commit']
ext['last_commit_time'] = commit['last_commit_time']
self.ext_db.put(ext_id, ext)
self.ext_db.commit()

if need_restart:
self.ext_runner.run(ext_id)
self.ext_runner.run(ext_id)

return True

Expand All @@ -140,21 +133,19 @@ def get_new_version(self, ext_id):
"""
ext = self.ext_db.find(ext_id)
if not ext:
raise ExtensionNotFound("Extension %s not found" % ext_id)
raise ExtensionNotFound("Extension not found")

url = ext['url']
gh_ext = GithubExtension(url)

try:
gh_commit = gh_ext.get_last_commit()
except Exception as e:
logger.error('gh_ext.get_ext_meta() failed. %s: %s' % (type(e).__name__, e.message))
raise InvalidGithubUrlError('Project is not available on Github')

if ext['last_commit'] == gh_commit['last_commit']:
raise ExtensionIsUpToDateError('Extension %s is up-to-date' % ext_id)

return gh_commit
commit = gh_ext.find_compatible_version()
need_update = ext['last_commit'] != commit['sha']
if not need_update:
raise ExtensionIsUpToDateError('Extension is up to date')

return {
'last_commit': commit['sha'],
'last_commit_time': commit['time'].isoformat()
}


def unzip(filename, ext_path):
Expand Down
16 changes: 4 additions & 12 deletions ulauncher/api/server/ExtensionManifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@ def get_icon_path(self):
def load_icon(self, size):
return load_image(self.get_icon_path(), size)

def get_manifest_version(self):
return self.manifest['manifest_version']

def get_api_version(self):
return self.manifest['api_version']
def get_required_api_version(self):
return self.manifest.get('required_api_version') or self.manifest.get('api_version')

def get_developer_name(self):
return self.manifest['developer_name']
Expand All @@ -61,8 +58,7 @@ def get_option(self, name, default=None):

def validate(self):
try:
assert self.get_manifest_version() in ['1', '2'], "Supported manifest versions are '1' and '2'"
assert self.get_api_version() == '1', "api_version should be 1"
assert self.get_required_api_version(), "required_api_version is not provided"
assert self.get_name(), 'name is not provided'
assert self.get_description(), 'description is not provided'
assert self.get_developer_name(), 'developer_name is not provided'
Expand All @@ -86,13 +82,9 @@ def validate(self):

def check_compatibility(self):
app_version = get_version()
# only API version 1 is supported for now
if self.get_api_version() != '1':
if self.get_required_api_version() != '1':
raise VersionIncompatibilityError('Extension "%s" is not compatible with Ulauncher v%s' %
(self.extension_id, app_version))
if self.get_manifest_version() not in ['1', '2']:
raise VersionIncompatibilityError('Manifest version of "%s" is not compatible with Ulauncher v%s' %
(self.extension_id, app_version))


class VersionIncompatibilityError(RuntimeError):
Expand Down

0 comments on commit 486e302

Please sign in to comment.