def binary_resource_complete(self, resource): """ If the site is in development mode, just return. Otherwise, run jpegoptim to compress the jpg file. """ try: mode = self.site.config.mode except AttributeError: mode = "production" if not resource.source_file.kind == 'jpg': return if mode.startswith('dev'): self.logger.debug("Skipping jpegoptim in development mode.") return supported = [ "force", "max=", "strip-all", "strip-com", "strip-exif", "strip-iptc", "strip-icc", ] target = File(self.site.config.deploy_root_path.child( resource.relative_deploy_path)) jpegoptim = self.app args = [str(jpegoptim)] args.extend(self.process_args(supported)) args.extend(["-q", str(target)]) self.call_app(args)
def text_resource_complete(self, resource, text): """ Save the file to a temporary place and run less compiler. Read the generated file and return the text as output. Set the target path to have a css extension. """ if not self._should_parse_resource(resource): return supported = [ "verbose", ("silent", "s"), ("compress", "x"), "O0", "O1", "O2", "include-path=" ] less = self.app source = File.make_temp(text) target = File.make_temp('') args = [str(less)] args.extend(self.process_args(supported)) args.extend([str(source), str(target)]) try: self.call_app(args) except subprocess.CalledProcessError: HydeException.reraise( "Cannot process %s. Error occurred when " "processing [%s]" % (self.app.name, resource.source_file), sys.exc_info()) return target.read_all()
def commit(self, message): cmd = Popen('git commit -a'.split() + ['-m' + str(message)], cwd=str(self.path), stdout=PIPE) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def __init__(self, sitepath, site, preprocessor=None): config = site.config if hasattr(site, "config") else None if config: super(HydeLoader, self).__init__([str(config.content_root_path), str(config.layout_root_path)]) else: super(HydeLoader, self).__init__(str(sitepath)) self.site = site self.preprocessor = preprocessor
def __init__(self, sitepath, site, preprocessor=None): config = site.config if hasattr(site, 'config') else None if config: super(HydeLoader, self).__init__([ str(config.content_root_path), str(config.layout_root_path), ]) else: super(HydeLoader, self).__init__(str(sitepath)) self.site = site self.preprocessor = preprocessor
def text_resource_complete(self, resource, text): """ If the site is in development mode, just return. Otherwise, save the file to a temporary place and run the uglify app. Read the generated file and return the text as output. """ try: mode = self.site.config.mode except AttributeError: mode = "production" if not resource.source_file.kind == 'js': return if mode.startswith('dev'): self.logger.debug("Skipping uglify in development mode.") return supported = [ "source-map", "source-map-root", "source-map-url", "in-source-map", "screw-ie8", "expr", ("prefix", "p"), ("beautify", "b"), ("mangle", "m"), ("reserved", "r"), ("compress", "c"), ("define", "d"), ("enclose", "e"), "comments", "stats", "wrap", "lint", "verbose" ] uglify = self.app source = File.make_temp(text) target = File.make_temp('') args = [str(uglify)] args.extend(self.process_args(supported)) args.extend(["-o", str(target), str(source)]) self.call_app(args) out = target.read_all() return out
def test_ensure_no_exception_when_forced(): e = Engine(raise_exceptions=True) TEST_SITE.child_folder('layout').make() e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) verify_site_contents(TEST_SITE, Layout.find_layout()) TEST_SITE.delete() TEST_SITE.child_folder('content').make() e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) verify_site_contents(TEST_SITE, Layout.find_layout()) TEST_SITE.delete() TEST_SITE.make() File(TEST_SITE.child('site.yaml')).write("Hey") e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) verify_site_contents(TEST_SITE, Layout.find_layout())
def text_resource_complete(self, resource, text): """ Save the file to a temporary place and run the Coffee compiler. Read the generated file and return the text as output. """ if not resource.source_file.kind == 'coffee': return coffee = self.app source = File.make_temp(text) args = [str(coffee)] args.extend(["-c", "-p", str(source)]) return self.call_app(args)
def switch(self, branch): self.branch = branch cmd = Popen('git checkout %s' % branch, cwd=str(self.path), stdout=PIPE, shell=True) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def push(self): cmd = Popen("git push origin %s" % self.branch, cwd=str(self.path), stdout=PIPE, shell=True) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def push(self): cmd = Popen('git push origin'.split() + [self.branch], cwd=str(self.path), stdout=PIPE) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def add(self, path="."): cmd = Popen('git add --'.split() + [path], cwd=str(self.path), stdout=PIPE) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def get_source(self, environment, template): """ Calls the plugins to preprocess prior to returning the source. """ template = template.strip() # Fixed so that jinja2 loader does not have issues with # seprator in windows # template = template.replace(os.sep, '/') logger.debug("Loading template [%s] and preprocessing" % template) try: (contents, filename, date) = super(HydeLoader, self).get_source( environment, template) except UnicodeDecodeError: HydeException.reraise( "Unicode error when processing %s" % template, sys.exc_info()) except TemplateError as exc: HydeException.reraise('Error when processing %s: %s' % ( template, str(exc) ), sys.exc_info()) if self.preprocessor: resource = self.site.content.resource_from_relative_path(template) if resource: contents = self.preprocessor(resource, contents) or contents return (contents, filename, date)
def add_resource(self, a_file): """ Adds a file to the parent node. Also adds to to the hashtable of path to resource associations for quick lookup. """ afile = File(a_file) resource = self.resource_from_path(afile) if resource: logger.debug("Resource exists at [%s]" % resource.relative_path) return resource if not afile.is_descendant_of(self.source_folder): raise HydeException("The given file [%s] does not reside" " in this hierarchy [%s]" % (afile, self.source_folder)) node = self.node_from_path(afile.parent) if not node: node = self.add_node(afile.parent) resource = node.add_child_resource(afile) self.resource_map[str(afile)] = resource relative_path = resource.relative_path resource.simple_copy = any( fnmatch.fnmatch(relative_path, pattern) for pattern in self.site.config.simple_copy) logger.debug("Added resource [%s] to [%s]" % (resource.relative_path, self.source_folder)) return resource
def add_resource(self, a_file): """ Adds a file to the parent node. Also adds to to the hashtable of path to resource associations for quick lookup. """ afile = File(a_file) resource = self.resource_from_path(afile) if resource: logger.debug("Resource exists at [%s]" % resource.relative_path) return resource if not afile.is_descendant_of(self.source_folder): raise HydeException("The given file [%s] does not reside" " in this hierarchy [%s]" % (afile, self.source_folder)) node = self.node_from_path(afile.parent) if not node: node = self.add_node(afile.parent) resource = node.add_child_resource(afile) self.resource_map[str(afile)] = resource relative_path = resource.relative_path resource.simple_copy = any(fnmatch.fnmatch(relative_path, pattern) for pattern in self.site.config.simple_copy) logger.debug("Added resource [%s] to [%s]" % (resource.relative_path, self.source_folder)) return resource
def node_from_relative_path(self, relative_path): """ Gets the content node that maps to the given relative path. If no match is found it returns None. """ return self.node_from_path( self.source_folder.child(str(relative_path)))
def add_node(self, a_folder): """ Adds a new node to this folder's hierarchy. Also adds it to the hashtable of path to node associations for quick lookup. """ folder = Folder(a_folder) node = self.node_from_path(folder) if node: logger.debug("Node exists at [%s]" % node.relative_path) return node if not folder.is_descendant_of(self.source_folder): raise HydeException("The given folder [%s] does not" " belong to this hierarchy [%s]" % (folder, self.source_folder)) p_folder = folder parent = None hierarchy = [] while not parent: hierarchy.append(p_folder) p_folder = p_folder.parent parent = self.node_from_path(p_folder) hierarchy.reverse() node = parent if parent else self for h_folder in hierarchy: node = node.add_child_node(h_folder) self.node_map[str(h_folder)] = node logger.debug("Added node [%s] to [%s]" % ( node.relative_path, self.source_folder)) return node
def merge(self, branch): cmd = Popen('git merge'.split() + [branch], cwd=str(self.path), stdout=PIPE) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def add_node(self, a_folder): """ Adds a new node to this folder's hierarchy. Also adds it to the hashtable of path to node associations for quick lookup. """ folder = Folder(a_folder) node = self.node_from_path(folder) if node: logger.debug("Node exists at [%s]" % node.relative_path) return node if not folder.is_descendant_of(self.source_folder): raise HydeException("The given folder [%s] does not" " belong to this hierarchy [%s]" % (folder, self.source_folder)) p_folder = folder parent = None hierarchy = [] while not parent: hierarchy.append(p_folder) p_folder = p_folder.parent parent = self.node_from_path(p_folder) hierarchy.reverse() node = parent if parent else self for h_folder in hierarchy: node = node.add_child_node(h_folder) self.node_map[str(h_folder)] = node logger.debug("Added node [%s] to [%s]" % (node.relative_path, self.source_folder)) return node
def node_from_relative_path(self, relative_path): """ Gets the content node that maps to the given relative path. If no match is found it returns None. """ return self.node_from_path(self.source_folder.child( str(relative_path)))
def node_from_path(self, path): """ Gets the node that maps to the given path. If no match is found it returns None. """ if Folder(path) == self.source_folder: return self return self.node_map.get(str(Folder(path)), None)
def _get_layout_folder(root, layout_name='basic'): """ Finds the layout folder from the given root folder. If it does not exist, return None """ layouts_folder = Folder(str(root)).child_folder(LAYOUTS) layout_folder = layouts_folder.child_folder(layout_name) return layout_folder if layout_folder.exists else None
def switch(self, branch): self.branch = branch cmd = Popen('git checkout'.split() + [branch], cwd=str(self.path), stdout=PIPE) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def _render_spaceless(self, caller=None): """ Strip the spaces between tags using the regular expression from django. Stolen from `django.util.html` Returns the given HTML with spaces between tags removed. """ if not caller: return '' return re.sub(r'>\s+<', '><', str(caller().strip()))
def binary_resource_complete(self, resource): """ If the site is in development mode, just return. Otherwise, run optipng to compress the png file. """ try: mode = self.site.config.mode except AttributeError: mode = "production" if not resource.source_file.kind == 'png': return if mode.startswith('dev'): self.logger.debug("Skipping optipng in development mode.") return supported = [ "o", "fix", "force", "preserve", "quiet", "log", "f", "i", "zc", "zm", "zs", "zw", "full", "nb", "nc", "np", "nz" ] target = File(self.site.config.deploy_root_path.child( resource.relative_deploy_path)) optipng = self.app args = [str(optipng)] args.extend(self.process_args(supported)) args.extend([str(target)]) self.call_app(args)
def test_find_layout_from_env_var(): f = Layout.find_layout() LAYOUT_ROOT.make() f.copy_to(LAYOUT_ROOT) os.environ[HYDE_DATA] = str(DATA_ROOT) f = Layout.find_layout() assert f.parent == LAYOUT_ROOT assert f.name == 'basic' assert f.child_folder('layout').exists del os.environ[HYDE_DATA]
def text_resource_complete(self, resource, text): if not resource.source_file.name == 'rjs.conf': return rjs = self.app target = File.make_temp('') args = [str(rjs)] args.extend( ['-o', str(resource), ("out=" + target.fully_expanded_path)]) try: self.call_app(args) except subprocess.CalledProcessError: HydeException.reraise( "Cannot process %s. Error occurred when " "processing [%s]" % (self.app.name, resource.source_file), sys.exc_info()) return target.read_all()
def walk_resources_tagged_with(node, tag): tags = set(str(tag).split('+')) walker = get_tagger_sort_method(node.site) for resource in walker(): try: taglist = set(attrgetter("meta.tags")(resource)) except AttributeError: continue if tags <= taglist: yield resource
def test_find_layout_from_env_var(): f = Layout.find_layout() LAYOUT_ROOT.make() f.copy_to(LAYOUT_ROOT) os.environ[HYDE_DATA] = str(DATA_ROOT) f = Layout.find_layout() assert f.parent == LAYOUT_ROOT assert f.name == "basic" assert f.child_folder("layout").exists del os.environ[HYDE_DATA]
def call_app(self, args): """ Calls the application with the given command line parameters. """ try: self.logger.debug("Calling executable [%s] with arguments %s" % (args[0], str(args[1:]))) return subprocess.check_output(args) except subprocess.CalledProcessError as error: self.logger.error(error.output) raise
def call_app(self, args): """ Calls the application with the given command line parameters. """ try: self.logger.debug( "Calling executable [%s] with arguments %s" % (args[0], str(args[1:]))) return subprocess.check_output(args) except subprocess.CalledProcessError as error: self.logger.error(error.output) raise
def publish(self): command = "{command} {opts} ./ {username}{server}:{target}".format( command=self.command, opts=self.opts, username=self.username + '@' if self.username else '', server=self.server, target=self.target) deploy_path = self.site.config.deploy_root_path.path cmd = Popen(command, cwd=str(deploy_path), stdout=PIPE, shell=True) cmdresult = cmd.communicate()[0] if cmd.returncode: raise Exception(cmdresult)
def binary_resource_complete(self, resource): """ If the site is in development mode, just return. Otherwise, run jpegtran to compress the jpg file. """ try: mode = self.site.config.mode except AttributeError: mode = "production" if not resource.source_file.kind == 'jpg': return if mode.startswith('dev'): self.logger.debug("Skipping jpegtran in development mode.") return supported = [ "optimize", "progressive", "restart", "arithmetic", "perfect", "copy", ] source = File(self.site.config.deploy_root_path.child( resource.relative_deploy_path)) target = File.make_temp('') jpegtran = self.app args = [str(jpegtran)] args.extend(self.process_args(supported)) args.extend(["-outfile", str(target), str(source)]) self.call_app(args) target.copy_to(source) target.delete()
def text_resource_complete(self, resource, text): """ Save the file to a temporary place and run stylus compiler. Read the generated file and return the text as output. Set the target path to have a css extension. """ if not resource.source_file.kind == 'styl': return stylus = self.app source = File.make_temp(text.strip()) supported = [("compress", "c"), ("include", "I")] args = [str(stylus)] args.extend(self.process_args(supported)) args.append(str(source)) try: self.call_app(args) except subprocess.CalledProcessError: HydeException.reraise( "Cannot process %s. Error occurred when " "processing [%s]" % (stylus.name, resource.source_file), sys.exc_info()) target = File(source.path + '.css') return target.read_all()
def discover_executable(name, sitepath): """ Finds an executable in the given sitepath or in the path list provided by the PATH environment variable. """ # Check if an executable can be found in the site path first. # If not check the os $PATH for its presence. paths = [str(sitepath)] + os.environ['PATH'].split(os.pathsep) for path in paths: full_name = os.path.join(path, name) if os.path.exists(full_name): return full_name return None
def __init__(self, source_folder, parent=None): super(Node, self).__init__(source_folder) if not source_folder: raise HydeException("Source folder is required" " to instantiate a node.") self.root = self self.module = None self.site = None self.source_folder = Folder(str(source_folder)) self.parent = parent if parent: self.root = self.parent.root self.module = self.parent.module if self.parent.module else self self.site = parent.site self.child_nodes = [] self.resources = []
def asciidoc(env, value): """ (simple) Asciidoc filter """ try: from asciidocapi import AsciiDocAPI except ImportError: print(u"Requires AsciiDoc library to use AsciiDoc tag.") raise output = value asciidoc = AsciiDocAPI() asciidoc.options("--no-header-footer") result = StringIO() asciidoc.execute(StringIO(output.encode("utf-8")), result, backend="html4") return str(result.getvalue(), "utf-8")
def asciidoc(env, value): """ (simple) Asciidoc filter """ try: from asciidocapi import AsciiDocAPI except ImportError: print("Requires AsciiDoc library to use AsciiDoc tag.") raise output = value asciidoc = AsciiDocAPI() asciidoc.options('--no-header-footer') result = StringIO() asciidoc.execute(StringIO(output.encode('utf-8')), result, backend='html4') return str(result.getvalue(), "utf-8")
def get_dependencies(self, path): """ Finds dependencies hierarchically based on the included files. """ text = self.env.loader.get_source(self.env, path)[0] from jinja2.meta import find_referenced_templates try: ast = self.env.parse(text) except Exception as e: HydeException.reraise("Error processing %s: \n%s" % (path, str(e)), sys.exc_info()) tpls = find_referenced_templates(ast) deps = list(self.env.globals["deps"].get("path", [])) for dep in tpls: deps.append(dep) if dep: deps.extend(self.get_dependencies(dep)) return list(set(deps))
def get_dependencies(self, path): """ Finds dependencies hierarchically based on the included files. """ text = self.env.loader.get_source(self.env, path)[0] from jinja2.meta import find_referenced_templates try: ast = self.env.parse(text) except Exception as e: HydeException.reraise("Error processing %s: \n%s" % (path, str(e)), sys.exc_info()) tpls = find_referenced_templates(ast) deps = list(self.env.globals['deps'].get('path', [])) for dep in tpls: deps.append(dep) if dep: deps.extend(self.get_dependencies(dep)) return list(set(deps))
def test_ensure_can_create_site_at_user(): e = Engine(raise_exceptions=True) TEST_SITE_AT_USER.delete() e.run(e.parse(['-s', str(TEST_SITE_AT_USER), 'create', '-f'])) verify_site_contents(TEST_SITE_AT_USER, Layout.find_layout())
def test_ensure_no_exception_when_sitepath_does_not_exist(): e = Engine(raise_exceptions=True) TEST_SITE.delete() e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) verify_site_contents(TEST_SITE, Layout.find_layout())
def test_ensure_no_exception_when_empty_site_exists(): e = Engine(raise_exceptions=True) e.run(e.parse(['-s', str(TEST_SITE), 'create'])) verify_site_contents(TEST_SITE, Layout.find_layout())