1+ #! /bin/bash
2+
3+ set -e
4+
5+ # Configuration - Edit these arrays to customize what to skip
6+ SKIP_EXTENSIONS=(
7+ " jpg"
8+ " jpeg"
9+ " png"
10+ " gif"
11+ " bmp"
12+ " tiff"
13+ " webp"
14+ " ico"
15+ " svg"
16+ " pdf"
17+ " zip"
18+ " tar"
19+ " gz"
20+ " 7z"
21+ " rar"
22+ " mp3"
23+ " mp4"
24+ " avi"
25+ " mov"
26+ " wmv"
27+ " flv"
28+ " wav"
29+ " ogg"
30+ " sh"
31+ " md"
32+ )
33+
34+ SKIP_PATHS=(
35+ " node_modules/"
36+ " .git/"
37+ " vendor/"
38+ " storage/"
39+ " bootstrap/cache/"
40+ " public/storage/"
41+ " .env"
42+ " .env.*"
43+ " composer.lock"
44+ " package-lock.json"
45+ " yarn.lock"
46+ " *.log"
47+ " *.tmp"
48+ " *.cache"
49+ " .DS_Store"
50+ " Thumbs.db"
51+ " code/tests/Feature/"
52+ " code/tests/Integration/"
53+ " code/tests/Unit/"
54+ )
55+
56+ # Colors for output
57+ RED=' \033[0;31m'
58+ GREEN=' \033[0;32m'
59+ YELLOW=' \033[1;33m'
60+ BLUE=' \033[0;34m'
61+ NC=' \033[0m' # No Color
62+
63+ print_usage () {
64+ echo " Usage: $0 <remote_project_path> [options]"
65+ echo " "
66+ echo " Options:"
67+ echo " -h, --help Show this help message"
68+ echo " -n, --dry-run Show what would be copied without actually copying"
69+ echo " -f, --force Copy files without prompting for confirmation"
70+ echo " -v, --verbose Verbose output"
71+ echo " --skip-ext EXT Skip files with extension EXT (can be used multiple times)"
72+ echo " --skip-path PATH Skip files matching PATH pattern (can be used multiple times)"
73+ echo " "
74+ echo " Examples:"
75+ echo " $0 /path/to/remote/project"
76+ echo " $0 /path/to/remote/project --dry-run"
77+ echo " $0 /path/to/remote/project --skip-ext txt --skip-path 'temp/'"
78+ }
79+
80+ should_skip_file () {
81+ local file=" $1 "
82+ local basename=$( basename " $file " )
83+ local extension=" ${basename##* .} "
84+
85+ # Skip if extension is in SKIP_EXTENSIONS
86+ for skip_ext in " ${SKIP_EXTENSIONS[@]} " ; do
87+ if [[ " $extension " == " $skip_ext " ]]; then
88+ return 0
89+ fi
90+ done
91+
92+ # Special case: Skip code/app/ but NOT code/app/Athenia/
93+ if [[ " $file " == code/app/* ]] && [[ " $file " != code/app/Athenia/* ]]; then
94+ return 0
95+ fi
96+
97+ # Skip if path matches any pattern in SKIP_PATHS
98+ for skip_path in " ${SKIP_PATHS[@]} " ; do
99+ if [[ " $file " == * " $skip_path " * ]]; then
100+ return 0
101+ fi
102+ done
103+
104+ return 1
105+ }
106+
107+ compare_files () {
108+ local main_file=" $1 "
109+ local remote_file=" $2 "
110+
111+ # If remote file doesn't exist, we can't pull it
112+ if [ ! -f " $remote_file " ]; then
113+ return 1
114+ fi
115+
116+ # If main file doesn't exist, it's definitely different
117+ if [ ! -f " $main_file " ]; then
118+ return 0
119+ fi
120+
121+ # Compare files byte-for-byte
122+ if ! diff -q " $main_file " " $remote_file " > /dev/null 2>&1 ; then
123+ return 0
124+ fi
125+
126+ return 1
127+ }
128+
129+ # Parse command line arguments
130+ REMOTE_PATH=" "
131+ DRY_RUN=false
132+ FORCE=false
133+ VERBOSE=false
134+
135+ while [[ $# -gt 0 ]]; do
136+ case $1 in
137+ -h|--help)
138+ print_usage
139+ exit 0
140+ ;;
141+ -n|--dry-run)
142+ DRY_RUN=true
143+ shift
144+ ;;
145+ -f|--force)
146+ FORCE=true
147+ shift
148+ ;;
149+ -v|--verbose)
150+ VERBOSE=true
151+ shift
152+ ;;
153+ --skip-ext)
154+ SKIP_EXTENSIONS+=(" $2 " )
155+ shift 2
156+ ;;
157+ --skip-path)
158+ SKIP_PATHS+=(" $2 " )
159+ shift 2
160+ ;;
161+ -* )
162+ echo " Unknown option: $1 "
163+ print_usage
164+ exit 1
165+ ;;
166+ * )
167+ if [ -z " $REMOTE_PATH " ]; then
168+ REMOTE_PATH=" $1 "
169+ else
170+ echo " Too many arguments"
171+ print_usage
172+ exit 1
173+ fi
174+ shift
175+ ;;
176+ esac
177+ done
178+
179+ if [ -z " $REMOTE_PATH " ]; then
180+ echo " Error: Remote project path is required"
181+ print_usage
182+ exit 1
183+ fi
184+
185+ if [ ! -d " $REMOTE_PATH " ]; then
186+ echo " Error: Remote project path does not exist: $REMOTE_PATH "
187+ exit 1
188+ fi
189+
190+ # Get absolute paths
191+ REMOTE_PATH=$( cd " $REMOTE_PATH " && pwd)
192+ MAIN_PATH=$( pwd)
193+
194+ echo -e " ${BLUE} Pulling changes from: ${NC} $REMOTE_PATH "
195+ echo -e " ${BLUE} To main project: ${NC} $MAIN_PATH "
196+ echo " "
197+
198+ # Get all tracked files in the main project
199+ TRACKED_FILES=()
200+ while IFS= read -r line; do
201+ TRACKED_FILES+=(" $line " )
202+ done < <( git ls-files)
203+
204+ # Arrays to store results
205+ DIFFERENT_FILES=()
206+ SKIPPED_FILES=()
207+ MISSING_FILES=()
208+
209+ echo -e " ${BLUE} Analyzing files...${NC} "
210+
211+ # Check each tracked file
212+ for file in " ${TRACKED_FILES[@]} " ; do
213+ if should_skip_file " $file " ; then
214+ SKIPPED_FILES+=(" $file " )
215+ [ " $VERBOSE " = true ] && echo -e " ${YELLOW} SKIP: ${NC} $file "
216+ continue
217+ fi
218+
219+ main_file=" $MAIN_PATH /$file "
220+ remote_file=" $REMOTE_PATH /$file "
221+
222+ if [ ! -f " $remote_file " ]; then
223+ MISSING_FILES+=(" $file " )
224+ [ " $VERBOSE " = true ] && echo -e " ${RED} MISSING: ${NC} $file (not found in remote)"
225+ continue
226+ fi
227+
228+ if compare_files " $main_file " " $remote_file " ; then
229+ DIFFERENT_FILES+=(" $file " )
230+ [ " $VERBOSE " = true ] && echo -e " ${GREEN} DIFF: ${NC} $file "
231+ else
232+ [ " $VERBOSE " = true ] && echo -e " SAME: $file "
233+ fi
234+ done
235+
236+ echo " "
237+ echo -e " ${BLUE} Analysis complete:${NC} "
238+ echo -e " ${GREEN} Different files: ${NC}${# DIFFERENT_FILES[@]} "
239+ echo -e " ${YELLOW} Skipped files: ${NC}${# SKIPPED_FILES[@]} "
240+ echo -e " ${RED} Missing files: ${NC}${# MISSING_FILES[@]} "
241+ echo " "
242+
243+ if [ ${# DIFFERENT_FILES[@]} -eq 0 ]; then
244+ echo -e " ${GREEN} No differences found. All files are up to date.${NC} "
245+ exit 0
246+ fi
247+
248+ # Show what will be copied
249+ echo -e " ${BLUE} Files that are DIFFERENT and will be copied from remote:${NC} "
250+ for file in " ${DIFFERENT_FILES[@]} " ; do
251+ echo " $file "
252+ done
253+
254+ if [ ${# MISSING_FILES[@]} -gt 0 ]; then
255+ echo " "
256+ echo -e " ${RED} Files missing in remote project (will NOT be copied):${NC} "
257+ for file in " ${MISSING_FILES[@]} " ; do
258+ echo " $file "
259+ done
260+ fi
261+
262+ echo " "
263+
264+ # Ask for confirmation unless forced or dry run
265+ if [ " $DRY_RUN " = true ]; then
266+ echo -e " ${YELLOW} DRY RUN: Would copy ${# DIFFERENT_FILES[@]} different files${NC} "
267+ exit 0
268+ fi
269+
270+ if [ " $FORCE " = false ]; then
271+ echo -n " Do you want to proceed with copying these ${# DIFFERENT_FILES[@]} DIFFERENT files? (y/N): "
272+ read -r response
273+ if [[ ! " $response " =~ ^[Yy]$ ]]; then
274+ echo " Aborted."
275+ exit 0
276+ fi
277+ fi
278+
279+ # Create report file
280+ TIMESTAMP=$( date +%Y%m%d_%H%M%S)
281+ REPORT_FILE=" $MAIN_PATH /pull_report_$TIMESTAMP .txt"
282+
283+ echo " Pull Report - $( date) " > " $REPORT_FILE "
284+ echo " Remote: $REMOTE_PATH " >> " $REPORT_FILE "
285+ echo " Main: $MAIN_PATH " >> " $REPORT_FILE "
286+ echo " " >> " $REPORT_FILE "
287+
288+ # Copy files
289+ echo -e " ${BLUE} Copying files...${NC} "
290+ COPIED_COUNT=0
291+ FAILED_COUNT=0
292+
293+ for file in " ${DIFFERENT_FILES[@]} " ; do
294+ main_file=" $MAIN_PATH /$file "
295+ remote_file=" $REMOTE_PATH /$file "
296+
297+ # Create directory if it doesn't exist
298+ mkdir -p " $( dirname " $main_file " ) "
299+
300+ # Copy file
301+ if cp " $remote_file " " $main_file " ; then
302+ echo -e " ${GREEN} ✓${NC} $file "
303+ echo " COPIED: $file " >> " $REPORT_FILE "
304+ (( COPIED_COUNT++ ))
305+ else
306+ echo -e " ${RED} ✗${NC} $file "
307+ echo " FAILED: $file " >> " $REPORT_FILE "
308+ (( FAILED_COUNT++ ))
309+ fi
310+ done
311+
312+ # Add skipped and missing files to report
313+ if [ ${# SKIPPED_FILES[@]} -gt 0 ]; then
314+ echo " " >> " $REPORT_FILE "
315+ echo " SKIPPED FILES:" >> " $REPORT_FILE "
316+ for file in " ${SKIPPED_FILES[@]} " ; do
317+ echo " $file " >> " $REPORT_FILE "
318+ done
319+ fi
320+
321+ if [ ${# MISSING_FILES[@]} -gt 0 ]; then
322+ echo " " >> " $REPORT_FILE "
323+ echo " MISSING FILES:" >> " $REPORT_FILE "
324+ for file in " ${MISSING_FILES[@]} " ; do
325+ echo " $file " >> " $REPORT_FILE "
326+ done
327+ fi
328+
329+ echo " "
330+ echo -e " ${BLUE} Summary:${NC} "
331+ echo -e " ${GREEN} Successfully copied: ${NC} $COPIED_COUNT files"
332+ if [ $FAILED_COUNT -gt 0 ]; then
333+ echo -e " ${RED} Failed to copy: ${NC} $FAILED_COUNT files"
334+ fi
335+ echo -e " ${BLUE} Report saved to: ${NC} $REPORT_FILE "
336+
337+ # Git status
338+ echo " "
339+ echo -e " ${BLUE} Git status:${NC} "
340+ git status --porcelain
341+
342+ exit 0
0 commit comments