FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
python_treeLsCat/python_treeLsCat.py at master · mamba73/python_treeLsCat · GitHub
mamba73
/
python_treeLsCat
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
python_treeLsCat
/
python_treeLsCat.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
151 lines (121 loc) · 5.26 KB
Breadcrumbs
python_treeLsCat
/
python_treeLsCat.py
Copy path
File metadata and controls
151 lines (121 loc) · 5.26 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
# -*- coding: utf-8 -*-
import
os
import
datetime
import
configparser
from
pathlib
import
Path
import
pathspec
def
log
(
message
):
"""Prints a debug message with a timestamp."""
timestamp
=
datetime
.
datetime
.
now
().
strftime
(
"%Y-%m-%d %H:%M:%S"
)
print
(
f"[
{
timestamp
}
] [DEBUG]
{
message
}
"
)
def
is_binary
(
file_path
):
"""
Checks if a file is binary by looking for a null byte in the first 1024 bytes.
This is a reliable way to skip .dll, .exe, .so, etc.
"""
try
:
with
open
(
file_path
,
'rb'
)
as
f
:
chunk
=
f
.
read
(
1024
)
return
b'
\x00
'
in
chunk
except
:
return
True
# Treat as binary if unreadable
def
ensure_config_exists
(
config_path
):
"""Creates a default config.ini if it does not exist."""
if
not
os
.
path
.
exists
(
config_path
):
log
(
f"Configuration file
{
config_path
}
not found. Creating default..."
)
config
=
configparser
.
ConfigParser
()
config
[
'SETTINGS'
]
=
{
'PATH'
:
r'C:\Path\To\Your\Project'
,
'SAVE'
:
'project_export.txt'
}
with
open
(
config_path
,
'w'
,
encoding
=
'utf-8'
)
as
configfile
:
config
.
write
(
configfile
)
log
(
f"Created
{
config_path
}
. Please edit the PATH variable in it."
)
def
get_gitignore_spec
(
root_path
):
"""Reads .gitignore and always ignores .git directory."""
gitignore_path
=
os
.
path
.
join
(
root_path
,
".gitignore"
)
patterns
=
[
'.git/'
]
if
os
.
path
.
exists
(
gitignore_path
):
log
(
"Loading .gitignore rules..."
)
with
open
(
gitignore_path
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
patterns
.
extend
(
f
.
readlines
())
return
pathspec
.
PathSpec
.
from_lines
(
'gitwildmatch'
,
patterns
)
def
generate_tree
(
dir_path
,
spec
,
root_path
,
prefix
=
""
):
"""Generates a directory tree respecting .gitignore."""
tree_str
=
""
dir_obj
=
Path
(
dir_path
)
try
:
entries
=
sorted
(
list
(
dir_obj
.
iterdir
()),
key
=
lambda
x
: (
not
x
.
is_dir
(),
x
.
name
.
lower
()))
except
(
PermissionError
,
FileNotFoundError
):
return
f"
{
prefix
}
[Access Denied]
\n
"
filtered_entries
=
[]
for
x
in
entries
:
rel_path
=
os
.
path
.
relpath
(
str
(
x
),
root_path
)
match_path
=
rel_path
+
(
"/"
if
x
.
is_dir
()
else
""
)
if
not
spec
.
match_file
(
match_path
)
or
x
.
name
==
".gitignore"
:
filtered_entries
.
append
(
x
)
for
i
,
path
in
enumerate
(
filtered_entries
):
is_last
=
(
i
==
len
(
filtered_entries
)
-
1
)
connector
=
"└─ "
if
is_last
else
"├─ "
tree_str
+=
f"
{
prefix
}
{
connector
}
{
path
.
name
}
{
'/'
if
path
.
is_dir
()
else
''
}
\n
"
if
path
.
is_dir
():
extension
=
" "
if
is_last
else
"│ "
tree_str
+=
generate_tree
(
path
,
spec
,
root_path
,
prefix
+
extension
)
return
tree_str
def
run_scanner
():
log
(
"Aplication python_treeLsCat started."
)
config_file
=
'config.ini'
ensure_config_exists
(
config_file
)
config
=
configparser
.
ConfigParser
()
config
.
read
(
config_file
,
encoding
=
'utf-8'
)
raw_path
=
config
.
get
(
'SETTINGS'
,
'PATH'
,
fallback
=
'./'
)
root_path
=
os
.
path
.
abspath
(
os
.
path
.
normpath
(
raw_path
))
save_filename
=
config
.
get
(
'SETTINGS'
,
'SAVE'
,
fallback
=
'export.txt'
)
save_dir
=
"./save"
if
not
os
.
path
.
isdir
(
root_path
):
log
(
f"ERROR: Path '
{
root_path
}
' not found."
)
return
if
not
os
.
path
.
exists
(
save_dir
):
os
.
makedirs
(
save_dir
)
output_path
=
Path
(
save_dir
)
/
save_filename
# Handle filename collision with numbering
base
,
ext
=
output_path
.
stem
,
output_path
.
suffix
counter
=
1
while
output_path
.
exists
():
output_path
=
Path
(
save_dir
)
/
f"
{
base
}
_
{
counter
}
{
ext
}
"
counter
+=
1
spec
=
get_gitignore_spec
(
root_path
)
log
(
f"Scanning:
{
root_path
}
"
)
with
open
(
output_path
,
"w"
,
encoding
=
"utf-8"
)
as
out_file
:
# 1. TREE
out_file
.
write
(
f"PROJECT STRUCTURE:
{
os
.
path
.
basename
(
root_path
)
}
\n
"
)
out_file
.
write
(
"-"
*
30
+
"
\n
"
)
out_file
.
write
(
generate_tree
(
root_path
,
spec
,
root_path
))
out_file
.
write
(
"
\n
"
+
"="
*
60
+
"
\n
\n
"
)
# 2. CONTENT
for
root
,
dirs
,
files
in
os
.
walk
(
root_path
):
# Prune ignored directories
dirs
[:]
=
[
d
for
d
in
dirs
if
not
spec
.
match_file
(
os
.
path
.
relpath
(
os
.
path
.
join
(
root
,
d
),
root_path
)
+
"/"
)]
dirs
.
sort
()
files
.
sort
()
for
file
in
files
:
full_path
=
os
.
path
.
join
(
root
,
file
)
rel_path
=
os
.
path
.
relpath
(
full_path
,
root_path
)
# Skip if ignored by gitignore
if
spec
.
match_file
(
rel_path
)
and
file
!=
".gitignore"
:
continue
# SKIP BINARY FILES (dll, exe, images, etc.)
if
is_binary
(
full_path
):
log
(
f"Skipping binary file:
{
rel_path
}
"
)
continue
log
(
f"Reading file:
{
rel_path
}
"
)
out_file
.
write
(
f"
{
rel_path
}
\n
---
\n
"
)
try
:
with
open
(
full_path
,
"r"
,
encoding
=
"utf-8"
,
errors
=
"ignore"
)
as
f
:
out_file
.
write
(
f
.
read
())
except
Exception
as
e
:
out_file
.
write
(
f"[Error:
{
e
}
]"
)
out_file
.
write
(
"
\n
---
\n
---
\n
"
)
log
(
f"Completed! Output:
{
output_path
}
"
)
if
__name__
==
"__main__"
:
run_scanner
()
Back
|
FazBrowse Home
|
New Git URL