diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index f24cd99..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,27 +0,0 @@
-*.py[co]
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
-.installed.cfg
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-
-#Translations
-*.mo
-
-#Mr Developer
-.mr.developer.cfg
diff --git a/.hgignore b/.hgignore
deleted file mode 100644
index 00cefb9..0000000
--- a/.hgignore
+++ /dev/null
@@ -1,2 +0,0 @@
-glob:*.pyc
-glob:*.swp
diff --git a/.hgsub b/.hgsub
deleted file mode 100644
index e69de29..0000000
diff --git a/.hgsubstate b/.hgsubstate
deleted file mode 100644
index e69de29..0000000
diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..ce82294
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+opm.objectjs.org
diff --git a/README.md b/README.md
deleted file mode 100644
index 539ec87..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-OPM
-===
\ No newline at end of file
diff --git a/__init__.py b/__init__.py
deleted file mode 100644
index 792d600..0000000
--- a/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-#
diff --git a/build.bat b/build.bat
deleted file mode 100644
index b659a96..0000000
--- a/build.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-set pyinstaller=d:\works\pyinstaller-1.5-rc1
-python %pyinstaller%/makespec.py --onefile --upx --paths .;cssutils-0.9.7a3-py2.6.egg;C:\Python27\Lib\site-packages\flup-1.0.3.dev_20110405-py2.7.egg --name scompiler staticcompiler.py
-python %pyinstaller%/build.py scompiler.spec
diff --git a/commands.py b/commands.py
deleted file mode 100644
index 41022dc..0000000
--- a/commands.py
+++ /dev/null
@@ -1,510 +0,0 @@
-#python
-#encoding=utf-8
-import os
-import sys
-import ui
-import utils.commandline
-from utils.commandline import arg, cwdarg, option, usage
-from opm import StaticPackage, Workspace, PackageNotFoundException, PackageExistsException, ConfigError
-from flup.server.fcgi import WSGIServer
-
-@cwdarg
-@usage(u'scompiler get [源库url]')
-@arg('url')
-def get(workspace, url):
- u''' 从公共代码库获取源库
-
- 当前目录会被作为工作区,所有获取到的源库代码都会放到此工作区内
- '''
-
- if workspace.__class__ == str:
- try:
- workspace = Workspace(workspace)
- except ConfigError as e:
- ui.error(u'config error %s' % e.path)
- return 1
-
- load(workspace)
-
- try:
- packages = workspace.fetch_packages(url)
- except PackageNotFoundException, e:
- ui.error('%s package not found' % e.url)
- return 1
- except ConfigError as e:
- ui.error(u'config error %s' % e.path)
- return 1
- else:
- for package in packages:
- try:
- workspace.fetch(package)
- except ImportError, e:
- ui.error(u'mercurial module not found.')
- return 1
- except PackageExistsException, e:
- ui.error(u'%s package already exists' % e.root)
-
-@cwdarg
-@usage(u'opm workspace [源库路径]')
-def workspace(root_path):
- u''' 源库所在工作区 '''
- if StaticPackage.get_root(root_path):
- ui.msg(Workspace.get_workspace(root_path))
- else:
- ui.msg(u'不是一个源库')
- return 1
-
-@arg('filename')
-@option('force', '-f', '--force', action = 'store_true', help = u'强制重新编译')
-@option('no_build_files', '--no-build-files', action = 'store_true', help = u'不发布相关文件')
-@usage(u'opm compile 发布库中的某个js/css文件 [options]')
-def compile(filename, package = None, force = False, no_build_files = False):
- u'编译一个css/js文件'
-
- filename = os.path.realpath(filename)
-
- if not package:
- publish_path, root_path = StaticPackage.get_roots(filename)
-
- if not root_path:
- ui.error(u'没有找到源文件')
- return 1
- else:
- package = StaticPackage(root_path, publish_path)
-
- try:
- modified, not_exists = package.compile(filename, force = force)
- except IOError, e:
- ui.error('%s file not found' % e.filename)
- return 1
- except PackageNotFoundException, e:
- ui.error('%s package not found' % e.url)
- return 1
-
- if modified or (force and modified != None):
- for modified_file in modified:
- ui.msg(u'Modified: %s' % modified_file)
-
- ui.msg(u'Compiled: %s' % filename)
-
- # 未被维护的文件
- elif modified == None:
- #ui.msg(u'No Source: %s' % filename)
- pass
-
- if not no_build_files:
- buildfiles(package = package)
-
-def buildfiles(package = None):
- files = package.build_files()
- for build_file in files:
- ui.msg(u'Copy File: %s' % build_file)
-
-@cwdarg
-@arg('link_path')
-@option('force', '-f', '--force', action='store_true', help=u'强制建立发布文件夹')
-def link(path, link_path, force = False):
- u''' 将发布库与源库进行映射
-
-如果库设置了url,则同时使用.package文件进行连接,需要工作区支持,如果没有url,则只进行本地连接。'''
-
- publish_path, root_path = StaticPackage.get_roots(path)
- if not publish_path and not root_path and link_path:
- publish_path, root_path = StaticPackage.get_roots(link_path)
- path, link_path = link_path, path
-
- if not publish_path:
- publish_path = os.path.realpath(link_path)
- else:
- root_path = os.path.realpath(link_path)
-
- if not root_path:
- ui.error('package not found')
-
- package = StaticPackage(root_path, publish_path = publish_path)
-
- if not os.path.exists(publish_path):
- if force:
- os.makedirs(publish_path)
- else:
- ui.msg(u'%s path not exists, run opm link path -f to create it.' % publish_path)
- return 1
-
- package.link()
-
- ui.msg(u'linked publish %s to %s' % (publish_path, root_path))
-
-@cwdarg
-@arg('publish_path')
-@option('force', '-f', '--force', help = u'强制编译', action = 'store_true')
-@option('rebuild', '-r', '--rebuild', help = u'重建索引库,确保发布文件完整', action = 'store_true')
-@usage(u'opm publish [源库路径] [发布库路径] [options]')
-def publish(path, publish_path = None, force = False, rebuild = False):
- u'''将整个发布库进行编译'''
-
- do_link = False
- # 指定了第二个参数,则path一定是一个源库,第二个参数则是发布库,并自动进行link
- if publish_path:
- root_path = StaticPackage.get_root(path)
- path = publish_path # 发布整个库
- do_link = True
- # 没有指定第二个参数,则path一定是一个发布库
- else:
- publish_path, root_path = StaticPackage.get_roots(path)
-
- if not publish_path:
- ui.msg(u'No publish path.')
- else:
- package = StaticPackage(root_path, publish_path = publish_path)
- if not package.publish_path:
- ui.msg(u'No publish path.')
- else:
- ui.msg(u'publish to %s' % (path,) + (' with rebuild' if rebuild else ''))
-
- if rebuild:
- # 遍历磁盘目录,慢
- all_files = package.get_publish_files()
- else:
- # 只搜索合并索引,快
- all_files = package.listener.get_files()
-
- for filename in all_files:
- compile(filename, package = package, force = force, no_build_files = True)
-
- buildfiles(package = package)
- if do_link:
- package.link()
-
-@cwdarg
-@usage(u'opm load [工作区路径]')
-def load(workspace):
- u''' 加载本地工作区 '''
-
- if workspace.__class__ == str:
- workspace_path = Workspace.get_workspace(workspace)
- if not workspace_path:
- workspace_path = workspace
-
- try:
- workspace = Workspace(workspace_path)
- except ConfigError as e:
- ui.error(u'config error %s' % e.path)
- return 1
-
- old_count = len(workspace.local_packages)
- workspace.load()
- added_count = len(workspace.local_packages) - old_count
-
- if len(workspace.useless_packages):
- for package in workspace.useless_packages:
- ui.msg(u'删除无用package %s' % package)
-
- ui.msg(u'已加入 %s 个源库' % added_count)
-
-@cwdarg
-@option('show_url', '-u', '--show-url', action = 'store_true', help = u'显示有url的源库的url')
-@usage(u'opm packages [工作区路径]')
-def packages(workspace_path, show_url = False):
- u''' 本工作区中所有源库 '''
-
- if os.path.isfile(workspace_path):
- workspace_path = os.path.dirname(workspace_path)
-
- # 有可能不是workspace跟路径,而是某个子路径
- workspace_path = Workspace.get_workspace(workspace_path)
- if not workspace_path:
- ui.error(u'没有工作区')
- return 1
- else:
- workspace = Workspace(workspace_path)
- if show_url:
- for url in workspace.url_packages.keys():
- ui.msg(url)
- else:
- for local_path in workspace.local_packages.keys():
- ui.msg(os.path.realpath(os.path.join(workspace.root, local_path)))
-
-@cwdarg
-@option('publish_path', '-p', '--publish-path', type = 'string', help = u'发布目录')
-@option('force', '-f', '--force', action = 'store_true', help = u'强制建立发布目录')
-def init(root_path, publish_path = None, force = False):
- u''' 初始化一个新的库
-
-初始化一个新的库,建立template-config.xml配置文件及常用的目录,如果指定了 -p 参数,还可以自动建立与发布目录的连接'''
-
- # 确保不要init了一个工作区
- if Workspace.get_workspace(root_path) == root_path:
- ui.error(u'工作区不能被初始化')
- return 1
-
- # 确保不要init了一个publish库
- if StaticPackage.get_publish(root_path):
- ui.error(u'发布目录不能被初始化')
- return 1
-
- ui.msg(u'初始化%s' % root_path)
- try:
- StaticPackage.init(root_path)
- ui.msg(u'创建配置文件')
-
- except PackageExistsException:
- ui.error(u'已经存在')
- return 1
-
- pathnames = ['test', 'doc', 'src', 'lib', 'res']
- for name in pathnames:
- path = os.path.join(root_path, name)
- if not os.path.exists(path):
- os.makedirs(path)
- ui.msg(u'生成默认目录 %s' % name)
-
- workspace_path = Workspace.get_workspace(root_path)
- if not workspace_path:
- ui.msg(u'没有工作区,请参照 opm help load')
- else:
- workspace = Workspace(workspace_path)
-
- if not workspace.has_package(root_path):
- workspace.add_package(root_path)
- ui.msg(u'加入本地工作区')
- else:
- ui.msg(u'本地工作区中已存在')
-
- ui.msg(u'成功!')
-
- if publish_path:
- link(root_path, publish_path, force = force)
-
-@cwdarg
-@usage(u'opm root [源库路径]')
-def root(root_path):
- u''' 源库的根路径 '''
- ui.msg(StaticPackage.get_root(root_path))
-
-@cwdarg
-@usage(u'opm source [源库路径] [options]')
-def source(publish_path):
- u''' 映射的源库路径 '''
- if StaticPackage.get_publish(publish_path):
- StaticPackage.get_root(publish_path)
- else:
- ui.error(u'不是一个发布库')
-
-@cwdarg
-def status(publish_path):
- u''' 检查发布库的编译状态 '''
- publish_path, root_path = StaticPackage.get_roots(publish_path)
- if not publish_path:
- ui.error(u'不是发布库')
- return 1
-
- package = StaticPackage(root_path, publish_path)
-
- files = package.get_publish_files()
- for filename in files:
- filetype = os.path.splitext(filename)[1]
-
- source, mode = package.parse(filename)
- try:
- rfiles = package.get_relation_files(source, all = True)
- except PackageNotFoundException, e:
- ui.error(u'%s package not found' % e.url)
- else:
- modified, not_exists = package.listener.check(filename, rfiles)
- if len(modified) or len(not_exists):
- for modified_file in modified:
- ui.msg('M ' + modified_file)
-
- for not_exists_file in not_exists:
- ui.msg('! ' + not_exists_file)
-
-@cwdarg
-@usage(u'opm libs [源库路径]')
-@option('show_url', '-u', '--show-url', help=u'显示url而非本地路径', action='store_true')
-@option('all', '-a', '--all', help=u'递归显示所有', action='store_true')
-@option('reverse', '-r', '--reverse', help=u'显示被依赖的', action='store_true')
-def libs(root_path, show_url = False, all = False, reverse = False):
- u''' 库的相关依赖库 '''
- root_path = StaticPackage.get_root(root_path)
- if not root_path:
- ui.error(u'不是源库')
- return 1
-
- package = StaticPackage(root_path)
- # 这个库没有设置url,不可能被别的库依赖
- if not package.url:
- ui.error(u'no url')
- return 1
-
- # 显示依赖自己的
- if reverse:
- try:
- libs = package.get_reverse_libs(all = all)
- except PackageNotFoundException, e:
- ui.error(u'%s package not found' % e.url)
- return 1
- # 显示依赖了谁
- else:
- try:
- libs = package.get_libs(all = all)
- except PackageNotFoundException, e:
- ui.error(u'%s package not found' % e.url)
- return 1
-
- if show_url:
- if package.workspace:
- for local_path in libs:
- url = package.workspace.local_packages.get(local_path)
- if url:
- ui.msg(url)
-
- else:
- ui.error(u'没有工作区')
- else:
- for local_path in libs:
- ui.msg(local_path)
-
-@arg('filename')
-@option('all', '-a', '--all', help=u'递归显示所有', action='store_true')
-@option('reverse', '-r', '--reverse', help=u'显示被依赖的', action='store_true')
-def incs(filename, all = False, reverse = False):
- u''' 某文件所有依赖的文件 '''
-
- filename = os.path.realpath(filename)
- root_path = StaticPackage.get_root(filename)
- package = StaticPackage(root_path)
-
- filetype = os.path.splitext(filename)[1]
-
- if reverse:
- if filetype == '.css':
- ui.error(u'Not support yet, sorry.')
- return 1
- else:
- files = package.get_included(filename, all = all)
- else:
- files = package.get_relation_files(filename, all = all)
-
- for file in files:
- ui.msg(file)
-
-@cwdarg
-@option('fastcgi', '--fastcgi', help = u'使用fastcgi进行serve', action = 'store_true')
-@option('port', '--port', help = u'指定端口号', type = 'int')
-@option('debug', '-d', '--debug', help = u'debug模式', action = 'store_true')
-@option('noload', '-L', '--noload', help = u'启动时不load工作区', action = 'store_true')
-@option('hg', '--hg', help = u'同时开启hgweb', action = 'store_true')
-@option('hg_port', '--hg-port', help = u'hg serve端口', type='int')
-def serve(workspace_path, fastcgi = False, port = 8080, debug = False, noload = False, hg = False, hg_port = 8000):
- u''' 启动一个可实时编译的静态服务器
-
-请指定工作区路径'''
-
- if Workspace.is_root(workspace_path):
- workspace = Workspace(os.path.realpath(workspace_path))
- if not noload:
- load(workspace = workspace)
- else:
- ui.error(u'工作区无效');
- workspace = None
-
- def print_request(environ, start_response):
- ''' 输出fastcgi本次请求的相关信息 '''
-
- import cgi
- start_response('200 OK', [('Content-Type', 'text/html')])
- yield '
Hello World! \n' \
- '\n' \
- 'Hello World!
\n' \
- ''
- names = environ.keys()
- names.sort()
- for name in names:
- yield '%s %s \n' % (
- name, cgi.escape(`environ[name]`))
-
- form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,
- keep_blank_values=1)
- if form.list:
- yield 'Form data '
-
- for field in form.list:
- yield '%s %s \n' % (
- field.name, field.value)
-
- yield '
\n' \
- '\n'
-
- def listen(environ, start_response):
- ''' 监听请求 '''
- if environ['DOCUMENT_URI'].endswith('/net.test'):
- return print_request(environ, start_response)
-
- DEBUG = debug
-
- filename = os.path.realpath(environ['REQUEST_FILENAME'])
- url = environ['DOCUMENT_URI']
-
- force = False # 是否强制重新编译
- # 没有 referer 时强制重新编译
- if not 'HTTP_REFERER' in environ.keys():
- force = True
-
- try:
- publish_path, root_path = StaticPackage.get_roots(filename, workspace = workspace)
- except PackageNotFoundException, e:
- ui.error(u'%s package not found' % e.url)
- else:
- # 直接访问源文件时没有publish_path,不进行编译
- if root_path:
- package = StaticPackage(root_path, publish_path, workspace = workspace)
- compile(filename, package = package, force = force, no_build_files = True)
- buildfiles(package = package)
-
- mimetypes = {
- '.css': 'text/css',
- '.js': 'text/javascript'
- }
- mimetype = mimetypes[os.path.splitext(filename)[1]]
-
- if not os.path.exists(filename):
- # 文件不存在
- start_response('404 Not Found', [])
- return '404 Not Found'
-
- start_response('200 OK', [('Content-Type', mimetype)])
- return [open(filename).read()]
-
- # 启动 hg serve
- if workspace and hg:
- config_path = os.path.join(workspace.root, 'hgweb.config')
- if not os.path.exists(config_path):
- config_file = open(config_path, 'w')
- config_file.write(u'[web]\nallow_push=*\npush_ssl=false\nstyle=monoblue\nbaseurl=\n[paths]\n/=**\n')
- config_file.close()
-
- ui.msg(u'已开启hgweb于%s端口' % hg_port)
- os.popen('hg serve --webdir-conf %s --daemon --port %s' % (config_path, hg_port))
-
- if fastcgi:
- WSGIServer(listen, bindAddress=('localhost', port), debug = debug).run()
- else:
- ui.msg(u'现在还不支持server,请使用 opm serve --fastcgi 方式')
-
-def main():
- commands = [get, init, compile, publish, link, load, serve, packages, workspace, root, source, status, libs, incs]
- if len(sys.argv) < 2:
- ui.msg(u'使用 opm help 得到用法')
- else:
- command = sys.argv[1]
- if command == 'help':
- subcommand = None
- if len(sys.argv) > 2:
- subcommand = globals()[sys.argv[2]]
- utils.commandline.help(commands, subcommand)
- else:
- all = globals()
- if command in all:
- utils.commandline.call(commands, globals()[command])
- else:
- utils.commandline.help(commands)
diff --git a/css/__init__.py b/css/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/css/cssrevisionpath.py b/css/cssrevisionpath.py
deleted file mode 100644
index e5cee07..0000000
--- a/css/cssrevisionpath.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#python
-#coding=utf-8
-
-import re
-import os
-import os.path
-from urlparse import urlparse, urljoin
-from xml.etree import ElementTree
-
-def generateRevisionUrl(url, compiler):
- ''' 生成版本号路径 '''
-
- localpath = compiler.translatePath(url)
- if not (localpath and os.path.exists(localpath)):
- # 本地不存在这个文件,返回原始url
- return url
-
- newurl = urljoin(compiler.cururl, url).split('/')
- urlarr = []
- lastRevisionUrl = ''
- lastPart = ''
- lastRevision = ''
- for i in range(len(newurl), 0, -1):
- part = newurl[i - 1]
- localpath = '/'.join(newurl[0:i])
- if localpath == '':
- localpath = '/'
-
- localpath = compiler.translatePath(localpath)
-
- infoXml = ElementTree.fromstring(os.popen('svn info --xml %s' % localpath).read())
- revisionUrl = infoXml.find('entry/url').text
- revision = infoXml.find('entry/commit').attrib['revision']
-
- if revisionUrl + '/' + lastPart != lastRevisionUrl:
- if lastRevision:
- #urlarr[-1] = urlarr[-1] + 'a%s' % lastRevision
- urlarr.append('%s' % lastRevision)
-
- lastRevision = revision
-
- urlarr.append(part)
- lastRevisionUrl = revisionUrl
- lastPart = part
-
- urlarr.insert(-1, '%s' % lastRevision)
- newurl = '/'.join(urlarr[::-1])
-
- return newurl
-
-
-def generateRevisionUrl2(url, compiler):
- ''' 新版生成版本号路径 '''
-
- localpath = compiler.translatePath(url)
- if not (localpath and os.path.exists(localpath)):
- # 本地不存在这个文件,返回原始url
- return url
-
- newurl = urljoin(compiler.cururl, url)
- infoXml = ElementTree.fromstring(os.popen('svn info --xml %s' % localpath).read())
- revision = infoXml.find('entry/commit').attrib['revision']
- repositoryUrl = infoXml.find('entry/repository/root').text
- repositoryName = ElementTree.fromstring(os.popen('svn propget --xml xn:name %s' % repositoryUrl).read()).find('target/property').text
- #newurl = '/' + repositoryName + '_' + revision + newurl
- newurl = '/' + 'a' + revision + newurl
-
- return newurl
-
-
-def generateRevisionUrl3(url, compiler):
- localpath = compiler.translatePath(url)
- if not (localpath and os.path.exists(localpath)):
- # 本地不存在这个文件,返回原始url
- return url
-
- newurl = 'http://xnimg.cn' + urljoin(compiler.puburl, url)
-
- return newurl
-
-
-def cssRevisionPath(css, compiler):
- ''' 给css中的所有 url() (包括import url,但是此时import应该已经被替换成内容了) 增加版本号 '''
-
- prefix = re.search(r'\/\*Prefix=(.+?)\*\/', css)
- if prefix:
- prefix = prefix.group(1)
- else:
- prefix = compiler.urlPrefix
-
- def urlReplace(m):
- url = m.group(1)
- # 去掉 http 前缀
- if url.startswith(compiler.urlPrefix):
- url = url[len(compiler.urlPrefix):]
-
- newurl = generateRevisionUrl3(url, compiler)
-
- return 'url(' + newurl + ')'
-
- return re.sub(r'url\([\'"]?(.+?)[\'"]?\)', urlReplace, css)
-
-
-
diff --git a/css/cssrulecompiler.py b/css/cssrulecompiler.py
deleted file mode 100644
index 53ce576..0000000
--- a/css/cssrulecompiler.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#python
-#coding=utf-8
-
-import re
-
-class CSSRuleCompiler():
-
- def __init__(self):
- self.mode = 'std'
- self.rule = None
- self.sprites = []
-
-
- def getStyle(self, name):
- names = self.rule.style.keys()
- ie6Name = '_' + name
- ieName = '*' + name
- if ((self.mode == 'ie6' and (ie6Name in names or ieName in names))) or (self.mode == 'ie7' and ieName in names):
- value = ''
- for property in self.rule.style:
- if property.name in (name):
- value = property.value
-
- if self.mode == 'ie6' and property.name in (name, ieName, ie6Name):
- value = property.value
-
- if self.mode == 'ie7' and property.name in (name, ieName):
- value = property.value
-
- else:
- value = self.rule.style[name]
-
- return value
-
-
- def ieContent(self, rule):
- ''' content '''
-
- content = self.getStyle('content')
- if content and content != '"\\20"':
- # content: '\20' 为清除浮动,不做处理
- content = re.sub('^"(.*?)"$', lambda m: m.group(1).replace('\'', '\\\\\\\''), content)
- rule.style['behavior'] = 'expression("ele.runtimeStyle.behavior=\'none\';Expressions.style.content(ele, \'' + content + '\');!run-once")'
-
- def ie6PositionFixed(self, rule):
- ''' positioin: fixed '''
-
- if self.getStyle('position') == 'fixed':
- rule.style.position = 'expression("ele.runtimeStyle.position=\'absolute\';Expressions.style.position.fixed(ele);!run-once")'
-
-
- def ie6PositionFixedDelay(self, rule):
- ''' fixed position delay '''
-
- delay = self.getStyle('-ie6-position-fixed-delay')
- if delay:
- rule.style['behavior'] = 'expression("ele.runtimeStyle.behavior=\'none\';Expressions.style.position.fixed.delay(ele, ' + delay + ');!run-once")'
-
-
- def ie6LineHeightFix(self, rule):
- if self.getStyle('-ie6-line-height-fix') == 'fix':
- rule.style['_letter-spacing'] = 'expression("ele.runtimeStyle.letterSpacing=\'0\';Expressions.style.fixLineHeight(ele);!run-once");'
-
-
- def ie6FloatFix(self, rule):
- if self.getStyle('float'):
- # 浮动双倍margin
- rule.style['display'] = 'inline'
-
-
- def ie6MinWidth(self, rule):
- if self.getStyle('min-width'):
- # min-width
- rule.style.width = 'expression("ele.runtimeStyle.width=\'auto\';Expressions.style.minWidth(ele, \'' + self.getStyle('min-width') + '\');!run-once")'
-
-
- def ieBoxSizingBorderBox(self, rule):
- if self.getStyle('box-sizing') == 'border-box':
- rule.style['zoom'] = 'expression("ele.runtimeStyle.zoom=\'1\';Expressions.style.boxSizing.borderBox(ele);!run-once");'
-
-
- def ieInlineBlock(self, rule):
- if self.getStyle('display') == 'inline-block':
- rule.style['display'] = 'inline'
- rule.style['zoom'] = '1'
-
-
- def ieOutline(self, rule):
- if self.getStyle('outline') == '0 none':
- rule.style['zoom'] = 'expression("ele.runtimeStyle.zoom=\'1\';Expressions.style.outline(ele, \'0 none\');!run-once");'
-
-
- def compile(self, sheet, mode):
- for i, rule in enumerate(sheet.cssRules):
- if rule.typeString == 'STYLE_RULE':
- self.rule = rule
- if mode == 'std':
- rule = self.compileStandard(rule, i)
- elif mode == 'ie6':
- rule = self.compileIE6(rule, i)
- elif mode == 'ie7':
- rule = self.compileIE7(rule, i)
-
-
- def compileIE6(self, rule, i):
- self.mode = 'ie6'
-
- self.ie6PositionFixed(rule)
- self.ie6PositionFixedDelay(rule)
- self.ie6LineHeightFix(rule)
- self.ie6FloatFix(rule)
- self.ie6MinWidth(rule)
- #self.ieBoxSizingBorderBox(rule)
- self.ieContent(rule)
- self.ieInlineBlock(rule)
- self.ieOutline(rule)
-
- #if rule.style.position == 'relative':
- #rule.style['_zoom'] = '1'
-
- return rule
-
-
- def compileIE7(self, rule, i):
- self.mode = 'ie7'
- ie6UsePrefix = ('_', '-ie6-')
-
- self.ieInlineBlock(rule)
- self.ieContent(rule)
- self.ieOutline(rule)
-
- for property in rule.style:
- for prefix in ie6UsePrefix:
- if property.name.startswith(prefix):
- rule.style.removeProperty(property.name)
-
- return rule
-
-
- def compileStandard(self, rule, i):
- self.mode = 'std'
-
- ieUsePrefixs = ['_', '*', '-ie-', '-ie6-', '-ie7-']
- for property in rule.style:
- # 删除所有IE专有属性
- for prefix in ieUsePrefixs:
- if property.name.startswith(prefix):
- rule.style.removeProperty(property.name)
-
-
- def compileAll(self, rule, i):
- self.mode = 'ie6'
-
- self.ie6PositionFixed(rule)
- self.ie6PositionFixedDelay(rule)
- self.ie6LineHeightFix(rule)
- self.ie6FloatFix(rule)
- self.ie6MinWidth(rule)
- #self.ieBoxSizingBorderBox(rule)
- self.ieContent(rule)
- self.ieInlineBlock(rule)
- self.ieOutline(rule)
-
- #if rule.style.position == 'relative':
- #rule.style['_zoom'] = '1'
-
- return rule
-
-
- def compileIE7(self, rule, i):
- self.mode = 'ie7'
- ie6UsePrefix = ('_', '-ie6-')
-
- self.ieInlineBlock(rule)
- self.ieContent(rule)
- self.ieOutline(rule)
-
- for property in rule.style:
- for prefix in ie6UsePrefix:
- if property.name.startswith(prefix):
- rule.style.removeProperty(property.name)
-
- return rule
diff --git a/css/cssselectorcompiler.py b/css/cssselectorcompiler.py
deleted file mode 100644
index 607dc68..0000000
--- a/css/cssselectorcompiler.py
+++ /dev/null
@@ -1,411 +0,0 @@
-#python
-#coding=utf-8
-
-import re
-
-def getTrigger(cssId, selectorHacks):
- if not selectorHacks: return None
- rulestr = '#CSSID_' + cssId + ' {_display: expression("ele.runtimeStyle.display=\'block\';'
- for hack in selectorHacks:
- rulestr += 'Expressions.selector(\'' + hack[0].replace('\'', '\\\\\\\'') + '\', \'' + 'h_' + cssId + '_' + str(hack[1]) + '\');'
-
- rulestr = rulestr + '!run-once");}'
- return rulestr
-
-class CSSSelectorCompiler():
- ''' 微软浏览器的CSS兼容性列表:
-
- http://msdn.microsoft.com/en-us/library/cc351024%28VS.85%29.aspx
-
- '''
-
- def __init__(self):
- self.hackedSelector = self.hackedSelector2 = {}
- self.selectorHacks = []
- self.hackid = 1
- self.cssId = ''
-
- self.combinator_compile = True
-
-
- def getHackId(self, hackid = ''):
- if not hackid: hackid = self.hackid
- return 'h_' + self.cssId + '_' + str(hackid)
-
-
- def deparseSelectorPart(self, part, noCombinator = False):
- ''' 将selector部分对象转换成selector字符串, noCombinator不转换选择符 '''
-
- text = ''
-
- if not noCombinator and 'combinator' in part.keys() and part['combinator']:
- text += part['combinator']
-
- if 'tag' in part.keys() and part['tag']:
- text += part['tag']
-
- if len(part['ident']) >= 2 and part['ident'][1] == '*':
- text += '*'
-
- if 'id' in part.keys() and part['id']:
- text += '#' + part['id']
-
- if 'classes' in part.keys() and part['classes']:
- for className in part['classes']:
- text += '.' + className
-
- if 'attributes' in part.keys() and part['attributes']:
- for attribute in part['attributes']:
- text += '[' + attribute['name']
- if attribute['operator']:
- text += attribute['operator'] + "'" + attribute['value'] + "'"
-
- text += ']'
-
- if 'pseudos' in part.keys() and part['pseudos']:
- for pseudo in part['pseudos']:
- text += ':' + pseudo['name']
- if pseudo['value']:
- text += '(' + pseudo['value'] + ')'
-
- return text
-
-
- def deparseSelector(self, selector):
- ''' 转换整个selector '''
- text = ''
- for part in selector:
- text += self.deparseSelectorPart(part)
-
- return text
-
-
- def parseSelector(self, text):
- ''' 解析选择器字符串为对象,核心算法来自Sly.js '''
-
- pattern = re.compile(ur'''[\w\u00a1-\uFFFF][\w\u00a1-\uFFFF-]*|[#.](?:[\w\u00a1-\uFFFF-]|\\:|\\.)+|[ \t\r\n\f](?=[\w\u00a1-\uFFFF*#.[:])|[ \t\r\n\f]*(,|>|\+|~)[ \t\r\n\f]*|\[([\w\u00a1-\uFFFF-]+)[ \t\r\n\f]*(?:([!*=^=$=~=|=]?=)[ \t\r\n\f]*(?:"([^"]*)"|'([^']*)'|([^\]]*)))?]|:([-\w\u00a1-\uFFFF]+)(?:\((?:"([^"]*)"|'([^']*)'|([^)]*))\))?|\*|(.+)''')
-
- def create(combinator):
- return {
- 'ident': [],
- 'classes': [],
- 'attributes': [],
- 'pseudos': [],
- 'combinator': combinator
- }
-
- parsed = []
- current = create(None)
- current['first'] = True
-
- def refresh(combinator, current):
- parsed.append(current)
- current = create(combinator)
-
- return current
-
- match = None
- first = None
-
- results = pattern.finditer(text)
- for result in results:
- match = [result.group(0)]
- match.extend(result.groups())
-
- if match[-1]:
- print 'error'
- return []
-
- first = match[0]
- char = first[0]
-
- if char == '.':
- current['classes'].append(first[1:].replace('\\', ''))
-
- elif char == '#':
- current['id'] = first[1:].replace('\\', '')
-
- elif char == '[':
- current['attributes'].append({
- 'name': match[2],
- 'operator': match[3] or None,
- 'value': match[4] or match[5] or match[6] or None
- })
-
- elif char == ':':
- current['pseudos'].append({
- 'name': match[7],
- 'value': match[8] or match[9] or match[10] or None
- })
-
- else:
- if char in (' ', '\t', '\r', '\n', '\f'):
- match[1] = match[1] or ' '
-
- combinator = match[1]
-
- if combinator:
- if combinator == ',':
- current['last'] = True
- current = refresh(null, current)
- current['first'] = True
- continue
-
- if 'first' in current and not len(current['ident']):
- current['combinator'] = combinator
-
- else:
- current = refresh(combinator, current)
- else:
- if first != '*':
- current['tag'] = first
-
- current['ident'].append(first);
-
- current['last'] = True;
- parsed.append(current);
-
- return parsed;
-
-
- def insertTrigger(self, sheet):
- ''' 将Expression加入到css文件中 '''
-
- sheet.insertRule(cssselectorcompiler.getTrigger(self.cssId, self.selectorHacks))
-
-
- def compile(self, sheet, cssId, mode, doInsertTrigger = True):
- if mode not in ('ie6', 'ie7'):
- return []
-
- self.cssId = cssId
- for i, rule in enumerate(sheet.cssRules):
- if rule.typeString == 'STYLE_RULE':
- if mode == 'ie6':
- rule = self.compileIE6(rule, i)
-
- elif mode == 'ie7':
- rule = self.compileIE7(rule, i)
-
- if doInsertTrigger: self.insertTrigger(sheet)
- return self.selectorHacks
-
-
- def compileIE7(self, rule, i):
- ''' 将selector解析成IE7可用 '''
-
- pseudoTriggers = {
- 'hover' : ('page-break-before', 'pageBreakBefore', 'auto'),
- 'disabled' : ('page-break-after', 'pageBreakAfter', 'auto'),
- }
-
- for selector in rule.selectorList:
-
- prefix = ''
- prefix2 = ''
-
- selectorSeq = self.parseSelector(selector.selectorText)
- selectorSeq2 = self.parseSelector(selector.selectorText)
-
- for j, partSeq2 in enumerate(selectorSeq2):
- partSeq = selectorSeq[j]
- needCompile = False
- compileStatusPseudo = False
-
- if partSeq2['pseudos']:
- #伪类
- for k, pseudo in enumerate(partSeq2['pseudos']):
- if (pseudo['name'] in ('focus', 'disabled', 'enabled')) \
- or (pseudo['name'] in ('before', 'after') and rule.style.content not in ('"\\20"', "'\\20'")):
- partSeq2['pseudos'].remove(pseudo)
- partSeq['pseudos'].pop(k)
- needCompile = True
- compileStatusPseudo = pseudo['name']
-
- prefix += self.deparseSelectorPart(partSeq)
-
- if needCompile and compileStatusPseudo:
- if compileStatusPseudo in ('after', 'before'):
- prefix2 += self.deparseSelectorPart(partSeq2)
- if compileStatusPseudo == 'after':
- rule.parentStyleSheet.insertRule(prefix2 + '{behavior:expression("ele.runtimeStyle.behavior=\'none\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
-
- else:
- rule.parentStyleSheet.insertRule(prefix2 + '{zoom:expression("ele.runtimeStyle.zoom=\'1\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
-
- selectorSeq.append({
- 'tag': compileStatusPseudo,
- 'ident': [],
- 'classes': [],
- 'attributes': [],
- 'pseudos': [],
- 'combinator': ' '
- })
- selectorSeq2.append({
- 'tag': compileStatusPseudo,
- 'ident': [],
- 'classes': [],
- 'attributes': [],
- 'pseudos': [],
- 'combinator': ' '
- })
-
- else:
- if prefix in self.hackedSelector.keys():
- # 已经处理过
- partSeq2['classes'] = [self.getHackId(self.hackedSelector2[prefix])]
-
- prefix2 += self.deparseSelectorPart(partSeq2)
- if compileStatusPseudo in pseudoTriggers:
- trigger = pseudoTriggers[compileStatusPseudo]
-
- else:
- trigger = ('behavior', 'behavior', 'none')
-
- rule.parentStyleSheet.insertRule(prefix2 + '{' + trigger[0] + ':expression("ele.runtimeStyle.' + trigger[1] + '=\'' + trigger[2] + '\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
- partSeq2['classes'] = [self.getHackId()]
- prefix2 += self.deparseSelectorPart(partSeq2)
- self.hackid += 1
-
- elif needCompile and not compileStatusPseudo:
- if prefix in self.hackedSelector.keys():
- # 已经处理过
- partSeq2['classes'] = [self.getHackId(self.hackedSelector2[prefix])]
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- else:
- # 需要处理
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- self.selectorHacks.append((prefix, self.hackid))
- self.hackedSelector[prefix2] = self.hackid
- self.hackedSelector[prefix] = self.hackid
-
- partSeq2['classes'] = [self.getHackId()]
- self.hackid += 1
-
- else:
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- selector.selectorText = self.deparseSelector(selectorSeq2)
-
- return rule
-
-
- def compileIE6(self, rule, i):
- ''' 将selector解析成IE6可用 '''
-
- pseudoTriggers = {
- 'hover' : ('page-break-before', 'pageBreakBefore', 'auto'),
- 'disabled' : ('page-break-after', 'pageBreakAfter', 'auto'),
- }
-
- for selector in rule.selectorList:
-
- prefix = ''
- prefix2 = ''
-
- selectorSeq = self.parseSelector(selector.selectorText)
- selectorSeq2 = self.parseSelector(selector.selectorText)
-
- for j, partSeq2 in enumerate(selectorSeq2):
- partSeq = selectorSeq[j]
- needCompile = False
- compileStatusPseudo = False
-
- if partSeq2['combinator'] == ">" or len(partSeq2['classes']) > 1:
- #子选择符
- partSeq2['combinator'] = ' '
- if self.combinator_compile:
- partSeq2['classes'] = []
- needCompile = True
-
- if partSeq2['attributes']:
- for k, pseudo in enumerate(partSeq2['attributes']):
- partSeq2['attributes'].remove(pseudo)
- needCompile = True
-
- if partSeq2['pseudos']:
- #伪类
- for k, pseudo in enumerate(partSeq2['pseudos']):
- if pseudo['name'] in ('nth-child', 'not'):
- partSeq2['pseudos'].remove(pseudo)
- needCompile = True
-
- elif ('tag' not in partSeq2.keys() or partSeq2['tag'] != 'a') and pseudo['name'] == 'hover' \
- or (pseudo['name'] in ('focus', 'disabled', 'enabled')) \
- or (pseudo['name'] in ('before', 'after') and rule.style.content not in ('"\\20"', "'\\20'")):
- partSeq2['pseudos'].remove(pseudo)
- partSeq['pseudos'].pop(k)
- needCompile = True
- compileStatusPseudo = pseudo['name']
-
- prefix += self.deparseSelectorPart(partSeq)
-
- if needCompile and compileStatusPseudo:
- if compileStatusPseudo in ('after', 'before'):
- prefix2 += self.deparseSelectorPart(partSeq2)
- if compileStatusPseudo == 'after':
- rule.parentStyleSheet.insertRule(prefix2 + '{behavior:expression("ele.runtimeStyle.behavior=\'none\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
-
- else:
- rule.parentStyleSheet.insertRule(prefix2 + '{zoom:expression("ele.runtimeStyle.zoom=\'1\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
-
- selectorSeq.append({
- 'tag': compileStatusPseudo,
- 'ident': [],
- 'classes': [],
- 'attributes': [],
- 'pseudos': [],
- 'combinator': ' '
- })
- selectorSeq2.append({
- 'tag': compileStatusPseudo,
- 'ident': [],
- 'classes': [],
- 'attributes': [],
- 'pseudos': [],
- 'combinator': ' '
- })
-
- else:
- if prefix in self.hackedSelector.keys():
- # 已经处理过
- partSeq2['classes'] = ['h_' + self.cssId + '_' + str(self.hackedSelector2[prefix])]
-
- prefix2 += self.deparseSelectorPart(partSeq2)
- if compileStatusPseudo in pseudoTriggers:
- trigger = pseudoTriggers[compileStatusPseudo]
-
- else:
- trigger = ('behavior', 'behavior', 'none')
-
- rule.parentStyleSheet.insertRule(prefix2 + '{' + trigger[0] + ':expression("ele.runtimeStyle.' + trigger[1] + '=\'' + trigger[2] + '\';Expressions.pseudo.' + compileStatusPseudo + '(ele,\'' + self.getHackId() + '\');!run-once");}')
- partSeq2['classes'] = [self.getHackId()]
- prefix2 += self.deparseSelectorPart(partSeq2)
- self.hackid += 1
-
- elif needCompile and not compileStatusPseudo:
- if prefix in self.hackedSelector.keys():
- # 已经处理过
- partSeq2['classes'] = ['h_' + self.cssId + '_' + str(self.hackedSelector2[prefix])]
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- else:
- # 需要处理
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- self.selectorHacks.append((prefix, self.hackid))
- self.hackedSelector[prefix2] = self.hackid
- self.hackedSelector[prefix] = self.hackid
-
- partSeq2['classes'] = [self.getHackId()]
- self.hackid += 1
-
- else:
- prefix2 += self.deparseSelectorPart(partSeq2)
-
- selector.selectorText = self.deparseSelector(selectorSeq2)
-
- return rule
-
diff --git a/css/cssspritegenerator.py b/css/cssspritegenerator.py
deleted file mode 100644
index c3fa169..0000000
--- a/css/cssspritegenerator.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#python
-#coding=utf-8
-
-import re
-
-def base64Encode(localpath):
- ''' base64 '''
-
- import StringIO
-
- if os.path.exists(localpath):
- localfile = open(localpath, 'rb')
- base64io = StringIO.StringIO()
- base64.encode(localfile, base64io)
- base64str = base64io.getvalue()
- localfile.close()
- base64io.close()
- return base64str.replace('\n', '')
-
- return ""
-
-
-def cssDataURI(css):
- ''' data-uri '''
-
- on = re.search(r'\/\*DATA_URI=TRUE\*\/', css)
- if not on:
- return css
-
- def urlReplace(m):
- url = m.group(1)
- localpath = self.translatePath(url)
- if localpath:
- if not mimetypes.inited:
- mimetypes.init() # get system mime.types
-
- base64str = base64Encode(localpath)
- if not base64str:
- newurl = url
- else:
- newurl = 'data:' + mimetypes.types_map[os.path.splitext(localpath)[1]] + ';base64,' + base64str
- else:
- newurl = url
-
- return 'url(\'' + newurl + '\')'
-
- return re.sub(r'url\([\'"]?(.+?)[\'"]?\)', urlReplace, css)
-
-
-def cssIEDataURI(basename, css):
- ''' data-uri '''
-
- on = re.search(r'\/\*DATA_URI=TRUE\*\/', css)
- if not on:
- return css
-
- mhtmlSeparator = '_MY_BOUNDARY_SEPARATOR'
- mhtmlName = '_' + basename + '.mhtml.css'
- mhtml = 'Content-Type: multipart/related; boundary="' + mhtmlSeparator + '"' + 2 *'\n'
- pi = 0
-
- def createMHTMLSection(path, pi):
- filename = os.path.basename(path)
- section = '--' + mhtmlSeparator + '\n' \
- + 'Content-Location:file' + str(pi) + '\n' \
- + 'Content-Transfer-Encoding:base64' + 2 * '\n' \
- + base64Encode(path) + '\n'
-
- return section
-
- def urlReplace(m, pi, mhtml):
- url = m.group(1)
- localpath = self.translatePath(url)
- if localpath:
- if not mimetypes.inited:
- mimetypes.init() # get system mime.types
-
- mhtml += createMHTMLSection(localpath, pi)
-
- newurl = 'mhtml:' + self.rooturl + urljoin(self.cururl, mhtmlName) + '!file' + str(pi)
- else:
- newurl = url
-
- pi += 1
-
- return 'url(\'' + newurl + '\')'
-
- css = re.sub(r'url\([\'"]?(.+?)[\?&]uri-data=(.+?)[\'"]?\)', lambda m: urlReplace(m, pi, mhtml), css)
-
- mhtmlfile = open(self.translatePath(mhtmlName), "w")
- mhtmlfile.write(mhtml)
- mhtmlfile.close()
-
- return css
-
- def getSpriteConf(self, spritePath):
- ''' 读取 sprite 配置文件为conf对象 '''
-
- confPath = spritePath + '.conf'
-
- try:
- confFile = open(confPath, 'r')
- except:
- return {}
-
- confList = confFile.read().split('\n')
- conf = {}
- for c in confList:
- if c != '':
- l = c.split(' ')
- if l[0] == 'define':
- key = l[1]
- conf[key] = l[2:]
- conf[key][0] = int(conf[key][0])
- conf[key][1] = int(conf[key][1])
- conf[key].append(True)
- else:
- key = l[0]
- conf[key] = l[1:]
- conf[key][0] = int(conf[key][0])
- conf[key][1] = int(conf[key][1])
- conf[key].append(False)
-
- confFile.close()
-
- return conf
-
-
- def setSpriteConf(self, spritePath, conf):
- ''' 将conf配置写入到sprite配置文件中 '''
-
- result = sorted(conf.items(), key = lambda (k, v): (v[0], v[1]))
-
- confStr = ''
- for c in result:
- key = c[0]
- value = c[1]
- if value[2] == True:
- confStr += 'define '
-
- confStr += ' '.join([key, str(value[0]), str(value[1])])
- confStr += '\n'
-
- confPath = spritePath + '.conf'
- confFile = open(confPath, 'w')
- confFile.write(confStr)
- confFile.close()
-
-
- def cssSprite(self, rule):
- ''' 处理 background 属性,生成 CSS Sprite '''
-
- def relativePath(url1, url2):
- ''' 给出url2相对于url1的相对路径字符串 '''
-
- # 去掉 ./ 这种表示当前目录的,学习一下 (?<=) 这种前导匹配
- url1 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url1)
- url2 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url2)
- url1 = url1.split('/')
- url2 = url2.split('/')
- pos = 0
- for i, part in enumerate(url1):
- if url2[i] != part:
- break
- else:
- pos = i
-
- url2 = url2[i:]
- return (len(url1[i:]) - len(url2)) * '../' + '/'.join(url2)
-
- match = re.search('url\(([a-zA-Z0-9\.\/_-]+)\?sprite=([a-zA-Z0-9\.\/_-]+)(?:\&left\=(-?\d+))?(?:\&top\=(-?\d+))?\)\s+.+?\s+(0|left|\d+px)?\s+(0|top|\d+px)?', self.getStyle('background'))
- if match:
- sourceUrl, spriteUrl, left, top, positionX, positionY = match.groups()
-
- # 如果给出了left或者top的定位信息,则通过这个信息定位图片,否则为非编译模式,仅读取
- compileMode = bool(left or top)
-
- left = int(left) if left else 0
- top = int(top) if top else 0
-
- positionX = int(positionX.replace('px', '')) if positionX not in (None, 'left') else 0
- positionY = int(positionY.replace('px', '')) if positionY not in (None, 'top') else 0
-
- spriteUrl = urljoin(sourceUrl, spriteUrl)
-
- # 修改css中的background-image和background-position属性为新的图片和定位信息,此定位信息不可从配置文件中获取,以确保css文件中写的定位信息是准确的。
- self.rule.style.backgroundImage = 'url(' + spriteUrl + ')'
- self.rule.style.backgroundPosition = str(-left + positionX) + 'px ' + str(-top + positionY) + 'px'
-
- # 将此文件加入到待处理数组中,处理完整个css文件后通过调用doSprite生成图片文件
- if spriteUrl not in self.sprites:
- self.sprites.append(spriteUrl)
-
- # 编译模式,更新配置文件
- if compileMode:
- sourceKey = relativePath(spriteUrl, sourceUrl) # 文件的相对路径为conf的key
- spritePath = self.compiler.translatePath(spriteUrl)
- conf = self.getSpriteConf(spritePath)
- if not (sourceKey in conf.keys() and conf[sourceKey][2] == True):
- # 图片需要被处理
- conf[sourceKey] = [left, top, False]
- self.setSpriteConf(spritePath, conf)
-
-
- def doSprite(self):
- ''' 每个css文件仅执行一次CSS Sprite图片合并,在css编译结束前调用一次 '''
-
- for spriteUrl in self.sprites:
- spritePath = self.compiler.translatePath(spriteUrl)
- conf = self.getSpriteConf(spritePath)
-
- cmd = 'convert'
- for key in conf:
- value = conf[key]
- sourcePath = self.compiler.translatePath(urljoin(spriteUrl, key))
- cmd += ' -page +' + str(value[0]) + '+' + str(value[1]) + ' ' + sourcePath
-
- cmd += ' -background none -mosaic png8:' + spritePath
-
- os.system(cmd)
- print 'generated css sprite:', spriteUrl
-
- self.sprites = []
-
diff --git a/csscompiler.py b/csscompiler.py
deleted file mode 100644
index 632f1cd..0000000
--- a/csscompiler.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#python
-#coding=utf-8
-
-import os
-import sys
-import re
-import base64
-import mimetypes
-import logging
-from urlparse import urlparse, urljoin
-
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'cssutils-0.9.7a3-py2.6.egg'))
-import cssutils
-import cssutils.cssproductions
-
-import css.cssselectorcompiler as cssselectorcompiler
-import css.cssrulecompiler as cssrulecompiler
-
-DEVELOPMENT = True
-DEBUG = False
-SUPPORT_COMPILE_MODE = ('std', 'ie6', 'ie7', 'all') # TODO:需要一个 allie 的mode,以避免IE条件注释的bug造成的影响
-
-cssutils.cssproductions.PRODUCTIONS.insert(1, cssutils.cssproductions._DXImageTransform) # 从settings中获得的代码,支持DXImageTransform
-cssutils.cssproductions.PRODUCTIONS.insert(1, ('FUNCTION', r'\(?\s*function\s*\(({ident},?\s*)*\)\s*\{(\s|\S)*?\}\s*\)?\((({ident}|\.),?\s*)*\)'))
-cssutils.cssproductions.PRODUCTIONS.insert(1, ('EXPRESSIONJS', r'Expressions(\.\S+?)+?\(.+?\);'))
-cssutils.cssproductions.MACROS['ident'] = r'[-\*]?{nmstart}{nmchar}*' # 支持 *zoom 形式的 IE7 hack
-cssutils.profile.removeProfile(all=True)
-cssutils.log.setLevel(logging.ERROR)
-
-cssutils.ser.prefs.useDefaults()
-#if DEBUG:
- #cssutils.ser.prefs.useDefaults()
-#else:
- #cssutils.ser.prefs.useMinified()
-
-
-class CSSCompiler():
- ''' CSS Compiler '''
-
-
- def __init__(self, pathTransformer = lambda path: path):
-
- self.__selectorHacks = []
- self.pathTransformer = pathTransformer
-
-
- def getOptions(self, css):
- '''
- selector-compile: none, all, no-combinator
- rule-compile: none, all
- '''
- profile = None
- options = {}
- profileText = re.search(r'@-css-compiler-profile\s+[\'\"](.+?)[\'\"];', css)
- optionText = re.search(r"""
- @-css-compiler\s*{
- ((?:\s*?(?:\S+)\s*:\s*(?:.*);?\s*?)*?)
- }
- """, css, re.M | re.VERBOSE)
-
- if profileText:
- profile = profileText.group(1)
- if profile == 'all':
- options['selector-compile'] = 'all'
- options['rule-compile'] = 'all'
-
- if profile == 'default':
- options['selector-compile'] = 'none'
- options['rule-compile'] = 'all'
-
- if profile == 'not-good-in-ie6':
- options['selector-compile'] = 'no-combinator'
- options['rule-compile'] = 'all'
-
- if profile == 'just-compress':
- options['selector-compile'] = 'none'
- options['rule-compile'] = 'none'
-
- if optionText:
- optionText = optionText.group(1)
- matches = re.finditer(r'\s*?(\S+)\s*:\s*([^;]*);?\s*?', optionText, re.M)
- for match in matches:
- key, value = match.groups()
- options[key] = value
-
- return options
-
-
- def processImport(self, path, mode, cssId):
- ''' 处理 import '''
-
- def doProcessImport(path, url = '.'):
-
- def processStr(m):
- k = m.group(1)
- result = '/* import by ' + url + ' */\n'
- result += doProcessImport(os.path.join(os.path.dirname(path), k), urljoin(url, k))
- result = re.sub(r'url\([\'"]?(.+?)[\'"]?\)', lambda m: 'url(' + urljoin(k, m.group(1)) + ')', result) # 把所有文件路径改为相对于最初的文件
-
- return result
-
- try:
- src = open(self.pathTransformer(path))
- except:
- return '/* ' + os.path.abspath(path) + ' is not exists */'
-
- css = src.read()
-
- options = self.getOptions(css)
-
- if options:
- sheet = cssutils.parseString(css)
- if 'rule-compile' in options.keys() and options['rule-compile'] != 'none':
- ruleCompiler = cssrulecompiler.CSSRuleCompiler()
- ruleCompiler.compile(sheet, mode)
-
- if 'selector-compile' in options.keys() and options['selector-compile'] != 'none':
- selectorCompiler = cssselectorcompiler.CSSSelectorCompiler()
- if options['selector-compile'] == 'no-combinator': selectorCompiler.combinator_compile = False
- selectorHacks = selectorCompiler.compile(sheet, cssId, mode, doInsertTrigger = False)
- self.__selectorHacks.extend(selectorHacks)
-
- css = sheet.cssText
-
- css = re.sub("@import\s+?url\('?(.+?)'?\);", processStr, css)
-
- return css + '\n\n'
-
- return doProcessImport(path)
-
-
- def compile(self, path, mode, cssId = ''):
- ''' 执行编译 '''
-
- if mode not in SUPPORT_COMPILE_MODE: return ''
-
- css = self.processImport(path, mode, cssId)
-
- triggerStr = cssselectorcompiler.getTrigger(cssId, self.__selectorHacks)
- if triggerStr: css += triggerStr.encode('utf-8')
- css = re.sub('expression\(\"((\s|\S)*?)!run-once\"\)', lambda m: 'expression(function(ele){' + m.group(1) + '}(this))', css)
- # expressions(function(){}(this)) Chrome可以识别;
- # expressions((function(){})(this)) 会导致chrome一些老版本中断解析css,但是!chrome引用 -std.min.css 并不会出现expression
-
- return css
-
-
-def getUrls(path, pathTransformer = lambda path: path, recursion = True, inAll = False):
- ''' 返回css中的所有url, recursion 递归处理 import, inAll 返回一个url被处理过的平面数组, 否则返回一个 tuple '''
-
- root, name = os.path.split(path)
-
- def processFile(rurl, imports = [], urls = []):
- path = os.path.join(root, rurl)
- path = pathTransformer(path)
- try:
- src = open(path)
- except:
- return
-
- css = src.read()
- src.close()
- css = re.sub(r'\/\*(\s|\S)*?\*\/', lambda m: '', css) # 先清空注释
-
- matches = re.finditer(r'(@import)?\s*?url\([\'"]?(.+?)[\'"]?\)', css, re.M)
- if inAll == True:
- for match in matches:
- value = urljoin(rurl, match.group(2))
- flag = match.group(1)
- if urls.count(value): continue
- if flag == '@import':
- imports.append(value)
- if recursion:
- processFile(value, imports = imports, urls = urls)
- else:
- urls.append(value)
-
- return (imports, urls)
-
- else:
- imports = []
- urls = []
- for match in matches:
- value = match.group(2)
- flag = match.group(1)
- if flag == '@import':
- if recursion:
- imports.append(processFile(value))
- else:
- imports.append(value)
- else:
- urls.append(value)
-
- return (rurl, imports, urls)
-
- return processFile(name)
-
diff --git a/cssutils-0.9.7a3-py2.6.egg b/cssutils-0.9.7a3-py2.6.egg
deleted file mode 100644
index 29d1cec..0000000
Binary files a/cssutils-0.9.7a3-py2.6.egg and /dev/null differ
diff --git a/doc/opmstruct.graphml b/doc/opmstruct.graphml
deleted file mode 100644
index bfc6b4d..0000000
--- a/doc/opmstruct.graphml
+++ /dev/null
@@ -1,435 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 工作区(/opt/workspace)
-
-
-
-
-
-
-
-
-
-
-
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
- 源库(renren/apps/home)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
- 源库(renren/modules/publisher)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 源库(objectjs.org/object)
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- template-config.xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
- 源库(renren/core)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .packages
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 静态服务器(app.xnimg.cn)
-
-
-
-
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
- 发布库(core)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 静态服务器1(xnimg.cn)
-
-
-
-
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 发布库(apps/home)
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .template-info
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
- 发布库(n/core)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 发布
-
-
-
-
-
-
-
-
-
-
- 发布
-
-
-
-
-
-
-
-
-
-
- 发布
-
-
-
-
-
-
-
-
-
-
- 依赖
-
-
-
-
-
-
-
-
-
-
- 依赖
-
-
-
-
-
-
-
-
-
-
- 依赖
-
-
-
-
-
-
-
-
-
diff --git a/doc/opmstruct.png b/doc/opmstruct.png
deleted file mode 100644
index 07b946f..0000000
Binary files a/doc/opmstruct.png and /dev/null differ
diff --git a/doc/ppt.pptx b/doc/ppt.pptx
deleted file mode 100644
index 650c902..0000000
Binary files a/doc/ppt.pptx and /dev/null differ
diff --git a/doc/pptv2.pptx b/doc/pptv2.pptx
deleted file mode 100644
index 0d1505d..0000000
Binary files a/doc/pptv2.pptx and /dev/null differ
diff --git a/filelistener.py b/filelistener.py
deleted file mode 100644
index 18ad8b1..0000000
--- a/filelistener.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#python
-#encoding=utf-8
-
-import os
-import re
-from urllib import quote_plus, unquote_plus
-
-class FileListener():
- ''' 文件改动监控 '''
-
- def __init__(self, fileInfoPath):
- self.fileInfoPath = fileInfoPath
-
- def get_files(self):
- files = []
-
- if os.path.exists(self.fileInfoPath):
- for file in os.listdir(self.fileInfoPath):
- file = os.path.realpath(unquote_plus(file))
- if os.path.exists(file):
- files.append(file)
-
- return files
-
- def writeChanges(self, path, info):
- u''' 将文件改动信息写入到文件中 '''
-
- hash = quote_plus(path)
- filename = os.path.join(self.fileInfoPath, hash)
-
- text = ''
- info = sorted(info.items(), key = lambda d: d[0])
- for path, timestamp in info:
- text += '"%s" %s\n' % (path, timestamp)
-
- try:
- file = open(filename, 'w')
- except:
- return
-
- file.write(text)
- file.close()
-
- def getChanges(self, path):
- ''' 通过缓存文件读取改动配置信息 '''
-
- hash = quote_plus(path)
- filename = os.path.join(self.fileInfoPath, hash)
-
- try:
- file = open(filename, 'r')
- except:
- dir = os.path.dirname(filename)
- if not os.path.exists(dir): os.makedirs(dir)
- file = open(filename, 'w').write('')
- file = open(filename, 'r')
-
- lines = file.readlines()
- info = {}
- for line in lines:
- match = re.match(r'^\"(.+?)\"\s+?([\d\.]+?)$', line)
- if match:
- path, timestamp = match.groups()
- path = os.path.realpath(path)
- info[path] = timestamp
-
- return info
-
- def check(self, file, files, fake = False):
- modified = []
- not_exists = []
-
- # 假的,每次都返回全都改过,测试用
- if fake:
- return (files, [])
-
- if file.__class__ == dict:
- info = file
- else:
- info = self.getChanges(file)
-
- for path in files:
- path = os.path.realpath(path) # lint
- if not os.path.exists(path):
- not_exists.append(path)
- # 如果存有信息,但是文件已经不存在了,说明文件曾经有过,现在被删除了,需要把信息也删除,并执行重写
- # 如果没有信息,文件也不存在,说明路径写错了,无需重写信息,只需返回not_exists就可以了
- if path in info.keys():
- del info[path]
-
- else:
- timestamp = str(os.stat(path).st_mtime)
- if path not in info.keys() or timestamp != info[path]:
- info[path] = timestamp
- modified.append(path)
-
- return modified, not_exists
-
- def update(self, file, files, fake = False):
- info = self.getChanges(file)
- modified, not_exists = self.check(info, files, fake = fake)
-
- if len(modified) or len(not_exists):
- self.writeChanges(file, info)
-
- return modified, not_exists
diff --git a/hgext/compilecommit.sh b/hgext/compilecommit.sh
deleted file mode 100644
index 983be67..0000000
--- a/hgext/compilecommit.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-
-START=`date +%s`
-
-XN_STATIC=/opt/xn.static
-scompiler=/opt/staticcompiler/staticcompiler.py
-# 获取刚刚push的库属于哪个分支,只对default分支进行编译
-branch=`hg log -r $HG_NODE --template {branch}`
-# 必须用全路径,compile函数在不同路径下工作
-commitlog=`pwd`/commitlog.txt
-
-compile() {
-
- if [ -f .publish ]; then
- tmp=`cat .publish`
- publish_path=`eval echo $tmp`
- svn update $publish_path --accept theirs-full >> /dev/null
- python $scompiler publish $publish_path
- cd $publish_path
- svn add * --force
- svn commit -F $commitlog
- cd -
- else
- echo can\'t find .publish file for `pwd`
- fi
-}
-
-update_repo() {
-
- # hg优先级更高,因为有些库是hg、svn共同都在维护的
- if [ -d .hg ]; then
- echo $repo is a hg repo, hg update
- # hg update 不能传参数
- hg update >> /dev/null
- else
- echo $repo is a svn repo, svn update
- svn update >> /dev/null
- fi
-}
-
-if [ "$branch" = "default" ]; then
- # 编译当前库
- cd .
- parent=`hg parents --template {rev}`
- hg update >> /dev/null
- rev=`hg tip --template {rev}`
- echo up $parent to $rev
- # 将log保存到commitlog
- hg log -r $parent:$rev > $commitlog
-
- # 更新依赖的库
- python $scompiler libs -a | while read repo; do
- cd $repo
- update_repo
- done
-
- # 编译当前库
- compile
-
- # 编译依赖自己的库
- # 编译时并不更新其依赖库
- python $scompiler libs -r -a | while read repo; do
- cd $repo
- compile
- done
-
- rm $commitlog
-
-else
- echo ignore branch $branch.
-fi
-
-END=`date +%s`
-echo "Duration: $(($END-$START))s"
diff --git a/hgext/opm.py b/hgext/opm.py
deleted file mode 100644
index 4e8b489..0000000
--- a/hgext/opm.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#/usr/bin/python
-#encoding=utf-8
-
-import sys
-import os
-sys.path.insert(0, os.path.realpath(os.path.join(__file__, '../../')))
-for p in os.environ.get('PYTHONPATH', '').split(';'):
- sys.path.append(p)
-
-# mercurial默认开始demandimport,替换了默认的import动作,将所有import模块变成延时加载,调用时才load
-# 因此cssutils中的一个cssutils.codec模块没有被执行导致出错
-# 使用__import__避免import带来的demandimport
-from mercurial import demandimport
-demandimport.disable()
-opm = __import__('opm')
-
-import commands
-
-from mercurial import hg
-from mercurial import merge as mergemod
-from mercurial.i18n import _
-import mercurial.ui
-import mercurial.commands
-import mercurial.extensions
-import time
-
-def runcmd(ui, repo, cmd, empty = ''):
- #ui.write('%s: %s\n' % (repo.root, cmd))
- returnValue = os.popen3(cmd)
- returnValue = returnValue[1].read() + returnValue[2].read() # 输出stdout和stderr
- returnValue = returnValue.strip()
- if returnValue:
- for line in returnValue.split('\n'):
- ui.write('%s: %s\n' % (repo.root, line))
- elif empty:
- ui.write('%s: %s\n' % (repo.root, empty))
-
-def _publish(ui, repo, commitlog_path, rebuild = False):
- u'发布一个库至svn'
-
- # 编译当前库
- publish_path = ui.config('opm', 'publish-path')
-
- if not publish_path:
- ui.warn('%s: no publish path\n' % repo.root)
- else:
- # 编译当前库
- runcmd(ui, repo, 'svn update %s --force --accept theirs-full' % publish_path)
- commands.ui.prefix = repo.root + ': '
- commands.ui.fout = ui.fout # 输入导出到客户端
- commands.publish(repo.root, publish_path, rebuild = rebuild)
- commands.ui.prefix = ''
- runcmd(ui, repo, 'svn commit %s -F %s' % (publish_path, commitlog_path), 'nothing to commit.')
-
-def publish(ui, repo, source = '', node = 'default', **opts):
-
- # 只对静态编译框架维护的库进行操作
- if not opm.StaticPackage.is_root(repo.root) or source == 'pull':
- return
-
- publish_branch = ui.config('opm', 'publish-branch', 'default') # 默认作为发布源的分支名称
- node = repo[node]
- node_branch = node.branch()
-
- # 不是需要被编译的分支
- # 不判断分支,因为通过changegroup hook触发编译时,获取到的分支信息有可能不是default,导致不编译
- #if node_branch != publish_branch:
- #ui.warn('%s: ignore branch %s\n' % (repo.root, node_branch))
- #return
-
- # update到需要编译的分支
- mergemod.update(repo, publish_branch, False, False, None)
-
- # 生成commitlog
- commitlog_path = os.path.realpath(os.path.join(repo.root, './commitlog.txt'))
- parent = node.parents()[0].rev()
- rev = node.rev()
- ui.write('%s: update version from %s to %s\n' % (repo.root, parent, rev))
- os.chdir(repo.root)
- os.system('hg log -b %s -r %s:%s > %s' % (node_branch, parent, rev, commitlog_path))
-
- # 编译自己
- _publish(ui, repo, commitlog_path, rebuild = True)
-
- # 编译依赖自己的库
- package = opm.StaticPackage(repo.root)
- for repo_path in package.get_reverse_libs(all=True):
- sub_repo = hg.repository(ui, repo_path)
- _publish(sub_repo.ui, sub_repo, commitlog_path, rebuild = False)
-
- # 删除commitlog
- os.remove(commitlog_path)
-
-def pullwrapper(orig, *args, **kwargs):
- result = orig(*args, **kwargs)
- if kwargs['depts']:
- pull(*args, **kwargs)
- return result
-
-def pull(ui, repo, *args, **kwargs):
- package = opm.StaticPackage(repo.root)
- for repo_path in package.get_libs(all=True):
- sub_repo = hg.repository(ui, repo_path)
- mercurial.commands.pull(sub_repo.ui, sub_repo, *args, **kwargs)
-
-def reposetup(ui, repo):
- ui.setconfig('hooks', 'changegroup.autocompile', publish)
-
-def uisetup(ui):
- '''Initialize the extension.'''
-
- #wrap pull
- entry = mercurial.extensions.wrapcommand(mercurial.commands.table, 'pull', pullwrapper)
- entry[1].append(('D', 'depts', None, _('pull dependencies')))
-
-cmdtable = {
- 'opm-publish': (publish,
- [],
- '[options] [NODE]')
-}
-
diff --git a/images/bkg.png b/images/bkg.png
new file mode 100644
index 0000000..fcebb5b
Binary files /dev/null and b/images/bkg.png differ
diff --git a/images/blacktocat.png b/images/blacktocat.png
new file mode 100644
index 0000000..273d571
Binary files /dev/null and b/images/blacktocat.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..56b1601
--- /dev/null
+++ b/index.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+ Opm by ObjectJS
+
+
+
+
+
+
+
+
+ Welcome to GitHub Pages.
+
+This automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:
+
+$ cd your_repo_root/repo_name
+$ git fetch origin
+$ git checkout gh-pages
+
+
+If you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.
+
+Designer Templates
+
+We've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.
+
+Rather Drive Stick?
+
+If you prefer to not use the automatic generator, push a branch named gh-pages to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.
+
+Authors and Contributors
+
+You can @mention a GitHub username to generate a link to their profile. The resulting <a> element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt ), PJ Hyett (@pjhyett ), and Tom Preston-Werner (@mojombo ) founded GitHub.
+
+Support or Contact
+
+Having trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javascripts/main.js b/javascripts/main.js
new file mode 100644
index 0000000..d8135d3
--- /dev/null
+++ b/javascripts/main.js
@@ -0,0 +1 @@
+console.log('This would be the main JS file.');
diff --git a/jscompiler.py b/jscompiler.py
deleted file mode 100644
index c1be4f3..0000000
--- a/jscompiler.py
+++ /dev/null
@@ -1,9 +0,0 @@
-#python
-#coding=utf-8
-
-class JSCompiler():
- ''' JS Compiler '''
-
- def __init__(self):
- pass
-
diff --git a/opm.py b/opm.py
deleted file mode 100644
index 78cf7d5..0000000
--- a/opm.py
+++ /dev/null
@@ -1,995 +0,0 @@
-#python
-#encoding=utf-8
-
-import sys
-import os
-import os.path
-import shutil
-import urllib2
-import hashlib
-import re
-from urlparse import urlparse, urljoin
-from xml.etree import ElementTree
-from filelistener import FileListener
-import csscompiler
-from csscompiler import CSSCompiler
-
-DEBUG = False
-CONFIG_FILENAME = 'template-config.xml'
-SOURCE_FILENAME = '.template-info/source'
-INFO_PATH = '.template-info/fileinfo'
-PACKAGES_FILENAME = '.packages'
-PACKAGE_FILENAME = '.package'
-
-def relativeURI(url1, url2):
- u''' url2相对于url1的相对路径字符串 '''
- import re
-
- # 去掉 ./ 这种表示当前目录的,学习一下 (?<=) 这种前导匹配
- url1 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url1)
- url2 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url2)
- url1 = url1.split('/')
- url2 = url2.split('/')
- pos = 0
- for i, part in enumerate(url1):
- if url2[i] != part: break
- else: pos = i
-
- url2 = url2[i:]
- url = len(url1[i+1:]) * '../' + '/'.join(url2)
- return url
-
-def path2uri(path):
- u''' 将windows的path转换成没有协议的uri '''
- return urlparse(path.replace('\\', '/'))[2]
-
-class PackageExistsException(Exception):
- def __init__(self, root_path):
- self.root = root_path
-
-class NotInWorkspaceException(Exception):
- pass
-
-class PackageNotFoundException(Exception):
- def __init__(self, package_url, caller_root = None):
- self.url = package_url
- self.caller = caller_root
-
-class WorkspaceNotFoundException(Exception):
- pass
-
-class ConfigError(Exception):
- def __init__(self, path):
- self.path = path
-
-class File():
- def __init__(self, path):
- self.path = path
-
- def read(self):
- return open(self.path, 'rb').read()
-
-class ModuleFile(File):
-
- text_exts = ['.mustache', '.tpl', '.html']
- json_exts = ['.json']
-
- def __init__(self, path, base):
- self.path = path
- self.base = base;
-
- def read(self):
-
- module = path2uri(self.path[self.path.index('node_modules') + 13:])
-
- if os.path.splitext(self.path)[1] in self.text_exts:
- txt = open(self.path, 'rb').read()
- txt = 'return "%s"' % txt.replace('"', '\\"').replace('\n', '\\\n');
- elif os.path.splitext(self.path)[1] in self.json_exts:
- txt = open(self.path, 'rb').read()
- txt = 'return %s' % txt
- else:
- txt = open(self.path, 'rb').read()
-
- id = urljoin(self.base, module)
- dependencies = []
-
- matches = re.finditer(r'require\([\'\"](.*)[\'\"]\)', txt, re.M | re.VERBOSE)
- for match in matches:
- dependencies.append(match.group(1))
-
- dependencies = ', '.join(dependencies)
-
- if dependencies:
- dependencies = '\'' + dependencies + '\', '
-
- txt = ';object.define(\'%s\', %sfunction(require, exports, module) {\n%s\n});\n' % (id, dependencies, txt)
- return txt
-
-class StaticPackage():
- u''' 静态编译库 '''
-
- def __init__(self, root_path, publish_path = None, workspace = None, listener = None):
- self.url = None
- self.combines = {}
- self.listener = listener
- self.workspace = workspace
-
- self.root = root_path # 框架所在本地目录
- self.publish_path = publish_path # 发布文件的目录路径
-
- self.source_path = '' # 源文件的目录路径
- self.resource_path = '' # 资源文件目录路径
- self.library_path = '' # 库文件目录路径
- self.library_folders = {}
-
- self.combine_cache = {self.root: self} # 存储在combine过程中生成的package
-
- self.resource_dir = None
-
- self.serverPrefix = ''
- self.serverUrl = ''
- self.serverRoot = ''
-
- self.load_config()
- if not self.workspace: self.load_workspace()
- if not self.listener: self.init_listener()
-
- def load_workspace(self):
- workspace_path = Workspace.get_workspace(self.root)
- if workspace_path:
- self.workspace = Workspace(workspace_path)
-
- def init_listener(self):
- # 不是所有的库都需要有publish_path
- if self.publish_path:
- self.listener = FileListener(os.path.join(self.publish_path, INFO_PATH))
-
- def get_package(self, root_path):
- u''' 从缓存中获取package引用,如果没有则生成新的并加入缓存 '''
- package = self.combine_cache.get(root_path)
- if not package:
- package = StaticPackage(root_path, self.publish_path, workspace = self.workspace, listener = self.listener)
- self.combine_cache[root_path] = package
- package.combine_cache = self.combine_cache
-
- return package
-
- def get_publish_files(self):
- u''' 发布目录所有的css/js文件 '''
-
- def get_files(dir_path):
- paths = []
- for root, dirs, files in os.walk(dir_path):
- if '.svn' in root:
- dirs[:] = []
- continue
- for file in files:
- path = os.path.join(root, file)
- if os.path.splitext(path)[1] in ('.css', '.js'):
- paths.append(path)
-
- return paths
-
- files = get_files(self.publish_path)
- return files
-
- def get_reverse_libs(self, all = False):
- u''' 所有被依赖库 '''
-
- libs = []
- if self.workspace:
- for local_path in self.workspace.url_packages.values():
- package = self.get_package(local_path)
-
- # 自己的路径在package相关library中,加入package的路径
- if self.root in package.get_libs():
-
- if package.root not in libs:
- libs.append(package.root)
-
- if all:
- sublibs = package.get_reverse_libs(all = True)
- libs.extend([subpath for subpath in sublibs if subpath not in libs and subpath != self.root])
-
- return libs
-
- def get_sub_packages(self):
- subs = []
-
- if self.workspace:
- for package_root in self.workspace.local_packages:
- if package_root != self.root and package_root.startswith(self.root):
- subs.append(package_root)
-
- else:
- # 遍历磁盘
- pass
-
- return subs
-
- def get_libs(self, all = False):
- u''' 所有依赖库 '''
-
- libs = []
-
- def get_sub(local_path):
- u'获取一个库的所有依赖库并存入libs'
- package = self.get_package(local_path)
- if package:
- sublibs = package.get_libs(all = True)
- libs.extend([subpath for subpath in sublibs if subpath not in libs])
-
- if self.workspace:
-
- if all:
- # 获取sub_packages的所有依赖库
- sub_packages = self.get_sub_packages()
- for local_path in sub_packages:
- get_sub(local_path)
-
- for url in self.library_folders.values():
- # url有可能写错了,或者url更改了
- local_path = self.workspace.url_packages.get(url)
-
- if local_path:
- if local_path not in libs:
- libs.append(local_path)
-
- if all:
- get_sub(local_path)
-
- else:
- raise PackageNotFoundException(url, self.root)
-
- return libs
-
- def get_relation_files(self, source, all = False):
- u''' 在合并过程中相关的文件列表 '''
-
- filetype = os.path.splitext(source)[1]
-
- if filetype == '.css' and os.path.exists(source):
-
- def pathTransformer(path):
- return self.get_library_path(path)
-
- imports, urls = csscompiler.getUrls(source, pathTransformer = pathTransformer, recursion = all, inAll = True)
- urls.extend(imports)
- # 需要监视的文件列表
- files = [source]
- for aurl in urls:
- # 不支持 http:// 和 绝对路径
- if not urlparse(aurl)[0] and not urlparse(aurl)[2].startswith('/'):
- file = os.path.join(os.path.split(source)[0], aurl)
- file = self.get_library_path(file)
- files.append(file)
-
- return files
-
- elif filetype == '.js' and (source in self.combines.keys() or os.path.exists(source)):
- if all:
- return [file.path for file in self.get_combine_files(source)]
- else:
- return self.combines[source]
-
- else:
- # 永远返回一个数组
- return []
-
- def get_combine_included(self, file):
- u''' 某个文件在当前库中被哪些文件引用了 '''
-
- files = []
- for combine in self.combines:
- for include in self.combines[combine]:
- if self.get_library_path(include) == file:
- files.append(combine)
- continue
-
- return files
-
- def get_included(self, source, all = False):
- if os.path.splitext(source)[1] == '.css':
- return []
- else:
- # 到workspace中找一圈
- feed_files = []
- if self.workspace:
- for local_path in self.workspace.local_packages.keys():
- package = self.get_package(local_path)
- feed_files.extend(package.get_combine_included(source))
- else:
- feed_files = self.get_combine_included(source)
-
- if all:
- others = []
- for feed_file in feed_files:
- others.extend(self.get_included(feed_file, all = True))
-
- feed_files.extend(others)
-
- return feed_files
-
- def get_combine_files(self, path):
- u'''
- @param path 执行合并的文件
- @return combine_files 数组用来存储此文件相关的最小颗粒度的实体文件(非合并出来的文件)
- '''
-
- combine_files = [] # 存储整个合并过程中最小粒度的文件,最终会按照顺序进行合并
-
- if path not in self.combines.keys():
- return [File(path)]
-
- for include in self.combines[path]:
-
- include = self.get_library_path(include)
-
- # package变量用来存储需要执行combine方法的package
- # 本框架外部文件
- if not include.startswith(self.source_path):
- root_path = StaticPackage.get_root(include)
- package = self.get_package(root_path)
- package.parse(include)
- # 默认为本package内部文件,为self
- else:
- package = self
-
- # 一个合并出来的文件
- if include in package.combines.keys():
- rFiles = package.get_combine_files(include)
- combine_files.extend(rFiles)
-
- elif include.find('node_modules') != -1:
- combine_files.append(ModuleFile(include, self.module_base))
-
- # 一个最小粒度的文件
- else:
- combine_files.append(File(include))
-
- return combine_files
-
- def combine(self, output, files):
- u''' 将files文件列表合并成一个文件并写入到output '''
-
- text = ''
- for file in files:
- text += file.read()
-
- target_dir = os.path.dirname(output)
- if not os.path.exists(target_dir): os.makedirs(target_dir)
- open(output, 'wb').write(text)
-
- def compile(self, filename, force = False):
- filename = os.path.realpath(filename)
- source, mode = self.parse(filename)
- if not source or not self.publish_path or not filename.startswith(self.publish_path):
- return None, None
-
- # 传进来的有可能是源文件路径 TODO
- if filename.startswith(self.source_path):
- return None, None
-
- relation_files = self.get_relation_files(source, all = True)
- if not relation_files:
- # 没有源文件的发布文件
- return None, None
-
- modified, not_exists = self.listener.update(filename, relation_files)
-
- filetype = os.path.splitext(filename)[1]
- if filetype == '.js':
- if force or len(modified):
- combine_files = self.get_combine_files(source)
- self.combine(filename, combine_files)
-
- return modified, not_exists
-
- elif filetype == '.css':
- if DEBUG:
- reload(csscompiler)
- csscompiler.DEBUG = DEBUG
-
- def pathTransformer(path):
- return self.get_library_path(path)
-
- if modified or force:
- name = os.path.split(filename)[1]
- cssId = hashlib.md5(urljoin('/' + urljoin(self.serverRoot, self.serverUrl), name)).hexdigest()[:8]
-
- compiler = CSSCompiler(pathTransformer = pathTransformer)
- css = compiler.compile(source, mode = mode, cssId = cssId)
- css = self.replace_css_url(css, source, name)
- self.write_file(filename, css)
-
- return (modified, not_exists)
-
- return None, None
-
- def replace_css_url(self, css, source, target):
- u''' 将css源文件中的url路径进行转换 '''
-
- def replaceURL(m):
- url = m.group(1)
- urltuple = urlparse(url)
-
- # 如果没有协议,则需要进行处理
- if not urltuple[0]:
- # 如果是绝对路径,则同serverPrefix+serverRoot进行拼接
- if url.startswith('/'):
- prefix = urljoin(self.serverPrefix, self.serverRoot)
- url = urljoin(prefix, url)
-
- # 如果是相对路径
- else:
- # 拼出prefix http://xnimg.cn/n/apps/msg/
- prefix = urljoin(self.serverPrefix, self.serverRoot)
- prefix = urljoin(prefix, self.serverUrl)
-
- # 本地路径
- path = os.path.realpath(os.path.join(os.path.split(source)[0], url))
-
- # 拼出url css/global-all-min.css
- relative = target[len(self.publish_path) + 1:].replace('\\', '/')
- url = urljoin(relative, url)
-
- # 在同一目录树的库中,判断url引用的是否是source目录中的东西
- # 如果是source中的,source中的所有东西都会复制到publish中,因此不需要针对publish进行路径转换
- # 如果是resource中的,resource会复制到publish中,需要进行路径转换
- # 如果不是url引用的文件不是source中的,没有复制过程,需要针对publish进行路径转换
-
- if self.resource_path and path.startswith(self.resource_path):
- resource_publish_path = os.path.realpath(os.path.join(self.publish_path, self.resource_dir))
- url = urljoin(relativeURI(path2uri(self.publish_path), path2uri(resource_publish_path)), url)
- elif not path.startswith(self.source_path):
- url = urljoin(relativeURI(path2uri(self.publish_path), path2uri(self.source_path)), url)
-
- # 合并成最终的url http://xnimg.cn/n/core/css/global-all-min.css
- url = urljoin(prefix, url)
-
- return 'url(' + url + ')'
-
- return re.sub(r'url\([\'"]?(.+?)[\'"]?\)', replaceURL, css) # 绝对路径
-
- def build_files(self):
- u''' 复制相关文件 '''
-
- if not self.publish_path:
- return []
-
- files = self.build_source_files()
- if self.resource_path:
- files.extend(self.build_resource_files())
-
- return files
-
- def build_source_files(self):
- # package下的所有资源文件,忽略 lib 目录
- allFiles = []
- for root, dirs, files in os.walk(self.source_path):
- folders = re.split(r'[/\\]', root)
- if '.svn' in folders \
- or root.startswith(os.path.realpath(os.path.join(self.source_path, 'lib'))):
- continue
- for file in files:
- if os.path.splitext(file)[1] in ('.css', '.xhtml', '.html', '.js', '.xsl', '.xml', '.un~', '.tmp', '.swp'): continue
- path = os.path.join(root, file)
- allFiles.append(path)
-
- modified, notExists = self.listener.update(self.source_path, allFiles)
-
- files = []
- for file in modified:
- target = os.path.join(self.publish_path, file[len(self.source_path) + 1:])
- target_dir = os.path.dirname(target)
- if not os.path.exists(target_dir):
- os.makedirs(target_dir)
-
- shutil.copy(file, target)
- files.append(target)
-
- return files
-
- def build_resource_files(self):
- # package下的所有资源文件,忽略 lib 目录
- allFiles = []
- for root, dirs, files in os.walk(self.resource_path):
- folders = re.split(r'[/\\]', root)
- if '.svn' in folders:
- continue
- for file in files:
- path = os.path.join(root, file)
- allFiles.append(path)
-
- modified, notExists = self.listener.update(self.resource_path, allFiles)
-
- files = []
- for file in modified:
- resource_publish_path = os.path.realpath(os.path.join(self.publish_path, self.resource_dir))
- target = os.path.join(resource_publish_path, file[len(self.resource_path) + 1:])
- target_dir = os.path.dirname(target)
- if not os.path.exists(target_dir):
- os.makedirs(target_dir)
-
- shutil.copy(file, target)
- files.append(target)
-
- return files
-
-
- def write_file(self, path, txt):
- cssfile = open(path, 'wb')
- cssfile.write(txt)
- cssfile.close()
-
- def joinpath(self, path1, path2):
- return os.path.realpath(os.path.join(path1, path2))
-
- def parse_config(self, xmlConfig):
- # 已通过source文件读取到publish_path信息
- # 或者已经通过构造函数传进了publish_path信息
- # 不用通过template-config.xml读取
- # source引用方式下,不需要配置文件的publish配置
- if self.publish_path:
- pass
-
- # 没有source文件,publish_path同库在同一个目录树,需要通过publish配置生成publish_path信息
- else:
- publishNode = xmlConfig.find('publish')
- if publishNode != None:
- publishDir = xmlConfig.find('publish').get('dir')
- if not publishDir.endswith('/'): publishDir += '/'
-
- self.publish_path = self.joinpath(self.root, publishDir)
-
- self.url = xmlConfig.get('url')
-
- # source 是必需的
- sourceDir = xmlConfig.find('source').attrib['dir']
- if not sourceDir.endswith('/'): sourceDir += '/'
- self.source_path = self.joinpath(self.root, sourceDir)
-
- libraryNode = xmlConfig.find('library')
- if libraryNode != None:
- libraryDir = libraryNode.get('dir')
- self.library_path = self.joinpath(self.root, libraryDir)
- folderNodes = libraryNode.findall('folder')
- for folderNode in folderNodes:
- self.library_folders[folderNode.get('name')] = folderNode.get('url')
-
- resourceNode = xmlConfig.find('resource')
- if resourceNode != None and 'dir' in resourceNode.attrib.keys():
- self.resource_dir = resourceNode.attrib['dir']
- if not self.resource_dir.endswith('/'): self.resource_dir += '/'
- self.resource_path = self.joinpath(self.root, self.resource_dir)
-
- serverNode = xmlConfig.find('server')
- if serverNode != None:
- if 'prefix' in serverNode.attrib:
- self.serverPrefix = serverNode.attrib['prefix']
-
- if 'url' in serverNode.attrib:
- self.serverUrl = serverNode.attrib['url']
-
- if 'root' in serverNode.attrib:
- self.serverRoot = serverNode.attrib['root']
-
- if self.serverUrl and not self.serverUrl.endswith('/'):
- self.serverUrl = self.serverUrl + '/'
-
- if self.serverRoot and not self.serverRoot.endswith('/'):
- self.serverRoot = self.serverRoot + '/'
-
- self.module_base = xmlConfig.get('module-base')
-
- combinesXML = xmlConfig.findall('source/combine')
- if combinesXML:
- for combine in combinesXML:
- key = self.joinpath(self.source_path, combine.get('path'))
- includesXML = combine.findall('include')
- includes = []
- for include in includesXML:
- if include.get('module'):
- includePath = self.joinpath(self.source_path, 'node_modules/' + include.get('module'))
- else:
- includePath = self.joinpath(self.source_path, include.get('path'))
-
- includes.append(includePath)
-
- self.combines[key] = includes
-
- def load_config(self):
- ''' 解析配置文件 '''
- path = os.path.join(self.root, CONFIG_FILENAME)
- xmlConfig = ElementTree.parse(path)
- self.parse_config(xmlConfig.getroot())
-
- def get_library_path(self, includePath):
- includePath = os.path.realpath(includePath)
- # lib下的,要通过packages转换一下路径
- if includePath.startswith(self.library_path):
- path = includePath[len(self.library_path) + 1:]
- if path.find(os.sep) != -1: # lib/xxx.js 直接放,没有在一个library目录中
- folderName, pathInPackage = path.split(os.sep, 1) # lib下的目录名和相应package的内部路径
- if folderName in self.library_folders.keys():
- url = self.library_folders[folderName]
- if not self.workspace:
- raise WorkspaceNotFoundException()
-
- local_path = self.workspace.url_packages.get(url)
- if local_path:
- package = self.get_package(local_path)
- new_path = os.path.join(package.root, pathInPackage)
- return os.path.realpath(new_path)
- # 在lib下,也定义了folder,但是相对应的url没有在packages中配置本地磁盘的路径,或者相应的库没有配置package的url属性
- else:
- raise PackageNotFoundException(url, self.root)
-
- return includePath
-
- def parse(self, path):
- u''' source 和 publish 路径一一对应 '''
-
- path = os.path.realpath(path)
-
- if path.startswith(self.source_path):
- return path, None
-
- elif self.publish_path and path.startswith(self.publish_path):
- package_path = path[len(self.publish_path) + 1:]
-
- if os.path.splitext(path)[1] == '.css':
- # xxx-all-min.css --> xxx
- package_path = os.path.splitext(package_path)[0].split('-')
- if len(package_path) < 3: return (None, None)
- name = '-'.join(package_path[:-2])
- mode = package_path[-2]
- source = os.path.join(self.source_path, name + '.css')
- else:
- source = os.path.join(self.source_path, package_path)
- mode = None
-
- return source, mode
-
- # 有可能是lib下的
- else:
- return None, None
-
- def link(self):
- u''' 连接源库与发布库 '''
-
- if self.url:
- package_file_path = os.path.join(self.publish_path, PACKAGE_FILENAME)
- open(package_file_path, 'wb').write(self.url)
-
- source_path = os.path.join(self.publish_path, SOURCE_FILENAME)
- source_dir = os.path.dirname(source_path)
- if not os.path.exists(source_dir):
- os.makedirs(source_dir)
-
- open(source_path, 'wb').write(self.root)
-
- @staticmethod
- def init(root_path):
- u''' 初始化一个目录为源库 '''
-
- root_path = os.path.realpath(root_path)
- config_path = os.path.join(root_path, CONFIG_FILENAME)
-
- if os.path.exists(config_path):
- raise PackageExistsException(root_path)
-
- if not os.path.exists(root_path):
- os.makedirs(root_path)
-
- open(config_path, 'wb').write(
- '\n\t\n\t \n\t\n\t \n\t\n\t \n '
- )
-
- @staticmethod
- def is_root(path):
- u''' path是否是一个静态库的根路径 '''
- return os.path.exists(os.path.join(path, CONFIG_FILENAME))
-
- @staticmethod
- def get_root(path):
- u'''一个目录的源库根路径'''
- return StaticPackage.get_roots(path)[1]
-
- @staticmethod
- def get_publish(path):
- u''' 一个路径的发布库根路径 '''
- return StaticPackage.get_roots(path, just_publish_path = True)
-
- @staticmethod
- def get_roots(path, just_publish_path = False, workspace = None):
- u''' 通过遍历父目录查找root及publish_path '''
-
- publish_path = None
- root_path = None
-
- if os.path.isfile(path):
- path = os.path.dirname(path)
-
- while True:
- # 通过找 source 的方式读取到地址
- publish_source_path = os.path.join(path, SOURCE_FILENAME)
- if os.path.exists(publish_source_path):
- publish_path = path
- root_path = os.path.realpath(open(publish_source_path, 'r').read().strip())
- if just_publish_path: break
-
- # 通过.package 文件读取到地址
- if workspace:
- package_file_path = os.path.join(path, PACKAGE_FILENAME)
- if os.path.exists(package_file_path):
- publish_path = path
- package_url = open(package_file_path, 'r').read().strip()
- package = workspace.get_package_by_url(package_url)
- if not package:
- raise PackageNotFoundException(package_url)
- root_path = package.root
- if just_publish_path: break
-
- # 直接找到配置文件
- if not just_publish_path and StaticPackage.is_root(path):
- root_path = os.path.realpath(path)
- break
-
- newpath = os.path.realpath(os.path.join(path, '../'))
- if newpath == path: break # 已经到根目录了,停止循环
- else: path = newpath
-
- if just_publish_path:
- return publish_path
- else:
- return publish_path, root_path
-
-class Workspace():
- u''' 工作区 '''
-
- def __init__(self, root):
- self.root = root
- self.packages_file_path = os.path.join(self.root, PACKAGES_FILENAME)
- self.url_packages = {}
- self.local_packages = {}
- self.useless_packages = []
- self.remote_server = 'http://hg.xnimg.cn/'
- self.init_packages()
-
- def init_packages(self):
- if not os.path.exists(self.packages_file_path): return
-
- packages_file = open(self.packages_file_path, 'r').read().strip()
- if packages_file:
- lines = packages_file.split('\n')
- else:
- lines = []
-
- for package_path in lines:
- package_path, publish_path = re.match('^(.+?)\s*(?:=\s*(.+)?)?$', package_path.strip()).groups()
- local_path = os.path.realpath(os.path.join(self.root, package_path))
- self.add_package(local_path)
-
- def remote2local(self, package):
- u''' 将一个remotepackage的地址转换成当在本地时的地址 '''
- return os.path.realpath(os.path.join(self.root, package.hg_dir))
-
- def fetch_packages(self, package_url):
- u''' 根据package url找到所有相关package '''
-
- remote_workspace = RemoteWorkspace(self.remote_server)
-
- if package_url not in remote_workspace.url_packages.keys():
- raise PackageNotFoundException(package_url, self.root)
-
- path = remote_workspace.url_packages[package_url]
- package = RemoteStaticPackage(path, workspace = remote_workspace)
-
- packages = [path]
-
- for local_path in package.get_libs(all = True):
- packages.append(local_path)
-
- # 所有子库的相关依赖库
- for sub in package.subs:
- sub = package.get_package(sub)
- for local_path in sub.get_libs(all = True):
- if local_path not in packages:
- packages.append(local_path)
-
- packages = [package.get_package(root_path) for root_path in packages]
-
- return packages
-
- def fetch(self, package):
- u''' 将一个package下载到本地工作区 '''
-
- # hg update
- def hg_update(local_path):
- dir = os.path.realpath(os.curdir)
- os.chdir(local_path)
- a = os.system('hg update')
- os.chdir(dir)
-
- # hg clone
- def hg_clone(url, local_path, noupdate = False):
- #print 'hg clone ' + ('--noupdate ' if noupdate else '') + '%s %s' % (url, local_path)
- os.system('hg clone ' + ('--noupdate ' if noupdate else '') + '%s %s' % (url, local_path))
-
- local_path = self.remote2local(package)
-
- # 本地已经有这个package了
- if os.path.exists(local_path):
- hg_update(local_path)
-
- # 本地存放的路径有可能与远程并不相同
- elif package.url in self.url_packages:
- local_path = self.url_packages[package.url]
- hg_update(local_path)
-
- # 本地没有,按照远程的路径获取
- else:
- self.add_package(local_path)
-
- # 处理父路径
- for parent in package.parents:
- parent = package.get_package(parent)
- parent_local_path = os.path.realpath(os.path.join(self.root, parent.hg_dir))
- if not os.path.exists(parent_local_path):
- hg_clone(parent.hg_root, parent_local_path, noupdate = True)
-
- hg_clone(package.hg_root, local_path)
-
- # 处理子库,加入workspace
- for sub in package.subs:
- sub = package.get_package(sub)
- self.add_package(self.remote2local(sub))
-
- def load(self):
- for root, dirs, files in os.walk(self.root):
- if StaticPackage.is_root(root):
- if not self.has_package(root):
- self.add_package(root)
-
- self.rebuild_package()
-
- def get_package_by_url(self, url):
- local_path = self.url_packages.get(url)
- if local_path:
- package = StaticPackage(local_path, workspace = self)
- return package
-
- def has_package(self, root_path):
- root_path = os.path.realpath(root_path)
- return root_path in self.local_packages.keys()
-
- def add_package(self, local_path):
- local_path = os.path.realpath(local_path)
- if not local_path.startswith(os.path.realpath(self.root)):
- raise NotInWorkspaceException
-
- config_path = os.path.join(local_path, CONFIG_FILENAME)
- if not os.path.exists(config_path):
- self.useless_packages.append(local_path)
- else:
- try:
- package_config = ElementTree.parse(config_path)
- except BaseException as e:
- raise ConfigError(config_path)
- else:
- package_url = package_config.getroot().get('url')
- self.local_packages[local_path] = package_url
- if package_url: self.url_packages[package_url] = local_path
- self.rebuild_package()
-
- def rebuild_package(self):
- # 不要在fastcgi中rebuild_package,因为没有文件锁,会出问题,给出提示即可。
- packages_file = open(self.packages_file_path, 'wb')
- packages = self.local_packages.keys()
- packages.sort()
- for local_path in packages:
- packages_file.write(self.transform_name(local_path) + '\n')
-
- packages_file.close()
-
- def transform_name(self, path):
- return path2uri(path[len(self.root) + 1:])
-
- @staticmethod
- def get_workspace(workspace_path):
- u''' 源库所在工作区 '''
-
- while True:
- if Workspace.is_root(workspace_path):
- return workspace_path
- else:
- newpath = os.path.realpath(os.path.join(workspace_path, '../'))
- if newpath == workspace_path: return
- else: workspace_path = newpath
-
- return None
-
- @staticmethod
- def is_root(path):
- u''' path是否是一个工作区的根路径 '''
- return os.path.exists(os.path.join(path, PACKAGES_FILENAME))
-
-class RemoteWorkspace(Workspace):
- u'远程Workspace'
-
- def init_packages(self):
- sock = urllib2.urlopen(self.root + '_/raw-file/tip/.packages')
- lines = sock.read().strip().split('\n')
- for package_path in lines:
- package_path, publish_path = re.match('^(.+?)\s*(?:=\s*(.+)?)?$', package_path.strip()).groups()
- remote_path = urljoin(self.root, package_path + '/raw-file/tip/')
- config_path = urljoin(remote_path, CONFIG_FILENAME)
- try:
- sock = urllib2.urlopen(config_path)
- except:
- self.useless_packages.append(remote_path)
- else:
- try:
- package_config = ElementTree.fromstring(sock.read())
- except BaseException as e:
- raise ConfigError(config_path)
- else:
- package_url = package_config.get('url')
- self.local_packages[remote_path] = package_url
- if package_url: self.url_packages[package_url] = remote_path
- sock.close()
-
- sock.close()
-
-class RemoteStaticPackage(StaticPackage):
- u'远程静态库'
-
- def __init__(self, root_path, publish_path = None, workspace = None, listener = None):
- StaticPackage.__init__(self, root_path, publish_path = publish_path, workspace = workspace, listener = listener)
-
- self.hg_root = self.get_hg_path(root_path)
- self.hg_dir = self.get_hg_path(root_path[len(self.workspace.root):])
-
- parents = []
- subs = []
- hg_root = self.get_hg_path(self.root)
- for path in self.workspace.local_packages:
- if path != self.root:
- if self.root.startswith(self.get_hg_path(path)):
- parents.append(path)
- elif path.startswith(hg_root):
- subs.append(path)
-
- # 按照路径长短排序,短的排前面,确保生成路径时先生成短的,先生成长的会导致短的无法生成
- self.parents = sorted(parents, cmp = lambda x, y: cmp(len(x), len(y)))
- self.subs = sorted(subs, cmp = lambda x, y: cmp(len(x), len(y)))
-
- def joinpath(self, path1, path2):
- return urljoin(path1, path2)
-
- def load_config(self):
- ''' 解析配置文件 '''
- config_path = urljoin(self.root, CONFIG_FILENAME)
- sock = urllib2.urlopen(config_path)
- package_config = ElementTree.fromstring(sock.read())
- self.parse_config(package_config)
- sock.close()
-
- def get_package(self, root_path):
- u''' 从缓存中获取package引用,如果没有则生成新的并加入缓存 '''
- package = self.combine_cache.get(root_path)
- if not package:
- package = RemoteStaticPackage(root_path, self.publish_path, workspace = self.workspace, listener = self.listener)
- self.combine_cache[root_path] = package
- package.combine_cache = self.combine_cache
-
- return package
-
- @staticmethod
- def get_hg_path(path):
- if path.endswith('/raw-file/tip/'):
- return path[:-13] # remove /raw-file/tip/ at the end
- else:
- return path
diff --git a/params.json b/params.json
new file mode 100644
index 0000000..93054c2
--- /dev/null
+++ b/params.json
@@ -0,0 +1 @@
+{"name":"Opm","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.","tagline":"","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
\ No newline at end of file
diff --git a/staticcompiler.py b/staticcompiler.py
deleted file mode 100644
index e1409ba..0000000
--- a/staticcompiler.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#python
-#encoding=utf-8
-
-import commands
-
-if __name__ == '__main__':
- commands.main()
diff --git a/staticserver/__init__.py b/staticserver/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/staticserver/staticserver.py b/staticserver/staticserver.py
deleted file mode 100644
index 5df2dc2..0000000
--- a/staticserver/staticserver.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# coding=utf-8
-
-import os
-import os.path
-import sys
-import getopt
-import re
-import posixpath
-import ConfigParser
-import BaseHTTPServer
-import SimpleHTTPServer
-from SimpleHTTPServer import SimpleHTTPRequestHandler
-from BaseHTTPServer import HTTPServer
-
-global csscompiler
-global jscompiler
-global xsltemplate
-
-DEBUG = False
-_defaultServer = ''
-_servers = {}
-
-class StaticHTTPRequestHandler(SimpleHTTPRequestHandler):
-
- serverRoot = ''
- domain = ''
-
- def parse_request(self):
- result = SimpleHTTPRequestHandler.parse_request(self)
-
- if self.headers:
- self.domain = self.headers['host'].split(':')[0]
-
- if self.domain in _servers.keys():
- self.serverRoot = _servers[self.domain]['path']
- else:
- self.serverRoot = _defaultServer
-
- os.chdir(self.serverRoot)
-
- return result
-
- def guess_type(self, path):
- ''' .xhtml的mime-type、IE下的特殊处理 '''
-
- self.extensions_map['.xhtml'] = r'application/xhtml+xml'
- #self.extensions_map['.xhtml'] = r'text/xml'
- if self.headers.getheader('user-agent').count('MSIE'):
- self.extensions_map['.xhtml'] = r'text/xml'
-
- return SimpleHTTPRequestHandler.guess_type(self, path)
-
-
- def do_GET(self):
- """ Rewrite版本号、监听css/js/html """
-
- self.path = re.sub('^\/([ab]?\d+?)\/', '/', self.path) # rewrite版本号路径
- path = self.translate_path(self.path)
- ctype = self.guess_type(path)
- if ctype == "text/css":
- if DEBUG:
- reload(csscompiler)
-
- csscompiler.DEBUG = DEBUG
- csscompiler.listen_css(self.serverRoot,
- serverDomain = server.domain,
- serverPath = server.path,
- referer = server.headers['referer'] if 'referer' in server.headers.keys(),
- userAgent = server.headers['user-agent']
- )
-
- if ctype == "text/javascript":
- if DEBUG:
- reload(jscompiler)
-
- jscompiler.DEBUG = DEBUG
- jscompiler.listen_js(self.serverRoot, self)
-
- if ctype == "application/xhtml+xml":
- if DEBUG:
- reload(xsltemplate)
-
- xsltemplate.DEBUG = DEBUG
- xsltemplate.listen_xhtml(self.serverRoot, self)
-
- if ctype == "text/html":
- if DEBUG:
- reload(xsltemplate)
-
- xsltemplate.DEBUG = DEBUG
- xsltemplate.listen_xhtml(self.serverRoot, self)
-
- SimpleHTTPRequestHandler.do_GET(self)
-
-
-class StaticServer():
-
- port = 80
-
- def __init__(self, port):
- confpath = 'server.ini'
- cfg = ConfigParser.RawConfigParser()
- global _defaultServer
- global _servers
- cfg.readfp(open(confpath))
-
- for section in cfg.sections():
- if section == 'Server0':
- _defaultServer = cfg.get(section, 'path')
- else:
- _servers[cfg.get(section, 'name')] = {
- 'path': cfg.get(section, 'path'),
- }
- self.port = port
-
-
- def start(self, ServerClass = BaseHTTPServer.HTTPServer, HandlerClass = StaticHTTPRequestHandler):
- httpd = ServerClass(('', self.port), HandlerClass)
- httpd.serve_forever()
-
-
-if __name__ == '__main__':
-
- PORT = 80
-
- def showUsage():
- print u"""
- -p, --help: 输出此信息
- -c path, --compiler path: 定义csscompiler的路径,默认 ../../
- -p port, --port port: 定义服务器监听端口,默认80
- -d, --debug: Debug模式
- """.encode(sys.getfilesystemencoding())
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hc:p:d', ['help', 'compiler=', 'port=', 'debug'])
- except getopt.GetoptError:
- showUsage()
- sys.exit(2)
-
-
- config = {
- 'compiler_path': '../../',
- }
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- showUsage()
- sys.exit()
- elif opt in ('-d', '--debug'):
- DEBUG = True
- elif opt in ('-p', '--port'):
- PORT = int(arg)
- elif opt in ('-c', '--compiler'):
- config['compiler_path'] = os.path.abspath(arg)
-
- curdir = os.getcwd()
- sys.path.insert(0, os.path.abspath(config['compiler_path']))
- os.chdir(config['compiler_path'])
- csscompiler = __import__('csscompiler')
- jscompiler = __import__('jscompiler')
- xsltemplate = __import__('xsltemplate')
- os.chdir(curdir)
-
- server = StaticServer(PORT)
- server.start()
-
diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css
new file mode 100644
index 0000000..d1df6a2
--- /dev/null
+++ b/stylesheets/pygment_trac.css
@@ -0,0 +1,68 @@
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .o { font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #d14 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #0086B3 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #CBDFFF } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #d14 } /* Literal.String.Backtick */
+.highlight .sc { color: #d14 } /* Literal.String.Char */
+.highlight .sd { color: #d14 } /* Literal.String.Doc */
+.highlight .s2 { color: #d14 } /* Literal.String.Double */
+.highlight .se { color: #d14 } /* Literal.String.Escape */
+.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
+.highlight .si { color: #d14 } /* Literal.String.Interpol */
+.highlight .sx { color: #d14 } /* Literal.String.Other */
+.highlight .sr { color: #009926 } /* Literal.String.Regex */
+.highlight .s1 { color: #d14 } /* Literal.String.Single */
+.highlight .ss { color: #990073 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
+
+.type-csharp .highlight .k { color: #0000FF }
+.type-csharp .highlight .kt { color: #0000FF }
+.type-csharp .highlight .nf { color: #000000; font-weight: normal }
+.type-csharp .highlight .nc { color: #2B91AF }
+.type-csharp .highlight .nn { color: #000000 }
+.type-csharp .highlight .s { color: #A31515 }
+.type-csharp .highlight .sc { color: #A31515 }
diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css
new file mode 100644
index 0000000..a54a639
--- /dev/null
+++ b/stylesheets/stylesheet.css
@@ -0,0 +1,247 @@
+body {
+ margin: 0;
+ padding: 0;
+ background: #151515 url("../images/bkg.png") 0 0;
+ color: #eaeaea;
+ font: 16px;
+ line-height: 1.5;
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+}
+
+/* General & 'Reset' Stuff */
+
+.container {
+ width: 90%;
+ max-width: 600px;
+ margin: 0 auto;
+}
+
+section {
+ display: block;
+ margin: 0 0 20px 0;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ margin: 0 0 20px;
+}
+
+li {
+ line-height: 1.4 ;
+}
+
+/* Header,
+ header - container
+ h1 - project name
+ h2 - project description
+*/
+
+header {
+ background: rgba(0, 0, 0, 0.1);
+ width: 100%;
+ border-bottom: 1px dashed #b5e853;
+ padding: 20px 0;
+ margin: 0 0 40px 0;
+}
+
+header h1 {
+ font-size: 30px;
+ line-height: 1.5;
+ margin: 0 0 0 -40px;
+ font-weight: bold;
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+ color: #b5e853;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
+ 0 0 5px rgba(181, 232, 83, 0.1),
+ 0 0 10px rgba(181, 232, 83, 0.1);
+ letter-spacing: -1px;
+ -webkit-font-smoothing: antialiased;
+}
+
+header h1:before {
+ content: "./ ";
+ font-size: 24px;
+}
+
+header h2 {
+ font-size: 18px;
+ font-weight: 300;
+ color: #666;
+}
+
+#downloads .btn {
+ display: inline-block;
+ text-align: center;
+ margin: 0;
+}
+
+/* Main Content
+*/
+
+#main_content {
+ width: 100%;
+ -webkit-font-smoothing: antialiased;
+}
+section img {
+ max-width: 100%
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+ color: #b5e853;
+ letter-spacing: -0.03em;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
+ 0 0 5px rgba(181, 232, 83, 0.1),
+ 0 0 10px rgba(181, 232, 83, 0.1);
+}
+
+#main_content h1 {
+ font-size: 30px;
+}
+
+#main_content h2 {
+ font-size: 24px;
+}
+
+#main_content h3 {
+ font-size: 18px;
+}
+
+#main_content h4 {
+ font-size: 14px;
+}
+
+#main_content h5 {
+ font-size: 12px;
+ text-transform: uppercase;
+ margin: 0 0 5px 0;
+}
+
+#main_content h6 {
+ font-size: 12px;
+ text-transform: uppercase;
+ color: #999;
+ margin: 0 0 5px 0;
+}
+
+dt {
+ font-style: italic;
+ font-weight: bold;
+}
+
+ul li {
+ list-style: none;
+}
+
+ul li:before {
+ content: ">>";
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+ font-size: 13px;
+ color: #b5e853;
+ margin-left: -37px;
+ margin-right: 21px;
+ line-height: 16px;
+}
+
+blockquote {
+ color: #aaa;
+ padding-left: 10px;
+ border-left: 1px dotted #666;
+}
+
+pre {
+ background: rgba(0, 0, 0, 0.9);
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ padding: 10px;
+ font-size: 14px;
+ color: #b5e853;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ text-wrap: normal;
+ overflow: auto;
+ overflow-y: hidden;
+}
+
+table {
+ width: 100%;
+ margin: 0 0 20px 0;
+}
+
+th {
+ text-align: left;
+ border-bottom: 1px dashed #b5e853;
+ padding: 5px 10px;
+}
+
+td {
+ padding: 5px 10px;
+}
+
+hr {
+ height: 0;
+ border: 0;
+ border-bottom: 1px dashed #b5e853;
+ color: #b5e853;
+}
+
+/* Buttons
+*/
+
+.btn {
+ display: inline-block;
+ background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.3), rgba(35, 35, 35, 0.3) 50%, rgba(10, 10, 10, 0.3) 50%, rgba(0, 0, 0, 0.3));
+ padding: 8px 18px;
+ border-radius: 50px;
+ border: 2px solid rgba(0, 0, 0, 0.7);
+ border-bottom: 2px solid rgba(0, 0, 0, 0.7);
+ border-top: 2px solid rgba(0, 0, 0, 1);
+ color: rgba(255, 255, 255, 0.8);
+ font-family: Helvetica, Arial, sans-serif;
+ font-weight: bold;
+ font-size: 13px;
+ text-decoration: none;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
+}
+
+.btn:hover {
+ background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.6), rgba(35, 35, 35, 0.6) 50%, rgba(10, 10, 10, 0.8) 50%, rgba(0, 0, 0, 0.8));
+}
+
+.btn .icon {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ margin: 1px 8px 0 0;
+ float: left;
+}
+
+.btn-github .icon {
+ opacity: 0.6;
+ background: url("../images/blacktocat.png") 0 0 no-repeat;
+}
+
+/* Links
+ a, a:hover, a:visited
+*/
+
+a {
+ color: #63c0f5;
+ text-shadow: 0 0 5px rgba(104, 182, 255, 0.5);
+}
+
+/* Clearfix */
+
+.cf:before, .cf:after {
+ content:"";
+ display:table;
+}
+
+.cf:after {
+ clear:both;
+}
+
+.cf {
+ zoom:1;
+}
\ No newline at end of file
diff --git a/ui.py b/ui.py
deleted file mode 100644
index 8c9ff22..0000000
--- a/ui.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#python
-#encoding=utf-8
-
-import sys
-
-fout = sys.stdout
-
-prefix = '' # 输出所有消息时会带上这个前缀,一般用于被调用时的方便封装
-
-def error(msg):
- sys.stdout = fout
- print prefix + msg
-
-def warn(msg):
- sys.stdout = fout
- print prefix + 'WARN:' + msg
-
-def msg(msg):
- sys.stdout = fout
- print prefix + msg
diff --git a/utils/__init__.py b/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/utils/commandline.py b/utils/commandline.py
deleted file mode 100644
index 92dd513..0000000
--- a/utils/commandline.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#python
-#encoding=utf-8
-
-import sys
-import os
-import inspect
-from optparse import OptionParser
-
-__doc__ = u'''
-一个用decorator描述命令行的辅助库
-每一个用call调用的函数都是一个子命令
-arg - 描述一个参数,可通过设置函数参数的默认值设定此参数是否必须
-cwdarg - 描述函数的第一个参数为当前路径
-option - 描述一个option
-
-Arg Example:
-
- @cwdarg
- @arg('arg2')
- @arg('arg3')
- def subcommand(arg1, arg2, arg3 = None)
-
- command subcommand path1 path2 --> 当前路径 path1 path2
- command subcommand path1 --> 当前路径 path1
- command subcommand --> 出错,参数个数不足两个
- command subcommand path1 path2 path3 --> path3 path1 path2 当参数个数与定义参数个数相同时,最后一个参数用于替换当前路径
-'''
-
-def arg(name):
- def _arg(func):
- def _func(*args, **kwargs):
- return func(*args, **kwargs)
-
- if 'commands' in func.__dict__:
- _func.commands = func.commands
- else:
- _func.commands = {'func': func}
-
- if 'allowlength' not in _func.commands:
- _func.commands['allowlength'] = 1
- else:
- allowlength = _func.commands['allowlength']
- _func.commands['allowlength'] = allowlength + 1
-
- return _func
- return _arg
-
-def cwdarg(func):
- def _func(*args, **kwargs):
- return func(*args, **kwargs)
-
- if 'commands' in func.__dict__:
- _func.commands = func.commands
- else:
- _func.commands = {'func': func}
-
- if 'allowlength' not in _func.commands:
- _func.commands['allowlength'] = 1
- else:
- allowlength = _func.commands['allowlength']
- _func.commands['allowlength'] = allowlength + 1
-
- if 'cwdarg' not in _func.commands:
- _func.commands['cwdarg'] = True
-
- return _func
-
-def option(name, *optionargs, **optionkwargs):
- def _option(func):
- def _func(*args, **kwargs):
- return func(*args, **kwargs)
-
- if 'commands' in func.__dict__:
- _func.commands = func.commands
- else:
- _func.commands = {'func': func}
-
- if 'options' not in _func.commands:
- _func.commands['options'] = []
-
- optionkwargs['dest'] = name
- _func.commands['options'].append((optionargs, optionkwargs))
-
- return _func
- return _option
-
-def usage(usage):
- def _usage(func):
- def _func(*args, **kwargs):
- return func(*args, **kwargs)
-
- if 'commands' in func.__dict__:
- _func.commands = func.commands
- else:
- _func.commands = {'func': func}
-
- _func.commands['usage'] = usage
-
- return _func
- return _usage
-
-def initcommand(func):
- parser = OptionParser()
- cwdarg = False
- allowlength = 0
- if 'commands' not in func.__dict__:
- func()
- sys.exit(0)
-
- if 'options' in func.commands:
- for option in func.commands['options']:
- parser.add_option(*option[0], **option[1])
-
- if 'usage' in func.commands:
- usage = func.commands['usage']
-
- usage = usage + '\n' + func.commands['func'].__name__.strip()
- else:
- usage = ''
-
- if 'allowlength' in func.commands:
- allowlength = func.commands['allowlength']
-
- if 'cwdarg' in func.commands:
- cwdarg = True
-
- doc = func.commands['func'].__doc__;
- if doc:
- usage = usage + doc
-
- parser.set_usage(usage)
-
- return (parser, cwdarg, allowlength)
-
-def call(commands, command):
- if command not in commands:
- help(commands)
- sys.exit(1)
-
- parser, cwdarg, allowlength = initcommand(command)
- if 'commands' in command.__dict__: command = command.commands['func']
-
- opts, args = parser.parse_args()
- args = list(args[1:]) # 去掉子命令
-
- argspec = inspect.getargspec(command)
- if argspec.defaults:
- argsmin = len(argspec.args) - len(argspec.defaults)
- else:
- argsmin = len(argspec.args)
-
- if cwdarg:
- if len(args) == allowlength:
- cwd = os.path.join(os.getcwd(), args[0])
- args = args[1:]
- args.insert(0, cwd)
- else:
- args.insert(0, os.getcwd()) # 第一个参数为当前路径
-
- if len(args) > allowlength or len(args) < argsmin:
- print u'参数错误'
- return
-
- kwargs = {}
- for key in opts.__dict__.keys():
- if opts.__dict__[key] is not None:
- kwargs[key] = opts.__dict__[key]
-
- result = command(*args, **kwargs)
- if not result: result = 0
- sys.exit(result)
-
-def help(commands, command = None):
- if not command:
- print u'输入 scompiler help command 获得子命令的帮助\n'
- for command in commands:
- desc = command.commands['func'].__doc__.split('\n')[0].strip()
- print ' %s %s %s' % (command.commands['func'].__name__, (12 - len(command.commands['func'].__name__)) * ' ', desc)
-
- else:
- parser, cwdarg, allowlength = initcommand(command)
- parser.print_help()
-
diff --git a/xsltemplate.py b/xsltemplate.py
deleted file mode 100644
index fc21824..0000000
--- a/xsltemplate.py
+++ /dev/null
@@ -1,158 +0,0 @@
-#python
-#coding=utf-8
-
-import sys
-import os
-import os.path
-from urlparse import urlparse, urljoin
-sys.path.insert(0, 'lib/lxml-2.2.4-py2.6-win32.egg')
-from lxml import etree
-
-class XSLTemplate():
-
- def __init__(self, urlResolver = lambda url: url):
- self.urlResolver = urlResolver
- self.url = ''
-
-
- def relativeURI(self, url1, url2):
- ''' url2相对于url1的相对路径字符串 '''
- import re
-
- # 去掉 ./ 这种表示当前目录的,学习一下 (?<=) 这种前导匹配
- url1 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url1)
- url2 = re.sub(r'(^\./|(?<=/)\./)', lambda m: '', url2)
- url1 = url1.split('/')
- url2 = url2.split('/')
- pos = 0
- for i, part in enumerate(url1):
- if url2[i] != part: break
- else: pos = i
-
- url2 = url2[i:]
- url = len(url1[i+1:]) * '../' + '/'.join(url2)
- return url
-
-
- def translatePath(self, url):
- url = urljoin(self.url, url)
-
- return self.urlResolver(url)
-
-
- def compile(self, url, pubdir):
- ''' 执行编译 '''
-
- self.url = url
-
- # 执行编译xhtml
- xmlparser = etree.XMLParser()
- xmlparser.resolvers.add(PathResolver(self.translatePath))
-
- path = self.translatePath(url)
- xml = etree.parse(path)
- pi = xml.getroot().getprevious()
- if not isinstance(pi, etree._XSLTProcessingInstruction):
- return
-
- print 'Recompiling XHTML'
-
- xsltpath = pi.get('href')
- xslt = etree.parse(xsltpath, xmlparser)
-
- try:
- transform = etree.XSLT(xslt)
- resultTree = transform(xml,\
- template_mode = etree.XSLT.strparam('publish'),\
- template_uri_prefix = etree.XSLT.strparam(self.relativeURI(urljoin(url, '.'), pubdir)),\
- template_lint_uri = etree.XSLT.strparam('true')\
- )
- result = etree.tostring(resultTree, method='html', encoding='utf-8', pretty_print=True)
- except:
- print 'transform xhtml error.'
- return
-
- filename = url[len(urljoin(url, '.')):-5] + 'html'
- path = self.translatePath(urljoin(pubdir, filename))
- self.writeFile(path, result)
-
- return resultTree
-
-
- def writeFile(self, path, txt):
- print 'generated:', path
- cssfile = open(path, "w")
- cssfile.write(txt)
- cssfile.close()
-
-
-def getUrls(url, urlResolver = lambda u: u):
- tree = etree.parse(urlResolver(url))
- xsltpath = os.path.abspath('d:/works/xn.static/n/template.xsl')
- xmlparser = etree.XMLParser()
- xmlparser.resolvers.add(PathResolver(urlResolver))
- xslt = etree.parse(xsltpath, xmlparser)
- try:
- transform = etree.XSLT(xslt)
- resultTree = transform(tree,\
- template_mode = etree.XSLT.strparam('geturls'),\
- template_lint_uri = etree.XSLT.strparam('true'),\
- template_server_root = etree.XSLT.strparam('/n/')\
- )
- except:
- print 'get urls error'
- return []
-
- result = resultTree.findall('//*')
- arr = []
- for item in result:
- arr.append(urljoin(url, item.text))
-
- return arr
-
-
-def main():
- from optparse import OptionParser
- parser = OptionParser('usage: python %prog command [options] args')
-
- parser.add_option('-p', '--pppp',
- dest="var",
- type='string',
- default=False,
- help="write afsdafsdaf")
-
- opts, args = parser.parse_args()
-
- if len(args) <= 1:
- parser.print_help()
- return
-
- command = args[0]
- url = args[1]
-
-
-
-
-class PathResolver(etree.Resolver):
- def __init__(self, urlResolver):
- self.urlResolver = urlResolver
-
- def resolve(self, url, id, context):
- import re
- if re.search(r'^file\:///[a-zA-Z]\:/', url): # file:///d:/works/xn.static/n/apps...
- path = re.sub(r'^file\:///', '', url)
- elif re.search(r'^file\:///', url): # file:///n/apps...
- url = re.sub(r'^file\://', '', url)
- path = self.urlResolver(url)
- else:
- path = self.urlResolver(url)
-
- try:
- return self.resolve_file(open(path), context)
- except:
- pass
-
-
-if __name__ == '__main__':
- main()
-