Skip to content

Using Jekyll

The HYIP Project (On Construction) edited this page May 4, 2015 · 3 revisions
🔼 Intro ◀️ Prev< 🔁 Reload Next ▶️ Last 🔽
# The Concept

We have started to ported our site template on Github. The main concept of our project is to make our page could be stand as a dynamic page using data driven. We see that this is possible using Jekyll that available as an engine behind the Github Pages.

Jekyll is a simple, blog aware, static site generator (documented here & here). Jekyll is an open source program, written in Ruby by Tom Preston-Werner, GitHub's co-founder.

In brief the basic concept as explained the author page could be interpreted from existence of the following files.

_config.yml

encoding: utf-8
pygments: false

index.html

---
layout: default
title: HYIP World
---

_layouts/default.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{{ page.title }}</title>
        .....

So in the case above we shall be able to change {{ page.title }} from the string of 'HYIP World' to any desired title remotely. That would make our page stand as dynamic. So let discuss every aspect to get it work.

The Jekyll executable

Based on this documentation. The command-line parameters, the defaults and the _config.yml (through Jekyll::configuration method) are used to create an options hash and then a new site is instantiated:

# Create the Site  
site = Jekyll::Site.new(options)  

After that, it starts to watch the necessary directories if the --auto option was used.

if options['auto']
  require 'directory_watcher'
  puts "Auto-regenerating enabled: #{source} -> #{destination}"
  # ...
else
  puts "Building site: #{source} -> #{destination}"
  # ...
end

The site is built through a call to site.process, the main method in the Jekyll::Site class. Finally, it runs the local server if --server was specified.

The actual processing

The site.process call is responsible for doing all the work necessary to turn the files in the site's source into a site. In lib/jekyll/site.rb:

def initialize(config)
  self.config = config.clone

  # Lots of configuration...

  self.reset
  self.setup
end

def process
  self.reset
  self.read
  self.generate
  self.render
  self.cleanup
  self.write
end

reset and setup are called during initialization of the site to reset its internal data structures and to load libraries, plugins, generators and converters, respectively. process delegates the work to these 6 methods:

  • reset: initialize the layouts, categories and tags hashes and the posts, pages and static_files arrays.
  • read: get site data from the filesystem and store it in internal data structures. Generators and converters are loaded.
  • generate: call each of the generators' generate method.
  • render: call the render method for each post and page.
  • cleanup: All pages, posts and static_files are stored in a Set and everything else (unused files, empty directories) is deleted.
  • write: call the write method of each post, page and static_file, copying them to the destination folder.

This makes it easy to see that a plugin is hooked into Jekyll in the generate and render stages. As seen in the Plugins page, you only need to implement the correct methods. In addition, GitHub Pages supports all other functionality of Jekyll, such as native Sass and CoffeeScript support.

The Jekyll Plugins

Plugins at Github

GitHub Pages currently supports several Jekyll plugins:

  • Jemoji - provides support for emoji within Jekyll posts and pages
  • Jekyll-mentions - provides support for @mentions within Jekyll posts and pages
  • Jekyll-sitemap - adds a standards compliant sitemap for your GitHub Pages.
  • Jekyll-redirect-from - redirects visitors to an updated URL when Jekyll post or page filenames change. See here also for more information.

You have 3 options for installing plugins:

  1. In your site source root, make a _plugins directory. Place your plugins here. Any file ending in *.rb inside this directory will be loaded before Jekyll generates your site.
  2. In your _config.yml file, add a new array with the key gems and the values of the gem names of the plugins you’d like to use. An example: gems: [jekyll-test-plugin, jekyll-jsonify, jekyll-assets] # This will require each of these gems automatically.
  3. Add the relevant plugins to a Bundler group in your Gemfile. An example: group :jekyll_plugins do gem "my-jekyll-plugin" end

_plugins, _config.yml and Gemfile can be used simultaneously You may use any of the aforementioned plugin options simultaneously in the same site if you so choose. Use of one does not restrict the use of the others.

There are a lot of of beautiful plugin from many contributors listed on the plugin page above. To achieve our concept the following type of plugins are considered having a similar purpose with our target. Some of them are copied to our _plugins directory.

  • Jekyll remote-include: It’s like {% include file.html %} but instead of grabbing files from your includes directory it gets the file from a remote URL e.g.: {% remote_include http://static.2inspire.co.uk/img/vector.svg %}

  • Jekyll Delicious Plugin by Christian Hellsten: Fetches and renders bookmarks from delicious.com e.g: {% delicious username:x tag:design count:15 ttl:3600 %}.The package has also a plugin that is used for fetching and rendering RSS and Atom feeds e.g: {% rssfeed url:https://github.com/cz8s.atom count:15 ttl:3600 %}

  • Jekyll Suggested Tweet by David Ensinger: A Liquid tag for Jekyll that allows for the embedding of suggested tweets via Twitter’s Web Intents API. Content is fetched from the Twitter API e.g: {% twitter oembed status_url *options %}

  • Jekyll webmention_io.rb by Aaron Gustafson: A plugin to enable webmention integration using Webmention.io. Includes an optional JavaScript for updating webmentions automatically between publishes and, if available, in realtime using WebSockets: {% webmention_count YOUR_URL %}

  • Jekyll Image Encode by GSI: Tag that renders base64 codes of images fetched from the web: <img src="{% base64 http://example.org/image.png %}" />

  • Jekyll Debbugs: Allows posting links to Debian BTS easily.

At last but not least is Jekyll Http Basic Auth Plugin: Plugin to manage http basic auth for jekyll generated pages and directories. The plugin creates user-, group- and .htaccess files for the http basic auth stuff to work properly. The .htaccess files are merged into the other jekyll generated pages. This is possible by using jekyll_auth.rb a simple way to use Github Oauth to serve a protected jekyll site to your GitHub organization.

Work around --safe mode

From the above sample a custom plugins can definitely be used to update our page dynamically. However if you want to run Jekyll with plugins. This will complicates your deployment because GitHub Pages runs Jekyll in --safe mode, which quite reasonably prevents the running of arbitrary Ruby code on the GitHub servers.

There were some work around to overcome this limitation we got from external sources as described below:

Despite off all choice above, since we could not find a recommendation nor a support in to the method from GitHub it self, we would prefer to consider another option that officially featured as the best way to integrate which is called GitHub API.

GitHub API

The Github APi is documented here. By default, all requests receive the v3 version of the API. We need to explicitly request this version via the Accept header.

Accept: application/vnd.github.v3+json

All API access is over HTTPS, and accessed from the api.github.com domain (or through yourdomain.com/api/v3/ for enterprise). All data is sent and received as JSON.

####On the command line

Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:

$ curl -i "https://api.github.com/repos/vmg/redcarpet/issues?state=closed"

For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL should be encoded as JSON with a Content-Type of ‘application/json’:

$ curl -i -u username -d '{"scopes":["public_repo"]}' \
    https://api.github.com/authorizations

Create File

curl -X PUT -H 'Authorization: token <TOKEN>' \
-d '{"path": "test.txt", "message": "Test Commit", \
"committer": {"name": "Kevin Clark", "email": "kevin@kevinclark.ca"}, \
"content": "bXkgbmV3IGZpbGUgY29udGVudHM="}' \
https://api.github.com/repos/vernalkick/kevinclark/contents/test.txt

Note: Reference see here

####On python:

def http = new HTTPBuilder("https://api.github.com")
    def response = http.get(path: "/users/qmetric",
                      headers: [(USER_AGENT): "Apache HTTPClient"])

Note: GitHub denies access if the User-Agent header is missing.

####On ruby

require 'rest_client'

params = {
  :path => "test.txt",
  :message => "Test Commit",
  :committer => {
    :name => "Kevin Clark",
    :email => "kevin@kevinclark.ca"
  },
  :content => "bXkgbmV3IGZpbGUgY29udGVudHM=",
  :access_token => <TOKEN>
}

RestClient.put \
"https://api.github.com/repos/vernalkick/kevinclark/contents/test.txt", \
:params => JSON.generate(params)

Note: Ref is here

####On php Get data:

$ch = curl_init();
curl_setopt($ch,CURLOPT_USERAGENT,'Content-type: application/json');
curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/repos/ruby/ruby');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);

$json = json_decode($data, true);
var_dump($json['name']);
var_dump($json['full_name']);

Note: Ref is here

Upload File:

/** 
 * Send a POST request using cURL
 *
 * @param   UriInterface   $url      The url and request containing the post information
 * @param   array          $options  Extra options for cURL. This can also override the defaults
 *
 * @return  string The response of the object
 */
private function curl_post(UriInterface $url, array $options = array())
{
    $this->log('Attempting to upload file with URL ' . $url->toString(), Project::MSG_INFO);
    $defaults = array(
        CURLOPT_POST => 1,
        CURLOPT_HEADER => 1,
        CURLOPT_FRESH_CONNECT => 1,
        CURLOPT_FORBID_REUSE => 1,
        CURLOPT_TIMEOUT => 4,
        CURLOPT_POSTFIELDS => file_get_contents("file.zip"),
    );

    // Initiate CURL
    $ch = curl_init($url->toString());

    // Create the full params
    $params = array_merge($options, $defaults);
    curl_setopt_array($ch, $params);

    if(!$result = curl_exec($ch)) 
    {
        $this->log(curl_error($ch), Project::MSG_ERR);
        return curl_error($ch);
    }

    curl_close($ch);
    return $result;
}

$pageUrl = "https://uploads.github.com/repos/" . $this->owner . '/' . $this->repo . "/releases/" . $this->version . "/assets?name=";

        $fullUrl = $pageUrl . $filename;

        $headers = array(
            'Content-Type: ' . $header,
            'Accept: application/vnd.github.manifold-preview',
            'Authorization: token TOKEN',
            'Content-Type: application/zip',
        );

        $options = array(
            CURLOPT_SSL_VERIFYPEER => false, // Despite SSL is 100% supported to suppress the Error 60 currently thrown
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_BINARYTRANSFER => 1 // --data-binary
        );

        // Create the Uri object
        $url = new Uri($fullUrl);

        $url->setQuery(array('file' => "@$filename"));
        $response = $this->curl_post($url, $options);

Note: Ref is here

##Github.js Github.js provides a minimal higher-level wrapper around git's plumbing commands, exposing an API for manipulating GitHub repositories on the file level. It is being developed in the context of Prose, a content editor for GitHub. #Conclusion Having discussed in detail what we could do with jekyll, the engine behind GitHub Pages, we came to the conclusion as mentioned below:

  • Having setup jekyll we can get our pages as dynamic by updating the parameters called front-matter in html pages e.g. index.html or _layout/default.html.
  • Dynamic updating actually can be made internally trough a custom of jekyll plugins but we have to drop it since GitHub pages is generated using --safe option.
  • A cleanest way to make a regularly update of a static page might be the remote access using GitHub API to the html pages that carrying on the front-matter.

🔼 Intro ◀️ Prev< 🔁 Reload Next ▶️ Last 🔽

Clone this wiki locally