2
2
import argparse
3
3
import tarfile
4
4
import subprocess
5
+ import stat
5
6
6
7
7
- def is_exe (fpath ) :
8
+ def is_exe (fpath : str ) -> bool :
8
9
return os .path .isfile (fpath ) and os .access (fpath , os .X_OK )
9
10
10
11
11
12
def _usage () -> str :
12
13
return "\n " .join (
13
14
[
14
15
"Usage:" ,
15
- f"`tar_directory.py archive.tar directory [skip prefix ] [--exclude fileOrDir0 ... --exclude fileOrDirN]`" ,
16
+ f"`tar_directory.py [--tar-by-py ] [--exclude fileOrDir0 ... --exclude fileOrDirN] archive.tar directory [skip prefix ]`" ,
16
17
"or" ,
17
- f"`tar_directory.py archive. tar output_directory --extract`" ,
18
+ f"`tar_directory.py [-- tar-by-py] --extract archive.tar output_directory `" ,
18
19
]
19
20
)
20
21
21
22
22
23
def main ():
23
24
parser = argparse .ArgumentParser (description = 'Make or extract tar archive' )
24
25
parser .add_argument ('--extract' , action = "store_true" , default = False , help = "Extract archive" )
26
+ parser .add_argument ('--tar-by-py' , action = "store_true" , default = False , help = "Force use taring by python" )
25
27
parser .add_argument (
26
28
'--exclude' , type = str , action = 'append' , default = [], help = "Exclude for create archive (can use multiply times)"
27
29
)
@@ -42,14 +44,16 @@ def main():
42
44
directory = args .directory
43
45
prefix = args .prefix
44
46
45
- for tar_exe in ('/usr/bin/tar' , '/bin/tar' ):
47
+ if args .extract :
48
+ dest = os .path .abspath (directory )
49
+ if not os .path .exists (dest ):
50
+ os .makedirs (dest )
51
+
52
+ for tar_exe in ('/usr/bin/tar' , '/bin/tar' ) if not args .tar_by_py else []:
46
53
if not is_exe (tar_exe ):
47
54
continue
48
55
if args .extract :
49
- dest = os .path .abspath (directory )
50
- if not os .path .exists (dest ):
51
- os .makedirs (dest )
52
- os .execv (tar_exe , [tar_exe , '-xf' , tar , '-C' , dest ])
56
+ command = [tar_exe , '-xf' , tar , '-C' , dest ]
53
57
else :
54
58
source = os .path .relpath (directory , prefix ) if prefix else directory
55
59
command = (
@@ -59,29 +63,39 @@ def main():
59
63
+ (['-C' , prefix ] if prefix else [])
60
64
+ [source ]
61
65
)
62
- subprocess .run (command , check = True )
66
+ subprocess .run (command , check = True )
63
67
break
64
68
else :
65
69
if args .extract :
66
- dest = os .path .abspath (directory )
67
- if not os .path .exists (dest ):
68
- os .makedirs (dest )
69
70
with tarfile .open (tar , 'r' ) as tar_file :
70
71
tar_file .extractall (dest )
71
72
else :
72
73
source = directory
73
74
with tarfile .open (tar , 'w' ) as out :
74
75
75
- def filter (tarinfo ):
76
- for exclude in args .exclude :
77
- if tarinfo .name .endswith (exclude ):
78
- return None
76
+ def filter (tarinfo : tarfile .TarInfo ):
77
+ if args .exclude :
78
+ for exclude in args .exclude :
79
+ if tarinfo .name .endswith (exclude ):
80
+ return None
81
+ tarinfo .mode = stat .S_IXUSR | stat .S_IXGRP | stat .S_IXOTH if tarinfo .mode | stat .S_IXUSR else 0
82
+ tarinfo .mode = (
83
+ tarinfo .mode | stat .S_IRUSR | stat .S_IWUSR | stat .S_IRGRP | stat .S_IWGRP | stat .S_IROTH
84
+ )
85
+ # Set mtime to 1970-01-01 00:00:01, else if mtime == 0
86
+ # it not used here https://a.yandex-team.ru/arcadia/contrib/python/python-libarchive/py3/libarchive/__init__.py#L355
87
+ # But mtime != 0 also ignored by libarchive too :((
88
+ tarinfo .mtime = 1
89
+ tarinfo .uid = 0
90
+ tarinfo .gid = 0
91
+ tarinfo .uname = 'dummy'
92
+ tarinfo .gname = 'dummy'
79
93
return tarinfo
80
94
81
95
out .add (
82
96
os .path .abspath (source ),
83
97
arcname = os .path .relpath (source , prefix ) if prefix else source ,
84
- filter = filter if args . exclude else None ,
98
+ filter = filter ,
85
99
)
86
100
87
101
0 commit comments