17db96d56Sopenharmony_ci# Copyright (C) 2005 Martin v. Löwis 27db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement. 37db96d56Sopenharmony_cifrom _msi import * 47db96d56Sopenharmony_ciimport fnmatch 57db96d56Sopenharmony_ciimport os 67db96d56Sopenharmony_ciimport re 77db96d56Sopenharmony_ciimport string 87db96d56Sopenharmony_ciimport sys 97db96d56Sopenharmony_ciimport warnings 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ciwarnings._deprecated(__name__, remove=(3, 13)) 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciAMD64 = "AMD64" in sys.version 147db96d56Sopenharmony_ci# Keep msilib.Win64 around to preserve backwards compatibility. 157db96d56Sopenharmony_ciWin64 = AMD64 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci# Partially taken from Wine 187db96d56Sopenharmony_cidatasizemask= 0x00ff 197db96d56Sopenharmony_citype_valid= 0x0100 207db96d56Sopenharmony_citype_localizable= 0x0200 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_citypemask= 0x0c00 237db96d56Sopenharmony_citype_long= 0x0000 247db96d56Sopenharmony_citype_short= 0x0400 257db96d56Sopenharmony_citype_string= 0x0c00 267db96d56Sopenharmony_citype_binary= 0x0800 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_citype_nullable= 0x1000 297db96d56Sopenharmony_citype_key= 0x2000 307db96d56Sopenharmony_ci# XXX temporary, localizable? 317db96d56Sopenharmony_ciknownbits = datasizemask | type_valid | type_localizable | \ 327db96d56Sopenharmony_ci typemask | type_nullable | type_key 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ciclass Table: 357db96d56Sopenharmony_ci def __init__(self, name): 367db96d56Sopenharmony_ci self.name = name 377db96d56Sopenharmony_ci self.fields = [] 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci def add_field(self, index, name, type): 407db96d56Sopenharmony_ci self.fields.append((index,name,type)) 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci def sql(self): 437db96d56Sopenharmony_ci fields = [] 447db96d56Sopenharmony_ci keys = [] 457db96d56Sopenharmony_ci self.fields.sort() 467db96d56Sopenharmony_ci fields = [None]*len(self.fields) 477db96d56Sopenharmony_ci for index, name, type in self.fields: 487db96d56Sopenharmony_ci index -= 1 497db96d56Sopenharmony_ci unk = type & ~knownbits 507db96d56Sopenharmony_ci if unk: 517db96d56Sopenharmony_ci print("%s.%s unknown bits %x" % (self.name, name, unk)) 527db96d56Sopenharmony_ci size = type & datasizemask 537db96d56Sopenharmony_ci dtype = type & typemask 547db96d56Sopenharmony_ci if dtype == type_string: 557db96d56Sopenharmony_ci if size: 567db96d56Sopenharmony_ci tname="CHAR(%d)" % size 577db96d56Sopenharmony_ci else: 587db96d56Sopenharmony_ci tname="CHAR" 597db96d56Sopenharmony_ci elif dtype == type_short: 607db96d56Sopenharmony_ci assert size==2 617db96d56Sopenharmony_ci tname = "SHORT" 627db96d56Sopenharmony_ci elif dtype == type_long: 637db96d56Sopenharmony_ci assert size==4 647db96d56Sopenharmony_ci tname="LONG" 657db96d56Sopenharmony_ci elif dtype == type_binary: 667db96d56Sopenharmony_ci assert size==0 677db96d56Sopenharmony_ci tname="OBJECT" 687db96d56Sopenharmony_ci else: 697db96d56Sopenharmony_ci tname="unknown" 707db96d56Sopenharmony_ci print("%s.%sunknown integer type %d" % (self.name, name, size)) 717db96d56Sopenharmony_ci if type & type_nullable: 727db96d56Sopenharmony_ci flags = "" 737db96d56Sopenharmony_ci else: 747db96d56Sopenharmony_ci flags = " NOT NULL" 757db96d56Sopenharmony_ci if type & type_localizable: 767db96d56Sopenharmony_ci flags += " LOCALIZABLE" 777db96d56Sopenharmony_ci fields[index] = "`%s` %s%s" % (name, tname, flags) 787db96d56Sopenharmony_ci if type & type_key: 797db96d56Sopenharmony_ci keys.append("`%s`" % name) 807db96d56Sopenharmony_ci fields = ", ".join(fields) 817db96d56Sopenharmony_ci keys = ", ".join(keys) 827db96d56Sopenharmony_ci return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (self.name, fields, keys) 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci def create(self, db): 857db96d56Sopenharmony_ci v = db.OpenView(self.sql()) 867db96d56Sopenharmony_ci v.Execute(None) 877db96d56Sopenharmony_ci v.Close() 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ciclass _Unspecified:pass 907db96d56Sopenharmony_cidef change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified): 917db96d56Sopenharmony_ci "Change the sequence number of an action in a sequence list" 927db96d56Sopenharmony_ci for i in range(len(seq)): 937db96d56Sopenharmony_ci if seq[i][0] == action: 947db96d56Sopenharmony_ci if cond is _Unspecified: 957db96d56Sopenharmony_ci cond = seq[i][1] 967db96d56Sopenharmony_ci if seqno is _Unspecified: 977db96d56Sopenharmony_ci seqno = seq[i][2] 987db96d56Sopenharmony_ci seq[i] = (action, cond, seqno) 997db96d56Sopenharmony_ci return 1007db96d56Sopenharmony_ci raise ValueError("Action not found in sequence") 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_cidef add_data(db, table, values): 1037db96d56Sopenharmony_ci v = db.OpenView("SELECT * FROM `%s`" % table) 1047db96d56Sopenharmony_ci count = v.GetColumnInfo(MSICOLINFO_NAMES).GetFieldCount() 1057db96d56Sopenharmony_ci r = CreateRecord(count) 1067db96d56Sopenharmony_ci for value in values: 1077db96d56Sopenharmony_ci assert len(value) == count, value 1087db96d56Sopenharmony_ci for i in range(count): 1097db96d56Sopenharmony_ci field = value[i] 1107db96d56Sopenharmony_ci if isinstance(field, int): 1117db96d56Sopenharmony_ci r.SetInteger(i+1,field) 1127db96d56Sopenharmony_ci elif isinstance(field, str): 1137db96d56Sopenharmony_ci r.SetString(i+1,field) 1147db96d56Sopenharmony_ci elif field is None: 1157db96d56Sopenharmony_ci pass 1167db96d56Sopenharmony_ci elif isinstance(field, Binary): 1177db96d56Sopenharmony_ci r.SetStream(i+1, field.name) 1187db96d56Sopenharmony_ci else: 1197db96d56Sopenharmony_ci raise TypeError("Unsupported type %s" % field.__class__.__name__) 1207db96d56Sopenharmony_ci try: 1217db96d56Sopenharmony_ci v.Modify(MSIMODIFY_INSERT, r) 1227db96d56Sopenharmony_ci except Exception: 1237db96d56Sopenharmony_ci raise MSIError("Could not insert "+repr(values)+" into "+table) 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci r.ClearData() 1267db96d56Sopenharmony_ci v.Close() 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_cidef add_stream(db, name, path): 1307db96d56Sopenharmony_ci v = db.OpenView("INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name) 1317db96d56Sopenharmony_ci r = CreateRecord(1) 1327db96d56Sopenharmony_ci r.SetStream(1, path) 1337db96d56Sopenharmony_ci v.Execute(r) 1347db96d56Sopenharmony_ci v.Close() 1357db96d56Sopenharmony_ci 1367db96d56Sopenharmony_cidef init_database(name, schema, 1377db96d56Sopenharmony_ci ProductName, ProductCode, ProductVersion, 1387db96d56Sopenharmony_ci Manufacturer): 1397db96d56Sopenharmony_ci try: 1407db96d56Sopenharmony_ci os.unlink(name) 1417db96d56Sopenharmony_ci except OSError: 1427db96d56Sopenharmony_ci pass 1437db96d56Sopenharmony_ci ProductCode = ProductCode.upper() 1447db96d56Sopenharmony_ci # Create the database 1457db96d56Sopenharmony_ci db = OpenDatabase(name, MSIDBOPEN_CREATE) 1467db96d56Sopenharmony_ci # Create the tables 1477db96d56Sopenharmony_ci for t in schema.tables: 1487db96d56Sopenharmony_ci t.create(db) 1497db96d56Sopenharmony_ci # Fill the validation table 1507db96d56Sopenharmony_ci add_data(db, "_Validation", schema._Validation_records) 1517db96d56Sopenharmony_ci # Initialize the summary information, allowing atmost 20 properties 1527db96d56Sopenharmony_ci si = db.GetSummaryInformation(20) 1537db96d56Sopenharmony_ci si.SetProperty(PID_TITLE, "Installation Database") 1547db96d56Sopenharmony_ci si.SetProperty(PID_SUBJECT, ProductName) 1557db96d56Sopenharmony_ci si.SetProperty(PID_AUTHOR, Manufacturer) 1567db96d56Sopenharmony_ci if AMD64: 1577db96d56Sopenharmony_ci si.SetProperty(PID_TEMPLATE, "x64;1033") 1587db96d56Sopenharmony_ci else: 1597db96d56Sopenharmony_ci si.SetProperty(PID_TEMPLATE, "Intel;1033") 1607db96d56Sopenharmony_ci si.SetProperty(PID_REVNUMBER, gen_uuid()) 1617db96d56Sopenharmony_ci si.SetProperty(PID_WORDCOUNT, 2) # long file names, compressed, original media 1627db96d56Sopenharmony_ci si.SetProperty(PID_PAGECOUNT, 200) 1637db96d56Sopenharmony_ci si.SetProperty(PID_APPNAME, "Python MSI Library") 1647db96d56Sopenharmony_ci # XXX more properties 1657db96d56Sopenharmony_ci si.Persist() 1667db96d56Sopenharmony_ci add_data(db, "Property", [ 1677db96d56Sopenharmony_ci ("ProductName", ProductName), 1687db96d56Sopenharmony_ci ("ProductCode", ProductCode), 1697db96d56Sopenharmony_ci ("ProductVersion", ProductVersion), 1707db96d56Sopenharmony_ci ("Manufacturer", Manufacturer), 1717db96d56Sopenharmony_ci ("ProductLanguage", "1033")]) 1727db96d56Sopenharmony_ci db.Commit() 1737db96d56Sopenharmony_ci return db 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_cidef add_tables(db, module): 1767db96d56Sopenharmony_ci for table in module.tables: 1777db96d56Sopenharmony_ci add_data(db, table, getattr(module, table)) 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_cidef make_id(str): 1807db96d56Sopenharmony_ci identifier_chars = string.ascii_letters + string.digits + "._" 1817db96d56Sopenharmony_ci str = "".join([c if c in identifier_chars else "_" for c in str]) 1827db96d56Sopenharmony_ci if str[0] in (string.digits + "."): 1837db96d56Sopenharmony_ci str = "_" + str 1847db96d56Sopenharmony_ci assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE"+str 1857db96d56Sopenharmony_ci return str 1867db96d56Sopenharmony_ci 1877db96d56Sopenharmony_cidef gen_uuid(): 1887db96d56Sopenharmony_ci return "{"+UuidCreate().upper()+"}" 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ciclass CAB: 1917db96d56Sopenharmony_ci def __init__(self, name): 1927db96d56Sopenharmony_ci self.name = name 1937db96d56Sopenharmony_ci self.files = [] 1947db96d56Sopenharmony_ci self.filenames = set() 1957db96d56Sopenharmony_ci self.index = 0 1967db96d56Sopenharmony_ci 1977db96d56Sopenharmony_ci def gen_id(self, file): 1987db96d56Sopenharmony_ci logical = _logical = make_id(file) 1997db96d56Sopenharmony_ci pos = 1 2007db96d56Sopenharmony_ci while logical in self.filenames: 2017db96d56Sopenharmony_ci logical = "%s.%d" % (_logical, pos) 2027db96d56Sopenharmony_ci pos += 1 2037db96d56Sopenharmony_ci self.filenames.add(logical) 2047db96d56Sopenharmony_ci return logical 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci def append(self, full, file, logical): 2077db96d56Sopenharmony_ci if os.path.isdir(full): 2087db96d56Sopenharmony_ci return 2097db96d56Sopenharmony_ci if not logical: 2107db96d56Sopenharmony_ci logical = self.gen_id(file) 2117db96d56Sopenharmony_ci self.index += 1 2127db96d56Sopenharmony_ci self.files.append((full, logical)) 2137db96d56Sopenharmony_ci return self.index, logical 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci def commit(self, db): 2167db96d56Sopenharmony_ci from tempfile import mktemp 2177db96d56Sopenharmony_ci filename = mktemp() 2187db96d56Sopenharmony_ci FCICreate(filename, self.files) 2197db96d56Sopenharmony_ci add_data(db, "Media", 2207db96d56Sopenharmony_ci [(1, self.index, None, "#"+self.name, None, None)]) 2217db96d56Sopenharmony_ci add_stream(db, self.name, filename) 2227db96d56Sopenharmony_ci os.unlink(filename) 2237db96d56Sopenharmony_ci db.Commit() 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci_directories = set() 2267db96d56Sopenharmony_ciclass Directory: 2277db96d56Sopenharmony_ci def __init__(self, db, cab, basedir, physical, _logical, default, componentflags=None): 2287db96d56Sopenharmony_ci """Create a new directory in the Directory table. There is a current component 2297db96d56Sopenharmony_ci at each point in time for the directory, which is either explicitly created 2307db96d56Sopenharmony_ci through start_component, or implicitly when files are added for the first 2317db96d56Sopenharmony_ci time. Files are added into the current component, and into the cab file. 2327db96d56Sopenharmony_ci To create a directory, a base directory object needs to be specified (can be 2337db96d56Sopenharmony_ci None), the path to the physical directory, and a logical directory name. 2347db96d56Sopenharmony_ci Default specifies the DefaultDir slot in the directory table. componentflags 2357db96d56Sopenharmony_ci specifies the default flags that new components get.""" 2367db96d56Sopenharmony_ci index = 1 2377db96d56Sopenharmony_ci _logical = make_id(_logical) 2387db96d56Sopenharmony_ci logical = _logical 2397db96d56Sopenharmony_ci while logical in _directories: 2407db96d56Sopenharmony_ci logical = "%s%d" % (_logical, index) 2417db96d56Sopenharmony_ci index += 1 2427db96d56Sopenharmony_ci _directories.add(logical) 2437db96d56Sopenharmony_ci self.db = db 2447db96d56Sopenharmony_ci self.cab = cab 2457db96d56Sopenharmony_ci self.basedir = basedir 2467db96d56Sopenharmony_ci self.physical = physical 2477db96d56Sopenharmony_ci self.logical = logical 2487db96d56Sopenharmony_ci self.component = None 2497db96d56Sopenharmony_ci self.short_names = set() 2507db96d56Sopenharmony_ci self.ids = set() 2517db96d56Sopenharmony_ci self.keyfiles = {} 2527db96d56Sopenharmony_ci self.componentflags = componentflags 2537db96d56Sopenharmony_ci if basedir: 2547db96d56Sopenharmony_ci self.absolute = os.path.join(basedir.absolute, physical) 2557db96d56Sopenharmony_ci blogical = basedir.logical 2567db96d56Sopenharmony_ci else: 2577db96d56Sopenharmony_ci self.absolute = physical 2587db96d56Sopenharmony_ci blogical = None 2597db96d56Sopenharmony_ci add_data(db, "Directory", [(logical, blogical, default)]) 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci def start_component(self, component = None, feature = None, flags = None, keyfile = None, uuid=None): 2627db96d56Sopenharmony_ci """Add an entry to the Component table, and make this component the current for this 2637db96d56Sopenharmony_ci directory. If no component name is given, the directory name is used. If no feature 2647db96d56Sopenharmony_ci is given, the current feature is used. If no flags are given, the directory's default 2657db96d56Sopenharmony_ci flags are used. If no keyfile is given, the KeyPath is left null in the Component 2667db96d56Sopenharmony_ci table.""" 2677db96d56Sopenharmony_ci if flags is None: 2687db96d56Sopenharmony_ci flags = self.componentflags 2697db96d56Sopenharmony_ci if uuid is None: 2707db96d56Sopenharmony_ci uuid = gen_uuid() 2717db96d56Sopenharmony_ci else: 2727db96d56Sopenharmony_ci uuid = uuid.upper() 2737db96d56Sopenharmony_ci if component is None: 2747db96d56Sopenharmony_ci component = self.logical 2757db96d56Sopenharmony_ci self.component = component 2767db96d56Sopenharmony_ci if AMD64: 2777db96d56Sopenharmony_ci flags |= 256 2787db96d56Sopenharmony_ci if keyfile: 2797db96d56Sopenharmony_ci keyid = self.cab.gen_id(keyfile) 2807db96d56Sopenharmony_ci self.keyfiles[keyfile] = keyid 2817db96d56Sopenharmony_ci else: 2827db96d56Sopenharmony_ci keyid = None 2837db96d56Sopenharmony_ci add_data(self.db, "Component", 2847db96d56Sopenharmony_ci [(component, uuid, self.logical, flags, None, keyid)]) 2857db96d56Sopenharmony_ci if feature is None: 2867db96d56Sopenharmony_ci feature = current_feature 2877db96d56Sopenharmony_ci add_data(self.db, "FeatureComponents", 2887db96d56Sopenharmony_ci [(feature.id, component)]) 2897db96d56Sopenharmony_ci 2907db96d56Sopenharmony_ci def make_short(self, file): 2917db96d56Sopenharmony_ci oldfile = file 2927db96d56Sopenharmony_ci file = file.replace('+', '_') 2937db96d56Sopenharmony_ci file = ''.join(c for c in file if not c in r' "/\[]:;=,') 2947db96d56Sopenharmony_ci parts = file.split(".") 2957db96d56Sopenharmony_ci if len(parts) > 1: 2967db96d56Sopenharmony_ci prefix = "".join(parts[:-1]).upper() 2977db96d56Sopenharmony_ci suffix = parts[-1].upper() 2987db96d56Sopenharmony_ci if not prefix: 2997db96d56Sopenharmony_ci prefix = suffix 3007db96d56Sopenharmony_ci suffix = None 3017db96d56Sopenharmony_ci else: 3027db96d56Sopenharmony_ci prefix = file.upper() 3037db96d56Sopenharmony_ci suffix = None 3047db96d56Sopenharmony_ci if len(parts) < 3 and len(prefix) <= 8 and file == oldfile and ( 3057db96d56Sopenharmony_ci not suffix or len(suffix) <= 3): 3067db96d56Sopenharmony_ci if suffix: 3077db96d56Sopenharmony_ci file = prefix+"."+suffix 3087db96d56Sopenharmony_ci else: 3097db96d56Sopenharmony_ci file = prefix 3107db96d56Sopenharmony_ci else: 3117db96d56Sopenharmony_ci file = None 3127db96d56Sopenharmony_ci if file is None or file in self.short_names: 3137db96d56Sopenharmony_ci prefix = prefix[:6] 3147db96d56Sopenharmony_ci if suffix: 3157db96d56Sopenharmony_ci suffix = suffix[:3] 3167db96d56Sopenharmony_ci pos = 1 3177db96d56Sopenharmony_ci while 1: 3187db96d56Sopenharmony_ci if suffix: 3197db96d56Sopenharmony_ci file = "%s~%d.%s" % (prefix, pos, suffix) 3207db96d56Sopenharmony_ci else: 3217db96d56Sopenharmony_ci file = "%s~%d" % (prefix, pos) 3227db96d56Sopenharmony_ci if file not in self.short_names: break 3237db96d56Sopenharmony_ci pos += 1 3247db96d56Sopenharmony_ci assert pos < 10000 3257db96d56Sopenharmony_ci if pos in (10, 100, 1000): 3267db96d56Sopenharmony_ci prefix = prefix[:-1] 3277db96d56Sopenharmony_ci self.short_names.add(file) 3287db96d56Sopenharmony_ci assert not re.search(r'[\?|><:/*"+,;=\[\]]', file) # restrictions on short names 3297db96d56Sopenharmony_ci return file 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci def add_file(self, file, src=None, version=None, language=None): 3327db96d56Sopenharmony_ci """Add a file to the current component of the directory, starting a new one 3337db96d56Sopenharmony_ci if there is no current component. By default, the file name in the source 3347db96d56Sopenharmony_ci and the file table will be identical. If the src file is specified, it is 3357db96d56Sopenharmony_ci interpreted relative to the current directory. Optionally, a version and a 3367db96d56Sopenharmony_ci language can be specified for the entry in the File table.""" 3377db96d56Sopenharmony_ci if not self.component: 3387db96d56Sopenharmony_ci self.start_component(self.logical, current_feature, 0) 3397db96d56Sopenharmony_ci if not src: 3407db96d56Sopenharmony_ci # Allow relative paths for file if src is not specified 3417db96d56Sopenharmony_ci src = file 3427db96d56Sopenharmony_ci file = os.path.basename(file) 3437db96d56Sopenharmony_ci absolute = os.path.join(self.absolute, src) 3447db96d56Sopenharmony_ci assert not re.search(r'[\?|><:/*]"', file) # restrictions on long names 3457db96d56Sopenharmony_ci if file in self.keyfiles: 3467db96d56Sopenharmony_ci logical = self.keyfiles[file] 3477db96d56Sopenharmony_ci else: 3487db96d56Sopenharmony_ci logical = None 3497db96d56Sopenharmony_ci sequence, logical = self.cab.append(absolute, file, logical) 3507db96d56Sopenharmony_ci assert logical not in self.ids 3517db96d56Sopenharmony_ci self.ids.add(logical) 3527db96d56Sopenharmony_ci short = self.make_short(file) 3537db96d56Sopenharmony_ci full = "%s|%s" % (short, file) 3547db96d56Sopenharmony_ci filesize = os.stat(absolute).st_size 3557db96d56Sopenharmony_ci # constants.msidbFileAttributesVital 3567db96d56Sopenharmony_ci # Compressed omitted, since it is the database default 3577db96d56Sopenharmony_ci # could add r/o, system, hidden 3587db96d56Sopenharmony_ci attributes = 512 3597db96d56Sopenharmony_ci add_data(self.db, "File", 3607db96d56Sopenharmony_ci [(logical, self.component, full, filesize, version, 3617db96d56Sopenharmony_ci language, attributes, sequence)]) 3627db96d56Sopenharmony_ci #if not version: 3637db96d56Sopenharmony_ci # # Add hash if the file is not versioned 3647db96d56Sopenharmony_ci # filehash = FileHash(absolute, 0) 3657db96d56Sopenharmony_ci # add_data(self.db, "MsiFileHash", 3667db96d56Sopenharmony_ci # [(logical, 0, filehash.IntegerData(1), 3677db96d56Sopenharmony_ci # filehash.IntegerData(2), filehash.IntegerData(3), 3687db96d56Sopenharmony_ci # filehash.IntegerData(4))]) 3697db96d56Sopenharmony_ci # Automatically remove .pyc files on uninstall (2) 3707db96d56Sopenharmony_ci # XXX: adding so many RemoveFile entries makes installer unbelievably 3717db96d56Sopenharmony_ci # slow. So instead, we have to use wildcard remove entries 3727db96d56Sopenharmony_ci if file.endswith(".py"): 3737db96d56Sopenharmony_ci add_data(self.db, "RemoveFile", 3747db96d56Sopenharmony_ci [(logical+"c", self.component, "%sC|%sc" % (short, file), 3757db96d56Sopenharmony_ci self.logical, 2), 3767db96d56Sopenharmony_ci (logical+"o", self.component, "%sO|%so" % (short, file), 3777db96d56Sopenharmony_ci self.logical, 2)]) 3787db96d56Sopenharmony_ci return logical 3797db96d56Sopenharmony_ci 3807db96d56Sopenharmony_ci def glob(self, pattern, exclude = None): 3817db96d56Sopenharmony_ci """Add a list of files to the current component as specified in the 3827db96d56Sopenharmony_ci glob pattern. Individual files can be excluded in the exclude list.""" 3837db96d56Sopenharmony_ci try: 3847db96d56Sopenharmony_ci files = os.listdir(self.absolute) 3857db96d56Sopenharmony_ci except OSError: 3867db96d56Sopenharmony_ci return [] 3877db96d56Sopenharmony_ci if pattern[:1] != '.': 3887db96d56Sopenharmony_ci files = (f for f in files if f[0] != '.') 3897db96d56Sopenharmony_ci files = fnmatch.filter(files, pattern) 3907db96d56Sopenharmony_ci for f in files: 3917db96d56Sopenharmony_ci if exclude and f in exclude: continue 3927db96d56Sopenharmony_ci self.add_file(f) 3937db96d56Sopenharmony_ci return files 3947db96d56Sopenharmony_ci 3957db96d56Sopenharmony_ci def remove_pyc(self): 3967db96d56Sopenharmony_ci "Remove .pyc files on uninstall" 3977db96d56Sopenharmony_ci add_data(self.db, "RemoveFile", 3987db96d56Sopenharmony_ci [(self.component+"c", self.component, "*.pyc", self.logical, 2)]) 3997db96d56Sopenharmony_ci 4007db96d56Sopenharmony_ciclass Binary: 4017db96d56Sopenharmony_ci def __init__(self, fname): 4027db96d56Sopenharmony_ci self.name = fname 4037db96d56Sopenharmony_ci def __repr__(self): 4047db96d56Sopenharmony_ci return 'msilib.Binary(os.path.join(dirname,"%s"))' % self.name 4057db96d56Sopenharmony_ci 4067db96d56Sopenharmony_ciclass Feature: 4077db96d56Sopenharmony_ci def __init__(self, db, id, title, desc, display, level = 1, 4087db96d56Sopenharmony_ci parent=None, directory = None, attributes=0): 4097db96d56Sopenharmony_ci self.id = id 4107db96d56Sopenharmony_ci if parent: 4117db96d56Sopenharmony_ci parent = parent.id 4127db96d56Sopenharmony_ci add_data(db, "Feature", 4137db96d56Sopenharmony_ci [(id, parent, title, desc, display, 4147db96d56Sopenharmony_ci level, directory, attributes)]) 4157db96d56Sopenharmony_ci def set_current(self): 4167db96d56Sopenharmony_ci global current_feature 4177db96d56Sopenharmony_ci current_feature = self 4187db96d56Sopenharmony_ci 4197db96d56Sopenharmony_ciclass Control: 4207db96d56Sopenharmony_ci def __init__(self, dlg, name): 4217db96d56Sopenharmony_ci self.dlg = dlg 4227db96d56Sopenharmony_ci self.name = name 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_ci def event(self, event, argument, condition = "1", ordering = None): 4257db96d56Sopenharmony_ci add_data(self.dlg.db, "ControlEvent", 4267db96d56Sopenharmony_ci [(self.dlg.name, self.name, event, argument, 4277db96d56Sopenharmony_ci condition, ordering)]) 4287db96d56Sopenharmony_ci 4297db96d56Sopenharmony_ci def mapping(self, event, attribute): 4307db96d56Sopenharmony_ci add_data(self.dlg.db, "EventMapping", 4317db96d56Sopenharmony_ci [(self.dlg.name, self.name, event, attribute)]) 4327db96d56Sopenharmony_ci 4337db96d56Sopenharmony_ci def condition(self, action, condition): 4347db96d56Sopenharmony_ci add_data(self.dlg.db, "ControlCondition", 4357db96d56Sopenharmony_ci [(self.dlg.name, self.name, action, condition)]) 4367db96d56Sopenharmony_ci 4377db96d56Sopenharmony_ciclass RadioButtonGroup(Control): 4387db96d56Sopenharmony_ci def __init__(self, dlg, name, property): 4397db96d56Sopenharmony_ci self.dlg = dlg 4407db96d56Sopenharmony_ci self.name = name 4417db96d56Sopenharmony_ci self.property = property 4427db96d56Sopenharmony_ci self.index = 1 4437db96d56Sopenharmony_ci 4447db96d56Sopenharmony_ci def add(self, name, x, y, w, h, text, value = None): 4457db96d56Sopenharmony_ci if value is None: 4467db96d56Sopenharmony_ci value = name 4477db96d56Sopenharmony_ci add_data(self.dlg.db, "RadioButton", 4487db96d56Sopenharmony_ci [(self.property, self.index, value, 4497db96d56Sopenharmony_ci x, y, w, h, text, None)]) 4507db96d56Sopenharmony_ci self.index += 1 4517db96d56Sopenharmony_ci 4527db96d56Sopenharmony_ciclass Dialog: 4537db96d56Sopenharmony_ci def __init__(self, db, name, x, y, w, h, attr, title, first, default, cancel): 4547db96d56Sopenharmony_ci self.db = db 4557db96d56Sopenharmony_ci self.name = name 4567db96d56Sopenharmony_ci self.x, self.y, self.w, self.h = x,y,w,h 4577db96d56Sopenharmony_ci add_data(db, "Dialog", [(name, x,y,w,h,attr,title,first,default,cancel)]) 4587db96d56Sopenharmony_ci 4597db96d56Sopenharmony_ci def control(self, name, type, x, y, w, h, attr, prop, text, next, help): 4607db96d56Sopenharmony_ci add_data(self.db, "Control", 4617db96d56Sopenharmony_ci [(self.name, name, type, x, y, w, h, attr, prop, text, next, help)]) 4627db96d56Sopenharmony_ci return Control(self, name) 4637db96d56Sopenharmony_ci 4647db96d56Sopenharmony_ci def text(self, name, x, y, w, h, attr, text): 4657db96d56Sopenharmony_ci return self.control(name, "Text", x, y, w, h, attr, None, 4667db96d56Sopenharmony_ci text, None, None) 4677db96d56Sopenharmony_ci 4687db96d56Sopenharmony_ci def bitmap(self, name, x, y, w, h, text): 4697db96d56Sopenharmony_ci return self.control(name, "Bitmap", x, y, w, h, 1, None, text, None, None) 4707db96d56Sopenharmony_ci 4717db96d56Sopenharmony_ci def line(self, name, x, y, w, h): 4727db96d56Sopenharmony_ci return self.control(name, "Line", x, y, w, h, 1, None, None, None, None) 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ci def pushbutton(self, name, x, y, w, h, attr, text, next): 4757db96d56Sopenharmony_ci return self.control(name, "PushButton", x, y, w, h, attr, None, text, next, None) 4767db96d56Sopenharmony_ci 4777db96d56Sopenharmony_ci def radiogroup(self, name, x, y, w, h, attr, prop, text, next): 4787db96d56Sopenharmony_ci add_data(self.db, "Control", 4797db96d56Sopenharmony_ci [(self.name, name, "RadioButtonGroup", 4807db96d56Sopenharmony_ci x, y, w, h, attr, prop, text, next, None)]) 4817db96d56Sopenharmony_ci return RadioButtonGroup(self, name, prop) 4827db96d56Sopenharmony_ci 4837db96d56Sopenharmony_ci def checkbox(self, name, x, y, w, h, attr, prop, text, next): 4847db96d56Sopenharmony_ci return self.control(name, "CheckBox", x, y, w, h, attr, prop, text, next, None) 485