From ef7a606f63ff485236c08a9bd077b1e3e6e30841 Mon Sep 17 00:00:00 2001 From: syrmel <104119569+syrmel@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:01:57 +0100 Subject: [PATCH] Implement link util (#180) * Begin link * Make normalise public * Improve link tests * Remove outdated delete.me * Update README * Update error messages and tests based on CI results --- README.md | 6 ++-- common/testing/testing.v | 2 +- src/id/delete.me | 0 src/link/delete.me | 0 src/link/link.v | 42 +++++++++++++++++++++++++ src/link/link_test.v | 67 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 4 deletions(-) delete mode 100644 src/id/delete.me delete mode 100644 src/link/delete.me create mode 100644 src/link/link.v create mode 100644 src/link/link_test.v diff --git a/README.md b/README.md index 295d3288..819b86df 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ count below and mark it as done in this README.md. Thanks! GNU coreutils. They are not 100% compatiable. If you encounter different behaviors, compare against the true GNU coreutils version on the Linux-based tests first. -## Completed (73/109) - 67% done! +## Completed (74/109) - 68% done! | Done | Cmd | Descripton | Windows | | :-----: | --------- | ------------------------------------------------ | ------- | @@ -94,7 +94,7 @@ compare against the true GNU coreutils version on the Linux-based tests first. | | install | Copy files and set attributes | | | | join | Join lines on a common field | ✓ | | | kill | Send a signal to processes | ✓ | -| | link | Make a hard link via the link syscall | ✓ | +| ✓ | link | Make a hard link via the link syscall | ✓ | | ✓ | ln | Make links between files | ✓ | | ✓ | logname | Print current login name | ✓ | | ✓ | ls | List directory contents | | @@ -129,7 +129,7 @@ compare against the true GNU coreutils version on the Linux-based tests first. | ✓ | sha256sum | Print or check SHA-2 256 bit digests | ✓ | | ✓ | sha384sum | Print or check SHA-2 384 bit digests | ✓ | | ✓ | sha512sum | Print or check SHA-2 512 bit digests | ✓ | -| | shred | Remove files more securely | ✓ | +| ✓ | shred | Remove files more securely | ✓ | | ✓ | shuf | Shuffling text | ✓ | | ✓ | sleep | Delay for a specified time | ✓ | | ✓ | sort | Sort text files | ✓ | diff --git a/common/testing/testing.v b/common/testing/testing.v index e3516f5f..343b0790 100644 --- a/common/testing/testing.v +++ b/common/testing/testing.v @@ -186,7 +186,7 @@ pub fn same_results(cmd1 string, cmd2 string) bool { return cmd1_res.exit_code == cmd2_res.exit_code && noutput1 == noutput2 } -fn normalise(s string) string { +pub fn normalise(s string) string { return s.replace_each(['‘', "'", '’', "'"]).replace(' ', ' ').replace(' ', ' ').replace(' ', ' ').replace(', ', ' ').split_into_lines().join('\n').trim_space() } diff --git a/src/id/delete.me b/src/id/delete.me deleted file mode 100644 index e69de29b..00000000 diff --git a/src/link/delete.me b/src/link/delete.me deleted file mode 100644 index e69de29b..00000000 diff --git a/src/link/link.v b/src/link/link.v new file mode 100644 index 00000000..b90efd45 --- /dev/null +++ b/src/link/link.v @@ -0,0 +1,42 @@ +module main + +import common +import os + +const app = common.CoreutilInfo{ + name: 'link' + description: 'Call the link function to create a link named FILE2 to an existing FILE1.' +} + +struct Settings { +mut: + files []string +} + +fn args() Settings { + mut fp := app.make_flag_parser(os.args) + mut st := Settings{} + st.files = fp.remaining_parameters() + match st.files.len { + 0 { app.quit(message: 'missing operand') } + 1 { app.quit(message: "missing operand after '${st.files[0]}'", show_help_advice: true) } + 2 {} + else { app.quit(message: "extra operand '${st.files[2]}'", show_help_advice: true) } + } + + return st +} + +fn link(settings Settings) !int { + mut exit_code := 0 + os.link(settings.files[0], settings.files[1]) or { + app.quit( + message: "cannot create link '${settings.files[1]}' to '${settings.files[0]}': ${err.msg()}" + ) + } + return exit_code +} + +fn main() { + exit(link(args()) or { common.err_programming_error }) +} diff --git a/src/link/link_test.v b/src/link/link_test.v new file mode 100644 index 00000000..0c5bfbf6 --- /dev/null +++ b/src/link/link_test.v @@ -0,0 +1,67 @@ +module main + +import common.testing +import os + +const rig = testing.prepare_rig(util: 'link') + +fn testsuite_begin() { +} + +fn testsuite_end() { +} + +fn test_help_and_version() { + rig.assert_help_and_version_options_work() +} + +fn test_compare() { + $if windows { + // The coreutils used on Windows does not produce the exact + // same error messages + rig.assert_same_exit_code('a') + rig.assert_same_exit_code('a b') + rig.assert_same_exit_code('a b c') + rig.assert_same_exit_code('a b c d e f') + os.mkdir('d')! + rig.assert_same_exit_code('d e') + os.rmdir('d')! + } $else { + rig.assert_same_results('a') + rig.assert_same_results('a b') + rig.assert_same_results('a b c') + rig.assert_same_results('a b c d e f') + os.mkdir('d')! + rig.assert_same_results('d e') + os.rmdir('d')! + } + + // We can't use assert_same_results here because the hard link will already + // exist when the second util is called + os.write_file('a', '12345')! + cmd1_res := rig.call_orig('a b') + assert os.is_file('a') + assert os.is_file('b') + assert os.read_file('b') or { '' } == '12345' + mut f := os.open_append('b')! + f.write_string('67890')! + f.close() + assert os.read_file('a') or { '' } == '1234567890' + os.rm('b')! + os.rm('a')! + + os.write_file('a', '12345')! + cmd2_res := rig.call_new('a b') + assert os.is_file('a') + assert os.is_file('b') + assert os.read_file('b') or { '' } == '12345' + f = os.open_append('b')! + f.write_string('67890')! + f.close() + assert os.read_file('a') or { '' } == '1234567890' + os.rm('b')! + os.rm('a')! + + assert cmd1_res.exit_code == cmd2_res.exit_code + assert testing.normalise(cmd1_res.output) == testing.normalise(cmd2_res.output) +}