diff --git a/.gitignore b/.gitignore index bd75f50..12b6dc6 100644 --- a/.gitignore +++ b/.gitignore @@ -23,10 +23,16 @@ public/uploads/* .rbx .env -/.dir-locals.el -/.lein-env -/.lein-repl-history +/target +/classes +/checkouts +pom.xml +pom.xml.asc +*.jar +*.class +/.lein-* /.nrepl-port -/dev/ +/.dir-locals.el /profiles.clj -/target/ +/dev/resources/local.edn +/dev/src/local.clj diff --git a/README.md b/README.md index 548b7fa..4c97863 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,140 @@ -# asciinema.org +# asciinema -[![Build Status](https://travis-ci.org/asciinema/asciinema.org.svg?branch=master)](https://travis-ci.org/asciinema/asciinema.org) -[![Code Climate](https://codeclimate.com/github/asciinema/asciinema.org/badges/gpa.svg)](https://codeclimate.com/github/asciinema/asciinema.org) -[![Coverage Status](https://coveralls.io/repos/asciinema/asciinema.org/badge.svg)](https://coveralls.io/r/asciinema/asciinema.org) +FIXME: description -Record and share your terminal sessions, the right way. +## Developing -asciinema is a free and open source solution for recording terminal sessions -and sharing them on the web. +### Setup -This is the source code of asciinema.org website. You can find asciinema's -terminal recorder at -[asciinema/asciinema](https://github.com/asciinema/asciinema) and asciinema -player at -[asciinema/asciinema-player](https://github.com/asciinema/asciinema-player). +When you first clone this repository, run: -## Setup instructions +```sh +lein setup +``` -Below you'll find setup instructions in case you want to contribute, play with -it on your local machine, or setup your own instance for private use or for -your organization. +This will create files for local configuration, and prep your system +for the project. -### Quickstart Using Docker Compose +### Environment -Required: - - [Docker](https://docs.docker.com/engine/getstarted/step_one/#step-1-get-docker) - - [docker-compose 1.5+](https://docs.docker.com/compose/install/) -```bash -$ wget https://raw.githubusercontent.com/asciinema/asciinema.org/master/docker-compose.yml -$ docker-compose up -d asciinema -$ docker-compose run --rm db_init +To begin developing, start with a REPL. +```sh +lein repl ``` -You can override the address/port that is sent in email with login token by passing HOST="host:port" environment variable when starting the web server. - -Assuming you are running Docker Toolbox and VirtualBox: go to http://192.168.99.100:3000/ and enjoy. +Then load the development environment. -### Manual setup +```clojure +user=> (dev) +:loaded +``` -#### 1. Install dependencies +Run `go` to initiate and start the system. -asciinema.org site is a Ruby on Rails application. You need to have following -dependencies installed: +```clojure +dev=> (go) +:started +``` -* Ruby 2.0+ (Ruby 2.1 is recommended) +By default this creates a web server at . -* bundler gem - `gem install bundler` +When you make changes to your source files, use `reset` to reload any +modified files and reset the server. -* PostgreSQL 8+ with libpq development headers - `sudo apt-get install postgresql libpq-dev` on Debian/Ubuntu +```clojure +dev=> (reset) +:reloading (...) +:resumed +``` -* asciinema's libtsm fork (`asciinema` branch) - See [here](https://github.com/asciinema/libtsm/blob/asciinema/README) for installation instructions. - If you don't install it now the setup script (point 4 below) will try to - install it for you anyway. +### Testing -* phantomjs 2.0+ - `sudo add-apt-repository ppa:tanguy-patte/phantomjs && sudo apt-get update && sudo apt-get install phantomjs` +Testing is fastest through the REPL, as you avoid environment startup +time. -#### 2. Get the source code +```clojure +dev=> (test) +... +``` -Clone git repository: +But you can also run tests through Leiningen. -```bash -$ git clone git://github.com/asciinema/asciinema.org.git -$ cd asciinema.org +```sh +lein test ``` -#### 3. Prepare database config file +### Migrations -Copy *config/database.yml.example* to *config/database.yml*. Then set -database/user/password to whatever you prefer. +Migrations are handled by [ragtime][]. Migration files are stored in +the `resources/migrations` directory, and are applied in alphanumeric +order. -If database specified in database.yml doesn't exist then the following setup -task will create it (make sure database user is allowed to create new -databases). +To update the database to the latest migration, open the REPL and run: -#### 4. Setup the app +```clojure +dev=> (migrate) +Applying 20150815144312-create-users +Applying 20150815145033-create-posts +``` -Following script will install gem dependencies and setup database: +To rollback the last migration, run: -```bash -$ ./script/setup +```clojure +dev=> (rollback) +Rolling back 20150815145033-create-posts ``` -#### 5. Run Rails server +Note that the system needs to be setup with `(init)` or `(go)` before +migrations can be applied. -```bash -$ bundle exec rails server +[ragtime]: https://github.com/weavejester/ragtime + +### Generators + +This project has several generator functions to help you create files. + +To create a new endpoint: + +```clojure +dev=> (gen/endpoint "bar") +Creating file src/foo/endpoint/bar.clj +Creating file test/foo/endpoint/bar_test.clj +Creating directory resources/foo/endpoint/bar +nil ``` -#### 6. Run the background job processor +To create a new component: -The background job processor is needed for asciicast pre-processing and -thumbnail generation. +```clojure +dev=> (gen/component "baz") +Creating file src/foo/component/baz.clj +Creating file test/foo/component/baz_test.clj +nil +``` + +To create a new boundary: -```bash -$ bundle exec sidekiq +```clojure +dev=> (gen/boundary "quz" foo.component.baz.Baz) +Creating file src/foo/boundary/quz.clj +Creating file test/foo/boundary/quz_test.clj +nil ``` -## Contributing +To create a new SQL migration: -If you want to contribute to this project check out -[Contributing](http://asciinema.org/contributing) page. +```clojure +dev=> (gen/sql-migration "create-users") +Creating file resources/foo/migrations/20160519143643-create-users.up.sql +Creating file resources/foo/migrations/20160519143643-create-users.down.sql +nil +``` -## Authors +## Deploying -Developed with passion by [Marcin Kulik](http://ku1ik.com) and great open -source [contributors](https://github.com/asciinema/asciinema.org/contributors) +FIXME: steps to deploy -## Copyright +## Legal -Copyright © 2011-2016 Marcin Kulik. See LICENSE.txt for details. +Copyright © 2017 FIXME diff --git a/dev/resources/dev.edn b/dev/resources/dev.edn new file mode 100644 index 0000000..83a8e7c --- /dev/null +++ b/dev/resources/dev.edn @@ -0,0 +1,9 @@ +{:config + {:app + {:middleware + {:functions {:stacktrace #var ring.middleware.stacktrace/wrap-stacktrace} + :applied ^:replace [:not-found :webjars :ring-defaults :route-aliases :stacktrace]}} + :http + {:port 4000} + :db + {:uri "jdbc:postgresql://localhost/postgres"}}} diff --git a/dev/src/dev.clj b/dev/src/dev.clj new file mode 100644 index 0000000..5889c96 --- /dev/null +++ b/dev/src/dev.clj @@ -0,0 +1,21 @@ +(ns dev + (:refer-clojure :exclude [test]) + (:require [clojure.repl :refer :all] + [clojure.pprint :refer [pprint]] + [clojure.tools.namespace.repl :refer [refresh]] + [clojure.java.io :as io] + [com.stuartsierra.component :as component] + [duct.generate :as gen] + [duct.util.repl :refer [setup test cljs-repl migrate rollback]] + [duct.util.system :refer [load-system]] + [reloaded.repl :refer [system init start stop go reset]])) + +(defn new-system [] + (load-system (keep io/resource ["asciinema/system.edn" "dev.edn" "local.edn"]))) + +(when (io/resource "local.clj") + (load "local")) + +(gen/set-ns-prefix 'asciinema) + +(reloaded.repl/set-init! new-system) diff --git a/dev/src/user.clj b/dev/src/user.clj new file mode 100644 index 0000000..9cf3c0c --- /dev/null +++ b/dev/src/user.clj @@ -0,0 +1,8 @@ +(ns user) + +(defn dev + "Load and switch to the 'dev' namespace." + [] + (require 'dev) + (in-ns 'dev) + :loaded) diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..d886b2c --- /dev/null +++ b/project.clj @@ -0,0 +1,40 @@ +(defproject asciinema "0.1.0-SNAPSHOT" + :description "FIXME: write description" + :url "http://example.com/FIXME" + :min-lein-version "2.0.0" + :dependencies [[org.clojure/clojure "1.8.0"] + [com.stuartsierra/component "0.3.1"] + [compojure "1.5.1"] + [duct "0.8.2"] + [environ "1.1.0"] + [ring "1.5.0"] + [ring/ring-defaults "0.2.1"] + [ring-jetty-component "0.3.1"] + [ring-webjars "0.1.1"] + [org.slf4j/slf4j-nop "1.7.21"] + [org.webjars/normalize.css "3.0.2"] + [duct/hikaricp-component "0.1.0"] + [org.postgresql/postgresql "9.4.1211"] + [duct/ragtime-component "0.1.4"]] + :plugins [[lein-environ "1.0.3"]] + :main ^:skip-aot asciinema.main + :target-path "target/%s/" + :aliases {"setup" ["run" "-m" "duct.util.repl/setup"]} + :profiles + {:dev [:project/dev :profiles/dev] + :test [:project/test :profiles/test] + :uberjar {:aot :all} + :profiles/dev {} + :profiles/test {} + :project/dev {:dependencies [[duct/generate "0.8.2"] + [reloaded.repl "0.2.3"] + [org.clojure/tools.namespace "0.2.11"] + [org.clojure/tools.nrepl "0.2.12"] + [eftest "0.1.1"] + [com.gearswithingears/shrubbery "0.4.1"] + [kerodon "0.8.0"]] + :source-paths ["dev/src"] + :resource-paths ["dev/resources"] + :repl-options {:init-ns user} + :env {:port "3000"}} + :project/test {}}) diff --git a/resources/asciinema/endpoint/example/example.html b/resources/asciinema/endpoint/example/example.html new file mode 100644 index 0000000..f808576 --- /dev/null +++ b/resources/asciinema/endpoint/example/example.html @@ -0,0 +1,11 @@ + + + + Example Endpoint + + + + +

This is an example endpoint

+ + diff --git a/resources/asciinema/errors/404.html b/resources/asciinema/errors/404.html new file mode 100644 index 0000000..b9cab04 --- /dev/null +++ b/resources/asciinema/errors/404.html @@ -0,0 +1,12 @@ + + + + Server Error + + + + +

Resource Not Found

+

The requested page does not exist.

+ + diff --git a/resources/asciinema/errors/500.html b/resources/asciinema/errors/500.html new file mode 100644 index 0000000..985ff84 --- /dev/null +++ b/resources/asciinema/errors/500.html @@ -0,0 +1,12 @@ + + + + Server Error + + + + +

Internal Server Error

+

Sorry, something went wrong.

+ + diff --git a/resources/asciinema/public/css/site.css b/resources/asciinema/public/css/site.css new file mode 100644 index 0000000..37086ca --- /dev/null +++ b/resources/asciinema/public/css/site.css @@ -0,0 +1,103 @@ +.error-page body { + background: #eee; +} + +.error-page h1 { + margin: 15% 0 0 0; + text-align: center; + font-size: 42px; + color: #900; +} + +.error-page h2 { + text-align: center; + font-size: 32px; + font-weight: normal; + color: #333; +} + +.welcome body { + background: #eee; + color: #333; + font-family: Helvetica, Arial, sans-serif; + max-width: 700px; + padding: 15px; + margin: auto; +} + +.welcome p { + line-height: 1.4em; +} + +.welcome code { + font-family: Menlo, DejaVu Sans Mono, Lucida Console, monospace; + font-size: 12px; + background: #ddd; + color: #111; +} + +.welcome h1 { + text-align: center; + font-size: 36px; + font-weight: lighter; + margin: 40px 0 30px 0; +} + +.welcome h1 .outer { + border: solid 4px #555; + padding: 3px; + display: inline-block; +} + +.welcome h1 .inner { + border: solid 2px #555; + padding: 0 3px; + display: inline-block; + font-weight: normal; + color: #444; +} + +.welcome .project-name { + font-weight: bold; +} + +.welcome .profiles { + margin-top: 30px; +} + +.welcome .profiles code { + font-size: 11px; +} + +.welcome .profiles h2 { + font-weight: normal; + font-size: 23px; + margin-bottom: 0; + color: #333; +} + +.welcome .profiles dl { + margin: 0 10px; +} + +.welcome .profiles dt { + font-weight: normal; + font-size: 19px; + margin: 18px 0 5px 0; +} + +.welcome .profiles dd { + font-size: 14px; + margin: 8px 0 8px 0; +} + +.example body { + background: #eee; +} + +.example h1 { + margin: 15% 0 0 0; + text-align: center; + font-size: 36px; + font-weight: normal; +} diff --git a/resources/asciinema/public/favicon.ico b/resources/asciinema/public/favicon.ico new file mode 100644 index 0000000..0e50cb2 Binary files /dev/null and b/resources/asciinema/public/favicon.ico differ diff --git a/resources/asciinema/public/index.html b/resources/asciinema/public/index.html new file mode 100644 index 0000000..36d2e30 --- /dev/null +++ b/resources/asciinema/public/index.html @@ -0,0 +1,36 @@ + + + + Welcome to Duct + + + + +

Welcome to Duct

+
+

Congratulations! Your project asciinema is + ready and running.

+

This is a static welcome page located at resources/asciinema/public/index.html + in the project directory. Remove or replace it when you start developing. + If you remove the index page entirely, be sure to change the + :route-aliases map in resources/asciinema/system.edn. +

+
+

Template profiles used:

+
+
+example
+
Adds an example endpoint at /example.
+
+postgres
+
Adds a PostgreSQL dependency and database component. The database used for + development defaults to postgres on localhost.
+
+ragtime
+
Adds Ragtime migrations. Use (migrate) and (rollback) + in the REPL. Migrations are stored in resources/asciinema/migrations. +
+
+site
+
Adds middleware and configuration suited for a user-facing website.
+
+
+ + + diff --git a/resources/asciinema/public/robots.txt b/resources/asciinema/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/resources/asciinema/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/resources/asciinema/system.edn b/resources/asciinema/system.edn new file mode 100644 index 0000000..a61ca89 --- /dev/null +++ b/resources/asciinema/system.edn @@ -0,0 +1,50 @@ +{:components + {:app #var duct.component.handler/handler-component + :http #var ring.component.jetty/jetty-server + :db #var duct.component.hikaricp/hikaricp + :ragtime #var duct.component.ragtime/ragtime} + :endpoints + {:example #var asciinema.endpoint.example/example-endpoint} + :dependencies + {:http [:app] + :app [:example] + :ragtime [:db] + :example [:db]} + :config + {:app + {:middleware + {:functions + {:hide-errors #var duct.middleware.errors/wrap-hide-errors + :not-found #var duct.middleware.not-found/wrap-not-found + :ring-defaults #var ring.middleware.defaults/wrap-defaults + :route-aliases #var duct.middleware.route-aliases/wrap-route-aliases + :webjars #var ring.middleware.webjars/wrap-webjars} + :applied + [:not-found :webjars :ring-defaults :route-aliases :hide-errors] + :arguments + {:not-found #resource "asciinema/errors/404.html" + :hide-errors #resource "asciinema/errors/500.html" + :route-aliases {"/" "/index.html"} + :ring-defaults + {:params {:urlencoded true + :keywordize true + :multipart true + :nested true} + :cookies true + :session {:flash true + :cookie-attrs {:http-only true}} + :security {:anti-forgery true + :xss-protection {:enable? true, :mode :block} + :frame-options :sameorigin + :content-type-options :nosniff} + :static {:resources "asciinema/public"} + :responses {:not-modified-responses true + :absolute-redirects true + :content-types true + :default-charset "utf-8"}}}}} + :http + {:port http-port} + :db + {:uri db-uri} + :ragtime + {:resource-path "asciinema/migrations"}}} diff --git a/src/asciinema/endpoint/example.clj b/src/asciinema/endpoint/example.clj new file mode 100644 index 0000000..46c9821 --- /dev/null +++ b/src/asciinema/endpoint/example.clj @@ -0,0 +1,8 @@ +(ns asciinema.endpoint.example + (:require [compojure.core :refer :all] + [clojure.java.io :as io])) + +(defn example-endpoint [{{db :spec} :db}] + (context "/example" [] + (GET "/" [] + (io/resource "asciinema/endpoint/example/example.html")))) diff --git a/src/asciinema/main.clj b/src/asciinema/main.clj new file mode 100644 index 0000000..becb032 --- /dev/null +++ b/src/asciinema/main.clj @@ -0,0 +1,15 @@ +(ns asciinema.main + (:gen-class) + (:require [com.stuartsierra.component :as component] + [duct.util.runtime :refer [add-shutdown-hook]] + [duct.util.system :refer [load-system]] + [environ.core :refer [env]] + [clojure.java.io :as io])) + +(defn -main [& args] + (let [bindings {'http-port (Integer/parseInt (:port env "3000")) + 'db-uri (:database-url env)} + system (->> (load-system [(io/resource "asciinema/system.edn")] bindings) + (component/start))] + (add-shutdown-hook ::stop-system #(component/stop system)) + (println "Started HTTP server on port" (-> system :http :port)))) diff --git a/test/asciinema/endpoint/example_test.clj b/test/asciinema/endpoint/example_test.clj new file mode 100644 index 0000000..ec32ab1 --- /dev/null +++ b/test/asciinema/endpoint/example_test.clj @@ -0,0 +1,16 @@ +(ns asciinema.endpoint.example-test + (:require [com.stuartsierra.component :as component] + [clojure.test :refer :all] + [kerodon.core :refer :all] + [kerodon.test :refer :all] + [shrubbery.core :as shrub] + [asciinema.endpoint.example :as example])) + +(def handler + (example/example-endpoint {})) + +(deftest smoke-test + (testing "example page exists" + (-> (session handler) + (visit "/example") + (has (status? 200) "page exists"))))