neocities-red 1.1.0 → 1.1.2

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -32
  3. data/.github/PULL_REQUEST_TEMPLATE.md +18 -18
  4. data/.github/dependabot.yml +6 -6
  5. data/.github/workflows/ci.yml +139 -139
  6. data/.gitignore +38 -38
  7. data/.rspec +3 -3
  8. data/.rubocop.yml +43 -43
  9. data/CODE_OF_CONDUCT.md +128 -128
  10. data/CONTRIBUTING.md +83 -83
  11. data/Gemfile +12 -12
  12. data/Gemfile.lock +194 -193
  13. data/LICENSE +21 -21
  14. data/README.md +153 -153
  15. data/SECURITY.md +7 -7
  16. data/bin/neocities-red +9 -9
  17. data/ext/mkrf_conf.rb +21 -21
  18. data/lib/neocities_red/cli.rb +340 -335
  19. data/lib/neocities_red/cli_display.rb +281 -271
  20. data/lib/neocities_red/client.rb +200 -200
  21. data/lib/neocities_red/services/common/pizza.rb +107 -107
  22. data/lib/neocities_red/services/file/folder_uploader.rb +65 -65
  23. data/lib/neocities_red/services/file/list.rb +65 -65
  24. data/lib/neocities_red/services/file/remover.rb +35 -35
  25. data/lib/neocities_red/services/file/uploader.rb +45 -45
  26. data/lib/neocities_red/services/site/differencer.rb +76 -76
  27. data/lib/neocities_red/services/site/exporter.rb +43 -43
  28. data/lib/neocities_red/services/site/informer.rb +43 -43
  29. data/lib/neocities_red/services/site/pusher.rb +146 -146
  30. data/lib/neocities_red/version.rb +5 -5
  31. data/lib/neocities_red.rb +17 -17
  32. data/neocities-red.gemspec +54 -54
  33. data/spec/neocities_red/cli_display_spec.rb +139 -139
  34. data/spec/neocities_red/cli_spec.rb +68 -68
  35. data/spec/neocities_red/client_spec.rb +306 -306
  36. data/spec/neocities_red/services/common/pizza_spec.rb +26 -26
  37. data/spec/neocities_red/services/file/folder_uploader_spec.rb +64 -64
  38. data/spec/neocities_red/services/file/list_spec.rb +177 -177
  39. data/spec/neocities_red/services/file/remover_spec.rb +125 -125
  40. data/spec/neocities_red/services/file/uploader_spec.rb +158 -158
  41. data/spec/neocities_red/services/site/differencer_spec.rb +162 -162
  42. data/spec/neocities_red/services/site/exporter_spec.rb +116 -116
  43. data/spec/neocities_red/services/site/informer_spec.rb +180 -180
  44. data/spec/neocities_red/services/site/pusher_spec.rb +167 -167
  45. data/spec/spec_helper.rb +20 -20
  46. metadata +4 -10
@@ -1,65 +1,65 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "pastel"
5
-
6
- module NeocitiesRed
7
- module Services
8
- module File
9
- # warning - the big quantity of working threads could be considered like-a DDOS.
10
- # Your ip-address could get banned for a few days.
11
- MAX_THREADS = 5
12
-
13
- class FolderUploader
14
- def initialize(client, filepath, remote_path)
15
- @client = client
16
- @filepath = filepath
17
- @remote_path = remote_path
18
- @pastel = Pastel.new(eachline: "\n")
19
- end
20
-
21
- def files
22
- path = Pathname.new(::File.expand_path(@filepath))
23
-
24
- raise FileIsNotExists, "#{path} does not exist locally." unless path.exist?
25
-
26
- if path.file?
27
- puts @pastel.bold("#{path} is not a directory, skipping")
28
- return
29
- end
30
-
31
- Dir.chdir(path) do
32
- Dir.glob("**/*", ::File::FNM_DOTMATCH)
33
- .select { |f| ::File.file?(f) }
34
- end
35
- end
36
-
37
- def upload(files_list, threads = MAX_THREADS)
38
- base = ::File.expand_path(@filepath)
39
-
40
- queue = Queue.new
41
- files_list.each { |file| queue << file }
42
-
43
- workers = Array.new(threads) do
44
- Thread.new do
45
- loop do
46
- begin
47
- file = queue.pop(true)
48
- rescue ThreadError
49
- break
50
- end
51
-
52
- local_path = ::File.join(base, file)
53
- remote_path = ::File.join(@remote_path, file)
54
-
55
- Uploader.new(@client, local_path, remote_path).upload
56
- end
57
- end
58
- end
59
-
60
- workers.each(&:join)
61
- end
62
- end
63
- end
64
- end
65
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "pastel"
5
+
6
+ module NeocitiesRed
7
+ module Services
8
+ module File
9
+ # warning - the big quantity of working threads could be considered like-a DDOS.
10
+ # Your ip-address could get banned for a few days.
11
+ MAX_THREADS = 5
12
+
13
+ class FolderUploader
14
+ def initialize(client, filepath, remote_path)
15
+ @client = client
16
+ @filepath = filepath
17
+ @remote_path = remote_path
18
+ @pastel = Pastel.new(eachline: "\n")
19
+ end
20
+
21
+ def files
22
+ path = Pathname.new(::File.expand_path(@filepath))
23
+
24
+ raise FileIsNotExists, "#{path} does not exist locally." unless path.exist?
25
+
26
+ if path.file?
27
+ puts @pastel.bold("#{path} is not a directory, skipping")
28
+ return
29
+ end
30
+
31
+ Dir.chdir(path) do
32
+ Dir.glob("**/*", ::File::FNM_DOTMATCH)
33
+ .select { |f| ::File.file?(f) }
34
+ end
35
+ end
36
+
37
+ def upload(files_list, threads = MAX_THREADS)
38
+ base = ::File.expand_path(@filepath)
39
+
40
+ queue = Queue.new
41
+ files_list.each { |file| queue << file }
42
+
43
+ workers = Array.new(threads) do
44
+ Thread.new do
45
+ loop do
46
+ begin
47
+ file = queue.pop(true)
48
+ rescue ThreadError
49
+ break
50
+ end
51
+
52
+ local_path = ::File.join(base, file)
53
+ remote_path = ::File.join(@remote_path, file)
54
+
55
+ Uploader.new(@client, local_path, remote_path).upload
56
+ end
57
+ end
58
+ end
59
+
60
+ workers.each(&:join)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,65 +1,65 @@
1
- # frozen_string_literal: true
2
-
3
- require "pastel"
4
- require "time"
5
- require "tty/table"
6
-
7
- module NeocitiesRed
8
- module Services
9
- module File
10
- class List
11
- def initialize(client, path, detail)
12
- @client = client
13
- @path = path
14
- @detail = detail || false
15
- @pastel = Pastel.new(eachline: "\n")
16
- end
17
-
18
- def list
19
- resp = @client.list(@path)
20
-
21
- display_error_and_exit(resp) if resp[:result] == "error"
22
-
23
- resp[:files]
24
- end
25
-
26
- def show
27
- resp = @client.list(@path)
28
-
29
- display_error_and_exit(resp) if resp[:result] == "error"
30
-
31
- if @detail
32
- out = [
33
- [@pastel.bold("Path"), @pastel.bold("Size"), @pastel.bold("sha1_Hash"),
34
- @pastel.bold("Updated")]
35
- ]
36
-
37
- resp[:files].each do |file|
38
- out.push([
39
- @pastel.send(file[:is_directory] ? :blue : :green).bold(file[:path]),
40
- file[:size] || "",
41
- file[:sha1_hash],
42
- Time.parse(file[:updated_at]).localtime
43
- ])
44
- end
45
-
46
- puts TTY::Table.new(out)
47
- end
48
-
49
- resp[:files].map do |file|
50
- @pastel.send(file[:is_directory] ? :blue : :green).bold(file[:path])
51
- end
52
-
53
- resp[:files]
54
- end
55
-
56
- private
57
-
58
- def display_error_and_exit(resp)
59
- puts(resp[:message] || resp[:error_type] || resp.inspect)
60
- exit
61
- end
62
- end
63
- end
64
- end
65
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "pastel"
4
+ require "time"
5
+ require "tty/table"
6
+
7
+ module NeocitiesRed
8
+ module Services
9
+ module File
10
+ class List
11
+ def initialize(client, path, detail)
12
+ @client = client
13
+ @path = path
14
+ @detail = detail || false
15
+ @pastel = Pastel.new(eachline: "\n")
16
+ end
17
+
18
+ def list
19
+ resp = @client.list(@path)
20
+
21
+ display_error_and_exit(resp) if resp[:result] == "error"
22
+
23
+ resp[:files]
24
+ end
25
+
26
+ def show
27
+ resp = @client.list(@path)
28
+
29
+ display_error_and_exit(resp) if resp[:result] == "error"
30
+
31
+ if @detail
32
+ out = [
33
+ [@pastel.bold("Path"), @pastel.bold("Size"), @pastel.bold("sha1_Hash"),
34
+ @pastel.bold("Updated")]
35
+ ]
36
+
37
+ resp[:files].each do |file|
38
+ out.push([
39
+ @pastel.send(file[:is_directory] ? :blue : :green).bold(file[:path]),
40
+ file[:size] || "",
41
+ file[:sha1_hash],
42
+ Time.parse(file[:updated_at]).localtime
43
+ ])
44
+ end
45
+
46
+ puts TTY::Table.new(out)
47
+ end
48
+
49
+ resp[:files].map do |file|
50
+ @pastel.send(file[:is_directory] ? :blue : :green).bold(file[:path])
51
+ end
52
+
53
+ resp[:files]
54
+ end
55
+
56
+ private
57
+
58
+ def display_error_and_exit(resp)
59
+ puts(resp[:message] || resp[:error_type] || resp.inspect)
60
+ exit
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,35 +1,35 @@
1
- # frozen_string_literal: true
2
-
3
- require "pastel"
4
-
5
- module NeocitiesRed
6
- module Services
7
- module File
8
- class Remover
9
- attr_accessor :client, :filepath
10
-
11
- def initialize(client, filepath)
12
- @client = client
13
- @filepath = filepath
14
- @pastel = Pastel.new(eachline: "\n")
15
- end
16
-
17
- def remove
18
- puts @pastel.bold("Deleting #{filepath} ...")
19
-
20
- response = @client.delete(filepath)
21
-
22
- puts @pastel.bold(response[:message]) if response[:result] == "error"
23
-
24
- if response[:result] == "error" && response[:error_type] == "file_exists"
25
- print @pastel.yellow.bold("EXISTS")
26
- elsif response[:result] == "success"
27
- print @pastel.green.bold("SUCCESS")
28
- end
29
-
30
- response
31
- end
32
- end
33
- end
34
- end
35
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "pastel"
4
+
5
+ module NeocitiesRed
6
+ module Services
7
+ module File
8
+ class Remover
9
+ attr_accessor :client, :filepath
10
+
11
+ def initialize(client, filepath)
12
+ @client = client
13
+ @filepath = filepath
14
+ @pastel = Pastel.new(eachline: "\n")
15
+ end
16
+
17
+ def remove
18
+ puts @pastel.bold("Deleting #{filepath} ...")
19
+
20
+ response = @client.delete(filepath)
21
+
22
+ puts @pastel.bold(response[:message]) if response[:result] == "error"
23
+
24
+ if response[:result] == "error" && response[:error_type] == "file_exists"
25
+ print @pastel.yellow.bold("EXISTS")
26
+ elsif response[:result] == "success"
27
+ print @pastel.green.bold("SUCCESS")
28
+ end
29
+
30
+ response
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,45 +1,45 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "pastel"
5
-
6
- module NeocitiesRed
7
- module Services
8
- module File
9
- class FileIsNotExists < StandardError; end
10
-
11
- class Uploader
12
- def initialize(client, filepath, remote_path = nil)
13
- @client = client
14
- @filepath = filepath
15
- @remote_path = remote_path
16
- @pastel = Pastel.new(eachline: "\n")
17
- end
18
-
19
- def upload
20
- path = Pathname.new(@filepath)
21
-
22
- raise FileIsNotExists, "#{path} does not exist locally." unless path.exist?
23
-
24
- if path.directory?
25
- puts @pastel.bold("#{path} is a directory, skipping")
26
- return
27
- end
28
-
29
- puts @pastel.bold("Uploading #{path} to #{@remote_path} ...")
30
-
31
- response = @client.upload(path, @remote_path)
32
- puts response if response[:result] == "error"
33
-
34
- if response[:result] == "error" && response[:error_type] == "file_exists"
35
- puts @pastel.yellow.bold("EXISTS")
36
- elsif response[:result] == "success"
37
- puts @pastel.green.bold("SUCCESS")
38
- end
39
-
40
- response
41
- end
42
- end
43
- end
44
- end
45
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "pastel"
5
+
6
+ module NeocitiesRed
7
+ module Services
8
+ module File
9
+ class FileIsNotExists < StandardError; end
10
+
11
+ class Uploader
12
+ def initialize(client, filepath, remote_path = nil)
13
+ @client = client
14
+ @filepath = filepath
15
+ @remote_path = remote_path
16
+ @pastel = Pastel.new(eachline: "\n")
17
+ end
18
+
19
+ def upload
20
+ path = Pathname.new(@filepath)
21
+
22
+ raise FileIsNotExists, "#{path} does not exist locally." unless path.exist?
23
+
24
+ if path.directory?
25
+ puts @pastel.bold("#{path} is a directory, skipping")
26
+ return
27
+ end
28
+
29
+ puts @pastel.bold("Uploading #{path} to #{@remote_path} ...")
30
+
31
+ response = @client.upload(path, @remote_path)
32
+ puts response if response[:result] == "error"
33
+
34
+ if response[:result] == "error" && response[:error_type] == "file_exists"
35
+ puts @pastel.yellow.bold("EXISTS")
36
+ elsif response[:result] == "success"
37
+ puts @pastel.green.bold("SUCCESS")
38
+ end
39
+
40
+ response
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,76 +1,76 @@
1
- # frozen_string_literal: true
2
-
3
- require "pastel"
4
- require "tty/table"
5
-
6
- module NeocitiesRed
7
- module Services
8
- module Site
9
- class Differencer
10
- def initialize(client, path: ".", detail: false, ignore_dotfiles: false, exclude: [])
11
- @client = client
12
- @path = path
13
- @detail = detail || false
14
- @ignore_dotfiles = ignore_dotfiles || false
15
- @exclude = exclude || []
16
- @pastel = Pastel.new(eachline: "\n")
17
- end
18
-
19
- def show
20
- server_files = Services::File::List.new(@client, nil, @detail).show
21
-
22
- root_path = Pathname(@path)
23
-
24
- added_paths = []
25
- removed_paths = []
26
- modified_paths = []
27
-
28
- Dir.chdir(root_path) do
29
- paths = Dir.glob(::File.join("**", "*"), ::File::FNM_DOTMATCH)
30
-
31
- local_paths = paths.reject { |path| path.start_with?(".") }
32
- local_files = local_paths.select { |path| ::File.file?(path) }.map do |path|
33
- {
34
- path: path,
35
- sha1_hash: Digest::SHA1.file(path).hexdigest
36
- }
37
- end
38
- server_paths = server_files.map { |n| n[:path] }
39
-
40
- server_file_map = server_files.to_h do |file|
41
- [file[:path], file[:sha1_hash]]
42
- end
43
-
44
- if @ignore_dotfiles
45
- server_paths = server_paths.reject { |path| path.start_with?(".") }
46
- local_paths = local_paths.reject { |path| path.start_with?(".") }
47
- end
48
-
49
- if @exclude.any?
50
- server_paths -= @exclude
51
- local_paths -= @exclude
52
- end
53
-
54
- removed_paths = server_paths - local_paths
55
- removed_paths.map! { |file| @pastel.red(file) }
56
-
57
- added_paths = local_paths - server_paths
58
- added_paths.map! { |file| @pastel.green(file) }
59
-
60
- modified_paths = local_files.select do |file|
61
- server_hash = server_file_map[file[:path]]
62
- server_hash && server_hash != file[:sha1_hash]
63
- end
64
- modified_paths.map! { |file| @pastel.yellow(file[:path]) }
65
- end
66
-
67
- [
68
- added_paths,
69
- modified_paths,
70
- removed_paths
71
- ]
72
- end
73
- end
74
- end
75
- end
76
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "pastel"
4
+ require "tty/table"
5
+
6
+ module NeocitiesRed
7
+ module Services
8
+ module Site
9
+ class Differencer
10
+ def initialize(client, path: ".", detail: false, ignore_dotfiles: false, exclude: [])
11
+ @client = client
12
+ @path = path
13
+ @detail = detail || false
14
+ @ignore_dotfiles = ignore_dotfiles || false
15
+ @exclude = exclude || []
16
+ @pastel = Pastel.new(eachline: "\n")
17
+ end
18
+
19
+ def show
20
+ server_files = Services::File::List.new(@client, nil, @detail).show
21
+
22
+ root_path = Pathname(@path)
23
+
24
+ added_paths = []
25
+ removed_paths = []
26
+ modified_paths = []
27
+
28
+ Dir.chdir(root_path) do
29
+ paths = Dir.glob(::File.join("**", "*"), ::File::FNM_DOTMATCH)
30
+
31
+ local_paths = paths.reject { |path| path.start_with?(".") }
32
+ local_files = local_paths.select { |path| ::File.file?(path) }.map do |path|
33
+ {
34
+ path: path,
35
+ sha1_hash: Digest::SHA1.file(path).hexdigest
36
+ }
37
+ end
38
+ server_paths = server_files.map { |n| n[:path] }
39
+
40
+ server_file_map = server_files.to_h do |file|
41
+ [file[:path], file[:sha1_hash]]
42
+ end
43
+
44
+ if @ignore_dotfiles
45
+ server_paths = server_paths.reject { |path| path.start_with?(".") }
46
+ local_paths = local_paths.reject { |path| path.start_with?(".") }
47
+ end
48
+
49
+ if @exclude.any?
50
+ server_paths -= @exclude
51
+ local_paths -= @exclude
52
+ end
53
+
54
+ removed_paths = server_paths - local_paths
55
+ removed_paths.map! { |file| @pastel.red(file) }
56
+
57
+ added_paths = local_paths - server_paths
58
+ added_paths.map! { |file| @pastel.green(file) }
59
+
60
+ modified_paths = local_files.select do |file|
61
+ server_hash = server_file_map[file[:path]]
62
+ server_hash && server_hash != file[:sha1_hash]
63
+ end
64
+ modified_paths.map! { |file| @pastel.yellow(file[:path]) }
65
+ end
66
+
67
+ [
68
+ added_paths,
69
+ modified_paths,
70
+ removed_paths
71
+ ]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,43 +1,43 @@
1
- # frozen_string_literal: true
2
-
3
- require "whirly"
4
- require "pastel"
5
-
6
- module NeocitiesRed
7
- module Services
8
- module Site
9
- class Exporter
10
- attr_accessor :client, :sitename, :data, :app_config_path
11
-
12
- def initialize(client, sitename, data, app_config_path)
13
- @client = client
14
- @sitename = sitename
15
- @data = data
16
- @app_config_path = app_config_path
17
- @pastel = Pastel.new(eachline: "\n")
18
- end
19
-
20
- def export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
21
- if quiet
22
- Whirly.start spinner: ["😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"],
23
- status: "Retrieving files for #{@pastel.bold @sitename}"
24
- end
25
-
26
- @client.pull(@sitename, last_pull_time, last_pull_loc, quiet: quiet)
27
-
28
- # write last pull data to file (not necessarily the best way to do this, but better than cloning every time)
29
- data["LAST_PULL"] = {
30
- time: Time.now,
31
- loc: Dir.pwd
32
- }
33
-
34
- File.write(app_config_path, data.to_json)
35
- rescue StandardError => e
36
- e
37
- ensure
38
- Whirly.stop if quiet
39
- end
40
- end
41
- end
42
- end
43
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "whirly"
4
+ require "pastel"
5
+
6
+ module NeocitiesRed
7
+ module Services
8
+ module Site
9
+ class Exporter
10
+ attr_accessor :client, :sitename, :data, :app_config_path
11
+
12
+ def initialize(client, sitename, data, app_config_path)
13
+ @client = client
14
+ @sitename = sitename
15
+ @data = data
16
+ @app_config_path = app_config_path
17
+ @pastel = Pastel.new(eachline: "\n")
18
+ end
19
+
20
+ def export(quiet: false, last_pull_time: nil, last_pull_loc: nil)
21
+ if quiet
22
+ Whirly.start spinner: ["😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"],
23
+ status: "Retrieving files for #{@pastel.bold @sitename}"
24
+ end
25
+
26
+ @client.pull(@sitename, last_pull_time, last_pull_loc, quiet: quiet)
27
+
28
+ # write last pull data to file (not necessarily the best way to do this, but better than cloning every time)
29
+ data["LAST_PULL"] = {
30
+ time: Time.now,
31
+ loc: Dir.pwd
32
+ }
33
+
34
+ File.write(app_config_path, data.to_json)
35
+ rescue StandardError => e
36
+ e
37
+ ensure
38
+ Whirly.stop if quiet
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end