airsdk / Adobe-Runtime-Support

Report, track and discuss issues in Adobe AIR. Monitored by Adobe - and HARMAN - and maintained by the AIR community.
206 stars 11 forks source link

Command Line Utility Output #461

Open marchbold opened 4 years ago

marchbold commented 4 years ago

Feature

Recently we have been discussing the development of an AIR package manager to simplify handling dependencies on AIR applications.

To aid this development it would be helpful to be able to develop command line utilities in AS3. These utilities would not have any window or ui, simply be commands run on the command line.

Required Changes

  1. Removing the UI window requirements

We can currently hide the window but removing it altogether would be preferable.

  1. Access to stdin/stdout functionality

Currently input is limited to the invoke event to get arguments and output to trace statements. We would need to be able to:

  1. Package into a command line utility (could be an alternative of adl?)

Example

This is a simple example of what is currently possible.

In this example, we simply use trace to output the command line arguments.

package
{
    import flash.desktop.NativeApplication;
    import flash.display.Sprite;
    import flash.events.InvokeEvent;

    public class Main extends Sprite
    {
        public function Main()
        {
            trace( "start..." );
            NativeApplication.nativeApplication.addEventListener( InvokeEvent.INVOKE, invokeHandler );
        }

        private function invokeHandler( event:InvokeEvent ):void
        {
            trace( event.arguments );
            NativeApplication.nativeApplication.exit( 0 );
        }

    }
}

To invoke this on the command line we would compile the swf and then use a simple app xml:

<?xml version="1.0" encoding="utf-8" ?>
<application xmlns="http://ns.adobe.com/air/application/33.1">
    <id>Main</id>
    <filename>Main</filename>
    <name>Main</name>
    <versionNumber>0.0.0</versionNumber>
    <initialWindow>
        <content>Main.swf</content>
        <visible>false</visible>
    </initialWindow>
</application>

We can create a small script to invoke this using adl and passing arguments, eg if we have the following in a Main.sh script (with Main.swf and Main-app.xml in an out directory):

#!/bin/bash
adl -profile extendedDesktop out/Main-app.xml out -- $@

Then we can call it using

./Main.sh -s some_parameter 

This would result in the following output:

start...
-s some_parameter
rewb0rn commented 4 years ago

I am wondering, is there a reason you need to develop the command line tools in AS3? Or is it just a preference to keep everything in the AS3 eco-system?

Personally I was always thinking it would be great to have a centralized market-place where developers can acquire ANEs, libraries or even assets from other developers like Distriqt. Similar to the Unity Asset store. Money always fuels an eco-system and open-source providers could still offer their packages for free. The central market-place would make the most sense if it is provided by Harman, but if you already plan to work in a similar direction, maybe it could be a combined effort?

marchbold commented 4 years ago

The apm tool idea is more around adding packages (ANEs/SWCs) to an application (downloading them from a central repository and their dependencies) and then creating the application descriptor (manifest additions / info additions etc) from these.

The concept of a central marketplace is a separate concept and completely complimentary. This is more akin to the "import package" functionality in unity once you have purchased from the asset store.

The reason for developing this in AIR is just the classic concept of developing the tools for an ecosystem in the same tech stack. Advantages I see are that the users of the tool are already familiar with AS3 and hence would easily be able to contribute or modify the tool. Also that users could develop AIR based UI clients and simply import the functionality of apm as it would be written in as3 and could be imported as a lib.

marchbold commented 4 years ago

@ajwfrost Any comment here? We would like to know a direction for this tool before we start development.

ajwfrost commented 4 years ago

Hi

This is done, at least an initial version for Windows. For now it's just available via ADL where you can add a command-line option which switches it into this mode. I think it's also done for Linux, in case that helps...

Looking to merge this in and release it in our next release (which was going to be in about a month, but we maybe need to accelerate that plan given the other issues re. that missing symbol and some signing issues..)

thanks

Andrew

marchbold commented 4 years ago

Okay more just needed to know that it will be possible and that it is in the works, this will at least give us the confidence to start down this path.

Would prefer a complete release when it is ready rather than a partial one.

ajwfrost commented 3 years ago

Hi @marchbold - this isn't really a "complete release when it's ready" I'm afraid, but we have some initial support for this in our release that's pending deployment now (should be up today hopefully or tomorrow latest). But we'd appreciate feedback from everyone on whether this mechanism works, or whether there should be some changes. The "stdin" support I think may need to change slightly.. Looking back to your original message above: this is currently only available via ADL with a command-line option. Would that be a problem? I'd wondered if we could package this up into a single application i.e. extend ADT so that we could generate a new application that's just a command-line app.. but this would be quite a bit more effort.

From the release notes:

Experimental command-line support: this is initially available on Windows and we plan to roll this out also to MacOS and Linux platforms. If a SWF file doesn’t require access to the Stage or other window-related components, it can be run via ADL with a -cmd flag, for example: [sdkfolder]\bin\adl.exe -cmd application.xml Access to the stage property or functions relying on this will throw run-time errors which are still displayed as pop-up windows, unless the -nodebug command-line option is also used. The “System” class has been updated to include the below functions:

    public static native function output(outString:String):void;
    public static native function input(format:String):String;

The ‘output’ method simply writes the string to the console (via stdout). The ‘input’ method accepts up to 256 characters of input from stdin and returns a new string containing these characters; the ‘format’ parameter is currently ignored.

marchbold commented 3 years ago

Looking good @ajwfrost ! I'll hopefully get some time over the christmas break to have a play with this.

As a side note, I think you should really start beta builds, rather than pushing things like this into the release builds. Something as incomplete as this should never be in the release build.

The issue with just using adl is around distribution and ease of use, eg providing an app to a developer to use which is just an executable is much more common than providing a package of files and relying on access to an AIR SDK. I have no problem with using this approach initially but the end goal should be a complete captive runtime equivalent for a command line app.

mrchnk commented 3 years ago

I am finding that feature very useful in CI for running tests or other related jobs since the latest MacOS and Windows have strict restrictions on how windowed desktop applications should be executed. Looking forward to putting my hands into the Unix version of adl to run tests in a headless container environment.

marchbold commented 3 years ago

Any updates as to when we can expect a macOS version? Really keen to get this moving along for the air package manager.

mrchnk commented 3 years ago

I tried that feature for the Linux version of SDK (33.1.1.575).

package {

import flash.display.Sprite;
import flash.desktop.NativeApplication;

public class App extends Sprite {
    public function App() {
        trace("Hello, Linux!");
        NativeApplication.nativeApplication.exit(0);
    }
}

}

During execution, I got additional unexpected output to both stderr and stdout

root# adl -cmd App.xml

stdout

loadRuntime: /air-sdk/adl/bin/../runtimes/air/linux/Adobe AIR/Versions/1.0/libCore.so
Hello, Linux! 

stderr


(process:4386): Gtk-CRITICAL **: IA__gtk_clipboard_get_for_display: assertion 'display != NULL' failed

(process:4386): Gtk-CRITICAL **: IA__gtk_clipboard_clear: assertion 'clipboard != NULL' failed

(process:4386): Gtk-CRITICAL **: IA__gtk_clipboard_get_for_display: assertion 'display != NULL' failed

(process:4386): Gtk-CRITICAL **: IA__gtk_clipboard_clear: assertion 'clipboard != NULL' failed  

That output should be disabled by default as unexpected behavior. And having an extra flag -verbose to adl executable would be the better option for that.

ajwfrost commented 3 years ago

Hi Thanks for that; the first one is some debug output left in accidentally by the looks of it! The GTK output is happening due to default code (gtk_clipboard_get) where it's using the default display and we don't have one in command-line mode, so we can just prevent those calls where there's no default display... thanks

marchbold commented 3 years ago

@mrchnk Thanks for checking this on linux!

mrchnk commented 3 years ago

You can use g_log_set_default_handler to turn off gtk logs by passing noop logger function.

itlancer commented 1 year ago

@ajwfrost Is it possible to package AIR application (Linux x86_64 and Windows interested right now) to work in console mode? As I see right now it possible to launch it using adl. But I need to run it without AIR SDK and without display. I tried to run packaged AIR app using: MyApp.exe -cmd via cmd/Powershell. But it immediately return output (cause it not console app) and something wrong with codepage (charset) of symbols printed by System.output().

ajwfrost commented 1 year ago

Hi

We don't have this capability at the moment: the executable that gets used when you package up an application is a normal Windows executable, as you've seen.. so to handle this we'd need to have an alternative option in the packaging process, and a separate template executable for command-line apps. The simplest mechanism currently would be to use adl (with the "-nodebug" option alongside "-cmd").

We can look at a new platform/packaging option here perhaps, if there's interest in this?

thanks

itlancer commented 1 year ago

@ajwfrost, yes it interesting for us. We would be able to create command-line AIR applications which could be used as services or in automation processes. Especially as Linux-based console apps (for CI/CD, Raspprery Pi-like devices and so on). May be in future it also could be usefull to create even web services for some developers.

2jfw commented 1 year ago

@ajwfrost: Would it be possible to look into options to run an AIR app as a Windows Service, too? So if it was defined to run as a service it would auto start automatically (unless turned off by the user) and also be headless?

EDIT: Something like this can already be achieved with NativeApplication.startAtLogin

marchbold commented 1 year ago

Super interested here too :)

Using AIR to create command line utilities would be massive for us, particularly if there was linux support as well.

myflashlab commented 1 year ago

This will be super awesome. Looking forward to it 🤩

ylazy commented 4 weeks ago

@ajwfrost I see in -cmd mode, stage is null. So, how can I get something like stage.frameRate? If the stage does not affect performance, I think we should keep it alive for more compatibility. This way, we can develop an application that can run both in GUI and CLI mode.

ajwfrost commented 3 weeks ago

@ylazy I'm not sure there should be any way of getting enter-frame events anyway .. so framerate is a little irrelevant in this case? The Timer class could be used still.

We basically took out/disabled anything to do with display objects and windows etc. The initial stage is actually created as a result of the window object being set up based on the app descriptor settings; it could be possible to create this in the command-line case but I'm not sure what we'd gain..

Are there any other properties you'd need from the stage? Having to support the display object structures to specifically allow/prevent execution based on whether you are in command-line mode or not would mean a lot more changes than the current approach so I'd be more inclined to provide other properties via the 'System' class or similar..

thanks

ajwfrost commented 3 weeks ago

Also just re-reading the earlier comments -> I'm hoping people picked up on the update in 51.1.1.1 to enable command-line apps to be created:

Similar to a “bundle” target for ADT, a new “cmdline” option can be used to create command-line applications that have a captive AIR runtime, for the desktop operating systems. The applications that are then run will not generate a native window and cannot access any UI-related components. They can be quit either via a ctrl-c type command from the console/terminal, or within the application via NativeApplication.exit().

ylazy commented 3 weeks ago

We basically took out/disabled anything to do with display objects and windows etc

@ajwfrost I agree that there're nothing to do with the NativeWindow object in the command line mode.

I think in most cases we also don't need the stage and display objects, but sometimes we may need them. For example, if I want to make a command line application that inputs some pictures to create a 3D image using Away3D (a 3D book, for example), then add some blending effects, capture it, then output it to an image file.

I think it could be better if we can choose what to keep via a command line option or a descriptor tag. We can choose to keep all or keep nothing, it would be better than we have no choice?

By the way, it seems like we can't debug command line applications (breakpoints and code navigation)? I see it's possible with other programming languages. I think it will be possible if we have an option to "keep all" as I mentioned. This way, we can create a command line application that contains full features like a gui application, except everything (including the icon on the taskbar) will be hidden for users. Then we could still debug console apps.

Thanks!

ylazy commented 3 weeks ago

Another reason to have the "keep all" option is the compatibility as I mentioned. Today when I tried to make a simple command line application, it took a long time to fix "cannot access a property or method of a null object reference" errors everywhere. Because many libraries are using the stage. Though I can fix it all but I feel inconvenient. For me, when I need a command line application, that means I don't want to see the GUI, but that does not mean I don't want to use GUI features.

ajwfrost commented 3 weeks ago

Hi

We had recently added some changes in where it had required some of the display objects when dealing with BitmapData (this was actually when generating icons for a 'bundle' application) - so I take your point there may be other such issues, and if third party libraries may depend on all this then that would definitely add some challenges for you..

Let me discuss with the guy who implemented this to see if we could look at a different way of disassociating the native visual components from the AS3 objects.

Plus - not sure why the debugger would not work for command-line applications, we can definitely check on that one.

thanks

2jfw commented 3 weeks ago

Two questions regarding the cmd functionality (Windows):

ajwfrost commented 3 weeks ago

thanks

2jfw commented 3 weeks ago

I see, thanks for the info here. My concern is, that even for very small helper/util AIR apps (with captive runtime), they occupy quite a lot of space on disk and in memory (~15MB) in relation to what they actually do. I mean this is rather getting offtopic here from my side but having smaller AIR.dll and thus having less occupied RAM would be something really nice.

I don't know how much space we would save if trying to cut out the visual-related code and then recompile it all separately, probably not a huge amount.

This somehow amazes me - I would actually have bet on that when omitting the graphics parts of the AIR runtime, the file size could highly be reduced. I mean it all started with flash animations and swf being highly graphically orientated, also the font rendering part etc. but yeah, looks like there was so much other stuff added that the graphics part became small in comparison to that..

ylazy commented 3 weeks ago

@ajwfrost Let me give one more example. I have a c++ command line project that can read text aloud, using TTS api. It's not possible for a "standard" comnand line application because the TTS (text to speech) feature is a visual component so it's not available for command line applications. It's only available for x86 Win32 applications. But I still can make it. I created a Win32 project, edit the HWND to remove all visibility components, I still can use console API, and it work just like a standard command line application. So I think it's possible to keep GUI features for command line applications.

Thank u.

ajwfrost commented 3 weeks ago

@2jfw - you might be right about the size thing if I think about other stuff like the Stage3D code etc, and the rendering code is fairly extensive. Probably the main challenge would be to be able to configure it to build in the different ways..

@ylazy it sounds like this might be more suitable to a 'normal' AIR application but with the initial window visibility set to false? Your example there might work on Windows but on other platforms we could hit issues e.g. on Linux just trying to open a display would fail, let alone creating an invisible GTK window.

2jfw commented 3 weeks ago

@2jfw - you might be right about the size thing if I think about other stuff like the Stage3D code etc, and the rendering code is fairly extensive. Probably the main challenge would be to be able to configure it to build in the different ways..

Would it be possible to split the Adobe AIR.dll into a bunch of other DLL's with specific code only? Or have it being "composed" at compile time based on the imports being used (of course considering dependencies to other "packages")?

ajwfrost commented 3 weeks ago

That's actually something we wondered about a while ago, to make everything a bit more modular (and then to be able to enable other people to start creating modules that could bolt in too...)

It would need quite a significant amount of re-structuring! And could get a little dangerous if we have unexpected cross-dependencies within the code. But an interesting thought...

Practically speaking though .. we probably have higher priorities to work on at the moment, sorry!

MalacTheLittle commented 3 weeks ago

I definitely agree it would be great if there was an option to remove unused stuff. When I see that some apps on Google Play are only 1 MB, it's pity mine can't go under 10 MB. And I don't use a lot of stuff in my apps, e.g. 3D stuff. But then again, 10 MB isn't a lot these days, so it's definitely not a high priority.

2jfw commented 3 weeks ago

That's actually something we wondered about a while ago, to make everything a bit more modular (and then to be able to enable other people to start creating modules that could bolt in too...)

It would need quite a significant amount of re-structuring! And could get a little dangerous if we have unexpected cross-dependencies within the code. But an interesting thought...

Practically speaking though .. we probably have higher priorities to work on at the moment, sorry!

Agreed - it's definitely no urgent feature but would be really nice-to-have 👍

Not sure if applicable or the same effort but would it be possible to not load the entire content of the DLL into the RAM so the memory footprint becomes smaller?

ylazy commented 3 weeks ago

it sounds like this might be more suitable to a 'normal' AIR application but with the initial window visibility set to false

@ajwfrost yes except that a normal AIR app with invisible window still display icon on taskbar and the Harman logo. I need to hide them all. Sorry but I'm ok with the Harman logo on the command line but I think there're no need to block ActionScript executing with AIR command line applications. Imagine an AIR application using some chaining AIR command line tools (A then B then C then D...), if each of them blocks AS 3 seconds so I have to wait 12 seconds for all...

2jfw commented 3 weeks ago

@ajwfrost yes except that a normal AIR app with invisible window still display icon on taskbar and the Harman logo. I need to hide them all.

You can "work-around" the windows in the taskbar by opening a new NativeWindow with InitOptions.type NativeWindowType.UTILITY and directly close the initial window. The new Window should have visibility set to false (I do not remember in detail, but it may require width+height set to 0). It would be nicer however, if AIR would support a property to set the visibility in taskbar at runtime and also pass the InitOptions to the initial window, which is currently not possible so it cannot be set at all for the initial window.

Regarding the Harman Splash, yeah, I mean you could buy a license to remove it of course (somehow they gotta make some profit ..)

ylazy commented 3 weeks ago

Regarding the Harman Splash, yeah, I mean you could buy a license to remove it of course (somehow they gotta make some profit ..)

image

Yes if one day I can make profit from AIR then I definitely want to buy a license. But at this time I'm on progress builing some libraries & tools and currently I've not earn any profit from them. Some of them are for education and they're free to use.

itlancer commented 3 weeks ago

My concern is, that even for very small helper/util AIR apps (with captive runtime), they occupy quite a lot of space on disk and in memory (~15MB) in relation to what they actually do. I mean this is rather getting offtopic here from my side but having smaller AIR.dll and thus having less occupied RAM would be something really nice.

@ajwfrost, @2jfw I have similar task with multiple small AIR apps utilities . And I wonder what if we can use the same AIR captive runtime for that?

I mean right now MyAIRApp.exe uses /META-INF/AIR/application.xml with their manifest settings and SWF file. May be we should have a way to allow something like this (all utilities .exe files in the same directory):

And all of them uses the same /Adobe AIR/Versions/1.0/Adobe AIR.dll

ajwfrost commented 3 weeks ago

@itlancer that's a great idea!

Currently, I think that we'd set up the "command-line app" executable templates to look for the AIR runtime first in the "captive" location, but secondly in the "installed" location i.e. if you had a shared AIR runtime it could be used instead, assuming it was the right version. This might be a little dangerous though given we don't always push an updated shared runtime out, and the auto-update functionality isn't there for that yet either.

The above suggestion could be a bit simpler to do because we could use the executable filename as a root to then look for the XML app descriptor, and if that's not found we just fall back to application.xml. But are you suggesting this would then be something you craft internally rather than building a set of multiple tools like this via ADT? Plus, we would need to check how this might work on macOS with the bundle format meaning you only have one executable in a bundle...

thanks

ylazy commented 3 weeks ago

@itlancer @ajwfrost is this simpler:

MyAIRUtility1.exe uses MyAIRUtility1.xml MyAIRUtility2.exe uses MyAIRUtility2.xml (same folder)

Because an IDE like VSCode will export the application descriptor in the same folder as the .swf. This can be simpler for us to navigate and edit. Just copy/paste. I don't know if META-INF/signatures.xml and META-INF/AIR/hash are needed for console apps? If not, then we don't need the META-INF folder anymore?

itlancer commented 3 weeks ago

But are you suggesting this would then be something you craft internally rather than building a set of multiple tools like this via ADT? Plus, we would need to check how this might work on macOS with the bundle format meaning you only have one executable in a bundle...

@ajwfrost For me it's enough for start to support such "manually combining". I didn't thought yet how to make it automatically. May be passing to ADT multiple XML files with multiple SWFs.