39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
# File 'lib/discourse_theme/cli.rb', line 39
def run(args)
if args.delete("--version")
puts VERSION
return
end
usage unless args[1]
reset = !!args.delete("--reset")
command = args[0].to_s.downcase
dir = File.expand_path(args[1])
config = DiscourseTheme::Config.new(self.class.settings_file)
settings = config[dir]
theme_id = settings.theme_id
components = settings.components
if command == "new"
if Dir.exist?(dir) && !Dir.empty?(dir)
raise DiscourseTheme::ThemeError.new "'#{dir}' is not empty"
end
raise DiscourseTheme::ThemeError.new "git is not installed" if !command?("git")
raise DiscourseTheme::ThemeError.new "yarn is not installed" if !command?("yarn")
raise DiscourseTheme::ThemeError.new "pnpm is not installed" if !command?("pnpm")
DiscourseTheme::Scaffold.generate(dir, name: args[1])
watch_theme?(args)
elsif command == "watch"
raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exist?(dir)
client = DiscourseTheme::Client.new(dir, settings, reset: reset)
theme_list = client.get_themes_list
options = {}
if theme_id && theme = theme_list.find { |t| t["id"] == theme_id }
options["Sync with existing theme: '#{theme["name"]}' (id:#{theme_id})"] = :default
end
options["Create and sync with a new theme"] = :create
options["Select a different theme"] = :select
choice = UI.select("How would you like to sync this theme?", options.keys)
if options[choice] == :create
theme_id = nil
elsif options[choice] == :select
themes = render_theme_list(theme_list)
choice = UI.select("Which theme would you like to sync with?", themes)
theme_id = (choice)
theme = theme_list.find { |t| t["id"] == theme_id }
end
about_json =
begin
JSON.parse(File.read(File.join(dir, "about.json")))
rescue StandardError
nil
end
already_uploaded = !!theme
is_component = theme&.[]("component")
component_count = about_json&.[]("components")&.length || 0
if !already_uploaded && !is_component && component_count > 0
options = {}
options["Yes"] = :sync
options["No"] = :none
options = options.sort_by { |_, b| b == components.to_sym ? 0 : 1 }.to_h if components
choice = UI.select("Would you like to update child theme components?", options.keys)
settings.components = components = options[choice].to_s
end
uploader =
DiscourseTheme::Uploader.new(
dir: dir,
client: client,
theme_id: theme_id,
components: components,
)
UI.progress "Uploading theme from #{dir}"
settings.theme_id =
theme_id = uploader.upload_full_theme(skip_migrations: skip_migrations(theme, dir))
UI.success "Theme uploaded (id:#{theme_id})"
UI.info "Preview: #{client.url}/?preview_theme_id=#{theme_id}"
if client.is_theme_creator
UI.info "Manage: #{client.url}/my/themes"
else
UI.info "Manage: #{client.url}/admin/customize/themes/#{theme_id}"
end
UI.info "Tests: #{client.url}/theme-qunit?id=#{theme_id}"
watcher = DiscourseTheme::Watcher.new(dir: dir, uploader: uploader)
UI.progress "Watching for changes in #{dir}..."
watcher.watch
elsif command == "download"
client = DiscourseTheme::Client.new(dir, settings, reset: reset)
downloader = DiscourseTheme::Downloader.new(dir: dir, client: client)
FileUtils.mkdir_p dir unless Dir.exist?(dir)
raise DiscourseTheme::ThemeError.new "'#{dir} is not empty" unless Dir.empty?(dir)
UI.progress "Loading theme list..."
themes = render_theme_list(client.get_themes_list)
choice = UI.select("Which theme would you like to download?", themes)
theme_id = (choice)
UI.progress "Downloading theme into #{dir}"
downloader.download_theme(theme_id)
settings.theme_id = theme_id
UI.success "Theme downloaded"
watch_theme?(args)
elsif command == "upload"
raise DiscourseTheme::ThemeError.new "'#{dir} does not exist" unless Dir.exist?(dir)
if theme_id == 0
raise DiscourseTheme::ThemeError.new "No theme_id is set, please sync via the 'watch' command initially"
end
client = DiscourseTheme::Client.new(dir, settings, reset: reset)
theme_list = client.get_themes_list
theme = theme_list.find { |t| t["id"] == theme_id }
unless theme
raise DiscourseTheme::ThemeError.new "theme_id is set, but the theme does not exist in Discourse"
end
uploader =
DiscourseTheme::Uploader.new(
dir: dir,
client: client,
theme_id: theme_id,
components: components,
)
UI.progress "Uploading theme (id:#{theme_id}) from #{dir} "
settings.theme_id = theme_id = uploader.upload_full_theme
UI.success "Theme uploaded (id:#{theme_id})"
UI.info "Preview: #{client.root}/?preview_theme_id=#{theme_id}"
if client.is_theme_creator
UI.info "Manage: #{client.root}/my/themes"
else
UI.info "Manage: #{client.root}/admin/customize/themes/#{theme_id}"
end
elsif command == "rspec"
DiscourseTheme::CliCommands::Rspec.run(
settings: config[dir.split("/spec")[0]],
dir: dir,
args: args,
reset: reset,
)
else
usage
end
UI.progress "Exiting..."
rescue DiscourseTheme::ThemeError => e
UI.error "#{e.message}"
rescue Interrupt, TTY::Reader::InputInterrupt => e
UI.error "Interrupted"
end
|