VirtualBox

Changeset 90268 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jul 21, 2021 1:51:37 AM (4 years ago)
Author:
vboxsync
Message:

VBoxManage: cloud machine info - implement, use for cloud machine list -l.
Probably needs ability to select machine by name for better UX. bugref:10065.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageCloudMachine.cpp

    r90235 r90268  
    2424#include <VBox/com/errorprint.h>
    2525
     26#include <algorithm>
     27#include <vector>
     28
    2629
    2730static int selectCloudProvider(ComPtr<ICloudProvider> &pProvider,
     
    3639static RTEXITCODE listCloudMachinesImpl(HandlerArg *a, int iFirst,
    3740                                        const ComPtr<ICloudProfile> &pProfile);
     41static RTEXITCODE handleCloudMachineInfo(HandlerArg *a, int iFirst,
     42                                          const ComPtr<ICloudProfile> &pProfile);
     43
     44static HRESULT printMachineInfo(const ComPtr<ICloudMachine> &pMachine);
     45static HRESULT printFormValue(const ComPtr<IFormValue> &pValue);
    3846
    3947
     
    208216
    209217
     218static HRESULT
     219getMachineById(ComPtr<ICloudMachine> &pMachineOut,
     220               const ComPtr<ICloudProfile> &pProfile,
     221               const char *pcszStrId)
     222{
     223    HRESULT hrc;
     224
     225    ComPtr<ICloudClient> pCloudClient;
     226    CHECK_ERROR2_RET(hrc, pProfile,
     227        CreateCloudClient(pCloudClient.asOutParam()), hrc);
     228
     229    ComPtr<ICloudMachine> pMachine;
     230    CHECK_ERROR2_RET(hrc, pCloudClient,
     231        GetCloudMachine(com::Bstr(pcszStrId).raw(),
     232                        pMachine.asOutParam()), hrc);
     233
     234    ComPtr<IProgress> pRefreshProgress;
     235    CHECK_ERROR2_RET(hrc, pMachine,
     236        Refresh(pRefreshProgress.asOutParam()), hrc);
     237
     238    hrc = showProgress(pRefreshProgress, SHOW_PROGRESS_NONE);
     239    if (FAILED(hrc))
     240        return hrc;
     241
     242    pMachineOut = pMachine;
     243    return S_OK;
     244}
     245
     246
    210247/*
    211248 * RTGETOPTINIT_FLAGS_NO_STD_OPTS recognizes both --help and --version
     
    266303        {
    267304            case kMachine_Info:
    268                 return RTMsgErrorExit(RTEXITCODE_FAILURE,
    269                                       "cloud machine info: not yet implemented");
     305                return handleCloudMachineInfo(a, OptState.iNext, pProfile);
    270306
    271307            case kMachine_List:
     
    335371    {
    336372        { "--long",         'l',                    RTGETOPT_REQ_NOTHING },
    337         { "--short",        's',                    RTGETOPT_REQ_NOTHING },
     373        { "--sort",         's',                    RTGETOPT_REQ_NOTHING },
    338374          CLOUD_MACHINE_RTGETOPTDEF_HELP
    339375    };
    340376
    341     enum kFormatEnum
    342     {
    343         kFormat_Default,
    344         kFormat_Short,
    345         kFormat_Long
    346     };
     377    enum kFormatEnum { kFormat_Short, kFormat_Long };
     378    kFormatEnum enmFormat = kFormat_Short;
     379
     380    enum kSortOrderEnum { kSortOrder_None, kSortOrder_Name, kSortOrder_Id };
     381    kSortOrderEnum enmSortOrder = kSortOrder_None;
    347382
    348383    HRESULT hrc;
    349384    int rc;
    350 
    351     kFormatEnum enmFormat = kFormat_Default;
    352385
    353386
     
    371404
    372405            case 's':
    373                 enmFormat = kFormat_Short;
     406                /** @todo optional argument to select the sort key? */
     407                enmSortOrder = kSortOrder_Name;
    374408                break;
    375409
     
    407441            RTEXITCODE_FAILURE);
    408442
    409     for (size_t i = 0; i < aMachines.size(); ++i)
    410     {
    411         const ComPtr<ICloudMachine> pMachine = aMachines[i];
    412 
    413         com::Bstr bstrId;
     443    const size_t cMachines = aMachines.size();
     444    if (cMachines == 0)
     445        return RTEXITCODE_SUCCESS;
     446
     447
     448    /*
     449     * Get names/ids that we need for the short output and to sort the
     450     * list.
     451     */
     452    std::vector<ComPtr<ICloudMachine> > vMachines(cMachines);
     453    std::vector<com::Bstr> vBstrNames(cMachines);
     454    std::vector<com::Bstr> vBstrIds(cMachines);
     455    for (size_t i = 0; i < cMachines; ++i)
     456    {
     457        vMachines[i] = aMachines[i];
     458
     459        CHECK_ERROR2_RET(hrc, vMachines[i],
     460            COMGETTER(Name)(vBstrNames[i].asOutParam()),
     461                RTEXITCODE_FAILURE);
     462
     463        CHECK_ERROR2_RET(hrc, vMachines[i],
     464            COMGETTER(Id)(vBstrIds[i].asOutParam()),
     465                RTEXITCODE_FAILURE);
     466    }
     467
     468
     469    /*
     470     * Sort the list if necessary.  The sort is indirect via an
     471     * intermediate array of indexes.
     472     */
     473    std::vector<size_t> vIndexes(cMachines);
     474    for (size_t i = 0; i < cMachines; ++i)
     475        vIndexes[i] = i;
     476
     477    if (enmSortOrder != kSortOrder_None)
     478    {
     479        struct SortBy {
     480            const std::vector<com::Bstr> &ks;
     481            SortBy(const std::vector<com::Bstr> &aKeys) : ks(aKeys) {}
     482            bool operator() (size_t l, size_t r) { return ks[l] < ks[r]; }
     483        };
     484
     485        std::sort(vIndexes.begin(), vIndexes.end(),
     486                  SortBy(enmSortOrder == kSortOrder_Name
     487                         ? vBstrNames : vBstrIds));
     488    }
     489
     490
     491    if (enmFormat == kFormat_Short)
     492    {
     493        for (size_t i = 0; i < cMachines; ++i)
     494        {
     495            const size_t idx = vIndexes[i];
     496            const com::Bstr &bstrId = vBstrIds[idx];
     497            const com::Bstr &bstrName = vBstrNames[idx];
     498
     499            RTPrintf("%ls %ls\n", bstrId.raw(), bstrName.raw());
     500        }
     501    }
     502    else // kFormat_Long
     503    {
     504        for (size_t i = 0; i < cMachines; ++i)
     505        {
     506            const size_t idx = vIndexes[i];
     507            const ComPtr<ICloudMachine> &pMachine = vMachines[idx];
     508
     509            if (i != 0)
     510                RTPrintf("\n");
     511            printMachineInfo(pMachine);
     512        }
     513    }
     514
     515    return RTEXITCODE_SUCCESS;
     516}
     517
     518
     519static RTEXITCODE
     520handleCloudMachineInfo(HandlerArg *a, int iFirst,
     521                       const ComPtr<ICloudProfile> &pProfile)
     522{
     523    HRESULT hrc;
     524
     525    if (a->argc == iFirst)
     526    {
     527        return RTMsgErrorExit(RTEXITCODE_SYNTAX,
     528                   "cloud machine info: machine id required\n"
     529                   "Try '--help' for more information.");
     530    }
     531
     532    for (int i = iFirst; i < a->argc; ++i)
     533    {
     534        ComPtr<ICloudMachine> pMachine;
     535        hrc = getMachineById(pMachine, pProfile, a->argv[i]);
     536        if (FAILED(hrc))
     537            return RTEXITCODE_FAILURE;
     538
     539        hrc = printMachineInfo(pMachine);
     540        if (FAILED(hrc))
     541            return RTEXITCODE_FAILURE;
     542    }
     543
     544    return RTEXITCODE_SUCCESS;
     545}
     546
     547
     548static HRESULT
     549printMachineInfo(const ComPtr<ICloudMachine> &pMachine)
     550{
     551    HRESULT hrc;
     552
     553    /*
     554     * Check if the machine is accessible and print the error
     555     * message if not.
     556     */
     557    BOOL fAccessible = FALSE;
     558    CHECK_ERROR2_RET(hrc, pMachine,
     559        COMGETTER(Accessible)(&fAccessible), hrc);
     560
     561    if (!fAccessible)
     562    {
     563        RTMsgError("machine is not accessible"); // XXX: Id?
     564
     565        ComPtr<IVirtualBoxErrorInfo> pErrorInfo;
    414566        CHECK_ERROR2_RET(hrc, pMachine,
    415             COMGETTER(Id)(bstrId.asOutParam()),
    416                 RTEXITCODE_FAILURE);
    417 
    418         com::Bstr bstrName;
    419         CHECK_ERROR2_RET(hrc, pMachine,
    420             COMGETTER(Name)(bstrName.asOutParam()),
    421                 RTEXITCODE_FAILURE);
    422 
    423         RTPrintf("%ls %ls\n", bstrId.raw(), bstrName.raw());
    424     }
    425 
    426     return RTEXITCODE_SUCCESS;
    427 }
     567            COMGETTER(AccessError)(pErrorInfo.asOutParam()), hrc);
     568
     569        while (!pErrorInfo.isNull())
     570        {
     571            com::Bstr bstrText;
     572            CHECK_ERROR2_RET(hrc, pErrorInfo,
     573                COMGETTER(Text)(bstrText.asOutParam()), hrc);
     574            RTStrmPrintf(g_pStdErr, "%ls\n", bstrText.raw());
     575
     576            CHECK_ERROR2_RET(hrc, pErrorInfo,
     577                COMGETTER(Next)(pErrorInfo.asOutParam()), hrc);
     578        }
     579
     580        return E_FAIL;
     581    }
     582
     583
     584    /*
     585     * The machine seems to be ok, print its details.
     586     */
     587    ComPtr<IForm> pDetails;
     588    CHECK_ERROR2_RET(hrc, pMachine,
     589        GetDetailsForm(pDetails.asOutParam()), hrc);
     590
     591    if (RT_UNLIKELY(pDetails.isNull()))
     592    {
     593        RTMsgError("null details"); /* better error message? */
     594        return E_FAIL;
     595    }
     596
     597    com::SafeIfaceArray<IFormValue> aValues;
     598    CHECK_ERROR2_RET(hrc, pDetails,
     599        COMGETTER(Values)(ComSafeArrayAsOutParam(aValues)), hrc);
     600    for (size_t i = 0; i < aValues.size(); ++i)
     601    {
     602        hrc = printFormValue(aValues[i]);
     603        if (FAILED(hrc))
     604            return hrc;
     605    }
     606
     607    return S_OK;
     608}
     609
     610
     611static HRESULT
     612printFormValue(const ComPtr<IFormValue> &pValue)
     613{
     614    HRESULT hrc;
     615
     616    BOOL fVisible = FALSE;
     617    CHECK_ERROR2_RET(hrc, pValue,
     618        COMGETTER(Visible)(&fVisible), hrc);
     619    if (!fVisible)
     620        return S_OK;
     621
     622
     623    com::Bstr bstrLabel;
     624    CHECK_ERROR2_RET(hrc, pValue,
     625        COMGETTER(Label)(bstrLabel.asOutParam()), hrc);
     626
     627    FormValueType_T enmType;
     628    CHECK_ERROR2_RET(hrc, pValue,
     629        COMGETTER(Type)(&enmType), hrc);
     630
     631    switch (enmType)
     632    {
     633        case FormValueType_Boolean:
     634        {
     635            ComPtr<IBooleanFormValue> pBoolValue;
     636            hrc = pValue.queryInterfaceTo(pBoolValue.asOutParam());
     637            if (FAILED(hrc))
     638            {
     639                RTStrmPrintf(g_pStdErr,
     640                    "%ls: unable to obtain boolean value\n", bstrLabel.raw());
     641                break;
     642            }
     643
     644            BOOL fSelected;
     645            hrc = pBoolValue->GetSelected(&fSelected);
     646            if (FAILED(hrc))
     647            {
     648                RTStrmPrintf(g_pStdOut,
     649                    "%ls: %Rhra", bstrLabel.raw(), hrc);
     650                break;
     651            }
     652
     653            RTPrintf("%ls: %RTbool\n",
     654                bstrLabel.raw(), RT_BOOL(fSelected));
     655            break;
     656        }
     657
     658        case FormValueType_String:
     659        {
     660            ComPtr<IStringFormValue> pStrValue;
     661            hrc = pValue.queryInterfaceTo(pStrValue.asOutParam());
     662            if (FAILED(hrc))
     663            {
     664                RTStrmPrintf(g_pStdErr,
     665                    "%ls: unable to obtain string value\n", bstrLabel.raw());
     666                break;
     667            }
     668
     669            /*
     670             * GUI hack: if clipboard string is set, it contains
     671             * untruncated long value, usually full OCID, so check it
     672             * first.  Make this selectable with an option?
     673             */
     674            com::Bstr bstrValue;
     675            hrc = pStrValue->GetClipboardString(bstrValue.asOutParam());
     676            if (FAILED(hrc))
     677            {
     678                RTStrmPrintf(g_pStdOut,
     679                    "%ls: %Rhra", bstrLabel.raw(), hrc);
     680                break;
     681            }
     682
     683            if (bstrValue.isEmpty())
     684            {
     685                hrc = pStrValue->GetString(bstrValue.asOutParam());
     686                if (FAILED(hrc))
     687                {
     688                    RTStrmPrintf(g_pStdOut,
     689                        "%ls: %Rhra", bstrLabel.raw(), hrc);
     690                    break;
     691                }
     692            }
     693
     694            RTPrintf("%ls: %ls\n",
     695                bstrLabel.raw(), bstrValue.raw());
     696            break;
     697        }
     698
     699        case FormValueType_RangedInteger:
     700            RTStrmPrintf(g_pStdOut, "integer\n");
     701            break;
     702
     703        case FormValueType_Choice:
     704            RTStrmPrintf(g_pStdOut, "choice\n");
     705            break;
     706
     707        default:
     708            RTStrmPrintf(g_pStdOut, "unknown value type %RU32\n", enmType);
     709            break;
     710    }
     711
     712    return S_OK;
     713}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette