def softwareupdated_installhistory(start_date=None, end_date=None): '''Returns softwareupdated items from InstallHistory.plist that are within the given date range. (dates must be NSDates)''' start_date = start_date or NSDate.distantPast() end_date = end_date or NSDate.distantFuture() try: installhistory = FoundationPlist.readPlist(INSTALLHISTORY_PLIST) except FoundationPlist.FoundationPlistException: return [] return [item for item in installhistory if item.get('processName') == 'softwareupdated' and item['date'] >= start_date and item['date'] <= end_date]
def main(): # # UNIX command 'date' # if False: pr("UNIX command 'date'") cmd = 'date' r = commands.getoutput(cmd) pr("UNIX date command", r) pr("r.split()[4]", r.split()[4]) # # Python datetime # if False: pr("Python datetime") pr('datetime.datetime.now() ', datetime.datetime.now() ) t = datetime.datetime.now() - datetime.datetime.utcnow() pr("datetime.now() - datetime.utcnow()", t) pr("timedelta(-1, 68399, 999998) == timedelta(-1, 68400, 0)", datetime.timedelta(-1, 68399, 999998) == datetime.timedelta(-1, 68400, 0) ) pr("datetime.timedelta(hours=-5, seconds = -1) < t < datetime.timedelta(hours=-5, seconds = 1)", datetime.timedelta(hours=-5, seconds = -1) < t < datetime.timedelta(hours=-5, seconds = 1)) # print datetime.timedelta(hours=-5, seconds = 0) < t < datetime.timedelta(hours=-5, seconds = 1) #False # print datetime.timedelta(hours=-5, seconds = -1) < t < datetime.timedelta(hours=-5, seconds = 0) #True t2 = datetime.datetime.utcnow() + t pr('strftime("%a %Y.%m.%d %I:%M:%S")', t2.strftime("%a %Y.%m.%d %I:%M:%S") ) d3 = datetime.datetime(2011, 7, 29, 23, 46, 39) pr( 'str(d3)', str(d3) ) prr("_DATETIME_to_python(d3)", _DATETIME_to_python(d3)) # # Cocoa (Foundation) NSDate, NSCalendar, NSDateFormatter, etc. # pr("Cocoa (Foundation) NSDate, etc.") date1 = NSDate.dateWithTimeIntervalSinceReferenceDate_(333675999.713839) date2 = NSDate.dateWithTimeIntervalSinceReferenceDate_(333675999.713839 - 6 * 30 * 24 *60 * 60) date3 = NSDate.distantPast() # dateWithTimeIntervalSinceNow_(0- 6 * 30 * 24 *60 * 60) pr( "date1" , date1) pr( "date2" , date2) pr( "date3" , date3) prr("_DATETIME_to_python(date1)", _DATETIME_to_python(date1)) # pr( "str(date1) ", str(date1) ) currentCalendar = NSCalendar.currentCalendar() # # time zones # def pr_tz(l, tz): s = tz.secondsFromGMT() / (60 * 60) print "%s:\n\n %r (%s) offset %d hours%s\n" % (l,tz.name(), tz.abbreviation(), s , " (**local**)" if "Local Time Zone " in tz.description() else "") # print tz.description() # timeZone_Current = currentCalendar.timeZone() # # pr_tz('timeZone_Local', timeZone_Local) # # # s = timeZone_GMT.secondsFromGMT() / (60 * 60) # # pr("timeZone_GMT", str(timeZone_GMT) + " offset: %d hours" % s ) # pr( "timeZone_Local.isDaylightSavingTime()", timeZone_Local.isDaylightSavingTime() ) # determines whether daylight saving time is currently in effect. # pr( "timeZone_Local.daylightSavingTimeOffset()", timeZone_Local.daylightSavingTimeOffset() ) # determines the current daylight saving time offset. For most time zones this is either zero or one. # pr( "timeZone_Local.nextDaylightSavingTimeTransition()", timeZone_Local.nextDaylightSavingTimeTransition()) # Formatting for Machines: Controlled Environment Needed # # It is a whole other matter if you need to create a date string according to # the specification of a certain file format or API. # In such a case, you usually have to follow a very strict spec to # make sure the other party can read the string you are generating. # By default, NSDateFormatter uses the user’s current calendar and time zone, # which are possibly different from the requirements. # Most file formats and web APIs use the western, Gregorian calendar, # so we need to make sure that our date formatter uses it, too. dateFormatter_Local = NSDateFormatter.alloc().init() dateFormatter_Current = NSDateFormatter.alloc().init() dateFormatter_GMT = NSDateFormatter.alloc().init() dateFormatter_GMT5 = NSDateFormatter.alloc().init() dateFormatter_NY = NSDateFormatter.alloc().init() # dateFormatter_Local.__name__ = 'dateFormatter_Local' formatter_names = [ ] time_zones = [ ('Local' , NSTimeZone.localTimeZone()) , ('Current' , currentCalendar.timeZone()) , ('GMT' , NSTimeZone.timeZoneForSecondsFromGMT_(0)) , ('GMT5' , NSTimeZone.timeZoneForSecondsFromGMT_(-18000)) , ('NY' , NSTimeZone.timeZoneWithName_(u'America/New_York')) , ('System', NSTimeZone. systemTimeZone() ) , ('G' , NSTimeZone.timeZoneWithAbbreviation_(u'GMT')) ] dx = [ {'name' : n , 'tz' : tz, 'df' : NSDateFormatter.alloc().init() } for n, tz in time_zones ] s = [ "%12s: %s" % (x['name'], "%r (%s) %s%s" % tz_pr(x['tz']) ) for x in dx ] print "\n".join(s) print def eq_classes(dx, k): # z = [] d = {} for n, x in enumerate(dx): if x[k] not in d: d[x[k]] = set([ x['name'] ]) for m in range(n): y = dx[m] if x != y and x[k] == y[k]: # z.append((x['name'], y['name'])) if x[k] in d: d[x[k]].add( x['name'] ) # else: # d[x[k]] = set([ x['name'] ]) if y[k] in d: d[y[k]].add( y['name'] ) # else: # d[y[k]] = [ y['name'] ] return d print "eq_classes of dx (under tz):" print eq_classes_dx = eq_classes(dx, 'tz') print "\n".join([ "%20s: %s" % (x.name(), list(eq_classes_dx[x])) for x in eq_classes_dx]) print eq_names = [ list(eq_classes_dx[x])[0] for x in eq_classes_dx ] dx = [ z for z in dx if z['name'] in eq_names ] s = [ "%12s: %s" % (x['name'], "%r (%s) %s%s" % tz_pr(x['tz']) ) for x in dx ] print "\n".join(s) print # print "\n".join([ "%20s: %r" % [k for k in x] for x in dx ]) # format string (formatter) # format_string = "E yyyy'-'MM'-'dd' 'HH':'mm':'ss VVVV" # ==> "AD 2011-07-29 19:46:39 United States (New York)" # format_string = "E yyyy'-'MM'-'dd' 'HH':'mm':'ss VVV" # ==> " 'Fri 2011-07-29 19:46:39 GMT-04:00' format_string = "E yyyy'-'MM'-'dd' 'HH':'mm':'ss z" # ==> 'Fri 2011-07-29 19:46:39 EDT') or 'EST', or 'GMT-04:00' map ( lambda y : NSDateFormatter.setDateFormat_(y, format_string) , [x['df'] for x in dx] ) # locale locale = NSLocale.alloc().initWithLocaleIdentifier_("en_US_POSIX") pr("NSDate.date()", NSDate.date()) map ( lambda y : NSDateFormatter.setLocale_(y, locale) , [x['df'] for x in dx] ) map ( lambda y : NSDateFormatter.setTimeZone_(y[0], y[1]) , [ (x['df'], x['tz']) for x in dx] ) pr('descriptionWithCalendarFormat:timeZone:locale', date1.descriptionWithCalendarFormat_timeZone_locale_( None, None, locale) ) # format_string,NSTimeZone.timeZoneForSecondsFromGMT_(-18000),locale pr('descriptionWithCalendarFormat:timeZone:locale', date1.descriptionWithCalendarFormat_timeZone_locale_( None, NSTimeZone.timeZoneForSecondsFromGMT_(-18000), locale) ) # format_string,NSTimeZone.timeZoneForSecondsFromGMT_(-18000),locale for a in [date1, date2, date3]: dsd = get_datestrings(dx, a) s = [ "%12s: %r" % (x[0], x[1] ) for x in dsd ] print "\n".join(s) print # # date1_components # fcdc = currentCalendar.components_fromDate_( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit , date1 ) pr( "currentCalendar.components_fromDate", [ fcdc.year(), fcdc.month(), fcdc.day(), fcdc.hour(), fcdc.minute(), fcdc.second(), ] ) dateOfKeynote = currentCalendar.dateFromComponents_(fcdc) pr( "currentCalendar.dateFromComponents", dateOfKeynote )
def do_cnx_basepath(cnx, basepath, item_tally=defaultdict(list), force_folder_scan=False, scan_hidden_files=False, depth_limit=4, scan_packages=False, verbose_level=3, do_recursion=True ): GPR.verbose_level = verbose_level # # do superfolder(s) # superfolder_list = get_superfolders_list(basepath) vol_id = None n = len(superfolder_list) for i, superfolder_dict in enumerate(superfolder_list): # to indicate this is a placeholder directory entry, not a fully listed directory # (which is what an up-to-date date would indicate) # we are inserting a placeholder while there might also already be an actual one. # will be cleaned up when the placeholder is not found to be in the database? superfolder_dict[NSURLContentModificationDateKey] = NSDate.distantPast() # dvpr depth = i - n + 1 vol_id, insert_result = insertItem(cnx, superfolder_dict, vol_id, depth, item_tally) GPR.pr8(str(insert_result), vol_id, superfolder_dict, depth) # # do basepath # basepath_url = NSURL.fileURLWithPath_(basepath) basepath_dict = GetURLResourceValuesForKeys(basepath_url, enumeratorURLKeys) folderIDAtDepth = {} # dvpr depth = 0 # depth is defined as zero for basepath vol_id, insert_result = insertItem(cnx, basepath_dict, vol_id, depth, item_tally) GPR.pr8(str(insert_result), vol_id, basepath_dict, depth) # # enumerate through files and directories beneath basepath # # if we are a directory and not a package (and we don't want to do packages) # check to see if basepath is a package nsd1, error = basepath_url.resourceValuesForKeys_error_( [NSURLIsPackageKey] , None ) if not (basepath_dict[NSURLIsDirectoryKey] and (scan_packages or not nsd1[NSURLIsPackageKey] )): GPR.print_it("\nskipping basepath because, though it is a directory, it is also a package and we're not doing packages.\n", 3) item_dict = basepath_dict if basepath_dict[NSURLIsDirectoryKey] and (scan_packages or not nsd1[NSURLIsPackageKey] ): # finish up some housekeeping on basepath now that we know its a directory # folder stuff folder_id = basepath_dict['NSFileSystemFileNumber'] folderIDAtDepth[depth] = 0 # placeholder, not actively searchable list if (not insert_result.is_existing()) or options.force_folder_scan: DoDBQueryFolder(cnx, "basepath", vol_id, basepath_dict, folderIDAtDepth, depth) # the basepath enumeration enumeratorOptionKeys = 0L if not scan_packages: enumeratorOptionKeys |= NSDirectoryEnumerationSkipsPackageDescendants if not options.scan_hidden_files: enumeratorOptionKeys |= NSDirectoryEnumerationSkipsHiddenFiles enumerator2 = sharedFM.enumeratorAtURL_includingPropertiesForKeys_options_errorHandler_( basepath_url, enumeratorURLKeys, enumeratorOptionKeys, errorHandler1 ) for url in enumerator2: item_dict = GetURLResourceValuesForKeys(url, enumeratorURLKeys) # call enumerator2.skipDescendents() to skip all subdirectories print_dict_tall("item dict", item_dict, 32, 4) depth = enumerator2.level() # pop_item_stack includes copying items to the list folderContentsAtDepth # and could just to the deletion at "pop time". currently we wait until the end. if max(folderIDAtDepth.keys()) + 1 > depth: # ie, if our current stack is larger than our current depth pop_item_stack(depth, folderIDAtDepth, 4) if item_dict[NSURLIsDirectoryKey]: # is a directory # item_dict.update( { "NSURLTotalFileSizeKey": 0 }) # file size is zero for directories vol_id, insert_result = insertItem(cnx, item_dict, vol_id, depth, item_tally) # item_tally[str(insert_result)].append(item_dict[NSURLNameKey].encode('utf8')) print_label = str(insert_result) # if the directory shows as modified get database contents for the directory # DoDBQueryFolder marks this directory as "one worth following" # folder stuff if options.force_folder_scan or not insert_result.is_existing(): DoDBQueryFolder(cnx, "directory", vol_id, item_dict, folderIDAtDepth, depth) else: folderIDAtDepth[depth] = 0 # placeholder, not a real entry, won't ever match an item's folder_id # if we are looking at an existing directory (and not forced) (1) we don't need to query # database but also (2) do we even need to run the rest of the filesystem enumerator # past the database (they'll all exist, even if attribute data might have changed # without the directory being updated)? else: # not a directory # don't have to do this if we are "within" an alrady checked existing directory? # ( or we have another "force" option to scan every file? or is this force_scan?) # a file can be *updated* in the filesystem without updating the mod date of the directory? folder_id = item_dict['NSFileSystemFolderNumber'] if not (depth-1 in folderIDAtDepth and folder_id == folderIDAtDepth[depth-1] ) : # print "skipped. assumed existing because immediate folder is not updated." # no insert_item but want to tally "skipped" also print_label = "skipped" item_tally[print_label].append(item_dict[NSURLNameKey].encode('utf8')) else: vol_id, insert_result = insertItem(cnx, item_dict, vol_id, depth, item_tally) # item_tally[str(insert_result)].append(item_dict[NSURLNameKey].encode('utf8')) print_label = str(insert_result) folder_id = item_dict['NSFileSystemFolderNumber'] # # Here's where we: # (1) check to see if we need to check: check if our current item is from a folder that # we are keeping track of # (2) if we are even within a tracked folder, then we check if this particular item # is within the list obtained from the database when we "entered" this folder. # # If the current item shows as haveing just been inserted then there is no need to check # to see if it is already in the database :-) # if depth-1 in folderIDAtDepth and folder_id == folderIDAtDepth[depth-1] \ and not insert_result.is_inserted(): # Remove a file item from the list of database contents. file_id = item_dict['NSFileSystemFileNumber'] filename = item_dict[NSURLNameKey] file_mod_date = item_dict[NSURLContentModificationDateKey] s = str(file_mod_date) file_mod_date = s[:-len(" +0000")] # print file_mod_date # these fields are those of the primary key of the table (minus file_mod_date). define these somewhere/ retrieve them from the database at start? # rs = {'file_name': filename, 'vol_id': vol_id, 'folder_id': folder_id, 'file_id': file_id} rs = ( vol_id, folder_id, filename, file_id, file_mod_date) # print rs , folderContentsAtDepth[depth-1] if rs in folderContentsAtDepth[depth-1]: folderContentsAtDepth[depth-1].remove(rs) else: print "not in database list" print rs zs = folderContentsAtDepth[depth-1].tuple_d(*rs) print "zs in folderContentsAtDepth[depth-1]", zs in folderContentsAtDepth[depth-1] print folderContentsAtDepth[depth-1] # print [( "%s (%d)" % x[2:4] )for x in folderContentsAtDepth[depth-1] ] # print "filesystem item \n%s not in database list [%d] %s\n" % ( "%s (%d)" % (rs[2] , rs[3] ), depth-1, ", ".join([( "%s (%d)" % x[2:] )for x in folderContentsAtDepth[depth-1] ] )) if print_label != "skipped": GPR.pr8(print_label, vol_id, item_dict, depth) #end for url in enumerator2 # final pop(s) back up to depth zero depth = 0 # depth is defined as zero for basepath pop_item_stack(depth, folderIDAtDepth, 4) if folderIDAtDepth != {}: print "\n folderIDAtDepth is not empty!", folderIDAtDepth volume_url = basepath_dict[NSURLVolumeURLKey] DoDBInsertVolumeData(cnx, vol_id, volume_url) return (vol_id, item_dict, insert_result) # should return list of all id pairs?, list of superfolders? return (vol_id, superfolder_list, list_of_results) #item_dict for each?