diff --git a/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj b/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj
index 043db32e..99e7f53b 100644
--- a/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj
+++ b/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj
@@ -111,6 +111,7 @@ if EXIST "$(SharedIdb)" xcopy /Y /F "$(SharedIdb)" "$(IntDir)"
+
diff --git a/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj.filters b/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj.filters
index 6b835077..64af04d3 100644
--- a/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj.filters
+++ b/DistroLauncher-Tests/DistroLauncher-Tests/DistroLauncher-Tests.vcxproj.filters
@@ -104,6 +104,7 @@
+
@@ -116,4 +117,4 @@
{c6954f59-9f21-4dd8-a33d-693e8797d882}
-
+
\ No newline at end of file
diff --git a/DistroLauncher-Tests/DistroLauncher-Tests/upgrade_policy_tests.cpp b/DistroLauncher-Tests/DistroLauncher-Tests/upgrade_policy_tests.cpp
index 7c2d9abc..bdaf07a3 100644
--- a/DistroLauncher-Tests/DistroLauncher-Tests/upgrade_policy_tests.cpp
+++ b/DistroLauncher-Tests/DistroLauncher-Tests/upgrade_policy_tests.cpp
@@ -20,37 +20,37 @@
TEST(UpgradePolicyTests, StringParsing)
{
- ASSERT_FALSE(internal::starts_with(L"", L"hello"));
- ASSERT_FALSE(internal::starts_with(L"he", L"hello"));
- ASSERT_TRUE(internal::starts_with(L"hello", L"hello"));
- ASSERT_TRUE(internal::starts_with(L"hello, world!", L"hello"));
- ASSERT_FALSE(internal::starts_with(L"cheers, world!", L"hello"));
- ASSERT_FALSE(internal::starts_with(L"HELLO", L"hello"));
+ ASSERT_FALSE(starts_with(L"", L"hello"));
+ ASSERT_FALSE(starts_with(L"he", L"hello"));
+ ASSERT_TRUE(starts_with(L"hello", L"hello"));
+ ASSERT_TRUE(starts_with(L"hello, world!", L"hello"));
+ ASSERT_FALSE(starts_with(L"cheers, world!", L"hello"));
+ ASSERT_FALSE(starts_with(L"HELLO", L"hello"));
- ASSERT_FALSE(internal::ends_with(L"", L"world!"));
- ASSERT_FALSE(internal::ends_with(L"d!", L"world!"));
- ASSERT_TRUE(internal::ends_with(L"world!", L"world!"));
- ASSERT_TRUE(internal::ends_with(L"hello, world!", L"world!"));
- ASSERT_FALSE(internal::ends_with(L"hello, world?", L"world!"));
- ASSERT_FALSE(internal::ends_with(L"this string is completely diferent", L"world!"));
- ASSERT_FALSE(internal::ends_with(L"HELLO", L"hello"));
+ ASSERT_FALSE(ends_with(L"", L"world!"));
+ ASSERT_FALSE(ends_with(L"d!", L"world!"));
+ ASSERT_TRUE(ends_with(L"world!", L"world!"));
+ ASSERT_TRUE(ends_with(L"hello, world!", L"world!"));
+ ASSERT_FALSE(ends_with(L"hello, world?", L"world!"));
+ ASSERT_FALSE(ends_with(L"this string is completely diferent", L"world!"));
+ ASSERT_FALSE(ends_with(L"HELLO", L"hello"));
- ASSERT_FALSE(internal::starts_with(L"", L"Ubuntu"));
- ASSERT_TRUE(internal::starts_with(L"Ubuntu 22.04.1 LTS", L"Ubuntu"));
- ASSERT_TRUE(internal::ends_with(L"Ubuntu 22.04.1 LTS", L"LTS"));
+ ASSERT_FALSE(starts_with(L"", L"Ubuntu"));
+ ASSERT_TRUE(starts_with(L"Ubuntu 22.04.1 LTS", L"Ubuntu"));
+ ASSERT_TRUE(ends_with(L"Ubuntu 22.04.1 LTS", L"LTS"));
}
TEST(UpgradePolicyTests, Concat)
{
// Checking default functionality
std::wstring dog = L"dog";
- auto example = internal::concat(L"The", L" quick brown fox", L" jumps over the lazy ", std::quoted(dog), '.');
+ auto example = concat(L"The", L" quick brown fox", L" jumps over the lazy ", std::quoted(dog), '.');
ASSERT_EQ(example, LR"(The quick brown fox jumps over the lazy "dog".)");
// Checking quote nesting
- auto nested = internal::concat(L"\n{\n ", std::quoted(L"name"), L": ", std::quoted(L"example"), L",\n ",
- std::quoted(L"value"), L": ", std::quoted(example), L"\n}\n");
+ auto nested = concat(L"\n{\n ", std::quoted(L"name"), L": ", std::quoted(L"example"), L",\n ",
+ std::quoted(L"value"), L": ", std::quoted(example), L"\n}\n");
auto expected = LR"(
{
"name": "example",
@@ -61,7 +61,6 @@ TEST(UpgradePolicyTests, Concat)
// Checking path auto-quoting
std::filesystem::path example_file{L"/home/fox/documents/example.json"};
- auto with_path =
- internal::concat(L"diff ", example_file, L" ", example_file.wstring()); // Only first one to be quoted
+ auto with_path = concat(L"diff ", example_file, L" ", example_file.wstring()); // Only first one to be quoted
ASSERT_EQ(with_path, LR"(diff "/home/fox/documents/example.json" /home/fox/documents/example.json)");
}
diff --git a/DistroLauncher/DistroLauncher.vcxproj b/DistroLauncher/DistroLauncher.vcxproj
index fd5bb906..fd57d4d7 100644
--- a/DistroLauncher/DistroLauncher.vcxproj
+++ b/DistroLauncher/DistroLauncher.vcxproj
@@ -138,6 +138,7 @@
+
diff --git a/DistroLauncher/WSLInfo.cpp b/DistroLauncher/WSLInfo.cpp
index b624c98b..8a273e91 100644
--- a/DistroLauncher/WSLInfo.cpp
+++ b/DistroLauncher/WSLInfo.cpp
@@ -137,6 +137,28 @@ namespace Oobe::internal
return ini_find_value(wslConf, L"boot", L"command", L"/usr/libexec/wsl-systemd");
}
+ bool hasSnap(std::wstring_view name)
+ {
+ namespace fs = std::filesystem;
+ const auto path = Oobe::WindowsPath(fs::path{L"/var/lib/snapd/snaps/"});
+ return find_file_if(path, [name](const auto& entry) {
+ return fs::is_regular_file(entry) && starts_with({entry.path().filename().wstring()}, name);
+ });
+ }
+
+ bool hasUdiSnap()
+ {
+ static bool hasUdi = hasSnap(L"ubuntu-desktop-installer");
+
+ return hasUdi;
+ }
+
+ bool hasSubiquitySnap()
+ {
+ static bool hasSubiquity = hasSnap(L"subiquity");
+ return hasSubiquity;
+ }
+
} // namespace Oobe::internal
// This was kept under Helpers namespace to avoid touching OOBE.cpp/h files.
@@ -145,8 +167,17 @@ namespace Helpers
{
bool WslGraphicsSupported()
{
+ // It's possible that we have only Subiquity instead of the Ubuntu-Desktop-Installer snap.
+ if (!Oobe::internal::hasUdiSnap()) {
+ return false;
+ }
+
+ if (!Oobe::internal::isWslgEnabled()) {
+ return false;
+ }
+
// Could WSL 3 or greater exist in the future?
- return (Oobe::internal::isWslgEnabled() && Oobe::internal::WslGetDistroSubsystemVersion() > 1);
+ return Oobe::internal::WslGetDistroSubsystemVersion() > 1;
}
} // namespace Helpers.
diff --git a/DistroLauncher/WSLInfo.h b/DistroLauncher/WSLInfo.h
index b3d5cbd1..44b29cf1 100644
--- a/DistroLauncher/WSLInfo.h
+++ b/DistroLauncher/WSLInfo.h
@@ -49,6 +49,15 @@ namespace Oobe::internal
///
bool isLocalhostForwardingEnabled(const std::filesystem::path& wslConfig);
+ /// Returns true if the ubuntu-desktop-installer snap is found inside the rootfs.
+ /// It's possible that we have only Subiquity or none instead.
+ /// That's meant to be called during setup, where filesystem errors are less likely to happen.
+ bool hasUdiSnap();
+
+ /// Returns true if the subiquity snap is found inside the rootfs.
+ /// It's possible that we have the ubuntu-desktop-installer or none instead.
+ /// That's meant to be called during setup, where filesystem errors are less likely to happen.
+ bool hasSubiquitySnap();
}
namespace Oobe
diff --git a/DistroLauncher/algorithms.h b/DistroLauncher/algorithms.h
new file mode 100644
index 00000000..f7302af1
--- /dev/null
+++ b/DistroLauncher/algorithms.h
@@ -0,0 +1,70 @@
+#pragma once
+/*
+ * Copyright (C) 2022 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+// Common algorithms to be used everywhere in the launcher project with style resembling the std ones.
+
+template
+bool starts_with(const std::basic_string_view tested, const std::basic_string_view start)
+{
+ if (tested.size() < start.size()) {
+ return false;
+ }
+ auto mismatch = std::mismatch(start.cbegin(), start.cend(), tested.cbegin());
+ return mismatch.first == start.cend();
+}
+
+template
+bool starts_with(CharT const (&tested)[TestedSize], CharT const (&start)[StartSize])
+{
+ return starts_with(std::basic_string_view{tested}, std::basic_string_view{start});
+}
+
+template
+bool ends_with(const std::basic_string_view tested, const std::basic_string_view end)
+{
+ if (tested.size() < end.size()) {
+ return false;
+ }
+ auto mismatch = std::mismatch(end.crbegin(), end.crend(), tested.crbegin());
+ return mismatch.first == end.crend();
+}
+
+template
+bool ends_with(const CharT (&tested)[TestedSize], const CharT (&end)[EndSize])
+{
+ return ends_with(std::basic_string_view{tested}, std::basic_string_view{end});
+}
+
+template std::wstring concat(Args&&... args)
+{
+ std::wstringstream buffer;
+ (buffer << ... << std::forward(args));
+ return buffer.str();
+}
+
+template bool find_file_if(const std::filesystem::path& directory, Pred&& pred)
+{
+ namespace fs = std::filesystem;
+ std::error_code error;
+ assert(fs::is_directory(directory));
+ auto listing = fs::directory_iterator{directory, error};
+ if (error) {
+ return false;
+ }
+ return std::find_if(begin(listing), end(listing), std::forward(pred)) != end(listing);
+}
diff --git a/DistroLauncher/stdafx.h b/DistroLauncher/stdafx.h
index 825bc8f1..836f80cd 100644
--- a/DistroLauncher/stdafx.h
+++ b/DistroLauncher/stdafx.h
@@ -41,6 +41,7 @@
#include
#include
#include
+#include "algorithms.h"
#include "expected.hpp"
#include "not_null.h"
#include "WslApiLoader.h"
diff --git a/DistroLauncher/upgrade_policy.cpp b/DistroLauncher/upgrade_policy.cpp
index 118ed70d..bb892217 100644
--- a/DistroLauncher/upgrade_policy.cpp
+++ b/DistroLauncher/upgrade_policy.cpp
@@ -20,31 +20,13 @@
namespace internal
{
- bool starts_with(const std::wstring_view tested, const std::wstring_view start)
- {
- if (tested.size() < start.size()) {
- return false;
- }
- auto mismatch = std::mismatch(start.cbegin(), start.cend(), tested.cbegin());
- return mismatch.first == start.cend();
- }
-
- bool ends_with(const std::wstring_view tested, const std::wstring_view end)
- {
- if (tested.size() < end.size()) {
- return false;
- }
- auto mismatch = std::mismatch(end.crbegin(), end.crend(), tested.crbegin());
- return mismatch.first == end.crend();
- }
-
std::wstring GetUpgradePolicy()
{
std::wstring_view name = DistributionInfo::Name;
if (name == L"Ubuntu") {
return L"lts";
}
- if (starts_with(name, L"Ubuntu") && ends_with(name, L"LTS")) {
+ if (starts_with(name, {L"Ubuntu"}) && ends_with(name, {L"LTS"})) {
return L"never";
}
return L"normal";
diff --git a/DistroLauncher/upgrade_policy.h b/DistroLauncher/upgrade_policy.h
index e6eea1f1..6cc24289 100644
--- a/DistroLauncher/upgrade_policy.h
+++ b/DistroLauncher/upgrade_policy.h
@@ -19,18 +19,8 @@
namespace internal
{
- bool starts_with(std::wstring_view tested, std::wstring_view start);
- bool ends_with(std::wstring_view tested, std::wstring_view end);
-
std::wstring GetUpgradePolicy();
- template std::wstring concat(Args&&... args)
- {
- std::wstringstream buffer;
- (buffer << ... << std::forward(args));
- return buffer.str();
- }
-
void SetDefaultUpgradePolicyImpl();
}