本文整理汇总了Python中synctool.lib.stdout函数的典型用法代码示例。如果您正苦于以下问题:Python stdout函数的具体用法?Python stdout怎么用?Python stdout使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了stdout函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Python代码示例。
示例1: compare
def compare(self, _src_path, dest_stat):
# type: (str, SyncStat) -> bool
'''see if devs are the same'''
if not self.exists:
return False
# dest_stat is a SyncStat object and it's useless here
# I need a real, fresh statbuf that includes st_rdev field
try:
dest_stat = os.lstat(self.name)
except OSError as err:
error('error checking %s : %s' % (self.name, err.strerror))
return False
# Note: mypy triggers false errors here
# Also, no luck with Union[SyncStat, posix.stat_result]
# In any case, for VNodeChrDev and VNodeBlkDev,
# the self.src_stat is of type posix.stat_result
src_major = os.major(self.src_stat.st_rdev) # type: ignore
src_minor = os.minor(self.src_stat.st_rdev) # type: ignore
dest_major = os.major(dest_stat.st_rdev) # type: ignore
dest_minor = os.minor(dest_stat.st_rdev) # type: ignore
if src_major != dest_major or src_minor != dest_minor:
stdout('%s should have major,minor %d,%d but has %d,%d' %
(self.name, src_major, src_minor, dest_major, dest_minor))
unix_out('# updating major,minor %s' % self.name)
terse(synctool.lib.TERSE_SYNC, self.name)
return False
return True
开发者ID:walterdejong,项目名称:synctool,代码行数:31,代码来源:object.py
示例2: _single_overlay_callback
def _single_overlay_callback(obj, post_dict, updated, *args):
'''do overlay function for single files'''
if obj.ov_type == synctool.overlay.OV_TEMPLATE:
return generate_template(obj, post_dict), False
go_on = True
if _match_single(obj.dest_path):
_, updated = _overlay_callback(obj, post_dict, False, *args)
if not updated:
stdout('%s is up to date' % obj.dest_path)
terse(synctool.lib.TERSE_OK, obj.dest_path)
unix_out('# %s is up to date\n' % obj.dest_path)
else:
# register .post on the parent dir, if it has a .post script
obj.dest_path = os.path.dirname(obj.dest_path)
obj.dest_stat = synctool.syncstat.SyncStat(obj.dest_path)
if obj.dest_path in post_dict:
changed_dict = args[0]
changed_dict[obj.dest_path] = (obj, post_dict[obj.dest_path])
if not SINGLE_FILES:
return False, updated
return go_on, updated
开发者ID:dineshbhoopathy,项目名称:synctool,代码行数:27,代码来源:client.py
示例3: worker_dsh_cp
def worker_dsh_cp(addr):
'''do remote copy to node'''
nodename = NODESET.get_nodename_from_address(addr)
if nodename == synctool.param.NODENAME:
# do not copy to local node; files are already here
return
# the fileset already has been added to DSH_CP_CMD_ARR
# create local copy of DSH_CP_CMD_ARR
# or parallelism may screw things up
dsh_cp_cmd_arr = DSH_CP_CMD_ARR[:]
dsh_cp_cmd_arr.append('%s:%s' % (addr, DESTDIR))
msg = 'copy %s to %s' % (FILES_STR, DESTDIR)
if synctool.lib.DRY_RUN:
msg += ' (dry run)'
if synctool.lib.OPT_NODENAME:
msg = ('%s: ' % nodename) + msg
stdout(msg)
unix_out(' '.join(dsh_cp_cmd_arr))
if not synctool.lib.DRY_RUN:
synctool.lib.run_with_nodename(dsh_cp_cmd_arr, nodename)
开发者ID:dineshbhoopathy,项目名称:synctool,代码行数:26,代码来源:dsh_cp.py
示例4: compare
def compare(self, src_path, dest_stat):
'''see if devs are the same'''
if not self.exists:
return False
# dest_stat is a SyncStat object and it's useless here
# I need a real, fresh statbuf that includes st_rdev field
try:
dest_stat = os.lstat(self.name)
except OSError as err:
error('error checking %s : %s' % (self.name, err.strerror))
return False
src_major = os.major(self.src_stat.st_rdev)
src_minor = os.minor(self.src_stat.st_rdev)
dest_major = os.major(dest_stat.st_rdev)
dest_minor = os.minor(dest_stat.st_rdev)
if src_major != dest_major or src_minor != dest_minor:
stdout('%s should have major,minor %d,%d but has %d,%d' %
(self.name, src_major, src_minor, dest_major, dest_minor))
unix_out('# updating major,minor %s' % self.name)
terse(synctool.lib.TERSE_SYNC, self.name)
return False
return True
开发者ID:dot-Sean,项目名称:synctool,代码行数:26,代码来源:object.py
示例5: _single_purge_callback
def _single_purge_callback(obj, pre_dict, post_dict):
# type: (SyncObject, Dict[str, str], Dict[str, str]) -> Tuple[bool, bool]
'''do purge function for single files'''
# The same as _single_overlay_callback(), except that
# purge entries may differ in timestamp. synctool has to report
# this because pure rsync will as well (which is bloody annoying)
#
# For normal synctool overlay/, it's regarded as not important
# and synctool will not complain about it
#
# This actually leaves a final wart; synctool --single may create
# purge entries that rsync will complain about and sync again
# Anyway, I don't think it's a big deal, and that's what you get
# when you mix up synctool and rsync
go_on = True
updated = False
if _match_single(obj.dest_path):
_, updated = _overlay_callback(obj, pre_dict, post_dict)
if not updated:
if obj.check_purge_timestamp():
stdout('%s is up to date' % obj.dest_path)
terse(synctool.lib.TERSE_OK, obj.dest_path)
unix_out('# %s is up to date\n' % obj.dest_path)
# else: pass
if not SINGLE_FILES:
return False, updated
return go_on, updated
开发者ID:walterdejong,项目名称:synctool,代码行数:32,代码来源:client.py
示例6: _compare_checksums
def _compare_checksums(self, src_path):
# type: (str) -> bool
'''compare checksum of src_path and dest: self.name
Return True if the same'''
try:
f1 = open(src_path, 'rb')
except IOError as err:
error('failed to open %s : %s' % (src_path, err.strerror))
# return True because we can't fix an error in src_path
return True
sum1 = hashlib.md5()
sum2 = hashlib.md5()
with f1:
try:
f2 = open(self.name, 'rb')
except IOError as err:
error('failed to open %s : %s' % (self.name, err.strerror))
return False
with f2:
ended = False
while not ended and (sum1.digest() == sum2.digest()):
try:
data1 = f1.read(IO_SIZE)
except IOError as err:
error('failed to read file %s: %s' % (src_path,
err.strerror))
return False
if not data1:
ended = True
else:
sum1.update(data1)
try:
data2 = f2.read(IO_SIZE)
except IOError as err:
error('failed to read file %s: %s' % (self.name,
err.strerror))
return False
if not data2:
ended = True
else:
sum2.update(data2)
if sum1.digest() != sum2.digest():
if synctool.lib.DRY_RUN:
stdout('%s mismatch (MD5 checksum)' % self.name)
else:
stdout('%s updated (MD5 mismatch)' % self.name)
unix_out('# updating file %s' % self.name)
terse(synctool.lib.TERSE_SYNC, self.name)
return False
return True
开发者ID:walterdejong,项目名称:synctool,代码行数:60,代码来源:object.py
示例7: check_purge_timestamp
def check_purge_timestamp(self):
'''check timestamp between src and dest
Returns True if same, False if not
'''
# This is only used for purge/
# check() has already determined that the files are the same
# Now only check the timestamp ...
if synctool.param.SYNC_TIMES:
# this was already handled by check() and fix()
return True
# set times, but not for symlinks, directories
if (not self.src_stat.is_link() and not self.src_stat.is_dir() and
self.src_stat.mtime != self.dest_stat.mtime):
stdout('%s mismatch (only timestamp)' % self.dest_path)
terse(synctool.lib.TERSE_WARNING,
'%s (only timestamp)' % self.dest_path)
vnode = self.vnode_obj()
# leave the atime intact
vnode.stat.atime = self.dest_stat.atime
vnode.set_times()
return False
return True
开发者ID:afghanistanyn,项目名称:synctool,代码行数:27,代码来源:object.py
示例8: _run_rsync_purge
def _run_rsync_purge(cmd_arr):
# type: (List[str]) -> None
'''run rsync for purging
cmd_arr holds already prepared rsync command + arguments
'''
unix_out(' '.join(cmd_arr))
sys.stdout.flush()
sys.stderr.flush()
try:
# run rsync
proc = subprocess.Popen(cmd_arr, shell=False, bufsize=4096,
stdout=subprocess.PIPE)
except OSError as err:
error('failed to run command %s: %s' % (cmd_arr[0], err.strerror))
return
out, _ = proc.communicate()
if synctool.lib.VERBOSE:
print out
out = out.split('\n')
for line in out:
line = line.strip()
if not line:
continue
code, filename = line.split(' ', 1)
if code[:6] == 'ERROR:' or code[:8] == 'WARNING:':
# output rsync errors and warnings
stderr(line)
continue
if filename == './':
# rsync has a habit of displaying ugly "./" path
# cmd_arr[-1] is the destination path
path = cmd_arr[-1]
else:
# cmd_arr[-1] is the destination path
path = os.path.join(cmd_arr[-1], filename)
if code[0] == '*':
# rsync has a message for us
# most likely "deleting"
msg = code[1:]
msg = msg.strip()
stdout('%s %s (purge)' % (msg, prettypath(path)))
else:
stdout('%s mismatch (purge)' % prettypath(path))
开发者ID:walterdejong,项目名称:synctool,代码行数:52,代码来源:client.py
示例9: compare
def compare(self, src_path, dest_stat):
'''see if files are the same
Return True if the same'''
if self.stat.size != dest_stat.size:
if synctool.lib.DRY_RUN:
stdout('%s mismatch (file size)' % self.name)
else:
stdout('%s updated (file size mismatch)' % self.name)
terse(synctool.lib.TERSE_SYNC, self.name)
unix_out('# updating file %s' % self.name)
return False
return self._compare_checksums(src_path)
开发者ID:dineshbhoopathy,项目名称:synctool,代码行数:14,代码来源:object.py
示例10: upload
def upload(up):
'''copy a file from a node into the overlay/ tree'''
# Note: this global is only needed because of callback fn ...
global GLOBAL_UPLOAD_FILE
if up.filename[0] != os.sep:
error('the filename to upload must be an absolute path')
sys.exit(-1)
if up.suffix and up.suffix not in synctool.param.ALL_GROUPS:
error("no such group '%s'" % up.suffix)
sys.exit(-1)
if up.overlay and up.overlay not in synctool.param.ALL_GROUPS:
error("no such group '%s'" % up.overlay)
sys.exit(-1)
if up.purge and up.purge not in synctool.param.ALL_GROUPS:
error("no such group '%s'" % up.purge)
sys.exit(-1)
if synctool.lib.DRY_RUN and not synctool.lib.QUIET:
stdout('DRY RUN, not uploading any files')
terse(synctool.lib.TERSE_DRYRUN, 'not uploading any files')
if up.purge != None:
rsync_upload(up)
return
# pretend that the current node is now the given node;
# this is needed for find() to find the best reference for the file
orig_nodename = synctool.param.NODENAME
synctool.param.NODENAME = up.node
synctool.config.insert_group(up.node, up.node)
orig_my_groups = synctool.param.MY_GROUPS[:]
synctool.param.MY_GROUPS = synctool.config.get_my_groups()
# see if file is already in the repository
# Note: ugly global is needed because of callback function
GLOBAL_UPLOAD_FILE = up
synctool.overlay.visit(synctool.param.OVERLAY_DIR, _upload_callback)
up = GLOBAL_UPLOAD_FILE
synctool.param.NODENAME = orig_nodename
synctool.param.MY_GROUPS = orig_my_groups
rsync_upload(up)
开发者ID:afghanistanyn,项目名称:synctool,代码行数:49,代码来源:upload.py
示例11: check
def check(self):
'''check differences between src and dest,
Return a FIX_xxx code
'''
# src_path is under $overlay/
# dest_path is in the filesystem
vnode = None
if not self.dest_stat.exists():
stdout('%s does not exist' % self.dest_path)
return SyncObject.FIX_CREATE
src_type = self.src_stat.filetype()
dest_type = self.dest_stat.filetype()
if src_type != dest_type:
# entry is of a different file type
vnode = self.vnode_obj()
stdout('%s should be a %s' % (self.dest_path, vnode.typename()))
terse(synctool.lib.TERSE_WARNING, 'wrong type %s' %
self.dest_path)
return SyncObject.FIX_TYPE
vnode = self.vnode_obj()
if not vnode.compare(self.src_path, self.dest_stat):
# content is different; change the entire object
log('updating %s' % self.dest_path)
return SyncObject.FIX_UPDATE
# check ownership and permissions
# rectify if needed
fix_action = 0
if ((self.src_stat.uid != self.dest_stat.uid) or
(self.src_stat.gid != self.dest_stat.gid)):
stdout('%s should have owner %s.%s (%d.%d), '
'but has %s.%s (%d.%d)' % (self.dest_path,
self.src_stat.ascii_uid(),
self.src_stat.ascii_gid(),
self.src_stat.uid, self.src_stat.gid,
self.dest_stat.ascii_uid(),
self.dest_stat.ascii_gid(),
self.dest_stat.uid, self.dest_stat.gid))
terse(synctool.lib.TERSE_OWNER, '%s.%s %s' %
(self.src_stat.ascii_uid(),
self.src_stat.ascii_gid(),
self.dest_path))
fix_action = SyncObject.FIX_OWNER
if self.src_stat.mode != self.dest_stat.mode:
stdout('%s should have mode %04o, but has %04o' %
(self.dest_path, self.src_stat.mode & 07777,
self.dest_stat.mode & 07777))
terse(synctool.lib.TERSE_MODE, '%04o %s' %
(self.src_stat.mode & 07777,
self.dest_path))
fix_action |= SyncObject.FIX_MODE
return fix_action
开发者ID:Linuxtester,项目名称:synctool,代码行数:59,代码来源:object.py
示例12: check
def check():
'''check for newer version on the website
It does this by downloading the LATEST.txt versioning file
Returns True if newer available, else False'''
latest_version = get_latest_version()
if latest_version == synctool.param.VERSION:
stdout('You are running the latest version of synctool')
return False
else:
stdout('A newer version of synctool is available: '
'version %s' % latest_version)
return True
开发者ID:dineshbhoopathy,项目名称:synctool,代码行数:15,代码来源:update.py
示例13: check_purge_timestamp
def check_purge_timestamp(self):
'''check timestamp between src and dest
Returns True if same, False if not
'''
# This is only used for purge/
# check() has already determined that the files are the same
# Now only check the timestamp ...
# FIXME have SyncStat time fields
# Note that SyncStat objects do not know the timestamps;
# they are not cached only to save memory
# So now we have to os.stat() again to get the times; it is
# not a big problem because this func is used for purge_single only
# src_path is under $purge/
# dest_path is in the filesystem
try:
src_stat = os.lstat(self.src_path)
except OSError as err:
error('stat(%s) failed: %s' % (self.src_path, err.strerror))
return False
try:
dest_stat = os.lstat(self.dest_path)
except OSError as err:
error('stat(%s) failed: %s' % (self.dest_path, err.strerror))
return False
# FIXME set_times() should not be called for symlinks
if src_stat.st_mtime > dest_stat.st_mtime:
stdout('%s mismatch (only timestamp)' % self.dest_path)
terse(synctool.lib.TERSE_WARNING,
'%s (only timestamp)' % self.dest_path)
verbose(dryrun_msg(' os.utime(%s, %s)'
'' % (self.dest_path,
time.ctime(src_stat.st_mtime))))
unix_out('touch -r %s %s' % (self.src_path, self.dest_path))
vnode = self.vnode_obj()
vnode.set_times(src_stat.st_atime, src_stat.st_mtime)
return False
return True
开发者ID:dot-Sean,项目名称:synctool,代码行数:45,代码来源:object.py
示例14: harddelete
def harddelete(self):
'''delete directory'''
if synctool.lib.DRY_RUN:
not_str = 'not '
else:
not_str = ''
stdout('%sremoving %s' % (not_str, self.name + os.sep))
unix_out('rmdir %s' % self.name)
terse(synctool.lib.TERSE_DELETE, self.name + os.sep)
if not synctool.lib.DRY_RUN:
verbose(' os.rmdir(%s)' % self.name)
try:
os.rmdir(self.name)
except OSError:
# probably directory not empty
# refuse to delete dir, just move it aside
verbose('refusing to delete directory %s' % self.name)
self.move_saved()
开发者ID:afghanistanyn,项目名称:synctool,代码行数:20,代码来源:object.py
示例15: harddelete
def harddelete(self):
'''delete existing entry'''
if synctool.lib.DRY_RUN:
not_str = 'not '
else:
not_str = ''
stdout('%sdeleting %s' % (not_str, self.name))
unix_out('rm %s' % self.name)
terse(synctool.lib.TERSE_DELETE, self.name)
if not synctool.lib.DRY_RUN:
verbose(' os.unlink(%s)' % self.name)
try:
os.unlink(self.name)
except OSError as err:
error('failed to delete %s : %s' % (self.name, err.strerror))
terse(synctool.lib.TERSE_FAIL, 'delete %s' % self.name)
else:
log('deleted %s' % self.name)
开发者ID:dot-Sean,项目名称:synctool,代码行数:21,代码来源:object.py
示例16: _single_overlay_callback
def _single_overlay_callback(obj, pre_dict, post_dict):
'''do overlay function for single files'''
if not SINGLE_FILES:
# proceed quickly
return True, False
if obj.ov_type == synctool.overlay.OV_TEMPLATE:
return generate_template(obj, post_dict), False
go_on = True
updated = False
if _match_single(obj.dest_path):
_, updated = _overlay_callback(obj, pre_dict, post_dict)
if not updated:
stdout('%s is up to date' % obj.dest_path)
terse(synctool.lib.TERSE_OK, obj.dest_path)
unix_out('# %s is up to date\n' % obj.dest_path)
return go_on, updated
开发者ID:afghanistanyn,项目名称:synctool,代码行数:21,代码来源:client.py
示例17: worker_dsh_cp
def worker_dsh_cp(addr):
'''do remote copy to node'''
nodename = NODESET.get_nodename_from_address(addr)
if nodename == param.NODENAME:
# do not copy to local node; files are already here
return
# the fileset already has been added to DSH_CP_CMD_ARR
# use ssh connection multiplexing (if possible)
use_multiplex = synctool.multiplex.use_mux(nodename)
# create local copy of DSH_CP_CMD_ARR
# or parallelism may screw things up
dsh_cp_cmd_arr = DSH_CP_CMD_ARR[:]
# add ssh cmd
ssh_cmd_arr = shlex.split(param.SSH_CMD)
if use_multiplex:
synctool.multiplex.ssh_args(ssh_cmd_arr, nodename)
dsh_cp_cmd_arr.extend(['-e', ' '.join(ssh_cmd_arr)])
dsh_cp_cmd_arr.append('--')
dsh_cp_cmd_arr.extend(SOURCE_LIST)
dsh_cp_cmd_arr.append('%s:%s' % (addr, DESTDIR))
msg = 'copy %s to %s' % (FILES_STR, DESTDIR)
if synctool.lib.DRY_RUN:
msg += ' (dry run)'
if synctool.lib.OPT_NODENAME:
msg = ('%s: ' % nodename) + msg
stdout(msg)
if not synctool.lib.DRY_RUN:
synctool.lib.run_with_nodename(dsh_cp_cmd_arr, nodename)
else:
unix_out(' '.join(dsh_cp_cmd_arr) + ' # dry run')
开发者ID:afghanistanyn,项目名称:synctool,代码行数:38,代码来源:dsh_cp.py
示例18: _single_purge_callback
def _single_purge_callback(obj, post_dict, updated, *args):
'''do purge function for single files'''
# The same as _single_overlay_callback(), except that
# purge entries may differ in timestamp. synctool has to report
# this because pure rsync will as well (which is bloody annoying)
#
# For normal synctool overlay/, it's regarded as not important
# and synctool will not complain about it
#
# This actually leaves a final wart; synctool --single may create
# purge entries that rsync will complain about and sync again
# Anyway, I don't think it's a big deal, and that's what you get
# when you mix up synctool and rsync
go_on = True
if _match_single(obj.dest_path):
_, updated = _overlay_callback(obj, post_dict, False, *args)
if not updated:
if obj.check_purge_timestamp():
stdout('%s is up to date' % obj.dest_path)
terse(synctool.lib.TERSE_OK, obj.dest_path)
unix_out('# %s is up to date\n' % obj.dest_path)
# else: pass
else:
# register .post on the parent dir, if it has a .post script
obj.dest_path = os.path.dirname(obj.dest_path)
obj.dest_stat = synctool.syncstat.SyncStat(obj.dest_path)
if obj.dest_path in post_dict:
changed_dict = args[0]
changed_dict[obj.dest_path] = (obj, post_dict[obj.dest_path])
if not SINGLE_FILES:
return False, updated
return go_on, updated
开发者ID:dineshbhoopathy,项目名称:synctool,代码行数:38,代码来源:client.py
示例19: check
def check():
"""check for newer version
It does this by looking at releases at GitHub
Returns True if a newer version is available
"""
info = ReleaseInfo()
if not info.load():
# error message already printed
return False
my_time = datetime.datetime.strptime(synctool.param.RELEASE_DATETIME, "%Y-%m-%dT%H:%M:%S")
if info.datetime <= my_time:
stdout("You are running the latest release of synctool")
return False
stdout("A newer version is available: %s" % info.version)
stdout("released %s" % info.datetime)
return True
开发者ID:dot-Sean,项目名称:synctool,代码行数:19,代码来源:update.py
示例20: main
def main():
# type: () -> None
'''run the program'''
param.init()
action = get_options()
config.init_mynodename()
if not param.NODENAME:
error('unable to determine my nodename (hostname: %s)' %
param.HOSTNAME)
stderr('please check %s' % param.CONF_FILE)
sys.exit(-1)
if param.NODENAME not in param.NODES:
error("unknown node '%s'" % param.NODENAME)
stderr('please check %s' % param.CONF_FILE)
sys.exit(-1)
if param.NODENAME in param.IGNORE_GROUPS:
# this is only a warning ...
# you can still run synctool-pkg on the client by hand
warning('node %s is disabled in %s' %
(param.NODENAME, param.CONF_FILE))
if synctool.lib.UNIX_CMD:
t = time.localtime(time.time())
unix_out('#')
unix_out('# script generated by synctool on '
'%04d/%02d/%02d %02d:%02d:%02d' %
(t[0], t[1], t[2], t[3], t[4], t[5]))
unix_out('#')
unix_out('# my hostname: %s' % param.HOSTNAME)
unix_out('# SYNCTOOL_NODE=%s' % param.NODENAME)
unix_out('# SYNCTOOL_ROOT=%s' % param.ROOTDIR)
unix_out('#')
if not synctool.lib.DRY_RUN:
unix_out('# NOTE: --fix specified, applying updates')
unix_out('#')
unix_out('')
else:
if not synctool.lib.MASTERLOG:
# only print this when running stand-alone
if not synctool.lib.QUIET:
if synctool.lib.DRY_RUN:
stdout('DRY RUN, not doing any updates')
terse(synctool.lib.TERSE_DRYRUN, 'not doing any updates')
else:
stdout('--fix specified, applying changes')
terse(synctool.lib.TERSE_FIXING, ' applying changes')
else:
if synctool.lib.DRY_RUN:
verbose('DRY RUN, not doing any updates')
else:
verbose('--fix specified, applying changes')
verbose('my nodename: %s' % param.NODENAME)
verbose('my hostname: %s' % param.HOSTNAME)
verbose('rootdir: %s' % param.ROOTDIR)
os.environ['SYNCTOOL_NODE'] = param.NODENAME
os.environ['SYNCTOOL_ROOT'] = param.ROOTDIR
unix_out('umask 077')
unix_out('')
os.umask(077)
if action == ACTION_DIFF:
diff_files()
elif action == ACTION_REFERENCE:
reference_files()
elif action == ACTION_ERASE_SAVED:
if SINGLE_FILES:
single_erase_saved()
else:
erase_saved()
elif SINGLE_FILES:
single_files()
else:
purge_files()
overlay_files()
delete_files()
unix_out('# EOB')
开发者ID:walterdejong,项目名称:synctool,代码行数:94,代码来源:client.py
注:本文中的synctool.lib.stdout函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论