From 274ef7bcf924a0aa31087947e64ce221a4026576 Mon Sep 17 00:00:00 2001
From: KHUDIYEV ALI <ali.khudiyev@etu.unistra.fr>
Date: Mon, 31 Mar 2025 16:53:17 +0200
Subject: [PATCH] stand-alone sh files + example groff man

---
 README.md |   3 +
 init.sh   |  22 +++++++
 loit.sh   |  16 ++++++
 lore.sh   |  19 ++++++
 new.sh    |  14 +++++
 tree.sh   |  46 +++++++++++++++
 utils.sh  |  36 ++++++++++++
 xper.1    |  97 +++++++++++++++++++++++++++++++
 xper.sh   | 168 ++++++++++++++++--------------------------------------
 9 files changed, 302 insertions(+), 119 deletions(-)
 create mode 100755 init.sh
 create mode 100755 loit.sh
 create mode 100755 lore.sh
 create mode 100755 new.sh
 create mode 100755 tree.sh
 create mode 100755 utils.sh
 create mode 100644 xper.1

diff --git a/README.md b/README.md
index f44b2d8..0c212ec 100644
--- a/README.md
+++ b/README.md
@@ -65,3 +65,6 @@ Git also introduces strong overhead for what the xper tries to do. With **xper**
 need to switch between different branches to rerun other versions of the experiments or 
 just remind yourself how stupid you are. Everything is directory-based and you can switch 
 between different experiments as easily as switching between different directories.
+
+## TO DO
+
diff --git a/init.sh b/init.sh
new file mode 100755
index 0000000..f7726bb
--- /dev/null
+++ b/init.sh
@@ -0,0 +1,22 @@
+#!/bin/zsh
+
+init(){
+	export XPER_ROOT=$(pwd)
+	mkdir 001 2>/dev/null
+	mkdir .xper 2>/dev/null
+
+	if [ $? -eq 1 ]; then
+		printf "already initialized ;)\n"
+	fi
+	printf "cd into the 001/\n"
+
+	TAG="main"
+	if [ $# -gt 0 ]; then
+		TAG=$1
+	fi
+	printf "TAG=$TAG\n" >> .meta
+};
+
+if [ $# -eq 0 ] || [ $1 != "--import" ]; then
+	init $@
+fi
diff --git a/loit.sh b/loit.sh
new file mode 100755
index 0000000..4ea6ec3
--- /dev/null
+++ b/loit.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+loit(){
+	mkdir 001 2>/dev/null
+	if [ $? -eq 1 ]; then
+		printf "extension already exists; cd to 001/\n"
+	else
+		mv $(find . -d 1 -not -iname "001") 001/ 2>/dev/null
+		printf "extension created at 001/\n"
+		cd 001 && xper.sh exp
+	fi
+};
+
+if [ $# -eq 0 ] || [ $1 != "--import" ]; then
+	new $@
+fi
diff --git a/lore.sh b/lore.sh
new file mode 100755
index 0000000..46c724a
--- /dev/null
+++ b/lore.sh
@@ -0,0 +1,19 @@
+#!/bin/zsh
+
+. utils.sh --import
+
+lore(){
+	if [ $(pwd) = $XPER_ROOT ]; then
+		printf "cannot expand from the root folder\n"
+	else
+		maxnum=$(get_next_max_num)
+		# echo $maxnum
+		mkdir ../$maxnum
+		cp -r ./ ../$maxnum/ 2>/dev/null
+		printf "copied_from=$(pwd)\n" > ../$maxnum/.meta
+	fi
+};
+
+if [ $# -eq 0 ] || [ $1 != "--import" ]; then
+	lore $@
+fi
diff --git a/new.sh b/new.sh
new file mode 100755
index 0000000..8f9a97d
--- /dev/null
+++ b/new.sh
@@ -0,0 +1,14 @@
+#!/bin/zsh
+
+. utils.sh --import
+
+new(){
+	cd 001 2>/dev/null
+	dir=$(get_next_max_num)
+	cd .. && mkdir $dir && cd $dir
+	printf "copied_from=-1\n" >> .meta
+};
+
+if [ $# -eq 0 ] || [ $1 != "--import" ]; then
+	new $@
+fi
diff --git a/tree.sh b/tree.sh
new file mode 100755
index 0000000..42a0db2
--- /dev/null
+++ b/tree.sh
@@ -0,0 +1,46 @@
+#!/bin/zsh
+
+print_tree_from(){
+	local dir=$1
+	local depth=$2
+	local folders=($(find $dir -type d -d 1))
+	folders=($(echo $folders | xargs -n1 | sort | xargs))
+	# echo sorted folders are... $folders
+	if [ ${#folders} -eq 0 ]
+	then
+		return 0
+	fi
+
+	for folder in $folders
+	do
+		local dirname=$(echo $folder | sed -E "s/.*(\/[0-9][0-9][0-9])/\1/g")
+		# echo dirname=$dirname
+		if [[ $dirname =~ "[0-9][0-9][0-9]$" ]]
+		then
+			local spaces=0
+			while [ $spaces -lt $depth ]
+			do
+				printf "  "
+				spaces=$((spaces+1))
+			done
+			printf "$dirname\n"
+			print_tree_from $folder $((depth+1))
+		fi
+	done
+};
+
+tree(){
+	if [ $# -eq 0 ]; then
+		echo print all tree
+		cd $XPER_ROOT && ./xper.sh tree .
+	else
+		echo print tree from $1
+		cd $1
+		print_tree_from . 1
+		printf "\n"
+	fi
+}
+
+if [ $# -eq 0 ] || [ $1 != "--import" ]; then
+	tree $@
+fi
diff --git a/utils.sh b/utils.sh
new file mode 100755
index 0000000..9b6b61b
--- /dev/null
+++ b/utils.sh
@@ -0,0 +1,36 @@
+#!/bin/zsh
+
+get_next_max_num(){
+	local folders=($(find .. -type d -d 1))
+	local maxnum=0
+	# echo folders $folders
+
+	for folder in $folders
+	do
+		local num=$(expr $(echo $folder | sed -E "s/.*([0-9][0-9][0-9]).*/\1/g"))
+		# echo curr_$num
+		case "$num" in 
+			"" | *[!0-9]*) ;;
+			*) 
+				if [ $num -gt $maxnum ]
+				then 
+					maxnum=$num
+				fi 
+			;;
+		esac
+		# if [[ $num =~ "[0-9]+" ]] && [ $num -gt $maxnum ]
+		# then
+		# 	maxnum=$num
+		# 	# echo updated to maxnum=$maxnum
+		# fi
+	done
+
+	maxnum="$((maxnum+1))"
+	local numlen=${#maxnum}
+	while [ $numlen -lt 3 ]
+	do
+		maxnum=0$maxnum
+		numlen=$((numlen+1))
+	done
+	echo "$maxnum"
+};
diff --git a/xper.1 b/xper.1
new file mode 100644
index 0000000..b7be8f5
--- /dev/null
+++ b/xper.1
@@ -0,0 +1,97 @@
+.\" Man page for xper
+.TH XPER 1 "March 30, 2025" "1.0" "xper Manual"
+.SH NAME
+xper \- experiment version control tool for managing ML experiments
+.SH SYNOPSIS
+.B xper
+.I command
+.RI [ options ...]
+.SH DESCRIPTION
+.B xper
+is a tool designed for researchers, particularly in machine learning, to manage experiment directories in a hierarchical tree structure. Unlike traditional version control systems like
+.BR git (1),
+.B xper
+organizes experiments using directories and subdirectories, distinguishing between major changes (siblings) and minor tweaks (children). It provides commands to initialize, create, run, and search experiments, with results stored in a structured way.
+.SH COMMANDS
+.TP
+.B init
+Initialize an experiment directory with a default "root" tag. Creates a
+.I .xper
+subdirectory with metadata.
+.TP
+.BI "ment -t " tag
+Create an empty experiment subdirectory under the directory with the specified
+.I tag.
+.TP
+.BI "lore -t " tag
+Create a subdirectory under the directory with
+.I tag
+and copy the current directory's contents into it.
+.TP
+.BI "loit -t " tag
+Create two child subdirectories in the current directory and store
+.I tag
+in a hidden file.
+.TP
+.B tree
+Display the experiment tree, showing tagged directories and their hierarchy.
+.TP
+.BI "run -e " entry
+Run an experiment using the specified
+.I entry
+file, store results in a
+.I result
+subdirectory, and set the directory to read-only.
+.TP
+.B origin
+Navigate to the first non-empty experiment subdirectory in the current directory.
+.TP
+.BI "search -t " tag1 " -t " tag2
+Search for experiments or results matching the specified tags.
+.SH OPTIONS
+.TP
+.BI -t " tag"
+Specify a tag to identify an experiment directory (used by
+.BR ment ", " lore ", " loit ", and " search ).
+.TP
+.BI -e " entry"
+Specify the entry file (e.g., a script) to execute (used by
+.BR run ).
+.SH EXAMPLES
+.TP
+Initialize a new experiment directory:
+.B xper init
+.TP
+Create a new empty experiment tagged "model1":
+.B xper ment -t model1
+.TP
+Run an experiment with a Python script:
+.B xper run -e train.py
+.TP
+View the experiment tree:
+.B xper tree
+.TP
+Search for experiments with tags "model1" and "datasetA":
+.B xper search -t model1 -t datasetA
+.SH FILES
+.TP
+.I .xper/
+Directory containing experiment metadata, created by
+.BR init .
+.TP
+.I .xper/root.json
+JSON file storing tags and IDs for each experiment directory.
+.TP
+.I result/
+Subdirectory storing experiment outputs, created by
+.BR run .
+.SH SEE ALSO
+.BR git (1),
+.BR mkdir (1),
+.BR chmod (1)
+.SH AUTHOR
+Written by [Your Name].
+.SH BUGS
+The
+.B origin
+command's definition of "non-empty" is not yet standardized. Report bugs to [your contact].
diff --git a/xper.sh b/xper.sh
index cd3d1c9..d42dc01 100755
--- a/xper.sh
+++ b/xper.sh
@@ -1,131 +1,61 @@
 #!/bin/zsh
 
-get_next_max_num(){
-	local folders=($(find .. -type d -d 1))
-	local maxnum=0
-	# echo folders $folders
+if [ $# -eq 0 ]; then
+	printf "usage: xper [init|new|lore|loit|origin]
+\tinit    - to initialize the experiment directory (run first)
+\tnew     - to create an empty experiment subdirectory
+\tlore    - to run major modification of the current experiment in a sibling subdirectory
+\tloit    - to run minor modification of the current experiment in a child subdirectory
+\torigin  - to go to the leaf subdirectory */001 of the current experiment directory
 
-	for folder in $folders
-	do
-		local num=$(expr $(echo $folder | sed -E "s/.*([0-9][0-9][0-9]).*/\1/g"))
-		# echo curr_$num
-		case "$num" in 
-			"" | *[!0-9]*) ;;
-			*) 
-				if [ $num -gt $maxnum ]
-				then 
-					maxnum=$num
-				fi 
-			;;
-		esac
-		# if [[ $num =~ "[0-9]+" ]] && [ $num -gt $maxnum ]
-		# then
-		# 	maxnum=$num
-		# 	# echo updated to maxnum=$maxnum
-		# fi
-	done
+example 1: expr new -m 'from MLP-AE to CNN-AE'
+example 2: expr ext -m '5x more parametrized AE'
 
-	maxnum="$((maxnum+1))"
-	local numlen=${#maxnum}
-	while [ $numlen -lt 3 ]
-	do
-		maxnum=0$maxnum
-		numlen=$((numlen+1))
-	done
-	echo "$maxnum"
-};
+usage: xper tree [|<path>]
+usage: xper new --at-depth <d>
+\t --at-depth <d> - to run major modification of the current expriment in a sibling subdirectory created at depth absolute <d> or relative depth <-d> or <+d>
+\n"
+	exit
+fi
 
-print_tree_from(){
-	local dir=$1
-	local depth=$2
-	local folders=($(find $dir -type d -d 1))
-	folders=($(echo $folders | xargs -n1 | sort | xargs))
-	# echo sorted folders are... $folders
-	if [ ${#folders} -eq 0 ]
-	then
-		return 0
-	fi
+. init.sh    --import
+. new.sh     --import
+. lore.sh    --import
+. loit.sh    --import
+. tree.sh    --import
 
-	for folder in $folders
-	do
-		local dirname=$(echo $folder | sed -E "s/.*(\/[0-9][0-9][0-9])/\1/g")
-		# echo dirname=$dirname
-		if [[ $dirname =~ "[0-9][0-9][0-9]$" ]]
-		then
-			local spaces=0
-			while [ $spaces -lt $depth ]
-			do
-				printf "  "
-				spaces=$((spaces+1))
-			done
-			printf "$dirname\n"
-			print_tree_from $folder $((depth+1))
-		fi
-	done
-};
+CMD=$1
+shift
 
-main(){
-	if [ $# -eq 0 ]
-	then
-		printf "usage: xper [init|new|ext|origin]
-\tinit   - to initialize the experiment directory in the experiments folder (run first)
-\tnew    - to run major modification of the current experiment in a sibling subdirectory
-\text    - to run minor modification of the current experiment in a child subdirectory
-\torigin - to go to the leaf subdirectory */001 of the current experiment directory
+ARGS=()
+TAG=""
 
-  example 1: expr new -m 'from MLP-AE to CNN-AE'
-  example 2: expr ext -m '5x more parametrized AE'
+while [[ $# -gt 0 ]]; do
+	case $1 in
+		-t|--tag)
+			TAG="$2"
+			shift
+			shift
+			;;
+		*)
+			ARGS+=("$1")
+			shift
+			;;
+	esac
+done
 
-usage: xper tree [|<path>]
-usage: xper new --at-depth <d>
-\t --at-depth <d> - to run major modification of the current expriment in a sibling subdirectory created at depth absolute <d> or relative depth <-d> or <+d>
-\n"
-	elif [ $1 = "init" ]
-	then
-		export XPER_ROOT=$(pwd)
-		mkdir 001 2>/dev/null
-		mkdir .xper 2>/dev/null
-		if [ $? -eq 1 ]
-		then
-			printf "already initialized ;)\n"
-		fi
-		printf "cd into the 001/\n"
-	elif [ $1 = "new" ] || [ $1 = "exp" ]
-	then
-		if [ $(pwd) = $XPER_ROOT ]
-		then
-			printf "cannot expand from the root folder\n"
-		else
-			maxnum=$(get_next_max_num)
-			# echo $maxnum
-			mkdir ../$maxnum
-			cp -r ./ ../$maxnum/ 2>/dev/null
-		fi
-	elif [ $1 = "ext" ]
-	then
-		mkdir 001 2>/dev/null
-		if [ $? -eq 1 ]
-		then
-			printf "extension already exists; cd to 001/\n"
-		else
-			mv $(find . -d 1 -not -iname "001") 001/ 2>/dev/null
-			printf "extension created at 001/\n"
-			cd 001 && xper.sh exp
-		fi
-	elif [ $1 = "tree" ]
-	then
-		if [ $# -eq 1 ]
-		then
-			echo print all tree
-			cd $XPER_ROOT && ./xper.sh $1 .
-		else
-			echo print tree from $2
-			cd $2
-			print_tree_from . 1
-			printf "\n"
-		fi
-	elif [ $1 = "search" ]
-	then
+main(){
+	if [ $CMD = "init" ]; then
+		init $TAG
+	elif [ $CMD = "new" ]; then
+		new ${ARGS:2}
+	elif [ $CMD = "lore" ]; then
+		lore ${ARGS:2}
+	elif [ $CMD = "loit" ]; then
+		loit ${ARGS:2}
+	elif [ $CMD = "tree" ]; then
+		tree ${ARGS:2}
+	elif [ $CMD = "search" ]; then
 		echo search
 	else
 		echo hi there
-- 
GitLab