diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37d356b --- /dev/null +++ b/.gitignore @@ -0,0 +1,207 @@ +# Created by .ignore support plugin (hsz.mobi) +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +/.idea/ +.idea diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/big_version.py b/big_version.py new file mode 100644 index 0000000..02c4754 --- /dev/null +++ b/big_version.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import sys +from collections import OrderedDict + +from pyquery import PyQuery as pq +from workflow import Workflow + +log = None + + +def get_version(url): + # 获得文档对象 + doc = pq(url) + # 创建版本列表 + version_dict = OrderedDict([]) + tbodys = doc('.versions').find('tbody') + for tbody in tbodys.items(): + trs = tbody('tr') + sm_list = [] + # 转成list + v_list = list(trs.items()) + # 判断是否有一个版本 + is_only_one = len(v_list) == 1 + for i, tr in enumerate(v_list): + if i != 0 or is_only_one: + sm_list.append(tr('a:first').text()) + version_dict[tbody('tr:first').find('b').text() + '.x'] = str(sm_list) + return version_dict + + +def main(wf): + # 获得参数 + params = wf.args[0] + # params = "http://mvnrepository.com/artifact/com.jayway.restassured/spring-mock-mvc" + # 获得project + versions = get_version(params) + for version in versions.keys(): + # match = re.match(r'^http://mvnrepository.com/artifact/(.+)(/.+)$', params) + # group = match.group(1) + sm_v = str(versions[version]) + wf.add_item(title=version, subtitle=sm_v, arg=params + ":-:" + sm_v, valid=True, icon='icon/version.png') + + wf.send_feedback() + + +if __name__ == '__main__': + wf = Workflow() + log = wf.logger + sys.exit(wf.run(main)) diff --git a/info.plist b/info.plist new file mode 100644 index 0000000..0d9d95f --- /dev/null +++ b/info.plist @@ -0,0 +1,537 @@ + + + + + bundleid + cn.coder4j.tool.alfred.depquery + category + Tools + connections + + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + + + destinationuid + C49F1DE5-C46D-4CE6-AD82-343DADC9EFAC + modifiers + 0 + modifiersubtext + + vitoclose + + + + 04156593-78D3-4A1F-A2E1-E8B9DD79B04D + + + destinationuid + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 102A47BE-BCDB-43EE-AC3A-68862D5A07B5 + + + destinationuid + 540AD87E-743B-4EF6-ADD6-2E9B13240AC4 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 13F8D8A2-E3E2-49AB-8C0F-1762A6A24AA4 + + + destinationuid + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 2C7B5359-DBB7-404D-B376-0384B0045941 + + + destinationuid + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + modifiers + 0 + modifiersubtext + + vitoclose + + + + 4BB14101-C584-4E3F-8D41-E33846488D71 + + + destinationuid + 102A47BE-BCDB-43EE-AC3A-68862D5A07B5 + modifiers + 0 + modifiersubtext + + vitoclose + + + + B891DA84-E2FD-4CAE-BFEC-86C920A4AE78 + + + destinationuid + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + modifiers + 0 + modifiersubtext + + vitoclose + + + + C49F1DE5-C46D-4CE6-AD82-343DADC9EFAC + + + destinationuid + 4BB14101-C584-4E3F-8D41-E33846488D71 + modifiers + 0 + modifiersubtext + + vitoclose + + + + + createdby + kiwi + description + 依赖快速查询工具 + disabled + + name + DepQuery + objects + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + dq + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目查询中。。。 + script + python main.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 依赖快速查询工具 + title + 依赖快速查询工具 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 04156593-78D3-4A1F-A2E1-E8B9DD79B04D + version + 2 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + mvn + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目查询中。。。 + script + python main.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 依赖快速查询工具 + title + 依赖快速查询工具 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + B891DA84-E2FD-4CAE-BFEC-86C920A4AE78 + version + 2 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + sv + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目的小版本查询中。。。 + script + python small_version.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 查询项目的小版本 + title + 查询项目的小版本 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + C49F1DE5-C46D-4CE6-AD82-343DADC9EFAC + version + 2 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + bv + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目的主版本查询中。。。 + script + python big_version.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 查询项目的主版本 + title + 查询项目的主版本 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + version + 2 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + type + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 构建工具类型查询中。。。 + script + python type.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 查询构建工具类型 + title + 查询构建工具类型 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 4BB14101-C584-4E3F-8D41-E33846488D71 + version + 2 + + + config + + autopaste + + clipboardtext + {query} + transient + + + type + alfred.workflow.output.clipboard + uid + 102A47BE-BCDB-43EE-AC3A-68862D5A07B5 + version + 2 + + + config + + lastpathcomponent + + onlyshowifquerypopulated + + removeextension + + text + 依赖信息已经复制到粘贴板 + title + 复制成功 + + type + alfred.workflow.output.notification + uid + 540AD87E-743B-4EF6-ADD6-2E9B13240AC4 + version + 1 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + gradle + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目查询中。。。 + script + python main.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 依赖快速查询工具 + title + 依赖快速查询工具 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 13F8D8A2-E3E2-49AB-8C0F-1762A6A24AA4 + version + 2 + + + config + + alfredfiltersresults + + argumenttype + 0 + escaping + 102 + keyword + ivy + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + 项目查询中。。。 + script + python main.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + 依赖快速查询工具 + title + 依赖快速查询工具 + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + 2C7B5359-DBB7-404D-B376-0384B0045941 + version + 2 + + + readme + + uidata + + 015AD3CD-9312-46CF-B16D-3EE44AA3CC74 + + xpos + 300 + ypos + 210 + + 04156593-78D3-4A1F-A2E1-E8B9DD79B04D + + xpos + 30 + ypos + 10 + + 102A47BE-BCDB-43EE-AC3A-68862D5A07B5 + + xpos + 860 + ypos + 220 + + 13F8D8A2-E3E2-49AB-8C0F-1762A6A24AA4 + + xpos + 30 + ypos + 260 + + 2C7B5359-DBB7-404D-B376-0384B0045941 + + xpos + 40 + ypos + 390 + + 4BB14101-C584-4E3F-8D41-E33846488D71 + + xpos + 670 + ypos + 210 + + 540AD87E-743B-4EF6-ADD6-2E9B13240AC4 + + xpos + 1070 + ypos + 220 + + B891DA84-E2FD-4CAE-BFEC-86C920A4AE78 + + xpos + 30 + ypos + 130 + + C49F1DE5-C46D-4CE6-AD82-343DADC9EFAC + + xpos + 480 + ypos + 210 + + + webaddress + https://github.com/kiwiflydream + + diff --git a/main.py b/main.py new file mode 100644 index 0000000..4f3f2c3 --- /dev/null +++ b/main.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import os +import re +import sys + +from pyquery import PyQuery as pq +from workflow import Workflow, web + +log = None + +# 基础地址 +BASE_URL = 'http://mvnrepository.com' + + +def get_url(key, page=1): + return BASE_URL + "/search?q=" + key + "&p=" + str(page) + + +def get_projects(key, page=1): + # 获得整个文档 + doc = pq(get_url(key, page)) + # 获得主内容 + main_content = doc('#maincontent') + # 获得总结果数 + counts = main_content('h2:first').find('b').text() + # print(counts) + # 项目列表 + projects = [] + for im in main_content('.im').items(): + title = im('.im-header').find('h2.im-title').find('a[class!=\'im-usage\']') + if title: + name = title.text() + url = title.attr('href') + img = im('picture').find('img') + logo = img.attr('src') + subtitle = im('.im-header').find('p.im-subtitle') + group = subtitle('a:first').text() + # print(name + "-" + url + "-" + logo + " - " + group) + projects.append({'name': name, 'url': BASE_URL + url, 'logo': logo, 'group': group}) + + # 分页计算 + counts = int(counts) + pages = counts // 10 + if counts % 10 != 0: + pages = pages + 1 + + if 0 < counts < 10: + pages = 1 + + return {'projects': projects, 'pages': pages, 'counts': counts} + + +def main(wf): + # 获得参数 + params = wf.args[0] + # params = '\'sp\': x' + params_arr = re.split(r'\s*:\s*', params) + # 获取页数 + key = params_arr[0] + + count = key.count('\'') + if count == 0 or count == 2: + page = 1 + if len(params_arr) == 2 and params_arr[1]: + try: + page = int(params_arr[1]) + except ValueError: + pass + # 获得project + url_ = re.sub(r'\s+', '+', key) + page = get_projects(url_, page) + projects = page['projects'] + for project in projects: + name_ = project['name'] + group_ = project['group'] + png = 'icon/' + group_ + '.png' + if not os.path.exists(png): + if not os.path.exists('icon/'): + os.mkdir('icon/') + web.get(project['logo']).save_to_path(png) + wf.add_item(title=name_, subtitle=group_, arg=project['url'], valid=True, icon=png) + else: + wf.add_item(title=u'请继续输入...', subtitle=u'请继续输入...') + + # valid=True 告诉alfred把arg传递给下一个动作 + # 把结果转成xml发给alfred + wf.send_feedback() + + +if __name__ == '__main__': + wf = Workflow() + log = wf.logger + sys.exit(wf.run(main)) diff --git a/pyquery/__init__.py b/pyquery/__init__.py new file mode 100644 index 0000000..37e5720 --- /dev/null +++ b/pyquery/__init__.py @@ -0,0 +1,13 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2008 - Olivier Lauzanne +# +# Distributed under the BSD license, see LICENSE.txt + +try: + import webob + import restkit +except ImportError: + from .pyquery import PyQuery +else: + from .ajax import PyQuery diff --git a/pyquery/ajax.py b/pyquery/ajax.py new file mode 100644 index 0000000..c5270a1 --- /dev/null +++ b/pyquery/ajax.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +from webob import Request +from webob import Response + +from .pyquery import PyQuery as Base +from .pyquery import no_default + +try: + from restkit.contrib.wsgi_proxy import HostProxy +except ImportError: + HostProxy = no_default # NOQA + + +class PyQuery(Base): + def __init__(self, *args, **kwargs): + if 'response' in kwargs: + self.response = kwargs.pop('response') + else: + self.response = Response() + if 'app' in kwargs: + self.app = kwargs.pop('app') + if len(args) == 0: + args = [[]] + else: + self.app = no_default + Base.__init__(self, *args, **kwargs) + if self._parent is not no_default: + self.app = self._parent.app + + def _wsgi_get(self, path_info, **kwargs): + if path_info.startswith('/'): + if 'app' in kwargs: + app = kwargs.pop('app') + elif self.app is not no_default: + app = self.app + else: + raise ValueError('There is no app available') + else: + if HostProxy is not no_default: + app = HostProxy(path_info) + path_info = '/' + else: + raise ImportError('restkit is not installed') + + environ = kwargs.pop('environ').copy() + environ.update(kwargs) + + # unsuported (came from Deliverance) + for key in ['HTTP_ACCEPT_ENCODING', 'HTTP_IF_MATCH', + 'HTTP_IF_UNMODIFIED_SINCE', 'HTTP_RANGE', 'HTTP_IF_RANGE']: + if key in environ: + del environ[key] + + req = Request.blank(path_info) + req.environ.update(environ) + resp = req.get_response(app) + status = resp.status.split() + ctype = resp.content_type.split(';')[0] + if status[0] not in '45' and ctype == 'text/html': + body = resp.body + else: + body = [] + result = self.__class__(body, + parent=self._parent, + app=self.app, # always return self.app + response=resp) + return result + + def get(self, path_info, **kwargs): + """GET a path from wsgi app or url + """ + environ = kwargs.setdefault('environ', {}) + environ['REQUEST_METHOD'] = 'GET' + environ['CONTENT_LENGTH'] = '0' + return self._wsgi_get(path_info, **kwargs) + + def post(self, path_info, **kwargs): + """POST a path from wsgi app or url + """ + environ = kwargs.setdefault('environ', {}) + environ['REQUEST_METHOD'] = 'POST' + return self._wsgi_get(path_info, **kwargs) diff --git a/pyquery/cssselectpatch.py b/pyquery/cssselectpatch.py new file mode 100644 index 0000000..66690c9 --- /dev/null +++ b/pyquery/cssselectpatch.py @@ -0,0 +1,448 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2008 - Olivier Lauzanne +# +# Distributed under the BSD license, see LICENSE.txt +from __future__ import unicode_literals + +from cssselect import xpath as cssselect_xpath +from cssselect.xpath import ExpressionError + +XPathExprOrig = cssselect_xpath.XPathExpr + + +class XPathExpr(XPathExprOrig): + def __init__(self, path='', element='*', condition='', star_prefix=False): + self.path = path + self.element = element + self.condition = condition + self.post_condition = None + + def add_post_condition(self, post_condition): + if self.post_condition: + self.post_condition = '%s and (%s)' % (self.post_condition, + post_condition) + else: + self.post_condition = post_condition + + def __str__(self): + path = XPathExprOrig.__str__(self) + if self.post_condition: + path = '%s[%s]' % (path, self.post_condition) + return path + + def join(self, combiner, other): + res = XPathExprOrig.join(self, combiner, other) + self.post_condition = other.post_condition + return res + + +# keep cssselect < 0.8 compat for now + + +class JQueryTranslator(cssselect_xpath.HTMLTranslator): + """This class is used to implement the css pseudo classes + (:first, :last, ...) that are not defined in the css standard, + but are defined in the jquery API. + """ + + xpathexpr_cls = XPathExpr + + def xpath_first_pseudo(self, xpath): + """Matches the first selected element:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('

') + >>> d('p:first') + [] + + .. + """ + xpath.add_post_condition('position() = 1') + return xpath + + def xpath_last_pseudo(self, xpath): + """Matches the last selected element:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('

') + >>> d('p:last') + [] + + .. + """ + xpath.add_post_condition('position() = last()') + return xpath + + def xpath_even_pseudo(self, xpath): + """Matches even elements, zero-indexed:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('

') + >>> d('p:even') + [

] + + .. + """ + # the first element is 1 in xpath and 0 in python and js + xpath.add_post_condition('position() mod 2 = 1') + return xpath + + def xpath_odd_pseudo(self, xpath): + """Matches odd elements, zero-indexed:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('

') + >>> d('p:odd') + [] + + .. + """ + xpath.add_post_condition('position() mod 2 = 0') + return xpath + + def xpath_checked_pseudo(self, xpath): + """Matches odd elements, zero-indexed:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('
') + >>> d('input:checked') + [] + + .. + """ + xpath.add_condition("@checked and name(.) = 'input'") + return xpath + + def xpath_selected_pseudo(self, xpath): + """Matches all elements that are selected:: + + >>> from pyquery import PyQuery + >>> d = PyQuery('') + >>> d('option:selected') + [