fluid_cli 0.1.9 → 0.2.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/README.md +185 -1
- data/lib/fluid_cli/file_system_listener.rb +5 -2
- data/lib/fluid_cli/theme/dev_server/watcher.rb +7 -1
- data/lib/fluid_cli/theme/fluid_ignore.rb +93 -0
- data/lib/fluid_cli/theme/root.rb +6 -0
- data/lib/fluid_cli/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84ff5fea48f57756d085af8e58148aec8b8b98161b152f5c7e95252f51e2348b
|
|
4
|
+
data.tar.gz: 0b65b1eccfcf8e095961e4518eb9c5e73cb4b6884b029f12074bfe477b1dc40a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a951d7bfafd5ce072e8b2b8e91f308878021a13697848f0eb6fa294f09e5e0d2118a02339530914fa3dcd0647b2c7e7f29bf36bc4d2f89adcfebaf3e3b225937
|
|
7
|
+
data.tar.gz: 1031eb13ffbfb6025e7adbea17dca9bc76d7ab220840e3a8e5782422ba2edba49ee8dc8ccbc7a631e244e04aca5d62718db9f1d85043ec4ad5770008c00e2533
|
data/README.md
CHANGED
|
@@ -1 +1,185 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Fluid CLI
|
|
2
|
+
|
|
3
|
+
The official command-line interface for the [Fluid](https://fluid.app) e-commerce platform. Build, preview, and deploy themes for your Fluid storefront directly from the terminal.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Ruby >= 3.1.0
|
|
10
|
+
- Bundler
|
|
11
|
+
|
|
12
|
+
### From Source
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
git clone https://github.com/fluid-commerce/fluid-cli.git
|
|
16
|
+
cd fluid-cli
|
|
17
|
+
bundle install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### As a Gem
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
gem install fluid_cli
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
# Authenticate with your Fluid account
|
|
30
|
+
fluid login
|
|
31
|
+
|
|
32
|
+
# Initialize a new theme from the base template
|
|
33
|
+
fluid theme init
|
|
34
|
+
|
|
35
|
+
# Start the local development server
|
|
36
|
+
fluid theme dev
|
|
37
|
+
|
|
38
|
+
# Push your theme to Fluid
|
|
39
|
+
fluid theme push
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Authentication
|
|
43
|
+
|
|
44
|
+
Fluid CLI uses OAuth2 for authentication. Running `fluid login` will open your browser and redirect you to the Fluid authentication page. Once authenticated, your session is stored locally.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
# Log in to your Fluid account
|
|
48
|
+
fluid login
|
|
49
|
+
|
|
50
|
+
# Log in to a specific company
|
|
51
|
+
fluid login --company=my-store
|
|
52
|
+
|
|
53
|
+
# Check who you're logged in as
|
|
54
|
+
fluid whoami
|
|
55
|
+
|
|
56
|
+
# Switch between companies
|
|
57
|
+
fluid switch --company=another-store
|
|
58
|
+
|
|
59
|
+
# Log out
|
|
60
|
+
fluid logout
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can also authenticate via environment variables:
|
|
64
|
+
|
|
65
|
+
| Variable | Description |
|
|
66
|
+
|----------|-------------|
|
|
67
|
+
| `FLUID_AUTH_TOKEN` | Bearer token for API authentication |
|
|
68
|
+
| `FLUID_COMPANY` | Default company subdomain |
|
|
69
|
+
|
|
70
|
+
## Commands
|
|
71
|
+
|
|
72
|
+
### `fluid login`
|
|
73
|
+
|
|
74
|
+
Authenticate with your Fluid account via the browser.
|
|
75
|
+
|
|
76
|
+
| Flag | Description |
|
|
77
|
+
|------|-------------|
|
|
78
|
+
| `-c, --company=COMPANY` | Specify the company to log in to |
|
|
79
|
+
|
|
80
|
+
### `fluid logout`
|
|
81
|
+
|
|
82
|
+
Clear stored authentication tokens.
|
|
83
|
+
|
|
84
|
+
### `fluid whoami`
|
|
85
|
+
|
|
86
|
+
Display the currently authenticated company.
|
|
87
|
+
|
|
88
|
+
### `fluid switch`
|
|
89
|
+
|
|
90
|
+
Switch between companies on your account.
|
|
91
|
+
|
|
92
|
+
| Flag | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `-c, --company=COMPANY` | Specify the company to switch to |
|
|
95
|
+
|
|
96
|
+
### `fluid theme init`
|
|
97
|
+
|
|
98
|
+
Initialize a new theme by cloning the base template into your current directory.
|
|
99
|
+
|
|
100
|
+
| Flag | Description |
|
|
101
|
+
|------|-------------|
|
|
102
|
+
| `-u, --clone-url=URL` | Custom Git URL to clone from |
|
|
103
|
+
|
|
104
|
+
### `fluid theme dev`
|
|
105
|
+
|
|
106
|
+
Start a local development server with hot reload. The dev server proxies requests to your Fluid storefront and injects local theme files, enabling a fast development workflow.
|
|
107
|
+
|
|
108
|
+
| Flag | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `--host=HOST` | Host to bind the dev server to |
|
|
111
|
+
| `--port=PORT` | Port to bind the dev server to |
|
|
112
|
+
| `--poll` | Use polling instead of filesystem events for file watching |
|
|
113
|
+
| `--live-reload=MODE` | Reload mode: `full-page` or `hot-reload` |
|
|
114
|
+
| `-t, --theme=THEME_ID` | Use a specific theme |
|
|
115
|
+
| `-f, --force` | Force create a new development theme |
|
|
116
|
+
| `--overwrite-json` | Overwrite remote JSON files with local versions |
|
|
117
|
+
| `--navigate` | Open the interactive route/resource navigator |
|
|
118
|
+
|
|
119
|
+
### `fluid theme push`
|
|
120
|
+
|
|
121
|
+
Upload your local theme files to Fluid.
|
|
122
|
+
|
|
123
|
+
| Flag | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `-n, --nodelete` | Don't delete remote files that are missing locally |
|
|
126
|
+
| `-t, --theme=THEME_ID` | Push to a specific theme |
|
|
127
|
+
| `-u, --unpublished` | Push to a new unpublished theme |
|
|
128
|
+
| `-j, --json` | Include JSON settings files |
|
|
129
|
+
| `-a, --allow-live` | Allow pushing to the live theme |
|
|
130
|
+
| `-p, --publish` | Publish the theme after pushing |
|
|
131
|
+
| `-f, --force` | Skip confirmation prompts |
|
|
132
|
+
|
|
133
|
+
### `fluid theme pull`
|
|
134
|
+
|
|
135
|
+
Download theme files from Fluid to your local directory.
|
|
136
|
+
|
|
137
|
+
| Flag | Description |
|
|
138
|
+
|------|-------------|
|
|
139
|
+
| `-t, --theme=THEME_ID` | Pull from a specific theme |
|
|
140
|
+
|
|
141
|
+
### `fluid theme navigate`
|
|
142
|
+
|
|
143
|
+
Launch an interactive navigator to browse routes and resources for your storefront.
|
|
144
|
+
|
|
145
|
+
| Flag | Description |
|
|
146
|
+
|------|-------------|
|
|
147
|
+
| `--host=HOST` | Host for the navigator server |
|
|
148
|
+
| `--port=PORT` | Port for the navigator server |
|
|
149
|
+
| `-t, --theme=THEME_ID` | Theme to navigate |
|
|
150
|
+
|
|
151
|
+
## `.fluidignore`
|
|
152
|
+
|
|
153
|
+
You can create a `.fluidignore` file in your theme's root directory to exclude files and directories from all theme operations (dev, push, pull, and file watching). The syntax is identical to `.gitignore`:
|
|
154
|
+
|
|
155
|
+
```gitignore
|
|
156
|
+
# Ignore node_modules
|
|
157
|
+
node_modules/
|
|
158
|
+
|
|
159
|
+
# Ignore all log files
|
|
160
|
+
*.log
|
|
161
|
+
|
|
162
|
+
# Ignore a specific directory
|
|
163
|
+
tmp/
|
|
164
|
+
|
|
165
|
+
# Negate a pattern (re-include a previously ignored file)
|
|
166
|
+
!important.log
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
After cloning the repository:
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
bundle install
|
|
175
|
+
|
|
176
|
+
# Run the CLI locally
|
|
177
|
+
bundle exec fluid
|
|
178
|
+
|
|
179
|
+
# Run tests
|
|
180
|
+
bundle exec rake test
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
This project is available under the [MIT License](LICENSE.txt).
|
|
@@ -6,11 +6,14 @@ module FluidCLI
|
|
|
6
6
|
class FileSystemListener
|
|
7
7
|
include Observable
|
|
8
8
|
|
|
9
|
-
def initialize(root:, force_poll:)
|
|
9
|
+
def initialize(root:, force_poll:, ignore_pattern: nil)
|
|
10
10
|
@root = root
|
|
11
11
|
@force_poll = force_poll
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
listen_opts = { force_polling: @force_poll }
|
|
14
|
+
listen_opts[:ignore] = ignore_pattern if ignore_pattern
|
|
15
|
+
|
|
16
|
+
@listener = Listen.to(@root, **listen_opts) do |updated, added, removed|
|
|
14
17
|
changed
|
|
15
18
|
notify_observers(updated, added, removed)
|
|
16
19
|
end
|
|
@@ -15,7 +15,13 @@ module FluidCLI
|
|
|
15
15
|
@ctx = ctx
|
|
16
16
|
@theme = theme
|
|
17
17
|
@syncer = syncer
|
|
18
|
-
|
|
18
|
+
|
|
19
|
+
ignore_pattern = @theme.fluid_ignore.to_listen_regexp
|
|
20
|
+
@listener = FileSystemListener.new(
|
|
21
|
+
root: @theme.root,
|
|
22
|
+
force_poll: poll,
|
|
23
|
+
ignore_pattern: ignore_pattern
|
|
24
|
+
)
|
|
19
25
|
|
|
20
26
|
add_observer(self, :upload_files_when_changed)
|
|
21
27
|
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FluidCLI
|
|
4
|
+
module Theme
|
|
5
|
+
class FluidIgnore
|
|
6
|
+
IGNORE_FILE = ".fluidignore"
|
|
7
|
+
|
|
8
|
+
attr_reader :patterns
|
|
9
|
+
|
|
10
|
+
def initialize(root)
|
|
11
|
+
@root = root
|
|
12
|
+
@patterns = parse(ignore_file_path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns true if the given relative path should be ignored.
|
|
16
|
+
# Last matching pattern wins (supports negation with !).
|
|
17
|
+
def ignore?(relative_path)
|
|
18
|
+
relative_path = relative_path.to_s
|
|
19
|
+
result = false
|
|
20
|
+
@patterns.each do |negated, pattern|
|
|
21
|
+
if match?(pattern, relative_path)
|
|
22
|
+
result = !negated
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
result
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns a Regexp suitable for Listen.to(ignore: ...).
|
|
29
|
+
# Returns nil if there are no positive patterns.
|
|
30
|
+
def to_listen_regexp
|
|
31
|
+
positive_patterns = @patterns.reject(&:first).map(&:last)
|
|
32
|
+
return nil if positive_patterns.empty?
|
|
33
|
+
|
|
34
|
+
parts = positive_patterns.map { |pat| fnmatch_to_regex(pat) }
|
|
35
|
+
Regexp.new(parts.join("|"))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def any?
|
|
39
|
+
@patterns.any?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def ignore_file_path
|
|
45
|
+
::File.join(@root.to_s, IGNORE_FILE)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def parse(path)
|
|
49
|
+
return [] unless ::File.exist?(path)
|
|
50
|
+
|
|
51
|
+
::File.readlines(path, chomp: true).filter_map do |line|
|
|
52
|
+
line = line.strip
|
|
53
|
+
next if line.empty? || line.start_with?("#")
|
|
54
|
+
|
|
55
|
+
negated = line.start_with?("!")
|
|
56
|
+
line = line[1..] if negated
|
|
57
|
+
|
|
58
|
+
# Leading slash means relative to root — strip it for fnmatch
|
|
59
|
+
line = line[1..] if line.start_with?("/")
|
|
60
|
+
|
|
61
|
+
[negated, line]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def match?(pattern, path)
|
|
66
|
+
if pattern.end_with?("/")
|
|
67
|
+
# Directory pattern — match anything under this directory
|
|
68
|
+
path.start_with?(pattern) || path == pattern.chomp("/")
|
|
69
|
+
elsif pattern.include?("/")
|
|
70
|
+
# Path pattern — match against the full relative path
|
|
71
|
+
::File.fnmatch(pattern, path, ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH)
|
|
72
|
+
else
|
|
73
|
+
# Basename pattern — match against both full path and basename
|
|
74
|
+
::File.fnmatch(pattern, path, ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH) ||
|
|
75
|
+
::File.fnmatch(pattern, ::File.basename(path), ::File::FNM_DOTMATCH)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def fnmatch_to_regex(pattern)
|
|
80
|
+
if pattern.end_with?("/")
|
|
81
|
+
# Directory pattern — match the directory and anything under it
|
|
82
|
+
Regexp.escape(pattern) + ".*"
|
|
83
|
+
else
|
|
84
|
+
re = Regexp.escape(pattern)
|
|
85
|
+
re.gsub("\\*\\*", "DOUBLE_STAR")
|
|
86
|
+
.gsub("\\*", "[^/]*")
|
|
87
|
+
.gsub("DOUBLE_STAR", ".*")
|
|
88
|
+
.gsub("\\?", "[^/]")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/fluid_cli/theme/root.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require_relative "file"
|
|
3
|
+
require_relative "fluid_ignore"
|
|
3
4
|
require "pathname"
|
|
4
5
|
|
|
5
6
|
module FluidCLI
|
|
@@ -24,11 +25,16 @@ module FluidCLI
|
|
|
24
25
|
glob("**/*.json")
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
def fluid_ignore
|
|
29
|
+
@fluid_ignore ||= FluidIgnore.new(root)
|
|
30
|
+
end
|
|
31
|
+
|
|
27
32
|
def glob(pattern, raise_on_dir: false)
|
|
28
33
|
root
|
|
29
34
|
.glob(pattern)
|
|
30
35
|
.select { |path| file?(path, raise_on_dir) }
|
|
31
36
|
.map { |path| File.new(path, root) }
|
|
37
|
+
.reject { |file| fluid_ignore.ignore?(file.relative_path) }
|
|
32
38
|
end
|
|
33
39
|
|
|
34
40
|
def static_asset_file?(file)
|
data/lib/fluid_cli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluid_cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Fluid
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-02
|
|
10
|
+
date: 2026-03-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bugsnag
|
|
@@ -142,6 +142,7 @@ files:
|
|
|
142
142
|
- lib/fluid_cli/theme/dev_server/web_server.rb
|
|
143
143
|
- lib/fluid_cli/theme/development_theme.rb
|
|
144
144
|
- lib/fluid_cli/theme/file.rb
|
|
145
|
+
- lib/fluid_cli/theme/fluid_ignore.rb
|
|
145
146
|
- lib/fluid_cli/theme/forms/select.rb
|
|
146
147
|
- lib/fluid_cli/theme/mime_type.rb
|
|
147
148
|
- lib/fluid_cli/theme/navigation/resource_fetcher.rb
|