Skip to content

Commit f2229fc

Browse files
authoredJan 11, 2023
Add a basic rwp manifest CLI utility (#63)
1 parent 2ea905a commit f2229fc

File tree

10 files changed

+160
-23
lines changed

10 files changed

+160
-23
lines changed
 

‎Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
help:
2+
@echo "Usage: make <target>\n\n\
3+
build\t\tBuild the \`rwp\` command-line utility in the current directory\n\
4+
install\tBuild and install the \`rwp\` command-line utility\n\
5+
"
6+
7+
.PHONY: build
8+
build:
9+
(cd cmd/rwp; go build; mv rwp ../..)
10+
11+
.PHONY: install
12+
install:
13+
(cd cmd/rwp; go install)
14+
15+

‎README.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,11 @@
22

33
More documentation coming soon! Things are changing too quickly right now.
44

5-
For development, run `go run cmd/server/main.go` to start the server, which by default listens on `127.0.0.1:5080`. Check out the [example configuration file](https://github.com/readium/go-toolkit/blob/master/cmd/server/configs/config.local.toml.example) for configuration options.
5+
For development, run `go run cmd/server/main.go` to start the server, which by default listens on `127.0.0.1:5080`. Check out the [example configuration file](https://github.com/readium/go-toolkit/blob/master/cmd/server/configs/config.local.toml.example) for configuration options.
6+
7+
## Command line utility
8+
9+
The `rwp` command provides utilities to parse and generate Web Publications.
10+
11+
To install `rwp` in `~/go/bin`, run `make install`. Use `make build` to build the binary in the current directory.
12+

‎cmd/rwp/cmd/manifest.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"path/filepath"
8+
9+
"github.com/readium/go-toolkit/pkg/asset"
10+
"github.com/readium/go-toolkit/pkg/streamer"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
// Indentation used to pretty-print
15+
var indentFlag string
16+
17+
var manifestCmd = &cobra.Command{
18+
Use: "manifest <pub-path>",
19+
Short: "Generate a Readium Web Publication Manifest for a publication",
20+
Long: `Generate a Readium Web Publication Manifest for a publication.
21+
22+
This command will parse a publication file (such as EPUB, PDF, audiobook, etc.)
23+
and build a Readium Web Publication Manifest for it. The JSON manifest is
24+
printed to stdout.
25+
26+
Examples:
27+
Print out a minimal JSON RWPM.
28+
$ readium manifest publication.epub
29+
30+
Pretty-print a JSON RWPM using tow-space indent.
31+
$ readium manifest --indent " " publication.epub
32+
33+
Extract the publication title with ` + "`jq`" + `.
34+
$ readium manifest publication.epub | jq -r .metadata.title
35+
`,
36+
Args: func(cmd *cobra.Command, args []string) error {
37+
if len(args) == 0 {
38+
return errors.New("expects a path to the publication")
39+
} else if len(args) > 1 {
40+
return errors.New("accepts a single path to a publication")
41+
}
42+
return nil
43+
},
44+
RunE: func(cmd *cobra.Command, args []string) error {
45+
path := filepath.Clean(args[0])
46+
pub, err := streamer.New(streamer.Config{}).Open(
47+
asset.File(path), "",
48+
)
49+
if err != nil {
50+
return fmt.Errorf("failed opening %s: %w", path, err)
51+
}
52+
53+
var jsonBytes []byte
54+
if indentFlag == "" {
55+
jsonBytes, err = json.Marshal(pub.Manifest)
56+
} else {
57+
jsonBytes, err = json.MarshalIndent(pub.Manifest, "", indentFlag)
58+
}
59+
if err != nil {
60+
return fmt.Errorf("failed rendering JSON for %s: %w", path, err)
61+
}
62+
63+
fmt.Println(string(jsonBytes))
64+
return err
65+
},
66+
}
67+
68+
func init() {
69+
rootCmd.AddCommand(manifestCmd)
70+
manifestCmd.Flags().StringVarP(&indentFlag, "indent", "i", "", "Indentation used to pretty-print")
71+
}

‎cmd/rwp/cmd/root.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// rootCmd represents the base command when called without any subcommands
10+
var rootCmd = &cobra.Command{
11+
Use: "rwp",
12+
Short: "Utilities for Readium Web Publications",
13+
}
14+
15+
// Execute adds all child commands to the root command and sets flags appropriately.
16+
// This is called by main.main(). It only needs to happen once to the rootCmd.
17+
func Execute() {
18+
err := rootCmd.Execute()
19+
if err != nil {
20+
// Error is already printed to stderr by Cobra.
21+
os.Exit(1)
22+
}
23+
}
24+
25+
func init() {
26+
rootCmd.CompletionOptions.DisableDefaultCmd = true
27+
}

‎cmd/rwp/main.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "github.com/readium/go-toolkit/cmd/rwp/cmd"
4+
5+
func main() {
6+
cmd.Execute()
7+
}

‎cmd/server/api/server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (s *PublicationServer) getPublication(filename string, r *http.Request) (*p
104104
}
105105

106106
cp := filepath.Clean(string(fpath))
107-
pub, err := streamer.New(nil, false, nil, nil).Open(asset.File(filepath.Join(s.config.PublicationPath, cp)), "")
107+
pub, err := streamer.New(streamer.Config{}).Open(asset.File(filepath.Join(s.config.PublicationPath, cp)), "")
108108
if err != nil {
109109
return nil, errors.Wrap(err, "failed opening "+cp)
110110
}

‎cmd/webpubgen/main.go

-7
This file was deleted.

‎go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ require (
2626
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
2727
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
2828
github.com/hashicorp/hcl v1.0.0 // indirect
29+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
2930
github.com/magiconair/properties v1.8.5 // indirect
3031
github.com/mitchellh/mapstructure v1.4.1 // indirect
3132
github.com/pelletier/go-toml v1.9.3 // indirect
3233
github.com/pmezard/go-difflib v1.0.0 // indirect
3334
github.com/spf13/afero v1.6.0 // indirect
3435
github.com/spf13/cast v1.3.1 // indirect
36+
github.com/spf13/cobra v1.6.1 // indirect
3537
github.com/spf13/jwalterweatherman v1.1.0 // indirect
3638
github.com/subosito/gotenv v1.2.0 // indirect
3739
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
3840
gopkg.in/ini.v1 v1.62.0 // indirect
3941
gopkg.in/yaml.v2 v2.4.0 // indirect
40-
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
42+
gopkg.in/yaml.v3 v3.0.1 // indirect
4143
)

‎go.sum

+9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
5959
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
6060
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
6161
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
62+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6263
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6364
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6465
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -172,6 +173,9 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
172173
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
173174
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
174175
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
176+
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
177+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
178+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
175179
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
176180
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
177181
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@@ -221,6 +225,7 @@ github.com/relvacode/iso8601 v1.1.0 h1:2nV8sp0eOjpoKQ2vD3xSDygsjAx37NHG2UlZiCkDH
221225
github.com/relvacode/iso8601 v1.1.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=
222226
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
223227
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
228+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
224229
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
225230
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
226231
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
@@ -233,6 +238,8 @@ github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
233238
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
234239
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
235240
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
241+
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
242+
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
236243
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
237244
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
238245
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -604,6 +611,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
604611
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
605612
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
606613
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
614+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
615+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
607616
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
608617
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
609618
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

‎pkg/streamer/streamer.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,37 @@ type Streamer struct {
1919
// onCreatePublication
2020
}
2121

22-
func New(parsers []parser.PublicationParser, ignoreDefaultParsers bool, archiveFactory archive.ArchiveFactory, httpClient *http.Client) Streamer { // TODO contentProtections
23-
cli := httpClient
24-
if cli == nil {
25-
cli = http.DefaultClient
22+
type Config struct {
23+
Parsers []parser.PublicationParser
24+
IgnoreDefaultParsers bool
25+
ArchiveFactory archive.ArchiveFactory
26+
HttpClient *http.Client
27+
}
28+
29+
func New(config Config) Streamer { // TODO contentProtections
30+
if config.HttpClient == nil {
31+
config.HttpClient = http.DefaultClient
2632
}
27-
afact := archiveFactory
28-
if afact == nil {
29-
afact = archive.NewArchiveFactory()
33+
if config.ArchiveFactory == nil {
34+
config.ArchiveFactory = archive.NewArchiveFactory()
3035
}
3136

3237
defaultParsers := []parser.PublicationParser{
3338
epub.NewParser(nil),
3439
// TODO PDF parser
35-
parser.NewWebPubParser(cli),
40+
parser.NewWebPubParser(config.HttpClient),
3641
parser.ImageParser{},
3742
parser.AudioParser{},
3843
}
3944

40-
if !ignoreDefaultParsers {
41-
parsers = append(parsers, defaultParsers...)
45+
if !config.IgnoreDefaultParsers {
46+
config.Parsers = append(config.Parsers, defaultParsers...)
4247
}
48+
4349
return Streamer{
44-
parsers: parsers,
45-
archiveFactory: afact,
46-
httpClient: cli,
50+
parsers: config.Parsers,
51+
archiveFactory: config.ArchiveFactory,
52+
httpClient: config.HttpClient,
4753
}
4854
}
4955

0 commit comments

Comments
 (0)
Please sign in to comment.