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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -32
- data/.github/PULL_REQUEST_TEMPLATE.md +18 -18
- data/.github/dependabot.yml +6 -6
- data/.github/workflows/ci.yml +139 -139
- data/.gitignore +38 -38
- data/.rspec +3 -3
- data/.rubocop.yml +43 -43
- data/CODE_OF_CONDUCT.md +128 -128
- data/CONTRIBUTING.md +83 -83
- data/Gemfile +12 -12
- data/Gemfile.lock +194 -193
- data/LICENSE +21 -21
- data/README.md +153 -153
- data/SECURITY.md +7 -7
- data/bin/neocities-red +9 -9
- data/ext/mkrf_conf.rb +21 -21
- data/lib/neocities_red/cli.rb +340 -335
- data/lib/neocities_red/cli_display.rb +281 -271
- data/lib/neocities_red/client.rb +200 -200
- data/lib/neocities_red/services/common/pizza.rb +107 -107
- data/lib/neocities_red/services/file/folder_uploader.rb +65 -65
- data/lib/neocities_red/services/file/list.rb +65 -65
- data/lib/neocities_red/services/file/remover.rb +35 -35
- data/lib/neocities_red/services/file/uploader.rb +45 -45
- data/lib/neocities_red/services/site/differencer.rb +76 -76
- data/lib/neocities_red/services/site/exporter.rb +43 -43
- data/lib/neocities_red/services/site/informer.rb +43 -43
- data/lib/neocities_red/services/site/pusher.rb +146 -146
- data/lib/neocities_red/version.rb +5 -5
- data/lib/neocities_red.rb +17 -17
- data/neocities-red.gemspec +54 -54
- data/spec/neocities_red/cli_display_spec.rb +139 -139
- data/spec/neocities_red/cli_spec.rb +68 -68
- data/spec/neocities_red/client_spec.rb +306 -306
- data/spec/neocities_red/services/common/pizza_spec.rb +26 -26
- data/spec/neocities_red/services/file/folder_uploader_spec.rb +64 -64
- data/spec/neocities_red/services/file/list_spec.rb +177 -177
- data/spec/neocities_red/services/file/remover_spec.rb +125 -125
- data/spec/neocities_red/services/file/uploader_spec.rb +158 -158
- data/spec/neocities_red/services/site/differencer_spec.rb +162 -162
- data/spec/neocities_red/services/site/exporter_spec.rb +116 -116
- data/spec/neocities_red/services/site/informer_spec.rb +180 -180
- data/spec/neocities_red/services/site/pusher_spec.rb +167 -167
- data/spec/spec_helper.rb +20 -20
- 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
|