6 if sys.hexversion < 0x02040000:
7 print >> sys.stderr, "Python 2.4 or newer is required."
28 Diff two folders and create delta using SS_BSDIFF
29 Will maintain same format of script that will be generated when we use diffutil
31 1. Create a list of files in each Base folders,
32 2. These files will fall into one these below categories:
33 1) Only in OLD - Should be deleted
34 2) Only in NEW - Should be added or renamed accordingly
35 3) File exists in both directories but contents are different - Create Diff.
36 4) File name is same but TYPE can change (File to Folder, Folder to Link etc.)
37 5) Duplicates in the list of Deletes and News
38 6) Close matching diffs even though name changes across directories. (for matching extension)
39 7) Clearing empty directories after Moves or diffs under Rename.
40 8) Supporting Verbatim - Any entry under Verbatim_list.txt will be treated as NEW files instead of patch.
43 1. Given two folders, from list of REMOVED and NEW files find if there
44 is version change and create diff between them
47 Want to extend the same script for entire DIFF generation and replace TOTAlib.sh file
48 Catching errors at all stages. SHOULD exit & return error in case of failure
55 global NEW_FILES_FOLDER
56 global NEW_FILES_ZIP_NAME
59 global SYMLINK_DOC_NAME
65 global SUPPORT_CONTAINERS
70 global COMMON_BIN_PATH
76 COMMON_BIN_PATH = "../../common/bin/"
77 DIFF_UTIL = "/usr/local/bin/ss_bsdiff"
78 DIFFPATCH_UTIL = "/usr/local/bin/ss_bspatch"
80 #ZIPUTIL = "7z a system.7z "
81 NEW_FILES_PATH = "system"
82 NEW_FILES_FOLDER = "system"
83 NEW_FILES_ZIP_NAME = "system.7z"
85 ATTR_DOC_EXT = "_attr.txt"
86 SYMLINK_DOC_NAME = "_sym.txt"
89 DIFF_SUFFIX = ".delta"
92 DELTA_IMG = "DELTA_IMG"
96 VERBATIM_LIST = "Verbatim_List.txt"
101 SUPPORT_RENAME = "TRUE" #Use appropriate name
102 SUPPORT_CONTAINERS = "FALSE"
103 SUPPORT_DZIMAGE = "TRUE"
104 SUPPORT_VERBATIM = "TRUE"
109 logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
111 global GenerateDiffAttr
114 if len(sys.argv) < 5:
115 sys.exit('Usage: CreatePatch.py UPDATE_TYPE PARTNAME OLDBASE NEWBASE OUTFOLDER')
116 UPDATE_TYPE = sys.argv[1]
117 PART_NAME = sys.argv[2] # lets make this also optional
119 BASE_OLD = sys.argv[3]
120 BASE_NEW = sys.argv[4]
121 OUT_DIR = sys.argv[5]
124 UPDATE_CFG_PATH = EMPTY
125 GenerateDiffAttr = "FALSE"
126 if UPDATE_TYPE == DELTA_FS:
127 #instead of arguments check it in outdirectory ?
128 if len(sys.argv) == 9:
129 ATTR_OLD = sys.argv[6]
130 ATTR_NEW = sys.argv[7]
131 UPDATE_CFG_PATH = '../'+sys.argv[8]
132 GenerateDiffAttr = "TRUE"
134 elif UPDATE_TYPE == DELTA_IMG or UPDATE_TYPE == FULL_IMG:
135 if len(sys.argv) == 7:
136 #Use path in better way
137 UPDATE_CFG_PATH = '../'+sys.argv[6]
140 global DIFFPATCH_UTIL
141 if not (os.path.isfile(DIFF_UTIL) and os.access(DIFF_UTIL, os.X_OK)):
142 DIFF_UTIL = COMMON_BIN_PATH+DIFF_UTIL
143 DIFFPATCH_UTIL = COMMON_BIN_PATH+DIFFPATCH_UTIL
144 if not (os.path.isfile(DIFF_UTIL) and os.access(DIFF_UTIL, os.X_OK)):
145 print >> sys.stderr, "Diff Util Does NOT exist -- ABORT"
146 logging.info ('Diff Util Does NOT exist -- ABORT')
149 start = datetime.datetime.now().time()
150 logging.info('*************** ENTERED PYTHON SCRIPT *****************')
151 logging.info('Arguments Passed: [UpdateType - %s][Part Name - %s] [BaseOld - %s] [BaseNew - %s] \n [OUTPUTDir - %s] [BASE ATTR - %s] [TARGET ATTR - %s]'% (UPDATE_TYPE, PART_NAME, BASE_OLD, BASE_NEW, OUT_DIR, ATTR_OLD, ATTR_NEW))
153 ensure_dir_exists(OUT_DIR)
154 if GenerateDiffAttr == "TRUE":
155 if not (os.path.isfile(ATTR_OLD) and os.path.isfile(ATTR_NEW)):
156 print >> sys.stderr, "Attributes missing -- ABORT"
160 # Should check if APT is supported on other linux flavours
162 if cache['p7zip'].is_installed and cache['attr'].is_installed and cache['tar'].is_installed:
163 logging.info ('Basic utils installed')
165 print >> sys.stderr, "Basic utils missing -- ABORT"
168 if UPDATE_TYPE == FULL_IMG:
169 SS_mk_full_img(BASE_OLD, BASE_NEW, OUT_DIR, PART_NAME, UPDATE_CFG_PATH)
170 elif UPDATE_TYPE == DELTA_IMG:
171 SS_mk_delta_img(BASE_OLD, BASE_NEW, OUT_DIR, PART_NAME, UPDATE_CFG_PATH)
172 elif UPDATE_TYPE == DELTA_FS:
173 AttributeFile = ATTR_NEW
174 ATTR_FILE = OUT_DIR+'/'+PART_NAME+ATTR_DOC_EXT
175 Diff_AttrFiles(ATTR_OLD, ATTR_NEW, ATTR_FILE)
176 Old_files, Old_dirs = Get_Files(BASE_OLD)
177 New_files, New_dirs = Get_Files(BASE_NEW)
178 SS_Generate_Delta(PART_NAME, BASE_OLD, Old_files, Old_dirs, BASE_NEW, New_files, New_dirs, OUT_DIR, ATTR_FILE)
180 if not UPDATE_CFG_PATH == EMPTY:
181 SS_update_cfg(PART_NAME, UPDATE_CFG_PATH)
184 elif UPDATE_TYPE == EXTRA:
185 print('UPDATE_TYPE ---- EXTRA')
187 print('UPDATE_TYPE ---- UNKNOWN FORMAT')
189 if GenerateDiffAttr == "TRUE":
190 if os.path.exists(ATTR_OLD) and os.path.exists(ATTR_NEW):
193 end = datetime.datetime.now().time()
195 logging.info('Max Memory requried to upgrade [%s] is [%d] for File[%s]' % (PART_NAME, MEM_REQ, MEM_FILE))
196 logging.info('*************** DONE WITH PYTHON SCRIPT ***************')
197 logging.info('Time start [%s] - Time end [%s]' % (start, end))
198 print('Done with [%s][%d]---- Time start [%s] - Time end [%s]' % (PART_NAME, MEM_REQ, start, end))
201 logging.error('Usage: {} <Update_Type> <Part_Name> <OLD_Base> <NEW_Base> <OUT_DIR>'.format(os.path.basename(sys.argv[0])))
205 def SS_update_cfg(DELTA_BIN, UPDATE_CFG_PATH):
206 f = open(UPDATE_CFG_PATH, 'r')
207 lines = f.readlines()
209 f = open(UPDATE_CFG_PATH, 'w')
211 ConfigItems = line.split()
212 if ConfigItems[0] == DELTA_BIN:
213 DELTA = ConfigItems[1]
214 logging.info ('Updating %s config' % DELTA_BIN)
215 line = line.rstrip('\n')
217 line = line.replace(line, line+'\t'+str(Value)+'\n')
223 def SS_mk_delta_img(BASE_OLD, BASE_NEW, OUT_DIR, DELTA_BIN, UPDATE_CFG_PATH):
226 ZIMAGE_SCRIPT = COMMON_BIN_PATH+'./dzImagescript.sh'
227 ZIMAGE_OLD = BASE_OLD+'_unpacked'
228 ZIMAGE_NEW = BASE_NEW+'_unpacked'
229 DZIMAGE_HEADER = 'UnpackdzImage'
232 oldsize_d= os.path.getsize(BASE_OLD)
233 newsize_d= os.path.getsize(BASE_NEW)
234 SHA_BIN_DEST= hash_file(BASE_NEW)
235 SHA_BIN_BASE=hash_file(BASE_OLD)
237 #incase UPDATE CFG is empty
239 SS_UpdateSize(BASE_OLD, BASE_NEW)
240 #Should throw error if PART NAME NOT found??
241 if not UPDATE_CFG_PATH == EMPTY:
242 f = open(UPDATE_CFG_PATH, 'r')
243 lines = f.readlines()
245 f = open(UPDATE_CFG_PATH, 'w')
247 ConfigItems = line.split()
248 if ConfigItems[0] == DELTA_BIN:
249 logging.info ('Updating %s config' % DELTA_BIN)
250 DELTA = ConfigItems[1]
251 line = line.rstrip('\n')
252 line = line.replace(line, line+'\t'+str(oldsize_d)+'\t\t'+str(newsize_d)+'\t\t'+str(SHA_BIN_BASE)+'\t\t'+str(SHA_BIN_DEST)+'\n')
258 #Any validation checks required?
259 if (DELTA_BIN == "zImage" or DELTA_BIN == "dzImage" or DELTA_BIN == "KERNEL" or DELTA_BIN == "BOOT") and SUPPORT_DZIMAGE == "TRUE":
261 #Unpack Old and New Images for creating delta
262 subprocess.call([ZIMAGE_SCRIPT, '-u', BASE_OLD])
263 subprocess.call([ZIMAGE_SCRIPT, '-u', BASE_NEW])
266 Old_files, Old_dirs = Get_Files(ZIMAGE_OLD)
267 New_files, New_dirs = Get_Files(ZIMAGE_NEW)
269 patchLoc = '%s/%s_temp' % (OUT_DIR, DELTA_BIN)
270 ensure_dir_exists(patchLoc)
272 for elt in New_files:
274 src_file = ZIMAGE_OLD+'/'+elt
275 dst_file = ZIMAGE_NEW+'/'+elt
276 if not filecmp.cmp(src_file, dst_file):
277 patch = '%s/%s' % (patchLoc,elt)
278 DeltaFiles.append(patch)
279 subprocess.call([DIFF_UTIL,src_file,dst_file,patch])
280 logging.info('Make dz Image %s <--> %s ==> %s %s' % (src_file, dst_file , DELTA_BIN, patch))
282 #Append all delta files to make image.delta
284 #HEADER FORMAT MAGICNAME:FILECOUNT:[FILENAME:FILESIZE:][FILECONTENT/S]
285 HeaderStr = DZIMAGE_HEADER+DZIMAGE_SEP+'%d' % len(DeltaFiles)
286 HeaderStr = HeaderStr+DZIMAGE_SEP
288 with open(OUT_DIR+'/'+DELTA, 'w') as DeltaFile:
289 for fname in DeltaFiles:
290 DeltaSize = os.path.getsize(fname)
291 HeaderStr = HeaderStr+path_leaf(fname)+DZIMAGE_SEP+'%d' % DeltaSize
292 HeaderStr = HeaderStr+DZIMAGE_SEP
293 #Using 128 bytes as max Header.
294 logging.info('zImage Header - %s' % HeaderStr.ljust(128,'0'))
295 DeltaFile.write(HeaderStr.ljust(128,'0'))
296 for fname in DeltaFiles:
297 with open(fname) as infile:
298 DeltaFile.write(infile.read())
302 shutil.rmtree(patchLoc)
303 shutil.rmtree(ZIMAGE_OLD)
304 shutil.rmtree(ZIMAGE_NEW)
305 #Do we need to incorprate Max memory required for backup??
308 patchLoc = '%s/%s' % (OUT_DIR, DELTA)
309 logging.info('Make Delta Image %s <--> %s ==> %s %s' % (BASE_OLD, BASE_NEW , DELTA_BIN, patchLoc))
310 subprocess.call([DIFF_UTIL,BASE_OLD,BASE_NEW,patchLoc])
314 def SS_mk_full_img(BASE_OLD, BASE_NEW, OUT_DIR, DELTA_BIN ,UPDATE_CFG_PATH):
315 logging.info('Make Full Image %s <--> %s ==> %s' % (BASE_OLD, BASE_NEW ,DELTA_BIN))
316 oldsize_d= os.path.getsize(BASE_OLD)
317 newsize_d= os.path.getsize(BASE_NEW)
318 SHA_BIN_DEST= hash_file(BASE_NEW)
319 SHA_BIN_BASE=hash_file(BASE_OLD)
320 #echo -e "\t${oldsize_d}\t\t${newsize_d}\t\t${SHA_BIN_BASE}\t\t${SHA_BIN_DEST}" >> ${DATA_DIR}/update_new.cfg
321 SS_UpdateSize(BASE_OLD, BASE_NEW)
323 if not UPDATE_CFG_PATH == EMPTY:
324 f = open(UPDATE_CFG_PATH, 'r')
325 lines = f.readlines()
327 f = open(UPDATE_CFG_PATH, 'w')
329 ConfigItems = line.split()
330 if ConfigItems[0] == DELTA_BIN:
331 logging.info ('Updating %s config' % DELTA_BIN)
332 DELTA = ConfigItems[1]
333 line = line.rstrip('\n')
334 line = line.replace(line, line+'\t'+str(oldsize_d)+'\t\t'+str(newsize_d)+'\t\t'+str(SHA_BIN_BASE)+'\t\t'+str(SHA_BIN_DEST)+'\n')
340 def zipdir(path, zip):
341 for root, dirs, files in os.walk(path):
343 zip.write(os.path.join(root, file))
345 def ensure_dir_exists(path):
346 if not os.path.exists(path):
353 head, tail = ntpath.split(path) #This is for windows?? Recheck
357 head, tail = ntpath.split(path)
360 def difflines(list1, list2):
361 c = set(list1).union(set(list2))
362 d = set(list1).intersection(set(list2))
365 #Creating Diff between OLD and NEW attribute files v12
366 def Diff_AttrFiles(ATTR_OLD, ATTR_NEW, ATTR_FILE):
367 if GenerateDiffAttr == "FALSE":
369 with open(ATTR_OLD, 'r') as f_old:
370 lines1 = set(f_old.read().splitlines())
372 with open(ATTR_NEW, 'r') as f_new:
373 lines2 = set(f_new.read().splitlines())
375 lines = difflines(lines2, lines1)
376 with open(ATTR_FILE, 'w+') as file_out:
378 if line not in lines1:
379 logging.info('Diff_AttrFiles - %s' % line)
380 file_out.write(line+'\n')
388 def Update_Attr(RequestedPath, Type, File_Attibutes, Sym_Attibutes):
389 #Full File Path should MATCH
390 if GenerateDiffAttr == "FALSE":
392 FilePath = '"/'+RequestedPath+'"'
393 #print ('FilePath - %s'% (FilePath))
394 with open(AttributeFile) as f:
397 if Type == SYMLINK_TYPE:
398 Sym_Attibutes.append(line)
400 File_Attibutes.append(line)
403 '''This function returns the SHA-1 hash of the file passed into it'''
404 def hash_file(filename):
409 # open file for reading in binary mode
410 with open(filename,'rb') as file:
411 # loop till the end of the file
414 # read only 1024 bytes at a time
415 chunk = file.read(1024*1024)
418 # return the hex representation of digest
421 def find_dupes_dir(BASE_OLD, BASE_NEW):
424 print('Finding Duplicates in - %s %s' % (BASE_OLD, BASE_NEW))
425 logging.info('Finding Duplicates in - %s %s' % (BASE_OLD, BASE_NEW))
426 for rootbase, subdirsB, fileListB in os.walk(BASE_OLD):
427 #print('Scanning %s...' % rootbase)
428 for filename in fileListB:
429 path = os.path.join(rootbase, filename)
430 if os.path.islink(path):
433 file_hash = hash_file(path)
434 dups[file_hash] = path
436 for roottarget, subdirsT, fileListT in os.walk(BASE_NEW):
437 #print('Scanning %s...' % roottarget)
438 for filename in fileListT:
439 # Get the path to the file
440 path = os.path.join(roottarget, filename)
441 if os.path.islink(path):
444 file_hash = hash_file(path)
445 # Add or append the file path
446 if file_hash in dups:
447 BaseStr = dups.get(file_hash)
448 Baseloc = path.find('/')
449 TarLoc = BaseStr.find('/')
450 if not path[Baseloc:] == BaseStr[TarLoc:]:
451 logging.info('Dupes - %s ==> %s' % (path[Baseloc:], BaseStr[TarLoc:]))
452 fdupes[path] = BaseStr
453 logging.info('Total Duplicate files %d' % (len(fdupes)))
457 def find_dupes_list(BASE_OLD, BASE_NEW, fileListB, fileListT):
460 print('Finding Duplicates in - %s %s' % (BASE_OLD, BASE_NEW))
462 for filename in fileListB:
463 Src_File = BASE_OLD+'/'+filename
464 if os.path.islink(Src_File) or os.path.isdir(Src_File):
467 file_hash = hash_file(Src_File)
468 dups[file_hash] = Src_File
471 for filename in fileListT:
472 Dest_File = BASE_NEW+'/'+filename
473 if os.path.islink(Dest_File) or os.path.isdir(Dest_File):
476 file_hash = hash_file(Dest_File)
477 if file_hash in dups:
478 BaseStr = dups.get(file_hash)
479 Baseloc = BaseStr.find('/')
480 if not BaseStr[Baseloc:] == filename:
481 #print('Dupes - %s ==> %s' % (BaseStr[Baseloc:], filename))
482 fdupes[BaseStr] = filename
484 logging.info('Total Duplicate files %d' % (len(fdupes)))
487 def SS_UpdateSize(src_file, dst_file):
490 oldsize_d= os.path.getsize(src_file)
491 newsize_d= os.path.getsize(dst_file)
492 if oldsize_d >= newsize_d:
502 def SS_Generate_Delta(PART_NAME, BASE_OLD, Old_files, Old_dirs, BASE_NEW, New_files, New_dirs, OUT_DIR, ATTR_FILE):
503 print('Going from %d files to %d files' % (len(Old_files), len(New_files)))
504 logging.info('Going from %d files to %d files' % (len(Old_files), len(New_files)))
506 # First let's fill up these categories
526 for elt in New_files:
527 if elt not in Old_files:
528 files_new.append(elt)
529 logging.info('New files %s' % elt)
531 # Generate Delete List
532 for elt in Old_files:
533 if elt not in New_files:
534 # Cant we just append it here only if this is NOT a directory???? so that we have list of removed files ONLY. including directories
535 files_removed.append(elt)
536 logging.info('Old files %s' % elt)
540 #print('List of Old Dirs %s' % elt)
541 # Delete END logic goes in hand with UPG, After Diffs and moves, DEL END should be done.
542 if elt not in New_dirs:
543 Dir_removed.append(elt)
544 logging.info('Old Dirs %s' % elt+'/')
547 if elt not in Old_dirs:
548 Dir_Added.append(elt)
549 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
551 # What files have changed contents but not name/path?
552 for elt in New_files:
554 #Both are symbolic linkes and they differ
555 src_file = BASE_OLD+'/'+elt
556 dst_file = BASE_NEW+'/'+elt
557 #print('Files Changed - %s -%s' % (src_file,dst_file))
558 if os.path.islink(src_file) and os.path.islink(dst_file):
559 if not os.readlink(src_file) == os.readlink(dst_file):
560 files_changed.append(elt)
561 #print('%d Sym link files changed' % len(files_changed))
562 logging.info('Sym links Changed - %s' % elt)
564 files_unchanged.append(elt)
565 #Both are Normal files and they differ. (Is file returns true in case of symlink also, so additional check to find either of the file is symlink)
566 elif (not (os.path.islink(src_file) or os.path.islink(dst_file))) and os.path.isfile(src_file) and os.path.isfile(dst_file):
567 if not filecmp.cmp(src_file, dst_file):
568 files_changed.append(elt)
569 #print('%d Normal files changed' % len(files_changed))
570 #print('Files Changed - %s' % elt)
572 files_unchanged.append(elt)
573 #File types differ between BASE and TARGET
575 logging.info('Files are of diff types but same names Src- %s Des- %s' % (src_file, dst_file))
576 #Both file types have changed and they differ
577 #Case 1: First Delete the OLD entry file type (Be it anything)
578 #Processing and updating partition txt file will be done under REMOVED case and NEW files case accordingly, we just make an entry here
579 files_removed.append(elt)
580 files_new.append(elt)
583 # HANDLING VERBATIM - Remove from changed list and delete the entries on device first
584 #This script is called partition wise, So, how do u want to handle it? (specialy for delete case?)
586 print("Check for any verbatim under - %s" % VERBATIM_LIST)
587 if SUPPORT_VERBATIM == "TRUE" and os.path.exists(VERBATIM_LIST):
588 with open(VERBATIM_LIST, 'r') as F_News:
589 lines = set(F_News.read().splitlines())
591 if line in files_changed:
592 files_changed.remove(line)
593 files_removed.append(line)
594 if line in files_new:
595 files_new.remove(line)
597 #Currently if Version or number is the first character of the file, then we are NOT making any diffs.
598 if SUPPORT_RENAME == "TRUE":
599 for elt in files_removed:
600 if os.path.isfile(BASE_OLD+'/'+elt):
601 FileName = path_leaf(elt)
602 entries = re.split('[0-9]' , FileName)
603 #Gives the STRING part of NAME. if name starts with version then later part wil b string
604 #print('Entires under removed list after split - %s %s - %s' % (FileName, entries[0], elt))
605 #If version is starting at the begining of the string?? shd we hav additional check for such cases??
606 if len(entries[0]) > 0:
607 files_Del_List.update({entries[0]: elt})
609 for elt in files_new:
610 if os.path.isfile(BASE_NEW+'/'+elt):
611 FileName = path_leaf(elt)
612 entries = re.split('[0-9]' , FileName)
613 #print('Entires under NEWfiles list after split - %s %s - %s' % (FileName, entries[0], elt))
614 if len(entries[0]) > 0:
615 files_New_List.update({entries[0]: elt})
617 for key, value in files_Del_List.iteritems():
618 #print('Key value pair -%s -%s' % (key, value))
619 if key in files_New_List:
620 # this file is the same name in both!
621 src_file = BASE_OLD+'/'+value
622 dst_file = BASE_NEW+'/'+files_New_List[key]
623 olddirpath = path_head(files_New_List[key])
624 newdirpath = path_head(value)
625 if os.path.islink(src_file) or os.path.islink(dst_file):
626 logging.debug('Cannot diff as one of them is Symlink')
627 elif os.path.isdir(src_file) or os.path.isdir(dst_file):
628 logging.debug('Cannot diff as one of them is dir')
630 #Pick the best diff of same type and diff names
631 files_renamed.append([files_New_List[key], value])
632 files_removed.remove(value)
633 files_new.remove(files_New_List[key])
637 Partition.txt contains Protocol for UPI
638 Types Supported: DIFFS, MOVES, NEWS, DELETES, SYMDIFFS, SYMNEWS.
647 SymLinkDoc = OUT_DIR+'/'+PART_NAME+SYMLINK_DOC_NAME
648 Partition_Doc = open(OUT_DIR+'/'+PART_NAME+'.txt','w')
649 Partition_Doc_SymLinks = open(SymLinkDoc,'w')
651 print("writing diff'ed changed files...")
652 for elt in files_changed:
653 dst_file = BASE_NEW+'/'+elt
654 src_file = BASE_OLD+'/'+elt
655 #Both files are symbolic links and they differ
656 if os.path.islink(dst_file) and os.path.islink(src_file):
657 #Both are symlinks and they differ
658 logging.debug(' File Changed is Link %s ' % dst_file)
659 patch = os.readlink(dst_file)
660 Sym_Diff_Cnt = Sym_Diff_Cnt + 1
661 Partition_Doc_SymLinks.write('SYM:DIFF:%s:%s:%s\n' % (elt, elt, patch))
662 Update_Attr(elt, "SYM", File_Attibutes, Sym_Attibutes)
663 #Both are NORMAL files and they differ
664 elif (not (os.path.islink(src_file) or os.path.islink(dst_file))) and os.path.isfile(dst_file) and os.path.isfile(src_file):
665 #Both are files and they differ
666 Diff_Cnt = Diff_Cnt + 1
667 patchName = (DIFF_PREFIX+'%d_%s_'+PART_NAME+DIFF_SUFFIX) % (Diff_Cnt, path_leaf(elt))
668 patchLoc = '%s/%s' % (OUT_DIR, patchName)
669 logging.debug(' File Differ %s %s' % (src_file, dst_file))
670 SS_UpdateSize(src_file, dst_file)
671 if SUPPORT_CONTAINERS == "TRUE":
672 if src_file.endswith('.zip') and dst_file.endswith('.zip'):
674 Partition_Doc.write('DIFF:ZIP:%s:%s:%s:%s:%s/\n' % (elt, elt, hash_file(src_file), hash_file(dst_file), patchName))
675 compute_containerdelta(src_file, dst_file, FORMAT, OUT_DIR+'/'+patchName, Partition_Doc)
676 elif src_file.endswith('.tpk') and dst_file.endswith('.tpk'):
678 Partition_Doc.write('DIFF:TPK:%s:%s:%s:%s:%s/\n' % (elt, elt, hash_file(src_file), hash_file(dst_file), patchName))
679 compute_containerdelta(src_file, dst_file, FORMAT, OUT_DIR+'/'+patchName, Partition_Doc)
682 Partition_Doc.write('DIFF:REG:%s:%s:%s:%s:%s\n' % (elt, elt, hash_file(src_file), hash_file(dst_file), patchName))
683 subprocess.call([DIFF_UTIL,src_file,dst_file,patchLoc])
686 ret = subprocess.call([DIFF_UTIL,src_file,dst_file,patchLoc])
688 logging.debug('Failed to create diff %d %s %s\n' % (ret, src_file, dst_file))
689 files_new.append(elt)
690 Diff_Cnt = Diff_Cnt - 1
692 Partition_Doc.write('DIFF:REG:%s:%s:%s:%s:%s\n' % (elt, elt, hash_file(src_file), hash_file(dst_file), patchName))
694 Update_Attr(elt, "FILE", File_Attibutes, Sym_Attibutes)
695 #Both differ but they are of diff types
697 #Processing and updating partition txt file will be done under REMOVED case and NEW files case accordingly, we just make an entry here
698 files_removed.append(elt)
699 files_new.append(elt)
701 fdupes = find_dupes_list(BASE_OLD, BASE_NEW, files_removed, files_new)
702 for oldpath, newpath in fdupes.iteritems():
703 logging.info('Dupes %s -> %s' % (oldpath, newpath))
705 for elt in files_removed:
706 src_file = BASE_OLD+'/'+elt
707 #If parent directory is deleted.. & del end not possible. (==> Moves should be done before deletes in ENGINE)
708 if src_file in fdupes.keys():
709 dst_file = BASE_NEW+'/'+ fdupes[src_file]
710 logging.debug(' File Moved %s ==> %s' % (src_file, dst_file))
711 Move_Cnt = Move_Cnt + 1
712 Partition_Doc.write('MOVE:REG:%s:%s:%s\n' % (elt, fdupes[src_file], hash_file(src_file)))
713 files_removed.remove(elt)
714 files_new.remove(fdupes[src_file])
716 #Should be placed after removing duplicates, else they will be filtered here.
717 # loop shd b for all NEW files, rather than for all delete files (Current understanding)
718 # First Step: Sort & Filter out unwanted files
719 # Minimum condition used is,
720 # 1. File name should match 70%
721 # 2. Extensions should be same
722 # 3. File name length shd b greater than 3 char
723 # 4. As we are using sorting on file names, once file name does not match and R_Flag is set to true, we nee not check remaining files. So, will execute break.
724 # 5. Should consider editdistance for RENAME LOGIC ==> TBD
726 Base_DelList = files_removed[:]
727 Base_NewList = files_new[:]
728 DelList = sorted(Base_DelList, key=path_leaf)
729 NewList = sorted(Base_NewList, key=path_leaf)
730 logging.debug('Rename Logic before filter: Delcount -%d NewCount -%d' % (len(DelList), len(NewList)))
734 #Remove unwanted items which we cant make diff with for rename logic
736 if os.path.islink(BASE_OLD+'/'+file):
738 elif os.path.isdir(BASE_OLD+'/'+file):
742 #logging.debug('Sorted del list - %s' % (file))
747 if os.path.islink(BASE_NEW+'/'+file):
749 elif os.path.isdir(BASE_NEW+'/'+file):
751 elif len(path_leaf(file)) <= 3:
752 logging.debug('Ignored for best picks -%s ' % (BASE_NEW+'/'+file))
759 logging.debug('Rename Logic After filter: Delcount -%d NewCount -%d' % (len(DelList), len(NewList)))
761 for new_file in NewList:
763 DirPathNew = path_head(new_file)
764 FileNameNew = path_leaf(new_file)
766 winning_patch_sz = os.path.getsize(BASE_NEW+'/'+new_file)
767 New_fs = winning_patch_sz
770 for del_file in DelList:
771 FileNameOld = path_leaf(del_file)
772 if (FileNameOld.startswith(FileNameNew[:len(FileNameNew)*7/10]) and (os.path.splitext(FileNameNew)[1] == os.path.splitext(del_file)[1])):
773 #winning_patch_sz = 0.9 * os.path.getsize(BASE_NEW+'/'+new_file)
774 #Percentage difference between two file sizes is within 30%, then we consider for diff generation
775 Del_fs = os.path.getsize(BASE_OLD+'/'+del_file)
776 v1 = abs(New_fs-Del_fs)
777 v2 = (New_fs+Del_fs)/2
778 if( v2<=0 or ((v1/v2) * 100) > 30 ):
779 logging.debug('Ignore diff generation New_fs - %d Del_Fs - %d' % (New_fs, Del_fs))
781 logging.debug('I can compute diff between %s %s Del_Fs - %d New_Fs - %d' % (del_file, new_file, Del_fs, New_fs))
783 DiffSize = measure_two_filediffs(BASE_OLD+'/'+del_file, BASE_NEW+'/'+new_file)
784 if (DiffSize < 0.8 * winning_patch_sz):
785 winning_patch_sz = DiffSize
786 winning_file = del_file
787 elif (not FileNameOld.startswith(FileNameNew[:len(FileNameNew)*7/10]) and R_Flag == 'TRUE'):
788 logging.debug('Becuase nex set of files will not have matching name - break @@ %s %s' % (del_file, new_file))
790 if len(winning_file) > 0:
791 logging.debug('Best Pick -%s ==> %s [%d]' % (winning_file, new_file, DiffSize))
792 files_renamed.append([new_file, winning_file])
793 DelList.remove(winning_file)
794 files_removed.remove(winning_file)
795 files_new.remove(new_file)
797 #********************** Files should NOT be deleted for any such renames ***********************
799 if SUPPORT_RENAME == "TRUE":
800 for elt in files_renamed:
801 src_file = BASE_OLD+'/'+elt[1]
802 dst_file = BASE_NEW+'/'+elt[0]
803 Diff_Cnt = Diff_Cnt + 1
804 patchName = (DIFF_PREFIX+'%d_%s_'+PART_NAME+DIFF_SUFFIX) % (Diff_Cnt, path_leaf(elt[1]))
805 #patchName = (DIFF_PREFIX+'_%s'+DIFF_SUFFIX) % (path_leaf(elt[0]))
806 patchLoc = '%s/%s' % (OUT_DIR, patchName)
807 logging.debug(' File Renamed %s ==> %s' % (src_file, dst_file))
808 # Should be careful of renaming files??
809 # Should we consider measure_two_filediffs ?? so that patch size is NOT greater than actual file?
810 # What if folder path has numerics??
812 if os.path.isdir(src_file) or os.path.isdir(dst_file):
813 #This case never occurs??
814 Partition_Doc.write('"%s" and "%s" renamed 0 0\n' % (elt[0], elt[1]))
815 Update_Attr(elt[0], "FILE", File_Attibutes, Sym_Attibutes)
816 else: #Make sure these files are PROPER and they shd NOT be symlinks
817 if filecmp.cmp(src_file, dst_file):
818 Move_Cnt = Move_Cnt + 1
819 Diff_Cnt = Diff_Cnt - 1
820 Partition_Doc.write('MOVE:REG:%s:%s:%s\n' % (elt[1], elt[0], hash_file(src_file)))
821 elif SUPPORT_CONTAINERS == "TRUE":
822 if src_file.endswith('.zip') and dst_file.endswith('.zip'):
824 Partition_Doc.write('DIFF:ZIP:%s:%s:%s:%s:%s/\n' % (elt[1], elt[0], hash_file(src_file), hash_file(dst_file), patchName))
825 compute_containerdelta(src_file, dst_file, FORMAT, OUT_DIR+'/'+patchName, Partition_Doc)
826 elif src_file.endswith('.tpk') and dst_file.endswith('.tpk'):
828 Partition_Doc.write('DIFF:TPK:%s:%s:%s:%s:%s/\n' % (elt[1], elt[0], hash_file(src_file), hash_file(dst_file), patchName))
829 compute_containerdelta(src_file, dst_file, FORMAT, OUT_DIR+'/'+patchName, Partition_Doc)
832 Partition_Doc.write('DIFF:REG:%s:%s:%s:%s:%s\n' % (elt[1], elt[0], hash_file(src_file), hash_file(dst_file), patchName))
833 subprocess.call([DIFF_UTIL,src_file,dst_file,patchLoc])
836 ret = subprocess.call([DIFF_UTIL,src_file,dst_file,patchLoc])
838 logging.debug('Failed to create diff %d %s %s\n' % (ret, src_file, dst_file))
839 files_new.append(elt)
840 Diff_Cnt = Diff_Cnt - 1
842 Partition_Doc.write('DIFF:REG:%s:%s:%s:%s:%s\n' % (elt[1], elt[0], hash_file(src_file), hash_file(dst_file), patchName))
844 SS_UpdateSize(src_file, dst_file)
845 Update_Attr(elt[0], "FILE", File_Attibutes, Sym_Attibutes)
848 #HANDLING VERBATIM - We Process NEWs and DELETEs for Verbatim list ONLY after processing duplicates & rename functionality.
849 #So that, the rename functionality will NOT create PATCH instead of verbatims.
851 if SUPPORT_VERBATIM == "TRUE" and os.path.exists(VERBATIM_LIST):
852 with open(VERBATIM_LIST, 'r') as F_News:
853 lines = set(F_News.read().splitlines())
855 if not line in files_new:
856 if os.path.exists(BASE_NEW+'/'+line):
857 files_new.append(line)
858 Verbatim_Cnt = Verbatim_Cnt+1
859 logging.debug("Added to list of verbatims -%s" % BASE_NEW+'/'+line)
863 for elt in files_removed:
864 #if files are part of patches after renaming, we shd remove them as part of removed.
865 src_file = BASE_OLD+'/'+elt
866 if os.path.islink(src_file):
867 Partition_Doc.write('DEL:SYM:%s\n' % (elt))
868 elif os.path.isdir(src_file):
869 #If we change to DIR TYPE, then the same token should be modified on UA also and SHA should be accordingly passed.
870 Partition_Doc.write('DEL:REG:%s:NA\n' % (elt))
872 Partition_Doc.write('DEL:REG:%s:%s\n' % (elt, hash_file(src_file)))
873 logging.debug(' File Deleted %s' % src_file)
874 Del_Cnt = Del_Cnt + 1
876 Dir_removed.sort(reverse=True)
877 for elt in Dir_removed:
878 #if Dir is empty, add it to the removed list.
879 src_file = BASE_OLD+'/'+elt
880 #Irrespective of weather files are MOVED or DIFF'ed, we can delete the folders. This action can be performed at the end.
881 #It covers symlinks also, as NEW symlinks cannot point to NON existant folders of TARGET (NEW binary)
882 if os.path.isdir(src_file):
883 Partition_Doc.write('DEL:END:%s\n' % (elt))
884 Del_Cnt = Del_Cnt + 1
885 logging.debug(' Dir Deleted- %s' % src_file)
888 for elt in files_new:
889 dst_file = BASE_NEW+'/'+elt
890 newfiles_dest_path = 'system/'
891 ensure_dir_exists(newfiles_dest_path)
892 if os.path.islink(dst_file):
893 patch = os.readlink(dst_file)
894 logging.debug(' File New Links %s' % elt)
895 Partition_Doc_SymLinks.write('SYM:NEW:%s:%s\n' % (elt, patch))
896 #What if this is only a new sym link and folder already exists??? Should recheck
897 destpath = newfiles_dest_path + elt
898 if not os.path.exists(path_head(destpath)):
899 os.makedirs(path_head(destpath))
900 logging.info('New SymLink - Adding missing Dir')
901 #Update_Attr(elt, "SYM", File_Attibutes, Sym_Attibutes)
902 Sym_New_Cnt = Sym_New_Cnt + 1
903 elif os.path.isdir(dst_file): # We create just empty directory here
904 destpath = newfiles_dest_path + elt
905 if not os.path.exists(destpath):
906 os.makedirs(destpath)
907 logging.debug(' File New Dir %s' % destpath)
908 New_Cnt = New_Cnt + 1
910 New_Cnt = New_Cnt + 1
911 #newfiles_dest_path = OUT_DIR + '/system/'
912 destpath = newfiles_dest_path + elt
913 destdir = os.path.dirname(destpath)
914 logging.debug('New files - %s ==> %s' % (dst_file, destdir))
916 if not os.path.isdir(destdir):
920 logging.critical('Error in NEW files DIR entry -%s' % destdir)
924 if not stat.S_ISFIFO(os.stat(dst_file).st_mode):
925 shutil.copy2(dst_file, destpath)
926 logging.debug('New files copied from- %s to- %s' % (dst_file, destpath))
928 logging.critical('Error in NEW files entry -%s -%s' % (dst_file, destpath))
931 for elt in Dir_Added:
932 newfiles_dest_path = 'system/'
933 ensure_dir_exists(newfiles_dest_path)
934 destpath = newfiles_dest_path + elt
935 if not os.path.exists(destpath):
936 os.makedirs(destpath)
937 logging.debug(' DirList New Dir %s' % destpath)
938 New_Cnt = New_Cnt + 1
940 #Base directory should be system
941 print 'Compressing New files'
943 WorkingDir = os.getcwd()
944 os.chdir(os.getcwd()+"/"+NEW_FILES_PATH)
945 logging.info('Curr Working Dir - %s' % os.getcwd())
946 os.system(ZIPUTIL+NEW_FILES_PATH+" >> " + LOGFILE)
947 shutil.move(NEW_FILES_ZIP_NAME, WorkingDir+"/"+OUT_DIR)
948 #New file size?? cos, we extract system.7z from delta.tar and then proceed with decompression
949 SS_UpdateSize(WorkingDir+"/"+OUT_DIR+"/"+NEW_FILES_ZIP_NAME, WorkingDir+"/"+OUT_DIR+"/"+NEW_FILES_ZIP_NAME)
951 shutil.rmtree(NEW_FILES_PATH)
952 # use 7z a system.7z ./*
954 #logging.info('%d Dir to be removed' % len(Dir_removed))
955 logging.info('%d files unchanged' % len(files_unchanged))
956 logging.info('%d files files_renamed' % len(files_renamed))
957 logging.info('%d files NEW' % len(files_new))
958 logging.info('%d File attr' % len(File_Attibutes))
959 logging.info('%d Sym attr' % len(Sym_Attibutes))
960 logging.info('PaTcHCoUnT:Diffs-%d Moves-%d News-%d Delets-%d SymDiffs-%d SymNews-%d Verbatim -%d\n' % (Diff_Cnt, Move_Cnt, New_Cnt, Del_Cnt, Sym_Diff_Cnt, Sym_New_Cnt, Verbatim_Cnt))
961 print('PaTcHCoUnT:Diffs-%d Moves-%d News-%d Delets-%d SymDiffs-%d SymNews-%d Verbatim -%d\n' % (Diff_Cnt, Move_Cnt, New_Cnt, Del_Cnt, Sym_Diff_Cnt, Sym_New_Cnt, Verbatim_Cnt))
963 #There could be duplicates, TODO, can check before adding..
964 ATTR_FILE_D = open(ATTR_FILE,'a+')
965 for elt in File_Attibutes:
966 ATTR_FILE_D.write(elt)
967 for elt in Sym_Attibutes:
968 ATTR_FILE_D.write(elt)
972 Partition_Doc_SymLinks.close()
973 Partition_Read_SymLinks = open(SymLinkDoc,'r+')
974 Partition_Doc.write(Partition_Read_SymLinks.read())
975 Partition_Doc.write('PaTcHCoUnT:%d %d %d %d %d %d\n' % (Diff_Cnt, Move_Cnt, New_Cnt, Del_Cnt, Sym_Diff_Cnt, Sym_New_Cnt))
976 Partition_Doc_SymLinks.close()
977 Partition_Doc.close()
978 os.remove(SymLinkDoc)
980 if Diff_Cnt + Move_Cnt + New_Cnt+ Del_Cnt + Sym_Diff_Cnt + Sym_New_Cnt + Verbatim_Cnt + os.path.getsize(ATTR_FILE) == 0:
981 print('No Delta Generated for %s - %s' % (PART_NAME,OUT_DIR))
982 logging.info('No Delta Generated for %s' % PART_NAME)
983 shutil.rmtree(OUT_DIR)
986 def Apply_Container_Delta(a_apk, b_apk, new_apk, a_folder, g_output_dir):
988 #CONTROL NAMES, AND PRINTS AND ERROR CASES... SHOULD NOT PROCEED.
989 print 'ApplyContainerDelta - ', b_apk, a_folder, g_output_dir
990 shutil.copy2(g_output_dir+'/'+b_apk, g_output_dir+'/temp')
991 temp_apk = '../'+g_output_dir+'/'+b_apk
992 Patch = 'Patch_'+b_apk
993 ensure_dir_exists(Patch)
994 shutil.copy2(g_output_dir+'/'+b_apk, Patch+'/'+b_apk)
996 #Size issue on Device side?? shd check this
997 subprocess.call(['unzip','-q', Patch+'/'+b_apk, '-d', Patch])
998 with open(g_output_dir+'/PATCH.txt', 'r') as f_new:
999 lines = set(f_new.read().splitlines())
1001 #print('Action ==> %s' % line)
1002 #Action, Path, Patch = line.split('|')
1003 Items = line.split('|')
1006 ActualPath = a_folder+'/'+Path
1007 PatchPath = Patch+'/'+Path
1008 SrcPath = g_output_dir+'/'+path_leaf(Path)
1009 #print('Action ==> %s Path ==> %s ' % (Action, Path))
1011 patchName = g_output_dir+'/'+Items[2]
1012 #print('Apply Patch: ActualPath %s SrcPath %s PatchLoc %s ' % (PatchPath, ActualPath, patchName))
1013 subprocess.call([DIFFPATCH_UTIL,ActualPath,ActualPath,patchName])
1014 WorkingDir = os.getcwd()
1015 os.chdir(WorkingDir+"/"+"temp_a")
1016 subprocess.call(['cp', '--parents', Path, '../'+Patch])
1017 os.chdir(WorkingDir)
1018 elif line[0] == 's':
1019 WorkingDir = os.getcwd()
1020 os.chdir(WorkingDir+"/"+"temp_a")
1021 subprocess.call(['cp', '--parents', Path, '../'+Patch])
1022 os.chdir(WorkingDir)
1024 print('Apply_Container_Delta - Unknown Error')
1025 #print('Touch all files and set common attributes for DIFF generation')
1026 WorkingDir = os.getcwd()
1027 os.chdir(WorkingDir+"/"+Patch)
1029 CONTAINER_DATE = '200011111111.11'
1030 CONTAINER_MODE = '0755'
1031 subprocess.call(['find', '.', '-type', 'l', '-exec', 'rm', '-rf', '{}', ';'])
1032 subprocess.call(['find', '.', '-exec', 'touch', '-t', CONTAINER_DATE, '{}', ';'])
1033 subprocess.call(['chmod', '-R', CONTAINER_MODE, '../'+Patch])
1035 print 'Update Intermediate Archive'
1036 #subprocess.call(['zip','-ryX', b_apk, '*'])
1037 subprocess.call(['zip','-ryX', b_apk] + glob.glob('*'))
1038 os.chdir(WorkingDir)
1039 #print('Apply Path completed - Now create diff for this and place in patch folder')
1041 print('Patch Applied, Create Final Diff - %s %s' % (g_output_dir+'/'+b_apk,new_apk))
1042 patchName = ('New'+'_%s'+DIFF_SUFFIX) % (b_apk)
1043 patchLoc = '%s/%s' % (g_output_dir, patchName)
1045 subprocess.call([DIFF_UTIL, Patch+'/'+b_apk ,new_apk,patchLoc])
1047 #Only on HOST... for testing
1048 if TEST_MODE == 'TRUE':
1049 UpgradedName = '%s_Upgraded' % (b_apk)
1050 subprocess.call([DIFFPATCH_UTIL,Patch+'/'+b_apk,UpgradedName,patchLoc])
1052 #This is file only with NEWS and empty diffs and same files.
1053 if TEST_MODE == 'FALSE':
1054 os.remove(g_output_dir+'/'+b_apk)
1055 os.rename(g_output_dir+'/temp', g_output_dir+'/'+b_apk)
1056 shutil.rmtree(Patch)
1058 def IsSymlink(info):
1059 return (info.external_attr >> 16) == 0120777
1062 def compute_containerdelta(src_file, dst_file, FORMAT, patchName, Partition_Doc):
1069 g_output_dir = patchName
1071 logging.info('Uncompressing Containers... [%s][%s]' % (src_file, dst_file))
1072 logging.info('Out Dir -%s' %(g_output_dir))
1073 ensure_dir_exists(a_folder)
1074 zipf = zipfile.ZipFile(a_apk, 'r');
1075 zipf.extractall(a_folder)
1078 ensure_dir_exists(b_folder)
1079 zipf = zipfile.ZipFile(b_apk, 'r');
1080 zipf.extractall(b_folder)
1084 for info in zipf.infolist():
1085 basefilename = info.filename[7:]
1087 symlinks.append(info.filename)
1088 os.remove(b_folder+'/'+info.filename)
1091 a_files, a_dirs = Get_Files(a_folder)
1092 b_files, b_dirs = Get_Files(b_folder)
1094 logging.info('Going from %d files %d files' % (len(a_files), len(b_files)))
1096 # First let's fill up these categories
1098 C_files_removed = []
1099 C_files_changed = []
1100 C_files_unchanged = []
1102 # What files appear in B but not in A?
1104 if elt not in a_files:
1105 #if not elt.endswith('.so'):
1106 C_files_new.append(elt)
1108 # What files appear in A but not in B?
1110 if elt not in b_files:
1111 C_files_removed.append(elt)
1113 # What files have changed contents but not name/path?
1116 if os.path.islink(a_folder+'/'+elt) or os.path.islink(b_folder+'/'+elt):
1117 print 'links - skip'
1118 elif not filecmp.cmp(a_folder+'/'+elt, b_folder+'/'+elt):
1119 C_files_changed.append(elt)
1121 C_files_unchanged.append(elt)
1124 print('%d new files' % len(C_files_new))
1125 print('%d removed files' % len(C_files_removed))
1126 print('%d files changed' % len(C_files_changed))
1127 print('%d files unchanged' % len(C_files_unchanged))
1129 # temp dir where we're assembling the patch
1130 ensure_dir_exists(g_output_dir)
1133 toc = open(g_output_dir+'/PATCH.txt','w')
1134 print("writing diff'ed changed files...")
1136 for elt in C_files_changed:
1137 dst_file = b_folder+'/'+elt
1138 src_file = a_folder+'/'+elt
1139 patchName = (DIFF_PREFIX+'%d_%s_'+PART_NAME+DIFF_SUFFIX) % (unique_fileid, path_leaf(elt))
1140 patchLoc = '%s/%s' % (g_output_dir, patchName)
1141 #print('src - %s dest -%s patch -%s' % (src_file ,dst_file,patchLoc))
1142 subprocess.call([DIFF_UTIL,src_file ,dst_file,patchLoc])
1143 toc.write('c%d|%s|%s\n' % (unique_fileid, elt, patchName))
1144 unique_fileid = unique_fileid + 1
1146 for elt in C_files_unchanged:
1147 dst_file = b_folder+'/'+elt
1148 src_file = a_folder+'/'+elt
1149 #print('Same Files src - %s dest -%s' % (src_file ,dst_file))
1150 toc.write('s%d|%s\n' % (unique_fileid, elt))
1151 unique_fileid = unique_fileid + 1
1153 #Create NEW TPK with empty data for below files and NEW files
1154 shutil.copy2(b_apk, g_output_dir)
1157 #temp_apk = '../'+g_output_dir+'/'+b_apk
1158 temp_apk = '../'+g_output_dir+'/'+path_leaf(b_apk)
1160 for elt in C_files_changed:
1161 dst_file = b_folder+'/'+elt
1163 open(dst_file, 'w').close()
1165 for elt in C_files_unchanged:
1166 dst_file = b_folder+'/'+elt
1167 open(dst_file, 'w').close()
1169 WorkingDir = os.getcwd()
1170 os.chdir(WorkingDir+"/"+b_folder)
1172 #for elt in files_changed:
1173 # subprocess.call(['zip', temp_apk, elt]) # confirm ZIP options, extra fields etc.. jus zip it, shd do all at once.. else time taking
1175 #for elt in files_unchanged:
1176 # subprocess.call(['zip', temp_apk, elt])
1178 subprocess.call(['zip','-ryq', temp_apk, '*'])
1179 os.chdir(WorkingDir)
1182 Apply_Container_Delta(path_leaf(a_apk), path_leaf(b_apk), b_apk, a_folder, g_output_dir)
1183 shutil.rmtree(a_folder)
1184 shutil.rmtree(b_folder)
1186 def NewFiles(src, dest):
1188 subprocess.call(['cp','-rp', src,dest])
1190 #shutil.copytree(src, dest)
1191 #except OSError as e:
1192 # If the error was caused because the source wasn't a directory
1193 #if e.errno == errno.ENOTDIR:
1194 #shutil.copy2(src, dest)
1196 #print('Directory not copied. Error: %s' % e)
1198 def measure_two_filediffs(src, dst):
1199 patchLoc = 'temp.patch'
1200 subprocess.call([DIFF_UTIL,src,dst,patchLoc])
1201 result_size = os.path.getsize(patchLoc)
1205 def Get_Files(path):
1209 for root, directories, filenames in os.walk(path, topdown=False, followlinks=False):
1210 for directory in directories:
1211 #DirName = os.path.join(root+'/',directory)
1212 DirName = os.path.join(root,directory)
1213 if os.path.islink(DirName):
1214 logging.debug('This is symlink pointing to dir -%s' % DirName)
1215 all_files.append(os.path.relpath(DirName, path))
1216 elif not os.listdir(DirName):
1217 #print('*****Empty Directory******* -%s', DirName)
1218 #This should NOT be appended ??? Empty dir shd b considered
1219 all_dirs.append(os.path.relpath(DirName, path))
1221 all_dirs.append(os.path.relpath(DirName, path))
1222 for filename in filenames:
1223 FileName = os.path.join(root,filename)
1224 all_files.append(os.path.relpath(FileName, path))
1228 return all_files, all_dirs
1231 USAGE_DOCSTRING = """
1232 Generate Delta using BASEOLD AND BASE NEW
1233 Attributes is optional
1234 Usage: CreatePatch.py UPDATE_TYPE PARTNAME OLDBASE NEWBASE OUTFOLDER
1237 def Usage(docstring):
1238 print docstring.rstrip("\n")
1239 print COMMON_DOCSTRING
1243 if __name__ == '__main__':