Repository navigation
Expand file tree
/
Copy pathcreate-project.sh
More file actions
executable file
·179 lines (162 loc) · 4.03 KB
/
Copy pathcreate-project.sh
File metadata and controls
executable file
·179 lines (162 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/bin/bash
# Fail fast: a failed mkdir/touch/R call must abort instead of falling
# through to the success message at the end
set -euo pipefail
# Default directories
# May be adjusted based on the -l option
dirs=(
"data"
"data/input"
"data/output"
"documentation"
"config"
"notebooks"
"src"
"scripts"
"research"
"plans"
"handoffs"
)
# Define files
files=(
".gitignore"
"LICENSE"
"README.md"
)
# Handle optional flags
# -l flag for language-specific directories
# -p path
lang=""
path=""
# Function to convert string to lowercase
to_lowercase() {
echo "$1" | tr '[:upper:]' '[:lower:]'
}
while getopts ":l:p:" opt; do
case $opt in
l)
lang=$(to_lowercase "$OPTARG")
;;
p)
path="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
# Enforce required -p flag (no implicit current-directory behavior)
if [[ -z "$path" ]]; then
echo "Error: -p <path> is required. Use -p . to target the current directory." >&2
exit 1
fi
# Check if the specified path exists
if [[ ! -d "$path" ]]; then
echo "Error: The specified path '$path' does not exist." >&2
exit 1
fi
# Adjust the directories based on the -l flag
if [[ "$lang" == "r" || "$lang" == "py" || "$lang" == "python" ]]; then
dirs+=("tests")
elif [[ "$lang" == "jl" || "$lang" == "julia" ]]; then
dirs+=("test")
else
dirs+=("test" "tests")
fi
# R reads .Renviron at startup for project-level environment variables
if [[ "$lang" == "r" ]]; then
files+=(".Renviron")
fi
# Create directories
echo "Creating directories at $path..."
for dir in "${dirs[@]}"; do
mkdir -p "$path/$dir"
echo "Created $path/$dir"
done
# Create files
echo "Creating files at $path..."
for file in "${files[@]}"; do
touch "$path/$file"
echo "Created $path/$file"
done
# Sensible default .gitignore entries.
# Universal entries apply to every project; language entries are
# appended based on -l. Appends are idempotent so re-runs do not
# duplicate lines.
gitignore_lines=(
".env"
".env.*"
"!.env.example"
"/.roborev/"
".DS_Store"
"Thumbs.db"
"Desktop.ini"
".vscode/"
".idea/"
"*.swp"
"*.log"
)
case "$lang" in
r)
gitignore_lines+=(
".Renviron"
".Rproj.user/"
".Rhistory"
".RData"
".Ruserdata"
)
;;
py|python)
gitignore_lines+=(
"__pycache__/"
"*.py[cod]"
".venv/"
"venv/"
".pytest_cache/"
".mypy_cache/"
".ruff_cache/"
".ipynb_checkpoints/"
"*.egg-info/"
"dist/"
"build/"
)
;;
jl|julia)
gitignore_lines+=("*.jl.cov" "*.jl.mem")
;;
esac
# Append each missing pattern, keeping existing content intact
for line in "${gitignore_lines[@]}"; do
if ! grep -qxF "$line" "$path/.gitignore"; then
# Prepend a newline if the file lacks a trailing one, so we
# append a line instead of gluing onto the previous one
if [[ -s "$path/.gitignore" ]] &&
[[ -n "$(tail -c 1 "$path/.gitignore")" ]]; then
printf '\n' >> "$path/.gitignore"
fi
printf '%s\n' "$line" >> "$path/.gitignore"
fi
done
# Only if R is selected and the path is not empty
# 1. If not already installed, install renv in the base R env as it's best practice to use project envs
# 2. Initialize the project env in the project path
# 3. Install usethis
# 4. Create an RStudio .Rproj file
if [[ "$lang" == "r" && -n "$path" ]]; then
# A missing or failing R must fail the run, not print a success message
if ! R -e "
if (!require('renv', quietly = TRUE)){
install.packages('renv', repos='http://cran.us.r-project.org')}
renv::init(project = '$path')
q(save = 'no')"; then
echo "Error: R failed; project setup is incomplete." >&2
exit 1
fi
fi
# The end
echo "Project structure created successfully at $path!"