48 Commits

Author SHA1 Message Date
9d020dd241 Create Windows installer #53
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-30 12:31:47 -05:00
cbb2bfa73d Create Windows installer #53
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-07-30 12:15:58 -05:00
0404950693 Create Windows installer #53 2025-07-30 12:12:18 -05:00
9948df0541 Create Windows installer #53
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-07-30 12:06:21 -05:00
c53ab513a0 fix
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-07-30 11:55:29 -05:00
9e76f88c8f Create Windows installer #53
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-07-30 11:44:39 -05:00
8da2a7d27a Merge branch 'v2.1.0-rc-develop' of ssh://git.fifthgrid.com:3022/blockstorage/repertory into v2.1.0-rc-develop
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-30 11:26:22 -05:00
025a5a0db7 fix mount failure when path contains a space 2025-07-30 11:23:00 -05:00
5fc391e5c0 spelling
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-30 11:21:56 -05:00
5357486659 fix mount failure when path contains a space 2025-07-30 07:56:11 -05:00
d8774ba7f7 Create Windows installer #53 2025-07-30 07:52:54 -05:00
1e7e304b43 Create Windows installer #53 2025-07-30 07:49:58 -05:00
17b7b09333 Create Windows installer #53 2025-07-30 07:49:34 -05:00
5f4b853764 fix mount failure when path contains a space 2025-07-29 15:16:34 -05:00
6d0f2a6c36 fix
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 14:28:25 -05:00
ccdbf2efde updated CHANGELOG.md
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 14:14:43 -05:00
e02eebba99 (Create Windows installer #53) ([ui] UI console window should close after launch #51) 2025-07-29 14:11:51 -05:00
7d06fb5617 Create Windows installer #53
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 12:48:32 -05:00
66053df28f Create Windows installer #53
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 10:59:18 -05:00
6920db4c88 updated build system
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 09:05:59 -05:00
e37b2492e9 Create Windows installer #53
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-29 08:07:49 -05:00
2435a765f0 Create Windows installer #53 2025-07-29 08:06:44 -05:00
f88e4181f1 Create Windows installer #53 2025-07-29 08:04:36 -05:00
5d2a1b0c17 Create Windows installer #53 2025-07-29 07:58:26 -05:00
1fff514e4e Create Windows installer #53
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-07-28 15:27:53 -05:00
2f14e0f054 Create Windows installer #53 2025-07-28 15:27:43 -05:00
0c049a17f6 Create Windows installer #53
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-07-28 13:14:28 -05:00
1390f96fdc Create Windows installer #53 2025-07-28 13:03:27 -05:00
1d7a3f5125 Create Windows installer #53 2025-07-28 12:47:27 -05:00
a9ebc52514 Create Windows installer #53 2025-07-28 11:53:54 -05:00
ca9eaf0249 Create Windows installer #53 2025-07-28 10:40:24 -05:00
7601746093 Create Windows installer #53 2025-07-28 10:37:03 -05:00
42f83170f7 Create Windows installer #53 2025-07-28 10:27:55 -05:00
9722cc06ff Create Windows installer #53 2025-07-28 10:24:54 -05:00
3d063a8ec2 Create Windows installer #53 2025-07-28 09:48:35 -05:00
b6719846bf Remove 'default' as initial bucket name for Sia #54
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-28 09:06:52 -05:00
9ed4187593 Remove 'default' as initial bucket name for Sia #54
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-07-28 08:20:13 -05:00
8c0bbe05ee Remove 'default' as initial bucket name for Sia #54
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-07-28 08:01:38 -05:00
c8b6d5053e Remove 'default' as initial bucket name for Sia #54
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-28 07:25:25 -05:00
4cf339cfc4 fix . and .. incorrectly being reported as files
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-26 13:37:59 -05:00
6fe23f270a fix . and .. incorrectly being reported as files 2025-07-26 13:17:06 -05:00
c85fe76a48 flutter ugrades
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-26 12:46:16 -05:00
4508b6d908 fix . and .. incorrectly being reported as files
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-26 11:04:59 -05:00
c74a70ce13 fix . and .. incorrectly being reported as files 2025-07-26 11:03:24 -05:00
f5e88e44bf cleanup
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-07-26 08:59:33 -05:00
f11f92ba55 updated build system
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-26 08:52:20 -05:00
14d0173bd3 fix link
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-07-25 09:26:31 -05:00
5b56c73528 updated version
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-07-25 07:59:25 -05:00
36 changed files with 629 additions and 274 deletions

View File

@@ -207,6 +207,7 @@ source_subdir
spdlog
spdlog_project
st_ctim
startupinfoa
static-libgcc
static-libstdc++
stbuf
@@ -247,4 +248,4 @@ wsign-conversion
wunused
wuseless
wxwidgets_version
xattr
xattr

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ scripts/cleanup.sh
version.rc
version.cpp
override.sh
repertory.iss

View File

@@ -1,8 +1,23 @@
# Changelog
## v2.1.0-rc
### Issues
* \#51 [ui] UI console window should close after launch
* \#53 Create Windows installer
* \#54 Remove 'default' as initial bucket name for Sia
### Changes from v2.0.6-release
* Fixed `.` and `..` incorrectly being reported as files in remote Linux mounts
* Fixed UI mount failure when path contains a space
## v2.0.6-release
<!-- markdownlint-disable-next-line -->
### Issues
* \#42 [bug] Remote mount directory listing on Windows connected to Linux is failing
* \#43 [bug] Directories are not importing properly for Sia
* \#44 [bug] Windows-to-Linux remote mount ignores `CREATE_NEW`

View File

@@ -115,6 +115,14 @@ if(PROJECT_BUILD)
${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}/version.cpp
@ONLY
)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.iss.in")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.iss.in
${PROJECT_DIST_DIR}/../${PROJECT_NAME}.iss
@ONLY
)
endif()
else()
message(STATUS "-=[CMake Settings]=-")
message(STATUS " C standard: ${CMAKE_C_STANDARD}")

View File

@@ -89,14 +89,12 @@ username and password.
* `--name, -na [name]`
* Identifies a unique configuration name to support multiple mounts.
* The `--name` option can be set to any valid value allowed as a file name for your filesystem.
* For Sia, the bucket name will be set to the same value if it is empty in the configuration file.
* If the `--name` option is not specified, `default` will be used.
* For S3, the `--name` option is required and does not affect the bucket name.
* The `--name` option is required
* `-dc`
* Display mount configuration
* For Sia, `--name` is optional
* For S3, the `-s3` option is required along with `--name`
* For Sia, the `--name` option is required
* For S3, the `-s3` and `--name` options are required
### Sia
@@ -104,14 +102,8 @@ username and password.
* Required steps:
* Set the appropriate bucket name and `renterd` API password in `repertory` configuration:
* To use `default` as the bucket name and configuration name, you only need to set the `renterd` API password:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* To specify a different bucket name while using `default` as the configuration name:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* `repertory -set SiaConfig.Bucket '<my bucket>'`
* For all other configurations:
* `repertory --name '<my config name>' -set HostConfig.ApiPassword '<my password>'`
* `repertory --name '<my config name>' -set SiaConfig.Bucket '<my bucket name>'`
* `repertory --name '<my config name>' -set HostConfig.ApiPassword '<my password>'`
* `repertory --name '<my config name>' -set SiaConfig.Bucket '<my bucket name>'`
* Optional steps:
* Set a user name used during `renterd` basic authentication:
@@ -131,7 +123,7 @@ username and password.
* `repertory -dc`
* `repertory --name '<my config name>' -dc`
* Example:
* `repertory --name default -dc`
* `repertory --name my_bucket -dc`
#### Sia Mounting
@@ -139,13 +131,13 @@ username and password.
* `repertory /mnt/location`
* `repertory --name '<my config name>' /mnt/location`
* Example:
* `repertory --name default /mnt/location`
* `repertory --name my_bucket /mnt/location`
* Windows:
* `repertory t:`
* `repertory --name '<my config name>' t:`
* Example:
* `repertory --name default t:`
* `repertory --name my_bucket t:`
#### Sia Configuration File
@@ -187,7 +179,7 @@ username and password.
"RetryReadCount": 6,
"RingBufferFileSize": 512,
"SiaConfig": {
"Bucket": "default"
"Bucket": "my_bucket"
},
"TaskWaitMs": 100,
"Version": 1
@@ -453,7 +445,7 @@ in the `dist/` directory
* [spdlog](https://github.com/gabime/spdlog)
* [SQLite](https://www.sqlite.org)
* [stduuid](https://github.com/mariusbancila/stduuid)
* [Storj](https://storj.io/)
* [Storj](https://www.storj.io/)
* [WinFSP - FUSE for Windows](https://github.com/billziss-gh/winfsp)
* [zlib](https://zlib.net/)

View File

@@ -7,6 +7,7 @@ set(EXPAT_HASH 85372797ff0673a8fc4a6be16466bb5a0ca28c0dcf3c6f7ac1686b4a3ba2aabb)
set(GCC_HASH 51b9919ea69c980d7a381db95d4be27edf73b21254eb13d752a08003b4d013b1)
set(GTEST_HASH 65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c)
set(ICU_HASH a2c443404f00098e9e90acf29dc318e049d2dc78d9ae5f46efb261934a730ce2)
set(INNOSETUP_HASH f3c42116542c4cc57263c5ba6c4feabfc49fe771f2f98a79d2f7628b8762723b)
set(JSON_HASH 4b92eb0c06d10683f7447ce9406cb97cd4b453be18d7279320f7b2f025c10187)
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
set(MINGW_HASH 5afe822af5c4edbf67daaf45eec61d538f49eef6b19524de64897c6b95828caf)
@@ -17,4 +18,5 @@ set(ROCKSDB_HASH afccfab496556904900afacf7d99887f1d50cb893e5d2288bd502db233adaca
set(SPDLOG_HASH 15a04e69c222eb6c01094b5c7ff8a249b36bb22788d72519646fb85feb267e67)
set(SQLITE_HASH 9ad6d16cbc1df7cd55c8b55127c82a9bca5e9f287818de6dc87e04e73599d754)
set(STDUUID_HASH b1176597e789531c38481acbbed2a6894ad419aab0979c10410d59eb0ebf40d3)
set(WINFSP_HASH 073a70e00f77423e34bed98b86e600def93393ba5822204fac57a29324db9f7a)
set(ZLIB_HASH 17e88863f3600672ab49182f217281b6fc4d3c762bde361935e436a95214d05c)

View File

@@ -1,18 +1,19 @@
set(BINUTILS_VERSION 2.44)
set(BOOST2_MAJOR_VERSION 1)
set(BOOST2_MINOR_VERSION 76)
set(BOOST2_PATCH_VERSION 0)
set(BOOST_MAJOR_VERSION 1)
set(BOOST_MINOR_VERSION 88)
set(BOOST_PATCH_VERSION 0)
set(BOOST2_MAJOR_VERSION 1)
set(BOOST2_MINOR_VERSION 76)
set(BOOST2_PATCH_VERSION 0)
set(CPP_HTTPLIB_VERSION 0.23.1)
set(CURL2_VERSION 8_15_0)
set(CURL_VERSION 8.15.0)
set(EXPAT2_VERSION 2_7_1)
set(CURL2_VERSION 8_15_0)
set(EXPAT_VERSION 2.7.1)
set(EXPAT2_VERSION 2_7_1)
set(GCC_VERSION 15.1.0)
set(GTEST_VERSION 1.17.0)
set(ICU_VERSION 76-1)
set(INNOSETUP_VERSION 6.4.3)
set(JSON_VERSION 3.12.0)
set(LIBSODIUM_VERSION 1.0.20)
set(MINGW_VERSION 13.0.0)
@@ -21,7 +22,9 @@ set(PKG_CONFIG_VERSION 0.29.2)
set(PUGIXML_VERSION 1.15)
set(ROCKSDB_VERSION 10.4.2)
set(SPDLOG_VERSION 1.15.3)
set(SQLITE2_VERSION 3.50.3)
set(SQLITE_VERSION 3500300)
set(SQLITE2_VERSION 3.50.3)
set(STDUUID_VERSION 1.2.3)
set(WINFSP_VERSION 2.1.25156)
set(WINFSP2_VERSION 2.1)
set(ZLIB_VERSION 1.3.1)

View File

@@ -9,10 +9,10 @@ PROJECT_COPYRIGHT="Copyright <2018-2025> <MIT License> <${PROJECT_URL}>"
PROJECT_DESC="Mount utility for Sia and S3"
PROJECT_MAJOR_VERSION=2
PROJECT_MINOR_VERSION=0
PROJECT_REVISION_VERSION=6
PROJECT_RELEASE_NUM=1
PROJECT_RELEASE_ITER=release
PROJECT_MINOR_VERSION=1
PROJECT_REVISION_VERSION=0
PROJECT_RELEASE_NUM=0
PROJECT_RELEASE_ITER=rc
PROJECT_APP_LIST=(${PROJECT_NAME})

View File

@@ -12,6 +12,7 @@ RUN apk add \
bzip2 \
clang17-extra-tools \
cmake \
curl \
file \
flex \
g++ \
@@ -43,6 +44,7 @@ RUN apk add \
ruby \
texinfo \
unzip \
xvfb \
wget \
wine \
xz \
@@ -102,6 +104,39 @@ RUN echo -e \
"system = 'windows'\n"\
> ${MY_TOOLCHAIN_FILE_MESON}
RUN mkdir -p /opt/bin;echo -e \
"#!/bin/sh\n"\
"COUNT=0\n"\
"echo \"Start waiting on \$@\"\n"\
"while pgrep \"\$@\" > /dev/null; do \n"\
" echo \"waiting ...\"\n"\
" sleep 1;\n"\
" COUNT=\$((COUNT+1))\n"\
" if [ \$COUNT -eq 60 ]; then\n"\
" exit 3;\n"\
" fi\n"\
"done\n"\
"echo \"\$@ completed\"\n"\
> /opt/bin/waitonprocess && \
chmod +x /opt/bin/waitonprocess && \
cat /opt/bin/waitonprocess
RUN echo -e \
"#!/bin/sh\n"\
"Xvfb \$DISPLAY &\n"\
"tokill=\$!\n"\
"wine wineboot --init\n"\
"waitonprocess wineserver\n"\
"\"\$@\"\n"\
"retval=\$?\n"\
"kill -15 \$tokill\n"\
"wine wineboot --shutdown\n"\
"return \$retval\n"\
> /opt/bin/wine-x11-run && \
chmod +x /opt/bin/wine-x11-run && \
cat /opt/bin/wine-x11-run
ENV PATH="/opt/bin:${PATH}"
SHELL [ "/bin/bash", "-c" ]
RUN mkdir -p \
@@ -799,6 +834,7 @@ RUN if [ -f "/3rd_party/libevent-${MY_LIBEVENT_VERSION}-stable.tar.gz" ]; then \
&& cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=${MY_CXX_STANDARD} \
-DCMAKE_C_FLAGS="-include winsock2.h -include ws2tcpip.h -include iphlpapi.h" \
-DCMAKE_INSTALL_PREFIX=${MY_MINGW_DIR} \
-DCMAKE_TOOLCHAIN_FILE=${MY_TOOLCHAIN_FILE_CMAKE} \
-DEVENT__DISABLE_OPENSSL=ON \
@@ -1119,6 +1155,31 @@ RUN if [ -f "/3rd_party/libdsm-${MY_LIBDSM_VERSION}.tar.gz" ]; then \
&& rm -r libdsm-${MY_LIBDSM_VERSION} \
; fi
ENV DISPLAY=:99
ENV WINEDEBUG=-all,err+all
RUN wine64 reg add 'HKEY_CURRENT_USER\Software\Wine' /v ShowDotFiles /d Y \
&& while [ ! -f /root/.wine/user.reg ]; do sleep 1; done
ARG INNOSETUP_VERSION
ENV MY_INNOSETUP_VERSION=${INNOSETUP_VERSION}
RUN wine-x11-run wine64 /3rd_party/mingw64/innosetup-${MY_INNOSETUP_VERSION}.exe /SP- /VERYSILENT /ALLUSERS /SUPPRESSMSGBOXES /DOWNLOADISCRYPT=1
ARG UID=1000
ARG GID=1000
ARG USERNAME=myuser
RUN addgroup -g $GID $USERNAME && \
adduser -D -u $UID -G $USERNAME -h /home/$USERNAME $USERNAME
RUN rsync -av --progress /root/.wine/ /home/$USERNAME/.wine/ && \
chown -R $UID:$GID -R /home/$USERNAME/.wine/
RUN (mv ${MY_MINGW_DIR}/lib/*.dll ${MY_MINGW_DIR}/bin || echo "no dll's found") \
&& chmod 0777 -R ${MY_MINGW_DIR} \
&& rm -rf /3rd_party
&& rm -rf /3rd_party \
&& rm -rf /root/.wine
USER $USERNAME
WORKDIR /home/$USERNAME

165
repertory.iss.in Normal file
View File

@@ -0,0 +1,165 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "repertory"
#define MyAppVersion "@PROJECT_MAJOR_VERSION@.@PROJECT_MINOR_VERSION@.@PROJECT_REVISION_VERSION@-@PROJECT_RELEASE_ITER@_@PROJECT_GIT_REV@"
#define MyAppPublisher "BlockStorage"
#define MyAppURL "https://git.fifthgrid.com/BlockStorage/repertory"
#define MyAppExeName "repertory.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{BD165823-1DEF-4D23-87DC-3D7A9BB73A00}
AppName={#MyAppName}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppVersion={#MyAppVersion}
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
LicenseFile=repertory\LICENSE.md
OutputBaseFilename=repertory_{#MyAppVersion}_windows_@PROJECT_MARCH@_setup
PrivilegesRequired=admin
SolidCompression=yes
UninstallDisplayIcon={app}\{#MyAppExeName}
WizardStyle=modern
[code]
const
SMTO_ABORTIFHUNG = $0002;
WM_SETTINGCHANGE = $001A;
type
LPARAM = LongWord;
LRESULT = LongWord;
WPARAM = LongWord;
function SendMessageTimeout(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM;
fuFlags: UINT; uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutW@user32.dll stdcall';
procedure RefreshEnvironment();
var
R: DWORD;
begin
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
'Environment', SMTO_ABORTIFHUNG, 5000, R);
end;
function NormalizeSemicolons(S: string): string;
begin
while Pos(';;', S) > 0 do
StringChange(S, ';;', ';');
Result := S;
end;
procedure AddAppToPath();
var
OldPath, NewPath, FinalPath: string;
begin
if not RegQueryStringValue(HKLM,
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
'Path', OldPath)
then
OldPath := '';
NewPath := ExpandConstant('{app}');
if Pos(LowerCase(NewPath), LowerCase(OldPath)) = 0 then
begin
if (OldPath <> '') and (Copy(OldPath, Length(OldPath), 1) <> ';') then
OldPath := OldPath + ';';
FinalPath := NormalizeSemicolons(OldPath + NewPath + ';');
RegWriteExpandStringValue(HKLM,
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
'Path', FinalPath);
RefreshEnvironment();
end;
end;
procedure RemoveAppFromPath();
var
OldPath, NewPath, Token, Remainder, FinalPath: string;
p: Integer;
begin
if not RegQueryStringValue(HKLM,
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
'Path', OldPath) then
Exit;
NewPath := ExpandConstant('{app}');
Remainder := OldPath;
FinalPath := '';
while Length(Remainder) > 0 do
begin
p := Pos(';', Remainder);
if p = 0 then
begin
Token := Remainder;
Remainder := '';
end
else
begin
Token := Copy(Remainder, 1, p - 1);
Delete(Remainder, 1, p);
end;
Token := Trim(Token);
if (Token <> '') and (CompareText(Token, NewPath) <> 0) then
begin
if (FinalPath <> '') and (FinalPath[Length(FinalPath)] <> ';') then
FinalPath := FinalPath + ';';
FinalPath := FinalPath + Token;
end;
end;
while Pos(';;', FinalPath) > 0 do
StringChange(FinalPath, ';;', ';');
if (FinalPath <> '') and (FinalPath[Length(FinalPath)] = ';') then
Delete(FinalPath, Length(FinalPath), 1);
RegWriteExpandStringValue(HKLM,
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
'Path', FinalPath);
RefreshEnvironment();
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
AddAppToPath();
end;
end;
procedure DeinitializeUninstall();
begin
RemoveAppFromPath();
end;
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Components]
Name: "main"; Description: "Repertory Core"; Types: full compact custom; Flags: fixed
Name: "winfsp"; Description: "WinFSP v@WINFSP_VERSION@"; Types: full custom
[Files]
Source: "repertory\*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: main
Source: "3rd_party\winfsp-@WINFSP_VERSION@.msi"; DestDir: "{app}"; Flags: ignoreversion; Components: winfsp
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Parameters: "-ui --hidden"
Name: "{commonstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Parameters: "-ui --launch_only --hidden"
[Run]
Filename: "msiexec.exe"; WorkingDir: "{app}"; Parameters: "/a winfsp-@WINFSP_VERSION@.msi /norestart"; \
Flags: 64bit waituntilterminated; Components: winfsp

View File

@@ -286,7 +286,8 @@ enum class exit_code : std::int32_t {
init_failed = -18,
ui_mount_failed = -19,
exception = -20,
provider_offline = -21
provider_offline = -21,
ui_failed = -22
};
enum http_error_codes : std::int32_t {

View File

@@ -42,6 +42,7 @@ inline const option get_directory_items_option = {"-gdi",
inline const option get_pinned_files_option = {"-gpf", "--get_pinned_files"};
inline const option help_option = {"-h", "--help"};
inline const option hidden_option = {"-hidden", "--hidden"};
inline const option launch_only_option = {"-lo", "--launch_only"};
inline const option open_files_option = {"-of", "--open_files"};
inline const option pin_file_option = {"-pf", "--pin_file"};
inline const option pinned_status_option = {"-ps", "--pinned_status"};
@@ -71,6 +72,7 @@ inline const std::vector<option> option_list = {
get_pinned_files_option,
help_option,
hidden_option,
launch_only_option,
open_files_option,
password_option,
pin_file_option,

View File

@@ -19,6 +19,7 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <memory>
#if !defined(_WIN32)
#include "drives/fuse/remotefuse/remote_fuse_drive.hpp"
@@ -102,7 +103,7 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
}
if (remote_instance_) {
const auto res = remote_instance_->fuse_destroy();
auto res = remote_instance_->fuse_destroy();
if (res != 0) {
utils::error::raise_error(function_name,
"remote fuse_destroy() failed|err|" +
@@ -128,8 +129,8 @@ auto remote_fuse_drive::fgetattr_impl(std::string api_path,
remote::stat r_stat{};
auto directory = false;
const auto res = remote_instance_->fuse_fgetattr(api_path.c_str(), r_stat,
directory, f_info->fh);
auto res = remote_instance_->fuse_fgetattr(api_path.c_str(), r_stat,
directory, f_info->fh);
if (res == 0) {
populate_stat(r_stat, directory, *unix_st);
}
@@ -191,7 +192,7 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
bool directory = false;
remote::stat r_stat{};
const auto res =
auto res =
remote_instance_->fuse_getattr(api_path.c_str(), r_stat, directory);
if (res == 0) {
populate_stat(r_stat, directory, *unix_st);
@@ -208,9 +209,9 @@ api_error remote_fuse_drive::getxtimes_impl(std::string api_path,
return utils::to_api_error(-EFAULT);
}
remote::file_time repertory_bkuptime = 0u;
remote::file_time repertory_crtime = 0u;
const auto res = remote_instance_->fuse_getxtimes(
remote::file_time repertory_bkuptime{0U};
remote::file_time repertory_crtime{0U};
auto res = remote_instance_->fuse_getxtimes(
api_path.c_str(), repertory_bkuptime, repertory_crtime);
if (res == 0) {
bkuptime->tv_nsec =
@@ -381,7 +382,7 @@ auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
fuse_fill_dir_t fuse_fill_dir,
off_t offset,
struct fuse_file_info *f_info,
fuse_readdir_flags /*flags*/)
fuse_readdir_flags /* flags */)
-> api_error {
#else // FUSE_USE_VERSION < 30
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
@@ -390,20 +391,42 @@ auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
struct fuse_file_info *f_info)
-> api_error {
#endif // FUSE_USE_VERSION >= 30
std::string item_path;
int res = 0;
int res{0};
while ((res = remote_instance_->fuse_readdir(
api_path.c_str(), static_cast<remote::file_offset>(offset),
f_info->fh, item_path)) == 0) {
if ((item_path != ".") && (item_path != "..")) {
std::unique_ptr<struct stat> p_stat{nullptr};
int stat_res{0};
if ((item_path == ".") || (item_path == "..")) {
p_stat = std::make_unique<struct stat>();
std::memset(p_stat.get(), 0, sizeof(struct stat));
if (item_path == ".") {
stat_res =
stat(utils::path::combine(get_mount_location(), {api_path}).c_str(),
p_stat.get());
} else {
stat_res =
stat(utils::path::get_parent_path(
utils::path::combine(get_mount_location(), {api_path}))
.c_str(),
p_stat.get());
}
if (stat_res != 0) {
res = stat_res;
break;
}
} else {
item_path = utils::path::strip_to_file_name(item_path);
}
#if FUSE_USE_VERSION >= 30
if (fuse_fill_dir(buf, item_path.c_str(), nullptr, ++offset,
static_cast<fuse_fill_dir_flags>(0)) != 0) {
if (fuse_fill_dir(buf, item_path.c_str(), p_stat.get(), ++offset,
FUSE_FILL_DIR_PLUS) != 0) {
#else // FUSE_USE_VERSION < 30
if (fuse_fill_dir(buf, item_path.c_str(), nullptr, ++offset) != 0) {
if (fuse_fill_dir(buf, item_path.c_str(), p_stat.get(), ++offset) != 0) {
#endif // FUSE_USE_VERSION >= 30
break;
}
@@ -592,7 +615,7 @@ auto remote_fuse_drive::write_impl(std::string api_path, const char *buffer,
size_t write_size, off_t write_offset,
struct fuse_file_info *f_info,
std::size_t &bytes_written) -> api_error {
const auto res = remote_instance_->fuse_write(
auto res = remote_instance_->fuse_write(
api_path.c_str(), buffer, write_size,
static_cast<remote::file_offset>(write_offset), f_info->fh);
if (res >= 0) {

View File

@@ -50,8 +50,17 @@
#endif // defined(PROJECT_ENABLE_CURL)
namespace {
#if defined(PROJECT_ENABLE_CURL)
bool curl_initialized{false};
#endif // defined(PROJECT_ENABLE_CURL)
#if defined(PROJECT_ENABLE_SPDLOG)
bool spdlog_initialized{false};
#endif // defined(PROJECT_ENABLE_SPDLOG)
#if defined(PROJECT_ENABLE_SQLITE)
bool sqlite3_initialized{false};
#endif // defined(PROJECT_ENABLE_SQLITE)
} // namespace
namespace repertory {
@@ -72,9 +81,12 @@ auto project_initialize() -> bool {
}
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
#if defined(PROJECT_ENABLE_SPDLOG)
spdlog::drop_all();
spdlog::flush_every(std::chrono::seconds(5));
spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
spdlog_initialized = true;
#endif // defined(PROJECT_ENABLE_SPDLOG)
#if defined(PROJECT_ENABLE_LIBSODIUM)
if (sodium_init() == -1) {
@@ -116,15 +128,22 @@ void project_cleanup() {
#if defined(PROJECT_ENABLE_CURL)
if (curl_initialized) {
curl_shared::cleanup();
curl_initialized = false;
}
#endif // defined(PROJECT_ENABLE_CURL)
#if defined(PROJECT_ENABLE_SQLITE)
if (sqlite3_initialized) {
sqlite3_shutdown();
sqlite3_initialized = false;
}
#endif // defined(PROJECT_ENABLE_SQLITE)
spdlog::shutdown();
#if defined(PROJECT_ENABLE_SPDLOG)
if (spdlog_initialized) {
spdlog::shutdown();
spdlog_initialized = false;
}
#endif // defined(PROJECT_ENABLE_SPDLOG)
}
} // namespace repertory

View File

@@ -41,13 +41,6 @@
#include "utils/utils.hpp"
namespace {
[[nodiscard]] auto get_bucket(const repertory::sia_config &cfg) -> std::string {
if (cfg.bucket.empty()) {
return "default";
}
return cfg.bucket;
}
[[nodiscard]] auto get_last_modified(const nlohmann::json &obj)
-> std::uint64_t {
try {
@@ -119,7 +112,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
curl::requests::http_put_file put_file{};
put_file.allow_timeout = true;
put_file.path = "/api/worker/object" + api_path + "/";
put_file.query["bucket"] = get_bucket(get_sia_config());
put_file.query["bucket"] = get_sia_config().bucket;
std::string error_data;
put_file.response_handler = [&error_data](auto &&data, long response_code) {
@@ -363,7 +356,7 @@ auto sia_provider::get_object_info(const std::string &api_path,
curl::requests::http_get get{};
get.allow_timeout = true;
get.path = "/api/bus/object" + api_path;
get.query["bucket"] = get_bucket(get_sia_config());
get.query["bucket"] = get_sia_config().bucket;
get.query["onlymetadata"] = "true";
std::string error_data;
@@ -413,7 +406,7 @@ auto sia_provider::get_object_list(const std::string &api_path,
curl::requests::http_get get{};
get.allow_timeout = true;
get.path = "/api/bus/objects" + api_path + "/";
get.query["bucket"] = get_bucket(get_sia_config());
get.query["bucket"] = get_sia_config().bucket;
if (marker.has_value()) {
get.query["limit"] = "1000";
get.query["marker"] = marker.value();
@@ -464,7 +457,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t {
curl::requests::http_get get{};
get.allow_timeout = true;
get.path = "/api/bus/autopilot";
get.query["bucket"] = get_bucket(get_sia_config());
get.query["bucket"] = get_sia_config().bucket;
json config_data;
std::string error_data;
@@ -581,7 +574,7 @@ auto sia_provider::is_online() const -> bool {
curl::requests::http_get get{};
get.allow_timeout = true;
get.path = "/api/bus/consensus/state";
get.query["bucket"] = get_bucket(get_sia_config());
get.query["bucket"] = get_sia_config().bucket;
std::string error_data;
json state_data;
@@ -675,7 +668,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
try {
curl::requests::http_get get{};
get.path = "/api/worker/object" + api_path;
get.query["bucket"] = get_bucket(get_sia_config());
get.query["bucket"] = get_sia_config().bucket;
get.headers["accept"] = "application/octet-stream";
get.range = {{
offset,
@@ -741,7 +734,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path)
curl::requests::http_delete del{};
del.allow_timeout = true;
del.path = "/api/bus/object" + api_path + "/";
del.query["bucket"] = get_bucket(get_sia_config());
del.query["bucket"] = get_sia_config().bucket;
std::string error_data;
del.response_handler = [&error_data](auto &&data, long response_code) {
@@ -777,7 +770,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error {
curl::requests::http_delete del{};
del.allow_timeout = true;
del.path = "/api/bus/object" + api_path;
del.query["bucket"] = get_bucket(get_sia_config());
del.query["bucket"] = get_sia_config().bucket;
std::string error_data;
del.response_handler = [&error_data](auto &&data, long response_code) {
@@ -815,7 +808,7 @@ auto sia_provider::rename_file(const std::string &from_api_path,
try {
curl::requests::http_post post{};
post.json = nlohmann::json({
{"bucket", get_bucket(get_sia_config())},
{"bucket", get_sia_config().bucket},
{"from", from_api_path},
{"to", to_api_path},
{"mode", "single"},
@@ -889,7 +882,7 @@ auto sia_provider::upload_file_impl(const std::string &api_path,
curl::requests::http_put_file put_file{};
put_file.path = "/api/worker/object" + api_path;
put_file.query["bucket"] = get_bucket(get_sia_config());
put_file.query["bucket"] = get_sia_config().bucket;
put_file.headers["content-type"] = "application/octet-stream";
put_file.source_path = source_path;

View File

@@ -37,7 +37,6 @@
#include "cli/set.hpp"
#include "cli/status.hpp"
#include "cli/test.hpp"
#include "cli/ui.hpp"
#include "cli/unmount.hpp"
#include "cli/unpin_file.hpp"
#include "utils/cli_utils.hpp"
@@ -73,7 +72,6 @@ inline const std::unordered_map<utils::cli::option, action, option_hasher>
{utils::cli::options::set_option, cli::actions::set},
{utils::cli::options::status_option, cli::actions::status},
{utils::cli::options::test_option, cli::actions::test},
{utils::cli::options::ui_option, cli::actions::ui},
{utils::cli::options::unmount_option, cli::actions::unmount},
{utils::cli::options::unpin_file_option, cli::actions::unpin_file},
};

View File

@@ -1,58 +0,0 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef REPERTORY_INCLUDE_CLI_UI_HPP_
#define REPERTORY_INCLUDE_CLI_UI_HPP_
#include "cli/common.hpp"
#include "ui/handlers.hpp"
#include "ui/mgmt_app_config.hpp"
namespace repertory::cli::actions {
[[nodiscard]] inline auto
ui(std::vector<const char *> args, const std::string & /*data_directory*/,
const provider_type & /* prov */, const std::string & /* unique_id */,
std::string /* user */, std::string /* password */) -> exit_code {
ui::mgmt_app_config config{};
std::string data;
auto res = utils::cli::parse_string_option(
args, utils::cli::options::ui_port_option, data);
if (res == exit_code::success && not data.empty()) {
config.set_api_port(utils::string::to_uint16(data));
}
if (not utils::file::change_to_process_directory()) {
return exit_code::ui_mount_failed;
}
httplib::Server server;
if (not server.set_mount_point("/ui", "./web")) {
return exit_code::ui_mount_failed;
}
ui::handlers handlers(&config, &server);
return exit_code::success;
}
} // namespace repertory::cli::actions
#endif // REPERTORY_INCLUDE_CLI_UI_HPP_

View File

@@ -27,7 +27,11 @@
namespace repertory::ui {
class mgmt_app_config final {
public:
mgmt_app_config();
mgmt_app_config(bool hidden, bool launch_only);
private:
std::atomic<bool> hidden_{false};
std::atomic<bool> launch_only_{false};
private:
atomic<std::string> api_password_{"repertory"};
@@ -52,6 +56,10 @@ public:
[[nodiscard]] auto get_api_user() const -> std::string { return api_user_; }
[[nodiscard]] auto get_hidden() const -> bool { return hidden_; }
[[nodiscard]] auto get_launch_only() const -> bool { return launch_only_; }
[[nodiscard]] auto get_mount_location(provider_type prov,
std::string_view name) const
-> std::string;
@@ -62,6 +70,10 @@ public:
void set_api_user(std::string_view api_user);
void set_hidden(bool hidden);
void set_launch_only(bool launch_only);
void set_mount_location(provider_type prov, std::string_view name,
std::string_view location);
};

View File

@@ -26,6 +26,8 @@
#include "cli/actions.hpp"
#include "initialize.hpp"
#include "types/repertory.hpp"
#include "ui/handlers.hpp"
#include "ui/mgmt_app_config.hpp"
#include "utils/cli_utils.hpp"
#include "utils/polling.hpp"
@@ -37,7 +39,6 @@ auto main(int argc, char **argv) -> int {
#endif // defined(PROJECT_ENABLE_BACKWARD_CPP)
if (not repertory::project_initialize()) {
std::cerr << "fatal: failed to initialize repertory" << std::endl;
repertory::project_cleanup();
return -1;
}
@@ -52,125 +53,146 @@ auto main(int argc, char **argv) -> int {
args.push_back("-h");
}
auto prov = utils::cli::get_provider_type_from_args(args);
int ret{0};
if (utils::cli::has_option(args, utils::cli::options::ui_option)) {
ui::mgmt_app_config config{
utils::cli::has_option(args, utils::cli::options::hidden_option),
utils::cli::has_option(args, utils::cli::options::launch_only_option),
};
std::string data_directory;
auto res = utils::cli::parse_string_option(
args, utils::cli::options::data_directory_option, data_directory);
std::string data;
auto res = utils::cli::parse_string_option(
args, utils::cli::options::ui_port_option, data);
if (res == exit_code::success && not data.empty()) {
config.set_api_port(utils::string::to_uint16(data));
}
std::string password;
res = (res == exit_code::success)
? utils::cli::parse_string_option(
args, utils::cli::options::password_option, password)
: res;
if (not utils::file::change_to_process_directory()) {
ret = static_cast<std::int32_t>(exit_code::ui_failed);
} else {
httplib::Server server;
if (not server.set_mount_point("/ui", "./web")) {
ret = static_cast<std::int32_t>(exit_code::ui_failed);
} else {
ui::handlers handlers(&config, &server);
}
}
} else {
auto prov = utils::cli::get_provider_type_from_args(args);
std::string user;
res = (res == exit_code::success)
? utils::cli::parse_string_option(
args, utils::cli::options::user_option, user)
: res;
std::string data_directory;
auto res = utils::cli::parse_string_option(
args, utils::cli::options::data_directory_option, data_directory);
std::string remote_host;
std::uint16_t remote_port{};
std::string unique_id;
if (res == exit_code::success) {
if (prov == provider_type::remote) {
std::string data;
res = utils::cli::parse_string_option(
args, utils::cli::options::remote_mount_option, data);
if (res == exit_code::success) {
const auto parts = utils::string::split(data, ':', false);
if (parts.size() != 2) {
std::cerr << "Invalid syntax for host/port '-rm "
"host:port,--remote_mount host:port'"
<< std::endl;
res = exit_code::invalid_syntax;
} else {
unique_id = parts.at(0U) + ':' + parts.at(1U);
remote_host = parts.at(0U);
try {
remote_port = utils::string::to_uint16(parts.at(1U));
data_directory =
data_directory.empty()
? utils::path::combine(
app_config::default_data_directory(prov),
{
utils::string::replace_copy(unique_id, ':', '_'),
})
: utils::path::absolute(data_directory);
} catch (const std::exception &e) {
std::cerr << (e.what() == nullptr ? "Unable to parse port"
: e.what())
std::string password;
res = (res == exit_code::success)
? utils::cli::parse_string_option(
args, utils::cli::options::password_option, password)
: res;
std::string user;
res = (res == exit_code::success)
? utils::cli::parse_string_option(
args, utils::cli::options::user_option, user)
: res;
std::string remote_host;
std::uint16_t remote_port{};
std::string unique_id;
if (res == exit_code::success) {
if (prov == provider_type::remote) {
std::string data;
res = utils::cli::parse_string_option(
args, utils::cli::options::remote_mount_option, data);
if (res == exit_code::success) {
const auto parts = utils::string::split(data, ':', false);
if (parts.size() != 2) {
std::cerr << "Invalid syntax for host/port '-rm "
"host:port,--remote_mount host:port'"
<< std::endl;
res = exit_code::invalid_syntax;
} else {
unique_id = parts.at(0U) + ':' + parts.at(1U);
remote_host = parts.at(0U);
try {
remote_port = utils::string::to_uint16(parts.at(1U));
data_directory =
data_directory.empty()
? utils::path::combine(
app_config::default_data_directory(prov),
{
utils::string::replace_copy(unique_id, ':',
'_'),
})
: utils::path::absolute(data_directory);
} catch (const std::exception &e) {
std::cerr << (e.what() == nullptr ? "Unable to parse port"
: e.what())
<< std::endl;
res = exit_code::invalid_syntax;
}
}
}
}
} else if ((prov == provider_type::s3) || (prov == provider_type::sia) ||
(prov == provider_type::encrypt)) {
std::string data;
res = utils::cli::parse_string_option(
args, utils::cli::options::name_option, data);
if (res == exit_code::success) {
unique_id = utils::string::trim(data);
if (unique_id.empty()) {
if (prov == provider_type::sia) {
unique_id = "default";
} else {
} else if ((prov == provider_type::s3) || (prov == provider_type::sia) ||
(prov == provider_type::encrypt)) {
std::string data;
res = utils::cli::parse_string_option(
args, utils::cli::options::name_option, data);
if (res == exit_code::success) {
unique_id = utils::string::trim(data);
if (unique_id.empty()) {
std::cerr << "Configuration name for '"
<< app_config::get_provider_display_name(prov)
<< "' was not provided" << std::endl;
res = exit_code::invalid_syntax;
}
}
}
if (res == exit_code::success) {
data_directory =
data_directory.empty()
? utils::path::combine(app_config::default_data_directory(prov),
{unique_id})
: utils::path::absolute(data_directory);
}
}
}
int mount_result{};
if (res == exit_code::success) {
if (utils::cli::has_option(args, utils::cli::options::help_option)) {
cli::actions::help<repertory_drive>(args);
} else if (utils::cli::has_option(args,
utils::cli::options::version_option)) {
cli::actions::version<repertory_drive>(args);
} else {
res = exit_code::option_not_found;
for (std::size_t idx = 0U;
(res == exit_code::option_not_found) &&
(idx < utils::cli::options::option_list.size());
idx++) {
try {
res = cli::actions::perform_action(
utils::cli::options::option_list[idx], args, data_directory, prov,
unique_id, user, password);
} catch (const std::exception &ex) {
res = exit_code::exception;
} catch (...) {
res = exit_code::exception;
if (res == exit_code::success) {
data_directory =
data_directory.empty()
? utils::path::combine(
app_config::default_data_directory(prov), {unique_id})
: utils::path::absolute(data_directory);
}
}
}
if (res == exit_code::option_not_found) {
res = cli::actions::mount(args, data_directory, mount_result, prov,
remote_host, remote_port, unique_id);
int mount_result{};
if (res == exit_code::success) {
if (utils::cli::has_option(args, utils::cli::options::help_option)) {
cli::actions::help<repertory_drive>(args);
} else if (utils::cli::has_option(args,
utils::cli::options::version_option)) {
cli::actions::version<repertory_drive>(args);
} else {
res = exit_code::option_not_found;
for (std::size_t idx = 0U;
(res == exit_code::option_not_found) &&
(idx < utils::cli::options::option_list.size());
idx++) {
try {
res = cli::actions::perform_action(
utils::cli::options::option_list[idx], args, data_directory,
prov, unique_id, user, password);
} catch (const std::exception &ex) {
res = exit_code::exception;
} catch (...) {
res = exit_code::exception;
}
}
if (res == exit_code::option_not_found) {
res = cli::actions::mount(args, data_directory, mount_result, prov,
remote_host, remote_port, unique_id);
}
}
}
ret = ((res == exit_code::mount_result) ? mount_result
: static_cast<std::int32_t>(res));
}
auto ret =
((res == exit_code::mount_result) ? mount_result
: static_cast<std::int32_t>(res));
repertory::project_cleanup();
return ret;
}

View File

@@ -38,6 +38,7 @@
#include <boost/process/v1/args.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/io.hpp>
namespace bp1 = boost::process::v1;
namespace {
[[nodiscard]] auto decrypt(std::string_view data, std::string_view password)
@@ -113,6 +114,41 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
server_(server) {
REPERTORY_USES_FUNCTION_NAME();
#if defined(_WIN32)
if (config_->get_hidden()) {
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
}
#endif // defined(_WIN32)
if (not config_->get_launch_only()) {
#if defined(_WIN32)
system(
fmt::format(
R"(start "Repertory Management Portal" "http://127.0.0.1:{}/ui")",
config_->get_api_port())
.c_str());
#elif defined(__linux__)
system(fmt::format(R"(xdg-open "http://127.0.0.1:{}/ui")",
config_->get_api_port())
.c_str());
#else // error
build fails here
#endif
}
std::uint16_t port{};
if (not utils::get_next_available_port(config_->get_api_port(), port)) {
fmt::println("failed to detect if port is available|{}",
config_->get_api_port());
return;
}
if (port != config_->get_api_port()) {
fmt::println("failed to listen on port|{}|next available|{}",
config_->get_api_port(), port);
return;
}
server_->set_socket_options([](auto &&sock) {
#if defined(_WIN32)
int enable{1};
@@ -244,32 +280,6 @@ handlers::handlers(mgmt_app_config *config, httplib::Server *server)
#endif // !defined(_WIN32)
std::signal(SIGTERM, quit_handler);
#if defined(_WIN32)
system(fmt::format(
R"(start "Repertory Management Portal" "http://127.0.0.1:{}/ui")",
config_->get_api_port())
.c_str());
#elif defined(__linux__)
system(fmt::format(R"(xdg-open "http://127.0.0.1:{}/ui")",
config_->get_api_port())
.c_str());
#else // error
build fails here
#endif
std::uint16_t port{};
if (not utils::get_next_available_port(config_->get_api_port(), port)) {
fmt::println("failed to detect if port is available|{}",
config_->get_api_port());
return;
}
if (port != config_->get_api_port()) {
fmt::println("failed to listen on port|{}|next available|{}",
config_->get_api_port(), port);
return;
}
event_system::instance().start();
nonce_thread_ =
@@ -711,19 +721,35 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
recur_mutex_lock inst_lock(inst_mtx);
if (background) {
#if defined(_WIN32)
std::array<char, MAX_PATH + 1U> path{};
::GetSystemDirectoryA(path.data(), path.size());
args.insert(args.begin(), "--hidden");
args.insert(args.begin(), utils::path::combine(path.data(), {"cmd.exe"}));
args.insert(std::next(args.begin()), "/c");
args.insert(std::next(args.begin(), 2U), "start");
args.insert(std::next(args.begin(), 3U), "");
args.insert(std::next(args.begin(), 4U), "/MIN");
args.insert(std::next(args.begin(), 5U), repertory_binary_);
auto cmdline = fmt::format("{}{}{}", '"', repertory_binary_, '"');
for (const auto &arg : args) {
cmdline += " ";
if (arg.find_first_of(" \t") != std::string::npos) {
cmdline += fmt::format("{}{}{}", '"', arg, '"');
} else {
cmdline += arg;
}
}
STARTUPINFOA start_info{};
start_info.cb = sizeof(start_info);
PROCESS_INFORMATION proc_info{};
auto result = ::CreateProcessA(
nullptr, &cmdline[0U], nullptr, nullptr, FALSE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
nullptr, utils::path::get_parent_path(repertory_binary_).c_str(),
&start_info, &proc_info);
if (result) {
::CloseHandle(proc_info.hProcess);
::CloseHandle(proc_info.hThread);
}
#else // !defined(_WIN32)
args.insert(args.begin(), "-f");
args.insert(args.begin(), repertory_binary_);
#endif // defined(_WIN32)
args.insert(std::next(args.begin()), "-f");
std::vector<const char *> exec_args;
exec_args.reserve(args.size() + 1U);
@@ -732,10 +758,6 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
}
exec_args.push_back(nullptr);
#if defined(_WIN32)
_spawnv(_P_DETACH, exec_args.at(0U),
const_cast<char *const *>(exec_args.data()));
#else // !defined(_WIN32)
auto pid = fork();
if (pid < 0) {
exit(1);
@@ -769,10 +791,8 @@ auto handlers::launch_process(provider_type prov, std::string_view name,
return {};
}
boost::process::v1::ipstream out;
boost::process::v1::child proc(repertory_binary_,
boost::process::v1::args(args),
boost::process::v1::std_out > out);
bp1::ipstream out;
bp1::child proc(repertory_binary_, bp1::args(args), bp1::std_out > out);
std::string data;
std::string line;

View File

@@ -72,7 +72,8 @@ namespace {
} // namespace
namespace repertory::ui {
mgmt_app_config::mgmt_app_config() {
mgmt_app_config::mgmt_app_config(bool hidden, bool launch_only)
: hidden_(hidden), launch_only_(launch_only) {
REPERTORY_USES_FUNCTION_NAME();
auto config_file =
@@ -174,6 +175,12 @@ void mgmt_app_config::set_api_user(std::string_view api_user) {
save();
}
void mgmt_app_config::set_hidden(bool hidden) { hidden_ = hidden; }
void mgmt_app_config::set_launch_only(bool launch_only) {
launch_only_ = launch_only;
}
void mgmt_app_config::set_mount_location(provider_type prov,
std::string_view name,
std::string_view location) {

View File

@@ -62,11 +62,30 @@ if [ "${PROJECT_PRIVATE_KEY}" != "" ] && [ ! -f "./${PROJECT_OUT_FILE}.sig" ]; t
error_exit "failed to find file: ${PROJECT_OUT_FILE}.sig" 1
fi
cp -f ./${PROJECT_OUT_FILE} ${DEST_DIR} || error_exit "failed to deliver file: ${PROJECT_OUT_FILE}" 1
cp -f ./${PROJECT_OUT_FILE}.sha256 ${DEST_DIR} || error_exit "failed to deliver file: ${PROJECT_OUT_FILE}.sha256" 1
cp -f ./${PROJECT_OUT_FILE} ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_OUT_FILE}" 1
cp -f ./${PROJECT_OUT_FILE}.sha256 ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_OUT_FILE}.sha256" 1
if [ "${PROJECT_PRIVATE_KEY}" != "" ]; then
cp -f ./${PROJECT_OUT_FILE}.sig ${DEST_DIR} || error_exit "failed to deliver file: ${PROJECT_OUT_FILE}.sig" 1
cp -f ./${PROJECT_OUT_FILE}.sig ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_OUT_FILE}.sig" 1
fi
if [ "${PROJECT_IS_MINGW}" == "1" ] && [ -f "${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}_setup.exe" ]; then
cp -f "${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}_setup.exe" ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}" 1
cp -f "${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}_setup.exe.sha256" ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}.sha256" 1
if [ "${PROJECT_PRIVATE_KEY}" != "" ]; then
cp -f "${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}_setup.exe.sig" ${DEST_DIR} ||
error_exit "failed to deliver file: ${PROJECT_DIST_DIR}/${PROJECT_FILE_PART}.sig" 1
fi
fi
popd
error_exit "delivered ${PROJECT_FILE_PART}" 0

View File

@@ -26,10 +26,16 @@ if [ "${PROJECT_BUILD_ARCH}" == "aarch64" ]; then
docker build ${APP_VERSION_BUILD_ARGS} \
--platform linux/arm64 \
--build-arg NUM_JOBS=${NUM_JOBS} \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
--build-arg USERNAME=$(id -un) \
-t ${DOCKER_TAG} . || exit 1
else
docker build ${APP_VERSION_BUILD_ARGS} \
--build-arg NUM_JOBS=${NUM_JOBS} \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
--build-arg USERNAME=$(id -un) \
-t ${DOCKER_TAG} . || exit 1
fi
rm Dockerfile

View File

@@ -292,6 +292,8 @@ if [ "${PROJECT_IS_MINGW}" == "1" ] && [ "${PROJECT_IS_MINGW_UNIX}" != "1" ]; th
MSYS=winsymlinks:nativestrict
fi
PROJECT_ENABLE_INNOSETUP=1
export MSYS
export NUM_JOBS
export OPENSSL_ROOT_DIR

View File

@@ -26,6 +26,7 @@ PROJECT_CLEANUP[EXPAT]="3rd_party/mingw64/expat-*"
PROJECT_CLEANUP[GCC]="3rd_party/mingw64/gcc-*"
PROJECT_CLEANUP[ICU]="3rd_party/mingw64/icu-release-*"
PROJECT_CLEANUP[JSON]="3rd_party/json-*"
PROJECT_CLEANUP[INNOSETUP]="3rd_party/mingw64/innosetup-*"
PROJECT_CLEANUP[LIBBITCOIN_SYSTEM_ON]="3rd_party/boost_${PROJECT_VERSIONS[BOOST_MAJOR]}_${PROJECT_VERSIONS[BOOST_MINOR]}_*"
PROJECT_CLEANUP[LIBSODIUM]="3rd_party/libsodium-*:3rd_party/libsodium*"
PROJECT_CLEANUP[MINGW]="3rd_party/mingw64/mingw-w64-*"
@@ -52,6 +53,8 @@ PROJECT_DOWNLOADS[GCC]="https://mirrorservice.org/sites/sourceware.org/pub/gcc/r
PROJECT_DOWNLOADS[GTEST]="https://github.com/google/googletest/archive/refs/tags/v${PROJECT_VERSIONS[GTEST]}.tar.gz;googletest-${PROJECT_VERSIONS[GTEST]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[ICU]="https://github.com/unicode-org/icu/archive/refs/tags/release-${PROJECT_VERSIONS[ICU]}.tar.gz;icu-release-${PROJECT_VERSIONS[ICU]}.tar.gz;3rd_party/mingw64"
PROJECT_DOWNLOADS[JSON]="https://github.com/nlohmann/json/archive/refs/tags/v${PROJECT_VERSIONS[JSON]}.tar.gz;json-${PROJECT_VERSIONS[JSON]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[INNOSETUP]="https://files.jrsoftware.org/is/6/innosetup-${PROJECT_VERSIONS[INNOSETUP]}.exe;innosetup-${PROJECT_VERSIONS[INNOSETUP]}.exe;3rd_party/mingw64"
PROJECT_DOWNLOADS[WINFSP]="https://github.com/winfsp/winfsp/releases/download/v${PROJECT_VERSIONS[WINFSP2]}/winfsp-${PROJECT_VERSIONS[WINFSP]}.msi;winfsp-${PROJECT_VERSIONS[WINFSP]}.msi;3rd_party"
PROJECT_DOWNLOADS[LIBSODIUM]="https://github.com/jedisct1/libsodium/archive/refs/tags/${PROJECT_VERSIONS[LIBSODIUM]}-RELEASE.tar.gz;libsodium-${PROJECT_VERSIONS[LIBSODIUM]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[MINGW]="https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/mingw-w64-v${PROJECT_VERSIONS[MINGW]}.tar.bz2;;mingw-w64-v${PROJECT_VERSIONS[MINGW]}.tar.bz2;3rd_party/mingw64"
PROJECT_DOWNLOADS[OPENSSL]="https://github.com/openssl/openssl/releases/download/openssl-${PROJECT_VERSIONS[OPENSSL]}/openssl-${PROJECT_VERSIONS[OPENSSL]}.tar.gz;openssl-${PROJECT_VERSIONS[OPENSSL]}.tar.gz;3rd_party"

View File

@@ -43,6 +43,10 @@ make -j${CMAKE_BUILD_PARALLEL_LEVEL} || exit 1
popd
popd
if [ -f "${PROJECT_SOURCE_DIR}/LICENSE.md" ]; then
rsync -av --progress "${PROJECT_SOURCE_DIR}/LICENSE.md" "${PROJECT_DIST_DIR}/"
fi
if [ "${PROJECT_IS_MINGW}" != "1" ] && [ "${PROJECT_REQUIRE_ALPINE}" == "ON" ]; then
rsync -av --progress /usr/share/icu/74.2/ "${PROJECT_DIST_DIR}/icu/"
fi

View File

@@ -35,6 +35,16 @@ fi
if [ -f "${PROJECT_OUT_FILE}.sig" ]; then
rm -f "${PROJECT_OUT_FILE}.sig" || error_exit "failed to delete file: ${PROJECT_OUT_FILE}.sig" 1
fi
if [ -f "${PROJECT_FILE_PART}_setup.exe" ]; then
rm -f "${PROJECT_FILE_PART}_setup.exe" || error_exit "failed to delete file: ${PROJECT_FILE_PART}_setup.exe" 1
fi
if [ -f "${PROJECT_FILE_PART}_setup.exe.sha256" ]; then
rm -f "${PROJECT_FILE_PART}_setup.exe.sha256" || error_exit "failed to delete file: ${PROJECT_FILE_PART}_setup.exe.sha256" 1
fi
if [ -f "${PROJECT_FILE_PART}_setup.exe.sig" ]; then
rm -f "${PROJECT_FILE_PART}_setup.exe.sig" || error_exit "failed to delete file: ${PROJECT_FILE_PART}_setup.exe.sig" 1
fi
popd
rsync -av --progress ${PROJECT_DIST_DIR}/ ${TEMP_DIR}/${PROJECT_NAME}/ || error_exit "failed to rsync" 1
@@ -63,4 +73,23 @@ tar cvzf "${PROJECT_OUT_FILE}" -C ${TEMP_DIR} . || error_exit "failed to create
create_file_validations "${PROJECT_OUT_FILE}"
popd
if [ "${PROJECT_IS_MINGW}" == "1" ] && [ -f "${PROJECT_DIST_DIR}/../${PROJECT_NAME}.iss" ]; then
cp -f "${PROJECT_DIST_DIR}/../${PROJECT_NAME}.iss" "${TEMP_DIR}/${PROJECT_NAME}.iss"
rsync -av --progress --delete ${PROJECT_SOURCE_DIR}/support/3rd_party/*.msi ${TEMP_DIR}/3rd_party/
pushd "${TEMP_DIR}"
if [ "${PROJECT_IS_MINGW_UNIX}" == "1" ]; then
wine64 "c:/Program Files (x86)/Inno Setup 6/iscc.exe" "${PROJECT_NAME}.iss" || exit 1
else
iscc "${PROJECT_NAME}.iss" || exit 1
fi
pushd "Output"
create_file_validations "${PROJECT_FILE_PART}_setup.exe"
cp -f * "${PROJECT_DIST_DIR}/"
popd
popd
fi
error_exit "created package ${PROJECT_FILE_PART}" 0

View File

@@ -16,6 +16,7 @@ PROJECT_VERSIONS[EXPAT2]="2_7_1"
PROJECT_VERSIONS[GCC]="15.1.0"
PROJECT_VERSIONS[GTEST]="1.17.0"
PROJECT_VERSIONS[ICU]="76-1"
PROJECT_VERSIONS[INNOSETUP]="6.4.3"
PROJECT_VERSIONS[JSON]="3.12.0"
PROJECT_VERSIONS[LIBSODIUM]="1.0.20"
PROJECT_VERSIONS[MINGW]="13.0.0"
@@ -27,5 +28,7 @@ PROJECT_VERSIONS[SPDLOG]="1.15.3"
PROJECT_VERSIONS[SQLITE]="3500300"
PROJECT_VERSIONS[SQLITE2]="3.50.3"
PROJECT_VERSIONS[STDUUID]="1.2.3"
PROJECT_VERSIONS[WINFSP]="2.1.25156"
PROJECT_VERSIONS[WINFSP2]="2.1"
PROJECT_VERSIONS[ZLIB]="1.3.1"
export PROJECT_VERSIONS

View File

@@ -1 +1 @@
4b92eb0c06d10683f7447ce9406cb97cd4b453be18d7279320f7b2f025c10187 json-3.12.0.tar.gz
4b92eb0c06d10683f7447ce9406cb97cd4b453be18d7279320f7b2f025c10187 *json-3.12.0.tar.gz

Binary file not shown.

View File

@@ -0,0 +1 @@
f3c42116542c4cc57263c5ba6c4feabfc49fe771f2f98a79d2f7628b8762723b *innosetup-6.4.3.exe

BIN
support/3rd_party/winfsp-2.1.25156.msi vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
073a70e00f77423e34bed98b86e600def93393ba5822204fac57a29324db9f7a *winfsp-2.1.25156.msi

View File

@@ -100,7 +100,7 @@ Map<String, dynamic> createDefaultSettings(String mountType) {
'ApiPort': 9980,
'HostNameOrIp': 'localhost',
},
'SiaConfig': {'Bucket': 'default'},
'SiaConfig': {'Bucket': ''},
};
}

View File

@@ -212,7 +212,7 @@ class _AddMountScreenState extends State<AddMountScreen> {
if (_mountType == 'Remote') {
_mountNameController.text = 'remote';
} else if (changed) {
_mountNameController.text = mountType == 'Sia' ? 'default' : '';
_mountNameController.text = '';
}
_mount = (_mountNameController.text.isEmpty)

View File

@@ -50,7 +50,7 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0
flutter_lints: ^6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec