2
2
3
3
Utility functions for manipulating directories and directory trees."""
4
4
5
- import errno
5
+ import itertools
6
6
import os
7
+ import pathlib
7
8
8
9
from ._log import log
9
10
from .errors import DistutilsFileError , DistutilsInternalError
13
14
_path_created = set ()
14
15
15
16
16
- def mkpath (name , mode = 0o777 , verbose = True , dry_run = False ): # noqa: C901
17
+ def mkpath (name , mode = 0o777 , verbose = True , dry_run = False ):
17
18
"""Create a directory and any missing ancestor directories.
18
19
19
20
If the directory already exists (or if 'name' is the empty string, which
@@ -22,12 +23,6 @@ def mkpath(name, mode=0o777, verbose=True, dry_run=False): # noqa: C901
22
23
(eg. some sub-path exists, but is a file rather than a directory).
23
24
If 'verbose' is true, log the directory created.
24
25
Return the list of directories actually created.
25
-
26
- os.makedirs is not used because:
27
-
28
- a) It's new to Python 1.5.2, and
29
- b) it blows up if the directory already exists (in which case it should
30
- silently succeed).
31
26
"""
32
27
33
28
global _path_created
@@ -36,47 +31,24 @@ def mkpath(name, mode=0o777, verbose=True, dry_run=False): # noqa: C901
36
31
if not isinstance (name , str ):
37
32
raise DistutilsInternalError (f"mkpath: 'name' must be a string (got { name !r} )" )
38
33
39
- name = os .path .normpath (name )
40
-
41
- if verbose and not os .path .isdir (name ):
42
- log .info ("creating %s" , name )
43
-
44
- created_dirs = []
45
- if os .path .isdir (name ) or name == '' :
46
- return created_dirs
47
- if os .path .abspath (name ) in _path_created :
48
- return created_dirs
34
+ name = pathlib .Path (name )
49
35
50
- ( head , tail ) = os . path . split (name )
51
- tails = [ tail ] # stack of lone dirs to create
36
+ if str (name . absolute ()) in _path_created :
37
+ return
52
38
53
- while head and tail and not os .path .isdir (head ):
54
- (head , tail ) = os .path .split (head )
55
- tails .insert (0 , tail ) # push next higher dir onto stack
39
+ if verbose and not name .is_dir ():
40
+ log .info ("creating %s" , name )
56
41
57
- # now 'head' contains the deepest directory that already exists
58
- # (that is, the child of 'head' in 'name' is the highest directory
59
- # that does *not* exist)
60
- for d in tails :
61
- # print "head = %s, d = %s: " % (head, d),
62
- head = os .path .join (head , d )
63
- abs_head = os .path .abspath (head )
42
+ ancestry = itertools .chain ((name ,), name .parents )
43
+ missing = (path for path in ancestry if not path .is_dir ())
64
44
65
- if abs_head in _path_created :
66
- continue
45
+ try :
46
+ dry_run or name .mkdir (mode = mode , parents = True , exist_ok = True )
47
+ _path_created .add (name .absolute ())
48
+ except OSError as exc :
49
+ raise DistutilsFileError (f"could not create '{ name } ': { exc .args [- 1 ]} " )
67
50
68
- if not dry_run :
69
- try :
70
- os .mkdir (head , mode )
71
- except OSError as exc :
72
- if not (exc .errno == errno .EEXIST and os .path .isdir (head )):
73
- raise DistutilsFileError (
74
- f"could not create '{ head } ': { exc .args [- 1 ]} "
75
- )
76
- created_dirs .append (head )
77
-
78
- _path_created .add (abs_head )
79
- return created_dirs
51
+ return list (map (str , missing ))
80
52
81
53
82
54
def create_tree (base_dir , files , mode = 0o777 , verbose = True , dry_run = False ):
0 commit comments