12 Commits
Author SHA1 Message Date
phoenix 235174b404 Dependency name change (#9)
clean_file Build / Check (push) Successful in 46s
clean_file Build / Rustfmt (push) Successful in 42s
clean_file Build / Test Suite (push) Successful in 1m28s
clean_file Build / build (push) Successful in 1m7s
clean_file Build / Clippy (push) Successful in 2m15s
Reviewed-on: #9
2026-07-13 12:06:24 -04:00
phoenix f837b0f5d0 Update (#8)
Rust Build / Check (push) Successful in 1m18s
Rust Build / build (push) Successful in 58s
Rust Build / Test Suite (push) Successful in 1m54s
Rust Build / Rustfmt (push) Successful in 43s
Rust Build / Clippy (push) Successful in 1m16s
clean_file pr / Check (pull_request) Successful in 38s
clean_file pr / Rustfmt (pull_request) Successful in 35s
clean_file pr / Clippy (pull_request) Successful in 58s
Reviewed-on: #8
2026-06-14 18:08:36 -04:00
phoenix 79a3e47a1b Update deps (#7)
Rust Build / Check (push) Successful in 1m2s
Rust Build / Rustfmt (push) Successful in 36s
Rust Build / Test Suite (push) Successful in 1m23s
Rust Build / build (push) Successful in 52s
Rust Build / Clippy (push) Successful in 42s
Reviewed-on: #7
2026-06-13 13:09:55 -04:00
phoenix d8cb2cee19 Update dependencies (#6)
Rust Build / Check (push) Successful in 31s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 1m3s
Rust Build / build (push) Successful in 1m1s
Rust Build / Clippy (push) Successful in 41s
Reviewed-on: #6
2026-06-07 15:33:57 -04:00
phoenix 7d9142dc13 Merge pull request 'v1.0' (#1) from v1.x into main
Rust Build / Check (push) Successful in 26s
Rust Build / Test Suite (push) Successful in 47s
Rust Build / Rustfmt (push) Successful in 33s
Rust Build / build (push) Successful in 29s
Rust Build / Clippy (push) Successful in 47s
Rust Build / Check (pull_request) Successful in 1m17s
Rust Build / Rustfmt (pull_request) Successful in 30s
Rust Build / Clippy (pull_request) Successful in 40s
Rust Build / Test Suite (pull_request) Successful in 2m4s
Rust Build / build (pull_request) Successful in 58s
Reviewed-on: #1
2026-06-06 14:12:01 -04:00
phoenix f9339ae9a1 bump: clean_file
Rust Build / Check (pull_request) Successful in 33s
Rust Build / Test Suite (pull_request) Successful in 37s
Rust Build / Rustfmt (pull_request) Successful in 45s
Rust Build / Clippy (pull_request) Successful in 27s
Rust Build / build (pull_request) Successful in 1m13s
2026-06-06 14:08:18 -04:00
phoenix a0bf202b39 Workflow branch update
Rust Build / Check (pull_request) Successful in 26s
Rust Build / Test Suite (pull_request) Successful in 38s
Rust Build / Rustfmt (pull_request) Successful in 50s
Rust Build / Clippy (pull_request) Successful in 28s
Rust Build / build (pull_request) Successful in 45s
2026-06-06 14:07:23 -04:00
phoenix f5cb2ed892 Add tests (#5)
Rust Build / Check (push) Successful in 33s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / Test Suite (push) Successful in 38s
Rust Build / Clippy (push) Successful in 29s
Rust Build / build (push) Successful in 42s
Reviewed-on: #5
2026-06-06 14:03:42 -04:00
phoenix cd0ea8a387 Migrate (#4)
Rust Build / Clippy (push) Successful in 33s
Rust Build / Check (push) Successful in 26s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 47s
Rust Build / build (push) Successful in 30s
Reviewed-on: #4
2026-06-06 12:48:58 -04:00
phoenix e7f6ddec9a Adding rust files (#3)
Rust Build / Check (push) Successful in 38s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / Test Suite (push) Successful in 38s
Rust Build / Clippy (push) Successful in 37s
Rust Build / build (push) Successful in 42s
Reviewed-on: #3
2026-06-05 18:49:53 -04:00
phoenix 9ec9fa1516 Clear out (#2)
Reviewed-on: #2
2026-06-05 18:06:38 -04:00
phoenixandphoenix f2a650ef27 go version bump (#21)
Go / build (pull_request) Failing after 7s
Reviewed-on: #21
Co-authored-by: phoenix <mail@kundeng.us>
Co-committed-by: phoenix <mail@kundeng.us>
2026-05-03 16:15:12 -04:00
18 changed files with 2396 additions and 385 deletions
+65
View File
@@ -0,0 +1,65 @@
name: clean_file pr
on:
pull_request:
branches:
- main
jobs:
check:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo check
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo clippy -- -D warnings
-44
View File
@@ -1,44 +0,0 @@
name: Go
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.26.1'
- name: Build
run: |
echo "Initializing config"
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/textsender_models_deploy_key
chmod 600 ~/.ssh/textsender_models_deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/textsender_models_deploy_key
go env -w GOPRIVATE='${{ secrets.GIT_HOST_ROOT }}'
echo "Creating local .gitconfig"
touch ~/.gitconfig
cat > ~/.gitconfig << "EOF"
[url "ssh://git@${{ secrets.GIT_HOST_ROOT }}"]
insteadOf = https://${{ secrets.GIT_HOST_ROOT }}
EOF
make build
- name: Test
run: go test -v ./...
+103
View File
@@ -0,0 +1,103 @@
name: clean_file Build
on:
push:
branches:
- main
jobs:
check:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo check
test:
name: Test Suite
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo test
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo clippy -- -D warnings
build:
name: build
runs-on: ubuntu-24.04
needs: setup_ssh
steps:
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan ${{ secrets.MY_HOST }} >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/deploy_key
cargo build --release
+1 -2
View File
@@ -1,3 +1,2 @@
/vendor target/
/clean_file
numbers.json numbers.json
Generated
+1899
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "clean_file"
version = "1.1.1"
edition = "2024"
rust-version = "1.96"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.52.3", features = ["full"] }
serde_json = { version = "1.0.150" }
schedtxt_models = { git = "ssh://git@git.kundeng.us/phoenix/schedtxt_models.git", tag = "v0.5.3", features = ["contact"] }
[dev-dependencies]
-22
View File
@@ -1,22 +0,0 @@
VERSION ?= $(shell git describe --tags 2>/dev/null || echo "dev")
COMMIT ?= $(shell git rev-parse --short HEAD)
BUILD_TIME ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
GO_VERSION ?= $(shell go version | awk '{print $$3}')
.PHONY: build
build:
go build -ldflags="\
-X 'git.kundeng.us/phoenix/clean_file/internal/version.Version=$(VERSION)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.BuildTime=$(BUILD_TIME)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.Commit=$(COMMIT)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.GoVersion=$(GO_VERSION)'" \
-o clean_file cmd/clean_file/main.go
.PHONY: install
install:
go install -ldflags="\
-X 'git.kundeng.us/phoenix/clean_file/internal/version.Version=$(VERSION)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.BuildTime=$(BUILD_TIME)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.Commit=$(COMMIT)' \
-X 'git.kundeng.us/phoenix/clean_file/internal/version.GoVersion=$(GO_VERSION)'"
-o clean_file cmd/clean_file/main.go
-8
View File
@@ -1,8 +0,0 @@
CLI software that processes a text file containing US phone numbers
and sanitizes the numbers. The result is contained in a json file.
## Building
```
make build
```
-39
View File
@@ -1,39 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"git.kundeng.us/phoenix/clean_file/internal/parser"
"git.kundeng.us/phoenix/clean_file/internal/version"
)
func main() {
args := os.Args
if len(args) < 2 {
log.Println("Invalid arguments provided")
os.Exit(-1)
}
versionFlag := flag.Bool("version", false, "Print version information")
flag.Parse()
if *versionFlag {
fmt.Println(version.String())
return
}
log.Println("clean_file")
filepath := args[1]
log.Println("File path:", filepath)
prsr := parser.NumberParser{FilePath: filepath}
numbers := prsr.FileDump()
prsr.PrintValues(numbers, true)
prsr.SaveFile(numbers)
}
-7
View File
@@ -1,7 +0,0 @@
module git.kundeng.us/phoenix/clean_file
go 1.26.1
require git.kundeng.us/phoenix/textsender-models v0.2.0
require github.com/google/uuid v1.6.0 // indirect
-4
View File
@@ -1,4 +0,0 @@
git.kundeng.us/phoenix/textsender-models v0.2.0 h1:smz8Fs8VOs1Ya23txbOM0YPRidZIsM0yE9unHF0D/nQ=
git.kundeng.us/phoenix/textsender-models v0.2.0/go.mod h1:3CkqA/HFKPhpMYxkKn5uVbZEzEbG3sofLZE8pZ1BHO4=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-169
View File
@@ -1,169 +0,0 @@
package parser
import (
"bufio"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"unicode"
"git.kundeng.us/phoenix/textsender-models/tx0/contact"
)
const Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
type NumberParser struct {
FilePath string
}
func (prsr *NumberParser) FileDump() []contact.Contact {
log.Println("Dumping files")
objs := []contact.Contact{}
for _, line := range prsr.readLines(prsr.FilePath) {
if strings.ContainsAny(line, Letters) {
continue
}
myObj := contact.Contact{PhoneNumber: line}
if myObj.PhoneNumber != "" {
objs = append(objs, myObj)
}
}
objs = prsr.updateContacts(objs)
objs = prsr.removeDups(objs)
return objs
}
func (prsr *NumberParser) updateContacts(contacts []contact.Contact) []contact.Contact {
updated := []contact.Contact{}
for _, ct := range contacts {
parsed := ct.PhoneNumber
if len(parsed) < 2 {
log.Println("Invalid number:", parsed)
continue
}
pars := prsr.removeSomeData(parsed)
parsed = pars
log.Println("Parsed:", parsed)
updatedParsed := prsr.addPrefix(parsed)
updated = append(updated, contact.Contact{PhoneNumber: updatedParsed})
}
return updated
}
func (prsr *NumberParser) removeDups(contacts []contact.Contact) []contact.Contact {
updated := []contact.Contact{}
uniqueItems := make(map[string]string)
for _, val := range contacts {
uniqueItems[val.PhoneNumber] = val.PhoneNumber
}
for _, item := range uniqueItems {
updated = append(updated, contact.Contact{PhoneNumber: item})
}
return updated
}
func (prsr NumberParser) PrintValues(contacts []contact.Contact, printTotal bool) {
fmt.Println("Printing numbers")
for _, ct := range contacts {
fmt.Println("Number:", ct.PhoneNumber)
}
if printTotal {
fmt.Println("Total Numbers:", len(contacts))
}
}
func (prsr NumberParser) SaveFile(vals []contact.Contact) {
filename := "numbers.json"
// Create json and save it to the filesystem
jsonData, err := json.MarshalIndent(&vals, "", " ")
if err != nil {
log.Println("Error marshaling JSON:", err)
return
}
err = os.WriteFile(filename, jsonData, 0644)
if err != nil {
log.Println("Error writing file:", err)
return
}
}
func (prsr NumberParser) readLines(filename string) []string {
// Open the file
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Create a scanner to read the file line by line
scanner := bufio.NewScanner(file)
lines := []string{}
// Read line by line
for scanner.Scan() {
line := scanner.Text()
lines = append(lines, line)
}
// Check for any errors during scanning
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
return lines
}
func (prsr NumberParser) removeSomeData(unparsed string) string {
parsed := ""
for _, ch := range unparsed {
if ch == ' ' {
continue
} else {
if unicode.IsDigit(ch) {
parsed += string(ch)
}
}
}
log.Println("Parsed:", parsed)
return parsed
}
func (prsr NumberParser) addPrefix(raw string) string {
parsed := raw
firstChar := raw[0]
secondChar := raw[1]
if firstChar == '1' {
parsed = "+" + parsed
} else if firstChar != '+' {
if secondChar != '1' {
parsed = "+1" + parsed
} else {
parsed = "+1" + parsed
}
}
return parsed
}
-73
View File
@@ -1,73 +0,0 @@
package parser
import (
"fmt"
"log"
"testing"
"git.kundeng.us/phoenix/textsender-models/tx0/contact"
)
const Test_File_Path = "../../tests/numbers.txt"
// Remove duplicates
func Test_RemoveDups(t *testing.T) {
parser := NumberParser{FilePath: Test_File_Path}
finalAmount := parser.FileDump()
if len(finalAmount) < 1 {
t.Error("Dump should not be empty")
}
testValues := []contact.Contact{
{PhoneNumber: "+12175550194"},
{PhoneNumber: "+16025550177"},
{PhoneNumber: "+17135550167"},
{PhoneNumber: "+16085550190"},
{PhoneNumber: "+13055550112"},
{PhoneNumber: "+14155550135"},
{PhoneNumber: "+13175550123"},
{PhoneNumber: "+13605550158"},
}
aSize := len(finalAmount)
bSize := len(testValues)
if aSize != bSize {
t.Error("Data has varrying sizes A", aSize, " B", bSize)
}
if !dataEqual(finalAmount, testValues) {
fmt.Println("Printing final amount")
for _, val := range finalAmount {
fmt.Println("PhoneNumber:", val.PhoneNumber)
}
fmt.Println("\nPrinting test values")
for _, val := range testValues {
fmt.Println("PhoneNumber:", val.PhoneNumber)
}
t.Error("Data has not been updated")
} else {
log.Println("The duplicates have been removed")
}
}
func dataEqual(a, b []contact.Contact) bool {
if len(a) != len(b) {
return false
}
for i := range a {
foundIt := false
for j := range b {
if a[i] == b[j] {
foundIt = true
}
}
if !foundIt {
return false
}
}
return true
}
-17
View File
@@ -1,17 +0,0 @@
package version
import "fmt"
var (
Version = "dev"
BuildTime = "unknown"
Commit = "unknown"
GoVersion = "unknown"
)
func String() string {
return fmt.Sprintf(
"Version: %s\nBuild Date: %s\nCommit: %s\nGo Version: %s",
Version, BuildTime, Commit, GoVersion,
)
}
+32
View File
@@ -0,0 +1,32 @@
pub mod parser;
pub mod version;
#[tokio::main]
async fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
println!("Invalid arguments provided");
std::process::exit(-1);
}
if version::contains_version(&args) {
version::print_version();
std::process::exit(-1);
}
let filepath = &args[1];
println!("Filepath: {filepath:?}");
let prsr = parser::NumberParser {
filepath: filepath.clone(),
};
match prsr.file_dump().await {
Ok(contacts) => {
prsr.print_phone_numbers(&contacts);
prsr.save_file(contacts, parser::DEFAULT_OUTPUT_FILE).await;
}
Err(err) => {
eprintln!("Error: {err:?}");
}
};
}
+263
View File
@@ -0,0 +1,263 @@
use std::io::BufRead;
pub const DEFAULT_OUTPUT_FILE: &str = "numbers.json";
const LETTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#[derive(Clone, Debug, Default)]
pub struct NumberParser {
pub filepath: String,
}
impl NumberParser {
pub async fn file_dump(
&self,
) -> Result<Vec<schedtxt_models::contact::Contact>, std::io::Error> {
println!("Dumping files");
let mut objs: Vec<schedtxt_models::contact::Contact> = Vec::new();
match self.read_lines(&self.filepath).await {
Ok(lines) => {
for line in lines {
let contains_letters = line.chars().any(|c| LETTERS.contains(c));
if contains_letters {
continue;
} else {
let my_obj = schedtxt_models::contact::Contact {
phone_number: line.clone(),
..Default::default()
};
if !my_obj.phone_number.is_empty() {
objs.push(my_obj);
}
}
}
let updated_contacts = self.update_contacts(&objs).await;
let removed_duplicates = self.remove_dups(&updated_contacts).await;
Ok(removed_duplicates)
}
Err(err) => Err(err),
}
}
pub async fn save_file(&self, numbers: Vec<schedtxt_models::contact::Contact>, filename: &str) {
match serde_json::to_string(&numbers) {
Ok(json_string) => match std::fs::write(filename, json_string) {
Ok(_) => {
println!("Saved to: {filename:?}");
}
Err(err) => {
eprintln!("Error: {err:?}");
}
},
Err(err) => {
eprintln!("Error: {err:?}");
}
};
}
pub fn print_phone_numbers(&self, contacts: &Vec<schedtxt_models::contact::Contact>) {
println!("Printing phone numbers");
for contact in contacts {
println!("Phone Number: {:?}", contact.phone_number);
}
println!("Total phone numbers: {:?}", contacts.len());
}
async fn read_lines(&self, filename: &String) -> Result<Vec<String>, std::io::Error> {
match std::fs::File::open(filename) {
Ok(file) => {
let reader = std::io::BufReader::new(file);
reader.lines().collect()
}
Err(err) => Err(err),
}
}
async fn remove_dups(
&self,
contacts: &Vec<schedtxt_models::contact::Contact>,
) -> Vec<schedtxt_models::contact::Contact> {
let mut unique_contacts: Vec<schedtxt_models::contact::Contact> = Vec::new();
let mut unique_items = std::collections::HashSet::new();
for val in contacts {
unique_items.insert(val.phone_number.clone());
}
for unique_item in unique_items {
let contact = schedtxt_models::contact::Contact {
phone_number: unique_item,
..Default::default()
};
unique_contacts.push(contact);
}
unique_contacts
}
async fn update_contacts(
&self,
contacts: &Vec<schedtxt_models::contact::Contact>,
) -> Vec<schedtxt_models::contact::Contact> {
let mut updated: Vec<schedtxt_models::contact::Contact> = Vec::new();
for ct in contacts {
let phone_number = ct.phone_number.clone();
if phone_number.len() < 2 {
println!("Invalid number: {phone_number:?}");
continue;
}
let pars = self.remove_some_data(&phone_number).await;
match self.add_prefix(&pars) {
Ok(updated_parsed) => {
let contact = schedtxt_models::contact::Contact {
phone_number: updated_parsed,
..Default::default()
};
updated.push(contact);
}
Err(err) => {
eprintln!("Error: {err:?}");
std::process::exit(-2);
}
};
}
updated
}
fn add_prefix(&self, raw: &String) -> Result<String, std::io::Error> {
if raw.is_empty() {
Err(std::io::Error::other("Empty"))
} else {
let mut parsed: String = String::new();
let first_char = raw.chars().nth(0).unwrap();
if first_char == '1' {
parsed = format!("+{raw}");
} else if first_char != '+' {
parsed = format!("+1{raw}");
}
Ok(parsed)
}
}
async fn remove_some_data(&self, unparsed: &str) -> String {
let mut parsed: String = String::new();
for ch in unparsed.chars() {
if ch == ' ' {
continue;
} else {
if ch.is_numeric() {
parsed.push(ch);
}
}
}
parsed
}
}
#[cfg(test)]
mod tests {
use schedtxt_models::contact::Contact;
const TEST_NUMBERS_0: &str = "tests/numbers-0.txt";
#[tokio::test]
async fn test_file_dump() {
let file_exists = {
let path = std::path::Path::new(TEST_NUMBERS_0);
path.exists()
};
assert_eq!(true, file_exists, "File does not exists {TEST_NUMBERS_0:?}");
let filename = String::from(TEST_NUMBERS_0);
let prsr = super::NumberParser { filepath: filename };
let original: Vec<Contact> = vec![
Contact {
phone_number: String::from("+13055550112"),
..Default::default()
},
Contact {
phone_number: String::from("+13175550123"),
..Default::default()
},
Contact {
phone_number: String::from("+14155550135"),
..Default::default()
},
Contact {
phone_number: String::from("+16085550190"),
..Default::default()
},
Contact {
phone_number: String::from("+17135550167"),
..Default::default()
},
Contact {
phone_number: String::from("+16025550177"),
..Default::default()
},
Contact {
phone_number: String::from("+13605550158"),
..Default::default()
},
Contact {
phone_number: String::from("+12175550194"),
..Default::default()
},
];
match prsr.file_dump().await {
Ok(contacts) => {
assert!((contacts.len() > 0), "No contacts has been parsed");
let phone_numbers_1: std::collections::HashSet<_> =
contacts.iter().map(|p| p.phone_number.clone()).collect();
let phone_numbers_2: std::collections::HashSet<_> =
original.iter().map(|p| p.phone_number.clone()).collect();
assert_eq!(phone_numbers_1, phone_numbers_2, "No match");
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
};
}
#[tokio::test]
async fn test_save_file() {
let prsr = super::NumberParser {
filepath: String::from(TEST_NUMBERS_0),
};
let results = prsr.file_dump().await;
assert!(results.is_ok(), "File dump not successful");
let test_output_file: &str = "test-numbers.json";
let contacts = results.unwrap();
prsr.save_file(contacts, test_output_file).await;
let file_exists = {
let path = std::path::Path::new(test_output_file);
path.exists()
};
assert!(file_exists, "Contacts were not saved");
match std::fs::remove_file(test_output_file) {
Ok(_) => {
println!("File removed");
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
pub fn print_version() {
let name = env!("CARGO_PKG_NAME");
let version = env!("CARGO_PKG_VERSION");
println!("{name:?} {version:?}");
}
pub fn contains_version(args: &Vec<String>) -> bool {
let valid_flags = vec!["-v", "--version"];
for arg in args {
for valid_flag in &valid_flags {
if valid_flag == arg {
return true;
}
}
}
false
}