neocities 0.0.17 → 0.0.19
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/Gemfile +4 -0
- data/lib/neocities/cli.rb +92 -22
- data/lib/neocities/client.rb +86 -2
- data/lib/neocities/version.rb +1 -1
- metadata +15 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5baf997b1c58eaf0d7b2c7487623ab49966d72f0a637b0bbf32111a0608ad12
|
4
|
+
data.tar.gz: 16b8cf7786e0cf714f41f00e49bb97038ffaf1de1c72ba656e0223b9a3c9aa15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1459d3bff5633233a3968a4fab5033df7b8048435786e5c2642aa5fe4123061ed69f957e186cff1c0f9ba45b0249e188c21a96a56b80df87bacd1cd3532727c
|
7
|
+
data.tar.gz: 64eeed0bbf5fe5381d2eb8d9641cd00832a4be0369e32ad3da4a4ab9544976c4f8574c40274a6a3f64b1146259939fd21e71533628143c0562241735e0bce112
|
data/Gemfile
CHANGED
data/lib/neocities/cli.rb
CHANGED
@@ -3,11 +3,14 @@ require 'pastel'
|
|
3
3
|
require 'tty/table'
|
4
4
|
require 'tty/prompt'
|
5
5
|
require 'fileutils'
|
6
|
+
require 'json' # for reading configs
|
7
|
+
require 'whirly' # for loader spinner
|
8
|
+
|
6
9
|
require File.join(File.dirname(__FILE__), 'client')
|
7
10
|
|
8
11
|
module Neocities
|
9
12
|
class CLI
|
10
|
-
SUBCOMMANDS = %w{upload delete list info push logout pizza}
|
13
|
+
SUBCOMMANDS = %w{upload delete list info push logout pizza pull}
|
11
14
|
HELP_SUBCOMMANDS = ['-h', '--help', 'help']
|
12
15
|
PENELOPE_MOUTHS = %w{^ o ~ - v U}
|
13
16
|
PENELOPE_EYES = %w{o ~ O}
|
@@ -19,7 +22,7 @@ module Neocities
|
|
19
22
|
@subargs = @argv[1..@argv.length]
|
20
23
|
@prompt = TTY::Prompt.new
|
21
24
|
@api_key = ENV['NEOCITIES_API_KEY'] || nil
|
22
|
-
@app_config_path = File.join self.class.app_config_path('neocities'), 'config'
|
25
|
+
@app_config_path = File.join self.class.app_config_path('neocities'), 'config.json' # added json extension
|
23
26
|
end
|
24
27
|
|
25
28
|
def display_response(resp)
|
@@ -42,16 +45,28 @@ module Neocities
|
|
42
45
|
exit
|
43
46
|
end
|
44
47
|
|
45
|
-
|
46
|
-
|
48
|
+
if HELP_SUBCOMMANDS.include?(@subcmd) && SUBCOMMANDS.include?(@subargs[0])
|
49
|
+
send "display_#{@subargs[0]}_help_and_exit"
|
50
|
+
elsif @subcmd.nil? || !SUBCOMMANDS.include?(@subcmd)
|
51
|
+
display_help_and_exit
|
52
|
+
elsif @subargs.join("").match(HELP_SUBCOMMANDS.join('|')) && @subcmd != "info"
|
53
|
+
send "display_#{@subcmd}_help_and_exit"
|
54
|
+
end
|
47
55
|
|
48
56
|
if !@api_key
|
49
57
|
begin
|
50
|
-
|
58
|
+
file = File.read @app_config_path
|
59
|
+
data = JSON.load file
|
60
|
+
|
61
|
+
if data
|
62
|
+
@api_key = data["API_KEY"].strip # Remove any trailing whitespace causing HTTP requests to fail
|
63
|
+
@sitename = data["SITENAME"] # Store the sitename to be able to reference it later
|
64
|
+
@last_pull = data["LAST_PULL"] # Store the last time a pull was performed so that we only fetch from updated files
|
65
|
+
end
|
51
66
|
rescue Errno::ENOENT
|
52
67
|
@api_key = nil
|
53
68
|
end
|
54
|
-
end
|
69
|
+
end
|
55
70
|
|
56
71
|
if @api_key.nil?
|
57
72
|
puts "Please login to get your API key:"
|
@@ -65,8 +80,14 @@ module Neocities
|
|
65
80
|
|
66
81
|
resp = @client.key
|
67
82
|
if resp[:api_key]
|
83
|
+
conf = {
|
84
|
+
"API_KEY": resp[:api_key],
|
85
|
+
"SITENAME": @sitename,
|
86
|
+
}
|
87
|
+
|
68
88
|
FileUtils.mkdir_p Pathname(@app_config_path).dirname
|
69
|
-
File.write @app_config_path,
|
89
|
+
File.write @app_config_path, conf.to_json
|
90
|
+
|
70
91
|
puts "The api key for #{@pastel.bold @sitename} has been stored in #{@pastel.bold @app_config_path}."
|
71
92
|
else
|
72
93
|
display_response resp
|
@@ -80,6 +101,7 @@ module Neocities
|
|
80
101
|
end
|
81
102
|
|
82
103
|
def delete
|
104
|
+
display_delete_help_and_exit if @subargs.empty?
|
83
105
|
@subargs.each do |file|
|
84
106
|
puts @pastel.bold("Deleting #{file} ...")
|
85
107
|
resp = @client.delete file
|
@@ -90,16 +112,18 @@ module Neocities
|
|
90
112
|
|
91
113
|
def logout
|
92
114
|
confirmed = false
|
93
|
-
loop
|
115
|
+
loop do
|
94
116
|
case @subargs[0]
|
95
117
|
when '-y' then @subargs.shift; confirmed = true
|
96
|
-
when /^-/ then puts(@pastel.red.bold("Unknown option: #{@subargs[0].inspect}"));
|
118
|
+
when /^-/ then puts(@pastel.red.bold("Unknown option: #{@subargs[0].inspect}")); break
|
97
119
|
else break
|
98
120
|
end
|
99
|
-
|
121
|
+
end
|
100
122
|
if confirmed
|
101
123
|
FileUtils.rm @app_config_path
|
102
124
|
puts @pastel.bold("Your api key has been removed.")
|
125
|
+
else
|
126
|
+
display_logout_help_and_exit
|
103
127
|
end
|
104
128
|
end
|
105
129
|
|
@@ -113,7 +137,7 @@ module Neocities
|
|
113
137
|
|
114
138
|
out = []
|
115
139
|
|
116
|
-
resp[:info].each do |k,v|
|
140
|
+
resp[:info].each do |k, v|
|
117
141
|
v = Time.parse(v).localtime if v && (k == :created_at || k == :last_updated)
|
118
142
|
out.push [@pastel.bold(k), v]
|
119
143
|
end
|
@@ -123,6 +147,7 @@ module Neocities
|
|
123
147
|
end
|
124
148
|
|
125
149
|
def list
|
150
|
+
display_list_help_and_exit if @subargs.empty?
|
126
151
|
if @subargs.delete('-d') == '-d'
|
127
152
|
@detail = true
|
128
153
|
end
|
@@ -159,11 +184,12 @@ module Neocities
|
|
159
184
|
end
|
160
185
|
|
161
186
|
def push
|
187
|
+
display_push_help_and_exit if @subargs.empty?
|
162
188
|
@no_gitignore = false
|
163
189
|
@excluded_files = []
|
164
190
|
@dry_run = false
|
165
191
|
@prune = false
|
166
|
-
loop
|
192
|
+
loop do
|
167
193
|
case @subargs[0]
|
168
194
|
when '--no-gitignore' then @subargs.shift; @no_gitignore = true
|
169
195
|
when '-e' then @subargs.shift; @excluded_files.push(@subargs.shift)
|
@@ -172,7 +198,7 @@ module Neocities
|
|
172
198
|
when /^-/ then puts(@pastel.red.bold("Unknown option: #{@subargs[0].inspect}")); display_push_help_and_exit
|
173
199
|
else break
|
174
200
|
end
|
175
|
-
|
201
|
+
end
|
176
202
|
|
177
203
|
if @dry_run
|
178
204
|
puts @pastel.green.bold("Doing a dry run, not actually pushing anything")
|
@@ -213,7 +239,7 @@ module Neocities
|
|
213
239
|
end
|
214
240
|
|
215
241
|
Dir.chdir(root_path) do
|
216
|
-
paths = Dir.glob(File.join('**', '*'))
|
242
|
+
paths = Dir.glob(File.join('**', '*'), File::FNM_DOTMATCH)
|
217
243
|
|
218
244
|
if @no_gitignore == false
|
219
245
|
begin
|
@@ -235,13 +261,11 @@ module Neocities
|
|
235
261
|
end
|
236
262
|
end
|
237
263
|
|
238
|
-
paths.select! {|p| !@excluded_files.include?(p)}
|
264
|
+
paths.select! { |p| !@excluded_files.include?(p) }
|
239
265
|
|
240
|
-
paths.select! {|p|
|
241
|
-
!@excluded_files.include?(Pathname.new(p).dirname.to_s)
|
242
|
-
}
|
266
|
+
paths.select! { |p| !@excluded_files.include?(Pathname.new(p).dirname.to_s) }
|
243
267
|
|
244
|
-
paths.collect! {|path| Pathname path}
|
268
|
+
paths.collect! { |path| Pathname path }
|
245
269
|
|
246
270
|
paths.each do |path|
|
247
271
|
next if path.directory?
|
@@ -264,13 +288,13 @@ module Neocities
|
|
264
288
|
display_upload_help_and_exit if @subargs.empty?
|
265
289
|
@dir = ''
|
266
290
|
|
267
|
-
loop
|
291
|
+
loop do
|
268
292
|
case @subargs[0]
|
269
293
|
when '-d' then @subargs.shift; @dir = @subargs.shift
|
270
294
|
when /^-/ then puts(@pastel.red.bold("Unknown option: #{@subargs[0].inspect}")); display_upload_help_and_exit
|
271
295
|
else break
|
272
296
|
end
|
273
|
-
|
297
|
+
end
|
274
298
|
|
275
299
|
@subargs.each do |path|
|
276
300
|
path = Pathname path
|
@@ -293,6 +317,39 @@ module Neocities
|
|
293
317
|
end
|
294
318
|
end
|
295
319
|
|
320
|
+
def pull
|
321
|
+
begin
|
322
|
+
quiet = !(['--log', '-l'].include? @subargs[0])
|
323
|
+
|
324
|
+
file = File.read @app_config_path
|
325
|
+
data = JSON.load file
|
326
|
+
|
327
|
+
last_pull_time = data["LAST_PULL"] ? data["LAST_PULL"]["time"] : nil
|
328
|
+
last_pull_loc = data["LAST_PULL"] ? data["LAST_PULL"]["loc"] : nil
|
329
|
+
|
330
|
+
Whirly.start spinner: ["😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"], status: "Retrieving files for #{@pastel.bold @sitename}" if quiet
|
331
|
+
resp = @client.pull @sitename, last_pull_time, last_pull_loc, quiet
|
332
|
+
|
333
|
+
# write last pull data to file (not necessarily the best way to do this, but better than cloning every time)
|
334
|
+
data["LAST_PULL"] = {
|
335
|
+
"time": Time.now,
|
336
|
+
"loc": Dir.pwd
|
337
|
+
}
|
338
|
+
|
339
|
+
File.write @app_config_path, data.to_json
|
340
|
+
rescue StandardError => ex
|
341
|
+
Whirly.stop if quiet
|
342
|
+
puts @pastel.red.bold "\nA fatal error occurred :-("
|
343
|
+
puts @pastel.red ex
|
344
|
+
ensure
|
345
|
+
exit
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def pizza
|
350
|
+
display_pizza_help_and_exit
|
351
|
+
end
|
352
|
+
|
296
353
|
def display_pizza_help_and_exit
|
297
354
|
puts "Sorry, we're fresh out of dough today. Try again tomorrow."
|
298
355
|
exit
|
@@ -346,6 +403,16 @@ HERE
|
|
346
403
|
|
347
404
|
#{@pastel.green '$ neocities upload -d images img.jpg'} Upload img.jpg to the 'images' directory on your site
|
348
405
|
|
406
|
+
HERE
|
407
|
+
exit
|
408
|
+
end
|
409
|
+
|
410
|
+
def display_pull_help_and_exit
|
411
|
+
display_banner
|
412
|
+
|
413
|
+
puts <<HERE
|
414
|
+
#{@pastel.magenta.bold 'pull'} - Get the most recent version of files from your site
|
415
|
+
|
349
416
|
HERE
|
350
417
|
exit
|
351
418
|
end
|
@@ -366,6 +433,8 @@ HERE
|
|
366
433
|
|
367
434
|
#{@pastel.green '$ neocities push --dry-run .'} Just show what would be uploaded
|
368
435
|
|
436
|
+
#{@pastel.green '$ neocities push --prune .'} Delete site files not in dir (be careful!)
|
437
|
+
|
369
438
|
HERE
|
370
439
|
exit
|
371
440
|
end
|
@@ -419,6 +488,7 @@ HERE
|
|
419
488
|
info Information and stats for your site
|
420
489
|
logout Remove the site api key from the config
|
421
490
|
version Unceremoniously display version and self destruct
|
491
|
+
pull Get the most recent version of files from your site
|
422
492
|
pizza Order a free pizza
|
423
493
|
|
424
494
|
HERE
|
@@ -464,4 +534,4 @@ HERE
|
|
464
534
|
end
|
465
535
|
end
|
466
536
|
end
|
467
|
-
end
|
537
|
+
end
|
data/lib/neocities/client.rb
CHANGED
@@ -8,6 +8,10 @@ require 'pathname'
|
|
8
8
|
require 'uri'
|
9
9
|
require 'digest'
|
10
10
|
require 'httpclient'
|
11
|
+
require 'pastel'
|
12
|
+
require 'date'
|
13
|
+
|
14
|
+
require 'whirly'
|
11
15
|
|
12
16
|
module Neocities
|
13
17
|
class Client
|
@@ -17,6 +21,7 @@ module Neocities
|
|
17
21
|
@uri = URI.parse API_URI
|
18
22
|
@http = HTTPClient.new force_basic_auth: true
|
19
23
|
@opts = opts
|
24
|
+
@pastel = Pastel.new eachline: "\n"
|
20
25
|
|
21
26
|
unless opts[:api_key] || (opts[:sitename] && opts[:password])
|
22
27
|
raise ArgumentError, 'client requires a login (sitename/password) or an api_key'
|
@@ -27,13 +32,91 @@ module Neocities
|
|
27
32
|
else
|
28
33
|
@http.set_auth API_URI, opts[:sitename], opts[:password]
|
29
34
|
end
|
30
|
-
|
31
35
|
end
|
32
36
|
|
33
37
|
def list(path=nil)
|
34
38
|
get 'list', :path => path
|
35
39
|
end
|
36
40
|
|
41
|
+
def pull(sitename, last_pull_time=nil, last_pull_loc=nil, quiet=true)
|
42
|
+
site_info = get 'info', sitename: sitename
|
43
|
+
|
44
|
+
if site_info[:result] == 'error'
|
45
|
+
raise ArgumentError, site_info[:message]
|
46
|
+
end
|
47
|
+
|
48
|
+
# handle custom domains for supporter accounts
|
49
|
+
if site_info[:info][:domain] && site_info[:info][:domain] != ""
|
50
|
+
domain = "https://#{site_info[:info][:domain]}/"
|
51
|
+
else
|
52
|
+
domain = "https://#{sitename}.neocities.org/"
|
53
|
+
end
|
54
|
+
|
55
|
+
# start stats
|
56
|
+
success_loaded = 0
|
57
|
+
start_time = Time.now
|
58
|
+
curr_dir = Dir.pwd
|
59
|
+
|
60
|
+
# get list of files
|
61
|
+
resp = get 'list'
|
62
|
+
|
63
|
+
if resp[:result] == 'error'
|
64
|
+
raise ArgumentError, resp[:message]
|
65
|
+
end
|
66
|
+
|
67
|
+
# fetch each file
|
68
|
+
resp[:files].each do |file|
|
69
|
+
if !file[:is_directory]
|
70
|
+
print @pastel.bold("Loading #{file[:path]} ... ") if !quiet
|
71
|
+
|
72
|
+
if
|
73
|
+
last_pull_time && \
|
74
|
+
last_pull_loc && \
|
75
|
+
Time.parse(file[:updated_at]) <= Time.parse(last_pull_time) && \
|
76
|
+
last_pull_loc == curr_dir && \
|
77
|
+
File.exist?(file[:path]) # case when user deletes file
|
78
|
+
# case when file hasn't been updated since last
|
79
|
+
print "#{@pastel.yellow.bold "NO NEW UPDATES"}\n" if !quiet
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
pathtotry = domain + file[:path]
|
84
|
+
fileconts = @http.get pathtotry
|
85
|
+
|
86
|
+
# follow redirects
|
87
|
+
while fileconts.status == 301
|
88
|
+
new_path = fileconts.header['location'][0]
|
89
|
+
print "\n#{@pastel.red "Fetch from #{pathtotry} failed."}\nTrying #{new_path} instead..." if !quiet
|
90
|
+
|
91
|
+
pathtotry = new_path
|
92
|
+
fileconts = @http.get pathtotry
|
93
|
+
end
|
94
|
+
|
95
|
+
if fileconts.ok?
|
96
|
+
print "#{@pastel.green.bold 'SUCCESS'}\n" if !quiet
|
97
|
+
success_loaded += 1
|
98
|
+
|
99
|
+
File.open("#{file[:path]}", "w") do |f|
|
100
|
+
f.write(fileconts.body)
|
101
|
+
end
|
102
|
+
else
|
103
|
+
print "#{@pastel.red.bold 'FAIL'}\n" if !quiet
|
104
|
+
end
|
105
|
+
else
|
106
|
+
FileUtils.mkdir_p "#{file[:path]}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# calculate time command took
|
111
|
+
total_time = Time.now - start_time
|
112
|
+
|
113
|
+
# stop the spinner, if there is one
|
114
|
+
Whirly.stop if quiet
|
115
|
+
|
116
|
+
# display stats
|
117
|
+
puts @pastel.green "\nSuccessfully fetched #{success_loaded} files in #{total_time} seconds"
|
118
|
+
end
|
119
|
+
|
37
120
|
def key
|
38
121
|
get 'key'
|
39
122
|
end
|
@@ -86,6 +169,7 @@ module Neocities
|
|
86
169
|
uri = @uri+path
|
87
170
|
uri.query = URI.encode_www_form params
|
88
171
|
resp = @http.get uri
|
172
|
+
|
89
173
|
JSON.parse resp.body, symbolize_names: true
|
90
174
|
end
|
91
175
|
|
@@ -95,4 +179,4 @@ module Neocities
|
|
95
179
|
JSON.parse resp.body, symbolize_names: true
|
96
180
|
end
|
97
181
|
end
|
98
|
-
end
|
182
|
+
end
|
data/lib/neocities/version.rb
CHANGED
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neocities
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kyle Drake
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-table
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - '='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.10.0
|
20
17
|
- - "~>"
|
21
18
|
- !ruby/object:Gem::Version
|
22
19
|
version: '0.10'
|
20
|
+
- - '='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.10.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - '='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.10.0
|
30
27
|
- - "~>"
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: '0.10'
|
30
|
+
- - '='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.10.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: tty-prompt
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - '='
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: 0.12.0
|
40
37
|
- - "~>"
|
41
38
|
- !ruby/object:Gem::Version
|
42
39
|
version: '0.12'
|
40
|
+
- - '='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.12.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - '='
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
version: 0.12.0
|
50
47
|
- - "~>"
|
51
48
|
- !ruby/object:Gem::Version
|
52
49
|
version: '0.12'
|
50
|
+
- - '='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.12.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: pastel
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -148,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
148
|
- !ruby/object:Gem::Version
|
149
149
|
version: '0'
|
150
150
|
requirements: []
|
151
|
-
rubygems_version: 3.
|
151
|
+
rubygems_version: 3.5.13
|
152
152
|
signing_key:
|
153
153
|
specification_version: 4
|
154
154
|
summary: Neocities.org CLI and API client
|