python-msilib 0.1.1__cp314-cp314t-win_amd64.whl → 0.3.0__cp314-cp314t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-msilib might be problematic. Click here for more details.

msilib/__init__.py CHANGED
@@ -7,28 +7,35 @@ import re
7
7
  import string
8
8
  import sys
9
9
 
10
- __version__ = "0.1.1"
10
+ __version__ = "0.3.0"
11
11
 
12
12
  AMD64 = "AMD64" in sys.version
13
13
  # Keep msilib.Win64 around to preserve backwards compatibility.
14
14
  Win64 = AMD64
15
15
 
16
16
  # Partially taken from Wine
17
- datasizemask= 0x00ff
18
- type_valid= 0x0100
19
- type_localizable= 0x0200
20
-
21
- typemask= 0x0c00
22
- type_long= 0x0000
23
- type_short= 0x0400
24
- type_string= 0x0c00
25
- type_binary= 0x0800
26
-
27
- type_nullable= 0x1000
28
- type_key= 0x2000
17
+ datasizemask = 0x00FF
18
+ type_valid = 0x0100
19
+ type_localizable = 0x0200
20
+
21
+ typemask = 0x0C00
22
+ type_long = 0x0000
23
+ type_short = 0x0400
24
+ type_string = 0x0C00
25
+ type_binary = 0x0800
26
+
27
+ type_nullable = 0x1000
28
+ type_key = 0x2000
29
29
  # XXX temporary, localizable?
30
- knownbits = datasizemask | type_valid | type_localizable | \
31
- typemask | type_nullable | type_key
30
+ knownbits = (
31
+ datasizemask
32
+ | type_valid
33
+ | type_localizable
34
+ | typemask
35
+ | type_nullable
36
+ | type_key
37
+ )
38
+
32
39
 
33
40
  class Table:
34
41
  def __init__(self, name):
@@ -36,13 +43,13 @@ class Table:
36
43
  self.fields = []
37
44
 
38
45
  def add_field(self, index, name, type):
39
- self.fields.append((index,name,type))
46
+ self.fields.append((index, name, type))
40
47
 
41
48
  def sql(self):
42
49
  fields = []
43
50
  keys = []
44
51
  self.fields.sort()
45
- fields = [None]*len(self.fields)
52
+ fields = [None] * len(self.fields)
46
53
  for index, name, type in self.fields:
47
54
  index -= 1
48
55
  unk = type & ~knownbits
@@ -52,20 +59,20 @@ class Table:
52
59
  dtype = type & typemask
53
60
  if dtype == type_string:
54
61
  if size:
55
- tname="CHAR(%d)" % size
62
+ tname = "CHAR(%d)" % size
56
63
  else:
57
- tname="CHAR"
64
+ tname = "CHAR"
58
65
  elif dtype == type_short:
59
- assert size==2
66
+ assert size == 2
60
67
  tname = "SHORT"
61
68
  elif dtype == type_long:
62
- assert size==4
63
- tname="LONG"
69
+ assert size == 4
70
+ tname = "LONG"
64
71
  elif dtype == type_binary:
65
- assert size==0
66
- tname="OBJECT"
72
+ assert size == 0
73
+ tname = "OBJECT"
67
74
  else:
68
- tname="unknown"
75
+ tname = "unknown"
69
76
  print("%s.%sunknown integer type %d" % (self.name, name, size))
70
77
  if type & type_nullable:
71
78
  flags = ""
@@ -78,15 +85,23 @@ class Table:
78
85
  keys.append("`%s`" % name)
79
86
  fields = ", ".join(fields)
80
87
  keys = ", ".join(keys)
81
- return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (self.name, fields, keys)
88
+ return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (
89
+ self.name,
90
+ fields,
91
+ keys,
92
+ )
82
93
 
83
94
  def create(self, db):
84
95
  v = db.OpenView(self.sql())
85
96
  v.Execute(None)
86
97
  v.Close()
87
98
 
88
- class _Unspecified:pass
89
- def change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified):
99
+
100
+ class _Unspecified:
101
+ pass
102
+
103
+
104
+ def change_sequence(seq, action, seqno=_Unspecified, cond=_Unspecified):
90
105
  "Change the sequence number of an action in a sequence list"
91
106
  for i in range(len(seq)):
92
107
  if seq[i][0] == action:
@@ -98,6 +113,7 @@ def change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified):
98
113
  return
99
114
  raise ValueError("Action not found in sequence")
100
115
 
116
+
101
117
  def add_data(db, table, values):
102
118
  v = db.OpenView("SELECT * FROM `%s`" % table)
103
119
  count = v.GetColumnInfo(MSICOLINFO_NAMES).GetFieldCount()
@@ -107,34 +123,41 @@ def add_data(db, table, values):
107
123
  for i in range(count):
108
124
  field = value[i]
109
125
  if isinstance(field, int):
110
- r.SetInteger(i+1,field)
126
+ r.SetInteger(i + 1, field)
111
127
  elif isinstance(field, str):
112
- r.SetString(i+1,field)
128
+ r.SetString(i + 1, field)
113
129
  elif field is None:
114
130
  pass
115
131
  elif isinstance(field, Binary):
116
- r.SetStream(i+1, field.name)
132
+ r.SetStream(i + 1, field.name)
117
133
  else:
118
- raise TypeError("Unsupported type %s" % field.__class__.__name__)
134
+ raise TypeError(
135
+ "Unsupported type %s" % field.__class__.__name__
136
+ )
119
137
  try:
120
138
  v.Modify(MSIMODIFY_INSERT, r)
121
139
  except Exception:
122
- raise MSIError("Could not insert "+repr(values)+" into "+table)
140
+ raise MSIError(
141
+ "Could not insert " + repr(values) + " into " + table
142
+ )
123
143
 
124
144
  r.ClearData()
125
145
  v.Close()
126
146
 
127
147
 
128
148
  def add_stream(db, name, path):
129
- v = db.OpenView("INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name)
149
+ v = db.OpenView(
150
+ "INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name
151
+ )
130
152
  r = CreateRecord(1)
131
153
  r.SetStream(1, path)
132
154
  v.Execute(r)
133
155
  v.Close()
134
156
 
135
- def init_database(name, schema,
136
- ProductName, ProductCode, ProductVersion,
137
- Manufacturer):
157
+
158
+ def init_database(
159
+ name, schema, ProductName, ProductCode, ProductVersion, Manufacturer
160
+ ):
138
161
  try:
139
162
  os.unlink(name)
140
163
  except OSError:
@@ -147,7 +170,7 @@ def init_database(name, schema,
147
170
  t.create(db)
148
171
  # Fill the validation table
149
172
  add_data(db, "_Validation", schema._Validation_records)
150
- # Initialize the summary information, allowing atmost 20 properties
173
+ # Initialize the summary information, allowing at most 20 properties
151
174
  si = db.GetSummaryInformation(20)
152
175
  si.SetProperty(PID_TITLE, "Installation Database")
153
176
  si.SetProperty(PID_SUBJECT, ProductName)
@@ -157,34 +180,45 @@ def init_database(name, schema,
157
180
  else:
158
181
  si.SetProperty(PID_TEMPLATE, "Intel;1033")
159
182
  si.SetProperty(PID_REVNUMBER, gen_uuid())
160
- si.SetProperty(PID_WORDCOUNT, 2) # long file names, compressed, original media
183
+ si.SetProperty(
184
+ PID_WORDCOUNT, 2
185
+ ) # long file names, compressed, original media
161
186
  si.SetProperty(PID_PAGECOUNT, 200)
162
187
  si.SetProperty(PID_APPNAME, "Python MSI Library")
163
188
  # XXX more properties
164
189
  si.Persist()
165
- add_data(db, "Property", [
166
- ("ProductName", ProductName),
167
- ("ProductCode", ProductCode),
168
- ("ProductVersion", ProductVersion),
169
- ("Manufacturer", Manufacturer),
170
- ("ProductLanguage", "1033")])
190
+ add_data(
191
+ db,
192
+ "Property",
193
+ [
194
+ ("ProductName", ProductName),
195
+ ("ProductCode", ProductCode),
196
+ ("ProductVersion", ProductVersion),
197
+ ("Manufacturer", Manufacturer),
198
+ ("ProductLanguage", "1033"),
199
+ ],
200
+ )
171
201
  db.Commit()
172
202
  return db
173
203
 
204
+
174
205
  def add_tables(db, module):
175
206
  for table in module.tables:
176
207
  add_data(db, table, getattr(module, table))
177
208
 
209
+
178
210
  def make_id(str):
179
211
  identifier_chars = string.ascii_letters + string.digits + "._"
180
212
  str = "".join([c if c in identifier_chars else "_" for c in str])
181
213
  if str[0] in (string.digits + "."):
182
214
  str = "_" + str
183
- assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE"+str
215
+ assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE" + str
184
216
  return str
185
217
 
218
+
186
219
  def gen_uuid():
187
- return "{"+UuidCreate().upper()+"}"
220
+ return "{" + UuidCreate().upper() + "}"
221
+
188
222
 
189
223
  class CAB:
190
224
  def __init__(self, name):
@@ -213,17 +247,31 @@ class CAB:
213
247
 
214
248
  def commit(self, db):
215
249
  from tempfile import mktemp
250
+
216
251
  filename = mktemp()
217
252
  FCICreate(filename, self.files)
218
- add_data(db, "Media",
219
- [(1, self.index, None, "#"+self.name, None, None)])
253
+ add_data(
254
+ db, "Media", [(1, self.index, None, "#" + self.name, None, None)]
255
+ )
220
256
  add_stream(db, self.name, filename)
221
257
  os.unlink(filename)
222
258
  db.Commit()
223
259
 
260
+
224
261
  _directories = set()
262
+
263
+
225
264
  class Directory:
226
- def __init__(self, db, cab, basedir, physical, _logical, default, componentflags=None):
265
+ def __init__(
266
+ self,
267
+ db,
268
+ cab,
269
+ basedir,
270
+ physical,
271
+ _logical,
272
+ default,
273
+ componentflags=None,
274
+ ):
227
275
  """Create a new directory in the Directory table. There is a current component
228
276
  at each point in time for the directory, which is either explicitly created
229
277
  through start_component, or implicitly when files are added for the first
@@ -257,7 +305,9 @@ class Directory:
257
305
  blogical = None
258
306
  add_data(db, "Directory", [(logical, blogical, default)])
259
307
 
260
- def start_component(self, component = None, feature = None, flags = None, keyfile = None, uuid=None):
308
+ def start_component(
309
+ self, component=None, feature=None, flags=None, keyfile=None, uuid=None
310
+ ):
261
311
  """Add an entry to the Component table, and make this component the current for this
262
312
  directory. If no component name is given, the directory name is used. If no feature
263
313
  is given, the current feature is used. If no flags are given, the directory's default
@@ -279,17 +329,19 @@ class Directory:
279
329
  self.keyfiles[keyfile] = keyid
280
330
  else:
281
331
  keyid = None
282
- add_data(self.db, "Component",
283
- [(component, uuid, self.logical, flags, None, keyid)])
332
+ add_data(
333
+ self.db,
334
+ "Component",
335
+ [(component, uuid, self.logical, flags, None, keyid)],
336
+ )
284
337
  if feature is None:
285
338
  feature = current_feature
286
- add_data(self.db, "FeatureComponents",
287
- [(feature.id, component)])
339
+ add_data(self.db, "FeatureComponents", [(feature.id, component)])
288
340
 
289
341
  def make_short(self, file):
290
342
  oldfile = file
291
- file = file.replace('+', '_')
292
- file = ''.join(c for c in file if not c in r' "/\[]:;=,')
343
+ file = file.replace("+", "_")
344
+ file = "".join(c for c in file if not c in r' "/\[]:;=,')
293
345
  parts = file.split(".")
294
346
  if len(parts) > 1:
295
347
  prefix = "".join(parts[:-1]).upper()
@@ -300,10 +352,14 @@ class Directory:
300
352
  else:
301
353
  prefix = file.upper()
302
354
  suffix = None
303
- if len(parts) < 3 and len(prefix) <= 8 and file == oldfile and (
304
- not suffix or len(suffix) <= 3):
355
+ if (
356
+ len(parts) < 3
357
+ and len(prefix) <= 8
358
+ and file == oldfile
359
+ and (not suffix or len(suffix) <= 3)
360
+ ):
305
361
  if suffix:
306
- file = prefix+"."+suffix
362
+ file = prefix + "." + suffix
307
363
  else:
308
364
  file = prefix
309
365
  else:
@@ -318,13 +374,16 @@ class Directory:
318
374
  file = "%s~%d.%s" % (prefix, pos, suffix)
319
375
  else:
320
376
  file = "%s~%d" % (prefix, pos)
321
- if file not in self.short_names: break
377
+ if file not in self.short_names:
378
+ break
322
379
  pos += 1
323
380
  assert pos < 10000
324
381
  if pos in (10, 100, 1000):
325
382
  prefix = prefix[:-1]
326
383
  self.short_names.add(file)
327
- assert not re.search(r'[\?|><:/*"+,;=\[\]]', file) # restrictions on short names
384
+ assert not re.search(
385
+ r'[\?|><:/*"+,;=\[\]]', file
386
+ ) # restrictions on short names
328
387
  return file
329
388
 
330
389
  def add_file(self, file, src=None, version=None, language=None):
@@ -340,7 +399,9 @@ class Directory:
340
399
  src = file
341
400
  file = os.path.basename(file)
342
401
  absolute = os.path.join(self.absolute, src)
343
- assert not re.search(r'[\?|><:/*]"', file) # restrictions on long names
402
+ assert not re.search(
403
+ r'[\?|><:/*]"', file
404
+ ) # restrictions on long names
344
405
  if file in self.keyfiles:
345
406
  logical = self.keyfiles[file]
346
407
  else:
@@ -355,10 +416,23 @@ class Directory:
355
416
  # Compressed omitted, since it is the database default
356
417
  # could add r/o, system, hidden
357
418
  attributes = 512
358
- add_data(self.db, "File",
359
- [(logical, self.component, full, filesize, version,
360
- language, attributes, sequence)])
361
- #if not version:
419
+ add_data(
420
+ self.db,
421
+ "File",
422
+ [
423
+ (
424
+ logical,
425
+ self.component,
426
+ full,
427
+ filesize,
428
+ version,
429
+ language,
430
+ attributes,
431
+ sequence,
432
+ )
433
+ ],
434
+ )
435
+ # if not version:
362
436
  # # Add hash if the file is not versioned
363
437
  # filehash = FileHash(absolute, 0)
364
438
  # add_data(self.db, "MsiFileHash",
@@ -369,69 +443,114 @@ class Directory:
369
443
  # XXX: adding so many RemoveFile entries makes installer unbelievably
370
444
  # slow. So instead, we have to use wildcard remove entries
371
445
  if file.endswith(".py"):
372
- add_data(self.db, "RemoveFile",
373
- [(logical+"c", self.component, "%sC|%sc" % (short, file),
374
- self.logical, 2),
375
- (logical+"o", self.component, "%sO|%so" % (short, file),
376
- self.logical, 2)])
446
+ add_data(
447
+ self.db,
448
+ "RemoveFile",
449
+ [
450
+ (
451
+ logical + "c",
452
+ self.component,
453
+ "%sC|%sc" % (short, file),
454
+ self.logical,
455
+ 2,
456
+ ),
457
+ (
458
+ logical + "o",
459
+ self.component,
460
+ "%sO|%so" % (short, file),
461
+ self.logical,
462
+ 2,
463
+ ),
464
+ ],
465
+ )
377
466
  return logical
378
467
 
379
- def glob(self, pattern, exclude = None):
468
+ def glob(self, pattern, exclude=None):
380
469
  """Add a list of files to the current component as specified in the
381
470
  glob pattern. Individual files can be excluded in the exclude list."""
382
471
  try:
383
472
  files = os.listdir(self.absolute)
384
473
  except OSError:
385
474
  return []
386
- if pattern[:1] != '.':
387
- files = (f for f in files if f[0] != '.')
475
+ if pattern[:1] != ".":
476
+ files = (f for f in files if f[0] != ".")
388
477
  files = fnmatch.filter(files, pattern)
389
478
  for f in files:
390
- if exclude and f in exclude: continue
479
+ if exclude and f in exclude:
480
+ continue
391
481
  self.add_file(f)
392
482
  return files
393
483
 
394
484
  def remove_pyc(self):
395
485
  "Remove .pyc files on uninstall"
396
- add_data(self.db, "RemoveFile",
397
- [(self.component+"c", self.component, "*.pyc", self.logical, 2)])
486
+ add_data(
487
+ self.db,
488
+ "RemoveFile",
489
+ [(self.component + "c", self.component, "*.pyc", self.logical, 2)],
490
+ )
491
+
398
492
 
399
493
  class Binary:
400
494
  def __init__(self, fname):
401
495
  self.name = fname
496
+
402
497
  def __repr__(self):
403
498
  return 'msilib.Binary(os.path.join(dirname,"%s"))' % self.name
404
499
 
500
+
405
501
  class Feature:
406
- def __init__(self, db, id, title, desc, display, level = 1,
407
- parent=None, directory = None, attributes=0):
502
+ def __init__(
503
+ self,
504
+ db,
505
+ id,
506
+ title,
507
+ desc,
508
+ display,
509
+ level=1,
510
+ parent=None,
511
+ directory=None,
512
+ attributes=0,
513
+ ):
408
514
  self.id = id
409
515
  if parent:
410
516
  parent = parent.id
411
- add_data(db, "Feature",
412
- [(id, parent, title, desc, display,
413
- level, directory, attributes)])
517
+ add_data(
518
+ db,
519
+ "Feature",
520
+ [(id, parent, title, desc, display, level, directory, attributes)],
521
+ )
522
+
414
523
  def set_current(self):
415
524
  global current_feature
416
525
  current_feature = self
417
526
 
527
+
418
528
  class Control:
419
529
  def __init__(self, dlg, name):
420
530
  self.dlg = dlg
421
531
  self.name = name
422
532
 
423
- def event(self, event, argument, condition = "1", ordering = None):
424
- add_data(self.dlg.db, "ControlEvent",
425
- [(self.dlg.name, self.name, event, argument,
426
- condition, ordering)])
533
+ def event(self, event, argument, condition="1", ordering=None):
534
+ add_data(
535
+ self.dlg.db,
536
+ "ControlEvent",
537
+ [(self.dlg.name, self.name, event, argument, condition, ordering)],
538
+ )
427
539
 
428
540
  def mapping(self, event, attribute):
429
- add_data(self.dlg.db, "EventMapping",
430
- [(self.dlg.name, self.name, event, attribute)])
541
+ add_data(
542
+ self.dlg.db,
543
+ "EventMapping",
544
+ [(self.dlg.name, self.name, event, attribute)],
545
+ )
431
546
 
432
547
  def condition(self, action, condition):
433
- add_data(self.dlg.db, "ControlCondition",
434
- [(self.dlg.name, self.name, action, condition)])
548
+ add_data(
549
+ self.dlg.db,
550
+ "ControlCondition",
551
+ [(self.dlg.name, self.name, action, condition)],
552
+ )
553
+
435
554
 
436
555
  class RadioButtonGroup(Control):
437
556
  def __init__(self, dlg, name, property):
@@ -440,44 +559,97 @@ class RadioButtonGroup(Control):
440
559
  self.property = property
441
560
  self.index = 1
442
561
 
443
- def add(self, name, x, y, w, h, text, value = None):
562
+ def add(self, name, x, y, w, h, text, value=None):
444
563
  if value is None:
445
564
  value = name
446
- add_data(self.dlg.db, "RadioButton",
447
- [(self.property, self.index, value,
448
- x, y, w, h, text, None)])
565
+ add_data(
566
+ self.dlg.db,
567
+ "RadioButton",
568
+ [(self.property, self.index, value, x, y, w, h, text, None)],
569
+ )
449
570
  self.index += 1
450
571
 
572
+
451
573
  class Dialog:
452
- def __init__(self, db, name, x, y, w, h, attr, title, first, default, cancel):
574
+ def __init__(
575
+ self, db, name, x, y, w, h, attr, title, first, default, cancel
576
+ ):
453
577
  self.db = db
454
578
  self.name = name
455
- self.x, self.y, self.w, self.h = x,y,w,h
456
- add_data(db, "Dialog", [(name, x,y,w,h,attr,title,first,default,cancel)])
579
+ self.x, self.y, self.w, self.h = x, y, w, h
580
+ add_data(
581
+ db,
582
+ "Dialog",
583
+ [(name, x, y, w, h, attr, title, first, default, cancel)],
584
+ )
457
585
 
458
586
  def control(self, name, type, x, y, w, h, attr, prop, text, next, help):
459
- add_data(self.db, "Control",
460
- [(self.name, name, type, x, y, w, h, attr, prop, text, next, help)])
587
+ add_data(
588
+ self.db,
589
+ "Control",
590
+ [
591
+ (
592
+ self.name,
593
+ name,
594
+ type,
595
+ x,
596
+ y,
597
+ w,
598
+ h,
599
+ attr,
600
+ prop,
601
+ text,
602
+ next,
603
+ help,
604
+ )
605
+ ],
606
+ )
461
607
  return Control(self, name)
462
608
 
463
609
  def text(self, name, x, y, w, h, attr, text):
464
- return self.control(name, "Text", x, y, w, h, attr, None,
465
- text, None, None)
610
+ return self.control(
611
+ name, "Text", x, y, w, h, attr, None, text, None, None
612
+ )
466
613
 
467
614
  def bitmap(self, name, x, y, w, h, text):
468
- return self.control(name, "Bitmap", x, y, w, h, 1, None, text, None, None)
615
+ return self.control(
616
+ name, "Bitmap", x, y, w, h, 1, None, text, None, None
617
+ )
469
618
 
470
619
  def line(self, name, x, y, w, h):
471
- return self.control(name, "Line", x, y, w, h, 1, None, None, None, None)
620
+ return self.control(
621
+ name, "Line", x, y, w, h, 1, None, None, None, None
622
+ )
472
623
 
473
624
  def pushbutton(self, name, x, y, w, h, attr, text, next):
474
- return self.control(name, "PushButton", x, y, w, h, attr, None, text, next, None)
625
+ return self.control(
626
+ name, "PushButton", x, y, w, h, attr, None, text, next, None
627
+ )
475
628
 
476
629
  def radiogroup(self, name, x, y, w, h, attr, prop, text, next):
477
- add_data(self.db, "Control",
478
- [(self.name, name, "RadioButtonGroup",
479
- x, y, w, h, attr, prop, text, next, None)])
630
+ add_data(
631
+ self.db,
632
+ "Control",
633
+ [
634
+ (
635
+ self.name,
636
+ name,
637
+ "RadioButtonGroup",
638
+ x,
639
+ y,
640
+ w,
641
+ h,
642
+ attr,
643
+ prop,
644
+ text,
645
+ next,
646
+ None,
647
+ )
648
+ ],
649
+ )
480
650
  return RadioButtonGroup(self, name, prop)
481
651
 
482
652
  def checkbox(self, name, x, y, w, h, attr, prop, text, next):
483
- return self.control(name, "CheckBox", x, y, w, h, attr, prop, text, next, None)
653
+ return self.control(
654
+ name, "CheckBox", x, y, w, h, attr, prop, text, next, None
655
+ )