4
4
# --- BEGIN_HEADER ---
5
5
#
6
6
# addheader - add license header to all code modules.
7
- # Copyright (C) 2009-2024 The MiG Project by the Science HPC Center at UCPH
7
+ # Copyright (C) 2009-2025 The MiG Project by the Science HPC Center at UCPH
8
8
#
9
9
# This file is part of MiG.
10
10
#
26
26
# --- END_HEADER ---
27
27
#
28
28
29
- """Search code tree and add the required header to all python modules"""
29
+ """Search code tree and add the required header to all python modules."""
30
+
30
31
from __future__ import print_function
31
32
from __future__ import absolute_import
32
33
35
36
import os
36
37
import sys
37
38
39
+ # Try to import mig to assure we have a suitable python module load path
40
+ try :
41
+ import mig
42
+ except ImportError :
43
+ mig = None # type: ignore[assignment]
44
+
45
+ if mig is None :
46
+ # NOTE: include cmd parent path in search path for mig.X imports to work
47
+ MIG_ROOT = os .path .dirname (os .path .dirname (os .path .abspath (sys .argv [0 ])))
48
+ print ("Using mig installation in %s" % MIG_ROOT )
49
+ sys .path .append (MIG_ROOT )
50
+
51
+ from mig .shared .fileio import read_head_lines , read_file_lines , write_file_lines
38
52
from mig .shared .projcode import code_root , py_code_files , sh_code_files , \
39
53
js_code_files
40
54
41
55
# Modify these to fit actual project
42
- proj_vars = {}
43
- proj_vars ['project_name' ] = "MiG"
44
- proj_vars ['authors' ] = 'The MiG Project by the Science HPC Center at UCPH'
56
+ PROJ_CONSTS = {}
57
+ PROJ_CONSTS ['project_name' ] = "MiG"
58
+ PROJ_CONSTS ['authors' ] = 'The MiG Project by the Science HPC Center at UCPH'
45
59
46
- proj_vars ['copyright_year' ] = '2003-%d' % datetime .date .today ().year
60
+ PROJ_CONSTS ['copyright_year' ] = '2003-%d' % datetime .date .today ().year
47
61
48
62
# Set interpreter path and file encoding if not already set in source files
49
63
# Use empty string to leave them alone.
50
- proj_vars ['interpreter_path' ] = '/usr/bin/python'
51
- proj_vars ['module_encoding' ] = 'utf-8'
64
+ PROJ_CONSTS ['interpreter_path' ] = '/usr/bin/env python'
65
+ PROJ_CONSTS ['module_encoding' ] = 'utf-8'
52
66
53
- begin_marker , end_marker = "--- BEGIN_HEADER ---" , "--- END_HEADER ---"
67
+ BEGIN_MARKER , END_MARKER = "--- BEGIN_HEADER ---" , "--- END_HEADER ---"
68
+ BACKUP_MARKER = ".unlicensed"
54
69
55
70
# Mandatory copyright notice for any license
56
- license_text = """#
71
+ LICENSE_TEXT = """#
57
72
# %(module_name)s - [optionally add short module description on this line]
58
73
# Copyright (C) %(copyright_year)s %(authors)s
59
74
"""
65
80
# with a verbatim copy of the license text:
66
81
# wget -O COPYING http://www.gnu.org/licenses/gpl2.txt
67
82
68
- license_text += """#
83
+ LICENSE_TEXT += """#
69
84
# This file is part of %(project_name)s.
70
85
#
71
86
# %(project_name)s is free software: you can redistribute it and/or modify
84
99
# USA."""
85
100
86
101
87
- def check_header (path , var_dict , preamble_size = 4096 ):
102
+ def check_header (path , var_dict , preamble_lines = 100 ):
88
103
"""Check if path already has a credible license header. Only looks inside
89
104
the first preamble_size bytes of the file.
90
105
"""
91
- module_fd = open (path , 'r' )
92
- module_preamble = module_fd .read (4096 )
93
- module_fd .close ()
94
- if begin_marker in module_preamble or \
95
- proj_vars ['authors' ] in module_preamble :
96
- return True
97
- else :
98
- return False
106
+ module_preamble = '\n ' .join (read_head_lines (path , preamble_lines , None ))
107
+ return (BEGIN_MARKER in module_preamble or
108
+ var_dict ['authors' ] in module_preamble )
99
109
100
110
101
111
def add_header (path , var_dict , explicit_border = True , block_wrap = False ):
@@ -109,33 +119,29 @@ def add_header(path, var_dict, explicit_border=True, block_wrap=False):
109
119
Creates a '.unlicensed' backup copy of each file changed.
110
120
"""
111
121
112
- module_fd = open (path , 'r' )
113
- module_lines = module_fd .readlines ()
114
- module_fd .close ()
115
- backup_fd = open (path + '.unlicensed' , 'w' )
116
- backup_fd .writelines (module_lines )
117
- backup_fd .close ()
118
- # Do not truncate any existing unix executable hint and encoding
119
- act = '#!%(interpreter_path)s' % var_dict
122
+ module_lines = read_file_lines (path , None )
123
+ if not write_file_lines (module_lines , path + BACKUP_MARKER , None ):
124
+ print ("Failed to create backup of %s - skip!" % path )
125
+ return False
126
+ # Do not truncate any existing unix executable hint (shebang) and encoding
127
+ act = '#!%(interpreter_path)s\n ' % var_dict
120
128
if block_wrap :
121
129
enc = ''
122
130
else :
123
131
enc = '# -*- coding: %(module_encoding)s -*-' % var_dict
124
- lic = license_text % var_dict
132
+ lic = LICENSE_TEXT % var_dict
125
133
module_header = []
126
- if var_dict ['interpreter_path' ]:
134
+ if module_lines and module_lines [0 ].startswith ("#!" ):
135
+ module_header .append (module_lines [0 ])
136
+ module_lines = module_lines [1 :]
137
+ elif var_dict ['interpreter_path' ]:
127
138
module_header .append (act )
128
- if module_lines and module_lines [0 ].startswith ("#!" ):
129
- module_lines = module_lines [1 :]
130
- else :
131
- if module_lines and module_lines [0 ].startswith ("#!" ):
132
- module_header .append (module_lines [0 ].strip ())
133
- module_lines = module_lines [1 :]
134
139
135
- if var_dict ['module_encoding' ]:
140
+ if module_lines and module_lines [0 ].startswith ("# -*- coding" ):
141
+ module_header .append (module_lines [0 ])
142
+ module_lines = module_lines [1 :]
143
+ elif var_dict ['module_encoding' ]:
136
144
module_header .append (enc )
137
- if module_lines and module_lines [0 ].startswith ("# -*- coding" ):
138
- module_lines = module_lines [1 :]
139
145
140
146
if explicit_border :
141
147
lic = """
@@ -146,7 +152,7 @@ def add_header(path, var_dict, explicit_border=True, block_wrap=False):
146
152
#
147
153
# %s
148
154
#
149
- """ % (begin_marker , lic , end_marker )
155
+ """ % (BEGIN_MARKER , lic , END_MARKER )
150
156
if block_wrap :
151
157
lic = """
152
158
/*
@@ -155,23 +161,26 @@ def add_header(path, var_dict, explicit_border=True, block_wrap=False):
155
161
""" % lic
156
162
157
163
module_header .append (lic )
158
- module_text = '\n ' .join (module_header ) % var_dict + '\n ' \
159
- + '' .join (module_lines )
160
164
161
- module_fd = open (path , 'w' )
162
- module_fd .write (module_text )
163
- module_fd .close ()
165
+ updated_lines = [i % var_dict for i in module_header + ['' ] + module_lines ]
166
+
167
+ if not write_file_lines (updated_lines , path , None ):
168
+ print ("Failed to write %s with added headers!" % path )
169
+ return False
170
+ #print("DEBUG: wrote %s with added headers!" % path)
171
+ return True
164
172
165
173
166
- if __name__ == '__main__' :
174
+ def main (argv ):
175
+ """Run header addition for given argv"""
167
176
target = os .getcwd ()
168
- if len (sys . argv ) > 1 :
169
- target = os .path .abspath (sys . argv [1 ])
177
+ if len (argv ) > 1 :
178
+ target = os .path .abspath (argv [1 ])
170
179
mig_code_base = target
171
- if len (sys . argv ) > 2 :
172
- mig_code_base = os .path .abspath (sys . argv [2 ])
180
+ if len (argv ) > 2 :
181
+ mig_code_base = os .path .abspath (argv [2 ])
173
182
174
- for (root , dirs , files ) in os .walk (target ):
183
+ for (root , _ , files ) in os .walk (target ):
175
184
176
185
# skip all dot dirs - they are from repos etc and _not_ jobs
177
186
@@ -181,27 +190,33 @@ def add_header(path, var_dict, explicit_border=True, block_wrap=False):
181
190
src_path = os .path .join (root , name )
182
191
if os .path .islink (src_path ):
183
192
continue
193
+ if src_path .endswith (BACKUP_MARKER ):
194
+ continue
184
195
print ('Inspecting %s' % src_path )
185
196
for pattern in py_code_files + sh_code_files + js_code_files :
186
- if pattern in js_code_files :
187
- needs_block = True
188
- else :
189
- needs_block = False
190
-
191
- pattern = os .path .join (mig_code_base , code_root , pattern )
197
+ needs_block = (pattern in js_code_files )
198
+ pattern = os .path .normpath (os .path .join (
199
+ mig_code_base , code_root , pattern ))
192
200
193
- # print " Testing %s against %s" % (src_path, pattern)
201
+ #print("DEBUG: Testing %s against %s" % (src_path, pattern) )
194
202
195
203
if src_path == pattern or fnmatch .fnmatch (src_path , pattern ):
196
204
print ('Matched %s against %s' % (src_path , pattern ))
197
- proj_vars ['module_name' ] = name .replace ('.py' , '' )
198
- if check_header (src_path , proj_vars ):
205
+ PROJ_CONSTS ['module_name' ] = name .replace ('.py' , '' )
206
+ if check_header (src_path , PROJ_CONSTS ):
199
207
print ('Skip %s with existing header' % src_path )
200
208
continue
201
- add_header (src_path , proj_vars , block_wrap = needs_block )
209
+ add_header (src_path , PROJ_CONSTS , block_wrap = needs_block )
210
+ # else:
211
+ # print('DEBUG: %s does not match %s' % (src_path, pattern))
212
+
202
213
print ()
203
214
print ("Added license headers to code in %s" % target )
204
215
print ()
205
216
print ("Don't forget to include COPYING file in root of source, e.g. run:" )
206
217
print ("wget -O COPYING http://www.gnu.org/licenses/gpl2.txt" )
207
218
print ("if using the default GPL v2 license here." )
219
+
220
+
221
+ if __name__ == '__main__' :
222
+ main (sys .argv )
0 commit comments