32 Commits
Author SHA1 Message Date
phoenixandphoenix c391939960 Update go (#20)
Reviewed-on: #20
Co-authored-by: phoenix <mail@kundeng.us>
Co-committed-by: phoenix <mail@kundeng.us>
2026-04-04 21:35:07 -04:00
phoenixandphoenix 340c90211f Package update (#19)
Reviewed-on: #19
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-12-26 21:31:04 +00:00
phoenixandphoenix e737280a3c Removed workflow file (#18)
Reviewed-on: #18
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-27 02:13:44 +00:00
phoenixandphoenix 18d1d2730f Refactoring (#17)
Reviewed-on: #17
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-27 02:10:51 +00:00
phoenixandphoenix fc1f3fa814 tsk-15: Update go version (#16)
Closes #15

Reviewed-on: #16
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-24 20:00:26 +00:00
phoenixandphoenix 3151405d32 Some major changes (#14)
Reviewed-on: #14
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-11-16 00:44:55 +00:00
phoenixandphoenix 154c9f493e print version (#13)
Reviewed-on: #13
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-27 23:55:39 +00:00
phoenixandphoenix 7e3fff50c1 golang version bump (#12)
Reviewed-on: #12
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-27 23:22:56 +00:00
phoenix 27d76c1c51 Go migration (#5)
Reviewed-on: #5
2025-09-01 22:14:19 +00:00
phoenixandphoenix 4a109467e3 add versioning (#11)
Reviewed-on: #11
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 22:13:29 +00:00
phoenixandphoenix 71c99cdb50 Update go (#10)
Reviewed-on: #10
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 21:54:32 +00:00
phoenixandphoenix 2c0a662733 Parser (#9)
Reviewed-on: #9
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-09-01 21:50:00 +00:00
phoenixandphoenix 6f9029d4e3 main code (#8)
Reviewed-on: #8
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-28 21:28:37 +00:00
phoenixandphoenix 75dd476d71 Initial go code (#7)
Reviewed-on: #7
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-27 19:36:32 +00:00
phoenixandphoenix c930c146e5 Remove rust code (#6)
Reviewed-on: #6
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-07-27 19:27:02 +00:00
phoenixandphoenix 903ada907f Version bump (#4)
Reviewed-on: #4
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:38:32 +00:00
phoenixandphoenix 2c916856e9 Update dependencies (#3)
Reviewed-on: #3
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:34:54 +00:00
phoenixandphoenix 42e39df59f Add readme (#2)
Reviewed-on: #2
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:31:50 +00:00
phoenixandphoenix 49842756ba Rust std change (#1)
Reviewed-on: #1
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-06-29 18:26:05 +00:00
KD 6743a808b9 Merge branch 'version_bump' into 'main'
Version bump

See merge request kdeng00/clean_file!4
2025-03-09 18:56:00 +00:00
KD b2116332ed Version bump 2025-03-09 18:56:00 +00:00
KD ad3c350707 Merge branch 'ver_up' into 'main'
Updating rust edition

See merge request kdeng00/clean_file!3
2025-03-09 03:10:00 +00:00
phoenix f4937514dd Updating rust edition 2025-03-08 22:08:20 -05:00
KD 04f0c03db7 Merge branch 'ci' into 'main'
Added workflow file

See merge request kdeng00/clean_file!1
2025-03-09 03:06:12 +00:00
phoenix c810a85da0 Added workflow file 2025-03-08 22:02:33 -05:00
phoenixandphoenix 936f07ad01 Updated serde and serde_json (#1)
Reviewed-on: #1
Co-authored-by: phoenix <kundeng94@gmail.com>
Co-committed-by: phoenix <kundeng94@gmail.com>
2025-02-10 02:23:36 +00:00
phoenix 156ab957fd Update .github/workflows/rust.yaml 2025-02-03 00:32:53 +00:00
phoenix ef6eba61a7 Update .github/workflows/rust.yaml 2025-02-03 00:32:31 +00:00
phoenix 59a5e1f678 Update .github/workflows/rust.yaml 2025-02-03 00:31:44 +00:00
phoenix e240276db7 Update .github/workflows/rust.yaml 2025-02-03 00:31:23 +00:00
phoenix c4f27e924d Update .github/workflows/rust.yaml 2025-02-03 00:29:11 +00:00
phoenix 42fc92925d Add .github/workflows/rust.yaml 2025-02-03 00:27:12 +00:00
15 changed files with 396 additions and 262 deletions
+44
View File
@@ -0,0 +1,44 @@
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 ./...
+3 -1
View File
@@ -1 +1,3 @@
/target /vendor
/clean_file
numbers.json
View File
-10
View File
@@ -1,10 +0,0 @@
[package]
name = "clean_file"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117"
+22
View File
@@ -0,0 +1,22 @@
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
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,39 @@
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
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,4 @@
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
@@ -0,0 +1,169 @@
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
@@ -0,0 +1,73 @@
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
@@ -0,0 +1,17 @@
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,
)
}
-39
View File
@@ -1,39 +0,0 @@
use std::env;
mod parser;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Provide path to file");
return;
}
let filepath: &String = args.get(1).unwrap();
println!("Filepath is: {:?}", filepath);
let myparser = parser::parser::NumberParser {
filepath: filepath.clone(),
};
let rawvalues = myparser.filedump();
let parsed_values = myparser.updatevalues(&rawvalues);
let newupdated = myparser.removedups(&parsed_values);
myparser.print_values(&newupdated, true);
let result = myparser.save_file(parsed_values);
match result {
Ok(o) => {
println!("Successfully saved file: {:?}", o);
}
Err(er) => {
println!("Error saving file: {:?}", er);
}
}
}
-212
View File
@@ -1,212 +0,0 @@
pub mod parser {
use std::collections::HashSet;
use std::fs::File;
use std::io::prelude::*;
use std::io::{BufRead, BufReader};
use serde::Deserialize;
use serde::Serialize;
#[derive(Clone, Deserialize, Serialize)]
pub struct SomeObject {
pub value: String,
}
pub struct NumberParser {
pub filepath: String,
}
impl NumberParser {
pub fn filedump(&self) -> Vec<SomeObject> {
println!("\nDumping files");
let mut objs: Vec<SomeObject> = Vec::new();
if let Ok(lines) = self.read_lines(&self.filepath) {
for line in lines {
if let Ok(phonenumber) = line {
let contains_letters = phonenumber.chars().any(|c| c.is_alphabetic());
if contains_letters {
continue;
}
let myobj: SomeObject = SomeObject { value: phonenumber };
if !myobj.value.is_empty() {
objs.push(myobj);
}
}
}
}
return objs;
}
pub fn updatevalues(&self, vals: &Vec<SomeObject>) -> Vec<SomeObject> {
println!("\nUpdating values");
let mut updated: Vec<SomeObject> = Vec::new();
for a in vals {
let mut parsed: String = a.value.clone();
if a.value.len() < 2 {
println!("{} is an invalid number", a.value);
continue;
}
let pars = self.remove_some_data(&parsed);
parsed.clear();
parsed = pars;
println!("{}", parsed.clone());
let updated_parsed = self.add_prefix(parsed);
let myobj: SomeObject = SomeObject {
value: updated_parsed.clone(),
};
updated.push(myobj);
}
return updated;
}
pub fn removedups(&self, vals: &Vec<SomeObject>) -> Vec<SomeObject> {
println!("\nRemoving duplicates");
let mut tmp: HashSet<String> = HashSet::new();
let mut mm: Vec<SomeObject> = Vec::new();
mm.clone_from(vals);
mm.retain(|e| tmp.insert(e.value.clone()));
let mut updated: Vec<SomeObject> = Vec::new();
for t in tmp {
let so: SomeObject = SomeObject { value: t.clone() };
updated.push(so);
}
return updated;
}
pub fn print_values(&self, vals: &Vec<SomeObject>, print_total: bool) {
println!("\nPrinting values");
for o in vals {
println!("Value: {}", o.value);
}
if print_total {
println!("\nTotal numbers: {:?}", vals.len());
}
}
pub fn save_file(&self, vals: Vec<SomeObject>) -> std::io::Result<()> {
println!("\nSaving file");
let filename: String = String::from("numbers.json");
let mut all_numbers: Vec<String> = Vec::new();
for val in &vals {
all_numbers.push(val.value.clone());
}
let json = serde_json::to_string_pretty(&all_numbers).unwrap();
let mut file = File::create(filename)?;
file.write_all(json.as_bytes())?;
Ok(())
}
fn read_lines(&self, filename: &str) -> std::io::Result<std::io::Lines<BufReader<File>>> {
let file = File::open(filename)?;
Ok(BufReader::new(file).lines())
}
fn remove_some_data(&self, unparsed: &String) -> String {
println!("Unparsed: {}", unparsed);
let mut parsed: String = String::new();
let mychars = unparsed.chars();
for i in 0..unparsed.len() {
let mychar_wrap = mychars.clone().nth(i);
if let None = mychar_wrap {
continue;
}
let mychar = mychar_wrap.unwrap();
if mychar.is_numeric() {
parsed.push(mychar.clone());
}
}
println!("Parsed: {}", parsed);
return parsed;
}
fn add_prefix(&self, raw: String) -> String {
let mut mychars = raw.chars().clone();
let first_char: char = mychars.nth(0).clone().unwrap();
let second_char: char = mychars.nth(1).clone().unwrap();
let mut parsed: String = raw.clone();
if first_char == '1' {
parsed.insert(0, '+');
} else if first_char != '+' {
if second_char != '1' {
parsed.insert(0, '+');
parsed.insert(1, '1');
} else {
parsed.insert(0, '+');
parsed.insert(1, '1');
}
}
return parsed;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn removing_text() {
let sometext: String = String::from("a1234567890");
let numberparser = NumberParser {
filepath: String::new(),
};
let removetext = numberparser.remove_some_data(&sometext);
let mut result = true;
for i in 0..removetext.len() {
let c = removetext.chars().nth(i).unwrap();
if !c.is_numeric() {
result = false;
break;
}
}
assert_eq!(result, true);
}
#[test]
fn adding_prefix() {
let sometext: String = String::from("1234567890");
let numberparser = NumberParser {
filepath: String::new(),
};
let modified = numberparser.add_prefix(sometext);
let chars = modified.chars().clone();
let firstcharcheck: char = chars.clone().nth(0).unwrap();
let secondcharcheck: char = chars.clone().nth(1).unwrap();
assert_eq!(firstcharcheck, '+');
assert_eq!(secondcharcheck, '1');
}
}
}
+10
View File
@@ -0,0 +1,10 @@
(217) 555-0194
(602) 555-0177
(713) 555-0167
(608) 555-0190
(305) 555-0112
(415) 555-0135
(608) 555-0190
(602) 555-0177
(317) 555-0123
(360) 555-0158