File: android-deltas-sync/x-export-phone-part2-pc.py

#!/usr/bin/env python3
"""
=======================================================================
Export Phone Content, Part 2: PC    [new in 1.2]

Run exports occasionally (if ever) to propagate your on-phone content 
changes to both PC and proxy drive, with an on-phone zip and fast 
Mergealls to PC and proxy.  Use this after changing content on your
phone, to propagate the on-phone changes to your PC and proxy.

See also x-export-phone-part1-phone.py's Details and **CAUTION**.

See _README.html for license, attribution, version, and docs.

-----------------------------------------------------------------------
Usage:

Run this on your PC second (after running Part 1 on your phone), with:

     python3 x-export-phone-part2-pc.py

Run this in Terminal on macOS and Linux; and in Command Prompt,
PowerShell, Cygwin, or WSL on Windows.  Replace its "python3" 
with "python" where needed, and "py -3" in basic Windows shells.
This file may also be run with no command line by click or IDE.

Run this from any folder.  It uses paths set in config_pc.py,
and finds that and common.py in its own folder automatically.

Step runtimes are shown in the console after step completion.  
Step outputs go to files in LOGS; watch with 'tail -f LOGS/file'.

-----------------------------------------------------------------------
Notes:

0) "PC" here means a Windows, macOS, or Linux device, but "phone" 
can be anything: though designed to sync changes to Android 11 and 
later, these scripts can also sync to earlier Androids and PCs.

1) You can run the unzip and Mergeall steps here manually; this 
script is simply a convenience that automates the steps and
follows the rest of this package's motif, with error/safety checks.

2) This uses the PC config's settings unchanged, but inverts 
their meaning: "FROM" (the on-PC copy) is what the phone zip's
content is synced TO, and "TO" (the proxy drive) is really 
both FROM here (for the zip) and a TO (for a sync).  The phone
zip is assumed to be at the root of the TO proxy drive.

3) Caveat: exporting makes a full-content zipfile on the phone,
which is then moved to the proxy drive and unzipped on the PC.
Hence, you'll need _twice_ the size of full content on all three
devices.  This is unavoidable without on-phone POSIX USB access. 

4) This uses _uncompressed_ zips for speed; the space savings for 
compression is minimal, and won't help much with the preceding note.

5) This does _not_ move the phone-copy zip from proxy to PC, even 
though that may be faster than unzipping from the proxy, because
moving the zip to PC would raise the PC space requirement from 2X
to 3X content size - for both a content zip and content unzip.

6) This does _not_ delete the old PC+proxy copies and copy the
unzipped phone copy to them; a Mergeall run for each generally
brings them up to synch much faster than exhaustive copies.
=======================================================================
"""

import os, sys, shutil
from os.path import join

import config_pc, common              # get PC settings and common code 
common.startup(config_pc, common)     # copy and use PC config's settings
from common import *                  # use both's top-level names as globals

# subjects
TOroot = driveRootPath(TO)
prxzip = join(TOroot, 'PHONE.zip')    # where phone zip was put on proxy

tmpfld = join(FROM,   'PHONE')        # where phone zip is unzipped (temp)
tmpsrc = join(tmpfld, STUFF)          # where unzipped content is nested

thesrc = join(FROM,   STUFF)          # where content is on PC
thedst = join(TO,     STUFF)          # where content is on proxy

# proxy zip and both 'to' (pc and proxy) must exist here
if not os.path.isfile(prxzip):
    print('The TO/PHONE.zip file does not exist on the proxy: "%s"' % prxzip)
    print('Exiting; please check the config file and rerun.')
    shutdown(bad=True)

if not os.path.isdir(thesrc):
    print('The FROM/STUFF on-PC content folder does not exist: "%s"' % thesrc)
    print('Exiting; please check the config file and rerun.')
    shutdown(bad=True)

if not os.path.isdir(thedst):
    print('The TO/STUFF on-proxy content folder does not exist: "%s"' % thedst)
    print('Exiting; please check the config file and rerun.')
    shutdown(bad=True)

opener('Exporting:\nfrom %s\nto   %s\nand  %s\nlogs %s' % (prxzip, thesrc, thedst, LOGS))


#----------------------------------------------------------------
# 1) Unzip phone content on PC with [zip-extract.py] in console
#----------------------------------------------------------------

# Nit: this could warn about symlink overwrites, but it's well documented

# Do not move zipfile from proxy to PC: faster, but requires 3X space

announce('Unzipping phone content on pc to temp folder')
logto = join(LOGS, '%s--export-1-unzip-log.txt' % DATE)

# delete an existing content tree, iff approved
removeExistingOrStop(tmpfld, 'pc (temp unzip copy)')

# disables updates in app-specific storage on phone: likely moot here
permissions = ('-permissions',)

runpy(join(ZIP, 'zip-extract.py'), 
      prxzip, tmpfld, *permissions,             # makes tmpfld/STUFF == tmpsrc
      logpath=logto,
      tailing=(1, 'Zip extract summary'))


#----------------------------------------------------------------
# 2) Sync phone copy to PC copy, via mergeall update run
#----------------------------------------------------------------

# Do not replace existing PC copy via del+unzip: slower than mergeall
# Use PC-side backups config for PC+proxy updates: generally recommended

# backup PC+proxy changes? (fast but consumes space)
backup = ('-backup',) if BackupChanges else ()


def viewAndSyncWithMergeall(target, label, lognum):
    """
    Reused: this code is the same for PC and proxy, sans the parameters
    """
    assert target in (thesrc, thedst) and lognum in (2, 4)
    userreply = input("\nView diffs in %s's content copy (y or n)?" % label)
    if userreply == 'y':
        announce('Running mergeall to view %s diffs' % label)
        logto = join(LOGS, '%s--export-%d-mergeall-view-%s-log.txt' 
                            % (DATE, lognum, label.lower()) )

        runpy(join(MALL, 'mergeall.py'),
              tmpsrc, target, '-report', '-skipcruft', '-quiet',
              logpath=logto,
              tailing=(9, 'Mergeall summary'))

        userreply = input('\nShow full Mergeall output (y or n)?')
        if userreply == 'y':
            print(open(logto, 'r', encoding='utf8').read())

    userreply = input("\nSync %s's content copy to match phone (y or n)?" % label)
    if userreply == 'y':
        announce('Running mergeall to sync %s content' % label)
        logto = join(LOGS, '%s--export-%d-mergeall-sync-%s-log.txt' 
                            % (DATE, lognum+1, label.lower()) )

        runpy(join(MALL, 'mergeall.py'), 
              tmpsrc, target, '-auto', *backup, '-skipcruft', '-quiet',
              logpath=logto,
              tailing=(9, 'Mergeall summary'))

        userreply = input('\nShow full Mergeall output (y or n)?')
        if userreply == 'y':
            print(open(logto, 'r', encoding='utf8').read())


viewAndSyncWithMergeall(target=thesrc, label='PC', lognum=2)


#----------------------------------------------------------------
# 3) Sync phone copy to proxy copy, via mergeall update run
#----------------------------------------------------------------

# Do not replace existing proxy copy via del+unzip: slower than mergeall

viewAndSyncWithMergeall(target=thedst, label='proxy', lognum=4)


#----------------------------------------------------------------
# 4) Cleanup content zip on proxy, and content folder on PC
#----------------------------------------------------------------

# Ask first: may want to retain either/both if diffs to be analyzed, etc.

userreply = input("\nRemove export's zipfile from proxy drive (y or n)?")
if userreply == 'y':
    timefunc(lambda: os.remove(prxzip))
else:
    print('Retained "%s"' % prxzip)

userreply = input("\nRemove export's unzipped content folder from PC (y or n)?")
if userreply == 'y':
    timefunc(lambda: rmtree_FWP(tmpfld, required=False))
else:
    print('Retained "%s"' % tmpfld)


#----------------------------------------------------------------
# Optional: verify PC and proxy are the same post syncs
#----------------------------------------------------------------

verifyPCtoProxy('export-6', 'export-7')    # mergeall/diffall log names


closer('See logs in "%s".' % LOGS)



[Home page] Books Code Blog Python Author Train Find ©M.Lutz