Skip to content

Commit

Permalink
Add CLI interface
Browse files Browse the repository at this point in the history
  • Loading branch information
milmazz committed Mar 30, 2019
1 parent d9dd153 commit 0193537
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v0.6.0

* Add CLI interface

## v0.5.1

### Bug fixes
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ have any JavaScript, you will get warnings from validation tools such as

See `BUPE.Builder`, `BUPE.Config`, and `BUPE.Item` for more details.

### Using the builder via command line

You can build EPUB documents using the command line as follows:

1. Install `BUPE` as an escript:

```console
mix escript.install hex bupe
```

2. Then you are ready to use it in your projects:

```console
bupe "EPUB_TITLE" -p egg.xhtml -p bacon.xhtml -l path/to/logo.png
```

For more details about using the command line tool, review the usage guide:

```console
bupe --help
```

### Parser

If you want to parse an EPUB file you can do the following:
Expand Down
107 changes: 107 additions & 0 deletions lib/bupe/cli.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
defmodule BUPE.CLI do
@moduledoc """
CLI interface for BUPE.
"""

@aliases [
h: :help,
l: :logo,
o: :output,
p: :page,
v: :version
]

@switches [
help: :boolean,
language: :string,
logo: :string,
output: :string,
page: :keep,
version: :boolean
]

def main(args, builder \\ &BUPE.Builder.run/3) do
{opts, args, _invalid} = OptionParser.parse(args, aliases: @aliases, switches: @switches)

cond do
Keyword.has_key?(opts, :version) ->
print_version()

Keyword.has_key?(opts, :help) ->
print_usage()

true ->
generate(args, opts, builder)
end
end

defp generate([], _, _) do
IO.puts("Too few arguments.\n")
print_usage()
exit({:shutdown, 1})
end

defp generate([title], opts, builder) do
opts =
opts
|> Keyword.put(:title, title)
|> parse_pages()

name = parse_output(opts, title)

with {:ok, path} <- BUPE.Config |> struct(opts) |> builder.(name, []) do
IO.puts("EPUB successfully generated:")
path |> Path.relative_to_cwd() |> IO.puts()
end
end

def parse_pages(opts) do
case Keyword.get_values(opts, :page) do
[] ->
IO.puts("At least one page is required\n")
print_usage()
exit({:shutdown, 1})

pages ->
opts
|> Keyword.delete(:page)
|> Keyword.put(:pages, pages)
end
end

def parse_output(opts, title) do
Keyword.get_lazy(opts, :output, fn ->
title
|> String.downcase()
|> String.replace(" ", "_")
|> Kernel.<>(".epub")
end)
end

defp print_version do
IO.puts("BUPE v#{BUPE.version()}")
end

defp print_usage do
IO.puts(~S"""
Usage:
bupe EPUB_TITLE [OPTIONS]
Examples:
bupe "Ode to Food" -p egg.xhtml -p bacon.xhtml
Options:
EPUB_TITLE EPUB title
-p, --page Path to a page (e.g. XHTML) file that will be copied
to the EPUB file. May be given multiple times
--language Identify the primary language of the EPUB document, its
value must be a valid [BCP 47](https://tools.ietf.org/html/bcp47)
language tag, default: "en"
-l, --logo Path to the image logo of the EPUB document
-v, --version Print BUPE version
-o, --output Path to output EPUB document.
-h, --help Print this usage
""")
end
end
21 changes: 15 additions & 6 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule BUPE.Mixfile do
use Mix.Project

@version "0.5.2-dev"
@version "0.6.0"

def project do
[
Expand All @@ -19,11 +19,8 @@ defmodule BUPE.Mixfile do
docs: docs(),
package: package(),
deps: deps(),
dialyzer: [
plt_add_apps: [:mix, :ex_unit, :xmerl],
check_plt: true,
flags: [:error_handling, :race_conditions, :underspecs]
]
dialyzer: dialyzer(),
escript: escript()
]
end

Expand All @@ -34,6 +31,18 @@ defmodule BUPE.Mixfile do
[applications: []]
end

def dialyzer do
[
plt_add_apps: [:mix, :ex_unit, :xmerl],
check_plt: true,
flags: [:error_handling, :race_conditions, :underspecs]
]
end

def escript do
[main_module: BUPE.CLI]
end

defp deps do
[
{:ex_doc, "~> 0.19", only: :dev},
Expand Down
55 changes: 55 additions & 0 deletions test/bupe/cli_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
defmodule BUPE.CLITest do
use ExUnit.Case, async: true

alias BUPE.CLI

import ExUnit.CaptureIO

defp builder(_config, name, _opts) do
{:ok, name}
end

test "minimum command-line options" do
fun = fn ->
CLI.main(["sample", "--page", "egg.xhtml"], &builder/3)
end

assert "EPUB successfully generated:\nsample.epub\n" == capture_io(fun)
end

test "at least one page is required" do
fun = fn ->
CLI.main(["sample"])
end

assert catch_exit(capture_io(fun)) == {:shutdown, 1}
end

test "too few arguments" do
fun = fn ->
CLI.main(["--page", "egg.xhtml"])
end

assert catch_exit(capture_io(fun)) == {:shutdown, 1}
end

test "version" do
assert capture_io(fn ->
CLI.main(["--version"])
end) == "BUPE v#{BUPE.version()}\n"

assert capture_io(fn ->
CLI.main(["-v"])
end) == "BUPE v#{BUPE.version()}\n"
end

test "help" do
assert capture_io(fn ->
CLI.main(["--help"])
end) =~ "Usage:\n"

assert capture_io(fn ->
CLI.main(["-h"])
end) =~ "Usage:\n"
end
end

0 comments on commit 0193537

Please sign in to comment.