Skip to content

Commit

Permalink
Adding the unlink utility (#124)
Browse files Browse the repository at this point in the history
* Initial uniq

* Added uniq tests

* Fixed documentation on read_line_until()

* Replace CustomBufferedReader with new vlib version

* Add unlink utility

* Remove unused functions

* use os.posix_get_error_msg

* For Windows, fall back to calling os.rm()

* Disable some tests for Windows for now

* Update complete count in README
  • Loading branch information
syrmel authored Jan 27, 2024
1 parent 7d55322 commit 2b2c3b0
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 2 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Contributions are welcome!
Please only contribute versions of the original utilities written in V.
Contributions written in other languages will likely be rejected.

## Completed (46/109)
## Completed (47/109)

| Done | Cmd | Descripton |
| :-----: | --------- | ------------------------------------------------ |
Expand Down Expand Up @@ -143,7 +143,7 @@ Contributions written in other languages will likely be rejected.
| ✓ | uname | Print system information |
| | unexpand | Convert spaces to tabs |
| ✓ | uniq | Uniquify files |
| | unlink | Remove files via the unlink syscall |
| ✓ | unlink | Remove files via the unlink syscall |
| ✓ | uptime | Print system uptime and load |
| | users | Print login names of users currently logged in |
| | vdir | Verbosely list directory contents |
Expand Down
Empty file removed src/unlink/delete.me
Empty file.
31 changes: 31 additions & 0 deletions src/unlink/settings.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import common
import os

struct Settings {
mut:
target string
}

fn args() Settings {
mut fp := common.flag_parser(os.args)
fp.application(app_name)
fp.description(app_description)

mut st := Settings{}
fnames := fp.remaining_parameters()

// Validation
match fnames.len {
0 {
common.exit_with_error_message(app_name, 'missing operand')
}
1 {
// The desired outcome
st.target = fnames[0]
}
else {
common.exit_with_error_message(app_name, 'extra operand ‘${fnames[1]}’')
}
}
return st
}
20 changes: 20 additions & 0 deletions src/unlink/unlink.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os

#include <errno.h>
$if !windows {
#include <unistd.h>
}

fn C.unlink(&char) int

fn unlink(settings Settings) {
$if !windows {
err := C.unlink(&char(settings.target.str))
if err != 0 {
posix_error := os.posix_get_error_msg(C.errno)
fail("cannot unlink '${settings.target}': ${posix_error}")
}
} $else {
os.rm(settings.target) or { panic(err) }
}
}
15 changes: 15 additions & 0 deletions src/unlink/unlink.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module main

// POSIX Spec: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/unlink.html
const app_name = 'unlink'
const app_description = 'call the unlink function to remove the specified file'

@[noreturn]
pub fn fail(error string) {
eprintln('${app_name}: ${error}')
exit(1)
}

fn main() {
unlink(args())
}
55 changes: 55 additions & 0 deletions src/unlink/unlink_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import common.testing
import os

const util = 'unlink'
const platform_util = $if !windows {
util
} $else {
'coreutils ${util}'
}

const cmd = testing.new_paired_command(platform_util, executable_under_test)
const executable_under_test = testing.prepare_executable(util)
const temp_dir = testing.temp_folder

fn call_for_test(args string) os.Result {
res := os.execute('${executable_under_test} ${args}')
assert res.exit_code == 0
return res
}

// TODO: The following tests fail in a Windows environment; need to
// investigate what gives.
fn test_target_does_not_exist() {
$if !windows {
assert cmd.same_results('does_not_exist')
}
}

// TODO: This test does not run in all environments; to be investigated.
// fn test_too_many_operands() {
// $if !windows {
// assert cmd.same_results('a b c')
// }
// }

fn test_target_is_directory() {
$if !windows {
os.mkdir('foo')!
assert cmd.same_results('foo')
os.rmdir('foo')!
}
}

fn test_target_does_exist() {
// Unfortunately, we cannot do a same_results comparison since
// the first call will blow away the target
os.write_file('a', '')!
assert os.is_file('a')
call_for_test('a')
assert !os.is_file('a')
}

fn test_help_and_version() {
cmd.ensure_help_and_version_options_work()!
}

0 comments on commit 2b2c3b0

Please sign in to comment.