trmnl_preview 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +55 -21
- data/bin/trmnlp +14 -0
- data/lib/trmnlp/api_client.rb +62 -0
- data/lib/trmnlp/app.rb +98 -0
- data/lib/trmnlp/cli.rb +51 -0
- data/lib/trmnlp/commands/base.rb +23 -0
- data/lib/trmnlp/commands/build.rb +22 -0
- data/lib/trmnlp/commands/login.rb +25 -0
- data/lib/trmnlp/commands/pull.rb +45 -0
- data/lib/trmnlp/commands/push.rb +43 -0
- data/lib/trmnlp/commands/serve.rb +25 -0
- data/lib/trmnlp/commands.rb +1 -0
- data/lib/trmnlp/config/app.rb +39 -0
- data/lib/trmnlp/config/plugin.rb +74 -0
- data/lib/trmnlp/config/project.rb +47 -0
- data/lib/trmnlp/config.rb +15 -0
- data/lib/trmnlp/context.rb +211 -0
- data/lib/trmnlp/custom_filters.rb +14 -0
- data/lib/trmnlp/paths.rb +50 -0
- data/lib/trmnlp/screen_generator.rb +137 -0
- data/lib/trmnlp/version.rb +5 -0
- data/lib/trmnlp.rb +13 -0
- data/trmnl_preview.gemspec +32 -14
- data/web/public/index.css +98 -0
- data/web/public/index.js +75 -0
- data/web/views/index.erb +15 -80
- data/web/views/{render_view.erb → render_html.erb} +1 -6
- metadata +148 -26
- data/.ruby-version +0 -1
- data/config.example.toml +0 -14
- data/docs/preview.png +0 -0
- data/exe/trmnlp +0 -12
- data/lib/trmnl_preview/app.rb +0 -78
- data/lib/trmnl_preview/cmd/build.rb +0 -25
- data/lib/trmnl_preview/cmd/serve.rb +0 -31
- data/lib/trmnl_preview/cmd/usage.rb +0 -10
- data/lib/trmnl_preview/context.rb +0 -129
- data/lib/trmnl_preview/liquid_filters.rb +0 -8
- data/lib/trmnl_preview/version.rb +0 -5
- data/lib/trmnl_preview.rb +0 -10
- data/web/public/live-render.js +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51839346d4b2bd24698655d8e6a86a1a93aac73d2882a5b907072db9851ffa03
|
4
|
+
data.tar.gz: 0e54398757e865c8907f3b65b4046519dba2dced17d6d62ce3342b89ce2a5d75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e17bf9dba3a94a153c0182493d7b2ee597ba70b54177793fedae27a154817de8a79eb108a50194b5b5e0f1d2c012ff0b9047b9457cbdf52ad9b5e4d6331c6ab
|
7
|
+
data.tar.gz: a66a9b16b7c3512d018bd10a2444a7cfa4ecf335e9fd580583f27ac4cf6030c810bd48ab20878e3ec704b8f0faf64b7bc6e28ad08e585d1bf51ea3a01d0575fb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,47 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.4.0
|
4
|
+
|
5
|
+
### Plugin Migration Strategy
|
6
|
+
|
7
|
+
The plugin directory structure has changed to better align with the [plugin archive format](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0).
|
8
|
+
|
9
|
+
Here is a migration strategy for existing plugin repositories:
|
10
|
+
|
11
|
+
1. Create `.trmnlp.yml` and bring over preview settings from `config.toml` - [see README](README.md)
|
12
|
+
2. Rename directory `views/` to `src/`
|
13
|
+
3. Create `src/settings.yml` and bring over plugin settings from `config.toml` - [see TRMNL docs](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0)
|
14
|
+
4. Delete `config.toml`
|
15
|
+
|
16
|
+
### Changes
|
17
|
+
|
18
|
+
- Change plugin directory structure (see README for details)
|
19
|
+
- Add `login`, `push`, and `pull` commands
|
20
|
+
- Bring up-to-date with latest private plugin features:
|
21
|
+
- Add `static` strategy
|
22
|
+
- Add polling features: multiple URLs, new verbs, and request body
|
23
|
+
- Add settings `dark_mode`, `no_screen_padding`, `custom_fields`
|
24
|
+
- Add interpolation of custom fields in `polling\_\*` options
|
25
|
+
- Add `{{ trmnl }}` variables
|
26
|
+
- Add `watch` config
|
27
|
+
- Add interpolation of environment variables in `.trmnlp.yml` via `{{ env }}`
|
28
|
+
- Add auto-reload when `.trmnlp.yml` or `settings.yml` changes
|
29
|
+
- Add variable display
|
30
|
+
- Fix crash when #poll_data fails (#12)
|
31
|
+
- Fix git runtime error in Docker container (#12)
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
## 0.3.2
|
36
|
+
|
37
|
+
- Add bitmap rendering
|
38
|
+
- Add TRMNL's [custom plugin filters](https://help.usetrmnl.com/en/articles/10347358-custom-plugin-filters)
|
39
|
+
- Add support for user-supplied custom filters
|
40
|
+
|
41
|
+
## 0.3.1
|
42
|
+
|
43
|
+
- Add live render
|
44
|
+
|
3
45
|
## 0.3.0
|
4
46
|
|
5
47
|
- Add poll button
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# trmnlp
|
2
2
|
|
3
3
|
A basic self-hosted web server to ease the development and sharing of [TRMNL](https://usetrmnl.com/) plugins.
|
4
4
|
|
5
|
-
[Liquid](https://shopify.github.io/liquid/) templates are rendered
|
5
|
+
[Liquid](https://shopify.github.io/liquid/) templates are rendered leveraging the [TRMNL Design System](https://usetrmnl.com/framework). They may be generated as HTML (faster, and a good approximation of the final result) or as BMP images (slower, but more accurate).
|
6
6
|
|
7
7
|
The server watches the filesystem for changes to the Liquid templates, seamlessly updating the preview without the need to refresh.
|
8
8
|
|
@@ -10,20 +10,25 @@ The server watches the filesystem for changes to the Liquid templates, seamlessl
|
|
10
10
|
|
11
11
|
## Creating a Plugin
|
12
12
|
|
13
|
-
This is the structure of a plugin
|
13
|
+
This is the structure of a plugin project.
|
14
14
|
|
15
15
|
```
|
16
|
-
|
16
|
+
.trmnlp.yml
|
17
|
+
src/
|
17
18
|
full.liquid
|
18
19
|
half_horizontal.liquid
|
19
20
|
half_vertical.liquid
|
20
21
|
quadrant.liquid
|
21
|
-
|
22
|
+
settings.yml
|
22
23
|
```
|
23
24
|
|
24
|
-
|
25
|
+
## Syncing Plugin With TRMNL Server
|
25
26
|
|
26
|
-
|
27
|
+
```sh
|
28
|
+
trmnl login # authenticate with TRMNL account
|
29
|
+
trmnl pull [id] # download (plugin ID required on first pull only)
|
30
|
+
trmnl push # upload
|
31
|
+
```
|
27
32
|
|
28
33
|
## Running the Server (Docker)
|
29
34
|
|
@@ -31,36 +36,65 @@ The [trmnl-hello](https://github.com/schrockwell/trmnl-hello) repository is prov
|
|
31
36
|
docker run \
|
32
37
|
-p 4567:4567 \
|
33
38
|
-v /path/to/plugin/on/host:/plugin \
|
34
|
-
|
39
|
+
trmnl/trmnlp
|
35
40
|
```
|
36
41
|
|
37
42
|
## Running the Server (Local Ruby)
|
38
43
|
|
39
|
-
|
44
|
+
Prerequisites:
|
45
|
+
|
46
|
+
- Ruby 3.x
|
47
|
+
- For BMP rendering (optional):
|
48
|
+
- Firefox
|
49
|
+
- ImageMagick
|
50
|
+
|
51
|
+
In the plugin project:
|
40
52
|
|
41
53
|
```sh
|
42
|
-
|
43
|
-
trmnlp serve
|
54
|
+
gem install trmnl_preview
|
55
|
+
trmnlp serve
|
44
56
|
```
|
45
57
|
|
46
|
-
##
|
58
|
+
## `./.trmnlp.yml` Reference (Project Config)
|
59
|
+
|
60
|
+
The `.trmnlp.yml` file lives in the root of the plugin project, and is for configuring the local dev server.
|
47
61
|
|
48
|
-
|
62
|
+
System environment variables are made available in the `{{ env }}` Liquid varible in this file only. This can be used to safely
|
63
|
+
supply plugin secrets, like API keys.
|
49
64
|
|
50
|
-
|
65
|
+
All fields are optional.
|
66
|
+
|
67
|
+
```yaml
|
68
|
+
# {{ env.VARIABLE }} interpolation is available here
|
69
|
+
---
|
70
|
+
# auto-reload when files change (`watch: false` to disable)
|
71
|
+
watch:
|
72
|
+
- src
|
73
|
+
- .trmnlp.yml
|
74
|
+
|
75
|
+
# values of custom fields (defined in src/settings.yml)
|
76
|
+
custom_fields:
|
77
|
+
station: "{{ env.ICAO }}"
|
78
|
+
|
79
|
+
# override variables
|
80
|
+
variables:
|
81
|
+
trmnl:
|
82
|
+
user:
|
83
|
+
name: Peter Quill
|
84
|
+
plugin_settings:
|
85
|
+
instance_name: Kevin Bacon Facts
|
86
|
+
|
87
|
+
```
|
51
88
|
|
52
|
-
|
89
|
+
## `./src/settings.yml` Reference (Plugin Config)
|
53
90
|
|
54
|
-
|
91
|
+
The `settings.yml` file is part of the plugin definition.
|
55
92
|
|
56
|
-
|
57
|
-
- `url` - The URL from which to fetch JSON data (polling strategy only)
|
58
|
-
- `live_render` - Set to `false` to disable automatic rendering when Liquid templates change (default `true`)
|
59
|
-
- `[polling_headers]` - A section of headers to append to the HTTP poll request (polling strategy only)
|
93
|
+
See [TRMNL documentation](https://help.usetrmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0) for details on this file's contents.
|
60
94
|
|
61
95
|
## Contributing
|
62
96
|
|
63
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
97
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/usetrmnl/trmnlp.
|
64
98
|
|
65
99
|
## License
|
66
100
|
|
data/bin/trmnlp
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday/multipart'
|
3
|
+
|
4
|
+
require_relative 'config'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
class APIClient
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_plugin_setting_archive(id)
|
13
|
+
response = conn.get("plugin_settings/#{id}/archive")
|
14
|
+
|
15
|
+
if response.status == 200
|
16
|
+
temp_file = Tempfile.new(["plugin_settings_#{id}", '.zip'])
|
17
|
+
temp_file.binmode
|
18
|
+
temp_file.write(response.body)
|
19
|
+
temp_file.rewind
|
20
|
+
|
21
|
+
# return the path to the temp file
|
22
|
+
Pathname.new(temp_file.path)
|
23
|
+
else
|
24
|
+
raise Error, "failed to download plugin settings archive: #{response.status} #{response.body}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def post_plugin_setting_archive(id, path)
|
29
|
+
payload = {
|
30
|
+
file: Faraday::Multipart::FilePart.new(path, 'application/zip')
|
31
|
+
}
|
32
|
+
|
33
|
+
response = conn.post("plugin_settings/#{id}/archive", payload)
|
34
|
+
|
35
|
+
if response.status == 200
|
36
|
+
true
|
37
|
+
else
|
38
|
+
raise Error, "failed to upload plugin settings archive: #{response.status} #{response.body}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :config
|
45
|
+
|
46
|
+
def api_uri = config.app.api_uri
|
47
|
+
|
48
|
+
def conn
|
49
|
+
@conn ||= Faraday.new(url: api_uri, headers:) do |f|
|
50
|
+
f.request :multipart
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def headers
|
56
|
+
{
|
57
|
+
'Authorization' => "Bearer #{config.app.api_key}",
|
58
|
+
'User-Agent' => "trmnlp/#{VERSION}",
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/trmnlp/app.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
require 'faye/websocket'
|
3
|
+
require 'sinatra'
|
4
|
+
require 'sinatra/base'
|
5
|
+
|
6
|
+
require_relative 'context'
|
7
|
+
require_relative 'screen_generator'
|
8
|
+
|
9
|
+
module TRMNLP
|
10
|
+
class App < Sinatra::Base
|
11
|
+
# Sinatra settings
|
12
|
+
set :views, File.join(File.dirname(__FILE__), '..', '..', 'web', 'views')
|
13
|
+
set :public_folder, File.join(File.dirname(__FILE__), '..', '..', 'web', 'public')
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
|
18
|
+
@context = settings.context
|
19
|
+
|
20
|
+
@context.poll_data
|
21
|
+
|
22
|
+
@context.start_filewatcher if @context.config.project.live_render?
|
23
|
+
|
24
|
+
@live_reload_clients = []
|
25
|
+
@context.on_view_change do |view, user_data|
|
26
|
+
@live_reload_clients.each do |ws|
|
27
|
+
payload = {
|
28
|
+
'type' => 'reload',
|
29
|
+
'view' => view,
|
30
|
+
'user_data' => user_data
|
31
|
+
}
|
32
|
+
|
33
|
+
ws.send(payload.to_json)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
post '/webhook' do
|
39
|
+
@context.put_webhook(request.body.read)
|
40
|
+
"OK"
|
41
|
+
end
|
42
|
+
|
43
|
+
get '/' do
|
44
|
+
redirect '/full'
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/data' do
|
48
|
+
content_type :json
|
49
|
+
JSON.pretty_generate(@context.user_data)
|
50
|
+
end
|
51
|
+
|
52
|
+
get '/live_reload' do
|
53
|
+
ws = Faye::WebSocket.new(request.env)
|
54
|
+
|
55
|
+
ws.on(:open) do |event|
|
56
|
+
@live_reload_clients << ws
|
57
|
+
end
|
58
|
+
|
59
|
+
ws.on(:close) do |event|
|
60
|
+
@live_reload_clients.delete(ws)
|
61
|
+
end
|
62
|
+
|
63
|
+
ws.rack_response
|
64
|
+
end
|
65
|
+
|
66
|
+
get '/poll' do
|
67
|
+
@context.poll_data
|
68
|
+
redirect back
|
69
|
+
end
|
70
|
+
|
71
|
+
VIEWS.each do |view|
|
72
|
+
get "/#{view}" do
|
73
|
+
@view = view
|
74
|
+
@user_data = JSON.pretty_generate(@context.user_data)
|
75
|
+
@live_reload = @context.config.project.live_render?
|
76
|
+
|
77
|
+
erb :index
|
78
|
+
end
|
79
|
+
|
80
|
+
get "/render/#{view}.html" do
|
81
|
+
@view = view
|
82
|
+
@screen_classes = @context.screen_classes
|
83
|
+
|
84
|
+
erb :render_html do
|
85
|
+
@context.render_template(view)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
get "/render/#{view}.bmp" do
|
90
|
+
@view = view
|
91
|
+
html = @context.render_full_page(view)
|
92
|
+
generator = ScreenGenerator.new(html, image: true)
|
93
|
+
img_path = generator.process
|
94
|
+
send_file img_path, type: 'image/png', disposition: 'inline'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/trmnlp/cli.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
require_relative '../trmnlp'
|
4
|
+
require_relative '../trmnlp/commands'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
class CLI < Thor
|
8
|
+
package_name 'trmnlp'
|
9
|
+
|
10
|
+
class_option :dir, type: :string, default: Dir.pwd, aliases: '-d',
|
11
|
+
desc: 'Plugin directory'
|
12
|
+
|
13
|
+
def self.exit_on_failure? = true
|
14
|
+
|
15
|
+
desc 'build', 'Generate static HTML files'
|
16
|
+
def build
|
17
|
+
Commands::Build.new(options).call
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'login', 'Authenticate with TRMNL server'
|
21
|
+
def login
|
22
|
+
Commands::Login.new(options).call
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'pull [id]', 'Download plugin settings from TRMNL server'
|
26
|
+
method_option :force, type: :boolean, default: false, aliases: '-f',
|
27
|
+
desc: 'Skip confirmation prompts'
|
28
|
+
def pull(plugin_settings_id = nil)
|
29
|
+
Commands::Pull.new(options).call(plugin_settings_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'push [id]', 'Upload plugin settings to TRMNL server'
|
33
|
+
method_option :force, type: :boolean, default: false, aliases: '-f',
|
34
|
+
desc: 'Skip confirmation prompts'
|
35
|
+
def push(plugin_settings_id = nil)
|
36
|
+
Commands::Push.new(options).call(plugin_settings_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'serve', 'Start a local dev server'
|
40
|
+
method_option :bind, type: :string, default: '127.0.0.1', aliases: '-b', desc: 'Bind address'
|
41
|
+
method_option :port, type: :numeric, default: 4567, aliases: '-p', desc: 'Port number'
|
42
|
+
def serve
|
43
|
+
Commands::Serve.new(options).call
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'version', 'Show version'
|
47
|
+
def version
|
48
|
+
puts VERSION
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../context'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Base
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
@context = Context.new(options.dir)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :options, :context
|
18
|
+
|
19
|
+
def config = context.config
|
20
|
+
def paths = context.paths
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Build < Base
|
6
|
+
def call
|
7
|
+
context = Context.new(options.dir)
|
8
|
+
context.validate!
|
9
|
+
context.poll_data
|
10
|
+
context.paths.create_build_dir
|
11
|
+
|
12
|
+
VIEWS.each do |view|
|
13
|
+
output_path = context.paths.build_dir.join("#{view}.html")
|
14
|
+
puts "Writing #{output_path}..."
|
15
|
+
output_path.write(context.render_full_page(view))
|
16
|
+
end
|
17
|
+
|
18
|
+
puts "Done!"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
module Commands
|
5
|
+
class Login < Base
|
6
|
+
def call
|
7
|
+
if config.app.logged_in?
|
8
|
+
anonymous_key = config.app.api_key[0..10] + '*' * (config.app.api_key.length - 11)
|
9
|
+
puts "Currently authenticated as: #{anonymous_key}"
|
10
|
+
end
|
11
|
+
|
12
|
+
puts "Please visit #{config.app.account_uri} to grab your API key, then paste it here."
|
13
|
+
|
14
|
+
print "API Key: "
|
15
|
+
api_key = STDIN.gets.chomp
|
16
|
+
raise Error, "API key cannot be empty" if api_key.empty?
|
17
|
+
|
18
|
+
config.app.api_key = api_key
|
19
|
+
config.app.save
|
20
|
+
|
21
|
+
puts "Saved changes to #{paths.app_config}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Pull < Base
|
9
|
+
def call(plugin_settings_id)
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
raise Error, "please run `trmnlp login`" unless config.app.logged_in?
|
13
|
+
|
14
|
+
plugin_settings_id ||= config.plugin.id
|
15
|
+
raise Error, 'plugin ID must be specified' if plugin_settings_id.nil?
|
16
|
+
|
17
|
+
unless options.force
|
18
|
+
print "Local plugin files will be overwritten. Are you sure? (y/n) "
|
19
|
+
answer = $stdin.gets.chomp.downcase
|
20
|
+
raise Error, 'aborting' unless answer == 'y' || answer == 'yes'
|
21
|
+
end
|
22
|
+
|
23
|
+
api = APIClient.new(config)
|
24
|
+
temp_path = api.get_plugin_setting_archive(plugin_settings_id)
|
25
|
+
size = 0
|
26
|
+
|
27
|
+
begin
|
28
|
+
Zip::File.open(temp_path) do |zip_file|
|
29
|
+
zip_file.each do |entry|
|
30
|
+
dest_path = paths.src_dir.join(entry.name)
|
31
|
+
dest_path.dirname.mkpath
|
32
|
+
zip_file.extract(entry, dest_path) { true } # overwrite existing
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
size = File.size(temp_path)
|
37
|
+
ensure
|
38
|
+
temp_path.delete
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Downloaded plugin (#{size} bytes)"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Push < Base
|
9
|
+
def call(plugin_settings_id)
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
raise Error, "please run `trmnlp login`" unless config.app.logged_in?
|
13
|
+
|
14
|
+
plugin_settings_id ||= config.plugin.id
|
15
|
+
raise Error, 'plugin ID must be specified' if plugin_settings_id.nil?
|
16
|
+
|
17
|
+
unless options.force
|
18
|
+
print "Plugin settings on the server will be overwritten. Are you sure? (y/n) "
|
19
|
+
answer = $stdin.gets.chomp.downcase
|
20
|
+
raise Error, 'aborting' unless answer == 'y' || answer == 'yes'
|
21
|
+
end
|
22
|
+
|
23
|
+
api = APIClient.new(config)
|
24
|
+
size = 0
|
25
|
+
|
26
|
+
Tempfile.create(binmode: true) do |temp_file|
|
27
|
+
Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip_file|
|
28
|
+
paths.src_files.each do |file|
|
29
|
+
zip_file.add(File.basename(file), file)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
api.post_plugin_setting_archive(plugin_settings_id, temp_file.path)
|
34
|
+
|
35
|
+
size = File.size(temp_file.path)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
puts "Uploaded plugin (#{size} bytes)"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'zip'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
require_relative '../api_client'
|
5
|
+
|
6
|
+
module TRMNLP
|
7
|
+
module Commands
|
8
|
+
class Serve < Base
|
9
|
+
def call
|
10
|
+
context.validate!
|
11
|
+
|
12
|
+
# Must come AFTER parsing options
|
13
|
+
require_relative '../app'
|
14
|
+
|
15
|
+
# Now we can configure things
|
16
|
+
App.set(:context, context)
|
17
|
+
App.set(:bind, options.bind)
|
18
|
+
App.set(:port, options.port)
|
19
|
+
|
20
|
+
# Finally, start the app!
|
21
|
+
App.run!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.join(__dir__, 'commands', '*.rb')].each { |file| require file }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module TRMNLP
|
4
|
+
class Config
|
5
|
+
# Stores trmnlp-wide configuration (irrespective of the current plugin)
|
6
|
+
class App
|
7
|
+
def initialize(paths)
|
8
|
+
@paths = paths
|
9
|
+
@config = read_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def save
|
13
|
+
paths.app_config_dir.mkpath
|
14
|
+
paths.app_config.write(YAML.dump(@config))
|
15
|
+
end
|
16
|
+
|
17
|
+
def logged_in? = api_key && !api_key.empty?
|
18
|
+
def logged_out? = !logged_in?
|
19
|
+
|
20
|
+
def api_key = @config['api_key']
|
21
|
+
|
22
|
+
def api_key=(key)
|
23
|
+
@config['api_key'] = key
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_uri = URI.parse(@config['base_url'] || 'https://usetrmnl.com')
|
27
|
+
|
28
|
+
def api_uri = URI.join(base_uri, 'api')
|
29
|
+
|
30
|
+
def account_uri = URI.join(base_uri, 'account')
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :paths
|
35
|
+
|
36
|
+
def read_config = paths.app_config.exist? ? YAML.safe_load(paths.app_config.read) : {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|