@@ -131,14 +131,37 @@ def create_archive(source, target=None, interpreter=None, main=None,
131
131
elif not hasattr (target , 'write' ):
132
132
target = pathlib .Path (target )
133
133
134
+ # Create the list of files to add to the archive now, in case
135
+ # the target is being created in the source directory - we
136
+ # don't want the target being added to itself
137
+ files_to_add = sorted (source .rglob ('*' ))
138
+
139
+ # The target cannot be in the list of files to add. If it were, we'd
140
+ # end up overwriting the source file and writing the archive into
141
+ # itself, which is an error. We therefore check for that case and
142
+ # provide a helpful message for the user.
143
+
144
+ # Note that we only do a simple path equality check. This won't
145
+ # catch every case, but it will catch the common case where the
146
+ # source is the CWD and the target is a file in the CWD. More
147
+ # thorough checks don't provide enough value to justify the extra
148
+ # cost.
149
+
150
+ # If target is a file-like object, it will simply fail to compare
151
+ # equal to any of the entries in files_to_add, so there's no need
152
+ # to add a special check for that.
153
+ if target in files_to_add :
154
+ raise ZipAppError (
155
+ f"The target archive { target } overwrites one of the source files." )
156
+
134
157
with _maybe_open (target , 'wb' ) as fd :
135
158
_write_file_prefix (fd , interpreter )
136
159
compression = (zipfile .ZIP_DEFLATED if compressed else
137
160
zipfile .ZIP_STORED )
138
161
with zipfile .ZipFile (fd , 'w' , compression = compression ) as z :
139
- for child in sorted ( source . rglob ( '*' )) :
162
+ for child in files_to_add :
140
163
arcname = child .relative_to (source )
141
- if filter is None or filter (arcname ) and child . resolve () != arcname . resolve () :
164
+ if filter is None or filter (arcname ):
142
165
z .write (child , arcname .as_posix ())
143
166
if main_py :
144
167
z .writestr ('__main__.py' , main_py .encode ('utf-8' ))
0 commit comments