1
0
mirror of https://github.com/google/adb-sync.git synced 2026-01-03 09:58:01 +00:00

Fix lint, and make logging actually work again.

This commit is contained in:
Rudolf Polzer
2018-11-27 12:55:22 -08:00
parent 270bfe6b3a
commit bcd3541697

126
adb-sync
View File

@@ -17,14 +17,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import argparse import argparse
import glob
import locale import locale
import logging import logging
import os import os
import re import re
import stat import stat
import subprocess import subprocess
import sys
import time import time
from types import TracebackType from types import TracebackType
from typing import Callable, cast, Dict, List, IO, Iterable, Optional, Tuple, Type from typing import Callable, cast, Dict, List, IO, Iterable, Optional, Tuple, Type
@@ -32,25 +30,28 @@ from typing import Callable, cast, Dict, List, IO, Iterable, Optional, Tuple, Ty
class OSLike(object): class OSLike(object):
def listdir(self, path: bytes) -> Iterable[bytes]: def listdir(self, path: bytes) -> Iterable[bytes]: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def lstat(self, path: bytes) -> os.stat_result: def lstat(self, path: bytes) -> os.stat_result: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def unlink(self, path: bytes) -> None: def unlink(self, path: bytes) -> None: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def rmdir(self, path: bytes) -> None: def rmdir(self, path: bytes) -> None: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def makedirs(self, path: bytes) -> None: def makedirs(self, path: bytes) -> None: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def utime(self, path: bytes, times: Tuple[float, float]) -> None: def utime(self, path: bytes, times: Tuple[float, float]) -> None: # os's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
def glob(self, path: bytes) -> Iterable[bytes]:
class GlobLike(object):
def glob(self, path: bytes) -> Iterable[bytes]: # glob's name, so pylint: disable=g-bad-name
raise NotImplementedError('Abstract') raise NotImplementedError('Abstract')
@@ -83,7 +84,7 @@ class Stdout(object):
return False return False
class AdbFileSystem(OSLike): class AdbFileSystem(GlobLike, OSLike):
"""Mimics os's file interface but uses the adb utility.""" """Mimics os's file interface but uses the adb utility."""
def __init__(self, adb: List[bytes]) -> None: def __init__(self, adb: List[bytes]) -> None:
@@ -118,16 +119,16 @@ class AdbFileSystem(OSLike):
[ ]+ [ ]+
[^ ]+ # Group name/ID. [^ ]+ # Group name/ID.
[ ]+ [ ]+
(?(S_IFBLK) [^ ]+[ ]+[^ ]+[ ]+) # Device numbers. (?(S_IFBLK) [^ ]+[ ]+[^ ]+[ ]+) # Device numbers.
(?(S_IFCHR) [^ ]+[ ]+[^ ]+[ ]+) # Device numbers. (?(S_IFCHR) [^ ]+[ ]+[^ ]+[ ]+) # Device numbers.
(?(S_IFDIR) [0-9]+ [ ]+)? # directory Size. (?(S_IFDIR) [0-9]+ [ ]+)? # directory Size.
(?(S_IFREG) (?(S_IFREG)
(?P<st_size> [0-9]+) # Size. (?P<st_size> [0-9]+) # Size.
[ ]+) [ ]+)
(?P<st_mtime> (?P<st_mtime>
[0-9]{4}-[0-9]{2}-[0-9]{2} # Date. [0-9]{4}-[0-9]{2}-[0-9]{2} # Date.
[ ] [ ]
[0-9]{2}:[0-9]{2}) # Time. [0-9]{2}:[0-9]{2}) # Time.
[ ] [ ]
# Don't capture filename for symlinks (ambiguous). # Don't capture filename for symlinks (ambiguous).
(?(S_IFLNK) .* | (?P<filename> .*)) (?(S_IFLNK) .* | (?P<filename> .*))
@@ -253,7 +254,7 @@ class AdbFileSystem(OSLike):
if line.startswith(b'total '): if line.startswith(b'total '):
continue continue
line = line.rstrip(b'\r\n') line = line.rstrip(b'\r\n')
statdata, filename = self.LsToStat(line) statdata, _ = self.LsToStat(line)
self.stat_cache[path] = statdata self.stat_cache[path] = statdata
return statdata return statdata
raise OSError('No such file or directory') raise OSError('No such file or directory')
@@ -297,7 +298,7 @@ class AdbFileSystem(OSLike):
b'touch -at %s %s' % (timestr, self.QuoteArgument(path))]) != 0: b'touch -at %s %s' % (timestr, self.QuoteArgument(path))]) != 0:
raise OSError('touch failed') raise OSError('touch failed')
def glob(self, path: bytes) -> Iterable[bytes]: def glob(self, path: bytes) -> Iterable[bytes]: # glob's name, so pylint: disable=g-bad-name
with Stdout( with Stdout(
self.adb + self.adb +
[b'shell', b'for p in %s; do echo "$p"; done' % (path,)]) as stdout: [b'shell', b'for p in %s; do echo "$p"; done' % (path,)]) as stdout:
@@ -626,7 +627,7 @@ class FileSyncer(object):
dt) dt)
def ExpandWildcards(globber: OSLike, path: bytes) -> Iterable[bytes]: def ExpandWildcards(globber: GlobLike, path: bytes) -> Iterable[bytes]:
if path.find(b'?') == -1 and path.find(b'*') == -1 and path.find(b'[') == -1: if path.find(b'?') == -1 and path.find(b'*') == -1 and path.find(b'[') == -1:
return [path] return [path]
return globber.glob(path) return globber.glob(path)
@@ -654,25 +655,27 @@ def FixPath(src: bytes, dst: bytes) -> Tuple[bytes, bytes]:
def main() -> None: def main() -> None:
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Synchronize a directory between an Android device and the ' + description='Synchronize a directory between an Android device and the '
'local file system') 'local file system')
parser.add_argument( parser.add_argument(
'source', 'source',
metavar='SRC', metavar='SRC',
type=str, type=str,
nargs='+', nargs='+',
help='The directory to read files/directories from. ' + help='The directory to read files/directories from. '
'This must be a local path if -R is not specified, ' + 'This must be a local path if -R is not specified, '
'and an Android path if -R is specified. If SRC does ' + 'and an Android path if -R is specified. If SRC does '
'not end with a final slash, its last path component ' + 'not end with a final slash, its last path component '
'is appended to DST (like rsync does).') 'is appended to DST (like rsync does).')
parser.add_argument( parser.add_argument(
'destination', 'destination',
metavar='DST', metavar='DST',
type=str, type=str,
help='The directory to write files/directories to. ' + help='The directory to write files/directories to. '
'This must be an Android path if -R is not specified, ' + 'This must be an Android path if -R is not specified, '
'and a local path if -R is specified.') 'and a local path if -R is specified.')
parser.add_argument( parser.add_argument(
'-e', '-e',
@@ -684,38 +687,38 @@ def main() -> None:
parser.add_argument( parser.add_argument(
'--device', '--device',
action='store_true', action='store_true',
help='Directs command to the only connected USB device; ' + help='Directs command to the only connected USB device; '
'returns an error if more than one USB device is ' + 'present. ' + 'returns an error if more than one USB device is present. '
'Corresponds to the "-d" option of adb.') 'Corresponds to the "-d" option of adb.')
parser.add_argument( parser.add_argument(
'--emulator', '--emulator',
action='store_true', action='store_true',
help='Directs command to the only running emulator; ' + help='Directs command to the only running emulator; '
'returns an error if more than one emulator is running. ' + 'returns an error if more than one emulator is running. '
'Corresponds to the "-e" option of adb.') 'Corresponds to the "-e" option of adb.')
parser.add_argument( parser.add_argument(
'-s', '-s',
'--serial', '--serial',
metavar='DEVICE', metavar='DEVICE',
type=str, type=str,
help='Directs command to the device or emulator with ' + help='Directs command to the device or emulator with '
'the given serial number or qualifier. Overrides ' + 'the given serial number or qualifier. Overrides '
'ANDROID_SERIAL environment variable. Use "adb devices" ' + 'ANDROID_SERIAL environment variable. Use "adb devices" '
'to list all connected devices with their respective ' + 'serial number. ' 'to list all connected devices with their respective serial number. '
+ 'Corresponds to the "-s" option of adb.') 'Corresponds to the "-s" option of adb.')
parser.add_argument( parser.add_argument(
'-H', '-H',
'--host', '--host',
metavar='HOST', metavar='HOST',
type=str, type=str,
help='Name of adb server host (default: localhost). ' + help='Name of adb server host (default: localhost). '
'Corresponds to the "-H" option of adb.') 'Corresponds to the "-H" option of adb.')
parser.add_argument( parser.add_argument(
'-P', '-P',
'--port', '--port',
metavar='PORT', metavar='PORT',
type=str, type=str,
help='Port of adb server (default: 5037). ' + help='Port of adb server (default: 5037). '
'Corresponds to the "-P" option of adb.') 'Corresponds to the "-P" option of adb.')
parser.add_argument( parser.add_argument(
'-R', '-R',
@@ -726,54 +729,57 @@ def main() -> None:
'-2', '-2',
'--two-way', '--two-way',
action='store_true', action='store_true',
help='Two-way sync (compare modification time; after ' + help='Two-way sync (compare modification time; after '
'the sync, both sides will have all files in the ' + 'the sync, both sides will have all files in the '
'respective newest version. This relies on the clocks ' + 'respective newest version. This relies on the clocks '
'of your system and the device to match.') 'of your system and the device to match.')
#parser.add_argument('-t', '--times', action='store_true', parser.add_argument(
# help='Preserve modification times when copying.') '-t',
'--times',
action='store_true',
help='Preserve modification times when copying.')
parser.add_argument( parser.add_argument(
'-d', '-d',
'--delete', '--delete',
action='store_true', action='store_true',
help='Delete files from DST that are not present on ' + help='Delete files from DST that are not present on '
'SRC. Mutually exclusive with -2.') 'SRC. Mutually exclusive with -2.')
parser.add_argument( parser.add_argument(
'-f', '-f',
'--force', '--force',
action='store_true', action='store_true',
help='Allow deleting files/directories when having to ' + help='Allow deleting files/directories when having to '
'replace a file by a directory or vice versa. This is ' + 'replace a file by a directory or vice versa. This is '
'disabled by default to prevent large scale accidents.') 'disabled by default to prevent large scale accidents.')
parser.add_argument( parser.add_argument(
'-n', '-n',
'--no-clobber', '--no-clobber',
action='store_true', action='store_true',
help='Do not ever overwrite any ' + help='Do not ever overwrite any '
'existing files. Mutually exclusive with -f.') 'existing files. Mutually exclusive with -f.')
parser.add_argument( parser.add_argument(
'--dry-run', '--dry-run',
action='store_true', action='store_true',
help='Do not do anything - just show what would ' + 'be done.') help='Do not do anything - just show what would be done.')
args = parser.parse_args() args = parser.parse_args()
args_encoding = locale.getdefaultlocale()[1] args_encoding = locale.getdefaultlocale()[1] or 'ascii'
localpatterns = [x.encode(args_encoding) for x in args.source] localpatterns = [x.encode(args_encoding) for x in args.source]
remotepath = args.destination.encode(args_encoding) remotepath = args.destination.encode(args_encoding)
adb = args.adb.encode(args_encoding).split(b' ') adb_args = args.adb.encode(args_encoding).split(b' ')
if args.device: if args.device:
adb += [b'-d'] adb_args += [b'-d']
if args.emulator: if args.emulator:
adb += [b'-e'] adb_args += [b'-e']
if args.serial != None: if args.serial:
adb += [b'-s', args.serial.encode(args_encoding)] adb_args += [b'-s', args.serial.encode(args_encoding)]
if args.host != None: if args.host:
adb += [b'-H', args.host.encode(args_encoding)] adb_args += [b'-H', args.host.encode(args_encoding)]
if args.port != None: if args.port:
adb += [b'-P', args.port.encode(args_encoding)] adb_args += [b'-P', args.port.encode(args_encoding)]
adb = AdbFileSystem(adb) adb = AdbFileSystem(adb_args)
# Expand wildcards. # Expand wildcards, but only on the remote side.
localpaths = [] localpaths = []
remotepaths = [] remotepaths = []
if args.reverse: if args.reverse:
@@ -788,7 +794,7 @@ def main() -> None:
localpaths.append(src) localpaths.append(src)
remotepaths.append(dst) remotepaths.append(dst)
preserve_times = False # args.times preserve_times = args.times
delete_missing = args.delete delete_missing = args.delete
allow_replace = args.force allow_replace = args.force
allow_overwrite = not args.no_clobber allow_overwrite = not args.no_clobber