Witam w ostatniej części tego miniporadnika nt. przygotowania kodu dla mniej fajnych klientów ;)
W tej części zajmiemy się wyczyszczeniem plików rb z oryginalnych komentarzy oraz "zamieszaniem" w tychże plikach. Uruchomimy także całą resztę kodu, tak aby wszystko ładnie funkcjonowało.
A więc do dzieła!
Zacznijmy od metody która usunie nam wszystkie linijki komentarzy, ze wszystkich możliwych plików.
Metoda jest całkiem prosta. Otwieramy plik rb i usuwamy wszystkie linijki zaczynające się na "#", za wyjątkiem magicznego # coding: utf-8. Najpierw otwieramy plik do odczytu, kopiujemy linijka po linijce. Następnie otwieramy plik do zapisu (co automatycznie go wyczyści) a następnie zapisujemy tylko te linijki które nie są komentarzami. Przy okazji uważamy na #{ które nie jest komentarzem ale mogło zostać za takowy uznane.
Usuwamy także puste linijki i pozbywamy się wcięć.
# Usuwa komentarze (ale nie maskuje - tylko komentarze i białe znaki) z kodu def self.clean(path = './deploy/') Find.find(path) { |f| # Jeśli to nie plik rb to idz do nastepnego pliku next unless f[f.size-3, f.size-1] == '.rb' filename = f # Wrzuć info na konsole co sie dzieje puts "Cleaning #{filename}" lines = [] File.open(filename, "r").each_line {|l| lines << l } File.open(filename, 'w') {|f| lines.each { |l| a = l.strip # Jeśli to komentarz to przeskocz dalej next if (a[0] == "\#" && a != '# coding: utf-8' && a[0,2] != "\#\{") || a.size == 0 f.write(a+"\n") } } } end
Po przepuszczeniu naszego "deploy" przez ten kod, otrzymamy pliki które nie mają ani komentarzy ani też wcięć.
Pozostało nam jeszcze losowo "nabałaganić" w plikach i spiąć deploy.rb w jedną sensowną całość. Może najpierw pobałaganimy ;)
Po pierwsze, maskowanie powinno dotyczyć tylko i wyłącznie plików .rb, stąd poniższa linijka, która powoduje że kod nie zostanie wykonany dla plików o innych rozszerzeniach:
next unless f[f.size-3, f.size-1] == '.rb'
Dalej jest kawałek kodu, analogiczny do tego z metody czyszczącej komentarze. Ładujemy zawartość pliku do pamięci, po czym czyścimy go i otwieramy do zapisu. Bałaganimy generując losowo od 0 do 64 linijek z losowymi ciągami lub losowymi fragmentami kodu oraz z losową ilością spacji na początku każdej linijki.
Jedyna rzecz na jaką musimy uwazać to polecenia które składają się z wielu linijek, a w których nie można umieszczać komentarzy (np. wielolinijkowe stringi). Rozwiązałem to stosunkowo prosto. Zliczam po prostu liczbę otwarć cudzysłowów i jeśli nie jest parzysta, tzn że kod jest wielolinijkowy. Do czasu aż znajdę następną linijkę z ilością nieparzystą (co oznaczać będzie domknięcie), nie wstawiam śmieci. Śmieci też wstawiam na początku i końcu każdego pliku.
def self.mask(path) rand = Randomer.new Find.find(path) { |f| # Jeśli to nie plik rb to idz do nastepnego pliku next unless f[f.size-3, f.size-1] == '.rb' filename = f # Wrzuć info na konsole co sie dzieje puts "Masking: #{filename}" lines = [] File.open(filename, "r").each_line {|l| lines << l } File.open(filename, 'w') {|f| # Czy wyrazenie jest wieloliniowe (nie wsadza w takie komentów) multiline = false i = 0 lines.each { |l| a = l.strip # Jeśli to komentarz to przeskocz dalej next if (a[0] == "\#" && a != '# coding: utf-8' && a[0,2] != "\#\{") || a.size == 0 if a == '# coding: utf-8' f.write(a+"\n") rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } else rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } if i == 0 line = (multiline ? '' : rand.class.spaces) + a + "\n" multiline = !multiline if line.count('"') % 2 == 1 multiline = !multiline if line.count("'") % 2 == 1 f.write(line) end (rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") }) unless multiline i+=1 } rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } } } end
Całość opakowujemy w klasę:
# Maskuje pliki rb z podanego katalogu class Masker def self.mask(path) rand = Randomer.new Find.find(path) { |f| # Jeśli to nie plik rb to idz do nastepnego pliku next unless f[f.size-3, f.size-1] == '.rb' filename = f # Wrzuć info na konsole co sie dzieje puts "Masking: #{filename}" lines = [] File.open(filename, "r").each_line {|l| lines << l } File.open(filename, 'w') {|f| # Czy wyrazenie jest wieloliniowe (nie wsadza w takie komentów) multiline = false i = 0 lines.each { |l| a = l.strip # Jeśli to komentarz to przeskocz dalej next if (a[0] == "\#" && a != '# coding: utf-8' && a[0,2] != "\#\{") || a.size == 0 if a == '# coding: utf-8' f.write(a+"\n") rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } else rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } if i == 0 line = (multiline ? '' : rand.class.spaces) + a + "\n" multiline = !multiline if line.count('"') % 2 == 1 multiline = !multiline if line.count("'") % 2 == 1 f.write(line) end (rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") }) unless multiline i+=1 } rand(64).times { f.write(rand.class.spaces+'# '+rand.line+"\n") } } } end # Usuwa komentarze (ale nie maskuje - tylko komentarze i białe znaki) z kodu def self.clean(path = './deploy/') Find.find(path) { |f| # Jeśli to nie plik rb to idz do nastepnego pliku next unless f[f.size-3, f.size-1] == '.rb' filename = f # Wrzuć info na konsole co sie dzieje puts "Cleaning #{filename}" lines = [] File.open(filename, "r").each_line {|l| lines << l } File.open(filename, 'w') {|f| lines.each { |l| a = l.strip # Jeśli to komentarz to przeskocz dalej next if (a[0] == "\#" && a != '# coding: utf-8' && a[0,2] != "\#\{") || a.size == 0 f.write(a+"\n") } } } end end
Po czym odpalamy całość kodu napisanego przez 3 części tutoriala:
# Zrób kopię zapasową do której robimy deploy Backuper.run # Usuń co niepotrzebne w deployu Cleaner.run # Wyczysc komentarze z calosci plikow Masker.clean # I zamaskuj reszte kodu MASK_DIRS.each {|d| Masker.mask(d)}
Po tych operacjach otrzymujemy kod który:
- Nie zawiera elementów niepotrzebnych klientowi
- Nie zawiera plików tymczasowych
- Jest "niemiły" dla użyszkodników
To by było na tyle. Używajcie tego ilekroć macie klientów których niekoniecznie darzycie zaufaniem.
Sprawdź także pozostałe dwie części tutoriala:
Leave a Reply