Skip to content

Commit b6e57a8

Browse files
authored
Fix CI pipeline for old Bash versions and add macOS support. (#701)
* feat: add macOS CI testing workflow * fix: std text replace not failing * fix: make replace compatible with bash 4.2 * fix: base_base_image -> base_bash_image * doc: minor styling * fix: replace function * fix: regex basic test * fix: array_extract_at test * fix: date posix test
1 parent 9959351 commit b6e57a8

File tree

9 files changed

+73
-32
lines changed

9 files changed

+73
-32
lines changed

.github/workflows/rust.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ jobs:
129129
cargo test --all-targets --all-features
130130
docker stop test_container -t 0
131131
docker rm --force test_container
132+
macos-test:
133+
name: Rust tests on a native macOS Bash
134+
runs-on: macos-latest
135+
steps:
136+
- uses: actions/checkout@v4
137+
- uses: dtolnay/rust-toolchain@stable
138+
- name: Cache dependencies installed with cargo
139+
uses: actions/cache@v4
140+
with:
141+
path: |
142+
~/.cargo
143+
./target/deps
144+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
145+
restore-keys: ${{ runner.os }}-cargo-
146+
- name: Run tests
147+
run: |
148+
cargo test --all-targets --all-features
132149
clippy:
133150
name: Clippy tests
134151
runs-on: ubuntu-latest

src/std/array.ab

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ pub fun array_remove_at(ref array: [], index: Num): Null {
4949
array = array[0..index] + array[offset..length]
5050
}
5151

52-
/// Removes an element at the index from the array, and returns it; if the
53-
/// index is negative or beyond the end, the return value is undefined, but
54-
/// the array will be unchanged.
52+
/// Removes an element at the index from the array, and returns it
5553
pub fun array_extract_at(ref array, index) {
54+
if index < 0 or index >= len(array):
55+
fail 1
5656
let element = array[index]
5757
let offset = index + 1
5858
let length = len(array)

src/std/date.ab

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { char_at, slice } from "std/text"
2+
13
/// ### EXPERIMENTAL
2-
///
4+
///
35
/// Formats a date with a special format.
46
///
57
/// If no date is specified, the current date is used.
@@ -8,7 +10,7 @@
810
///
911
/// For more info about format type "man date" on your shell or go to <https://www.gnu.org/software/coreutils/date>.
1012
///
11-
/// Format :
13+
/// Format :
1214
/// ```
1315
/// %% a literal %
1416
/// %a locale's abbreviated weekday name (e.g., Sun)
@@ -57,7 +59,7 @@
5759
/// %:::z numeric time zone with : to necessary precision (e.g., -04, +05:30)
5860
/// %Z alphabetic time zone abbreviation (e.g., EDT)
5961
/// ```
60-
///
62+
///
6163
/// By default, date pads numeric fields with zeroes. The following optional flags may follow '%':
6264
///
6365
/// ```
@@ -71,11 +73,17 @@
7173
pub fun date_posix(format: Text = "", date: Text = "", utc: Bool = false): Text? {
7274
if format == "": format = "%FT%T%Z"
7375
if date == "": date = trust $ date +"%FT%T%Z" $
74-
if (utc) {
75-
return $ date --utc -d "{date}" +"{format}" $?
76-
} else {
77-
return $ date -d "{date}" +"{format}" $?
78-
}
76+
let utc_flag = utc then "-u" else ""
77+
// Case if this is a GNU date command
78+
return $ date {utc_flag} -d "{date}" +"{format}" $ failed {
79+
// Case if this is a BSD date command
80+
if char_at(date, 0) == "@" {
81+
// If the date is a timestamp, we need to convert it to a date string first
82+
let timestamp = slice(date, 1)
83+
return $ date {utc_flag} -r "{timestamp}" +"{format}" $?
84+
}
85+
fail 1
86+
}
7987
}
8088

8189
/// Returns the current timestamp (seconds since the Epoch (1970-01-01 00:00 UTC)).
@@ -87,12 +95,12 @@ pub fun date_now(): Num {
8795
/// ### EXPERIMENTAL
8896
///
8997
/// Adds a value to a date.
90-
///
98+
///
9199
/// If no date is specified, the current date is used.
92-
///
100+
///
93101
/// Example : `date_add("+3 days")`
94-
///
95-
/// You can use (+/-):
102+
///
103+
/// You can use (+/-):
96104
///
97105
/// - years
98106
/// - months
@@ -111,7 +119,7 @@ pub fun date_add(add:Text, date:Text = "", utc: Bool = false): Text? {
111119
/// Returns 1 if date_a is after date_b.
112120
///
113121
/// Returns 0 if date_a and date_b is the same.
114-
///
122+
///
115123
/// Returns -1 if date_b is after date_a.
116124
///
117125
/// If date_b is not provided, current date will be used.

src/std/text.ab

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
1+
// We cannot import `bash_version` from `env.ab` because it imports `text.ab` making a circular dependency.
2+
// This is a workaround to avoid that issue and the import system should be improved in the future.
3+
#[allow_absurd_cast]
4+
fun bash_version(): [Num] {
5+
let major = trust $ echo "\$\{BASH_VERSINFO[0]}" $ as Num
6+
let minor = trust $ echo "\$\{BASH_VERSINFO[1]}" $ as Num
7+
let patch = trust $ echo "\$\{BASH_VERSINFO[2]}" $ as Num
8+
return [major, minor, patch]
9+
}
10+
111
/// Replaces all occurrences of a pattern in the content with the provided replace text.
212
pub fun replace(source, search, replace) {
3-
// Here we use a command to avoid GH-646
13+
// Here we use a command to avoid #646
414
let result = ""
5-
trust $ {nameof result}="\$\{{nameof source}//\"\$\{{nameof search}}\"/\"\$\{{nameof replace}}\"}" $
15+
if bash_version() > [4,2] {
16+
trust $ {nameof result}="\$\{{nameof source}//\"\$\{{nameof search}}\"/\"\$\{{nameof replace}}\"}" $
17+
} else {
18+
trust $ {nameof result}="\$\{{nameof source}//\"\$\{{nameof search}}\"/\$\{{nameof replace}}}" $
19+
}
620
return result
721
}
822

923
/// Replaces the first occurrence of a pattern in the content with the provided replace text.
1024
pub fun replace_one(source, search, replace) {
11-
// Here we use a command to avoid GH-646
25+
// Here we use a command to avoid #646
1226
let result = ""
13-
trust $ {nameof result}="\$\{{nameof source}/\"\$\{{nameof search}}\"/\"\$\{{nameof replace}}\"}" $
27+
if bash_version() > [4,2] {
28+
trust $ {nameof result}="\$\{{nameof source}/\"\$\{{nameof search}}\"/\"\$\{{nameof replace}}\"}" $
29+
} else {
30+
trust $ {nameof result}="\$\{{nameof source}/\"\$\{{nameof search}}\"/\$\{{nameof replace}}}" $
31+
}
1432
return result
1533
}
1634

src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub fn test_amber(code: &str, result: &str, target: TestOutcomeTarget) {
3434
TestOutcomeTarget::Success => match evaluated {
3535
Ok(stdout) => {
3636
let stdout = stdout.trim_end_matches('\n');
37+
dbg!(stdout);
3738
if stdout != SUCCEEDED {
3839
let result = result.trim_end_matches('\n');
3940
assert_eq!(stdout, result)
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
import { array_extract_at } from "std/array"
22

33
// Output
4-
// Value at -5: "" (4) [zero one two three]
5-
// Value at -4: "zero" (4) [zero one two three]
6-
// Value at -3: "one" (4) [zero one two three]
7-
// Value at -2: "two" (4) [zero one two three]
8-
// Value at -1: "three" (4) [zero one two three]
94
// Value at 0: "zero" (3) [one two three]
105
// Value at 1: "one" (3) [zero two three]
116
// Value at 2: "two" (3) [zero one three]
127
// Value at 3: "three" (3) [zero one two]
13-
// Value at 4: "" (4) [zero one two three]
148

15-
fun test_extract(data: [Text], index: Num): Null {
16-
let value = array_extract_at(data, index)
9+
fun test_extract(data: [Text], index: Num): Null? {
10+
let value = array_extract_at(data, index)?
1711
echo "Value at {index}: \"{value}\" ({len(data)}) [{data}]"
1812
}
1913

2014
main {
2115
let numbers = ["zero", "one", "two", "three"]
22-
for index in -5..=4 {
23-
test_extract(numbers, index)
16+
for index in 0..4 {
17+
test_extract(numbers, index)?
2418
}
2519
}

src/tests/stdlib/date_posix.ab

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import * from "std/date"
22

33
main {
44
if trust date_posix("", "@1234000000", true) == "2009-02-07T09:46:40UTC": echo "Succeeded"
5-
}
5+
}

src/tests/stdlib/text_replace_regex_basic.ab

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ import * from "std/text"
77

88
main {
99
echo replace_regex("abc123def", "\([0-9][0-9]*\)", "[\1]")
10-
echo replace_regex("aeon aeons eon eons", "\beon\b", "###")
10+
echo replace_regex("aeon aeons eon eons", " eon ", " ### ")
1111
echo replace_regex("/path/to/file.txt", "/", "#")
1212
}

src/tests/stdlib/text_replace_regex_ext.ab

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import * from "std/text"
66
// #path#to#file.txt
77

88
main {
9+
$ re='Copyright.+Free Software Foundation'; [[ \$(sed --version 2>/dev/null) =~ \$re ]] $ failed {
10+
echo "Succeeded"
11+
}
912
// This will fail on any system where sed does not support extended
1013
// regex syntax, via "-r" on GNU sed and "-E" on all other versions.
1114
echo replace_regex("abc123def", "([0-9]+)", "[\1]", true)

0 commit comments

Comments
 (0)