mirror of
https://github.com/upa/mscp.git
synced 2026-02-04 03:24:58 +08:00
drop python binding support
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,7 +5,3 @@ CMakeUserPresets.json
|
|||||||
.*.swp
|
.*.swp
|
||||||
|
|
||||||
include/mscp_version.h
|
include/mscp_version.h
|
||||||
|
|
||||||
dist
|
|
||||||
*.egg-info
|
|
||||||
__pycache__
|
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ if (BUILD_STATIC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
option(INSTALL_EXECUTABLE_ONLY OFF) # do not install libmscp
|
|
||||||
|
|
||||||
|
|
||||||
# add libssh static library
|
# add libssh static library
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||||
@@ -90,28 +88,9 @@ configure_file(
|
|||||||
${mscp_SOURCE_DIR}/include/mscp_version.h.in
|
${mscp_SOURCE_DIR}/include/mscp_version.h.in
|
||||||
${mscp_SOURCE_DIR}/include/mscp_version.h)
|
${mscp_SOURCE_DIR}/include/mscp_version.h)
|
||||||
|
|
||||||
|
# libmscp.a
|
||||||
# libmscp.so
|
|
||||||
set(LIBMSCP_SRC
|
set(LIBMSCP_SRC
|
||||||
src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c)
|
src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c)
|
||||||
add_library(mscp-shared SHARED ${LIBMSCP_SRC})
|
|
||||||
target_include_directories(mscp-shared
|
|
||||||
PUBLIC $<BUILD_INTERFACE:${mscp_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
PRIVATE ${MSCP_BUILD_INCLUDE_DIRS})
|
|
||||||
target_compile_options(mscp-shared PRIVATE ${MSCP_COMPILE_OPTS})
|
|
||||||
target_link_libraries(mscp-shared PRIVATE ${MSCP_LINK_LIBS})
|
|
||||||
set_target_properties(mscp-shared
|
|
||||||
PROPERTIES
|
|
||||||
OUTPUT_NAME mscp
|
|
||||||
PUBLIC_HEADER ${mscp_SOURCE_DIR}/include/mscp.h)
|
|
||||||
|
|
||||||
if(!INSTALL_EXECUTABLE_ONLY)
|
|
||||||
install(TARGETS mscp-shared)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# libmscp.a
|
|
||||||
add_library(mscp-static STATIC ${LIBMSCP_SRC})
|
add_library(mscp-static STATIC ${LIBMSCP_SRC})
|
||||||
target_include_directories(mscp-static
|
target_include_directories(mscp-static
|
||||||
PRIVATE ${MSCP_BUILD_INCLUDE_DIRS} ${mscp_SOURCE_DIR}/include)
|
PRIVATE ${MSCP_BUILD_INCLUDE_DIRS} ${mscp_SOURCE_DIR}/include)
|
||||||
@@ -121,11 +100,6 @@ set_target_properties(mscp-static
|
|||||||
PROPERTIES
|
PROPERTIES
|
||||||
OUTPUT_NAME mscp)
|
OUTPUT_NAME mscp)
|
||||||
|
|
||||||
if(!INSTALL_EXECUTABLE_ONLY)
|
|
||||||
install(TARGETS mscp-static)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# mscp executable
|
# mscp executable
|
||||||
list(APPEND MSCP_LINK_LIBS m pthread)
|
list(APPEND MSCP_LINK_LIBS m pthread)
|
||||||
|
|
||||||
|
|||||||
2
Doxyfile
2
Doxyfile
@@ -9,5 +9,5 @@ GENERATE_MAN = NO
|
|||||||
|
|
||||||
SOURCE_BROWSER = YES
|
SOURCE_BROWSER = YES
|
||||||
|
|
||||||
INPUT = src include mscp
|
INPUT = src include
|
||||||
|
|
||||||
|
|||||||
4
debian/rules
vendored
4
debian/rules
vendored
@@ -4,10 +4,6 @@
|
|||||||
dh $@
|
dh $@
|
||||||
|
|
||||||
|
|
||||||
override_dh_auto_configure:
|
|
||||||
dh_auto_configure -- \
|
|
||||||
-DINSTALL_EXECUTABLE_ONLY=ON
|
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,3 @@ RUN cd ${mscpdir} \
|
|||||||
&& cpack -G RPM CPackConfig.cmake \
|
&& cpack -G RPM CPackConfig.cmake \
|
||||||
&& rpm -iv *.rpm
|
&& rpm -iv *.rpm
|
||||||
|
|
||||||
# install mscp python module
|
|
||||||
RUN cd ${mscpdir} \
|
|
||||||
&& python3 pysetup.py install --user \
|
|
||||||
&& ldconfig
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,3 @@ RUN cd ${mscpdir} \
|
|||||||
&& cp mscp /mscp/build/mscp_alpine-3.17-x86_64.static
|
&& cp mscp /mscp/build/mscp_alpine-3.17-x86_64.static
|
||||||
# copy mscp to PKG FILE NAME because this build doesn't use CPACK
|
# copy mscp to PKG FILE NAME because this build doesn't use CPACK
|
||||||
|
|
||||||
# install mscp python module
|
|
||||||
RUN cd ${mscpdir} \
|
|
||||||
&& python3 pysetup.py install --user
|
|
||||||
|
|||||||
@@ -29,8 +29,3 @@ RUN cd ${mscpdir} \
|
|||||||
&& cpack -G RPM CPackConfig.cmake \
|
&& cpack -G RPM CPackConfig.cmake \
|
||||||
&& rpm -iv *.rpm
|
&& rpm -iv *.rpm
|
||||||
|
|
||||||
# install mscp python module
|
|
||||||
RUN cd ${mscpdir} \
|
|
||||||
&& python3 pysetup.py install --user \
|
|
||||||
&& ldconfig
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,3 @@ RUN cd ${mscpdir} \
|
|||||||
&& cpack -G DEB CPackConfig.cmake \
|
&& cpack -G DEB CPackConfig.cmake \
|
||||||
&& dpkg -i *.deb
|
&& dpkg -i *.deb
|
||||||
|
|
||||||
# install mscp python module
|
|
||||||
RUN cd ${mscpdir} \
|
|
||||||
&& python3 pysetup.py install --user \
|
|
||||||
&& ldconfig
|
|
||||||
|
|||||||
@@ -33,8 +33,3 @@ RUN cd ${mscpdir} \
|
|||||||
&& cpack -G DEB CPackConfig.cmake \
|
&& cpack -G DEB CPackConfig.cmake \
|
||||||
&& dpkg -i *.deb
|
&& dpkg -i *.deb
|
||||||
|
|
||||||
# install mscp python module
|
|
||||||
RUN cd ${mscpdir} \
|
|
||||||
&& python3 pysetup.py install --user \
|
|
||||||
&& ldconfig
|
|
||||||
|
|
||||||
|
|||||||
3
examples/.gitignore
vendored
3
examples/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
simple-copy-dest
|
|
||||||
*.img
|
|
||||||
.ipynb_checkpoints
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "ccda9e3a-35de-43fc-9b6e-02475c763f6b",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# mscp python binding example"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 60,
|
|
||||||
"id": "df04d655-a082-47eb-9a1e-154ebc2a5655",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import glob\n",
|
|
||||||
"import time\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"import mscp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 53,
|
|
||||||
"id": "e9ed4519-c3fd-4639-89a5-1c1cdffd9519",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"this_dir = os.getcwd()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "fee75bf8-df40-45f4-81d1-113069c34f13",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Simple copy"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 54,
|
|
||||||
"id": "2b06e6d3-30cc-47be-bd4f-af27eb141c8c",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"['../src/ssh.c',\n",
|
|
||||||
" '../src/mscp.c',\n",
|
|
||||||
" '../src/platform.c',\n",
|
|
||||||
" '../src/pymscp.c',\n",
|
|
||||||
" '../src/main.c',\n",
|
|
||||||
" '../src/path.c',\n",
|
|
||||||
" '../src/message.c',\n",
|
|
||||||
" '../src/fileops.c']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 54,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"# preparing files to be transferred\n",
|
|
||||||
"c_sources = glob.glob(\"../src/*.c\")\n",
|
|
||||||
"c_sources"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 55,
|
|
||||||
"id": "89bb4558-9472-4d26-9af3-24f426b15edc",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# copy files using mscp\n",
|
|
||||||
"dst_dir = this_dir + \"/simple-copy-dest\"\n",
|
|
||||||
"m = mscp.mscp(\"localhost\", mscp.LOCAL2REMOTE)\n",
|
|
||||||
"m.copy(c_sources, dst_dir)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 56,
|
|
||||||
"id": "6daf2c98-8905-4039-b82a-a593df3107fe",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"['ssh.c',\n",
|
|
||||||
" 'mscp.c',\n",
|
|
||||||
" 'platform.c',\n",
|
|
||||||
" 'pymscp.c',\n",
|
|
||||||
" 'main.c',\n",
|
|
||||||
" 'path.c',\n",
|
|
||||||
" 'message.c',\n",
|
|
||||||
" 'fileops.c']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 56,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"os.listdir(\"simple-copy-dest\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "f4a3869a-878e-43b0-9758-a049eaf8b5bd",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Simple Copy with Python Rich ProgressBar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 64,
|
|
||||||
"id": "e7cb7cd6-b845-4d26-93ed-aee8ed3983ab",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# make a 256MB file\n",
|
|
||||||
"src = \"example-256MB-src.img\"\n",
|
|
||||||
"with open(src, \"wb\") as f:\n",
|
|
||||||
" f.seek(128 * 1024 * 1024 -1, 0)\n",
|
|
||||||
" f.write(b'1')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 69,
|
|
||||||
"id": "878607ed-5c06-4b15-81ac-9845dad0c9c6",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"application/vnd.jupyter.widget-view+json": {
|
|
||||||
"model_id": "b700e9fc00464969a22a26300404dc35",
|
|
||||||
"version_major": 2,
|
|
||||||
"version_minor": 0
|
|
||||||
},
|
|
||||||
"text/plain": [
|
|
||||||
"Output()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": []
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"# copy the 256MB file while ploting progress bar using python rich\n",
|
|
||||||
"dst = this_dir + \"/example-256MB-dst.img\"\n",
|
|
||||||
"\n",
|
|
||||||
"kw = {\"nr_threads\": 1, \"nr_ahead\": 1} # slow mscp to watch the progress bar\n",
|
|
||||||
"\n",
|
|
||||||
"m = mscp.mscp(\"localhost\", mscp.LOCAL2REMOTE, **kw)\n",
|
|
||||||
"m.copy(src, dst, nonblock = True)\n",
|
|
||||||
"\n",
|
|
||||||
"# m.stats() returns total bytes to be transferred, bytes transferred (done), and finished (bool).\n",
|
|
||||||
"total, done, finished = m.stats()\n",
|
|
||||||
"with Progress() as progress:\n",
|
|
||||||
"\n",
|
|
||||||
" task = progress.add_task(f\"[green]Copying {src}\", total = total)\n",
|
|
||||||
"\n",
|
|
||||||
" while not progress.finished:\n",
|
|
||||||
" total, done, finished = m.stats()\n",
|
|
||||||
" progress.update(task, completed = done)\n",
|
|
||||||
" time.sleep(0.5)\n",
|
|
||||||
"\n",
|
|
||||||
"m.join()\n",
|
|
||||||
"m.cleanup()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3 (ipykernel)",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.11.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 5
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""mscp.py
|
|
||||||
|
|
||||||
An example python script running mscp
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from rich.progress import Progress
|
|
||||||
|
|
||||||
import mscp
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("-f", "--from", dest = "fr",
|
|
||||||
metavar = "REMOTE", default = None,
|
|
||||||
help = "copy a file from this remote host")
|
|
||||||
parser.add_argument("-t", "--to", metavar = "REMOTE", default = None,
|
|
||||||
help = "copy a file to this remote host")
|
|
||||||
parser.add_argument("source", help = "path to source file to be copied")
|
|
||||||
parser.add_argument("destination", help = "path of copy destination")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.fr and args.to:
|
|
||||||
print("-f and -t are exclusive", file = sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
elif args.fr:
|
|
||||||
d = mscp.REMOTE2LOCAL
|
|
||||||
remote = args.fr
|
|
||||||
elif args.to:
|
|
||||||
d = mscp.LOCAL2REMOTE
|
|
||||||
remote = args.to
|
|
||||||
else:
|
|
||||||
print("-f or -t must be specified", file = sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
m = mscp.mscp(remote, d)
|
|
||||||
m.connect()
|
|
||||||
m.add_src_path(args.source)
|
|
||||||
m.set_dst_path(args.destination)
|
|
||||||
m.scan()
|
|
||||||
m.start()
|
|
||||||
|
|
||||||
total, done, finished = m.stats()
|
|
||||||
with Progress() as progress:
|
|
||||||
|
|
||||||
task = progress.add_task("[green]Copying...", total = total)
|
|
||||||
|
|
||||||
while not progress.finished:
|
|
||||||
total, done, finished = m.stats()
|
|
||||||
progress.update(task, completed = done)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
m.join()
|
|
||||||
m.cleanup()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from mscp.mscp import *
|
|
||||||
187
mscp/mscp.py
187
mscp/mscp.py
@@ -1,187 +0,0 @@
|
|||||||
|
|
||||||
_retry_import_pymscp = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pymscp
|
|
||||||
except ImportError:
|
|
||||||
_retry_import_pymscp = True
|
|
||||||
|
|
||||||
if _retry_import_pymscp:
|
|
||||||
""" libmscp.so is not installed on system library paths. So retry
|
|
||||||
to import libmscp.so installed on the mscp python module
|
|
||||||
directory.
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
if sys.platform == "linux":
|
|
||||||
libmscp = "libmscp.so"
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
libmscp = "libmscp.dylib"
|
|
||||||
|
|
||||||
mscp_dir = os.path.dirname(__file__)
|
|
||||||
ctypes.cdll.LoadLibrary("{}/{}".format(mscp_dir, libmscp))
|
|
||||||
import pymscp
|
|
||||||
|
|
||||||
|
|
||||||
# inherit static values from pymscp
|
|
||||||
LOCAL2REMOTE = pymscp.LOCAL2REMOTE
|
|
||||||
REMOTE2LOCAL = pymscp.REMOTE2LOCAL
|
|
||||||
SEVERITY_NONE = pymscp.SEVERITY_NONE
|
|
||||||
SEVERITY_ERR = pymscp.SEVERITY_ERR
|
|
||||||
SEVERITY_WARN = pymscp.SEVERITY_WARN
|
|
||||||
SEVERITY_NOTICE = pymscp.SEVERITY_NOTICE
|
|
||||||
SEVERITY_INFO = pymscp.SEVERITY_INFO
|
|
||||||
SEVERITY_DEBUG = pymscp.SEVERITY_DEBUG
|
|
||||||
|
|
||||||
STATE_INIT = 0
|
|
||||||
STATE_CONNECTED = 1
|
|
||||||
STATE_SCANNED = 2
|
|
||||||
STATE_RUNNING = 3
|
|
||||||
STATE_STOPPED = 4
|
|
||||||
STATE_JOINED = 5
|
|
||||||
STATE_CLEANED = 6
|
|
||||||
STATE_RELEASED = 7
|
|
||||||
|
|
||||||
_state_str = {
|
|
||||||
STATE_INIT: "init",
|
|
||||||
STATE_CONNECTED: "connected",
|
|
||||||
STATE_SCANNED: "scanned",
|
|
||||||
STATE_RUNNING: "running",
|
|
||||||
STATE_STOPPED: "stopped",
|
|
||||||
STATE_JOINED: "joined",
|
|
||||||
STATE_CLEANED: "cleaned",
|
|
||||||
STATE_RELEASED: "released",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class mscp:
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, remote: str, direction: int, **kwargs):
|
|
||||||
self.remote = remote
|
|
||||||
self.direction = direction
|
|
||||||
kwargs["remote"] = remote
|
|
||||||
kwargs["direction"] = direction
|
|
||||||
self.m = pymscp.mscp_init(**kwargs)
|
|
||||||
|
|
||||||
self.src_paths = []
|
|
||||||
self.dst_path = None
|
|
||||||
self.state = STATE_INIT
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if not hasattr(self, "state"):
|
|
||||||
# this instance failed on mscp_init
|
|
||||||
return "mscp:{}:init-failed"
|
|
||||||
return "mscp:{}:{}".format(self.remote, self.__state2str())
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<{}>".format(str(self))
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
|
|
||||||
if not hasattr(self, "state"):
|
|
||||||
return # this instance failed on mscp_init
|
|
||||||
|
|
||||||
if self.state == STATE_RUNNING:
|
|
||||||
self.stop()
|
|
||||||
if self.state == STATE_STOPPED:
|
|
||||||
self.join()
|
|
||||||
|
|
||||||
self.cleanup()
|
|
||||||
self.release()
|
|
||||||
|
|
||||||
def __state2str(self):
|
|
||||||
return _state_str[self.state]
|
|
||||||
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
if not (self.state == STATE_INIT or state.state == STATE_CLEANED):
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
pymscp.mscp_connect(m = self.m)
|
|
||||||
self.state = STATE_CONNECTED
|
|
||||||
|
|
||||||
def add_src_path(self, src_path: str):
|
|
||||||
if type(src_path) != str:
|
|
||||||
raise ValueError("src_path must be str: {}".format(src_path))
|
|
||||||
self.src_paths.append(src_path)
|
|
||||||
pymscp.mscp_add_src_path(m = self.m, src_path = src_path)
|
|
||||||
|
|
||||||
def set_dst_path(self, dst_path: str):
|
|
||||||
if type(dst_path) != str:
|
|
||||||
raise ValueError("dst_path must be str: {}".format(dst_path))
|
|
||||||
self.dst_path = dst_path
|
|
||||||
pymscp.mscp_set_dst_path(m = self.m, dst_path = dst_path);
|
|
||||||
|
|
||||||
def scan(self):
|
|
||||||
if self.state == STATE_SCANNED:
|
|
||||||
return
|
|
||||||
if self.state != STATE_CONNECTED:
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
if not self.src_paths:
|
|
||||||
raise RuntimeError("src path list is empty")
|
|
||||||
if self.dst_path == None:
|
|
||||||
raise RuntimeError("dst path is not set")
|
|
||||||
|
|
||||||
pymscp.mscp_scan(m = self.m)
|
|
||||||
self.state = STATE_SCANNED
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
if self.state != STATE_SCANNED:
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
|
|
||||||
pymscp.mscp_start(m = self.m)
|
|
||||||
self.state = STATE_RUNNING
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
if self.state != STATE_RUNNING:
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
pymscp.mscp_stop(m = self.m)
|
|
||||||
self.state = STATE_STOPPED
|
|
||||||
|
|
||||||
def join(self):
|
|
||||||
if self.state == STATE_JOINED:
|
|
||||||
return
|
|
||||||
if not (self.state == STATE_RUNNING or self.state == STATE_STOPPED):
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
pymscp.mscp_join(m = self.m)
|
|
||||||
self.state = STATE_JOINED
|
|
||||||
|
|
||||||
def stats(self):
|
|
||||||
return pymscp.mscp_get_stats(m = self.m)
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
if self.state == STATE_RUNNING:
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
pymscp.mscp_cleanup(m = self.m)
|
|
||||||
self.state = STATE_CLEANED
|
|
||||||
|
|
||||||
def release(self):
|
|
||||||
if self.state != STATE_CLEANED:
|
|
||||||
raise RuntimeError("invalid mscp state: {}".format(self.__state2str()))
|
|
||||||
pymscp.mscp_free(m = self.m)
|
|
||||||
self.state = STATE_RELEASED
|
|
||||||
|
|
||||||
# Simple interface: mscp.copy(src, dst)
|
|
||||||
def copy(self, src, dst, nonblock = False):
|
|
||||||
if self.state < STATE_CONNECTED:
|
|
||||||
self.connect()
|
|
||||||
|
|
||||||
if type(src) == list:
|
|
||||||
for path in src:
|
|
||||||
self.add_src_path(path)
|
|
||||||
elif type(src) == str:
|
|
||||||
self.add_src_path(src)
|
|
||||||
else:
|
|
||||||
raise ValueError("src must be str of list: '{}'".format(src))
|
|
||||||
|
|
||||||
self.set_dst_path(dst)
|
|
||||||
|
|
||||||
self.scan()
|
|
||||||
self.start()
|
|
||||||
if nonblock:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.join()
|
|
||||||
self.cleanup()
|
|
||||||
37
pysetup.py
37
pysetup.py
@@ -1,37 +0,0 @@
|
|||||||
from setuptools import setup, Extension, find_packages
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
mypackage_root_dir = os.path.dirname(__file__)
|
|
||||||
with open(os.path.join(mypackage_root_dir, 'VERSION')) as version_file:
|
|
||||||
version = version_file.read().strip()
|
|
||||||
|
|
||||||
if sys.platform == "linux":
|
|
||||||
libmscp = "libmscp.so"
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
libmscp = "libmscp.dylib"
|
|
||||||
|
|
||||||
data_dir = sys.prefix + "/lib"
|
|
||||||
libmscp = "build/" + libmscp
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='mscp',
|
|
||||||
version = version,
|
|
||||||
description = "libmscp python binding",
|
|
||||||
author = "Ryo Nakamura",
|
|
||||||
author_email = "upa@haeena.net",
|
|
||||||
url = "https://github.com/upa/mscp",
|
|
||||||
packages = find_packages("mscp"),
|
|
||||||
package_dir = {"": "mscp"},
|
|
||||||
data_files = [ (data_dir, [libmscp])],
|
|
||||||
py_modules = [ "mscp" ],
|
|
||||||
ext_modules = [
|
|
||||||
Extension(
|
|
||||||
'pymscp',
|
|
||||||
['src/pymscp.c'],
|
|
||||||
library_dirs = ['build'],
|
|
||||||
libraries = ['mscp'],
|
|
||||||
include_dirs = ['include']
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
499
src/pymscp.c
499
src/pymscp.c
@@ -1,499 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-3.0-only */
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <mscp.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a wrapper for python binding of libmscp. setup.py builds
|
|
||||||
* pymscp.c after libmscp was built, and setup.py installs pymscp
|
|
||||||
* modlue and mscp python module (mscp/mscp.py), which is a warpper
|
|
||||||
* for pymscp.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAX_MSCP_INSTS 64
|
|
||||||
|
|
||||||
/* XXX: cut corners */
|
|
||||||
struct instance {
|
|
||||||
struct mscp_opts mo;
|
|
||||||
struct mscp_ssh_opts so;
|
|
||||||
struct mscp *m;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct instance *insts[MAX_MSCP_INSTS];
|
|
||||||
|
|
||||||
static int add_instance(struct instance *i)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
|
||||||
if (insts[n] == NULL) {
|
|
||||||
insts[n] = i;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1; /* full of mscp instances */
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct instance *get_instance(unsigned long long addr)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
|
||||||
if (insts[n] == (void *)addr)
|
|
||||||
return insts[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mscp *get_mscp(unsigned long long addr)
|
|
||||||
{
|
|
||||||
struct instance *i = get_instance(addr);
|
|
||||||
|
|
||||||
if (!i)
|
|
||||||
return NULL;
|
|
||||||
return i->m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int release_instance(struct instance *i)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
|
||||||
if (insts[n] == i) {
|
|
||||||
insts[n] = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(i);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* wrapper functions */
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_init(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Initialize struct mscp with options. wrap_mscp_init
|
|
||||||
* receives all the arguments with keywords.
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *remote;
|
|
||||||
char *keywords[] = {
|
|
||||||
"remote", /* const char * */
|
|
||||||
"direction", /* int, MSCP_DIRECTION_L2R or MSCP_DIRECTION_R2L */
|
|
||||||
|
|
||||||
/* mscp_opts */
|
|
||||||
"nr_threads", /* int */
|
|
||||||
"nr_ahead", /* int */
|
|
||||||
|
|
||||||
"min_chunk_sz", /* unsigned long */
|
|
||||||
"max_chunk_sz", /* unsigned long */
|
|
||||||
"buf_sz", /* unsigned long */
|
|
||||||
|
|
||||||
"coremask", /* const char * */
|
|
||||||
|
|
||||||
"max_startups", /* int */
|
|
||||||
"interval", /* int */
|
|
||||||
"severity", /* int, MSCP_SERVERITY_* */
|
|
||||||
"msg_fd", /* int */
|
|
||||||
|
|
||||||
/* mscp_ssh_opts */
|
|
||||||
"login_name", /* const char * */
|
|
||||||
"port", /* const char * */
|
|
||||||
"config", /* const char * */
|
|
||||||
"identity", /* const char * */
|
|
||||||
|
|
||||||
"cipher", /* const char * */
|
|
||||||
"hmac", /* const char * */
|
|
||||||
"compress", /* const char * */
|
|
||||||
"ccalgo", /* const char * */
|
|
||||||
"password", /* const char * */
|
|
||||||
"passphrase", /* const char * */
|
|
||||||
|
|
||||||
"debug_level", /* int */
|
|
||||||
"no_hostkey_check", /* bool */
|
|
||||||
"enable_nagle", /* bool */
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
const char *fmt = "si" "|" "ii" "kkk" "s" "iiii" "ssss" "ssssss" "ipp";
|
|
||||||
char *coremask = NULL;
|
|
||||||
char *login_name = NULL, *port = NULL, *config = NULL, *identity = NULL;
|
|
||||||
char *cipher = NULL, *hmac = NULL, *compress = NULL, *ccalgo = NULL;
|
|
||||||
char *password = NULL, *passphrase = NULL;
|
|
||||||
|
|
||||||
struct instance *i;
|
|
||||||
int direction;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
i = malloc(sizeof(*i));
|
|
||||||
if (!i) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(i, 0, sizeof(*i));
|
|
||||||
|
|
||||||
ret = PyArg_ParseTupleAndKeywords(args, kw, fmt, keywords,
|
|
||||||
&remote,
|
|
||||||
&direction,
|
|
||||||
&i->mo.nr_threads,
|
|
||||||
&i->mo.nr_ahead,
|
|
||||||
&i->mo.min_chunk_sz,
|
|
||||||
&i->mo.max_chunk_sz,
|
|
||||||
&i->mo.buf_sz,
|
|
||||||
&coremask,
|
|
||||||
&i->mo.max_startups,
|
|
||||||
&i->mo.interval,
|
|
||||||
&i->mo.severity,
|
|
||||||
&i->mo.msg_fd,
|
|
||||||
&login_name,
|
|
||||||
&port,
|
|
||||||
&config,
|
|
||||||
&identity,
|
|
||||||
&cipher,
|
|
||||||
&hmac,
|
|
||||||
&compress,
|
|
||||||
&ccalgo,
|
|
||||||
&password,
|
|
||||||
&passphrase,
|
|
||||||
&i->so.debug_level,
|
|
||||||
&i->so.no_hostkey_check,
|
|
||||||
&i->so.enable_nagle);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (coremask)
|
|
||||||
strncpy(i->mo.coremask, coremask, MSCP_MAX_COREMASK_STR - 1);
|
|
||||||
if (login_name)
|
|
||||||
strncpy(i->so.login_name, login_name, MSCP_SSH_MAX_LOGIN_NAME - 1);
|
|
||||||
if (port)
|
|
||||||
strncpy(i->so.port, port, MSCP_SSH_MAX_PORT_STR - 1);
|
|
||||||
if (config)
|
|
||||||
strncpy(i->so.config, config, PATH_MAX - 1);
|
|
||||||
if (identity)
|
|
||||||
strncpy(i->so.identity, identity, MSCP_SSH_MAX_IDENTITY_PATH - 1);
|
|
||||||
if (cipher)
|
|
||||||
strncpy(i->so.cipher, cipher, MSCP_SSH_MAX_CIPHER_STR - 1);
|
|
||||||
if (hmac)
|
|
||||||
strncpy(i->so.hmac, hmac, MSCP_SSH_MAX_HMAC_STR - 1);
|
|
||||||
if (compress)
|
|
||||||
strncpy(i->so.compress, compress, MSCP_SSH_MAX_COMP_STR - 1);
|
|
||||||
if (ccalgo)
|
|
||||||
strncpy(i->so.ccalgo, ccalgo, MSCP_SSH_MAX_CCALGO_STR - 1);
|
|
||||||
if (password)
|
|
||||||
strncpy(i->so.password, password, MSCP_SSH_MAX_PASSWORD - 1);
|
|
||||||
if (passphrase)
|
|
||||||
strncpy(i->so.passphrase, passphrase, MSCP_SSH_MAX_PASSPHRASE - 1);
|
|
||||||
|
|
||||||
i->m = mscp_init(remote, direction, &i->mo, &i->so);
|
|
||||||
if (!i->m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "%s", mscp_get_error());
|
|
||||||
free(i);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_instance(i) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "too many mscp isntances");
|
|
||||||
mscp_free(i->m);
|
|
||||||
free(i);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("K", (unsigned long long)i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_connect(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_connect(m) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_add_src_path(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", "src_path", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
char *src_path;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "Ks", keywords, &addr, &src_path))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_add_src_path(m, src_path) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_set_dst_path(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", "dst_path", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
char *dst_path;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "Ks", keywords, &addr, &dst_path))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_set_dst_path(m, dst_path) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_scan(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_scan(m) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_start(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_start(m) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_stop(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mscp_stop(m);
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_join(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mscp_join(m) < 0) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_get_stats(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp_stats s;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mscp_get_stats(m, &s);
|
|
||||||
|
|
||||||
return Py_BuildValue("KKO", s.total, s.done, PyBool_FromLong(s.finished));
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_cleanup(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct mscp *m;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
m = get_mscp(addr);
|
|
||||||
if (!m) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mscp_cleanup(m);
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *wrap_mscp_free(PyObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
char *keywords[] = { "m", NULL };
|
|
||||||
unsigned long long addr;
|
|
||||||
struct instance *i;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
i = get_instance(addr);
|
|
||||||
if (!i) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp instance address");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mscp_free(i->m);
|
|
||||||
release_instance(i);
|
|
||||||
|
|
||||||
return Py_BuildValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef pymscpMethods[] = {
|
|
||||||
{
|
|
||||||
"mscp_init", (PyCFunction)wrap_mscp_init,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_connect", (PyCFunction)wrap_mscp_connect,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_add_src_path", (PyCFunction)wrap_mscp_add_src_path,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_set_dst_path", (PyCFunction)wrap_mscp_set_dst_path,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_scan", (PyCFunction)wrap_mscp_scan,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_start", (PyCFunction)wrap_mscp_start,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_stop", (PyCFunction)wrap_mscp_stop,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_join", (PyCFunction)wrap_mscp_join,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_get_stats", (PyCFunction)wrap_mscp_get_stats,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_cleanup", (PyCFunction)wrap_mscp_cleanup,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mscp_free", (PyCFunction)wrap_mscp_free,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, NULL
|
|
||||||
},
|
|
||||||
{ NULL, NULL, 0, NULL },
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyModuleDef pymscpModule = {
|
|
||||||
PyModuleDef_HEAD_INIT, "pymscp", NULL, -1, pymscpMethods,
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC PyInit_pymscp(void) {
|
|
||||||
PyObject *mod = PyModule_Create(&pymscpModule);
|
|
||||||
|
|
||||||
PyModule_AddIntConstant(mod, "LOCAL2REMOTE", MSCP_DIRECTION_L2R);
|
|
||||||
PyModule_AddIntConstant(mod, "REMOTE2LOCAL", MSCP_DIRECTION_R2L);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_NONE", MSCP_SEVERITY_NONE);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_ERR", MSCP_SEVERITY_ERR);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_WARN", MSCP_SEVERITY_WARN);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_NOTICE", MSCP_SEVERITY_NOTICE);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_INFO", MSCP_SEVERITY_INFO);
|
|
||||||
PyModule_AddIntConstant(mod, "SEVERITY_DEBUG", MSCP_SEVERITY_DEBUG);
|
|
||||||
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
|
|
||||||
"""
|
|
||||||
test_python.py: Testing libmscp through the mscp python binding.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import mscp
|
|
||||||
import os
|
|
||||||
from util import File, check_same_md5sum
|
|
||||||
|
|
||||||
def test_create_and_release():
|
|
||||||
m = mscp.mscp("localhost", mscp.LOCAL2REMOTE)
|
|
||||||
m.cleanup()
|
|
||||||
|
|
||||||
|
|
||||||
""" copy test """
|
|
||||||
|
|
||||||
remote = "localhost"
|
|
||||||
remote_prefix = "{}/".format(os.getcwd()) # use current dir
|
|
||||||
param_remote_prefix_and_direction = [
|
|
||||||
("", remote_prefix, mscp.LOCAL2REMOTE), (remote_prefix, "", mscp.REMOTE2LOCAL)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
param_single_copy = [
|
|
||||||
(File("src", size = 64), File("dst")),
|
|
||||||
(File("src", size = 4096 * 1), File("dst")),
|
|
||||||
(File("src", size = 128 * 1024 * 1024), File("dst")),
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix, direction",
|
|
||||||
param_remote_prefix_and_direction)
|
|
||||||
@pytest.mark.parametrize("src, dst", param_single_copy)
|
|
||||||
def test_single_copy(src_prefix, dst_prefix, direction, src, dst):
|
|
||||||
src.make()
|
|
||||||
m = mscp.mscp(remote, direction)
|
|
||||||
m.copy(src_prefix + src.path, dst_prefix + dst.path)
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
src.cleanup()
|
|
||||||
dst.cleanup()
|
|
||||||
|
|
||||||
|
|
||||||
param_double_copy = [
|
|
||||||
(File("src1", size = 1024 * 1024), File("src2", size = 1024 * 1024),
|
|
||||||
File("dst/src1"), File("dst/src2")
|
|
||||||
)
|
|
||||||
]
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix, direction",
|
|
||||||
param_remote_prefix_and_direction)
|
|
||||||
@pytest.mark.parametrize("s1, s2, d1, d2", param_double_copy)
|
|
||||||
def test_double_copy(src_prefix, dst_prefix, direction, s1, s2, d1, d2):
|
|
||||||
s1.make()
|
|
||||||
s2.make()
|
|
||||||
mscp.mscp(remote, direction).copy([src_prefix + s1.path, src_prefix + s2.path],
|
|
||||||
dst_prefix + "dst")
|
|
||||||
assert check_same_md5sum(s1, d1)
|
|
||||||
assert check_same_md5sum(s2, d2)
|
|
||||||
s1.cleanup()
|
|
||||||
s2.cleanup()
|
|
||||||
d1.cleanup()
|
|
||||||
d2.cleanup()
|
|
||||||
|
|
||||||
|
|
||||||
param_single_copy = [
|
|
||||||
(File("src", size = 1024 * 1024 * 4), File("dst")),
|
|
||||||
]
|
|
||||||
|
|
||||||
param_kwargs = [
|
|
||||||
{ "nr_threads": 6 },
|
|
||||||
{ "nr_ahead": 64 },
|
|
||||||
{ "min_chunk_sz": 1 * 1024 * 1024 },
|
|
||||||
{ "max_chunk_sz": 64 * 1024 * 1024 },
|
|
||||||
{ "coremask": "0x0f" },
|
|
||||||
{ "max_startups": 5 },
|
|
||||||
{ "severity": mscp.SEVERITY_NONE },
|
|
||||||
{ "cipher": "aes128-gcm@openssh.com" },
|
|
||||||
{ "compress": "yes" },
|
|
||||||
{ "no_hostkey_check": True },
|
|
||||||
{ "enable_nagle": True },
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("src_prefix, dst_prefix, direction",
|
|
||||||
param_remote_prefix_and_direction)
|
|
||||||
@pytest.mark.parametrize("src, dst", param_single_copy)
|
|
||||||
@pytest.mark.parametrize("kw", param_kwargs)
|
|
||||||
def test_kwargs(src_prefix, dst_prefix, direction, src, dst, kw):
|
|
||||||
src.make()
|
|
||||||
m = mscp.mscp(remote, direction, **kw)
|
|
||||||
m.copy(src_prefix + src.path, dst_prefix + dst.path)
|
|
||||||
assert check_same_md5sum(src, dst)
|
|
||||||
src.cleanup()
|
|
||||||
dst.cleanup()
|
|
||||||
|
|
||||||
def test_login_failed():
|
|
||||||
m = mscp.mscp("asdfasdf@" + remote, mscp.LOCAL2REMOTE)
|
|
||||||
with pytest.raises(RuntimeError) as e:
|
|
||||||
m.connect()
|
|
||||||
|
|
||||||
m = mscp.mscp(remote, mscp.LOCAL2REMOTE, login_name = "asdfadsf")
|
|
||||||
with pytest.raises(RuntimeError) as e:
|
|
||||||
m.connect()
|
|
||||||
|
|
||||||
m = mscp.mscp(remote, mscp.LOCAL2REMOTE, port = "65534")
|
|
||||||
with pytest.raises(RuntimeError) as e:
|
|
||||||
m.connect()
|
|
||||||
|
|
||||||
def test_get_stat_before_copy_start():
|
|
||||||
m = mscp.mscp("localhost", mscp.LOCAL2REMOTE)
|
|
||||||
m.connect()
|
|
||||||
(total, done, finished) = m.stats()
|
|
||||||
assert total == 0 and done == 0
|
|
||||||
|
|
||||||
|
|
||||||
param_invalid_kwargs = [
|
|
||||||
{ "nr_threads": -1 },
|
|
||||||
{ "nr_ahead": -1 },
|
|
||||||
{ "min_chunk_sz": 1 },
|
|
||||||
{ "max_chunk_sz": 1 },
|
|
||||||
{ "coremask": "xxxxx" },
|
|
||||||
{ "max_startups": -1 },
|
|
||||||
{ "cipher": "invalid" },
|
|
||||||
{ "hmac": "invalid"},
|
|
||||||
{ "compress": "invalid"},
|
|
||||||
{ "ccalgo": "invalid"},
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("kw", param_invalid_kwargs)
|
|
||||||
def test_invalid_options(kw):
|
|
||||||
with pytest.raises(RuntimeError) as e:
|
|
||||||
m = mscp.mscp("localhost", mscp.LOCAL2REMOTE, **kw)
|
|
||||||
m.connect()
|
|
||||||
Reference in New Issue
Block a user