Skip to content

deconbatch/rls

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ruby 版 ls

  • Ruby の勉強を目的に ls コマンドを再発明

結果概要

成果物

  • doc
    • YARD 形式ドキュメント
  • test
    • テスト用スクリプトとテスト結果
  • README.org
    • この Readme
  • rls
    • Ruby を用いた ls コマンド
    • 下記オプションを実装
      • -a
      • -r
      • -l

開発環境

  • OS
    • CentOS Linux 7.6.1810
  • Ruby
    • ruby 2.6.3p62
  • ls のリファレンス実装
    • GNU coreutils version.8.22-21

気づいたものの実現不能だった事項

  • [ ] ロケール対応(メッセージ、日付フォーマット)
    • テストは LANG=C 固定で実施
  • [ ] ls -l の SELinux セキュリティコンテキスト表示(バーミッション直後のドット表示)
    ls -l /
    total 32
    lrwxrwxrwx    1 root root    7 Sep 28  2018 bin -> usr/bin
    dr-xr-xr-x.   5 root root 4096 May 23 21:24 boot
    パーミッションの後のドット
        
  • [ ] オリジナルの ls -l で同じファイルのカラム表示位置がずれる場合がある(テストケース case.03)
    • 表示対象ではないファイルのユーザ名等の長さがカラム幅に反映されている?
      $ ls -l test.case.03.sh
      -rwxr-xr-x 1 dec dec 501 Jul 10 23:56 test.case.03.sh
      
      $ ls -l test.case.03.sh /root
      -rwxr-xr-x  1 dec  dec   501 Jul 10 23:56 test.case.03.sh
      
      ls: cannot open directory /root: Permission denied
      
      $ ls -l test.case.03.sh /var/log/httpd/
      -rwxr-xr-x 1 dec  dec   501 Jul 10 23:56 test.case.03.sh
      
      $ ls: cannot open directory /var/log/httpd/: Permission denied
      
              
  • [ ] オリジナルの ls でパイプに通すとエラーメッセージが表示されなくなる場合がある(テストケース case.03)
    • 実行権限無しディレクトリ中にあるファイルを対象としたエラーメッセージだけ?
      パイプに通すとエラーメッセージが表示されなくなる例
      
      $ ls ./dir.not.executable/ ./not.exist      
      ls: cannot access ./not.exist: No such file or directory
      ./dir.not.executable/:
      ls: cannot access ./dir.not.executable/file01: Permission denied
      ls: cannot access ./dir.not.executable/file02: Permission denied
      file01  file02
      
      $ ls ./dir.not.executable/ ./not.exist | cat
      ls: cannot access ./not.exist: No such file or directory
      ./dir.not.executable/:
      file01
      file02
      
      同じパスで -l を付けるとパイプに通しても全てのエラーメッセージが表示される
      
      $ ls -l ./dir.not.executable/ ./not.exist      
      ls: cannot access ./not.exist: No such file or directory
      ./dir.not.executable/:
      ls: cannot access ./dir.not.executable/file01: Permission denied
      ls: cannot access ./dir.not.executable/file02: Permission denied
      total 0
      ?????????? ? ? ? ?            ? file01
      ?????????? ? ? ? ?            ? file02
      
      $ ls -l ./dir.not.executable/ ./not.exist | cat
      ls: cannot access ./not.exist: No such file or directory
      ls: cannot access ./dir.not.executable/file01: Permission denied
      ls: cannot access ./dir.not.executable/file02: Permission denied
      ./dir.not.executable/:
      total 0
      ?????????? ? ? ? ?            ? file01
      ?????????? ? ? ? ?            ? file02
      
              

テスト詳細

  • 思いついたケースを試してみたレベルです。プロダクションレベルのテストは実施できておりません。

テストケース

オプションのパース

  • [X] オプション無し :case.00:
  • [X] ‘-a’, ‘-l’, ‘-r’ それぞれを単体で指定 :case.01:
  • [X] ‘-al’ や ‘-alr’ などのように組み合わして指定 :case.00:
  • [X] パスの前後に指定 :case.00:
  • [X] ‘–’ の後に書いたオプションはパス扱いになること :case.00:
  • [X] ‘- a’ はパス扱いになること :case.00:

パスのパース

  • [X] パス無し :case.01:
  • [X] 単体で指定 :case.01:
  • [X] 複数指定 :case.01:

パス、ファイルの種類

  • [X] 相対パス :case.01:
  • [X] 絶対パス :case.01:
  • [X] ファイル :case.01:
  • [X] ディレクトリ、最後 / 無し :case.01:
  • [X] ディレクトリ、最後 / 有り :case.01:
  • [X] ディレクトリ/* :case.01:
  • [X] * :case.02:
  • [X] キャラクタデバイス、ブロックデバイス、fifo、ソケット、シンボリックリンク :case.04:
  • [X] 実行権限無しのディレクトリ :case.03:
  • [X] 実行権限無しのディレクトリ中のファイル :case.03:

-l オプション無しカラム表示

  • [X] パイプ、ファイルへの出力が 1カラムになること :case.01:
  • [X] 一行で画面幅に収まるパターン :case.05:
  • [X] 複数行にわたるパターン :case.05:
  • [X] 同じパス指定で画面幅を変更して行数が変更になるパターン :case.05:
  • [X] 最大ファイル名長が画面幅を超えるパターン :case.05:

-l オプションありリスト表示

  • [X] 日付 182日以上過去/未来は時刻ではなく年を表示 :case.01:
  • [X] スティッキービット、setuid、setgid の表示 :case.03:
  • [X] ディレクトリ中のシンボリックリンクの表示 :case.01:
  • [X] シンボリックリンク単体の表示 :case.04:
  • [X] ディレクトリ表示の場合に合計ブロック数表示 :case.01:
  • [X] ファイルのみの表示の場合には合計ブロック数表示無し :case.01:
  • [X] ファイル種類、パーミッション、ハードリンク数、ユーザ名、グループ名、サイズ、最終更新日、ファイル名の表示 :case.01:
  • [X] 複数ディレクトリ表示 :case.01:

-a 有無

  • [X] -a 有りと無しのパターン :case.00:case.01:

-r 有無

  • [X] -r 有りと無しのパターン :case.00:case.01:

エラー表示

  • [X] 上位ディレクトリに実行権限が無い場合の cannot access Permission denied エラー :case.03:
  • [X] 存在しないファイル、ディレクトリ時の cannot access No such file or directory エラー :case.03:
  • [X] パスに指定したディレクトリに読み込み権限が無い場合の cannot open directory Permission denied エラー :case.03:
  • [X] 存在するファイルと同名のパスを / 付きで指定した際の cannot access Not a directory エラー :case.03:

テスト結果

概要説明

  • test/ ディレクトリ以下にテストケース毎に別ディレクトリで格納
  • ls と rls の結果の diff を取るシェルスクリプトを作成し、diff の結果が無いことをテスト OK とする。
    • test.case.nn.sh テスト実行シェルスクリプト
    • results/
  • dif.err.* 標準エラー出力の差異
  • dif.out.* 標準出力の差異
  • ols.err.* オリジナルの ls の標準エラー出力
  • ols.out.* オリジナルの ls の標準出力
  • rls.err.* 今回作成 rls の標準エラー出力
  • rls.out.* 今回作成 rls の標準出力
    • リダイレクトではなく画面表示のテスト(case.05)は、ターミナルに出力した結果を手作業で貼り付け

ケース毎の説明

  • case.00
    • オプションのパース
  • case.01
    • パスのパース
    • パス、ファイルの種類
    • -l オプション無しカラム表示でのパイプ、ファイルへの出力
    • -l オプションありリスト表示
    • -a オプションあり/なし
    • -r オプションあり/なし
  • case.02
    • パスに * のみ指定
    • テスト結果で生成されるファイルがテストに影響を与えるため、結果は dir01/results/ に格納
  • case.03
    • エラー表示
    • -l オプションありリスト表示でのスティッキービット、setuid、setgid の表示
    • 実行権限無しのディレクトリ、およびそのディレクトリ中のファイル
  • case.04
    • キャラクタデバイス、ブロックデバイス、fifo、ソケット、シンボリックリンク
  • case.05
    • -l オプション無しカラム表示での画面への出力
    • テスト結果は results.txt

スケジューリング

要件整理

  • `ls`コマンドを作成
    • オプションとして、最低限 `-a`, `-l`, `-r`を実装。`-al`や`-alr`などのように、組み合わされても使えるように。
  • 言語は最新版のRuby、あるいは、最新版のPHP
  • GitHub上のリポジトリとして、コードを提出
  • 納期 7月12日(金)17:00

スケジュール

要件整理

必要となる要素の洗い出し

開発環境構築

GNOME Boxes 上に構築

最新版のRuby、あるいは、最新版のPHP

git

GitHub

  • 既存アカウントを使用

開発

ドキュメント整理

提出

準備

必要となる要素の洗い出し

最新版のRuby

  • 19/07/01 現在 Ruby 2.6.3

最新版のPHP

  • 19/07/01 現在 PHP 7.3.6

Ruby/PHP 複数バージョン混在環境の管理方法

  • 開発中にさらなる最新バージョンがリリースされた場合に必要
  • 必要となる可能性低

Ruby/PHP 実行方法

  • インタプリタにソース読ませるのではなく、単体のコマンドとして実行する方法
  • シェルスクリプトではダメ?
  • シーバンで可
    • #!/usr/bin/env ruby

オプション読み込みの方法

  • Ruby
    • ARGV[]

出力整形の方法

  • Ruby
    • strftime()
    • format()

出力に色を付ける方法

  • ターミナルの問題。エスケープ文字出力で可能か?
  • 色付けなしがデフォルトなのでこれは考えない

ファイル属性の取得方法

  • Ruby
    • File.stat()

ls の仕様

Ruby/PHP でオプション受けてそのまま ls に渡せばいいんじゃ?

  • そういう話じゃない

テスト方法

  • ls の出力と作成プログラムの出力の diff で確認

ToDo

path の処理

  • [X] path にワイルドカードがあったときの対応←シェルの仕事では?
  • [X] ファイル一覧表示
    • ファイルは一つのファイル一覧に追加、ディレクトリはパスとファイル一覧のセットを保持
    • まずファイル一覧を処理、ファイル一覧に内容が無くパスとファイル一覧のセットが一個だけならそれをファイル一覧として処理
    • パスとファイル一覧のセットが複数あればパスを表示してファイル一覧を処理をセット分繰り返す
    • Dir.entries はディレクトリが対象でファイルは対象ではない
    • Dir.glob で path を一個ずつ取得し、ディレクトリかファイルかで処理を分ける?
    • 結果はこう
      ls ../golang/
      choice  main  main.go  main.go~  processlog
      
      ls  ../golang/choice/choice ../golang/main.go
      ../golang/choice/choice  ../golang/main.go
      
      ls ../golang/*
      ../golang/main  ../golang/main.go  ../golang/main.go~
      
      ../golang/choice:
      choice  main.go  main.go~
      
      ../golang/processlog:
      arg.go
      
      ls  ../golang/choice/choice ../golang/main.go ./ ./temp01.rb ./*
      ../golang/choice/choice  ../golang/main.go  ./temp01.rb  ./temp01.rb  ./temp01.rb~  ./temp02.rb  ./temp02.rb~
      
      ./:
      temp01.rb  temp01.rb~  temp02.rb  temp02.rb~
              
  • [X] path が指定されなかった場合はカレントディレクトリが対象
  • [X] path が存在しなかったらエラー表示
  • [-] 権限がない場合もエラー
    • path を絶対パスに変換し、最上位ディレクトリから順に検査、読み取り権限と実行権限が無ければ権限エラーで終了
      • を開くことが出来ません: 許可がありません
    • 順に下位のディレクトリを同様に検査
    • ディレクトリの中の最下位のものは読み取り権限が無いだけで権限エラーで終了
      • を開くことが出来ません: 許可がありません
    • path の最下位がディレクトリの場合で実行権限がなければ、その中のファイル一覧は表示しつつ、それぞれの権限エラーも表示
      • にアクセスできません: 許可がありません
    • path の最下位がファイルの場合はその上のディレクトリに実行権限がなければ権限エラー
      • にアクセスできません: 許可がありません
    • [X] 結果はこう
    ls -a /var/log/httpd/access_log 
    ls: /var/log/httpd/access_log にアクセスできません: 許可がありません
    
    ls -a /var/log/httpd/
    ls: ディレクトリ /var/log/httpd/ を開くことが出来ません: 許可がありません
    
        
    • [X]
    ls ../test/rx
    01rx  02rx
    
    rls ../test/rx
    01rx  02rx  
    
        
    • [ ] 最下位が実行権限のないディレクトリの場合。エラーメッセージ、ディレクトリ名の表示有無が異なる
    ls ../test/r
    ls: cannot access ../test/r/rx: Permission denied
    ls: cannot access ../test/r/r01: Permission denied
    ls: cannot access ../test/r/r02: Permission denied
    ls: cannot access ../test/r/r03: Permission denied
    ls: cannot access ../test/r/rxw: Permission denied
    r01  r02  r03  rx  rxw
    
    rls ../test/r 
    ls: cannot access ../test/r/.: Permission denied
    ls: cannot access ../test/r/..: Permission denied
    ls: cannot access ../test/r/r01: Permission denied
    ls: cannot access ../test/r/r02: Permission denied
    ls: cannot access ../test/r/r03: Permission denied
    ls: cannot access ../test/r/rx: Permission denied
    ls: cannot access ../test/r/rxw: Permission denied
    ../test/r:
    r01  r02  r03  rx  rxw
    
        
  • [X] 先頭がハイフンのファイル名の対応
    • – の後のパラメータを path として扱うことで OK
  • [X] ハイフン一個のみはファイル名として扱う

特殊ファイルの処理

  • [X] キャラクタデバイス
  • [X] ブロックデバイス
  • [X] fifo
  • [X] ソケット
  • [X] シンボリックリンクの処理
    • オプション -l のとき
    • [X] ファイル名にリンク先追加
    • [X] シンボリックリンクのパスを単体で与えた時、リンク先の一覧を表示してしまう
    • [X] シンボリックリンク /etc/grub2.cfg の表示がおかしい。
      ls -l /etc/grub2.cfg
      lrwxrwxrwx 1 root root 22 May  8 20:01 /etc/grub2.cfg -> ../boot/grub2/grub.cfg
      
      ./rls -l /etc/grub2.cfg
      ls: cannot access /etc/grub2.cfg: No such file or directory
              
  • [X] /dev の表示形式が異なる

オプションの処理

  • [X] – でオプション終了の対応
  • [X] -a 対応
    • [X] ls .*
  • [X] -r 対応
  • [X] -l 対応
    • [X] 日付 182日以上過去/未来は時刻ではなく年を表示
    • [X] スティッキービット、setuid、setgid 対応
    • [X] ls -s のブロック数と File.stat().blocks の数が合わない。
      • File.stat().blocks が 2倍の値になる?
    • [X] x なしディレクトリ中のファイル一覧で stat しようとしてパーミッションエラーになる。先にアクセス可能かテストする。だめなら例外で対応
      rls -l ../test/r
      ls: cannot access ../test/r/.: Permission denied
      ls: cannot access ../test/r/..: Permission denied
      ls: cannot access ../test/r/r01: Permission denied
      ls: cannot access ../test/r/r02: Permission denied
      ls: cannot access ../test/r/r03: Permission denied
      ls: cannot access ../test/r/rx: Permission denied
      ls: cannot access ../test/r/rxw: Permission denied
      ../test/r:
      Traceback (most recent call last):
      	8: from ./rls:356:in `<main>'
      	7: from ./rls:356:in `each_with_index'
      	6: from ./rls:356:in `each'
      	5: from ./rls:359:in `block in <main>'
      	4: from ./rls:150:in `print_dirs'
      	3: from ./rls:105:in `print_files'
      	2: from ./rls:105:in `map'
      	1: from ./rls:105:in `block in print_files'
      ./rls:105:in `stat': Permission denied @ rb_file_s_stat - ../test/r/r01 (Errno::EACCES)
      
      
      ls -l ../test/r
      ls: cannot access ../test/r/rx: Permission denied
      ls: cannot access ../test/r/r01: Permission denied
      ls: cannot access ../test/r/r02: Permission denied
      ls: cannot access ../test/r/r03: Permission denied
      ls: cannot access ../test/r/rxw: Permission denied
      total 0
      ?????????? ? ? ? ?            ? r01
      ?????????? ? ? ? ?            ? r02
      ?????????? ? ? ? ?            ? r03
      ?????????? ? ? ? ?            ? rx
      ?????????? ? ? ? ?            ? rxw
              

テスト

  • [ ] テストケース洗い出し

オプション無し時の動作

  • [X] ls -C 動作再現
    • [X] カラム数決定ロジック
      • ls /lib
    • [X] 整列表示
  • [X] ファイルやパイプに繋いだ時の表示対応
    • STDOUT.isatty

エラーメッセージ

  • [X] エラーメッセージと結果の表示順
    • [X] 下記の順?
      • ls: cannot access : Permission denied
      • ls: cannot access : No such file or directory
      • ファイルリスト
      • ls: cannot open directory
      • ディレクトリリスト
    • [X] oioi と /etc/oioi の順番が合わない、パラメータ出現順?
      ls -a /etc/oioi oioi
      ls: cannot access /etc/oioi: No such file or directory
      ls: cannot access oioi: No such file or directory
      
      ls -a oioi /etc/oioi     
      ls: cannot access oioi: No such file or directory
      ls: cannot access /etc/oioi: No such file or directory
      
              
    • [X] 結果例
      ls -a rls /root/temp /var/log/httpd
      ls: cannot access /root/temp: Permission denied
      rls
      
      ls: cannot open directory /var/log/httpd: Permission denied
              
    • [X] 結果例
      ls -a rls root.thing 
      root.thing
      
      rls:
      .  ..  .git  .gitignore  LICENSE  README.org  rls  rls~
      
      ls -a rls root.thing oioi
      ls: cannot access oioi: No such file or directory
      root.thing
      
      rls:
      .  ..  .git  .gitignore  LICENSE  README.org  rls  rls~
      
      ls -a  root.thing oioi
      ls: cannot access oioi: No such file or directory
      root.thing
      
      ls -a  rls oioi
      ls: cannot access oioi: No such file or directory
      rls:
      .  ..  .git  .gitignore  LICENSE  README.org  rls  rls~
              
  • [X] エラーメッセージの順番をオリジナルに合わせる
    オリジナル
    cannot open directory XXX: Permission denied 以外のエラーメッセージはパラメータの出現順
    cannot open directory XXX: Permission denied はファイル一覧の後に出力
    今回作成版
    cannot open directory XXX: Permission denied 以外のエラーメッセージは以下の順に出力、同じ種類のエラーはパラメータ出現順
      cannot access %s: No such file or directory
      cannot access %s: Not a directory
      cannot access %s: Permission denied
    cannot open directory XXX: Permission denied はファイル一覧の後に出力
    
    $ls /root/not.exist not.exist LICENSE/ /root /root/temp  LICENSE 
    ls: cannot access /root/not.exist: Permission denied
    ls: cannot access not.exist: No such file or directory
    ls: cannot access LICENSE/: Not a directory
    ls: cannot access /root/temp: Permission denied
    LICENSE
    
    ls: cannot open directory /root: Permission denied
    
    $rls /root/not.exist not.exist LICENSE/ /root /root/temp  LICENSE 
    ls: cannot access not.exist: No such file or directory
    ls: cannot access LICENSE/: Not a directory
    ls: cannot access /root/not.exist: Permission denied
    ls: cannot access /root/temp: Permission denied
    LICENSE
    
    ls: cannot open directory /root: Permission denied
        

日次実施事項ログ

19/07/01

  • 2h スケジューリング、環境準備

19/07/02

  • 1h README GitHUB へ push
  • 1h Ruby オプションパース、ファイル一覧取得部分調査

19/07/03

  • 1h ls 仕様調査、ls -C 動作再現方法考察
  • 1h ls -C 動作実装

19/07/04

  • 1h ToDo 洗い出し、テストケース洗い出し

19/07/05

  • 5h ls -C 動作再現、パス取得/展開

19/07/06

  • 5h パス取得/展開、存在/権限チェック、エラー表示

19/07/07

  • 2h エラー表示
  • 4h オプション対応

19/07/08

  • 1h テストスクリプト作成
  • 2h -l オプション対応、対象がシンボリックリンクの場合の対応
  • 1h YARD コメント追加

19/07/09

  • 1h オプション無し時のカラム表示バグ対応とリファクタリング
  • 1h テストケース洗い出し
  • 2h テスト実施

19/07/10

  • 4h テスト実施、バグ対応
  • 1h README 整理
  • 1h ドキュメント作成

19/07/11

  • 1h README 整理、rls リファクタリング

参考

ls仕様

About

ls command with Ruby

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published